Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(examples): 📝 added multi-themes example #256

Merged
merged 10 commits into from
May 6, 2024
35 changes: 35 additions & 0 deletions examples/multi-theme/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
3 changes: 3 additions & 0 deletions examples/multi-theme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# multi-theme example

> An example on how to handle multiple-themes with `next-themes` using `next.js` app directory.
4 changes: 4 additions & 0 deletions examples/multi-theme/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}

module.exports = nextConfig
24 changes: 24 additions & 0 deletions examples/multi-theme/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "multi-theme",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@types/node": "20.5.7",
"@types/react": "^18.2.21",
"@types/react-dom": "18.2.7",
"autoprefixer": "10.4.15",
"next": "^13.4.19",
"next-themes": "workspace:*",
"postcss": "8.4.28",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.3.3",
"typescript": "^5.2.2"
}
}
6 changes: 6 additions & 0 deletions examples/multi-theme/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
30 changes: 30 additions & 0 deletions examples/multi-theme/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
:root {
--primary: #1e293b;
--primary-foreground: #f8fafc;
}
html[data-theme='dark-classic'] {
--primary: #cbd5e1;
--primary-foreground: #0f172a;
}
html[data-theme='tangerine'] {
--primary: #fcd34d;
--primary-foreground: #0f172a;
}
html[data-theme='dark-tangerine'] {
--primary: #d97706;
--primary-foreground: #0f172a;
}
html[data-theme='mint'] {
--primary: #6ee7b7;
--primary-foreground: #0f172a;
}
html[data-theme='dark-mint'] {
--primary: #047857;
--primary-foreground: #f8fafc;
}
}
18 changes: 18 additions & 0 deletions examples/multi-theme/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import './globals.css'
import { ThemeProvider } from '../components/ThemeProvider'

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body className="bg-white dark:bg-black min-h-[100dvh]">
<ThemeProvider
defaultTheme="light"
enableColorScheme
themes={['light', 'dark-classic', 'tangerine', 'dark-tangerine', 'mint', 'dark-mint']}
>
{children}
</ThemeProvider>
</body>
</html>
)
}
16 changes: 16 additions & 0 deletions examples/multi-theme/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ThemeToggles from '../components/ThemeToggles'

export default function Home() {
return (
<div className="w-full container p-4 mx-auto">
<div className="py-20 flex flex-col items-center justify-center text-gray-800 dark:text-gray-100">
<h1 className="text-5xl text-center font-bold">
Next Themes + Tailwind +{' '}
<span className="text-primary-foreground bg-primary py-2 px-4 rounded">Multi</span> Themes
</h1>
<p className="italic text-2xl">with app-dir</p>
<ThemeToggles />
</div>
</div>
)
}
13 changes: 13 additions & 0 deletions examples/multi-theme/src/components/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use client'

import * as React from 'react'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
type ThemeProviderProps = Parameters<typeof NextThemesProvider>[0]

/**
* Your app's theme provider component.
* 'use client' is essential for next-themes to work with app-dir.
*/
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
47 changes: 47 additions & 0 deletions examples/multi-theme/src/components/ThemeToggles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use client'

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

function ThemeToggles() {
const { theme, setTheme } = useTheme()
const [mounted, setMounted] = useState(false)
// The active theme is not available on the server.
// If you have styling that is conditionally applied based on the active-theme,
// you have to await the mounted state before rendering the active theme.
useEffect(() => setMounted(true), [])

const themeMapping: Record<string, string> = {
light: 'Default',
'dark-classic': 'Dark',
tangerine: 'Tangerine',
'dark-tangerine': 'Tangerine (dark)',
mint: 'Mint',
'dark-mint': 'Mint (dark)'
}

return (
<div>
<div className="mt-16 grid grid-cols-3 grid-rows-2 grid-flow-col gap-4">
{Object.entries(themeMapping).map(([key, value]) => (
<button
key={key}
className={`px-4 py-2 font-semibold rounded-md transition-colors duration-200 ${
// The theme is only available after the component is mounted.
mounted && theme == key
? 'border border-primary bg-primary-foreground text-primary'
: 'bg-primary text-primary-foreground'
}`}
onClick={() => {
setTheme(key)
}}
>
{value}
</button>
))}
</div>
</div>
)
}

export default ThemeToggles
18 changes: 18 additions & 0 deletions examples/multi-theme/tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Config } from 'tailwindcss'

const config: Config = {
darkMode: ['class', '[data-theme^="dark-"]'],
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
theme: {
extend: {
colors: {
primary: {
DEFAULT: 'var(--primary)',
foreground: 'var(--primary-foreground)'
}
}
}
},
plugins: []
}
export default config
27 changes: 27 additions & 0 deletions examples/multi-theme/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
Loading
Loading