From db5f47586e3050736fd681135c70888f08e484af Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 21 Jan 2026 15:00:34 +0800 Subject: [PATCH] feat: add theme toggle functionality and update localization files - Implemented a theme toggle feature allowing users to switch between light and dark modes. - Added a new ThemeToggle component for the theme switching button. - Updated theme CSS to support dark mode variables and system preference detection. - Enhanced localization files to include translations for the "toggleTheme" key across multiple languages. --- README.md | 10 ++++ public/theme.js | 102 +++++++++++++++++++++++++++++++++ src/components/base.tsx | 1 + src/components/header.tsx | 7 +++ src/components/themeToggle.tsx | 55 ++++++++++++++++++ src/locales/af.json | 3 +- src/locales/am.json | 3 +- src/locales/ar.json | 3 +- src/locales/bg.json | 3 +- src/locales/bn.json | 3 +- src/locales/ca.json | 3 +- src/locales/cs.json | 3 +- src/locales/cy.json | 3 +- src/locales/da.json | 3 +- src/locales/de.json | 3 +- src/locales/el.json | 3 +- src/locales/en.json | 3 +- src/locales/es.json | 3 +- src/locales/et.json | 3 +- src/locales/eu.json | 3 +- src/locales/fa.json | 3 +- src/locales/fi.json | 3 +- src/locales/fil.json | 3 +- src/locales/fr.json | 3 +- src/locales/ga.json | 3 +- src/locales/gl.json | 3 +- src/locales/gu.json | 3 +- src/locales/he.json | 3 +- src/locales/hi.json | 3 +- src/locales/hr.json | 3 +- src/locales/hu.json | 3 +- src/locales/id.json | 3 +- src/locales/is.json | 3 +- src/locales/it.json | 3 +- src/locales/ja.json | 3 +- src/locales/km.json | 3 +- src/locales/kn.json | 3 +- src/locales/ko.json | 3 +- src/locales/lo.json | 3 +- src/locales/lt.json | 3 +- src/locales/lv.json | 3 +- src/locales/mk.json | 3 +- src/locales/ml.json | 3 +- src/locales/mr.json | 3 +- src/locales/ms.json | 3 +- src/locales/mt.json | 3 +- src/locales/my.json | 3 +- src/locales/ne.json | 3 +- src/locales/nl.json | 3 +- src/locales/no.json | 3 +- src/locales/pl.json | 3 +- src/locales/pt.json | 3 +- src/locales/ro.json | 3 +- src/locales/ru.json | 3 +- src/locales/si.json | 3 +- src/locales/sk.json | 3 +- src/locales/sl.json | 3 +- src/locales/sq.json | 3 +- src/locales/sr.json | 3 +- src/locales/sv.json | 3 +- src/locales/sw.json | 3 +- src/locales/ta.json | 3 +- src/locales/te.json | 3 +- src/locales/th.json | 3 +- src/locales/tr.json | 3 +- src/locales/uk.json | 3 +- src/locales/vi.json | 3 +- src/locales/zh-CN.json | 3 +- src/locales/zh-TW.json | 3 +- src/locales/zu.json | 3 +- src/pages/user.tsx | 6 +- src/theme/theme.css | 39 +++++++++---- 72 files changed, 338 insertions(+), 77 deletions(-) create mode 100644 public/theme.js create mode 100644 src/components/themeToggle.tsx diff --git a/README.md b/README.md index 907466e..dc05298 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,16 @@ docker compose up -d --- +## Dark Mode + +ConvertX-CN 支援亮色與暗色主題。 + +- 可手動切換主題(點擊導覽列的太陽/月亮圖示) +- 偏好設定自動儲存於瀏覽器 +- 預設跟隨系統色彩偏好 + +--- + ## MinerU ConvertX 內建文件轉換引擎。 diff --git a/public/theme.js b/public/theme.js new file mode 100644 index 0000000..41f277d --- /dev/null +++ b/public/theme.js @@ -0,0 +1,102 @@ +// ===== Theme Toggle Script ===== +// Handles dark/light mode switching with localStorage persistence +// and system preference detection + +(function () { + const THEME_KEY = "theme"; + + // Get stored theme or detect system preference + function getPreferredTheme() { + const storedTheme = localStorage.getItem(THEME_KEY); + if (storedTheme) { + return storedTheme; + } + // Return null to let CSS handle system preference + return null; + } + + // Get current effective theme (what's actually being displayed) + function getEffectiveTheme() { + const storedTheme = localStorage.getItem(THEME_KEY); + if (storedTheme) { + return storedTheme; + } + // Check system preference + return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; + } + + // Apply theme to document + function applyTheme(theme) { + const root = document.documentElement; + if (theme === "dark") { + root.setAttribute("data-theme", "dark"); + } else if (theme === "light") { + root.setAttribute("data-theme", "light"); + } else { + // Remove attribute to follow system preference + root.removeAttribute("data-theme"); + } + updateThemeIcons(); + } + + // Update theme toggle icons visibility + function updateThemeIcons() { + const effectiveTheme = getEffectiveTheme(); + const lightIcon = document.getElementById("theme-icon-light"); + const darkIcon = document.getElementById("theme-icon-dark"); + + if (lightIcon && darkIcon) { + if (effectiveTheme === "dark") { + // In dark mode, show sun icon (to switch to light) + lightIcon.classList.remove("hidden"); + darkIcon.classList.add("hidden"); + } else { + // In light mode, show moon icon (to switch to dark) + lightIcon.classList.add("hidden"); + darkIcon.classList.remove("hidden"); + } + } + } + + // Toggle theme + function toggleTheme() { + const currentTheme = getEffectiveTheme(); + const newTheme = currentTheme === "dark" ? "light" : "dark"; + localStorage.setItem(THEME_KEY, newTheme); + applyTheme(newTheme); + } + + // Initialize theme on page load + function initTheme() { + const preferredTheme = getPreferredTheme(); + applyTheme(preferredTheme); + + // Listen for system preference changes + window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => { + // Only update if no manual preference is set + if (!localStorage.getItem(THEME_KEY)) { + applyTheme(null); + } + }); + } + + // Apply theme immediately to prevent flash + const preferredTheme = getPreferredTheme(); + if (preferredTheme) { + document.documentElement.setAttribute("data-theme", preferredTheme); + } + + // Set up event listener when DOM is ready + document.addEventListener("DOMContentLoaded", function () { + initTheme(); + + const themeToggle = document.getElementById("theme-toggle"); + if (themeToggle) { + themeToggle.addEventListener("click", toggleTheme); + } + }); + + // Expose toggle function globally for programmatic access + window.toggleTheme = toggleTheme; + window.getEffectiveTheme = getEffectiveTheme; +})(); diff --git a/src/components/base.tsx b/src/components/base.tsx index 561c4e2..8862bc3 100644 --- a/src/components/base.tsx +++ b/src/components/base.tsx @@ -26,6 +26,7 @@ export const BaseHtml = ({