From a988fd0542b93edc45897a912f6a02ea782943f1 Mon Sep 17 00:00:00 2001 From: cte Date: Sun, 11 May 2025 23:12:16 -0700 Subject: [PATCH] Add themes --- package.json | 1 + pnpm-lock.yaml | 14 ++++++++ src/app/layout.tsx | 29 +++++++++------ src/components/LocaleSwitcher.tsx | 25 +++---------- src/components/ThemeProvider.tsx | 11 ++++++ src/components/ThemeSwitcher.tsx | 38 ++++++++++++++++++++ src/components/ToggleMenuButton.tsx | 2 +- src/components/dashboard/DashboardHeader.tsx | 4 +-- src/components/landing/CenteredMenu.tsx | 31 +++++++++------- src/components/templates/Navbar.tsx | 16 +++++---- src/components/ui/index.ts | 3 ++ 11 files changed, 121 insertions(+), 53 deletions(-) create mode 100644 src/components/ThemeProvider.tsx create mode 100644 src/components/ThemeSwitcher.tsx create mode 100644 src/components/ui/index.ts diff --git a/package.json b/package.json index 3acfcbf90e..395428cabd 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "lucide-react": "^0.509.0", "next": "^15.3.2", "next-intl": "^4.1.0", + "next-themes": "^0.4.6", "pg": "^8.13.0", "pino": "^9.5.0", "pino-pretty": "^13.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb2e320a4d..ca5f34579d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,6 +65,9 @@ importers: next-intl: specifier: ^4.1.0 version: 4.1.0(next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.8.3) + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) pg: specifier: ^8.13.0 version: 8.15.6 @@ -6449,6 +6452,12 @@ packages: typescript: optional: true + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + next@15.3.2: resolution: {integrity: sha512-CA3BatMyHkxZ48sgOCLdVHjFU36N7TF1HhqAHLFOkV6buwZnvMI84Cug8xD56B9mCuKrqXnLn94417GrZ/jjCQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} @@ -15704,6 +15713,11 @@ snapshots: optionalDependencies: typescript: 5.8.3 + next-themes@0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@next/env': 15.3.2 diff --git a/src/app/layout.tsx b/src/app/layout.tsx index bccfa44103..904f5bde22 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -4,12 +4,11 @@ import type { Metadata } from 'next'; import { NextIntlClientProvider } from 'next-intl'; import { getLocale } from 'next-intl/server'; +import { ThemeProvider } from '@/components/ThemeProvider'; + export const metadata: Metadata = { icons: [ - { - rel: 'apple-touch-icon', - url: '/apple-touch-icon.png', - }, + { rel: 'apple-touch-icon', url: '/apple-touch-icon.png' }, { rel: 'icon', type: 'image/png', @@ -22,14 +21,15 @@ export const metadata: Metadata = { sizes: '16x16', url: '/favicon-16x16.png', }, - { - rel: 'icon', - url: '/favicon.ico', - }, + { rel: 'icon', url: '/favicon.ico' }, ], }; -export default async function RootLayout(props: { children: React.ReactNode }) { +export default async function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { const locale = await getLocale(); return ( @@ -38,7 +38,16 @@ export default async function RootLayout(props: { children: React.ReactNode }) { className="bg-background text-foreground antialiased" suppressHydrationWarning > - {props.children} + + + {children} + + ); diff --git a/src/components/LocaleSwitcher.tsx b/src/components/LocaleSwitcher.tsx index 3abc7afb02..5e500e2882 100644 --- a/src/components/LocaleSwitcher.tsx +++ b/src/components/LocaleSwitcher.tsx @@ -6,14 +6,15 @@ import { useLocale } from 'next-intl'; import { Locales, isLocale } from '@/types/locale'; import { setLocale } from '@/actions/locale'; -import { Button } from '@/components/ui/button'; import { + Button, DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; +} from '@/components/ui'; +import { Globe } from 'lucide-react'; export const LocaleSwitcher = () => { const router = useRouter(); @@ -32,24 +33,8 @@ export const LocaleSwitcher = () => { return ( - diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx new file mode 100644 index 0000000000..9bf53d8607 --- /dev/null +++ b/src/components/ThemeProvider.tsx @@ -0,0 +1,11 @@ +'use client'; + +import * as React from 'react'; +import { ThemeProvider as NextThemesProvider } from 'next-themes'; + +export function ThemeProvider({ + children, + ...props +}: React.ComponentProps) { + return {children}; +} diff --git a/src/components/ThemeSwitcher.tsx b/src/components/ThemeSwitcher.tsx new file mode 100644 index 0000000000..ee98b72c9c --- /dev/null +++ b/src/components/ThemeSwitcher.tsx @@ -0,0 +1,38 @@ +'use client'; + +import { Moon, Sun } from 'lucide-react'; +import { useTheme } from 'next-themes'; + +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui'; + +export function ThemeSwitcher() { + const { setTheme } = useTheme(); + + return ( + + + + + + setTheme('light')}> + Light + + setTheme('dark')}> + Dark + + setTheme('system')}> + System + + + + ); +} diff --git a/src/components/ToggleMenuButton.tsx b/src/components/ToggleMenuButton.tsx index 7f2c2976a4..4062dbb5b9 100644 --- a/src/components/ToggleMenuButton.tsx +++ b/src/components/ToggleMenuButton.tsx @@ -1,6 +1,6 @@ import { type ForwardedRef, forwardRef } from 'react'; -import { Button } from '@/components/ui/button'; +import { Button } from '@/components/ui'; type ToggleMenuButtonProps = { onClick?: () => void; diff --git a/src/components/dashboard/DashboardHeader.tsx b/src/components/dashboard/DashboardHeader.tsx index cb4c75e998..47f4dac7df 100644 --- a/src/components/dashboard/DashboardHeader.tsx +++ b/src/components/dashboard/DashboardHeader.tsx @@ -11,8 +11,8 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { Separator } from '@/components/ui/separator'; + Separator, +} from '@/components/ui'; import { Logo } from '@/components/templates/Logo'; type DashboardHeaderProps = { diff --git a/src/components/landing/CenteredMenu.tsx b/src/components/landing/CenteredMenu.tsx index 587faee447..59a0fd6597 100644 --- a/src/components/landing/CenteredMenu.tsx +++ b/src/components/landing/CenteredMenu.tsx @@ -6,11 +6,17 @@ import { ToggleMenuButton } from '@/components/ToggleMenuButton'; import { useMenu } from '@/hooks/useMenu'; import { cn } from '@/lib/utils'; -export const CenteredMenu = (props: { +type CenteredMenuProps = { logo: React.ReactNode; - children: React.ReactNode; rightMenu: React.ReactNode; -}) => { + children?: React.ReactNode; +}; + +export const CenteredMenu = ({ + logo, + rightMenu, + children, +}: CenteredMenuProps) => { const { showMenu, handleToggleMenu } = useMenu(); const navClass = cn('max-lg:w-full max-lg:bg-secondary max-lg:p-5', { @@ -19,18 +25,17 @@ export const CenteredMenu = (props: { return (
- {props.logo} - + {logo}
- - - + {children && ( + + )}
    - {props.rightMenu} + {rightMenu}
diff --git a/src/components/templates/Navbar.tsx b/src/components/templates/Navbar.tsx index 6646d49655..690c001de5 100644 --- a/src/components/templates/Navbar.tsx +++ b/src/components/templates/Navbar.tsx @@ -1,8 +1,9 @@ import Link from 'next/link'; import { useTranslations } from 'next-intl'; +import { Button } from '@/components/ui'; import { LocaleSwitcher } from '@/components/LocaleSwitcher'; -import { buttonVariants } from '@/components/ui/button'; +import { ThemeSwitcher } from '@/components/ThemeSwitcher'; import { CenteredMenu } from '@/components/landing/CenteredMenu'; import { Section } from '@/components/landing/Section'; @@ -20,19 +21,20 @@ export const Navbar = () => {
  • +
  • + +
  • {t('sign_in')}
  • - - {t('sign_up')} - +
  • } - > -
    - + /> ); }; diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts new file mode 100644 index 0000000000..b64503aeb9 --- /dev/null +++ b/src/components/ui/index.ts @@ -0,0 +1,3 @@ +export * from './button'; +export * from './dropdown-menu'; +export * from './separator';