✨ style(web): unify design system across default frontend
🔤 Typography - Fix --font-sans stack: 'Public Sans Variable' was never applied (wrong family name), add CJK fallbacks (PingFang SC / Microsoft YaHei UI / Noto Sans SC) - Sync <html lang> with i18n language for correct CJK glyph selection - Remove dead fake font system (font-provider.tsx, config/fonts.ts, --font-inter/--font-manrope) - Typography contract: 3-tier headings, arbitrary text-[10px]/[11px] → text-xs (46 files), no uppercase table headers, font-bold → font-semibold - Numbers use tabular-nums only; font-mono reserved for keys/IDs/code (29 files) 🎨 Color discipline - Retire StatusBadge string-hash rainbow (autoColor → neutral); all variants resolve to 5 semantic voices - Add tintedBadgeClassMap as the single tinted-pill recipe - Replace hardcoded emerald/amber/rose/sky classes with semantic tokens across ~30 files (timing badges, progress bars, system panels, pricing, rankings, log row tints) - Drop all !important text overrides and [font-family:var(--font-body)] hacks 🧘 Motion restraint - Remove admin entrance animations: table row stagger, card hover lift/shadow, button press scale, dashboard shimmer line - Neuter page-transition stagger components into plain wrappers; page transitions reduced to pure opacity fade - Decorative motion stays landing-only 📐 Shape - Single radius source: --radius 1rem → 0.625rem - Sparklines use solid chart tokens instead of decorative gradients - PanelWrapper: border-only (no shadow), align radius with Card 📏 Guardrails - Add "Design System Discipline" section (3.10.1) to web/default/AGENTS.md ✅ Verified: tsgo typecheck clean, rsbuild production build passes
This commit is contained in:
@@ -62,19 +62,19 @@ function formatGroupRatio(
|
||||
|
||||
function getRatioBadgeClassName(ratio: ApiKeyGroupOption['ratio']) {
|
||||
if (typeof ratio !== 'number') {
|
||||
return 'border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-300'
|
||||
return 'border-success/25 bg-success/10 text-success'
|
||||
}
|
||||
|
||||
if (ratio > 5) {
|
||||
return 'border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-900/60 dark:bg-rose-950/40 dark:text-rose-300'
|
||||
return 'border-destructive/25 bg-destructive/10 text-destructive'
|
||||
}
|
||||
if (ratio > 3) {
|
||||
return 'border-orange-200 bg-orange-50 text-orange-700 dark:border-orange-900/60 dark:bg-orange-950/40 dark:text-orange-300'
|
||||
return 'border-warning/30 bg-warning/10 text-warning'
|
||||
}
|
||||
if (ratio > 1) {
|
||||
return 'border-blue-200 bg-blue-50 text-blue-700 dark:border-blue-900/60 dark:bg-blue-950/40 dark:text-blue-300'
|
||||
return 'border-info/25 bg-info/10 text-info'
|
||||
}
|
||||
return 'border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-300'
|
||||
return 'border-success/25 bg-success/10 text-success'
|
||||
}
|
||||
|
||||
function GroupRatioBadge({ ratio }: { ratio: ApiKeyGroupOption['ratio'] }) {
|
||||
@@ -87,7 +87,7 @@ function GroupRatioBadge({ ratio }: { ratio: ApiKeyGroupOption['ratio'] }) {
|
||||
<Badge
|
||||
variant='outline'
|
||||
className={cn(
|
||||
'max-w-24 shrink-0 truncate text-[10px] sm:max-w-none sm:text-xs',
|
||||
'max-w-24 shrink-0 truncate text-xs sm:max-w-none sm:text-xs',
|
||||
getRatioBadgeClassName(ratio)
|
||||
)}
|
||||
>
|
||||
@@ -149,7 +149,7 @@ export function ApiKeyGroupCombobox({
|
||||
{selectedOption?.label || placeholder || t('Select a group')}
|
||||
</span>
|
||||
{selectedOption?.desc && (
|
||||
<span className='text-muted-foreground block truncate text-[11px] sm:text-xs'>
|
||||
<span className='text-muted-foreground block truncate text-xs sm:text-xs'>
|
||||
{selectedOption.desc}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -44,9 +44,10 @@ import {
|
||||
import { DataTableRowActions } from './data-table-row-actions'
|
||||
|
||||
function getQuotaProgressColor(percentage: number): string {
|
||||
if (percentage <= 10) return '[&_[data-slot=progress-indicator]]:bg-rose-500'
|
||||
if (percentage <= 30) return '[&_[data-slot=progress-indicator]]:bg-amber-500'
|
||||
return '[&_[data-slot=progress-indicator]]:bg-emerald-500'
|
||||
if (percentage <= 10)
|
||||
return '[&_[data-slot=progress-indicator]]:bg-destructive'
|
||||
if (percentage <= 30) return '[&_[data-slot=progress-indicator]]:bg-warning'
|
||||
return '[&_[data-slot=progress-indicator]]:bg-success'
|
||||
}
|
||||
|
||||
function useGroupRatios(): Record<string, number> {
|
||||
@@ -254,7 +255,7 @@ export function useApiKeysColumns(): ColumnDef<ApiKey>[] {
|
||||
accessorKey: 'created_time',
|
||||
header: t('Created'),
|
||||
cell: ({ row }) => (
|
||||
<span className='text-muted-foreground block truncate font-mono text-xs tabular-nums'>
|
||||
<span className='text-muted-foreground block truncate text-xs tabular-nums'>
|
||||
{formatTimestampToDate(row.getValue('created_time'))}
|
||||
</span>
|
||||
),
|
||||
@@ -270,7 +271,7 @@ export function useApiKeysColumns(): ColumnDef<ApiKey>[] {
|
||||
return <span className='text-muted-foreground text-xs'>-</span>
|
||||
}
|
||||
return (
|
||||
<span className='text-muted-foreground block truncate font-mono text-xs tabular-nums'>
|
||||
<span className='text-muted-foreground block truncate text-xs tabular-nums'>
|
||||
{formatTimestampToDate(accessedTime)}
|
||||
</span>
|
||||
)
|
||||
@@ -296,7 +297,7 @@ export function useApiKeysColumns(): ColumnDef<ApiKey>[] {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
'block truncate font-mono text-xs tabular-nums',
|
||||
'block truncate text-xs tabular-nums',
|
||||
isExpired ? 'text-destructive' : 'text-muted-foreground'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -140,7 +140,7 @@ function ApiKeysMobileList({
|
||||
<div className='truncate text-sm font-semibold'>
|
||||
{apiKey.name}
|
||||
</div>
|
||||
<div className='text-muted-foreground text-[11px]'>
|
||||
<div className='text-muted-foreground text-xs'>
|
||||
{t('API Key')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -203,7 +203,7 @@ export function DataTableRowActions<TData>({
|
||||
className={
|
||||
isEnabled
|
||||
? 'text-destructive hover:text-destructive'
|
||||
: 'text-emerald-600 hover:text-emerald-600 dark:text-emerald-400 dark:hover:text-emerald-400'
|
||||
: 'text-success hover:text-success'
|
||||
}
|
||||
/>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user