Skip to content

Commit

Permalink
docs(examples): 📝 added multi-themes example (#256)
Browse files Browse the repository at this point in the history
* docs(examples): 📝 added example with multi themes with dark mode

* fix: 🐛 fix lock file

* chore: 💚 rebuild lock file

* docs(examples/multi-theme): simplify ThemeToggles component + mention multi-theme in readme

* docs(examples/multi-theme): add mounted check before rendering the active themes toggle as active

* docs(examples/multi-theme): add animate color to theme-toggle button

* chore: update to use pnpm v9

* docs: add link to root readme referring to multi-theme example

---------

Co-authored-by: Tobias Maier <30313631+trm217@users.noreply.github.com>
Co-authored-by: Tobias Maier <me@tobiasmaier.dev>
  • Loading branch information
3 people authored May 6, 2024
1 parent 4452e3d commit bf0c5a4
Show file tree
Hide file tree
Showing 17 changed files with 3,086 additions and 3,349 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

- uses: pnpm/action-setup@v3
with:
version: 8
version: 9

- uses: actions/setup-node@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

- uses: pnpm/action-setup@v3
with:
version: 8
version: 9

- uses: actions/setup-node@v4
with:
Expand Down
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"]
}
2 changes: 2 additions & 0 deletions next-themes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ next-themes is designed to support any number of themes! Simply pass a list of t
<ThemeProvider themes={['pink', 'red', 'blue', 'light', 'dark']}>
```

For an example on how to use this, check out the [multi-theme example](./examples/multi-theme/README.md)

### Without CSS variables

This library does not rely on your theme styling using CSS variables. You can hard-code the values in your CSS, and everything will work as expected (without any flashing):
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
},
"engines": {
"node": ">=20",
"pnpm": ">=8"
"pnpm": ">=9"
},
"packageManager": "pnpm@8.6.3"
}
"packageManager": "pnpm@9.0.6"
}
Loading

0 comments on commit bf0c5a4

Please sign in to comment.