Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ storybook-static
.DS_Store
.env
.env.*

# Editor / local tooling (do not commit)
.cursor/
.vscode/
3 changes: 2 additions & 1 deletion .storybook/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { addons } from '@storybook/manager-api';
import { create } from '@storybook/theming/create';

/**
* Strapi Design System 使用清晰的品牌色與文件風格;此處採相近的「設計系統文件」基調(亮色、品牌主色)。
* Strapi Design System uses crisp brand colors and a documentation-style layout; here we adopt a similar
* "design system documentation" look (light theme, brand primary color).
* @see https://design-system.strapi.io/
*/
const theme = create({
Expand Down
4 changes: 2 additions & 2 deletions src/components/AlertDialog/AlertDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ReactNode } from 'react';
import { useId } from 'react';
import './AlertDialog.css';

/** Figma `Type=Desktop`9:8006)與 `Type=Mobile`9:7999)。 */
/** Figma `Type=Desktop` (9:8006) and `Type=Mobile` (9:7999). */
export type AlertDialogLayout = 'desktop' | 'mobile';

export type AlertDialogAction = {
Expand All @@ -18,7 +18,7 @@ export type AlertDialogProps = {
secondaryAction: AlertDialogAction;
primaryAction: AlertDialogAction;
className?: string;
/** 設為 true 時加上 `aria-modal`(外層需搭配遮罩與 focus trap 才算完整 modal)。 */
/** When set to true, adds `aria-modal` (the outer scope should include an overlay and focus trap for a complete modal). */
modal?: boolean;
};

Expand Down
6 changes: 3 additions & 3 deletions src/components/Breadcrumb/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type BreadcrumbEntry =

export type BreadcrumbProps = {
items: BreadcrumbEntry[];
/** `nav` 的 `aria-label` */
/** `nav` aria-label */
ariaLabel?: string;
className?: string;
};
Expand All @@ -20,7 +20,7 @@ const iconProps = {
focusable: false as const,
};

export function Breadcrumb({ items, ariaLabel = '麵包屑', className }: BreadcrumbProps) {
export function Breadcrumb({ items, ariaLabel = 'Breadcrumb', className }: BreadcrumbProps) {
const rootClass = ['sds-breadcrumb', className].filter(Boolean).join(' ');

return (
Expand All @@ -42,7 +42,7 @@ export function Breadcrumb({ items, ariaLabel = '麵包屑', className }: Breadc
function BreadcrumbSegment({ item }: { item: BreadcrumbEntry }) {
if ('ellipsis' in item && item.ellipsis) {
return (
<span className="sds-breadcrumb__ellipsis" title="已摺疊的路徑" aria-label="已省略的中間階層">
<span className="sds-breadcrumb__ellipsis" title="Collapsed path" aria-label="Omitted intermediate segments">
<Ellipsis {...iconProps} />
</span>
);
Expand Down
8 changes: 4 additions & 4 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import './Button.css';

/**
* Orbie Button page — Primary / Secondary (solid gray) / Outline / Ghost / Ghost Muted / Destructive.
* `danger` `destructive` 別名(向後相容)。
* `danger` is an alias for `destructive` (backwards compatible).
*/
export type ButtonVariant =
| 'primary'
Expand All @@ -14,16 +14,16 @@ export type ButtonVariant =
| 'destructive'
| 'danger';

/** `md` = Regularmin-height 36);`sm` = Smallmin-height 32)。 */
/** `md` = Regular (min-height 36); `sm` = Small (min-height 32). */
export type ButtonSize = 'sm' | 'md';

export type ButtonProps = {
children: ReactNode;
variant?: ButtonVariant;
size?: ButtonSize;
/** 左側圖示(設計稿約 13.25px */
/** Left icon (about 13.25px in the design). */
iconLeft?: ReactNode;
/** 右側圖示 */
/** Right icon. */
iconRight?: ReactNode;
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'>;

Expand Down
8 changes: 4 additions & 4 deletions src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import './DatePicker.css';
const WEEKDAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] as const;

export type DatePickerCalendarProps = {
/** 當月任意一天(僅年月有效) */
/** Any day in the current month (only year/month are used). */
month: Date;
selected: Date | null;
onSelect: (date: Date) => void;
Expand Down Expand Up @@ -40,11 +40,11 @@ export function DatePickerCalendar({
return (
<div className={['sds-date-picker__calendar', className].filter(Boolean).join(' ')}>
<div className="sds-date-picker__header">
<button type="button" className="sds-date-picker__nav" onClick={onPrevMonth} aria-label="上個月">
<button type="button" className="sds-date-picker__nav" onClick={onPrevMonth} aria-label="Previous month">
<ChevronLeft strokeWidth={2} />
</button>
<p className="sds-date-picker__title">{title}</p>
<button type="button" className="sds-date-picker__nav" onClick={onNextMonth} aria-label="下個月">
<button type="button" className="sds-date-picker__nav" onClick={onNextMonth} aria-label="Next month">
<ChevronRight strokeWidth={2} />
</button>
</div>
Expand Down Expand Up @@ -193,7 +193,7 @@ export function DatePicker({
</button>

{open ? (
<div className="sds-date-picker__popover" role="dialog" aria-modal="true" aria-label="選擇日期">
<div className="sds-date-picker__popover" role="dialog" aria-modal="true" aria-label="Select date">
<DatePickerCalendar
month={viewMonth}
selected={value}
Expand Down
2 changes: 1 addition & 1 deletion src/components/DatePicker/calendarGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export type CalendarCell = {
inCurrentMonth: boolean;
};

/** 固定 42 格(6 週 × 7 日),週日起始 — 對齊 Figma 月曆。 */
/** Fixed 42 cells (6 weeks x 7 days), starting on Sunday — aligned with the Figma calendar. */
export function getCalendarGrid(year: number, monthIndex: number): CalendarCell[] {
const cells: CalendarCell[] = [];
const first = new Date(year, monthIndex, 1);
Expand Down
6 changes: 3 additions & 3 deletions src/components/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ function getPaginationTokens(opts: {
}

export type PaginationProps = {
/** 目前頁(1-based */
/** Current page (1-based). */
page: number;
/** 總頁數 */
/** Total number of pages. */
pageCount: number;
onPageChange: (page: number) => void;
className?: string;
boundaryCount?: number;
siblingCount?: number;
/** 是否顯示前後的標籤(Previous/Next */
/** Whether to show the Previous/Next labels. */
showNavLabel?: boolean;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type SidebarProps = {
onItemClick?: (item: SidebarItem) => void;
};

export function Sidebar({ collapsed = false, groups, ariaLabel = '側欄', className, onItemClick }: SidebarProps) {
export function Sidebar({ collapsed = false, groups, ariaLabel = 'Sidebar', className, onItemClick }: SidebarProps) {
const rootClass = ['sds-sidebar', collapsed ? 'sds-sidebar--collapsed' : 'sds-sidebar--expanded', className]
.filter(Boolean)
.join(' ');
Expand Down
2 changes: 1 addition & 1 deletion src/components/Switch/Switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export type SwitchProps = {
onCheckedChange: (checked: boolean) => void;
disabled?: boolean;
className?: string;
/** 用於 aria-label;若你外層有 <label>,可不填 */
/** Used for aria-label; if the outer scope already has a <label>, you can omit it. */
ariaLabel?: string;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type TabsProps = {
ariaLabel?: string;
};

export function Tabs({ items, value, onValueChange, className, ariaLabel = '分頁籤' }: TabsProps) {
export function Tabs({ items, value, onValueChange, className, ariaLabel = 'Tabs' }: TabsProps) {
return (
<div role="tablist" aria-label={ariaLabel} className={['sds-tabs', className].filter(Boolean).join(' ')} data-sds-component="Tabs">
{items.map((item) => {
Expand Down
2 changes: 1 addition & 1 deletion src/icons/orbieIconMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import {
/**
* Orbie UI KIT — `icons` page (Figma node `9:11137`).
* Slugs match layer names after `Icon / …` (Lucide-aligned).
* `gpu`: Figma GPULucide 無對應圖示,以 `Cpu` 近似。
* `gpu`: Figma has a GPU icon; Lucide doesn't have a matching icon, so we approximate it with `Cpu`.
*/
export const orbieIconMap = {
'arrow-down-to-line': ArrowDownToLine,
Expand Down
5 changes: 2 additions & 3 deletions stories/Components/AlertDialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { Meta, StoryObj } from '@storybook/react';
import { AlertDialog } from '../../src/components/AlertDialog';

const meta = {
title: 'Components/AlertDialog',
component: AlertDialog,
tags: ['autodocs'],
parameters: {
Expand All @@ -21,14 +20,14 @@ export default meta;

type Story = StoryObj<typeof meta>;

/** Figma `Type=Desktop`9:8006):次要鍵在左、主鍵在右;文案左對齊。 */
/** Figma `Type=Desktop` (9:8006): Secondary action on the left, primary action on the right; left-aligned copy. */
export const Desktop: Story = {
args: {
layout: 'desktop',
},
};

/** Figma `Type=Mobile`9:7999):主鍵在上、次要鍵在下、全寬;標題與內文置中。 */
/** Figma `Type=Mobile` (9:7999): Primary action on top, secondary action below, full width; title and body are centered. */
export const Mobile: Story = {
args: {
layout: 'mobile',
Expand Down
77 changes: 59 additions & 18 deletions stories/Components/Badge.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ const rowStyle: CSSProperties = {
};

const meta = {
title: 'Components/Badge',
component: Badge,
tags: ['autodocs'],
args: {
Expand All @@ -51,26 +50,30 @@ const meta = {
shape: 'rounded' as const,
layout: 'default' as const,
},
argTypes: {
tone: {
control: 'inline-radio',
options: ['blue', 'yellow', 'red', 'green'],
},
shape: {
control: 'inline-radio',
options: ['rounded', 'pill'],
},
layout: {
control: 'inline-radio',
options: ['default', 'numeric'],
},
},
parameters: {
layout: 'centered',
layout: 'padded',
backgrounds: {
grid: {
// Helps match design-system docs where spacing/alignment is verified via a grid overlay.
cellSize: 20,
opacity: 0.5,
cellAmount: 5,
},
},
docs: {
description: {
component: `Orbie UI KIT — **Badge** examples frame. Design tokens are defined in \`src/tokens.css\` (Secondary-* colors, spacing, radii, paragraph mini bold).

Usage:
\`\`\`tsx
import { Badge } from '@syncai/design-system';
import '@syncai/design-system/styles.css';

<Badge tone="blue" shape="rounded">
Healthy
</Badge>;
\`\`\`

[Figma — Examples (node 9:7795)](${figmaExamples})`,
},
},
Expand All @@ -91,6 +94,44 @@ export const Playground: Story = {
render: (args) => <Badge {...args} icon={<IconSmile />} />,
};

export const ToneVariants: Story = {
args: {
// Text-only (icon omitted) so users can focus on tone semantics.
children: 'Degraded',
tone: 'yellow',
shape: 'rounded',
layout: 'default',
},
};

export const ShapePill: Story = {
args: {
children: '+12.5%',
tone: 'green',
shape: 'pill',
layout: 'default',
},
};

export const NumericDefault: Story = {
args: {
children: '23',
tone: 'red',
shape: 'rounded',
layout: 'numeric',
},
};

export const IconAndTextSingle: Story = {
args: {
children: 'Healthy',
tone: 'blue',
shape: 'rounded',
layout: 'default',
},
render: (args) => <Badge {...args} icon={<IconSmile />} />,
};

/** Icon + text — rounded rectangles (semantic/rounded-lg). */
export const IconAndTextRounded: Story = {
name: 'Pattern / Icon + text (rounded)',
Expand Down Expand Up @@ -118,10 +159,10 @@ export const TextOnly: Story = {
Online
</Badge>
<Badge tone="red" shape="rounded">
系統
System
</Badge>
<Badge tone="blue" shape="rounded">
裝置
Device
</Badge>
</div>
),
Expand Down
9 changes: 4 additions & 5 deletions stories/Components/Breadcrumb.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { Meta, StoryObj } from '@storybook/react';
import { Breadcrumb } from '../../src/components/Breadcrumb';

const meta = {
title: 'Components/Breadcrumb',
component: Breadcrumb,
tags: ['autodocs'],
parameters: {
Expand All @@ -15,7 +14,7 @@ export default meta;

type Story = StoryObj<typeof meta>;

/** 對齊 Figma Examples9:7675):Home → … → Components → 目前頁。 */
/** Matches Figma Examples (9:7675): Home → … → Components → Current page. */
export const OrbieExample: Story = {
args: {
items: [
Expand All @@ -30,9 +29,9 @@ export const OrbieExample: Story = {
export const SimplePath: Story = {
args: {
items: [
{ label: '首頁', href: '#' },
{ label: '設定', href: '#' },
{ label: '帳號', current: true },
{ label: 'Home', href: '#' },
{ label: 'Settings', href: '#' },
{ label: 'Account', current: true },
],
},
};
13 changes: 1 addition & 12 deletions stories/Components/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { Meta, StoryObj } from '@storybook/react';
import { Button } from '../../src/components/Button';

const meta = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
args: {
Expand All @@ -12,22 +11,12 @@ const meta = {
size: 'md',
disabled: false,
},
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline', 'ghost', 'ghostMuted', 'destructive', 'danger'],
},
size: {
control: 'inline-radio',
options: ['sm', 'md'],
},
},
parameters: {
layout: 'centered',
docs: {
description: {
component:
'Orbie Button 頁(Figma):PrimarySecondary(灰底)、OutlineGhostGhost MutedDestructive`danger` Destructive。尺寸 Regular / Small',
'Orbie Button page (Figma): Primary, Secondary (gray background), Outline, Ghost, Ghost Muted, Destructive; `danger` is the same as Destructive. Sizes: Regular / Small.',
},
},
},
Expand Down
Loading