Skip to content

Commit

Permalink
feat: theming
Browse files Browse the repository at this point in the history
  • Loading branch information
KagamiChan committed Sep 29, 2024
1 parent fbbeb4a commit cadd96d
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 16 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"@cloudflare/next-on-pages": "^1.13.3",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-navigation-menu": "^1.2.0",
"@radix-ui/react-select": "^2.1.1",
Expand All @@ -22,6 +23,7 @@
"lodash": "^4.17.21",
"lucide-react": "^0.446.0",
"next": "^14.2.4",
"next-themes": "^0.3.0",
"polished": "^4.3.1",
"random": "^5.1.0",
"react": "^18.3.1",
Expand Down
114 changes: 114 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 15 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { GeistSans } from 'geist/font/sans'
import { type Metadata } from 'next'

import { Background } from '~/components/background'
import { ThemeProvider } from '~/components/theme-provider'

export const metadata: Metadata = {
title: 'Create T3 App',
Expand All @@ -15,10 +16,21 @@ export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en" className={`${GeistSans.variable}`}>
<html
lang="en"
className={`${GeistSans.variable}`}
suppressHydrationWarning
>
<body>
<Background />
{children}
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<Background />
{children}
</ThemeProvider>
</body>
</html>
)
Expand Down
6 changes: 5 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ThemeChooser } from '~/components/theme-chooser'

export default function HomePage() {
return (
<main className="flex min-h-screen flex-col items-center justify-center"></main>
<main className="flex min-h-screen flex-col items-center justify-center">
<ThemeChooser />
</main>
)
}
22 changes: 10 additions & 12 deletions src/components/background.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import debounce from 'lodash/debounce'
import times from 'lodash/times'
import { useTheme } from 'next-themes'
import { rgba } from 'polished'
import random from 'random'
import { useEffect, useRef } from 'react'
Expand Down Expand Up @@ -57,18 +58,14 @@ const getRandomXY = (w: number, h: number) => {

export const Background = () => {
const canvas = useRef<HTMLCanvasElement>(null)

// const theme = useContext(ThemeContext)

const drawCanvasRef = useRef<() => void>()
const { theme } = useTheme()

useEffect(() => {
const drawCanvas = () => {
const foreground = `hsl(${getComputedStyle(
document.documentElement,
).getPropertyValue('--foreground')})`

console.log(foreground)
if (!canvas.current) {
return
}
Expand Down Expand Up @@ -97,14 +94,15 @@ export const Background = () => {
})
}

if (drawCanvasRef.current) {
window.removeEventListener('resize', drawCanvasRef.current)
}
drawCanvasRef.current = debounce(drawCanvas, 100)
const debouncedDrawCanvas = debounce(drawCanvas, 100)

drawCanvas()
window.addEventListener('resize', drawCanvasRef.current)
}, [canvas])
// in current approach, the color is read from computed style, need to wait for theme change happen in DOM
requestAnimationFrame(drawCanvas)
window.addEventListener('resize', debouncedDrawCanvas)
return () => {
window.removeEventListener('resize', debouncedDrawCanvas)
}
}, [theme])

return <canvas className="-z-1 t-0 l-0 fixed bg-background" ref={canvas} />
}
43 changes: 43 additions & 0 deletions src/components/theme-chooser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client'

import { MoonIcon, SunIcon } from 'lucide-react'
import { useTheme } from 'next-themes'

import { Button } from '~/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from '~/components/ui/dropdown-menu'

export const ThemeChooser = () => {
const { theme, setTheme } = useTheme()

console.log('theme', theme)

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
title="设置主题"
aria-label="设置主题"
>
<SunIcon className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<MoonIcon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">设置主题</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
<DropdownMenuRadioItem value="light"></DropdownMenuRadioItem>
<DropdownMenuRadioItem value="dark"></DropdownMenuRadioItem>
<DropdownMenuRadioItem value="system">跟随系统</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
8 changes: 8 additions & 0 deletions src/components/theme-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use client'

import { ThemeProvider as NextThemesProvider } from 'next-themes'
import { type ThemeProviderProps } from 'next-themes/dist/types'

export const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
Loading

0 comments on commit cadd96d

Please sign in to comment.