diff --git a/public/index.html b/public/index.html index 28d5908..f870f9f 100644 --- a/public/index.html +++ b/public/index.html @@ -10,6 +10,20 @@ Word Game + diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js index ce7c934..4e2e84e 100644 --- a/src/components/Header/Header.js +++ b/src/components/Header/Header.js @@ -1,9 +1,14 @@ import React from 'react'; +import ThemeToggle from '../ThemeToggle'; function Header() { return (
+

Word Game

+
+ +
); } diff --git a/src/components/ThemeToggle/ThemeToggle.js b/src/components/ThemeToggle/ThemeToggle.js new file mode 100644 index 0000000..37b71a8 --- /dev/null +++ b/src/components/ThemeToggle/ThemeToggle.js @@ -0,0 +1,41 @@ +import React from 'react'; + +const STORAGE_KEY = 'theme'; + +function getInitialTheme() { + const stored = window.localStorage.getItem(STORAGE_KEY); + if (stored === 'light' || stored === 'dark') { + return stored; + } + + const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + return prefersDark ? 'dark' : 'light'; +} + +function ThemeToggle() { + const [theme, setTheme] = React.useState(getInitialTheme); + + React.useEffect(() => { + document.documentElement.setAttribute('data-theme', theme); + window.localStorage.setItem(STORAGE_KEY, theme); + }, [theme]); + + function toggleTheme() { + setTheme(prevTheme => (prevTheme === 'dark' ? 'light' : 'dark')); + } + + const isDark = theme === 'dark'; + + return ( + + ); +} + +export default ThemeToggle; diff --git a/src/components/ThemeToggle/index.js b/src/components/ThemeToggle/index.js new file mode 100644 index 0000000..8ef3c1f --- /dev/null +++ b/src/components/ThemeToggle/index.js @@ -0,0 +1,2 @@ +export * from './ThemeToggle'; +export { default } from './ThemeToggle'; diff --git a/src/styles.css b/src/styles.css index f54c1cf..e46460f 100644 --- a/src/styles.css +++ b/src/styles.css @@ -15,6 +15,30 @@ html { --color-gray-500: hsl(0deg 0% 50%); --color-gray-700: hsl(0deg 0% 75%); --color-gray-900: hsl(0deg 0% 90%); + + /* Light theme (default) */ + --color-background: hsl(0deg 0% 100%); + --color-surface: hsl(0deg 0% 96%); + --color-text: var(--color-gray-100); + --color-border: var(--color-gray-700); + --color-cell-incorrect: hsl(0deg 0% 25%); +} + +html[data-theme='dark'] { + --color-success: hsl(150deg 60% 40%); + --color-warning: hsl(50deg 90% 45%); + --color-error: hsl(0deg 65% 55%); + --color-gray-100: hsl(0deg 0% 90%); + --color-gray-300: hsl(0deg 0% 65%); + --color-gray-500: hsl(0deg 0% 50%); + --color-gray-700: hsl(0deg 0% 35%); + --color-gray-900: hsl(0deg 0% 20%); + + --color-background: hsl(220deg 15% 10%); + --color-surface: hsl(220deg 15% 16%); + --color-text: hsl(0deg 0% 92%); + --color-border: var(--color-gray-700); + --color-cell-incorrect: hsl(0deg 0% 35%); } /* @@ -22,6 +46,9 @@ html { */ body { font-family: sans-serif; + background: var(--color-background); + color: var(--color-text); + transition: background-color 150ms ease-in-out, color 150ms ease-in-out; } @media (max-height: 600px) { @@ -49,10 +76,24 @@ button { header { display: flex; height: var(--header-height); - border-bottom: 1px solid var(--color-gray-700); + border-bottom: 1px solid var(--color-border); color: var(--color-gray-300); } +.theme-toggle { + display: grid; + place-content: center; + width: 2.5rem; + height: 2.5rem; + border-radius: 50%; + font-size: 1.25rem; + transition: background-color 150ms ease-in-out; +} +.theme-toggle:hover, +.theme-toggle:focus-visible { + background: var(--color-surface); +} + header .side { width: var(--header-height); display: grid; @@ -102,7 +143,7 @@ h1 { display: grid; place-content: center; aspect-ratio: 1 / 1; - border: 2px solid var(--color-gray-700); + border: 2px solid var(--color-border); border-radius: var(--radius); font-size: 2rem; } @@ -130,8 +171,8 @@ h1 { color: white; } .cell.incorrect { - background: var(--color-gray-300); - border-color: var(--color-gray-300); + background: var(--color-cell-incorrect); + border-color: var(--color-cell-incorrect); color: white; } .cell.misplaced { @@ -155,10 +196,12 @@ h1 { display: block; width: 100%; font-size: 2rem; - border: 2px solid var(--color-gray-300); + border: 2px solid var(--color-border); border-radius: 4px; padding: 8px 16px; outline-offset: 4px; + background: var(--color-background); + color: var(--color-text); } .banner {