Add persistent dark theme toggle

This commit is contained in:
2026-08-05 13:15:03 +02:00
parent c1c63043c8
commit a88ca99697
5 changed files with 72 additions and 1 deletions
+16
View File
@@ -24,6 +24,7 @@ const sourceTitle = document.querySelector("#sourceTitle");
const sourceList = document.querySelector("#sourceList");
const sourceCloseButton = document.querySelector("#sourceCloseButton");
const settingsButton = document.querySelector("#settingsButton");
const themeToggle = document.querySelector("#themeToggle");
const settingsModal = document.querySelector("#settingsModal");
const settingsCloseButton = document.querySelector("#settingsCloseButton");
const databaseModeNote = document.querySelector("#databaseModeNote");
@@ -120,6 +121,7 @@ const productFieldMap = {
};
await loadStatus();
loadTheme();
renderFields();
renderTableHeader();
setTableWidth();
@@ -167,6 +169,7 @@ sourceModal.addEventListener("click", (event) => {
if (event.target === sourceModal) closeSourceCandidates();
});
settingsButton.addEventListener("click", openSettings);
themeToggle.addEventListener("click", toggleTheme);
settingsCloseButton.addEventListener("click", closeSettings);
settingsModal.addEventListener("click", (event) => {
if (event.target === settingsModal) closeSettings();
@@ -823,6 +826,19 @@ function openSettings() {
settingsModal.hidden = false;
}
function loadTheme() {
const isDark = localStorage.getItem("catalog-maker:theme") === "dark";
document.documentElement.classList.toggle("dark", isDark);
themeToggle.textContent = isDark ? "Light theme" : "Dark theme";
themeToggle.setAttribute("aria-pressed", String(isDark));
}
function toggleTheme() {
const isDark = !document.documentElement.classList.contains("dark");
localStorage.setItem("catalog-maker:theme", isDark ? "dark" : "light");
loadTheme();
}
function closeSettings() {
settingsModal.hidden = true;
}
+1
View File
@@ -60,6 +60,7 @@
<button class="action-button primary" type="button">Show menu (20)</button>
<button class="action-button" type="button">Scraper - 03</button>
<button class="action-button" type="button">BG remover - 04</button>
<button class="action-button" id="themeToggle" type="button" aria-pressed="false">Dark theme</button>
<button class="action-button" id="settingsButton" type="button">Settings</button>
</aside>
+1 -1
View File
File diff suppressed because one or more lines are too long
+42
View File
@@ -21,6 +21,10 @@
color-scheme: light;
}
html.dark {
color-scheme: dark;
}
body {
margin: 0;
min-height: 100vh;
@@ -142,4 +146,42 @@
.product-panel { @apply pt-0; }
.table-wrap { @apply max-h-[70vh]; }
}
html.dark body { @apply bg-slate-950 text-slate-100; }
html.dark .control-panel { @apply bg-slate-950; }
html.dark .product-panel { @apply bg-slate-800; }
html.dark .data-panel { @apply bg-slate-950; }
html.dark .field-label { @apply border-slate-700 bg-slate-800 text-slate-200; }
html.dark .field-value { @apply border-slate-700 bg-slate-900 text-slate-100; }
html.dark .variant-table th { @apply border-slate-700 bg-slate-800 text-slate-100; }
html.dark .variant-table td { @apply border-slate-700 bg-slate-900 text-slate-200; }
html.dark .variant-table tr:nth-child(even) td { @apply bg-slate-800; }
html.dark .variant-table tr:hover td { @apply bg-slate-700; }
html.dark .arrow-button,
html.dark .action-button,
html.dark .input-like { @apply border-slate-600 bg-slate-800 text-slate-100; }
html.dark .arrow-button:hover:not(:disabled),
html.dark .action-button:hover:not(:disabled) { @apply border-slate-400 bg-slate-700; }
html.dark #scanInput { @apply bg-slate-700 placeholder:text-slate-400; }
html.dark .settings-dialog,
html.dark .suggested-dialog,
html.dark .source-dialog { @apply border-slate-700 bg-slate-900; }
html.dark .suggested-header { @apply border-slate-700 bg-slate-800; }
html.dark .suggested-header h2,
html.dark .settings-group legend,
html.dark .settings-option,
html.dark .settings-field { @apply text-slate-100; }
html.dark .settings-group { @apply border-slate-700; }
html.dark .settings-field input { @apply border-slate-600 bg-slate-800 text-slate-100; }
html.dark .modal-close,
html.dark .settings-test-button,
html.dark .suggested-pick,
html.dark .source-row-action,
html.dark .source-picture-action { @apply border-slate-600 bg-slate-800 text-slate-100 hover:bg-slate-700; }
html.dark .source-section { @apply border-slate-700; }
html.dark .source-section-header { @apply border-slate-700 bg-slate-800 text-slate-100; }
html.dark .source-row { @apply border-slate-700 bg-slate-900 text-slate-100 hover:bg-slate-800; }
html.dark .suggested-row,
html.dark .picture-candidate { @apply border-slate-700; }
html.dark .suggested-row:nth-child(even) { @apply bg-slate-800; }
}
+12
View File
@@ -30,3 +30,15 @@ test("catalog maker remains usable on a narrow viewport", async ({ page }) => {
await expect(page.locator("#settingsButton")).toBeVisible();
await page.screenshot({ path: "test-results/catalog-maker-mobile.png", fullPage: true });
});
test("theme toggle switches and persists dark mode", async ({ page }) => {
await page.goto("/");
await expect(page.locator("html")).not.toHaveClass(/dark/);
await page.locator("#themeToggle").click();
await expect(page.locator("html")).toHaveClass(/dark/);
await expect(page.locator("#themeToggle")).toHaveText("Light theme");
await page.reload();
await expect(page.locator("html")).toHaveClass(/dark/);
});