From a9024ff6f815fe7b5cd1a4e07cdff1ba72ae9243 Mon Sep 17 00:00:00 2001 From: TaskPool Date: Sun, 26 Jul 2026 20:14:42 +0800 Subject: [PATCH] feat(ui): add size system (sm/md/lg) + compact mode + remove collapsed dot --- web/src/components/Layout.tsx | 3 -- web/src/components/ui/badge.tsx | 9 +++- web/src/components/ui/button.tsx | 2 +- web/src/components/ui/index.ts | 1 + web/src/components/ui/input.tsx | 10 +++- web/src/components/ui/select.tsx | 2 +- web/src/components/ui/switch.tsx | 17 +++++-- web/src/components/ui/table.tsx | 23 +++++++-- web/src/components/ui/tabs.tsx | 10 +++- web/src/components/ui/textarea.tsx | 10 +++- web/src/index.css | 79 +++++++++++++++++++++++++----- 11 files changed, 137 insertions(+), 29 deletions(-) diff --git a/web/src/components/Layout.tsx b/web/src/components/Layout.tsx index f0463b9..59798d2 100644 --- a/web/src/components/Layout.tsx +++ b/web/src/components/Layout.tsx @@ -211,9 +211,6 @@ export default function Layout() { {active ? : null} )} - {sidebarCollapsed && active ? ( - - ) : null} ) })} diff --git a/web/src/components/ui/badge.tsx b/web/src/components/ui/badge.tsx index df49d0e..9cf1aea 100644 --- a/web/src/components/ui/badge.tsx +++ b/web/src/components/ui/badge.tsx @@ -6,9 +6,11 @@ export type BadgeTone = 'default' | 'success' | 'warn' | 'danger' | 'info' export function Badge({ children, tone = 'default', + size = 'md', }: { children: ReactNode tone?: BadgeTone + size?: 'sm' | 'md' | 'lg' }) { const tones: Record = { default: 'border-[var(--border)] bg-[var(--bg-tertiary)] text-[var(--text-secondary)]', @@ -21,8 +23,13 @@ export function Badge({ info: 'border-[color-mix(in_srgb,var(--info)_25%,transparent)] bg-[color-mix(in_srgb,var(--info)_12%,transparent)] text-[var(--info)]', } + const badgeSizes = { + sm: 'px-1.5 py-px text-[10px]', + md: 'px-2 py-0.5 text-[11px]', + lg: 'px-2.5 py-1 text-[12px]', + } return ( - + {children} ) diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx index ba9690e..51b41b6 100644 --- a/web/src/components/ui/button.tsx +++ b/web/src/components/ui/button.tsx @@ -2,7 +2,7 @@ import type { ButtonHTMLAttributes } from 'react' import { cn } from '@/lib/utils' export type ButtonVariant = 'default' | 'secondary' | 'ghost' | 'danger' | 'outline' -export type ButtonSize = 'sm' | 'md' | 'icon' +export type ButtonSize = 'sm' | 'md' | 'lg' | 'icon' | 'icon-sm' | 'icon-lg' export interface ButtonProps extends ButtonHTMLAttributes { variant?: ButtonVariant diff --git a/web/src/components/ui/index.ts b/web/src/components/ui/index.ts index 4e48b5e..3eb21ed 100644 --- a/web/src/components/ui/index.ts +++ b/web/src/components/ui/index.ts @@ -10,6 +10,7 @@ export { Badge } from './badge' export type { BadgeTone } from './badge' export { Modal } from './modal' export { Table, Th, Td } from './table' +export type { TableSize } from './table' export { Field } from './field' export { PageHeader } from './page-header' export { Empty } from './empty' diff --git a/web/src/components/ui/input.tsx b/web/src/components/ui/input.tsx index 831d5c5..69d1fcf 100644 --- a/web/src/components/ui/input.tsx +++ b/web/src/components/ui/input.tsx @@ -1,6 +1,12 @@ import type { InputHTMLAttributes } from 'react' import { cn } from '@/lib/utils' -export function Input({ className, ...props }: InputHTMLAttributes) { - return +const heights: Record = { + sm: 'h-[var(--ui-height-sm)] text-[length:var(--ui-font-sm)] px-[var(--ui-px-sm)]', + md: 'h-[var(--ui-height-md)] text-[length:var(--ui-font-md)] px-[var(--ui-px-md)]', + lg: 'h-[var(--ui-height-lg)] text-[length:var(--ui-font-lg)] px-[var(--ui-px-lg)]', +} + +export function Input({ className, size = 'md', ...props }: InputHTMLAttributes & { size?: 'sm' | 'md' | 'lg' }) { + return } diff --git a/web/src/components/ui/select.tsx b/web/src/components/ui/select.tsx index d19fee2..c77e8bf 100644 --- a/web/src/components/ui/select.tsx +++ b/web/src/components/ui/select.tsx @@ -144,7 +144,7 @@ export function Select({ disabled={disabled} aria-haspopup="listbox" aria-expanded={open} - className={cn('ui-control ui-select-trigger h-9 px-3 text-left', open && 'ui-control-open')} + className={cn('ui-control ui-select-trigger h-[var(--ui-height-md)] px-[var(--ui-px-md)] text-left text-[length:var(--ui-font-md)]', open && 'ui-control-open')} onClick={() => { if (disabled) return setOpen((v) => !v) diff --git a/web/src/components/ui/switch.tsx b/web/src/components/ui/switch.tsx index 5e26887..3fd45ee 100644 --- a/web/src/components/ui/switch.tsx +++ b/web/src/components/ui/switch.tsx @@ -1,16 +1,25 @@ import { cn } from '@/lib/utils' +const sizes = { + sm: { track: 'h-4 w-7', thumb: 'h-2.5 w-2.5', on: 'translate-x-[14px]', off: 'translate-x-[2px]' }, + md: { track: 'h-5 w-9', thumb: 'h-3.5 w-3.5', on: 'translate-x-[18px]', off: 'translate-x-[3px]' }, + lg: { track: 'h-6 w-11', thumb: 'h-4 w-4', on: 'translate-x-[22px]', off: 'translate-x-[3px]' }, +} + export function Switch({ checked, onCheckedChange, disabled, className, + size = 'md', }: { checked: boolean onCheckedChange: (v: boolean) => void disabled?: boolean className?: string + size?: 'sm' | 'md' | 'lg' }) { + const s = sizes[size] return ( diff --git a/web/src/components/ui/table.tsx b/web/src/components/ui/table.tsx index cea8314..52981bb 100644 --- a/web/src/components/ui/table.tsx +++ b/web/src/components/ui/table.tsx @@ -1,6 +1,20 @@ import type { ReactNode } from 'react' import { cn } from '@/lib/utils' +export type TableSize = 'sm' | 'md' | 'lg' + +const thSizes: Record = { + sm: 'px-2 py-[var(--ui-table-py-sm)] text-[10px]', + md: 'px-3 py-[var(--ui-table-py-md)] text-[11px]', + lg: 'px-4 py-[var(--ui-table-py-lg)] text-[12px]', +} + +const tdSizes: Record = { + sm: 'px-2 py-[var(--ui-table-py-sm)] text-[length:var(--ui-font-sm)]', + md: 'px-3 py-[var(--ui-table-py-md)] text-[length:var(--ui-font-md)]', + lg: 'px-4 py-[var(--ui-table-py-lg)] text-[length:var(--ui-font-lg)]', +} + export function Table({ children }: { children: ReactNode }) { return (
@@ -9,11 +23,12 @@ export function Table({ children }: { children: ReactNode }) { ) } -export function Th({ children, className }: { children?: ReactNode; className?: string }) { +export function Th({ children, className, size = 'md' }: { children?: ReactNode; className?: string; size?: TableSize }) { return ( @@ -22,9 +37,9 @@ export function Th({ children, className }: { children?: ReactNode; className?: ) } -export function Td({ children, className }: { children?: ReactNode; className?: string }) { +export function Td({ children, className, size = 'md' }: { children?: ReactNode; className?: string; size?: TableSize }) { return ( - + {children} ) diff --git a/web/src/components/ui/tabs.tsx b/web/src/components/ui/tabs.tsx index 9243429..a6011a3 100644 --- a/web/src/components/ui/tabs.tsx +++ b/web/src/components/ui/tabs.tsx @@ -5,12 +5,19 @@ export function Tabs({ onValueChange, items, className, + size = 'md', }: { value: string onValueChange: (v: string) => void items: { value: string; label: string }[] className?: string + size?: 'sm' | 'md' | 'lg' }) { + const tabSizes = { + sm: 'px-2.5 py-1 text-[12px]', + md: 'px-3.5 py-1.5 text-[13px]', + lg: 'px-4 py-2 text-[14px]', + } return (
) { - return