Skip to content

Commit 21876a5

Browse files
feat: add ThemeProvider for improved theme management and integrate with layout
1 parent fd39789 commit 21876a5

4 files changed

Lines changed: 42 additions & 33 deletions

File tree

apps/web/app/layout.tsx

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import '@acme/ui/globals.css';
88

99
import { HeaderMenu, type HeaderNavItem } from '@/components/header-menu';
1010
import { QueryProvider } from '@/components/providers/query-provider';
11+
import { ThemeProvider } from '@/components/providers/theme-provider';
1112
import { getCurrentUser } from '@/lib/auth';
1213

1314
const displayFont = Space_Grotesk({
@@ -33,18 +34,6 @@ const navItems: HeaderNavItem[] = [
3334
{ href: '/api/v1/docs', label: 'API Docs', kind: 'link' },
3435
];
3536

36-
const themeInitScript = `
37-
(function () {
38-
try {
39-
var theme = window.localStorage.getItem('theme');
40-
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
41-
var isDark = theme === 'dark' || (!theme && prefersDark);
42-
document.documentElement.classList.toggle('dark', isDark);
43-
document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
44-
} catch (_) {}
45-
})();
46-
`;
47-
4837
export default async function RootLayout({
4938
children,
5039
}: Readonly<{
@@ -57,30 +46,32 @@ export default async function RootLayout({
5746

5847
return (
5948
<html lang="en" className="bg-background" suppressHydrationWarning>
60-
<head>
61-
<script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
62-
</head>
6349
<body
6450
className={`${displayFont.variable} ${monoFont.variable} min-h-screen bg-[linear-gradient(180deg,rgba(255,255,255,0.96),rgba(247,248,250,0.94)_28rem),#f7f8fa] text-slate-900 antialiased dark:bg-[linear-gradient(180deg,rgba(15,23,42,0.98),rgba(2,6,23,0.96)_28rem),#020617] dark:text-slate-100`}
6551
>
66-
<QueryProvider>
67-
<div className="relative isolate min-h-screen before:pointer-events-none before:fixed before:inset-0 before:-z-10 before:bg-[linear-gradient(rgba(15,23,42,0.035)_1px,transparent_1px),linear-gradient(90deg,rgba(15,23,42,0.035)_1px,transparent_1px)] before:bg-[size:48px_48px] before:[mask-image:linear-gradient(to_bottom,rgba(0,0,0,0.45),transparent_38rem)] dark:before:bg-[linear-gradient(rgba(148,163,184,0.07)_1px,transparent_1px),linear-gradient(90deg,rgba(148,163,184,0.07)_1px,transparent_1px)] dark:before:[mask-image:linear-gradient(to_bottom,rgba(0,0,0,0.38),transparent_38rem)]">
68-
<header className="sticky top-0 z-20 border-b border-slate-200/80 bg-white/90 backdrop-blur-lg dark:border-slate-800/90 dark:bg-slate-950/86">
69-
<div className="mx-auto flex w-full max-w-[1480px] items-center justify-between gap-4 px-4 py-3 sm:px-6 lg:px-8">
70-
<Link href="/" className="flex min-w-fit items-center gap-3 text-sm font-semibold">
71-
<span className="grid size-9 place-items-center rounded-lg border border-slate-200 bg-slate-900 text-xs font-bold text-white dark:border-slate-700 dark:bg-slate-100 dark:text-slate-950">
72-
AC
73-
</span>
74-
<span className="text-base text-slate-950 dark:text-slate-50">{APP_NAME}</span>
75-
</Link>
76-
<HeaderMenu currentUser={currentUser} navItems={visibleNavItems} />
77-
</div>
78-
</header>
79-
<main className="mx-auto w-full max-w-[1480px] px-4 py-6 sm:px-6 lg:px-8">
80-
{children}
81-
</main>
82-
</div>
83-
</QueryProvider>
52+
<ThemeProvider>
53+
<QueryProvider>
54+
<div className="relative isolate min-h-screen before:pointer-events-none before:fixed before:inset-0 before:-z-10 before:bg-[linear-gradient(rgba(15,23,42,0.035)_1px,transparent_1px),linear-gradient(90deg,rgba(15,23,42,0.035)_1px,transparent_1px)] before:bg-[size:48px_48px] before:[mask-image:linear-gradient(to_bottom,rgba(0,0,0,0.45),transparent_38rem)] dark:before:bg-[linear-gradient(rgba(148,163,184,0.07)_1px,transparent_1px),linear-gradient(90deg,rgba(148,163,184,0.07)_1px,transparent_1px)] dark:before:[mask-image:linear-gradient(to_bottom,rgba(0,0,0,0.38),transparent_38rem)]">
55+
<header className="sticky top-0 z-20 border-b border-slate-200/80 bg-white/90 backdrop-blur-lg dark:border-slate-800/90 dark:bg-slate-950/86">
56+
<div className="mx-auto flex w-full max-w-[1480px] items-center justify-between gap-4 px-4 py-3 sm:px-6 lg:px-8">
57+
<Link
58+
href="/"
59+
className="flex min-w-fit items-center gap-3 text-sm font-semibold"
60+
>
61+
<span className="grid size-9 place-items-center rounded-lg border border-slate-200 bg-slate-900 text-xs font-bold text-white dark:border-slate-700 dark:bg-slate-100 dark:text-slate-950">
62+
AC
63+
</span>
64+
<span className="text-base text-slate-950 dark:text-slate-50">{APP_NAME}</span>
65+
</Link>
66+
<HeaderMenu currentUser={currentUser} navItems={visibleNavItems} />
67+
</div>
68+
</header>
69+
<main className="mx-auto w-full max-w-[1480px] px-4 py-6 sm:px-6 lg:px-8">
70+
{children}
71+
</main>
72+
</div>
73+
</QueryProvider>
74+
</ThemeProvider>
8475
</body>
8576
</html>
8677
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use client';
2+
3+
import { ThemeProvider as NextThemesProvider, type ThemeProviderProps } from 'next-themes';
4+
5+
export function ThemeProvider({ children }: { children: React.ReactNode }) {
6+
const themeProps: ThemeProviderProps = {
7+
attribute: 'class',
8+
defaultTheme: 'system',
9+
enableSystem: true,
10+
disableTransitionOnChange: true,
11+
};
12+
13+
return <NextThemesProvider {...themeProps}>{children}</NextThemesProvider>;
14+
}

apps/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@tanstack/react-query": "^5.99.0",
2121
"better-auth": "^1.6.2",
2222
"next": "16.2.3",
23+
"next-themes": "^0.4.6",
2324
"react": "19.2.4",
2425
"react-dom": "19.2.4",
2526
"shadcn": "^4.2.0",

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)