Skip to content

Commit d470167

Browse files
committed
feat(ui): add navbar & dark mode
- Install next-themes for dark mode support - Create ThemeProvider component - Add global DashboardLayout with responsive navbar - Move UserButton into shared layout - Add native theme toggle to UserButton menu - Remove deprecated afterSignOutUrl prop
1 parent 81bcfa1 commit d470167

File tree

7 files changed

+77
-5
lines changed

7 files changed

+77
-5
lines changed

frontend/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"clsx": "^2.1.1",
1515
"lucide-react": "^0.574.0",
1616
"next": "16.1.6",
17+
"next-themes": "^0.4.6",
1718
"radix-ui": "^1.4.3",
1819
"react": "19.2.3",
1920
"react-dom": "19.2.3",
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use client';
2+
3+
import { UserButton } from '@clerk/nextjs';
4+
import Link from 'next/link';
5+
import { useTheme } from 'next-themes';
6+
import { Moon, Sun } from 'lucide-react';
7+
8+
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
9+
const { theme, setTheme } = useTheme();
10+
11+
return (
12+
<div className="flex min-h-screen flex-col">
13+
<header className="sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60">
14+
<div className="container flex h-16 items-center justify-between mx-auto px-4">
15+
<div className="flex gap-6 md:gap-10">
16+
<Link href="/dashboard" className="flex items-center space-x-2">
17+
<span className="inline-block font-bold">Outpost</span>
18+
</Link>
19+
</div>
20+
<div className="flex flex-1 items-center justify-end space-x-4">
21+
<nav className="flex items-center space-x-2">
22+
<UserButton>
23+
<UserButton.MenuItems>
24+
<UserButton.Action
25+
label={theme === 'dark' ? 'Light mode' : 'Dark mode'}
26+
labelIcon={
27+
theme === 'dark' ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />
28+
}
29+
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
30+
/>
31+
</UserButton.MenuItems>
32+
</UserButton>
33+
</nav>
34+
</div>
35+
</div>
36+
</header>
37+
<div className="flex-1">{children}</div>
38+
</div>
39+
);
40+
}

frontend/src/app/dashboard/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Plus, RefreshCw } from 'lucide-react';
88
import { CreateRunDialog } from '@/components/CreateRunDialog';
99
import { cn } from '@/lib/utils';
1010
import { logger } from '@/lib/logger';
11-
import { UserButton, useAuth } from '@clerk/nextjs';
11+
import { useAuth } from '@clerk/nextjs';
1212

1313
export default function Home() {
1414
const [runs, setRuns] = useState<Run[]>([]);

frontend/src/app/dashboard/runs/[id]/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Badge } from '@/components/ui/badge';
77
import { Button } from '@/components/ui/button';
88
import { ArrowLeft, RefreshCw, ChevronRight } from 'lucide-react';
99
import Link from 'next/link';
10-
import { UserButton, useAuth } from '@clerk/nextjs';
10+
import { useAuth } from '@clerk/nextjs';
1111
import {
1212
Table,
1313
TableBody,
@@ -98,7 +98,6 @@ export default function RunDetailsPage() {
9898
<ArrowLeft className="h-4 w-4" /> Back to Dashboard
9999
</Link>
100100
</Button>
101-
<UserButton afterSignOutUrl="/" />
102101
</div>
103102

104103
<div className="mb-8">

frontend/src/app/layout.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Metadata } from 'next';
22
import { ClerkProvider } from '@clerk/nextjs';
3+
import { ThemeProvider } from '@/components/theme-provider';
34
import './globals.css';
45

56
export const metadata: Metadata = {
@@ -14,8 +15,17 @@ export default function RootLayout({
1415
}>) {
1516
return (
1617
<ClerkProvider>
17-
<html lang="en">
18-
<body>{children}</body>
18+
<html lang="en" suppressHydrationWarning>
19+
<body>
20+
<ThemeProvider
21+
attribute="class"
22+
defaultTheme="system"
23+
enableSystem
24+
disableTransitionOnChange
25+
>
26+
{children}
27+
</ThemeProvider>
28+
</body>
1929
</html>
2030
</ClerkProvider>
2131
);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use client';
2+
3+
import * as React from 'react';
4+
import { ThemeProvider as NextThemesProvider } from 'next-themes';
5+
6+
export function ThemeProvider({
7+
children,
8+
...props
9+
}: React.ComponentProps<typeof NextThemesProvider>) {
10+
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
11+
}

0 commit comments

Comments
 (0)