fix: 修复亮暗模式颜色

This commit is contained in:
Montia37
2025-09-09 21:25:23 +08:00
parent 5a56b94e52
commit 02a4624b7d
9 changed files with 118 additions and 65 deletions

View File

@@ -2,7 +2,7 @@ import React from "react";
const Footer: React.FC = () => {
return (
<footer className="fixed inset-shadow-sm inset-shadow-(color:--accent-4)/50 bottom-0 left-0 right-0 p-2 text-center purcarte-blur z-50">
<footer className="fixed inset-shadow-sm inset-shadow-(color:--accent-a4) bottom-0 left-0 right-0 p-2 text-center purcarte-blur z-50">
<p className="flex justify-center text-sm text-secondary-foreground theme-text-shadow whitespace-pre">
Powered by{" "}
<a

View File

@@ -57,7 +57,7 @@ export const Header = ({
};
return (
<header className="purcarte-blur border-b border-(--accent-4)/50 sticky top-0 flex items-center justify-center shadow-sm shadow-(color:--accent-4)/50 z-10">
<header className="purcarte-blur border-b border-(--accent-a4) shadow-sm shadow-(color:--accent-a4) sticky top-0 flex items-center justify-center z-10">
<div className="w-[90%] max-w-screen-2xl px-4 py-2 flex items-center justify-between">
<div className="flex items-center theme-text-shadow text-accent-foreground">
<a href="/" className="flex items-center gap-2 text-2xl font-bold">

View File

@@ -10,14 +10,13 @@ const buttonVariants = cva(
variants: {
variant: {
default:
"bg-(--accent-5)/50 text-primary shadow-sm shadow-(color:--accent-4)/50 hover:bg-(--accent-6)/50",
"theme-button text-primary inset-shadow-xs inset-shadow-(color:--accent-a4) ",
destructive:
"bg-(--accent-5)/50 text-white shadow-sm shadow-(color:--accent-4)/50 hover:bg-(--accent-6)/50 focus-visible:ring-destructive/20",
outline:
"bg-(--accent-5)/50 theme-card-style hover:bg-(--accent-6)/50 hover:text-accent-foreground",
"theme-button text-white inset-shadow-xs inset-shadow-(color:--accent-a4) focus-visible:ring-destructive/20",
outline: "theme-button theme-card-style",
secondary:
"bg-(--accent-5)/50 text-secondary-foreground shadow-sm shadow-(color:--accent-4)/50 hover:bg-(--accent-6)/50",
ghost: "hover:bg-(--accent-5)/50 hover:bg-(--accent-6)/50",
"theme-button text-secondary-foreground inset-shadow-xs inset-shadow-(color:--accent-a4)",
ghost: "theme-button-ghost",
link: "text-primary underline-offset-4 hover:underline",
},
size: {

View File

@@ -11,14 +11,14 @@ const Switch = React.forwardRef<
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-(--accent-5) transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-(--accent-8)/50 data-[state=unchecked]:bg-(--accent-4)/50",
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-(--accent-a5) transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-(--accent-a6) data-[state=unchecked]:bg-(--accent-a2)",
className
)}
{...props}
ref={ref}>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-(--accent-9) dark:bg-(--accent-5) shadow-sm ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
"pointer-events-none block h-5 w-5 rounded-full bg-(--accent-a8) shadow-sm ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
)}
/>
</SwitchPrimitives.Root>

View File

@@ -0,0 +1,11 @@
import type { FC, ReactNode } from "react";
import { ThemeContext, type ThemeContextType } from "@/hooks/useTheme";
export const ThemeProvider: FC<{
children: ReactNode;
value: ThemeContextType;
}> = ({ children, value }) => {
return (
<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
);
};

View File

@@ -41,20 +41,66 @@ export const THEME_DEFAULTS = {
} as const;
export interface ThemeContextType {
appearance: Appearance;
appearance: "light" | "dark";
rawAppearance: Appearance;
setAppearance: (appearance: Appearance) => void;
color: Colors;
setColor: (color: Colors) => void;
}
export const ThemeContext = createContext<ThemeContextType>({
appearance: THEME_DEFAULTS.appearance,
appearance: "light",
rawAppearance: THEME_DEFAULTS.appearance,
setAppearance: () => {},
color: THEME_DEFAULTS.color,
setColor: () => {},
});
export const useTheme = () => {
/**
* Custom hook to convert "system" appearance to actual "light" or "dark" for Radix UI
* @param appearance - The appearance setting from context ("light", "dark", or "system")
* @returns The resolved appearance for Radix UI ("light" or "dark")
*/
export const useSystemTheme = (appearance: Appearance): "light" | "dark" => {
const [systemTheme, setSystemTheme] = useState<"light" | "dark">(() => {
// Initial system theme detection
if (typeof window !== "undefined" && window.matchMedia) {
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}
return "light";
});
useEffect(() => {
if (typeof window === "undefined" || !window.matchMedia) {
return;
}
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = (e: MediaQueryListEvent) => {
setSystemTheme(e.matches ? "dark" : "light");
};
// Add listener for system theme changes
mediaQuery.addEventListener("change", handleChange);
// Cleanup
return () => mediaQuery.removeEventListener("change", handleChange);
}, []);
// Return the resolved theme
if (appearance === "system") {
return systemTheme;
}
return appearance as "light" | "dark";
};
import { useContext } from "react";
export const useThemeManager = () => {
const enableLocalStorage = useConfigItem("enableLocalStorage");
const defaultAppearance = useConfigItem("selectedDefaultAppearance");
const defaultColor = useConfigItem("selectThemeColor");
@@ -86,39 +132,28 @@ export const useTheme = () => {
return (defaultColor as Colors) || THEME_DEFAULTS.color;
});
useEffect(() => {
if (appearance === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
setAppearance(systemTheme);
}
}, [appearance]);
const resolvedAppearance = useSystemTheme(appearance);
useEffect(() => {
const root = window.document.documentElement;
root.classList.remove("light", "dark");
if (appearance === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
root.classList.add(systemTheme);
} else {
root.classList.add(appearance);
}
if (enableLocalStorage) {
localStorage.setItem("appearance", appearance);
}
}, [appearance, enableLocalStorage]);
useEffect(() => {
if (enableLocalStorage) {
localStorage.setItem("color", color);
}
}, [color, enableLocalStorage]);
}, [appearance, color, enableLocalStorage]);
return { appearance, setAppearance, color, setColor };
return {
appearance: resolvedAppearance,
rawAppearance: appearance,
setAppearance,
color,
setColor,
};
};
export const useTheme = () => {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
};

View File

@@ -78,7 +78,6 @@
--sidebar-border: #e5e5e5;
--sidebar-ring: #a1a1a1;
--purcarte-blur: 10px;
--body-background-url: url("");
}
@@ -130,20 +129,19 @@
}
@layer utilities {
.dark .radix-themes {
--theme-text-muted-color: rgb(from var(--accent-4) r g b / 0.8);
--theme-line-muted-color: rgb(from var(--accent-2) r g b / 0.5);
}
.radix-themes {
--purcarte-blur: 10px;
--purcarte-card-color: var(--card-light);
--theme-text-muted-color: rgb(from var(--accent-12) r g b / 0.8);
--theme-line-muted-color: rgb(from var(--accent-10) r g b / 0.5);
}
.dark .rt-Badge-tag-transparent {
--tag-transparent-bg: rgb(from var(--accent-11) r g b / 0.4);
--tag-transparent-color: rgb(from var(--accent-4) r g b / 0.8);
@apply bg-(--tag-transparent-bg) text-(--tag-transparent-color);
.radix-themes.dark {
--purcarte-card-color: var(--card-dark);
}
.purcarte-blur {
@apply bg-(--purcarte-card-color)! backdrop-blur-(--purcarte-blur)!;
}
.rt-Badge-tag-transparent {
@@ -152,12 +150,20 @@
@apply bg-(--tag-transparent-bg) text-(--tag-transparent-color);
}
.theme-button {
@apply bg-(--accent-a6)! hover:bg-(--accent-a5)!;
}
.theme-button-ghost {
@apply hover:bg-(--accent-a6)! hover:bg-(--accent-a5)!;
}
.theme-text-shadow {
@apply text-shadow-sm text-shadow-(color:--accent-8)/50;
@apply text-shadow-sm text-shadow-(color:--accent-a4);
}
.theme-card-style {
@apply rounded-lg shadow-sm shadow-(color:--accent-4)/50 box-border border border-(--accent-4)/50;
@apply rounded-lg shadow-sm shadow-(color:--accent-a4) box-border border border-(--accent-a4);
}
.theme-text-muted {
@@ -178,11 +184,6 @@ body::before {
/* transition: var(--body-background-transition); */
}
.purcarte-blur {
background: var(--color-card);
backdrop-filter: blur(var(--purcarte-blur));
}
.striped-bg-red-translucent-diagonal {
background-image: linear-gradient(
45deg,

View File

@@ -6,7 +6,8 @@ import "@radix-ui/themes/styles.css";
import { Theme } from "@radix-ui/themes";
import { Header } from "@/components/sections/Header";
import { ConfigProvider } from "@/config";
import { useTheme } from "@/hooks/useTheme";
import { useThemeManager, useTheme } from "@/hooks/useTheme";
import { ThemeProvider } from "@/contexts/ThemeContext";
import { NodeDataProvider } from "@/contexts/NodeDataContext";
import { LiveDataProvider } from "@/contexts/LiveDataContext";
import { useNodeData } from "@/contexts/NodeDataContext";
@@ -57,7 +58,7 @@ export const AppContent = () => {
className="fixed right-0 bottom-0 min-w-full min-h-full w-auto h-auto -z-1 object-cover"></video>
)}
<Theme
appearance={appearance === "system" ? "inherit" : appearance}
appearance={appearance}
accentColor={color}
scaling="110%"
style={{ backgroundColor: "transparent" }}>
@@ -93,6 +94,7 @@ export const AppContent = () => {
const App = () => {
const { publicSettings, loading } = useNodeData();
const themeManager = useThemeManager();
if (loading) {
return <Loading />;
@@ -100,7 +102,9 @@ const App = () => {
return (
<ConfigProvider publicSettings={publicSettings}>
<ThemeProvider value={themeManager}>
<AppContent />
</ThemeProvider>
</ConfigProvider>
);
};

View File

@@ -82,7 +82,7 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
let foundKey = null;
// 查找是否可以合并到现有时间点
for (const key of timeKeys) {
if (Math.abs(key - t) <= 1500) {
if (Math.abs(key - t) <= 5000) {
foundKey = key;
break;
}
@@ -95,10 +95,11 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
timeKeys.push(useKey);
}
}
grouped[useKey][rec.task_id] = rec.value;
grouped[useKey][rec.task_id] = rec.value === -1 ? null : rec.value;
}
let full = Object.values(grouped).sort((a: any, b: any) => a.time - b.time);
console.log("Full :", full);
if (hours !== 0) {
const task = pingHistory.tasks;
@@ -227,6 +228,8 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
});
}, [pingHistory?.records, sortedTasks, timeRange]);
console.log("chartData:", chartData);
return (
<div className="relative space-y-4">
{loading && (
@@ -451,8 +454,8 @@ const PingChart = memo(({ node, hours }: PingChartProps) => {
{...brushIndices}
dataKey="time"
height={30}
stroke="var(--accent-track)"
fill="var(--accent-4)"
stroke="var(--theme-text-muted-color)"
fill="var(--accent-a4)"
alwaysShowText
tickFormatter={(time) => {
const date = new Date(time);