mirror of
https://github.com/yude-jp/yude.jp
synced 2025-04-20 22:14:51 +09:00
Add checkbox to toggle dark-mode
This commit is contained in:
parent
6bd9b71ff6
commit
86d04bbf22
@ -2,12 +2,15 @@ import Head from "next/head"
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import "tailwindcss/tailwind.css";
|
import "tailwindcss/tailwind.css";
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { ThemeProvider } from "./themeContext"
|
||||||
|
import Toggle from "./toggle"
|
||||||
|
|
||||||
const Layout = (props) => {
|
const Layout = (props) => {
|
||||||
const { title, children } = props
|
const { title, children } = props
|
||||||
const siteTitle = "yude.jp"
|
const siteTitle = "yude.jp"
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
|
<ThemeProvider>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{title ? `${title} - ${siteTitle}` : siteTitle}</title>
|
<title>{title ? `${title} - ${siteTitle}` : siteTitle}</title>
|
||||||
<link rel="icon" href="/static/images/favicon.ico" />
|
<link rel="icon" href="/static/images/favicon.ico" />
|
||||||
@ -33,11 +36,13 @@ const Layout = (props) => {
|
|||||||
<p className="text-sm text-gray-700 font-bold mb-2">
|
<p className="text-sm text-gray-700 font-bold mb-2">
|
||||||
This page is licensed under the MIT License. / Powered by Tailwind CSS and Next.js.
|
This page is licensed under the MIT License. / Powered by Tailwind CSS and Next.js.
|
||||||
</p>
|
</p>
|
||||||
|
<Toggle />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
|
</ThemeProvider>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ const Navbar = () => {
|
|||||||
<nav className='flex items-center flex-wrap p-3'>
|
<nav className='flex items-center flex-wrap p-3'>
|
||||||
<Link href='/'>
|
<Link href='/'>
|
||||||
<a className='inline-flex items-center p-2 mr-4'>
|
<a className='inline-flex items-center p-2 mr-4'>
|
||||||
<span className='text-xl text-black font-bold tracking-wide'>
|
<span className='text-xl text-black font-bold tracking-wide dark:text-white'>
|
||||||
yude.jp
|
yude.jp
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
53
pages/components/themeContext.js
Normal file
53
pages/components/themeContext.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const getInitialTheme = _ => {
|
||||||
|
if (typeof window !== "undefined" && window.localStorage) {
|
||||||
|
const storedPrefs = window.localStorage.getItem("color-theme")
|
||||||
|
if (typeof storedPrefs === "string") {
|
||||||
|
return storedPrefs
|
||||||
|
}
|
||||||
|
|
||||||
|
const userMedia = window.matchMedia("(prefers-color-scheme: dark)")
|
||||||
|
if (userMedia.matches) {
|
||||||
|
return "dark"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you want to use light theme as the default, return "light" instead
|
||||||
|
return "dark"
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeContext = React.createContext()
|
||||||
|
|
||||||
|
export default ThemeContext
|
||||||
|
|
||||||
|
export const ThemeProvider = ({ initialTheme, children }) => {
|
||||||
|
const [theme, setTheme] = React.useState(getInitialTheme)
|
||||||
|
|
||||||
|
const rawSetTheme = theme => {
|
||||||
|
const root = window.document.documentElement
|
||||||
|
const isDark = theme === "dark"
|
||||||
|
|
||||||
|
root.classList.remove(isDark ? "light" : "dark")
|
||||||
|
root.classList.add(theme)
|
||||||
|
|
||||||
|
localStorage.setItem("color-theme", theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialTheme) {
|
||||||
|
rawSetTheme(initialTheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
React.useEffect(
|
||||||
|
_ => {
|
||||||
|
rawSetTheme(theme)
|
||||||
|
},
|
||||||
|
[theme]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{ theme, setTheme }}>
|
||||||
|
{children}
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
23
pages/components/toggle.js
Normal file
23
pages/components/toggle.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ThemeContext from './themeContext'
|
||||||
|
|
||||||
|
const Toggle = () => {
|
||||||
|
const { theme, setTheme } = React.useContext(ThemeContext)
|
||||||
|
|
||||||
|
function isDark() {
|
||||||
|
return theme === "dark"
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={isDark()}
|
||||||
|
onChange={e => setTheme(e.target.checked ? "dark" : "light")}
|
||||||
|
></input>
|
||||||
|
ダーク モード
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Toggle
|
Loading…
x
Reference in New Issue
Block a user