Skip to content

Commit a35771a

Browse files
committed
feat: dark mode
1 parent 17c982b commit a35771a

12 files changed

+1162
-10
lines changed

app/globals.css

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,76 @@
11
@tailwind base;
22
@tailwind components;
33
@tailwind utilities;
4+
5+
@layer base {
6+
:root {
7+
--background: 0 0% 100%;
8+
--foreground: 222.2 84% 4.9%;
9+
10+
--card: 0 0% 100%;
11+
--card-foreground: 222.2 84% 4.9%;
12+
13+
--popover: 0 0% 100%;
14+
--popover-foreground: 222.2 84% 4.9%;
15+
16+
--primary: 222.2 47.4% 11.2%;
17+
--primary-foreground: 210 40% 98%;
18+
19+
--secondary: 210 40% 96.1%;
20+
--secondary-foreground: 222.2 47.4% 11.2%;
21+
22+
--muted: 210 40% 96.1%;
23+
--muted-foreground: 215.4 16.3% 46.9%;
24+
25+
--accent: 210 40% 96.1%;
26+
--accent-foreground: 222.2 47.4% 11.2%;
27+
28+
--destructive: 0 84.2% 60.2%;
29+
--destructive-foreground: 210 40% 98%;
30+
31+
--border: 214.3 31.8% 91.4%;
32+
--input: 214.3 31.8% 91.4%;
33+
--ring: 222.2 84% 4.9%;
34+
35+
--radius: 0.5rem;
36+
}
37+
38+
.dark {
39+
--background: 222.2 84% 4.9%;
40+
--foreground: 210 40% 98%;
41+
42+
--card: 222.2 84% 4.9%;
43+
--card-foreground: 210 40% 98%;
44+
45+
--popover: 222.2 84% 4.9%;
46+
--popover-foreground: 210 40% 98%;
47+
48+
--primary: 210 40% 98%;
49+
--primary-foreground: 222.2 47.4% 11.2%;
50+
51+
--secondary: 217.2 32.6% 17.5%;
52+
--secondary-foreground: 210 40% 98%;
53+
54+
--muted: 217.2 32.6% 17.5%;
55+
--muted-foreground: 215 20.2% 65.1%;
56+
57+
--accent: 217.2 32.6% 17.5%;
58+
--accent-foreground: 210 40% 98%;
59+
60+
--destructive: 0 62.8% 30.6%;
61+
--destructive-foreground: 210 40% 98%;
62+
63+
--border: 217.2 32.6% 17.5%;
64+
--input: 217.2 32.6% 17.5%;
65+
--ring: hsl(212.7,26.8%,83.9);
66+
}
67+
}
68+
69+
@layer base {
70+
* {
71+
@apply border-border;
72+
}
73+
body {
74+
@apply bg-background text-foreground;
75+
}
76+
}

app/layout.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import './globals.css';
22
import type { Metadata } from 'next';
33
import { inter } from './fonts';
4+
import { ThemeProvider } from '@/components/theme-provider';
45

56
export const metadata: Metadata = {
67
title: 'THEDEV',
@@ -13,8 +14,10 @@ export default function RootLayout({
1314
children: React.ReactNode;
1415
}) {
1516
return (
16-
<html lang='en'>
17-
<body className={inter.className}>{children}</body>
17+
<html lang='en' suppressHydrationWarning>
18+
<ThemeProvider attribute='class' defaultTheme='system' enableSystem>
19+
<body className={inter.className}>{children}</body>
20+
</ThemeProvider>
1821
</html>
1922
);
2023
}

app/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { ModeToggle } from '@/components/darkmode-toggle';
12
import { syncopate } from './fonts';
23

34
export default function Home() {
45
return (
5-
<main className='flex h-screen items-center justify-center '>
6+
<main className='flex h-screen gap-4 items-center justify-center '>
67
<h1 className={`uppercase text-5xl ${syncopate.className}`}>thedev</h1>
8+
<ModeToggle />
79
</main>
810
);
911
}

components.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": true,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.js",
8+
"css": "app/globals.css",
9+
"baseColor": "slate",
10+
"cssVariables": true
11+
},
12+
"aliases": {
13+
"components": "@/components",
14+
"utils": "@/lib/utils"
15+
}
16+
}

components/darkmode-toggle.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use client';
2+
3+
import * as React from 'react';
4+
import { MoonIcon, SunIcon } from '@radix-ui/react-icons';
5+
import { useTheme } from 'next-themes';
6+
7+
import { Button } from '@/components/ui/button';
8+
import {
9+
DropdownMenu,
10+
DropdownMenuContent,
11+
DropdownMenuItem,
12+
DropdownMenuTrigger,
13+
} from '@/components/ui/dropdown-menu';
14+
15+
export function ModeToggle() {
16+
const { setTheme } = useTheme();
17+
18+
return (
19+
<DropdownMenu>
20+
<DropdownMenuTrigger asChild>
21+
<Button variant='outline' size='icon'>
22+
<SunIcon className='h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0' />
23+
<MoonIcon className='absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100' />
24+
<span className='sr-only'>Toggle theme</span>
25+
</Button>
26+
</DropdownMenuTrigger>
27+
<DropdownMenuContent align='end'>
28+
<DropdownMenuItem onClick={() => setTheme('light')}>
29+
Light
30+
</DropdownMenuItem>
31+
<DropdownMenuItem onClick={() => setTheme('dark')}>
32+
Dark
33+
</DropdownMenuItem>
34+
<DropdownMenuItem onClick={() => setTheme('system')}>
35+
System
36+
</DropdownMenuItem>
37+
</DropdownMenuContent>
38+
</DropdownMenu>
39+
);
40+
}

components/theme-provider.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use client';
2+
3+
import * as React from 'react';
4+
import { ThemeProvider as NextThemesProvider } from 'next-themes';
5+
import { type ThemeProviderProps } from 'next-themes/dist/types';
6+
7+
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8+
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
9+
}

components/ui/button.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import * as React from "react"
2+
import { Slot } from "@radix-ui/react-slot"
3+
import { cva, type VariantProps } from "class-variance-authority"
4+
5+
import { cn } from "@/lib/utils"
6+
7+
const buttonVariants = cva(
8+
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
9+
{
10+
variants: {
11+
variant: {
12+
default:
13+
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
14+
destructive:
15+
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16+
outline:
17+
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
18+
secondary:
19+
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20+
ghost: "hover:bg-accent hover:text-accent-foreground",
21+
link: "text-primary underline-offset-4 hover:underline",
22+
},
23+
size: {
24+
default: "h-9 px-4 py-2",
25+
sm: "h-8 rounded-md px-3 text-xs",
26+
lg: "h-10 rounded-md px-8",
27+
icon: "h-9 w-9",
28+
},
29+
},
30+
defaultVariants: {
31+
variant: "default",
32+
size: "default",
33+
},
34+
}
35+
)
36+
37+
export interface ButtonProps
38+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
39+
VariantProps<typeof buttonVariants> {
40+
asChild?: boolean
41+
}
42+
43+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
44+
({ className, variant, size, asChild = false, ...props }, ref) => {
45+
const Comp = asChild ? Slot : "button"
46+
return (
47+
<Comp
48+
className={cn(buttonVariants({ variant, size, className }))}
49+
ref={ref}
50+
{...props}
51+
/>
52+
)
53+
}
54+
)
55+
Button.displayName = "Button"
56+
57+
export { Button, buttonVariants }

0 commit comments

Comments
 (0)