style(frontend): remove hardcoded indigo colors in settings components

Replace all manual bg-indigo and text-indigo overrides with standard CSS variables such as bg-primary/10 and text-primary across common settings modules to support theme integration.
This commit is contained in:
ryan
2026-06-28 11:31:20 +08:00
parent 9c7896df50
commit fb54d6da61
8 changed files with 43 additions and 43 deletions
@@ -85,7 +85,7 @@ export function AdminSettingsPageClient() {
if (loading || !user || !user.is_admin) {
return (
<div className="flex items-center justify-center min-h-[400px]">
<Loader2 className="size-6 animate-spin text-indigo-500" />
<Loader2 className="size-6 animate-spin text-primary" />
</div>
)
}
@@ -194,7 +194,7 @@ export function AccessTokenMain() {
<CardContent className="pt-6 space-y-4">
{accessTokensQuery.isPending ? (
<div className="flex items-center justify-center py-8">
<Loader2 className="size-6 animate-spin text-indigo-500" />
<Loader2 className="size-6 animate-spin text-primary" />
</div>
) : (accessTokensQuery.data ?? []).length > 0 ? (
<div className="space-y-3">
@@ -231,7 +231,7 @@ export function AccessTokenMain() {
type="button"
variant="outline"
size="sm"
className="text-xs border-dashed text-muted-foreground hover:text-indigo-500 hover:bg-indigo-500/5 rounded-lg h-8 px-2.5"
className="text-xs border-dashed text-muted-foreground hover:text-primary hover:bg-primary/5 rounded-lg h-8 px-2.5"
onClick={() => handleCopyText(token.masked_token, token.id)}
>
{copiedId === token.id ? (
@@ -245,7 +245,7 @@ export function AccessTokenMain() {
type="button"
variant="outline"
size="sm"
className="text-xs border-dashed text-muted-foreground hover:text-indigo-500 hover:bg-indigo-500/5 rounded-lg h-8 px-2.5"
className="text-xs border-dashed text-muted-foreground hover:text-primary hover:bg-primary/5 rounded-lg h-8 px-2.5"
onClick={() => handleRotateToken(token.id, token.name)}
disabled={rotateTokenMutation.isPending}
>
@@ -305,7 +305,7 @@ export function AccessTokenMain() {
value={tokenName}
onChange={(e) => setTokenName(e.target.value)}
disabled={createTokenMutation.isPending}
className="rounded-xl border border-dashed focus:border-indigo-500 focus:ring-0 focus-visible:ring-0"
className="rounded-xl border border-dashed focus:border-primary focus:ring-0 focus-visible:ring-0"
/>
</div>
{user?.is_admin && (
@@ -375,15 +375,15 @@ export function AccessTokenMain() {
{newCreatedToken && (
<div className="space-y-4 py-2">
{/* 明文 Token 文本框 */}
<div className="flex items-center gap-2 rounded-xl bg-indigo-500/5 border border-dashed border-indigo-500/30 p-3">
<span className="font-mono text-xs select-all break-all flex-1 text-indigo-600 font-semibold leading-relaxed">
<div className="flex items-center gap-2 rounded-xl bg-primary/5 border border-dashed border-primary/30 p-3">
<span className="font-mono text-xs select-all break-all flex-1 text-primary font-semibold leading-relaxed">
{newCreatedToken.token}
</span>
<Button
type="button"
size="icon"
variant="outline"
className="size-8 rounded-lg shrink-0 border-dashed text-indigo-500 hover:bg-indigo-500/10 hover:border-indigo-500/30 transition-colors"
className="size-8 rounded-lg shrink-0 border-dashed text-primary hover:bg-primary/10 hover:border-primary/30 transition-colors"
onClick={() => handleCopyText(newCreatedToken.token, 9999)}
>
{copiedId === 9999 ? (
@@ -88,7 +88,7 @@ export function OperationTab({ configs, systemConfigsQuery }: OperationTabProps)
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4">
<div className="flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<KeyRound className="size-4" />
</div>
<div>
@@ -125,9 +125,9 @@ export function OperationTab({ configs, systemConfigsQuery }: OperationTabProps)
</div>
{/* 当前白名单列表 */}
<div className="rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-indigo-500/30 transition-all duration-300 shadow-sm space-y-3">
<div className="rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-primary/30 transition-all duration-300 shadow-sm space-y-3">
<div className="flex items-center gap-2">
<ShieldAlert className="size-4 text-indigo-500" />
<ShieldAlert className="size-4 text-primary" />
<span className="font-medium text-sm text-foreground">当前免鉴权列表</span>
</div>
@@ -137,14 +137,14 @@ export function OperationTab({ configs, systemConfigsQuery }: OperationTabProps)
<Badge
key={type}
variant="secondary"
className="px-2.5 py-1 text-xs gap-1.5 flex items-center bg-indigo-500/10 text-indigo-700 dark:text-indigo-300 dark:bg-indigo-500/20 border border-indigo-500/20"
className="px-2.5 py-1 text-xs gap-1.5 flex items-center bg-primary/10 text-primary dark:bg-primary/20 border border-primary/20"
>
{availableTypes.find(t => t.value === type)?.label || type}
<button
type="button"
onClick={() => handleRemoveType(type)}
disabled={updateWhitelistMutation.isPending || systemConfigsQuery.isPending}
className="rounded-full outline-hidden hover:bg-indigo-500/20 p-0.5 text-indigo-600 dark:text-indigo-400 cursor-pointer disabled:cursor-not-allowed"
className="rounded-full outline-hidden hover:bg-primary/20 p-0.5 text-primary cursor-pointer disabled:cursor-not-allowed"
>
<X className="size-3" />
</button>
@@ -112,7 +112,7 @@ export function OtherTab({ configs }: OtherTabProps) {
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4">
<div className="flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<LayoutList className="size-4" />
</div>
<div>
@@ -141,11 +141,11 @@ export function OtherTab({ configs }: OtherTabProps) {
return (
<div
key={item.path}
className="flex items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-indigo-500/30 transition-all duration-300 shadow-sm"
className="flex items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-primary/30 transition-all duration-300 shadow-sm"
>
<div className="space-y-1.5 flex-1 min-w-0 pr-2">
<div className="flex items-center gap-2">
{Icon && <Icon className="size-4 text-indigo-500 shrink-0" />}
{Icon && <Icon className="size-4 text-primary shrink-0" />}
<span className="font-medium text-sm text-foreground truncate">{item.label}</span>
{isReadOnly && (
<span className="text-[9px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground border shrink-0">
@@ -171,8 +171,8 @@ export function OtherTab({ configs }: OtherTabProps) {
</div>
))}
<div className="p-3.5 rounded-lg border border-dashed border-indigo-500/20 bg-indigo-500/5 flex items-start gap-2.5">
<Info className="size-4 text-indigo-500 shrink-0 mt-0.5" />
<div className="p-3.5 rounded-lg border border-dashed border-primary/20 bg-primary/5 flex items-start gap-2.5">
<Info className="size-4 text-primary shrink-0 mt-0.5" />
<div className="text-xs text-muted-foreground leading-relaxed">
<span className="font-semibold text-foreground">安全提示:</span>
为了防止管理员在关闭“系统设置”后导致无法重新访问此配置页,系统限制了“系统设置”的关闭权限。其它所有菜单均可自由开关,隐藏后对应的分组标题在为空时也会自动隐藏。
@@ -275,7 +275,7 @@ export function ProfileMain() {
>
<Avatar className="size-20 md:size-24 border-2 border-primary/10 shadow-md">
<AvatarImage src={user.avatar_url} alt={user.nickname || user.username} />
<AvatarFallback className="text-2xl bg-indigo-600 text-white font-bold">
<AvatarFallback className="text-2xl bg-primary text-primary-foreground font-bold">
{(user.nickname || user.username).slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
@@ -342,7 +342,7 @@ export function ProfileMain() {
href={user.website.startsWith("http") ? user.website : `http://${user.website}`}
target="_blank"
rel="noopener noreferrer"
className="text-indigo-600 hover:underline"
className="text-primary hover:underline"
>
{user.website}
</a>
@@ -473,7 +473,7 @@ export function ProfileMain() {
<div className="space-y-6 bg-card border border-dashed rounded-lg p-6 flex flex-col justify-between">
<div>
<div className="border-b pb-4 flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<Link2 className="size-4" />
</div>
<div>
@@ -487,7 +487,7 @@ export function ProfileMain() {
<h3 className="text-[11px] font-semibold text-muted-foreground uppercase tracking-wider">已绑定账号</h3>
{externalAccountBindingsQuery.isPending ? (
<div className="flex items-center justify-center py-4">
<Loader2 className="size-4 animate-spin text-indigo-500" />
<Loader2 className="size-4 animate-spin text-primary" />
</div>
) : (externalAccountBindingsQuery.data ?? []).length > 0 ? (
<div className="space-y-2">
@@ -534,7 +534,7 @@ export function ProfileMain() {
<h3 className="text-[11px] font-semibold text-muted-foreground uppercase tracking-wider">绑定新账号</h3>
{publicAuthSourcesQuery.isPending ? (
<div className="flex items-center justify-center py-4">
<Loader2 className="size-4 animate-spin text-indigo-500" />
<Loader2 className="size-4 animate-spin text-primary" />
</div>
) : (publicAuthSourcesQuery.data ?? []).length > 0 ? (
<div className="grid grid-cols-1 gap-2">
@@ -543,16 +543,16 @@ export function ProfileMain() {
key={source.id}
type="button"
variant="outline"
className="flex items-center justify-between w-full border border-dashed rounded-xl px-3 py-2 text-left font-normal text-xs hover:bg-indigo-500/5 hover:text-indigo-500 hover:border-indigo-500/30 transition-all duration-300 group h-8"
className="flex items-center justify-between w-full border border-dashed rounded-xl px-3 py-2 text-left font-normal text-xs hover:bg-primary/5 hover:text-primary hover:border-primary/30 transition-all duration-300 group h-8"
onClick={() => {
void bindSourceMutation.mutateAsync(source.name)
}}
>
<div className="flex items-center gap-1.5">
<Link2 className="size-3 text-muted-foreground group-hover:text-indigo-500" />
<Link2 className="size-3 text-muted-foreground group-hover:text-primary" />
<span>绑定 {source.display_name || source.name}</span>
</div>
<ArrowRight className="size-3 opacity-0 -translate-x-1 group-hover:opacity-100 group-hover:translate-x-0 transition-all text-indigo-500" />
<ArrowRight className="size-3 opacity-0 -translate-x-1 group-hover:opacity-100 group-hover:translate-x-0 transition-all text-primary" />
</Button>
))}
</div>
@@ -583,7 +583,7 @@ export function ProfileMain() {
>
<Avatar className="size-20 border-2 border-primary/5 shadow-md">
<AvatarImage src={avatarUrl} alt={nickname} />
<AvatarFallback className="text-xl bg-indigo-600 text-white font-bold">
<AvatarFallback className="text-xl bg-primary text-primary-foreground font-bold">
{(nickname || "U").slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
@@ -245,7 +245,7 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4">
<div className="flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<Settings className="size-4" />
</div>
<div>
@@ -263,11 +263,11 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
return (
<div
key={item.key}
className="flex items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-indigo-500/30 transition-all duration-300 shadow-sm"
className="flex items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-primary/30 transition-all duration-300 shadow-sm"
>
<div className="space-y-1">
<div className="flex items-center gap-2">
{Icon && <Icon className="size-4 text-indigo-500" />}
{Icon && <Icon className="size-4 text-primary" />}
<span className="font-medium text-sm text-foreground">{item.title}</span>
</div>
<p className="text-xs text-muted-foreground leading-relaxed pr-2">{item.description}</p>
@@ -283,11 +283,11 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
{/* 登录状态保持时间 (选择后立即更改) */}
<div
className="flex items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-indigo-500/30 transition-all duration-300 shadow-sm md:col-span-2"
className="flex items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-primary/30 transition-all duration-300 shadow-sm md:col-span-2"
>
<div className="space-y-1 pr-4">
<div className="flex items-center gap-2">
<Clock className="size-4 text-indigo-500" />
<Clock className="size-4 text-primary" />
<span className="font-medium text-sm text-foreground">登录状态保持时间</span>
</div>
<p className="text-xs text-muted-foreground leading-relaxed pr-2">
@@ -340,7 +340,7 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4 flex flex-row items-center justify-between gap-4">
<div className="flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<Globe className="size-4" />
</div>
<div>
@@ -390,7 +390,7 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
<div className="flex items-center gap-4">
<span className={`text-xs px-2.5 py-1 rounded-lg border font-medium hidden sm:inline-block ${
source.client_secret_configured
? "bg-indigo-500/5 text-indigo-500 border-indigo-500/10"
? "bg-primary/5 text-primary border-primary/10"
: "bg-rose-500/5 text-rose-500 border-rose-500/10"
}`}>
{source.client_secret_configured ? "Secret 已配置" : "Secret 未配置"}
@@ -407,7 +407,7 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
type="button"
variant="ghost"
size="icon"
className="size-8 text-muted-foreground hover:text-indigo-500 hover:bg-indigo-500/10 rounded-lg transition-colors"
className="size-8 text-muted-foreground hover:text-primary hover:bg-primary/10 rounded-lg transition-colors"
onClick={() => {
setSelectedSource(source)
setAuthSourceModalOpen(true)
@@ -458,7 +458,7 @@ export function SecurityTab({ configs, systemConfigsQuery }: SecurityTabProps) {
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4 flex flex-row items-center justify-between gap-4">
<div className="flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<Shield className="size-4" />
</div>
<div>
@@ -193,7 +193,7 @@ export function SystemTab({ configs, systemConfigsQuery }: SystemTabProps) {
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4">
<div className="flex items-center gap-2">
<div className="rounded-lg bg-indigo-500/10 p-1.5 text-indigo-500">
<div className="rounded-lg bg-primary/10 p-1.5 text-primary">
<Server className="size-4" />
</div>
<div>
@@ -310,7 +310,7 @@ export function SystemTab({ configs, systemConfigsQuery }: SystemTabProps) {
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4">
<div className="flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<Mail className="size-4" />
</div>
<div>
@@ -124,7 +124,7 @@ export function TemplatesManager() {
<Card className="border border-dashed shadow-sm">
<CardHeader className="border-b border-dashed pb-4 flex flex-row items-center justify-between gap-4">
<div className="flex items-center gap-2">
<div className="p-1.5 rounded-lg bg-indigo-500/10 text-indigo-500">
<div className="p-1.5 rounded-lg bg-primary/10 text-primary">
<FileText className="size-4" />
</div>
<div>
@@ -154,14 +154,14 @@ export function TemplatesManager() {
{(templatesQuery.data ?? []).map((tmpl) => (
<div
key={tmpl.id}
className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-indigo-500/30 transition-all duration-300 shadow-sm"
className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 rounded-xl border border-dashed p-4 bg-card hover:bg-muted/10 hover:border-primary/30 transition-all duration-300 shadow-sm"
>
<div className="space-y-1.5">
<div className="flex items-center gap-2 flex-wrap">
<span className="font-semibold text-sm text-foreground">{tmpl.name}</span>
<span className={`text-[10px] px-2 py-0.5 rounded-full border font-medium ${
tmpl.is_system
? "bg-indigo-500/10 text-indigo-500 border-indigo-500/20"
? "bg-primary/10 text-primary border-primary/20"
: "bg-amber-500/10 text-amber-500 border-amber-500/20"
}`}>
{tmpl.is_system ? "系统内置" : "自定义"}
@@ -171,7 +171,7 @@ export function TemplatesManager() {
</span>
</div>
<div className="text-xs text-muted-foreground">
标识符: <span className="font-mono text-indigo-500 bg-indigo-500/5 px-1.5 py-0.5 rounded">{tmpl.key}</span>
标识符: <span className="font-mono text-primary bg-primary/5 px-1.5 py-0.5 rounded">{tmpl.key}</span>
{tmpl.subject && ` · 主题: ${tmpl.subject}`}
</div>
{tmpl.description && (
@@ -185,7 +185,7 @@ export function TemplatesManager() {
type="button"
variant="ghost"
size="icon"
className="size-8 text-muted-foreground hover:text-indigo-500 hover:bg-indigo-500/10 rounded-lg transition-colors"
className="size-8 text-muted-foreground hover:text-primary hover:bg-primary/10 rounded-lg transition-colors"
onClick={() => handleOpenEdit(tmpl)}
>
<Pencil className="size-4" />