✨ 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:
@@ -294,7 +294,7 @@ export function CheckinCalendarCard({
|
||||
{t('Daily Check-in')}
|
||||
</h3>
|
||||
{checkedToday && (
|
||||
<div className='inline-flex items-center gap-1 rounded-md bg-emerald-500/10 px-2 py-0.5 text-[11px] font-medium text-emerald-600 sm:gap-1.5 sm:px-2.5 sm:text-xs dark:text-emerald-400'>
|
||||
<div className='bg-success/10 text-success inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium sm:gap-1.5 sm:px-2.5'>
|
||||
<Sparkles className='h-2.5 w-2.5 sm:h-3 sm:w-3' />
|
||||
{t('Checked in')}
|
||||
</div>
|
||||
@@ -337,7 +337,7 @@ export function CheckinCalendarCard({
|
||||
<div className='text-xl font-semibold tracking-tight tabular-nums sm:text-2xl'>
|
||||
{checkinData?.stats?.total_checkins || 0}
|
||||
</div>
|
||||
<div className='text-muted-foreground mt-0.5 text-[10px] font-medium sm:mt-1 sm:text-xs'>
|
||||
<div className='text-muted-foreground mt-0.5 text-xs font-medium sm:mt-1 sm:text-xs'>
|
||||
{t('Total check-ins')}
|
||||
</div>
|
||||
</div>
|
||||
@@ -345,7 +345,7 @@ export function CheckinCalendarCard({
|
||||
<div className='text-xl font-semibold tracking-tight tabular-nums sm:text-2xl'>
|
||||
{formatQuotaWithCurrency(monthlyQuota, { digitsLarge: 0 })}
|
||||
</div>
|
||||
<div className='text-muted-foreground mt-0.5 text-[10px] font-medium sm:mt-1 sm:text-xs'>
|
||||
<div className='text-muted-foreground mt-0.5 text-xs font-medium sm:mt-1 sm:text-xs'>
|
||||
{t('This month')}
|
||||
</div>
|
||||
</div>
|
||||
@@ -358,7 +358,7 @@ export function CheckinCalendarCard({
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div className='text-muted-foreground mt-0.5 text-[10px] font-medium sm:mt-1 sm:text-xs'>
|
||||
<div className='text-muted-foreground mt-0.5 text-xs font-medium sm:mt-1 sm:text-xs'>
|
||||
{t('Total earned')}
|
||||
</div>
|
||||
</div>
|
||||
@@ -398,7 +398,7 @@ export function CheckinCalendarCard({
|
||||
{weekDays.map((day) => (
|
||||
<div
|
||||
key={day}
|
||||
className='text-muted-foreground flex h-7 items-center justify-center text-[10px] font-medium sm:h-8 sm:text-xs'
|
||||
className='text-muted-foreground flex h-7 items-center justify-center text-xs font-medium sm:h-8 sm:text-xs'
|
||||
>
|
||||
{day}
|
||||
</div>
|
||||
@@ -430,7 +430,7 @@ export function CheckinCalendarCard({
|
||||
>
|
||||
<span className='tabular-nums'>{dayNum}</span>
|
||||
{isCheckedIn && !isToday && (
|
||||
<span className='absolute bottom-0.5 h-1 w-1 rounded-full bg-emerald-500 sm:bottom-1' />
|
||||
<span className='bg-success absolute bottom-0.5 h-1 w-1 rounded-full sm:bottom-1' />
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
@@ -458,7 +458,7 @@ export function CheckinCalendarCard({
|
||||
</div>
|
||||
|
||||
{/* Footer hint */}
|
||||
<div className='text-muted-foreground border-t pt-3 text-center text-[11px] sm:pt-4 sm:text-xs'>
|
||||
<div className='text-muted-foreground border-t pt-3 text-center text-xs sm:pt-4 sm:text-xs'>
|
||||
{t('You can only check in once per day')}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ export function PasskeyCard({ loading: pageLoading }: PasskeyCardProps) {
|
||||
|
||||
{showUnsupportedNotice && (
|
||||
<div className='bg-muted/60 text-muted-foreground flex items-start gap-3 rounded-md p-4 text-sm'>
|
||||
<ShieldAlert className='mt-0.5 h-4 w-4 flex-shrink-0 text-amber-500' />
|
||||
<ShieldAlert className='text-warning mt-0.5 h-4 w-4 flex-shrink-0' />
|
||||
<div>
|
||||
<p className='text-foreground font-medium'>
|
||||
{t('Passkey not supported on this device')}
|
||||
|
||||
@@ -163,7 +163,7 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='text-foreground mt-1.5 truncate font-mono text-lg font-bold tracking-tight tabular-nums sm:mt-2 sm:text-2xl'>
|
||||
<div className='text-foreground mt-1.5 truncate text-lg font-bold tracking-tight tabular-nums sm:mt-2 sm:text-2xl'>
|
||||
{item.value}
|
||||
</div>
|
||||
<div className='text-muted-foreground/60 mt-1 hidden text-xs md:block'>
|
||||
|
||||
Reference in New Issue
Block a user