Skip to content

Commit b6bc30c

Browse files
committed
feat(ui): implement IBM Plex Sans typography and generic EmptyState component for dashboard
1 parent 687045f commit b6bc30c

6 files changed

Lines changed: 99 additions & 12 deletions

File tree

app/globals.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
--secondary: oklch(0.12 0 0); /* Darker secondary */
1717
--secondary-foreground: oklch(1 0 0);
1818
--muted: oklch(0.1 0 0); /* Darker muted */
19-
--muted-foreground: oklch(0.65 0 0);
19+
--muted-foreground: oklch(0.75 0 0);
2020
--accent: oklch(0.85 0.2 145); /* neon green */
2121
--accent-foreground: oklch(0.04 0 0);
2222
--destructive: oklch(0.6 0.24 27); /* #FF1744 - neon red for errors */
@@ -66,7 +66,7 @@
6666
--secondary: oklch(0.92 0 0); /* #EBEBEB - light gray */
6767
--secondary-foreground: oklch(0.04 0 0);
6868
--muted: oklch(0.92 0 0);
69-
--muted-foreground: oklch(0.45 0 0);
69+
--muted-foreground: oklch(0.35 0 0);
7070
--accent: oklch(0.45 0.2 145);
7171
--accent-foreground: oklch(1 0 0);
7272
--destructive: oklch(0.5 0.24 27); /* darker red for light mode */
@@ -103,8 +103,8 @@
103103
}
104104

105105
@theme inline {
106-
--font-sans: "JetBrains Mono", "Geist Mono", "Geist Mono Fallback", monospace;
107-
--font-mono: "JetBrains Mono", "Geist Mono", "Geist Mono Fallback", monospace;
106+
--font-sans: var(--font-sans), "IBM Plex Sans", sans-serif;
107+
--font-mono: var(--font-mono), "JetBrains Mono", monospace;
108108
--color-background: var(--background);
109109
--color-foreground: var(--foreground);
110110
--color-card: var(--card);

app/layout.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import type React from "react"
22
import type { Metadata } from "next"
3-
import { JetBrains_Mono } from "next/font/google"
3+
import { JetBrains_Mono, IBM_Plex_Sans } from "next/font/google"
44
import "./globals.css"
55
import { Toaster } from "sonner"
66

7-
const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"] })
7+
const jetbrainsMono = JetBrains_Mono({
8+
subsets: ["latin"],
9+
variable: "--font-mono",
10+
})
11+
12+
const ibmPlexSans = IBM_Plex_Sans({
13+
subsets: ["latin"],
14+
weight: ["400", "500", "600", "700"],
15+
variable: "--font-sans",
16+
})
817

918
export const metadata: Metadata = {
1019
title: "lab68dev Platform - Build, Learn, Collaborate",
@@ -45,12 +54,12 @@ export default function RootLayout({
4554
}}
4655
/>
4756
</head>
48-
<body
49-
className={`${jetbrainsMono.className} font-mono antialiased bg-background text-foreground`}
57+
<body
58+
className={`${ibmPlexSans.className} ${ibmPlexSans.variable} ${jetbrainsMono.variable} font-sans antialiased bg-background text-foreground`}
5059
suppressHydrationWarning
5160
>
5261
{children}
53-
<Toaster
62+
<Toaster
5463
position="top-right"
5564
toastOptions={{
5665
style: {

build.log

9.45 KB
Binary file not shown.

build_utf8.log

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+

2+
> lab68dev-platform@0.1.1 build D:\lab68dev-platform
3+
> next build
4+
5+
Γû▓ Next.js 16.0.10 (Turbopack)
6+
7+
Creating an optimized production build ...
8+
Γ£ô Compiled successfully in 5.5s
9+
Skipping validation of types
10+
Collecting page data using 15 workers ...
11+
Generating static pages using 15 workers (0/44) ...
12+
Generating static pages using 15 workers (11/44)
13+
Generating static pages using 15 workers (22/44)
14+
Generating static pages using 15 workers (33/44)
15+
ΓÇëELIFECYCLEΓÇë Command failed with exit code 1.

components/dashboard/DashboardClient.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import { DashboardCalendar } from "@/components/dashboard-calendar"
1010
import { RecentActivity } from "@/components/recent-activity"
1111
import { OnboardingFlow } from "@/components/onboarding-flow"
1212
import { BentoCard } from "@/components/bento-card"
13+
import { EmptyState } from "@/components/ui/empty-state"
1314
import { useLanguage } from "@/lib/config"
15+
import { Button } from "@/components/ui/button"
16+
import Link from "next/link"
1417

1518
interface DashboardClientProps {
1619
initialUser: any
@@ -92,9 +95,17 @@ export function DashboardClient({ initialUser, initialCounts, initialMeetings }:
9295
</BentoCard>
9396

9497
<BentoCard colSpan={2} title="Recent Projects" icon={<FolderKanban className="h-4 w-4" />}>
95-
<div className="flex h-full items-center justify-center text-muted-foreground text-sm flex-col gap-2 opacity-50">
96-
<FolderKanban className="h-8 w-8" />
97-
<p>No recent projects</p>
98+
<div className="h-full flex items-center justify-center">
99+
<EmptyState
100+
icon={FolderKanban}
101+
title="No active projects"
102+
description="You haven't created any projects yet. Start building something amazing!"
103+
action={
104+
<Button asChild variant="outline" className="border-primary text-primary hover:bg-primary/10">
105+
<Link href="/dashboard/projects">Create Project</Link>
106+
</Button>
107+
}
108+
/>
98109
</div>
99110
</BentoCard>
100111
</div>

components/ui/empty-state.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as React from "react"
2+
import { LucideIcon } from "lucide-react"
3+
import { cn } from "@/lib/utils"
4+
5+
interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
6+
icon: LucideIcon
7+
title: string
8+
description: string
9+
action?: React.ReactNode
10+
}
11+
12+
export function EmptyState({
13+
icon: Icon,
14+
title,
15+
description,
16+
action,
17+
className,
18+
...props
19+
}: EmptyStateProps) {
20+
return (
21+
<div
22+
className={cn(
23+
"flex flex-col items-center justify-center h-full w-full min-h-[250px] space-y-4 p-8 text-center animate-in fade-in duration-500",
24+
className
25+
)}
26+
{...props}
27+
>
28+
<div className="relative flex items-center justify-center">
29+
{/* Glow effect behind icon */}
30+
<div className="absolute inset-0 bg-primary/20 blur-xl rounded-full" />
31+
<div className="relative rounded-full border border-primary/30 bg-background/50 p-4">
32+
<Icon className="h-10 w-10 text-primary" />
33+
</div>
34+
</div>
35+
36+
<div className="space-y-2 max-w-[280px]">
37+
<h3 className="font-mono text-lg font-semibold tracking-tight text-foreground">
38+
{title}
39+
</h3>
40+
<p className="text-sm text-muted-foreground font-sans">
41+
{description}
42+
</p>
43+
</div>
44+
45+
{action && (
46+
<div className="pt-2">
47+
{action}
48+
</div>
49+
)}
50+
</div>
51+
)
52+
}

0 commit comments

Comments
 (0)