♻️ refactor(web): consolidate design-system primitives and responsive data views

This commit is contained in:
t0ng7u
2026-07-11 05:13:16 +08:00
parent 262ab93123
commit 0918bdb49a
451 changed files with 7295 additions and 7693 deletions
@@ -19,7 +19,7 @@ For commercial licensing, please contact support@quantumnous.com
import { Search } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Button } from '@/components/design-system/button'
export interface EmptyStateProps {
searchQuery?: string
@@ -49,7 +49,7 @@ export function EmptyState(props: EmptyStateProps) {
</p>
{(props.hasActiveFilters || hasSearch) && (
<Button variant='outline' size='sm' onClick={props.onClearFilters}>
<Button variant='outline' onClick={props.onClearFilters}>
{t('Clear all filters')}
</Button>
)}
@@ -21,7 +21,7 @@ import { ChevronLeft, ChevronRight } from 'lucide-react'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Button } from '@/components/design-system/button'
import { getPerfMetricsSummary } from '@/features/performance-metrics/api'
import { DEFAULT_PRICING_PAGE_SIZE, DEFAULT_TOKEN_UNIT } from '../constants'
@@ -101,7 +101,6 @@ export function ModelCardGrid(props: ModelCardGridProps) {
<Button
type='button'
variant='outline'
size='sm'
onClick={() => setPage((current) => Math.max(1, current - 1))}
disabled={currentPage <= 1}
className='gap-1.5'
@@ -112,7 +111,6 @@ export function ModelCardGrid(props: ModelCardGridProps) {
<Button
type='button'
variant='outline'
size='sm'
onClick={() =>
setPage((current) => Math.min(totalPages, current + 1))
}
+3 -6
View File
@@ -260,12 +260,9 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
{isTokenBased ? t('Token-based') : t('Per Request')}
</span>
{isDynamicPricing && (
<StatusBadge
label={t('Dynamic Pricing')}
variant='warning'
copyable={false}
size='sm'
/>
<StatusBadge variant='warning' size='sm'>
{t('Dynamic Pricing')}
</StatusBadge>
)}
</div>
<ModelPerfBadge perf={props.perf} className='row-span-2 self-start' />
@@ -36,8 +36,8 @@ import {
StaticDataTable,
staticDataTableClassNames as tableStyles,
} from '@/components/data-table'
import { Tabs, TabsList, TabsTrigger } from '@/components/design-system/tabs'
import { Badge } from '@/components/ui/badge'
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { useStatus } from '@/hooks/use-status'
import {
@@ -502,7 +502,7 @@ function CodeSamplesSection(props: {
<div className='flex flex-wrap items-center gap-2'>
{endpoints.length > 1 && (
<Tabs value={endpointType} onValueChange={setEndpointType}>
<TabsList className='bg-muted/40 h-8 p-0.5'>
<TabsList className='bg-muted/40 p-0.5'>
{endpoints.map((ep) => (
<TabsTrigger
key={ep.type}
@@ -521,7 +521,7 @@ function CodeSamplesSection(props: {
onValueChange={(v) => setLang(v as Lang)}
className='ml-auto'
>
<TabsList className='bg-muted/40 h-8 p-0.5'>
<TabsList className='bg-muted/40 p-0.5'>
{(Object.keys(LANG_LABELS) as Lang[]).map((l) => (
<TabsTrigger key={l} value={l} className='h-7 px-2.5 text-xs'>
{LANG_LABELS[l]}
@@ -35,10 +35,16 @@ import { useTranslation } from 'react-i18next'
import { CopyButton } from '@/components/copy-button'
import { StaticDataTable } from '@/components/data-table'
import { Button } from '@/components/design-system/button'
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from '@/components/design-system/tabs'
import { sideDrawerContentClassName } from '@/components/drawer-layout'
import { GroupBadge } from '@/components/group-badge'
import { PublicLayout } from '@/components/layout'
import { Button } from '@/components/ui/button'
import {
Sheet,
SheetContent,
@@ -47,7 +53,6 @@ import {
SheetTitle,
} from '@/components/ui/sheet'
import { Skeleton } from '@/components/ui/skeleton'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { getPerfMetrics } from '@/features/performance-metrics/api'
import {
formatLatency,
@@ -545,7 +550,7 @@ function ModelHeader(props: { model: PricingModel }) {
</h1>
<CopyButton
value={model.model_name || ''}
className='size-6'
size='icon-xs'
iconClassName='size-3'
tooltip={t('Copy model name')}
successTooltip={t('Copied!')}
@@ -1165,7 +1170,7 @@ export function ModelDetailsContent(props: ModelDetailsContentProps) {
<ModelHeader model={props.model} />
<Tabs defaultValue='overview' className='gap-4'>
<TabsList className='bg-muted/60 grid w-full grid-cols-3 gap-1 rounded-lg p-1 group-data-horizontal/tabs:h-auto'>
<TabsList className='bg-muted/60 grid w-full grid-cols-3 gap-1 rounded-lg p-1 group-data-horizontal/tabs:h-auto sm:group-data-horizontal/tabs:h-auto'>
{TAB_VALUES.map((value) => {
const Icon = TAB_META[value].icon
return (
@@ -1323,7 +1328,7 @@ export function ModelDetails() {
<p className='text-muted-foreground mb-4 text-sm'>
{t("The model you're looking for doesn't exist.")}
</p>
<Button onClick={handleBack} variant='outline' size='sm'>
<Button onClick={handleBack} variant='outline'>
{t('Back to Models')}
</Button>
</div>
@@ -1336,9 +1341,8 @@ export function ModelDetails() {
<div className='mx-auto max-w-5xl px-4 sm:px-6'>
<Button
variant='ghost'
size='sm'
onClick={handleBack}
className='text-muted-foreground hover:text-foreground mb-4 h-auto gap-1 px-0 py-1 text-xs'
className='text-muted-foreground hover:text-foreground mb-4 h-auto gap-1 px-0 py-1 text-xs sm:h-auto'
>
<ArrowLeft className='size-3.5' />
{t('Back')}
@@ -100,11 +100,9 @@ export function usePricingColumns(
cell: ({ row }) => {
const isTokenBased = row.original.quota_type === QUOTA_TYPE_VALUES.TOKEN
return (
<StatusBadge
label={isTokenBased ? t('Token') : t('Request')}
variant={isTokenBased ? 'info' : 'neutral'}
copyable={false}
/>
<StatusBadge variant={isTokenBased ? 'info' : 'neutral'}>
{isTokenBased ? t('Token') : t('Request')}
</StatusBadge>
)
},
size: 80,
@@ -334,12 +332,9 @@ export function usePricingColumns(
return (
<BadgeCell className='gap-1.5'>
{vendorIcon}
<StatusBadge
label={model.vendor_name}
autoColor={model.vendor_name}
size='sm'
copyable={false}
/>
<StatusBadge variant='neutral' size='sm'>
{model.vendor_name}
</StatusBadge>
</BadgeCell>
)
},
@@ -356,13 +351,9 @@ export function usePricingColumns(
return (
<BadgeListCell
items={tags.map((tag) => (
<StatusBadge
key={tag}
label={tag}
autoColor={tag}
size='sm'
copyable={false}
/>
<StatusBadge key={tag} variant='neutral' size='sm'>
{tag}
</StatusBadge>
))}
/>
)
@@ -380,13 +371,9 @@ export function usePricingColumns(
return (
<BadgeListCell
items={endpoints.map((ep) => (
<StatusBadge
key={ep}
label={ep}
autoColor={ep}
size='sm'
copyable={false}
/>
<StatusBadge key={ep} variant='neutral' size='sm'>
{ep}
</StatusBadge>
))}
/>
)
@@ -20,8 +20,8 @@ import { ChevronDown, RotateCcw } from 'lucide-react'
import type { ReactNode } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/design-system/button'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
Collapsible,
CollapsibleContent,
@@ -260,7 +260,6 @@ export function PricingSidebar(props: PricingSidebarProps) {
size='sm'
onClick={props.onClearFilters}
disabled={!props.hasActiveFilters}
className='h-7 gap-1.5 px-2 text-xs'
>
<RotateCcw className='size-3.5' />
{t('Reset')}
@@ -20,13 +20,13 @@ import { ArrowUpDown, Check, Filter, Grid2X2, Table2 } from 'lucide-react'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/design-system/button'
import {
sideDrawerContentClassName,
sideDrawerFormClassName,
sideDrawerHeaderClassName,
} from '@/components/drawer-layout'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
@@ -172,7 +172,6 @@ export function PricingToolbar(props: PricingToolbarProps) {
<Button
type='button'
variant='outline'
size='sm'
onClick={() => setMobileFiltersOpen(true)}
className='gap-1.5 xl:hidden'
>
@@ -222,14 +221,7 @@ export function PricingToolbar(props: PricingToolbarProps) {
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button
type='button'
variant='outline'
size='sm'
className='h-8 gap-1.5 px-3 text-xs'
/>
}
render={<Button type='button' variant='outline' />}
>
<ArrowUpDown className='size-3.5' />
<span>{sortLabels[props.sortBy as SortOption] || t('Sort')}</span>
+3 -3
View File
@@ -20,7 +20,7 @@ import { Search, X } from 'lucide-react'
import { useEffect, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Button } from '@/components/design-system/button'
import { cn } from '@/lib/utils'
export interface SearchBarProps {
@@ -70,9 +70,9 @@ export function SearchBar(props: SearchBarProps) {
{props.value ? (
<Button
variant='ghost'
size='icon'
size='icon-sm'
onClick={props.onClear}
className='text-muted-foreground/60 hover:text-foreground size-7'
className='text-muted-foreground/60 hover:text-foreground'
aria-label={t('Clear search')}
>
<X className='size-4' />