移除主题切换相关组件,简化主题管理逻辑,默认设置为暗黑模式,提升代码整洁性和用户体验。

This commit is contained in:
wood chen 2025-06-14 07:31:06 +08:00
parent 9090b407cc
commit 3958b3b35c
6 changed files with 20 additions and 171 deletions

View File

@ -3,29 +3,20 @@
<head>
<script>
// 在页面渲染前就执行主题初始化
try {
const storageKey = "vite-ui-theme"
let theme = localStorage.getItem(storageKey)
if (theme === "system" || !theme) {
theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
}
document.documentElement.classList.add(theme)
} catch (e) {
document.documentElement.classList.add("light")
}
document.documentElement.classList.add("dark")
// 全局配置变量
window.ShowServerDetails = true; // 是否显示服务器详细信息
</script>
<style>
/* Prevent FOUC in Safari */
html:not(.dark):not(.light) * {
html:not(.dark) * {
visibility: hidden;
}
:root {
color-scheme: light;
--bg: #ffffff;
color-scheme: dark;
--bg: #242424;
}
html.dark {
@ -33,11 +24,6 @@
--bg: #242424;
}
html.light {
color-scheme: light;
--bg: #ffffff;
}
html {
background-color: var(--bg) !important;
}
@ -67,31 +53,10 @@
</style>
<script>
;(function () {
const storageKey = "vite-ui-theme"
const theme = localStorage.getItem(storageKey) || "system"
const root = document.documentElement
function updateThemeColor(isDark) {
const themeColor = isDark ? "#242424" : "#fafafa"
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", themeColor)
}
function setTheme(newTheme) {
root.classList.remove("light", "dark")
root.classList.add(newTheme)
updateThemeColor(newTheme === "dark")
}
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
setTheme(systemTheme)
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
setTheme(e.matches ? "dark" : "light")
})
} else {
setTheme(theme)
}
root.classList.remove("light")
root.classList.add("dark")
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", "#242424")
// Add loaded class after React has mounted
window.addEventListener("load", () => {

View File

@ -1,4 +1,3 @@
import { ModeToggle } from "@/components/ThemeSwitcher"
import { Separator } from "@/components/ui/separator"
import { Skeleton } from "@/components/ui/skeleton"
import { useBackground } from "@/hooks/use-background"
@ -102,7 +101,6 @@ function Header() {
<Links />
<DashboardLink />
</div>
<ModeToggle />
{(customBackgroundImage || sessionStorage.getItem("savedBackgroundImage")) && (
<Button
variant="outline"

View File

@ -1,39 +0,0 @@
"use client"
import { useTheme } from "@/hooks/use-theme"
import { useEffect } from "react"
export function ThemeColorManager() {
const { theme } = useTheme()
useEffect(() => {
const updateThemeColor = () => {
const currentTheme = theme
const meta = document.querySelector('meta[name="theme-color"]')
if (!meta) {
const newMeta = document.createElement("meta")
newMeta.name = "theme-color"
document.head.appendChild(newMeta)
}
const themeColor =
currentTheme === "dark"
? "hsl(30 15% 8%)" // 深色模式背景色
: "hsl(0 0% 98%)" // 浅色模式背景色
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", themeColor)
}
// Update on mount and theme change
updateThemeColor()
// Listen for system theme changes
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
mediaQuery.addEventListener("change", updateThemeColor)
return () => mediaQuery.removeEventListener("change", updateThemeColor)
}, [theme])
return null
}

View File

@ -1,11 +1,9 @@
import { ReactNode, createContext, useEffect, useState } from "react"
import { ReactNode, createContext } from "react"
export type Theme = "dark" | "light" | "system"
export type Theme = "dark"
type ThemeProviderProps = {
children: ReactNode
defaultTheme?: Theme
storageKey?: string
}
type ThemeProviderState = {
@ -14,40 +12,22 @@ type ThemeProviderState = {
}
const initialState: ThemeProviderState = {
theme: "system",
theme: "dark",
setTheme: () => null,
}
const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
export function ThemeProvider({ children, storageKey = "vite-ui-theme" }: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem(storageKey) as Theme) || "system")
export function ThemeProvider({ children }: ThemeProviderProps) {
const root = window.document.documentElement
root.classList.remove("light")
root.classList.add("dark")
const themeColor = "hsl(30 15% 8%)"
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", themeColor)
useEffect(() => {
const root = window.document.documentElement
root.classList.remove("light", "dark")
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
root.classList.add(systemTheme)
const themeColor = systemTheme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)"
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", themeColor)
return
}
root.classList.add(theme)
const themeColor = theme === "dark" ? "hsl(30 15% 8%)" : "hsl(0 0% 98%)"
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", themeColor)
}, [theme])
const value = {
theme,
setTheme: (theme: Theme) => {
localStorage.setItem(storageKey, theme)
setTheme(theme)
},
const value: ThemeProviderState = {
theme: "dark",
setTheme: () => null,
}
return <ThemeProviderContext.Provider value={value}>{children}</ThemeProviderContext.Provider>

View File

@ -1,53 +0,0 @@
import { Theme } from "@/components/ThemeProvider"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { cn } from "@/lib/utils"
import { CheckCircleIcon } from "@heroicons/react/20/solid"
import { Moon, Sun } from "lucide-react"
import { useTranslation } from "react-i18next"
import { useTheme } from "../hooks/use-theme"
export function ModeToggle() {
const { t } = useTranslation()
const { setTheme, theme } = useTheme()
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const handleSelect = (e: Event, newTheme: Theme) => {
e.preventDefault()
setTheme(newTheme)
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className={cn("rounded-full px-[9px] bg-white dark:bg-black", {
"bg-white/70 dark:bg-black/70": customBackgroundImage,
})}
>
<Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="flex flex-col gap-0.5" align="end">
<DropdownMenuItem className={cn({ "gap-3 bg-muted": theme === "light" })} onSelect={(e) => handleSelect(e, "light")}>
{t("theme.light")}
{theme === "light" && <CheckCircleIcon className="size-4" />}
</DropdownMenuItem>
<DropdownMenuItem className={cn({ "gap-3 bg-muted": theme === "dark" })} onSelect={(e) => handleSelect(e, "dark")}>
{t("theme.dark")}
{theme === "dark" && <CheckCircleIcon className="size-4" />}
</DropdownMenuItem>
<DropdownMenuItem className={cn({ "gap-3 bg-muted": theme === "system" })} onSelect={(e) => handleSelect(e, "system")}>
{t("theme.system")}
{theme === "system" && <CheckCircleIcon className="size-4" />}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}

View File

@ -4,7 +4,6 @@ import ReactDOM from "react-dom/client"
import { Toaster } from "sonner"
import App from "./App"
import { ThemeColorManager } from "./components/ThemeColorManager"
import { ThemeProvider } from "./components/ThemeProvider"
import { MotionProvider } from "./components/motion/motion-provider"
import { SortProvider } from "./context/sort-provider"
@ -18,8 +17,7 @@ const queryClient = new QueryClient()
ReactDOM.createRoot(document.getElementById("root")!).render(
<MotionProvider>
<ThemeProvider storageKey="vite-ui-theme">
<ThemeColorManager />
<ThemeProvider>
<QueryClientProvider client={queryClient}>
<WebSocketProvider url="/api/v1/ws/server">
<StatusProvider>