fix settings dark theme styles

This commit is contained in:
yoma committed 2026-07-15 22:06:22 +08:00
1 parent 36df7c8c5d
commit db9700aebd
4 files changed
+46 -44

No files matched your search

+36 -34
View File
@@ -39,8 +39,10 @@ interface SettingsPaneProps {
onShowGuide?: () => void;
}
// Slate and brand color variables already switch values with the root theme.
// Keep this pane on the base utilities so dark variants do not invert them twice.
const SettingsGroup = ({ children }: { children: ReactNode }) => (
<div className="min-w-0 divide-y divide-slate-200 overflow-hidden rounded-xl border border-slate-200 bg-white dark:divide-slate-800 dark:border-slate-800 dark:bg-slate-950 [&>*]:rounded-none [&>*]:border-0 [&>*]:bg-transparent [&>*]:dark:bg-transparent">
<div className="min-w-0 divide-y divide-slate-200 overflow-hidden rounded-xl border border-slate-200 bg-white [&>*]:rounded-none [&>*]:border-0 [&>*]:bg-transparent">
{children}
</div>
);
@@ -79,10 +81,10 @@ export const SettingsPane = ({
key: "general",
label: t("settings.tabs.general"),
icon: SlidersHorizontal,
colorClass: "text-emerald-700 dark:text-emerald-400",
bgColorClass: "bg-emerald-50/80 dark:bg-emerald-950/40",
hoverColorClass: "hover:bg-emerald-50/40 dark:hover:bg-emerald-950/20",
iconColorClass: "text-emerald-600 dark:text-emerald-400",
colorClass: "text-emerald-700",
bgColorClass: "bg-emerald-50/80",
hoverColorClass: "hover:bg-emerald-50/40",
iconColorClass: "text-emerald-600",
},
...(isOwner
? [
@@ -90,10 +92,10 @@ export const SettingsPane = ({
key: "users" as const,
label: t("users.title"),
icon: Users,
colorClass: "text-emerald-700 dark:text-emerald-400",
bgColorClass: "bg-emerald-50/80 dark:bg-emerald-950/40",
hoverColorClass: "hover:bg-emerald-50/40 dark:hover:bg-emerald-950/20",
iconColorClass: "text-emerald-600 dark:text-emerald-400",
colorClass: "text-emerald-700",
bgColorClass: "bg-emerald-50/80",
hoverColorClass: "hover:bg-emerald-50/40",
iconColorClass: "text-emerald-600",
},
]
: []),
@@ -101,28 +103,28 @@ export const SettingsPane = ({
key: "data",
label: t("settings.tabs.data"),
icon: Database,
colorClass: "text-emerald-700 dark:text-emerald-400",
bgColorClass: "bg-emerald-50/80 dark:bg-emerald-950/40",
hoverColorClass: "hover:bg-emerald-50/40 dark:hover:bg-emerald-950/20",
iconColorClass: "text-emerald-600 dark:text-emerald-400",
colorClass: "text-emerald-700",
bgColorClass: "bg-emerald-50/80",
hoverColorClass: "hover:bg-emerald-50/40",
iconColorClass: "text-emerald-600",
},
{
key: "ai",
label: t("settings.tabs.ai"),
icon: Sparkles,
colorClass: "text-emerald-700 dark:text-emerald-400",
bgColorClass: "bg-emerald-50/80 dark:bg-emerald-950/40",
hoverColorClass: "hover:bg-emerald-50/40 dark:hover:bg-emerald-950/20",
iconColorClass: "text-emerald-600 dark:text-emerald-400",
colorClass: "text-emerald-700",
bgColorClass: "bg-emerald-50/80",
hoverColorClass: "hover:bg-emerald-50/40",
iconColorClass: "text-emerald-600",
},
{
key: "account",
label: t("settings.tabs.account"),
icon: Shield,
colorClass: "text-emerald-700 dark:text-emerald-400",
bgColorClass: "bg-emerald-50/80 dark:bg-emerald-950/40",
hoverColorClass: "hover:bg-emerald-50/40 dark:hover:bg-emerald-950/20",
iconColorClass: "text-emerald-600 dark:text-emerald-400",
colorClass: "text-emerald-700",
bgColorClass: "bg-emerald-50/80",
hoverColorClass: "hover:bg-emerald-50/40",
iconColorClass: "text-emerald-600",
},
];
@@ -153,9 +155,9 @@ export const SettingsPane = ({
const HeaderIconColorClass = (() => {
if (activeMobileTab !== null) {
const activeItem = tabItems.find((item) => item.key === activeMobileTab);
return activeItem ? activeItem.iconColorClass : "text-emerald-700 dark:text-emerald-400";
return activeItem ? activeItem.iconColorClass : "text-emerald-700";
}
return "text-emerald-700 dark:text-emerald-400";
return "text-emerald-700";
})();
const renderTabContent = (key: TabKey) => {
@@ -205,8 +207,8 @@ export const SettingsPane = ({
};
return (
<div className="flex h-full min-h-0 min-w-0 flex-col overflow-x-hidden bg-slate-50 dark:bg-slate-900/40">
<header className="flex h-[calc(3.5rem+env(safe-area-inset-top))] shrink-0 items-end justify-between border-b border-slate-200 bg-white px-4 pb-3 pt-[env(safe-area-inset-top)] dark:border-slate-800 dark:bg-slate-950 lg:h-16 lg:items-center lg:px-6 lg:pb-0 lg:pt-0">
<div className="flex h-full min-h-0 min-w-0 flex-col overflow-x-hidden bg-slate-50">
<header className="flex h-[calc(3.5rem+env(safe-area-inset-top))] shrink-0 items-end justify-between border-b border-slate-200 bg-white px-4 pb-3 pt-[env(safe-area-inset-top)] lg:h-16 lg:items-center lg:px-6 lg:pb-0 lg:pt-0">
<div className="flex min-w-0 items-center gap-3">
<Button
size="icon"
@@ -214,21 +216,21 @@ export const SettingsPane = ({
title={t("common.back")}
aria-label={t("common.back")}
onClick={handleBack}
className="h-9 w-9 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-900"
className="h-9 w-9 rounded-lg hover:bg-slate-100"
>
<ChevronLeft className="h-5 w-5 text-slate-500" />
</Button>
<div className="min-w-0">
<h1 className={`flex items-center gap-2 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}>
<HeaderIcon className={cn("h-4 w-4 shrink-0 transition-colors", HeaderIconColorClass)} />
<span className="truncate text-slate-900 dark:text-slate-100">{getHeaderTitle()}</span>
<span className="truncate text-slate-900">{getHeaderTitle()}</span>
</h1>
</div>
</div>
<ThemeToggle className="inline-flex" showLabel />
</header>
<div className="flex flex-1 min-h-0 min-w-0 bg-slate-50/50 dark:bg-slate-900/20">
<div className="flex flex-1 min-h-0 min-w-0 bg-slate-50/50">
{/* 桌面端布局:双栏 */}
<div className="hidden lg:flex flex-1 min-h-0 min-w-0 mx-auto max-w-5xl px-6 py-6 gap-6">
{/* 左侧垂直 Tab 栏 */}
@@ -245,10 +247,10 @@ export const SettingsPane = ({
"flex items-center gap-3 px-3.5 py-2.5 rounded-xl text-sm font-semibold transition-all duration-150 text-left w-full",
isSelected
? `${item.colorClass} ${item.bgColorClass}`
: "text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-200 hover:bg-slate-200/50 dark:hover:bg-slate-800/50"
: "text-slate-600 hover:bg-slate-200/50 hover:text-slate-900"
)}
>
<Icon className={cn("h-4 w-4 shrink-0 transition-colors", isSelected ? item.colorClass : "text-slate-400 dark:text-slate-500")} />
<Icon className={cn("h-4 w-4 shrink-0 transition-colors", isSelected ? item.colorClass : "text-slate-400")} />
{item.label}
</button>
);
@@ -268,7 +270,7 @@ export const SettingsPane = ({
{activeMobileTab === null ? (
/* 分类主菜单 */
<div className="grid gap-2">
<div className="divide-y divide-slate-100 overflow-hidden rounded-2xl border border-slate-200 bg-white dark:divide-slate-800 dark:border-slate-800 dark:bg-slate-950">
<div className="divide-y divide-slate-100 overflow-hidden rounded-2xl border border-slate-200 bg-white">
{tabItems.map((item) => {
const Icon = item.icon;
return (
@@ -276,15 +278,15 @@ export const SettingsPane = ({
key={item.key}
type="button"
onClick={() => setActiveMobileTab(item.key)}
className="flex items-center justify-between gap-4 p-4 text-left hover:bg-slate-50/50 dark:hover:bg-slate-900/40 transition-colors w-full"
className="flex w-full items-center justify-between gap-4 p-4 text-left transition-colors hover:bg-slate-50/50"
>
<div className="flex items-center gap-3">
<div className={cn("flex h-8 w-8 items-center justify-center rounded-lg", item.bgColorClass)}>
<Icon className={cn("h-4 w-4", item.iconColorClass)} />
</div>
<span className="text-sm font-semibold text-slate-800 dark:text-slate-200">{item.label}</span>
<span className="text-sm font-semibold text-slate-800">{item.label}</span>
</div>
<ChevronRight className="h-4 w-4 text-slate-400 dark:text-slate-600" />
<ChevronRight className="h-4 w-4 text-slate-400" />
</button>
);
})}
@@ -29,7 +29,7 @@ type OperationKind = "export" | "import";
const Progress = ({ progress }: { progress: EdgeEverZipProgress }) => {
const percentage = progress.total > 0 ? Math.round((progress.completed / progress.total) * 100) : 0;
return (
<div className="h-1.5 overflow-hidden rounded-full bg-slate-200 dark:bg-slate-800">
<div className="h-1.5 overflow-hidden rounded-full bg-slate-200">
<div className="h-full rounded-full bg-emerald-600 transition-[width]" style={{ width: `${percentage}%` }} />
</div>
);
@@ -146,7 +146,7 @@ export const DataExportCard = () => {
</CardTitle>
</CardHeader>
<CardContent className="grid gap-3 p-4 pt-0">
<div className="grid gap-2 rounded-lg border border-slate-200 dark:border-slate-800 p-3 bg-white/40 dark:bg-slate-900/10 md:grid-cols-[minmax(0,1fr)_auto] md:items-center">
<div className="grid gap-2 rounded-lg border border-slate-200 bg-card/40 p-3 md:grid-cols-[minmax(0,1fr)_auto] md:items-center">
<div className="min-w-0">
<CardDescription className="text-xs leading-5">{t("dataExport.description")}</CardDescription>
</div>
@@ -125,7 +125,7 @@ export const SystemInfoCard = () => {
<Button
size="sm"
variant="outline"
className="h-8 w-full bg-white dark:bg-slate-950 px-3 text-xs sm:w-auto"
className="h-8 w-full bg-white px-3 text-xs sm:w-auto"
type="button"
onClick={() => void handleCopy()}
>
@@ -135,9 +135,9 @@ export const SystemInfoCard = () => {
</div>
<div className="grid gap-2 sm:grid-cols-2">
{infoItems.map((item) => (
<div key={item.label} className="min-w-0 rounded-lg border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900/30 px-3 py-2.5">
<div className="text-[11px] font-semibold uppercase text-slate-400 dark:text-slate-500">{item.label}</div>
<div className="mt-1 truncate font-mono text-xs font-semibold text-slate-800 dark:text-slate-200" title={item.value}>
<div key={item.label} className="min-w-0 rounded-lg border border-slate-200 bg-white px-3 py-2.5">
<div className="text-[11px] font-semibold uppercase text-slate-400">{item.label}</div>
<div className="mt-1 truncate font-mono text-xs font-semibold text-slate-800" title={item.value}>
{item.value}
</div>
</div>
@@ -87,17 +87,17 @@ export const UserManagementCard = () => {
<CardContent className="grid gap-2 p-4 pt-0">
{usersQuery.isLoading ? <p className="text-sm text-slate-500">{t("users.loading")}</p> : null}
{usersQuery.data?.users.map((user) => (
<div key={user.id} className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-slate-200 dark:border-slate-800 p-3 bg-white/40 dark:bg-slate-900/10">
<div key={user.id} className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-slate-200 bg-card/40 p-3">
<div className="min-w-0">
<p className="truncate text-sm font-semibold text-slate-800 dark:text-slate-200">{user.displayName || user.username}</p>
<p className="truncate text-xs text-slate-500 dark:text-slate-400">@{user.username} · {t(`users.roles.${user.role}`)}</p>
<p className="truncate text-sm font-semibold text-slate-800">{user.displayName || user.username}</p>
<p className="truncate text-xs text-slate-500">@{user.username} · {t(`users.roles.${user.role}`)}</p>
</div>
<div className="flex items-center gap-3">
<Button size="sm" variant="outline" onClick={() => setResetUser(user)}>
<KeyRound className="h-3.5 w-3.5" /> {t("users.resetPassword")}
</Button>
{user.role !== "owner" ? (
<label className="flex items-center gap-2 text-xs text-slate-600 dark:text-slate-400">
<label className="flex items-center gap-2 text-xs text-slate-600">
{user.isDisabled ? t("users.disabled") : t("users.enabled")}
<Switch
checked={!user.isDisabled}