Skip to content

Commit

Permalink
feat: add darkmode support with next-themes
Browse files Browse the repository at this point in the history
  • Loading branch information
deployn committed Sep 10, 2023
1 parent f693221 commit 5c814a8
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 5 deletions.
33 changes: 33 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"eslint": "8.49.0",
"eslint-config-next": "13.4.19",
"next": "13.4.19",
"next-themes": "^0.2.1",
"postcss": "8.4.29",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand All @@ -31,6 +32,7 @@
"@commitlint/cz-commitlint": "^17.7.1",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@tailwindcss/forms": "^0.5.6",
"commitizen": "^4.3.0",
"cz-conventional-changelog": "^3.3.0",
"eslint-config-prettier": "^9.0.0",
Expand Down
5 changes: 4 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import { Providers } from './providers'

const inter = Inter({ subsets: ['latin'] })

Expand All @@ -16,7 +17,9 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<body className={inter.className}>
<Providers>{children}</Providers>
</body>
</html>
)
}
11 changes: 8 additions & 3 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import DarkModeToggle from '@/components/DarkModeToggle'

export default function Home() {
return (
<main className="flex min-h-screen items-center justify-center bg-gray-100 px-4 py-12 sm:px-6 lg:px-8">
<div className="w-full max-w-md space-y-8">
<main className="flex min-h-screen items-center justify-center bg-gradient-to-r from-green-400 to-blue-500 px-4 py-12 ease-in-out sm:px-6 lg:px-8">
<div className="w-full max-w-md transform space-y-8 rounded-xl bg-white p-6 shadow-md transition-all duration-300 hover:shadow-xl dark:bg-gray-800 md:p-12">
<div>
<h1 className="mt-6 text-center text-3xl font-extrabold text-gray-900">
<h1 className="mt-6 text-center text-3xl font-extrabold text-gray-900 transition-colors duration-100 ease-in-out dark:text-gray-200">
Welcome to My Next.js Boilerplate!
</h1>
<div className="mt-6 flex justify-center">
<DarkModeToggle />
</div>
</div>
</div>
</main>
Expand Down
7 changes: 7 additions & 0 deletions src/app/providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use client'

import { ThemeProvider } from 'next-themes'

export function Providers({ children }: { children: React.ReactNode }) {
return <ThemeProvider attribute="class">{children}</ThemeProvider>
}
54 changes: 54 additions & 0 deletions src/components/DarkModeToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use client'

import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'

export default function DarkModeToggle() {
const { theme, setTheme } = useTheme()
const [mounted, setMounted] = useState(false)

useEffect(() => {
const prefersDark =
window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches
const localTheme = localStorage.getItem('theme')

setTheme(localTheme || (prefersDark ? 'dark' : 'light'))
setMounted(true)
}, [setTheme])

useEffect(() => {
if (mounted) {
localStorage.setItem('theme', theme || 'light')
}
}, [theme, mounted])

const toggleTheme = () => {
setTheme(theme === 'dark' ? 'light' : 'dark')
}

return (
<div className="transition duration-500 ease-in-out">
<input
type="checkbox"
id="darkmode"
name="darkmode"
className={`form-switch h-6 w-10 rounded-full transition-all duration-150 ease-out focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 ${
theme === 'dark'
? 'bg-gray-800 ring-offset-gray-800'
: 'bg-indigo-200 ring-offset-indigo-600'
} checked:bg-current`}
checked={theme === 'dark'}
onChange={toggleTheme}
/>
<label
htmlFor="darkmode"
className={`${
theme === 'dark' ? 'text-gray-300' : 'text-gray-700'
} ml-3 text-sm font-medium`}
>
Darkmode
</label>
</div>
)
}
5 changes: 4 additions & 1 deletion tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import forms from '@tailwindcss/forms'

import type { Config } from 'tailwindcss'

const config: Config = {
Expand All @@ -6,7 +8,8 @@ const config: Config = {
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
],
darkMode: 'class',
theme: {},
plugins: [],
plugins: [forms],
}
export default config

0 comments on commit 5c814a8

Please sign in to comment.