fix: 共享页面全面适配 light/claude 主题配色

问题:非黑色背景的主题下,共享页面中的灰色/黑色硬编码颜色不协调

修复方案:
1. 扩展 CSS 变量体系:新增 --page-surface, --page-surface-hover,
   --page-divider, --page-inset, --page-success/warning/danger/info
2. .theme-light 和 .theme-claude 各自定义对应的浅色值
3. Tailwind 新增 text-page-success/warning/danger/info 语义色
4. 新增 CSS 工具类: bg-page-surface, hover:bg-page-surface-hover,
   border-page-divider, bg-page-inset

修改文件:
- index.css: 扩展 CSS 变量 + 工具类
- tailwind.config.js: 新增语义色 token
- Dashboard: SpotlightCard → 简单 glass 卡片,hover 色修复
- Pricing: border-white/hover-white → 主题感知类
- Tokens: bg-black/bg-neutral-800 → bg-page-inset/surface
- Topup: SpotlightCard → glass,hover/text 色修复
- ConfigExporter: 下拉菜单/代码预览区全面适配

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
abingyydsandClaude Sonnet 4.6 committed 2026-03-25 03:48:47 +09:00
1 parent 3b8206284f
commit b34e81bb58
7 files changed
+123 -61

No files matched your search

+10 -10
View File
@@ -258,7 +258,7 @@ print(message.content[0].text)`;
return (
<div className="glass rounded-2xl overflow-hidden">
{/* Header */}
<div className="px-5 py-4 border-b border-white/5">
<div className="px-5 py-4 border-b border-page-divider">
<h4 className="font-semibold text-sm text-page flex items-center gap-2">
<svg className="w-4 h-4 text-brand-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
@@ -316,14 +316,14 @@ print(message.content[0].text)`;
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
{modelDropdownOpen && (
<div className="absolute z-50 mt-1 w-full max-h-60 overflow-y-auto rounded-lg border border-white/10 bg-neutral-900 shadow-xl">
<div className="absolute z-50 mt-1 w-full max-h-60 overflow-y-auto rounded-lg glass shadow-xl">
{availableModels
.filter(m => m.toLowerCase().includes(modelSearch.toLowerCase()))
.map((model) => (
<button
key={model}
onClick={() => { setSelectedModel(model); setModelDropdownOpen(false); setModelSearch(''); }}
className={`w-full text-left px-3 py-2 text-sm transition-colors hover:bg-white/10 ${
className={`w-full text-left px-3 py-2 text-sm transition-colors hover:bg-page-surface-hover ${
model === selectedModel ? 'text-brand-400 bg-brand-500/10' : 'text-page-secondary'
}`}
>
@@ -351,7 +351,7 @@ print(message.content[0].text)`;
className={`px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${
selectedTool === tool.id
? 'bg-brand-500 text-white shadow-sm'
: 'bg-white/5 text-page-secondary hover:bg-white/10'
: 'bg-page-surface text-page-secondary hover:bg-page-surface-hover'
}`}
>
{tool.name}
@@ -362,8 +362,8 @@ print(message.content[0].text)`;
</div>
{/* Config Preview */}
<div className="border-t border-white/5">
<div className="flex items-center justify-between px-4 py-2.5 bg-black/20">
<div className="border-t border-page-divider">
<div className="flex items-center justify-between px-4 py-2.5 bg-page-inset">
<div className="flex items-center gap-2">
<div className="flex gap-1.5">
<span className="w-2.5 h-2.5 rounded-full bg-red-400" />
@@ -377,25 +377,25 @@ print(message.content[0].text)`;
<div className="flex items-center gap-2">
<button
onClick={handleCopy}
className="p-1.5 rounded-md hover:bg-white/10 transition-colors text-page-muted hover:text-page"
className="p-1.5 rounded-md hover:bg-page-surface-hover transition-colors text-page-muted hover:text-page"
title={t('config.copy')}
>
{copied ? (
<svg className="w-3.5 h-3.5 text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /></svg>
<svg className="w-3.5 h-3.5 text-page-success" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /></svg>
) : (
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" /></svg>
)}
</button>
<button
onClick={handleDownload}
className="p-1.5 rounded-md hover:bg-white/10 transition-colors text-page-muted hover:text-page"
className="p-1.5 rounded-md hover:bg-page-surface-hover transition-colors text-page-muted hover:text-page"
title={t('config.download')}
>
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>
</button>
</div>
</div>
<pre className="p-4 text-xs leading-relaxed overflow-x-auto max-h-64 font-mono text-green-400">
<pre className="p-4 text-xs leading-relaxed overflow-x-auto max-h-64 font-mono text-page-success">
<code>{config}</code>
</pre>
</div>
+66 -3
View File
@@ -5,16 +5,30 @@
@layer base {
:root {
--brand: 99 102 241;
/* Light theme text colors (overridden by .theme-light) */
/* Text colors */
--page-text: 255 255 255;
--page-text-secondary: 163 163 163;
--page-text-muted: 115 115 115;
--page-label: 212 212 212;
--page-link: 129 140 248;
/* Surface colors */
--page-card-bg: rgba(255,255,255,0.03);
--page-card-border: rgba(255,255,255,0.06);
--page-input-bg: rgba(255,255,255,0.04);
--page-input-border: rgba(255,255,255,0.1);
--page-link: 129 140 248;
--page-surface: rgba(255,255,255,0.04);
--page-surface-hover: rgba(255,255,255,0.08);
--page-divider: rgba(255,255,255,0.06);
--page-inset: rgba(0,0,0,0.4);
/* Semantic colors — dark mode defaults */
--page-success: 74 222 128;
--page-success-text: 74 222 128;
--page-warning: 250 204 21;
--page-warning-text: 253 224 71;
--page-danger: 248 113 113;
--page-danger-text: 248 113 113;
--page-info: 192 132 252;
--page-info-text: 192 132 252;
}
body {
@@ -46,15 +60,33 @@
--page-text-secondary: 107 114 128;
--page-text-muted: 156 163 175;
--page-label: 55 65 81;
--page-link: 79 70 229;
--page-card-bg: rgba(255,255,255,0.85);
--page-card-border: rgb(229,231,235);
--page-input-bg: #fff;
--page-input-border: rgb(209,213,219);
--page-link: 79 70 229;
--page-surface: rgba(0,0,0,0.03);
--page-surface-hover: rgba(0,0,0,0.06);
--page-divider: rgb(229,231,235);
--page-inset: rgba(0,0,0,0.04);
--page-success: 22 163 74;
--page-success-text: 22 163 74;
--page-warning: 202 138 4;
--page-warning-text: 161 98 7;
--page-danger: 220 38 38;
--page-danger-text: 220 38 38;
--page-info: 124 58 237;
--page-info-text: 124 58 237;
}
.theme-claude {
--page-link: 217 119 87;
--page-card-bg: rgba(255,255,255,0.7);
--page-card-border: #E8DDD0;
--page-surface: rgba(61,48,36,0.04);
--page-surface-hover: rgba(61,48,36,0.08);
--page-divider: #E8DDD0;
--page-inset: rgba(61,48,36,0.06);
}
}
@@ -182,3 +214,34 @@
.theme-claude .btn-secondary:hover {
background-color: rgba(217,119,87,0.05);
}
/* ═══════════════════════════════════════════════
Theme-aware utility classes for surfaces/dividers
═══════════════════════════════════════════════ */
.surface {
background: var(--page-surface);
}
.surface-hover:hover {
background: var(--page-surface-hover);
}
.bg-page-inset {
background: var(--page-inset);
}
.divide-page > * + * {
border-color: var(--page-divider);
}
.border-page-divider {
border-color: var(--page-divider);
}
.bg-page-surface {
background: var(--page-surface);
}
.bg-page-surface-hover {
background: var(--page-surface-hover);
}
.hover\:bg-page-surface:hover {
background: var(--page-surface);
}
.hover\:bg-page-surface-hover:hover {
background: var(--page-surface-hover);
}
+10 -14
View File
@@ -3,9 +3,7 @@ import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useAuth } from '../context/AuthContext';
import { getUserUsage, redeemCode, Q, quotaToDollar } from '../api';
import SpotlightCard from '../components/bits/SpotlightCard';
import CountUp from '../components/bits/CountUp';
import ShinyText from '../components/bits/ShinyText';
import toast from 'react-hot-toast';
export default function Dashboard() {
@@ -33,14 +31,12 @@ export default function Dashboard() {
if (res.data.success) {
toast.success(t('dashboard.redeemSuccess'));
setRedeemInput('');
// Refresh both usage AND user data to update balance
await Promise.all([loadUsage(), refreshUser()]);
}
} catch (err) { /* interceptor */ }
setRedeeming(false);
};
// Use usage data (fresh from API) for balance/used — NOT stale user object
const quota = usage?.quota ?? user?.quota ?? 0;
const usedQuota = usage?.used_quota ?? user?.used_quota ?? 0;
const requestCount = usage?.request_count ?? user?.request_count ?? 0;
@@ -51,35 +47,35 @@ export default function Dashboard() {
{/* Welcome */}
<div className="mb-8">
<h1 className="text-2xl font-heading font-bold text-page mb-1">
{t('dashboard.welcome')} <ShinyText text={user?.display_name || user?.username || 'User'} className="!inline" speed={3} color="#a5b4fc" shineColor="#e0e7ff" />
{t('dashboard.welcome')} {user?.display_name || user?.username || 'User'}
</h1>
<p className="text-sm text-page-secondary">{t('dashboard.manageDesc')}</p>
</div>
{/* Stats Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
<SpotlightCard className="!bg-neutral-900/60 !border-neutral-800/60 !p-6" spotlightColor="rgba(34,197,94,0.15)">
<div className="glass rounded-2xl p-6">
<p className="text-sm text-page-secondary mb-2">{t('dashboard.balance')}</p>
<div className="text-3xl font-bold text-page">
$<CountUp from={0} to={balanceDollars} duration={1.5} />
</div>
<p className="text-xs text-page-muted mt-1">{t('dashboard.quotaUnits', { count: quota.toLocaleString() })}</p>
</SpotlightCard>
</div>
<SpotlightCard className="!bg-neutral-900/60 !border-neutral-800/60 !p-6" spotlightColor="rgba(129,140,248,0.15)">
<div className="glass rounded-2xl p-6">
<p className="text-sm text-page-secondary mb-2">{t('dashboard.used')}</p>
<div className="text-3xl font-bold text-page">
$<CountUp from={0} to={usedQuota / Q} duration={1.5} />
</div>
<p className="text-xs text-page-muted mt-1">{t('dashboard.quotaUnits', { count: usedQuota.toLocaleString() })}</p>
</SpotlightCard>
</div>
<SpotlightCard className="!bg-neutral-900/60 !border-neutral-800/60 !p-6" spotlightColor="rgba(244,114,182,0.15)">
<div className="glass rounded-2xl p-6">
<p className="text-sm text-page-secondary mb-2">{t('dashboard.totalRequests')}</p>
<div className="text-3xl font-bold text-page">
<CountUp from={0} to={requestCount} duration={1.5} />
</div>
</SpotlightCard>
</div>
</div>
{/* Quick Actions */}
@@ -105,15 +101,15 @@ export default function Dashboard() {
<div className="glass rounded-2xl p-6">
<h2 className="text-lg font-semibold text-page mb-4">{t('dashboard.quickLinks')}</h2>
<div className="grid grid-cols-2 gap-3">
<Link to="/tokens" className="glass-sm !rounded-xl px-4 py-3 hover:bg-white/[0.06] transition-colors group">
<Link to="/tokens" className="glass-sm !rounded-xl px-4 py-3 hover:bg-page-surface-hover transition-colors group">
<p className="text-sm font-medium text-page group-hover:text-page-link transition-colors">{t('dashboard.apiKeys')}</p>
<p className="text-xs text-page-muted">{t('dashboard.manageKeys')}</p>
</Link>
<Link to="/packages" className="glass-sm !rounded-xl px-4 py-3 hover:bg-white/[0.06] transition-colors group">
<Link to="/packages" className="glass-sm !rounded-xl px-4 py-3 hover:bg-page-surface-hover transition-colors group">
<p className="text-sm font-medium text-page group-hover:text-page-link transition-colors">{t('dashboard.packages')}</p>
<p className="text-xs text-page-muted">{t('dashboard.viewPlans')}</p>
</Link>
<Link to="/pricing" className="glass-sm !rounded-xl px-4 py-3 hover:bg-white/[0.06] transition-colors group">
<Link to="/pricing" className="glass-sm !rounded-xl px-4 py-3 hover:bg-page-surface-hover transition-colors group">
<p className="text-sm font-medium text-page group-hover:text-page-link transition-colors">{t('dashboard.pricing')}</p>
<p className="text-xs text-page-muted">{t('dashboard.modelPrices')}</p>
</Link>
+6 -6
View File
@@ -73,7 +73,7 @@ export default function Pricing() {
className={`inline-flex items-center gap-1.5 px-3.5 py-2 rounded-xl text-sm font-medium transition-all ${
!vendor
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
: 'glass-sm text-page-secondary hover:text-page hover:bg-white/[0.08]'
: 'glass-sm text-page-secondary hover:text-page hover:bg-page-surface-hover'
}`}
>
{t('pricing.allVendors')}
@@ -85,7 +85,7 @@ export default function Pricing() {
className={`inline-flex items-center gap-1.5 px-3.5 py-2 rounded-xl text-sm font-medium transition-all ${
vendor === v.name
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
: 'glass-sm text-page-secondary hover:text-page hover:bg-white/[0.08]'
: 'glass-sm text-page-secondary hover:text-page hover:bg-page-surface-hover'
}`}
>
{v.name}
@@ -118,7 +118,7 @@ export default function Pricing() {
<div className="glass-sm rounded-xl overflow-hidden">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-white/[0.06]">
<tr className="border-b border-page-divider">
<th className="text-left px-5 py-3.5 font-medium text-page-secondary">{t('pricing.model')}</th>
<th className="text-right px-5 py-3.5 font-medium text-page-secondary">{t('pricing.inputPrice')}</th>
<th className="text-right px-5 py-3.5 font-medium text-page-secondary">{t('pricing.outputPrice')}</th>
@@ -127,7 +127,7 @@ export default function Pricing() {
</thead>
<tbody>
{filtered.map((m, i) => (
<tr key={m.model_name || i} className="border-b border-white/[0.04] last:border-0 hover:bg-white/[0.02] transition-colors">
<tr key={m.model_name || i} className="border-b border-page-divider last:border-0 hover:bg-page-surface transition-colors">
<td className="px-5 py-3.5">
<span className="font-mono text-page">{m.display_name || m.model_name}</span>
</td>
@@ -140,8 +140,8 @@ export default function Pricing() {
<td className="px-5 py-3.5 text-center">
<span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs border ${
m.status === 'healthy'
? 'bg-green-500/10 text-green-400 border-green-500/20'
: 'bg-neutral-500/10 text-page-secondary border-neutral-500/20'
? 'bg-green-500/10 text-page-success border-green-500/20'
: 'bg-page-surface text-page-secondary border-page-divider'
}`}>
<span className={`w-1.5 h-1.5 rounded-full ${m.status === 'healthy' ? 'bg-green-500' : 'bg-neutral-500'}`} />
{m.status === 'healthy' ? t('pricing.online') : t('pricing.unknown')}
+11 -11
View File
@@ -149,12 +149,12 @@ export default function Tokens() {
<div className="glass rounded-2xl p-6 w-full max-w-lg">
<h2 className="text-lg font-semibold text-page mb-2">{t('tokens.newApiKey')}</h2>
<div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl p-3 mb-4">
<p className="text-sm text-yellow-300">
<p className="text-sm text-page-warning">
{t('tokens.keyWarning')}
</p>
</div>
<div className="bg-black/40 rounded-xl p-4 flex items-center gap-3">
<code className="text-sm font-mono text-green-400 flex-1 break-all select-all">
<div className="bg-page-inset rounded-xl p-4 flex items-center gap-3">
<code className="text-sm font-mono text-page-success flex-1 break-all select-all">
{newKey}
</code>
<button
@@ -194,8 +194,8 @@ export default function Tokens() {
{/* Token List */}
{tokens.length === 0 ? (
<div className="glass rounded-2xl p-12 text-center">
<div className="w-16 h-16 mx-auto mb-4 rounded-2xl bg-neutral-800/50 flex items-center justify-center">
<svg className="w-8 h-8 text-neutral-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<div className="w-16 h-16 mx-auto mb-4 rounded-2xl bg-page-surface flex items-center justify-center">
<svg className="w-8 h-8 text-page-muted" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
</svg>
</div>
@@ -210,7 +210,7 @@ export default function Tokens() {
<div key={token.id} className="glass-sm rounded-xl p-5">
<div className="flex items-center gap-4">
{/* Status dot */}
<div className={`w-2.5 h-2.5 rounded-full flex-shrink-0 ${token.status === 1 ? 'bg-green-500' : 'bg-neutral-600'}`} />
<div className={`w-2.5 h-2.5 rounded-full flex-shrink-0 ${token.status === 1 ? 'bg-green-500' : 'bg-page-muted'}`} />
{/* Info */}
<div className="flex-1 min-w-0">
@@ -228,15 +228,15 @@ export default function Tokens() {
onClick={() => handleToggle(token)}
className={`px-3 py-1 text-xs rounded-lg border transition-colors ${
token.status === 1
? 'border-green-500/30 text-green-400 hover:bg-green-500/10'
: 'border-neutral-600 text-page-secondary hover:bg-neutral-800'
? 'border-green-500/30 text-page-success hover:bg-green-500/10'
: 'border-page-divider text-page-secondary hover:bg-page-surface-hover'
}`}
>
{token.status === 1 ? t('tokens.enabled') : t('tokens.disabled')}
</button>
<button
onClick={() => setDeleteConfirm(token)}
className="px-3 py-1 text-xs rounded-lg border border-red-500/20 text-red-400 hover:bg-red-500/10 transition-colors"
className="px-3 py-1 text-xs rounded-lg border border-red-500/20 text-page-danger hover:bg-red-500/10 transition-colors"
>
{t('tokens.delete')}
</button>
@@ -245,13 +245,13 @@ export default function Tokens() {
{/* Key row — always visible with copy button */}
{token.key && (
<div className="mt-3 flex items-center gap-2 bg-black/30 rounded-lg px-3 py-2">
<div className="mt-3 flex items-center gap-2 bg-page-inset rounded-lg px-3 py-2">
<code className="text-xs font-mono text-page-muted flex-1 break-all select-all">
sk-{token.key}
</code>
<button
onClick={() => handleCopy('sk-' + token.key)}
className="flex-shrink-0 px-2.5 py-1 text-xs rounded-md bg-white/10 text-page-secondary hover:bg-white/20 hover:text-page transition-colors"
className="flex-shrink-0 px-2.5 py-1 text-xs rounded-md bg-page-surface text-page-secondary hover:bg-page-surface-hover hover:text-page transition-colors"
>
{copiedId === 'sk-' + token.key ? t('tokens.copied') : t('tokens.copy')}
</button>
+16 -17
View File
@@ -8,7 +8,6 @@ import {
createCryptoOrder, getCryptoOrderStatus, getTopupHistory,
Q, quotaToDollar,
} from '../api';
import SpotlightCard from '../components/bits/SpotlightCard';
import CountUp from '../components/bits/CountUp';
import toast from 'react-hot-toast';
@@ -322,27 +321,27 @@ export default function Topup() {
{/* Balance Stats */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
<SpotlightCard className="!bg-neutral-900/60 !border-neutral-800/60 !p-6" spotlightColor="rgba(34,197,94,0.15)">
<div className="glass rounded-2xl p-6">
<p className="text-sm text-page-secondary mb-2">{t('dashboard.balance')}</p>
<div className="text-3xl font-bold text-page">
$<CountUp from={0} to={balanceDollars} duration={1.5} />
</div>
<p className="text-xs text-page-muted mt-1">{t('dashboard.quotaUnits', { count: quota.toLocaleString() })}</p>
</SpotlightCard>
</div>
<SpotlightCard className="!bg-neutral-900/60 !border-neutral-800/60 !p-6" spotlightColor="rgba(129,140,248,0.15)">
<div className="glass rounded-2xl p-6">
<p className="text-sm text-page-secondary mb-2">{t('dashboard.used')}</p>
<div className="text-3xl font-bold text-page">
$<CountUp from={0} to={usedQuota / Q} duration={1.5} />
</div>
</SpotlightCard>
</div>
<SpotlightCard className="!bg-neutral-900/60 !border-neutral-800/60 !p-6" spotlightColor="rgba(244,114,182,0.15)">
<div className="glass rounded-2xl p-6">
<p className="text-sm text-page-secondary mb-2">{t('dashboard.totalRequests')}</p>
<div className="text-3xl font-bold text-page">
<CountUp from={0} to={requestCount} duration={1.5} />
</div>
</SpotlightCard>
</div>
</div>
{/* Online Topup - EPay & Stripe */}
@@ -369,7 +368,7 @@ export default function Topup() {
className={`py-2.5 px-3 rounded-xl text-sm font-medium transition-all ${
selectedPreset === val
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
: 'glass-sm text-page-label hover:text-page hover:bg-white/[0.08]'
: 'glass-sm text-page-label hover:text-page hover:bg-page-surface-hover'
}`}
>
${val}
@@ -399,7 +398,7 @@ export default function Topup() {
<p className="text-xs text-page-muted mt-2">{t('topup.calculating')}</p>
) : payAmount ? (
<p className="text-xs text-page-secondary mt-2">
{t('topup.payAmountLabel')}: <span className="text-green-400 font-medium">¥{payAmount}</span>
{t('topup.payAmountLabel')}: <span className="text-page-success font-medium">¥{payAmount}</span>
</p>
) : null}
</div>
@@ -415,7 +414,7 @@ export default function Topup() {
key={method.type}
onClick={() => handlePay(method.type)}
disabled={paymentLoading || !amount}
className="px-4 py-2.5 rounded-xl text-sm font-medium glass-sm text-page-label hover:text-page hover:bg-white/[0.08] disabled:opacity-40 disabled:cursor-not-allowed transition-all"
className="px-4 py-2.5 rounded-xl text-sm font-medium glass-sm text-page-label hover:text-page hover:bg-page-surface-hover disabled:opacity-40 disabled:cursor-not-allowed transition-all"
>
{isCurrentLoading ? t('topup.processing') : method.name}
</button>
@@ -437,12 +436,12 @@ export default function Topup() {
className={`glass-sm rounded-xl p-4 cursor-pointer transition-all ${
selectedCreemProduct?.productId === product.productId
? 'ring-2 ring-brand-500 bg-brand-500/10'
: 'hover:bg-white/[0.06]'
: 'hover:bg-page-surface'
}`}
onClick={() => setSelectedCreemProduct(product)}
>
<h3 className="text-sm font-semibold text-page mb-1">{product.name}</h3>
<p className="text-xl font-bold text-green-400 mb-1">
<p className="text-xl font-bold text-page-success mb-1">
${product.price} <span className="text-xs text-page-muted font-normal">{product.currency || 'USD'}</span>
</p>
{product.quota && (
@@ -499,7 +498,7 @@ export default function Topup() {
className={`px-4 py-2 rounded-xl text-sm font-medium transition-all ${
selectedChain === chain.key
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
: 'glass-sm text-page-label hover:text-page hover:bg-white/[0.08]'
: 'glass-sm text-page-label hover:text-page hover:bg-page-surface-hover'
}`}
>
{chain.label}
@@ -519,7 +518,7 @@ export default function Topup() {
className={`px-4 py-2 rounded-xl text-sm font-medium transition-all ${
selectedToken === token
? 'bg-brand-500 text-white shadow-lg shadow-brand-500/25'
: 'glass-sm text-page-label hover:text-page hover:bg-white/[0.08]'
: 'glass-sm text-page-label hover:text-page hover:bg-page-surface-hover'
}`}
>
{token.toUpperCase()}
@@ -599,10 +598,10 @@ export default function Topup() {
</div>
<span className={`text-xs px-2 py-1 rounded-full ${
item.status === 'success'
? 'bg-green-500/10 text-green-400'
? 'bg-green-500/10 text-page-success'
: item.status === 'pending'
? 'bg-yellow-500/10 text-yellow-400'
: 'bg-red-500/10 text-red-400'
? 'bg-yellow-500/10 text-page-warning'
: 'bg-red-500/10 text-page-danger'
}`}>
{item.status === 'success' ? t('topup.statusSuccess') : item.status === 'pending' ? t('topup.statusPending') : t('topup.statusFailed')}
</span>
+4
View File
@@ -37,6 +37,10 @@ export default {
muted: 'rgb(var(--page-text-muted) / <alpha-value>)',
label: 'rgb(var(--page-label) / <alpha-value>)',
link: 'rgb(var(--page-link) / <alpha-value>)',
success: 'rgb(var(--page-success-text) / <alpha-value>)',
warning: 'rgb(var(--page-warning-text) / <alpha-value>)',
danger: 'rgb(var(--page-danger-text) / <alpha-value>)',
info: 'rgb(var(--page-info-text) / <alpha-value>)',
},
},
animation: {