diff options
Diffstat (limited to 'src/demos')
| -rw-r--r-- | src/demos/ActionsDemo.tsx | 83 | ||||
| -rw-r--r-- | src/demos/ChatDemo.tsx | 50 | ||||
| -rw-r--r-- | src/demos/CommandPaletteDemo.tsx | 46 | ||||
| -rw-r--r-- | src/demos/DataDemo.tsx | 72 | ||||
| -rw-r--r-- | src/demos/DialogsDemo.tsx | 95 | ||||
| -rw-r--r-- | src/demos/FeedbackDemo.tsx | 35 | ||||
| -rw-r--r-- | src/demos/InputsDemo.tsx | 58 | ||||
| -rw-r--r-- | src/demos/LayoutDemo.tsx | 52 | ||||
| -rw-r--r-- | src/demos/MenusDemo.tsx | 97 | ||||
| -rw-r--r-- | src/demos/NavigationDemo.tsx | 35 | ||||
| -rw-r--r-- | src/demos/ProvidersDemo.tsx | 29 | ||||
| -rw-r--r-- | src/demos/SelectionDemo.tsx | 55 | ||||
| -rw-r--r-- | src/demos/SelectorsDemo.tsx | 33 | ||||
| -rw-r--r-- | src/demos/TypographyDemo.tsx | 36 |
14 files changed, 776 insertions, 0 deletions
diff --git a/src/demos/ActionsDemo.tsx b/src/demos/ActionsDemo.tsx new file mode 100644 index 0000000..1f5f1ad --- /dev/null +++ b/src/demos/ActionsDemo.tsx @@ -0,0 +1,83 @@ +import { useState } from 'react' +import { Button } from '@astryxdesign/core/Button' +import { HStack } from '@astryxdesign/core/HStack' +import { Icon } from '@astryxdesign/core/Icon' +import { IconButton } from '@astryxdesign/core/IconButton' +import { Kbd } from '@astryxdesign/core/Kbd' +import { Link } from '@astryxdesign/core/Link' +import { + SegmentedControl, + SegmentedControlItem, +} from '@astryxdesign/core/SegmentedControl' +import { Text } from '@astryxdesign/core/Text' +import { ToggleButton, ToggleButtonGroup } from '@astryxdesign/core/ToggleButton' +import { Toolbar } from '@astryxdesign/core/Toolbar' +import { VStack } from '@astryxdesign/core/VStack' +import { Heart, List, LayoutGrid } from 'lucide-react' + +export function ActionsDemo() { + const [layout, setLayout] = useState('网格') + const [view, setView] = useState('概览') + + return ( + <VStack gap={4}> + <Toolbar + label="常用操作" + startContent={ + <HStack gap={2} wrap="wrap"> + <Button label="主要操作" variant="primary" size="sm" /> + <Button label="次要操作" variant="secondary" size="sm" /> + <Button label="幽灵按钮" variant="ghost" size="sm" /> + </HStack> + } + endContent={ + <IconButton + label="收藏" + tooltip="收藏" + variant="ghost" + icon={<Icon icon={Heart} />} + /> + } + /> + + <HStack gap={4} wrap="wrap" vAlign="center"> + <ToggleButtonGroup + label="调整视图布局" + value={layout} + onChange={(value) => setLayout((value as string | null) ?? '网格')} + size="sm"> + <ToggleButton + label="网格" + value="网格" + icon={<Icon icon={LayoutGrid} size="sm" />} + /> + <ToggleButton + label="列表" + value="列表" + icon={<Icon icon={List} size="sm" />} + /> + </ToggleButtonGroup> + + <SegmentedControl + label="切换视图" + value={view} + onChange={setView} + size="sm"> + <SegmentedControlItem label="概览" value="概览" /> + <SegmentedControlItem label="活动" value="活动" /> + <SegmentedControlItem label="成员" value="成员" /> + </SegmentedControl> + </HStack> + + <HStack gap={3} vAlign="center" wrap="wrap"> + <Link href="/about" isStandalone> + 查看关于页 + </Link> + <Text type="supporting" size="sm"> + 快捷键 + </Text> + <Kbd keys="mod+k" /> + </HStack> + </VStack> + ) +} diff --git a/src/demos/ChatDemo.tsx b/src/demos/ChatDemo.tsx new file mode 100644 index 0000000..cf371f2 --- /dev/null +++ b/src/demos/ChatDemo.tsx @@ -0,0 +1,50 @@ +import { + ChatMessage, + ChatMessageBubble, + ChatMessageList, + ChatMessageMetadata, +} from '@astryxdesign/core/Chat' +import { Text } from '@astryxdesign/core/Text' +import { Timestamp } from '@astryxdesign/core/Timestamp' + +export function ChatDemo() { + return ( + <ChatMessageList> + <ChatMessage sender="user"> + <ChatMessageBubble group="first"> + 我把权限模块重构好了。 + </ChatMessageBubble> + <ChatMessageBubble + group="last" + metadata={ + <ChatMessageMetadata + timestamp={ + <Timestamp value="2026-04-28T14:30:00" format="time" /> + } + status="read" + /> + }> + 可以帮我检查一下令牌校验的改动吗? + </ChatMessageBubble> + </ChatMessage> + <ChatMessage sender="assistant"> + <ChatMessageBubble + variant="ghost" + metadata={ + <ChatMessageMetadata + timestamp={ + <Timestamp value="2026-04-28T14:31:00" format="time" /> + } + footer={ + <Text type="supporting" color="secondary"> + Astryx 助手 + </Text> + } + /> + }> + 看过了,刷新令牌轮换和错误处理都覆盖到了,可以发布。 + </ChatMessageBubble> + </ChatMessage> + </ChatMessageList> + ) +} diff --git a/src/demos/CommandPaletteDemo.tsx b/src/demos/CommandPaletteDemo.tsx new file mode 100644 index 0000000..e3c4119 --- /dev/null +++ b/src/demos/CommandPaletteDemo.tsx @@ -0,0 +1,46 @@ +import { useMemo, useState } from 'react' +import { Button } from '@astryxdesign/core/Button' +import { CommandPalette } from '@astryxdesign/core/CommandPalette' +import { HStack } from '@astryxdesign/core/HStack' +import { useToast } from '@astryxdesign/core/Toast' +import { createStaticSource } from '@astryxdesign/core/Typeahead' + +export function CommandPaletteDemo() { + const [open, setOpen] = useState(false) + const showToast = useToast() + const source = useMemo( + () => + createStaticSource([ + { id: 'home', label: '回到概览' }, + { id: 'components', label: '浏览组件' }, + { id: 'about', label: '查看关于' }, + { id: 'theme', label: '切换主题' }, + ]), + [], + ) + + return ( + <> + <HStack gap={2} wrap="wrap"> + <Button + label="打开命令面板" + variant="primary" + onClick={() => setOpen(true)} + /> + <Button + label="显示通知" + variant="secondary" + onClick={() => + showToast({ body: '设置已保存', type: 'info' }) + } + /> + </HStack> + <CommandPalette + isOpen={open} + onOpenChange={setOpen} + searchSource={source} + label="命令面板" + /> + </> + ) +} diff --git a/src/demos/DataDemo.tsx b/src/demos/DataDemo.tsx new file mode 100644 index 0000000..f2a5be7 --- /dev/null +++ b/src/demos/DataDemo.tsx @@ -0,0 +1,72 @@ +import { Avatar } from '@astryxdesign/core/Avatar' +import { Badge } from '@astryxdesign/core/Badge' +import { Divider } from '@astryxdesign/core/Divider' +import { HStack } from '@astryxdesign/core/HStack' +import { List, ListItem } from '@astryxdesign/core/List' +import { Text } from '@astryxdesign/core/Text' +import { Table, pixel, proportional } from '@astryxdesign/core/Table' +import type { TableColumn } from '@astryxdesign/core/Table' +import { VStack } from '@astryxdesign/core/VStack' + +interface Member extends Record<string, unknown> { + id: string + name: string + role: string + projects: number +} + +const MEMBERS: Member[] = [ + { id: '1', name: '林晓', role: '产品设计', projects: 4 }, + { id: '2', name: '陈默', role: '前端开发', projects: 7 }, + { id: '3', name: '周雨', role: '内容运营', projects: 3 }, +] + +const COLUMNS: TableColumn<Member>[] = [ + { key: 'name', header: '成员', width: proportional(1) }, + { key: 'role', header: '角色', width: proportional(1) }, + { key: 'projects', header: '进行中', width: pixel(90) }, +] + +export function DataDemo() { + return ( + <VStack gap={4}> + <List hasDividers> + <ListItem + label="林晓" + description="产品设计 · 4 个项目" + startContent={<Avatar name="林晓" size="sm" />} + endContent={<Badge variant="blue" label="3" />} + /> + <ListItem + label="陈默" + description="前端开发 · 7 个项目" + startContent={<Avatar name="陈默" size="sm" />} + endContent={<Badge variant="teal" label="8" />} + /> + <ListItem + label="周雨" + description="内容运营 · 3 个项目" + startContent={<Avatar name="周雨" size="sm" />} + endContent={<Badge variant="purple" label="2" />} + /> + </List> + + <Divider /> + + <VStack gap={2}> + <HStack gap={2} vAlign="center"> + <Text type="label">团队进度</Text> + <Text type="supporting" size="sm"> + 数据表格 + </Text> + </HStack> + <Table + data={MEMBERS} + columns={COLUMNS} + idKey="id" + density="compact" + /> + </VStack> + </VStack> + ) +} diff --git a/src/demos/DialogsDemo.tsx b/src/demos/DialogsDemo.tsx new file mode 100644 index 0000000..1b887df --- /dev/null +++ b/src/demos/DialogsDemo.tsx @@ -0,0 +1,95 @@ +import { useState } from 'react' +import { BottomSheet } from '@astryxdesign/core/BottomSheet' +import { Button } from '@astryxdesign/core/Button' +import { Dialog, DialogHeader } from '@astryxdesign/core/Dialog' +import { Drawer, DrawerHeader } from '@astryxdesign/core/Drawer' +import { HStack } from '@astryxdesign/core/HStack' +import { Layout, LayoutContent } from '@astryxdesign/core/Layout' +import { Section } from '@astryxdesign/core/Section' +import { Heading } from '@astryxdesign/core/Heading' +import { Text } from '@astryxdesign/core/Text' +import { VStack } from '@astryxdesign/core/VStack' + +type ActiveLayer = 'dialog' | 'drawer' | 'sheet' | null + +export function DialogsDemo() { + const [active, setActive] = useState<ActiveLayer>(null) + + return ( + <> + <HStack gap={2} wrap="wrap"> + <Button label="打开对话框" onClick={() => setActive('dialog')} /> + <Button + label="打开抽屉" + variant="secondary" + onClick={() => setActive('drawer')} + /> + <Button + label="打开底部面板" + variant="secondary" + onClick={() => setActive('sheet')} + /> + </HStack> + + <Dialog + isOpen={active === 'dialog'} + onOpenChange={(open) => setActive(open ? 'dialog' : null)}> + <Layout + header={ + <DialogHeader + title="确认发布" + onOpenChange={(open) => setActive(open ? 'dialog' : null)} + /> + } + content={ + <LayoutContent> + <Text type="body" as="p"> + 发布后,当前版本会立即对全部用户可见。你仍然可以稍后回滚。 + </Text> + </LayoutContent> + } + /> + </Dialog> + + <Drawer + isOpen={active === 'drawer'} + onOpenChange={(open) => setActive(open ? 'drawer' : null)} + label="项目详情" + width={360}> + <Layout + header={ + <DrawerHeader + title="项目详情" + onOpenChange={(open) => setActive(open ? 'drawer' : null)} + /> + } + content={ + <LayoutContent> + <VStack gap={2}> + <Heading level={3}>Astryx 起始模板</Heading> + <Text type="body" color="secondary" as="p"> + 抽屉适合承载不打断主流程的详细信息和次要操作。 + </Text> + </VStack> + </LayoutContent> + } + /> + </Drawer> + + <BottomSheet + isOpen={active === 'sheet'} + onOpenChange={(open) => setActive(open ? 'sheet' : null)} + label="筛选"> + <Section padding={4}> + <VStack gap={3}> + <Heading level={3}>筛选条件</Heading> + <Text type="body" color="secondary" as="p"> + 底部面板适合移动端上的快速筛选和短操作。 + </Text> + <Button label="应用筛选" onClick={() => setActive(null)} /> + </VStack> + </Section> + </BottomSheet> + </> + ) +} diff --git a/src/demos/FeedbackDemo.tsx b/src/demos/FeedbackDemo.tsx new file mode 100644 index 0000000..2909878 --- /dev/null +++ b/src/demos/FeedbackDemo.tsx @@ -0,0 +1,35 @@ +import { Banner } from '@astryxdesign/core/Banner' +import { HStack } from '@astryxdesign/core/HStack' +import { ProgressBar } from '@astryxdesign/core/ProgressBar' +import { Skeleton } from '@astryxdesign/core/Skeleton' +import { Spinner } from '@astryxdesign/core/Spinner' +import { Text } from '@astryxdesign/core/Text' +import { VStack } from '@astryxdesign/core/VStack' + +export function FeedbackDemo() { + return ( + <VStack gap={4}> + <Banner + status="info" + title="新版本已经准备好" + description="刷新页面后即可使用最新的组件与主题。" + /> + <VStack gap={2}> + <Text type="label">工作区初始化</Text> + <ProgressBar label="工作区初始化" value={68} hasValueLabel isLabelHidden /> + </VStack> + <HStack gap={4} vAlign="center" wrap="wrap"> + <HStack gap={2} vAlign="center"> + <Spinner size="sm" /> + <Text type="supporting" size="sm"> + 正在同步数据… + </Text> + </HStack> + <VStack gap={1} width={160}> + <Skeleton width="100%" height={14} index={0} /> + <Skeleton width="70%" height={14} index={1} /> + </VStack> + </HStack> + </VStack> + ) +} diff --git a/src/demos/InputsDemo.tsx b/src/demos/InputsDemo.tsx new file mode 100644 index 0000000..47c9724 --- /dev/null +++ b/src/demos/InputsDemo.tsx @@ -0,0 +1,58 @@ +import { useState } from 'react' +import { Banner } from '@astryxdesign/core/Banner' +import { Button } from '@astryxdesign/core/Button' +import { HStack } from '@astryxdesign/core/HStack' +import { Switch } from '@astryxdesign/core/Switch' +import { TextArea } from '@astryxdesign/core/TextArea' +import { TextInput } from '@astryxdesign/core/TextInput' +import { VStack } from '@astryxdesign/core/VStack' + +export function InputsDemo() { + const [name, setName] = useState('模板项目') + const [description, setDescription] = useState( + '一个使用 Astryx 搭建的 React 应用。', + ) + const [updates, setUpdates] = useState(true) + const [saved, setSaved] = useState(false) + + return ( + <VStack gap={4}> + <TextInput + label="项目名称" + value={name} + onChange={setName} + isRequired + width="100%" + /> + <TextArea + label="项目描述" + value={description} + onChange={setDescription} + rows={3} + width="100%" + /> + <Switch + label="版本更新提醒" + description="有新版本时发送一封简短的邮件。" + value={updates} + onChange={setUpdates} + /> + <HStack gap={2} hAlign="end"> + <Button + label="保存设置" + variant="primary" + onClick={() => setSaved(true)} + /> + </HStack> + {saved ? ( + <Banner + status="success" + title="设置已保存" + description="表单值只保存在当前演示的内存中。" + isDismissable + onDismiss={() => setSaved(false)} + /> + ) : null} + </VStack> + ) +} diff --git a/src/demos/LayoutDemo.tsx b/src/demos/LayoutDemo.tsx new file mode 100644 index 0000000..53da1bd --- /dev/null +++ b/src/demos/LayoutDemo.tsx @@ -0,0 +1,52 @@ +import { useState } from 'react' +import { Collapsible, CollapsibleGroup } from '@astryxdesign/core/Collapsible' +import { Grid } from '@astryxdesign/core/Grid' +import { Heading } from '@astryxdesign/core/Heading' +import { SelectableCard } from '@astryxdesign/core/SelectableCard' +import { Text } from '@astryxdesign/core/Text' +import { VStack } from '@astryxdesign/core/VStack' + +const PLANS = [ + { id: 'basic', name: '基础版', price: '¥9/月', desc: '适合个人项目' }, + { id: 'pro', name: '专业版', price: '¥29/月', desc: '适合小型团队' }, + { id: 'team', name: '团队版', price: '¥99/月', desc: '适合协作组织' }, +] + +export function LayoutDemo() { + const [selected, setSelected] = useState('pro') + + return ( + <VStack gap={4}> + <Grid columns={{ minWidth: 140, max: 3 }} gap={3}> + {PLANS.map((plan) => ( + <SelectableCard + key={plan.id} + label={plan.name} + isSelected={selected === plan.id} + onChange={() => setSelected(plan.id)}> + <VStack gap={1}> + <Heading level={4}>{plan.name}</Heading> + <Text type="large" weight="bold"> + {plan.price} + </Text> + <Text type="supporting" size="sm"> + {plan.desc} + </Text> + </VStack> + </SelectableCard> + ))} + </Grid> + + <CollapsibleGroup type="single" defaultValue="layout"> + <Collapsible + value="layout" + trigger={<Text type="label">这个布局是如何组织的?</Text>}> + <Text type="body" color="secondary" as="p"> + 外层使用 Grid 负责响应式列数,SelectableCard 负责可选中的卡片语义,Collapsible + 负责按需展开说明。所有间距都来自同一套 token。 + </Text> + </Collapsible> + </CollapsibleGroup> + </VStack> + ) +} diff --git a/src/demos/MenusDemo.tsx b/src/demos/MenusDemo.tsx new file mode 100644 index 0000000..c928e6f --- /dev/null +++ b/src/demos/MenusDemo.tsx @@ -0,0 +1,97 @@ +import { useState } from 'react' +import { Avatar } from '@astryxdesign/core/Avatar' +import { Button } from '@astryxdesign/core/Button' +import { Card } from '@astryxdesign/core/Card' +import { ContextMenu } from '@astryxdesign/core/ContextMenu' +import { DropdownMenu } from '@astryxdesign/core/DropdownMenu' +import { HStack } from '@astryxdesign/core/HStack' +import { Heading } from '@astryxdesign/core/Heading' +import { HoverCard } from '@astryxdesign/core/HoverCard' +import { MoreMenu } from '@astryxdesign/core/MoreMenu' +import { Popover } from '@astryxdesign/core/Popover' +import { Text } from '@astryxdesign/core/Text' +import { Tooltip } from '@astryxdesign/core/Tooltip' +import { VStack } from '@astryxdesign/core/VStack' + +export function MenusDemo() { + const [popoverOpen, setPopoverOpen] = useState(false) + + return ( + <VStack gap={4}> + <HStack gap={2} wrap="wrap" vAlign="center"> + <DropdownMenu + button={{ label: '操作菜单' }} + items={[ + { label: '编辑', onClick: () => {} }, + { label: '复制', onClick: () => {} }, + { label: '删除', onClick: () => {} }, + ]} + /> + <MoreMenu + items={[ + { label: '导出', onClick: () => {} }, + { label: '分享', onClick: () => {} }, + { label: '归档', onClick: () => {} }, + ]} + /> + <Tooltip content="这是一段提示文字" placement="above"> + <Button label="悬停查看提示" variant="secondary" /> + </Tooltip> + <Popover + isOpen={popoverOpen} + onOpenChange={setPopoverOpen} + hasAutoFocus={false} + placement="below" + label="设置" + width={260} + content={ + <VStack gap={2}> + <Heading level={4}>快捷设置</Heading> + <Text type="body" color="secondary" as="p"> + 弹层可以承载简短设置、筛选或上下文信息。 + </Text> + </VStack> + }> + <Button label="打开浮层" variant="secondary" /> + </Popover> + <HoverCard + placement="above" + content={ + <VStack gap={2} width={220}> + <HStack gap={2} vAlign="center"> + <Avatar name="林晓" size="md" /> + <VStack gap={0}> + <Heading level={5}>林晓</Heading> + <Text type="supporting" size="sm"> + 产品设计 + </Text> + </VStack> + </HStack> + <Text type="body" color="secondary" as="p"> + 专注于设计系统与复杂交互体验。 + </Text> + </VStack> + }> + <Button label="悬停查看资料" variant="ghost" /> + </HoverCard> + </HStack> + + <ContextMenu + presentation="adaptive" + items={[ + { label: '剪切', onClick: () => {} }, + { label: '复制', onClick: () => {} }, + { label: '粘贴', onClick: () => {} }, + ]}> + <Card padding={4}> + <VStack gap={1} hAlign="center"> + <Text type="label">右键或长按此区域</Text> + <Text type="supporting" size="sm"> + 打开上下文菜单 + </Text> + </VStack> + </Card> + </ContextMenu> + </VStack> + ) +} diff --git a/src/demos/NavigationDemo.tsx b/src/demos/NavigationDemo.tsx new file mode 100644 index 0000000..ebc75f2 --- /dev/null +++ b/src/demos/NavigationDemo.tsx @@ -0,0 +1,35 @@ +import { useState } from 'react' +import { BreadcrumbItem, Breadcrumbs } from '@astryxdesign/core/Breadcrumbs' +import { VStack } from '@astryxdesign/core/VStack' +import { Step, Stepper } from '@astryxdesign/core/Stepper' +import { Tab, TabList } from '@astryxdesign/core/TabList' + +export function NavigationDemo() { + const [tab, setTab] = useState('overview') + const [step, setStep] = useState(2) + + return ( + <VStack gap={5}> + <Breadcrumbs> + <BreadcrumbItem href="/">首页</BreadcrumbItem> + <BreadcrumbItem href="/components">组件</BreadcrumbItem> + <BreadcrumbItem isCurrent>导航示例</BreadcrumbItem> + </Breadcrumbs> + + <TabList value={tab} onChange={setTab} hasDivider> + <Tab value="overview" label="概览" /> + <Tab value="activity" label="活动" /> + <Tab value="settings" label="设置" /> + </TabList> + + <VStack width="100%"> + <Stepper activeStep={step} orientation="horizontal" onStepClick={setStep}> + <Step step={0} label="购物车" /> + <Step step={1} label="配送" /> + <Step step={2} label="支付" /> + <Step step={3} label="完成" /> + </Stepper> + </VStack> + </VStack> + ) +} diff --git a/src/demos/ProvidersDemo.tsx b/src/demos/ProvidersDemo.tsx new file mode 100644 index 0000000..48f5a9f --- /dev/null +++ b/src/demos/ProvidersDemo.tsx @@ -0,0 +1,29 @@ +import { Button } from '@astryxdesign/core/Button' +import { HStack } from '@astryxdesign/core/HStack' +import { Link } from '@astryxdesign/core/Link' +import { Text } from '@astryxdesign/core/Text' +import { VStack } from '@astryxdesign/core/VStack' +import { useThemeMode } from '../theme/useThemeMode' + +export function ProvidersDemo() { + const { mode, toggleMode } = useThemeMode() + const nextModeLabel = mode === 'light' ? '切换到深色主题' : '切换到浅色主题' + + return ( + <VStack gap={3}> + <Text type="body" color="secondary" as="p"> + 当前页面已经由 Theme、LinkProvider 和 InternationalizationProvider + 包裹。切换主题或点击站内链接即可看到实际效果。 + </Text> + <HStack gap={3} wrap="wrap" vAlign="center"> + <Button label={nextModeLabel} variant="primary" onClick={toggleMode} /> + <Link href="/about" isStandalone> + 通过 LinkProvider 打开的站内链接 + </Link> + </HStack> + <Text type="supporting" size="sm"> + Astryx 内置文案同样是中文,例如「必填」「关闭」「跳至内容」。 + </Text> + </VStack> + ) +} diff --git a/src/demos/SelectionDemo.tsx b/src/demos/SelectionDemo.tsx new file mode 100644 index 0000000..41ca918 --- /dev/null +++ b/src/demos/SelectionDemo.tsx @@ -0,0 +1,55 @@ +import { useState } from 'react' +import { + CheckboxList, + CheckboxListItem, +} from '@astryxdesign/core/CheckboxList' +import { Grid } from '@astryxdesign/core/Grid' +import { RadioList, RadioListItem } from '@astryxdesign/core/RadioList' +import { Slider } from '@astryxdesign/core/Slider' + +export function SelectionDemo() { + const [notifications, setNotifications] = useState<string[]>(['email']) + const [plan, setPlan] = useState('team') + const [volume, setVolume] = useState(60) + + return ( + <Grid columns={{ minWidth: 220, max: 2 }} gap={5}> + <CheckboxList + label="通知方式" + description="可以选择多个渠道。" + value={notifications} + onChange={setNotifications} + hasDividers> + <CheckboxListItem + label="邮件" + value="email" + description="每周一发送摘要" + /> + <CheckboxListItem + label="推送" + value="push" + description="在设备上即时提醒" + /> + <CheckboxListItem + label="短信" + value="sms" + description="仅用于重要通知" + /> + </CheckboxList> + + <RadioList label="当前套餐" value={plan} onChange={setPlan}> + <RadioListItem label="个人版" value="personal" /> + <RadioListItem label="团队版" value="team" /> + <RadioListItem label="企业版" value="enterprise" /> + </RadioList> + + <Slider + label="提醒音量" + value={volume} + onChange={setVolume} + width="100%" + valueDisplay="text" + /> + </Grid> + ) +} diff --git a/src/demos/SelectorsDemo.tsx b/src/demos/SelectorsDemo.tsx new file mode 100644 index 0000000..5fd299f --- /dev/null +++ b/src/demos/SelectorsDemo.tsx @@ -0,0 +1,33 @@ +import { useState } from 'react' +import { DateInput } from '@astryxdesign/core/DateInput' +import { Grid } from '@astryxdesign/core/Grid' +import { Selector } from '@astryxdesign/core/Selector' + +type DateString = + `${number}${number}${number}${number}-${number}${number}-${number}${number}` + +export function SelectorsDemo() { + const [fruit, setFruit] = useState<string | undefined>() + const [date, setDate] = useState<DateString | undefined>() + + return ( + <Grid columns={{ minWidth: 220, max: 2 }} gap={5}> + <Selector + label="最喜欢的水果" + options={['苹果', '香蕉', '橙子', '芒果', '菠萝']} + placeholder="请选择一种水果" + value={fruit} + onChange={setFruit} + width="100%" + /> + <DateInput + label="开始日期" + placeholder="选择日期" + value={date} + onChange={setDate} + hasClear + width="100%" + /> + </Grid> + ) +} diff --git a/src/demos/TypographyDemo.tsx b/src/demos/TypographyDemo.tsx new file mode 100644 index 0000000..75842d9 --- /dev/null +++ b/src/demos/TypographyDemo.tsx @@ -0,0 +1,36 @@ +import { Blockquote } from '@astryxdesign/core/Blockquote' +import { CodeBlock } from '@astryxdesign/core/CodeBlock' +import { Divider } from '@astryxdesign/core/Divider' +import { Heading } from '@astryxdesign/core/Heading' +import { Text } from '@astryxdesign/core/Text' +import { VStack } from '@astryxdesign/core/VStack' + +const SNIPPET = `const theme = defineTheme({ + name: 'ocean', + tokens: {'--color-accent': '#0077B6'}, +})` + +export function TypographyDemo() { + return ( + <VStack gap={3}> + <VStack gap={1}> + <Heading level={3}>清晰的内容层级</Heading> + <Text type="body" color="secondary" as="p"> + 标题、正文、辅助文字和代码共享同一套字体与节奏,让界面在中文和英文下都保持稳定。 + </Text> + </VStack> + <Blockquote cite="Astryx 设计原则"> + 把复杂性留在系统里,把清晰留给界面。 + </Blockquote> + <Divider /> + <CodeBlock + code={SNIPPET} + language="tsx" + title="theme.ts" + hasLineNumbers={false} + width="100%" + size="sm" + /> + </VStack> + ) +} |
