feat: update theme colors

This commit is contained in:
CaIon
2026-07-11 19:25:04 +08:00
parent 6bbddb1046
commit 162f87925c
75 changed files with 1553 additions and 655 deletions
@@ -33,6 +33,7 @@ import { Dialog } from '@/components/dialog'
import { Turnstile } from '@/components/turnstile'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { IconBadge } from '@/components/ui/icon-badge'
import { Skeleton } from '@/components/ui/skeleton'
import {
Tooltip,
@@ -162,7 +163,7 @@ export function CheckinCalendarCard({
}
toast.error(res.message || t('Check-in failed'))
}
} catch (_error) {
} catch {
toast.error(t('Check-in failed'))
} finally {
setCheckinLoading(false)
@@ -241,6 +242,13 @@ export function CheckinCalendarCard({
)
}
let checkinButtonLabel = t('Check in now')
if (checkinLoading) {
checkinButtonLabel = t('Loading...')
} else if (checkedToday) {
checkinButtonLabel = t('Checked in')
}
return (
<TooltipProvider delay={100}>
<Dialog
@@ -282,12 +290,12 @@ export function CheckinCalendarCard({
className='flex min-w-0 flex-1 items-start gap-3 rounded-lg text-left whitespace-normal outline-none'
onClick={() => setCollapsed((v) => !v)}
>
<div className='bg-primary/10 text-primary flex h-10 w-10 shrink-0 items-center justify-center rounded-xl sm:h-11 sm:w-11'>
<IconBadge tone='neutral' size='lg' className='sm:size-11'>
<CalendarDays
className='h-4 w-4 sm:h-5 sm:w-5'
strokeWidth={2}
/>
</div>
</IconBadge>
<div className='min-w-0 flex-1'>
<div className='flex flex-wrap items-center gap-1.5 sm:gap-2'>
<h3 className='text-base font-semibold tracking-tight sm:text-lg'>
@@ -320,11 +328,7 @@ export function CheckinCalendarCard({
size='sm'
className='w-full shrink-0 sm:w-auto'
>
{checkinLoading
? t('Loading...')
: checkedToday
? t('Checked in')
: t('Check in now')}
{checkinButtonLabel}
</Button>
</div>
</div>
@@ -405,7 +409,7 @@ export function CheckinCalendarCard({
))}
{/* Calendar days */}
{calendarDays.map((dayObj, idx) => {
{calendarDays.map((dayObj) => {
const dateStr = `${dayObj.date.getFullYear()}-${String(
dayObj.date.getMonth() + 1
).padStart(2, '0')}-${String(
@@ -418,7 +422,7 @@ export function CheckinCalendarCard({
const dayButton = (
<Button
key={idx}
key={dateStr}
variant={isToday ? 'default' : 'ghost'}
disabled={!dayObj.isCurrentMonth}
className={cn(
@@ -430,15 +434,15 @@ 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 size-1 rounded-full sm:bottom-1' />
)}
</Button>
)
if (isCheckedIn && dayObj.isCurrentMonth) {
return (
<Tooltip key={idx}>
<TooltipTrigger render={dayButton}></TooltipTrigger>
<Tooltip key={dateStr}>
<TooltipTrigger render={dayButton} />
<TooltipContent>
<div className='text-xs'>
<div className='font-medium'>
@@ -93,7 +93,7 @@ export function LanguagePreferencesCard(props: LanguagePreferencesCardProps) {
props.onProfileUpdate()
toast.success(t('Language preference saved'))
} catch (_error) {
} catch {
setCurrentLanguage(previousLanguage)
await i18n.changeLanguage(previousLanguage)
toast.error(t('Failed to update settings'))
@@ -107,6 +107,7 @@ export function LanguagePreferencesCard(props: LanguagePreferencesCardProps) {
title={t('Language Preferences')}
description={t('Set the language used across the interface')}
icon={<Languages className='h-4 w-4' />}
iconTone='chart-4'
disableHoverEffect
>
<div className='flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4'>
@@ -120,12 +121,10 @@ export function LanguagePreferencesCard(props: LanguagePreferencesCardProps) {
</div>
<div className='flex items-center gap-2 sm:min-w-48'>
<Select
items={[
...INTERFACE_LANGUAGE_OPTIONS.map((language) => ({
value: language.code,
label: language.label,
})),
]}
items={INTERFACE_LANGUAGE_OPTIONS.map((language) => ({
value: language.code,
label: language.label,
}))}
value={currentLanguage}
onValueChange={handleLanguageChange}
disabled={saving}
@@ -41,6 +41,7 @@ import {
CardHeader,
CardTitle,
} from '@/components/ui/card'
import { IconBadge } from '@/components/ui/icon-badge'
import { Skeleton } from '@/components/ui/skeleton'
import { usePasskeyManagement } from '@/features/auth/passkey'
import {
@@ -242,9 +243,9 @@ export function PasskeyCard({ loading: pageLoading }: PasskeyCardProps) {
<div className='space-y-6'>
<div className='flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between xl:flex-col 2xl:flex-row'>
<div className='flex items-start gap-4'>
<div className='bg-muted rounded-md p-2'>
<KeyRound className='h-5 w-5' />
</div>
<IconBadge tone='info' size='sm'>
<KeyRound />
</IconBadge>
<div className='space-y-1'>
<div className='flex flex-wrap items-center gap-2'>
<p className='font-medium'>{t('Passkey Authentication')}</p>
@@ -22,6 +22,7 @@ import { useTranslation } from 'react-i18next'
import { StatusBadge } from '@/components/status-badge'
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
import { Card, CardContent } from '@/components/ui/card'
import { IconBadge, type IconBadgeTone } from '@/components/ui/icon-badge'
import { Skeleton } from '@/components/ui/skeleton'
import { getUserAvatarFallback, getUserAvatarStyle } from '@/lib/avatar'
import { formatCompactNumber, formatQuota } from '@/lib/format'
@@ -63,8 +64,8 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) {
</CardContent>
<div className='border-t'>
<div className='divide-border/60 grid grid-cols-1 divide-y sm:grid-cols-3 sm:divide-x sm:divide-y-0'>
{Array.from({ length: 3 }).map((_, i) => (
<div key={i} className='px-4 py-3.5 sm:px-5 sm:py-4'>
{['balance', 'usage', 'requests'].map((key) => (
<div key={key} className='px-4 py-3.5 sm:px-5 sm:py-4'>
<Skeleton className='h-3.5 w-20' />
<Skeleton className='mt-2 h-7 w-28' />
<Skeleton className='mt-1.5 h-3.5 w-24' />
@@ -83,24 +84,33 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) {
const avatarFallback = getUserAvatarFallback(avatarName)
const avatarFallbackStyle = getUserAvatarStyle(avatarName)
const roleLabel = getRoleLabel(profile.role)
const stats = [
const stats: {
label: string
value: string
description: string
icon: typeof WalletCards
tone: IconBadgeTone
}[] = [
{
label: t('Current Balance'),
value: formatQuota(profile.quota),
description: t('Remaining quota'),
icon: WalletCards,
tone: 'success',
},
{
label: t('Total Usage'),
value: formatQuota(profile.used_quota),
description: t('Total consumed quota'),
icon: BarChart3,
tone: 'info',
},
{
label: t('API Requests'),
value: formatCompactNumber(profile.request_count),
description: t('Total requests made'),
icon: Activity,
tone: 'chart-4',
},
]
@@ -157,7 +167,9 @@ export function ProfileHeader({ profile, loading }: ProfileHeaderProps) {
{stats.map((item) => (
<div key={item.label} className='min-w-0 px-3 py-3 sm:px-5 sm:py-4'>
<div className='flex items-center gap-2'>
<item.icon className='text-muted-foreground/60 size-3.5 shrink-0' />
<IconBadge tone={item.tone} size='stat'>
<item.icon />
</IconBadge>
<div className='text-muted-foreground truncate text-xs font-medium tracking-wider uppercase'>
{item.label}
</div>
@@ -20,6 +20,7 @@ import { Shield, Key, Trash2 } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Card, CardContent, CardHeader } from '@/components/ui/card'
import { IconBadge } from '@/components/ui/icon-badge'
import { Skeleton } from '@/components/ui/skeleton'
import { TitledCard } from '@/components/ui/titled-card'
import { useDialogs } from '@/hooks/use-dialog'
@@ -55,8 +56,8 @@ export function ProfileSecurityCard({
<Skeleton className='mt-2 h-4 w-48' />
</CardHeader>
<CardContent className='space-y-3 p-3 sm:p-5'>
{Array.from({ length: 3 }).map((_, i) => (
<Skeleton key={i} className='h-16 w-full' />
{['password', 'token', 'delete'].map((key) => (
<Skeleton key={key} className='h-16 w-full' />
))}
</CardContent>
</Card>
@@ -95,6 +96,7 @@ export function ProfileSecurityCard({
title={t('Security')}
description={t('Manage your security settings and account access')}
icon={<Shield className='h-4 w-4' />}
iconTone='success'
disableHoverEffect
>
<div className='grid grid-cols-1 gap-2.5 sm:gap-3 md:grid-cols-3'>
@@ -107,15 +109,9 @@ export function ProfileSecurityCard({
item.variant === 'destructive' ? 'border-destructive/30' : ''
}`}
>
<div
className={`rounded-md p-2 ${
item.variant === 'destructive'
? 'bg-destructive/10 text-destructive'
: 'bg-muted'
}`}
>
<item.icon className='h-5 w-5' />
</div>
<IconBadge tone='neutral' size='sm'>
<item.icon />
</IconBadge>
<div className='min-w-0 md:contents'>
<p className='text-sm font-medium'>{item.title}</p>
<p className='text-muted-foreground line-clamp-1 text-xs md:line-clamp-none'>
@@ -56,8 +56,8 @@ export function ProfileSettingsCard({
</CardHeader>
<CardContent className='space-y-4 p-3 sm:p-5'>
<Skeleton className='h-10 w-full' />
{Array.from({ length: 3 }).map((_, i) => (
<Skeleton key={i} className='h-20 w-full' />
{['bindings', 'preferences', 'notifications'].map((key) => (
<Skeleton key={key} className='h-20 w-full' />
))}
</CardContent>
</Card>
@@ -69,6 +69,7 @@ export function ProfileSettingsCard({
title={t('Settings')}
description={t('Configure your account preferences and integrations')}
icon={<Settings className='h-4 w-4' />}
iconTone='info'
disableHoverEffect
>
<Tabs value={activeTab} onValueChange={setActiveTab}>
@@ -29,6 +29,7 @@ import {
CardHeader,
CardTitle,
} from '@/components/ui/card'
import { IconBadge } from '@/components/ui/icon-badge'
import { Switch } from '@/components/ui/switch'
import { api } from '@/lib/api'
import { useAuthStore } from '@/stores/auth-store'
@@ -204,9 +205,9 @@ export function SidebarModulesCard() {
<Card data-card-hover='false' className='gap-0 overflow-hidden py-0'>
<CardHeader className='border-b p-3 !pb-3 sm:p-5 sm:!pb-5'>
<div className='flex items-center gap-3'>
<div className='bg-muted flex h-8 w-8 shrink-0 items-center justify-center rounded-lg sm:h-9 sm:w-9'>
<LayoutDashboard className='h-4 w-4' />
</div>
<IconBadge tone='info' size='title'>
<LayoutDashboard />
</IconBadge>
<div className='min-w-0'>
<CardTitle className='text-lg tracking-tight sm:text-xl'>
{t('Sidebar Personal Settings')}
@@ -28,6 +28,7 @@ import {
CardHeader,
CardTitle,
} from '@/components/ui/card'
import { IconBadge } from '@/components/ui/icon-badge'
import { Skeleton } from '@/components/ui/skeleton'
import { useDialogs } from '@/hooks/use-dialog'
@@ -82,9 +83,9 @@ export function TwoFACard({ loading: pageLoading }: TwoFACardProps) {
{/* Status Section */}
<div className='flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between xl:flex-col 2xl:flex-row'>
<div className='flex items-start gap-4'>
<div className='bg-muted rounded-md p-2'>
<Shield className='h-5 w-5' />
</div>
<IconBadge tone='success' size='sm'>
<Shield />
</IconBadge>
<div className='space-y-1'>
<div className='flex items-center gap-2'>
<p className='font-medium'>{t('Two-Step Verification')}</p>