Beyond Dark Mode (Read Article)
Creating more than one color scheme with Tailwind and Next.js
Creating more than one color scheme with Tailwind and Next.js
| let plugin = require('tailwindcss/plugin') | |
| module.exports = { | |
| darkMode: 'class', | |
| plugins: [ | |
| plugin(function ({ addVariant }) { | |
| addVariant('metal', '.metal &'), | |
| }), | |
| ], | |
| } |
| @tailwind utilities; | |
| @layer utilities { | |
| /* Background Colors (combined modes) */ | |
| .bg-default { | |
| @apply bg-white dark:bg-black metal:bg-black; | |
| } | |
| /* Border Colors (combined modes) */ | |
| .border-default { | |
| @apply border-black dark:border-white metal:border-red; | |
| } | |
| .border-default-50 { | |
| @apply border-black border-opacity-50 dark:border-white dark:border-opacity-50 metal:border-red metal:border-opacity-50; | |
| } | |
| /* Text Colors (combined modes) */ | |
| .text-default { | |
| @apply text-black dark:text-white metal:text-red; | |
| } | |
| .text-default-50 { | |
| @apply text-black text-opacity-50 dark:text-white dark:text-opacity-50 metal:text-red metal:text-opacity-50; | |
| } | |
| } |
| import React from 'react' | |
| const ExampleCard = () => { | |
| return ( | |
| <div className="bg-default border border-default"> | |
| <h2 className="text-default">linguine</h2> | |
| <p className="text-default-50">the best pasta</p> | |
| </div> | |
| ) | |
| } | |
| export default ExampleCard |
| import { ThemeProvider } from 'next-themes' | |
| function MyApp({ Component, pageProps }) { | |
| return ( | |
| <ThemeProvider | |
| themes={['dark', 'light', 'metal']} | |
| enableSystem={false} | |
| disableTransitionOnChange | |
| attribute="class" | |
| defaultTheme="dark" | |
| > | |
| <Component {...pageProps} /> | |
| </ThemeProvider> | |
| ) | |
| } | |
| export default MyApp |
| import React from 'react' | |
| import { useTheme } from 'next-themes' | |
| import { useHasMounted } from '@lib/helpers' | |
| const themes = [ | |
| { title: 'Light Mode', name: 'light' }, | |
| { title: 'Dark Mode', name: 'dark' }, | |
| { title: 'Metal Mode', name: 'metal' }, | |
| ] | |
| const ThemeSwitcher = () => { | |
| const hasMounted = useHasMounted() | |
| const { theme, setTheme } = useTheme() | |
| // store our current and next theme objects (will be first theme, if undefined) | |
| const currentIndex = Math.max( | |
| 0, | |
| themes.findIndex((t) => t.name === theme) | |
| ) | |
| const currentTheme = themes[currentIndex] | |
| const nextIndex = (currentIndex + 1) % themes.length | |
| const nextTheme = themes[nextIndex] | |
| // Make sure it's only rendered on the client | |
| if (!hasMounted || !theme) return null | |
| return ( | |
| <div> | |
| <p> | |
| Current: <strong>{currentTheme.title}</strong> | |
| </p> | |
| <button onClick={() => setTheme(nextTheme.name)}> | |
| Switch to {nextTheme.title} | |
| </button> | |
| </div> | |
| ) | |
| } | |
| export default ThemeSwitcher |