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 (
);
}
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 {