@uxuissk/design-system 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,6 +48,79 @@ export declare interface AccordionProps {
48
48
 
49
49
  export declare type AccordionType = "single" | "multiple";
50
50
 
51
+ export declare interface AdvancedColumn<T = Record<string, any>> {
52
+ /** Unique column key — matches field name in data row */
53
+ key: string;
54
+ /** Column header label */
55
+ header: string;
56
+ /** Enable server-side sort click */
57
+ sortable?: boolean;
58
+ /** Fixed pixel or CSS width */
59
+ width?: number | string;
60
+ /** Minimum width in px (default 80) */
61
+ minWidth?: number;
62
+ /** Text alignment */
63
+ align?: "left" | "center" | "right";
64
+ /** Stick to left edge (frozen column) */
65
+ frozen?: boolean;
66
+ /** Allow hiding via column toggle. Default true */
67
+ hideable?: boolean;
68
+ /** Start hidden */
69
+ defaultHidden?: boolean;
70
+ /** Custom cell renderer */
71
+ render?: (value: any, row: T, index: number) => default_2.ReactNode;
72
+ }
73
+
74
+ export declare function AdvancedDataTable<T extends Record<string, any>>({ columns, data, rowKey, pagination, sortBy, sortOrder, onPageChange, onSortChange, selectable, selectedRows: controlledSelected, onSelectionChange, bulkActions, onRowClick, expandedRowRender, loading, loadingRows, error, emptyMessage, emptyDescription, showColumnToggle, size, stickyHeader, className, }: AdvancedDataTableProps<T>): JSX.Element;
75
+
76
+ export declare interface AdvancedDataTableProps<T = Record<string, any>> {
77
+ /** Column definitions */
78
+ columns: AdvancedColumn<T>[];
79
+ /** Row data */
80
+ data: T[];
81
+ /** Field to use as unique row key (default: "id") */
82
+ rowKey?: string;
83
+ /** Server pagination metadata */
84
+ pagination?: PaginationMeta;
85
+ /** Currently sorted column key */
86
+ sortBy?: string;
87
+ /** Current sort direction */
88
+ sortOrder?: SortOrder;
89
+ /** Called when user changes page or page size */
90
+ onPageChange?: (page: number, pageSize: number) => void;
91
+ /** Called when user clicks a sortable column */
92
+ onSortChange?: (sortBy: string, sortOrder: SortOrder) => void;
93
+ /** Enable row checkboxes */
94
+ selectable?: boolean;
95
+ /** Controlled selection (set of rowKey values) */
96
+ selectedRows?: Set<string | number>;
97
+ /** Called when selection changes */
98
+ onSelectionChange?: (selected: Set<string | number>, rows: T[]) => void;
99
+ /** Actions shown in bulk action bar when rows are selected */
100
+ bulkActions?: BulkAction[];
101
+ /** Called when a row is clicked */
102
+ onRowClick?: (row: T) => void;
103
+ /** Render function for expanded row content */
104
+ expandedRowRender?: (row: T) => default_2.ReactNode;
105
+ /** Show skeleton loading rows */
106
+ loading?: boolean;
107
+ /** Number of skeleton rows to show while loading */
108
+ loadingRows?: number;
109
+ /** Error message — renders error state instead of table body */
110
+ error?: string;
111
+ /** Custom empty state message */
112
+ emptyMessage?: string;
113
+ /** Custom empty state description */
114
+ emptyDescription?: string;
115
+ /** Show column visibility toggle button */
116
+ showColumnToggle?: boolean;
117
+ size?: AdvancedTableSize;
118
+ stickyHeader?: boolean;
119
+ className?: string;
120
+ }
121
+
122
+ export declare type AdvancedTableSize = "sm" | "md" | "lg";
123
+
51
124
  export declare function Alert({ variant, title, children, dismissible, onDismiss, action, icon, className }: AlertProps): JSX.Element | null;
52
125
 
53
126
  declare interface AlertProps {
@@ -144,6 +217,13 @@ export declare type BreadcrumbSeparator = "chevron" | "slash" | "dot";
144
217
 
145
218
  export declare type BreadcrumbSize = "sm" | "md" | "lg";
146
219
 
220
+ export declare interface BulkAction {
221
+ label: string;
222
+ icon?: default_2.ReactNode;
223
+ variant?: "default" | "destructive";
224
+ onClick: (selectedKeys: Array<string | number>) => void;
225
+ }
226
+
147
227
  export declare function ButtonGroup({ children, className, }: {
148
228
  children: default_2.ReactNode;
149
229
  className?: string;
@@ -435,7 +515,7 @@ declare interface DSInputProps extends Omit<default_2.InputHTMLAttributes<HTMLIn
435
515
  helperText?: string;
436
516
  errorMessage?: string;
437
517
  successMessage?: string;
438
- inputSize?: InputSize;
518
+ size?: InputSize;
439
519
  variant?: InputVariant;
440
520
  state?: InputState;
441
521
  leftIcon?: default_2.ReactNode;
@@ -456,7 +536,7 @@ declare function DSRadio({ value, label, description, disabled: localDisabled, s
456
536
  export { DSRadio }
457
537
  export { DSRadio as Radio }
458
538
 
459
- declare function DSTable<T extends Record<string, any>>({ columns, data, size, striped, hoverable, bordered, selectable, selectedRows: controlledSelected, onSelectionChange, loading, emptyMessage, stickyHeader, className, }: TableProps<T>): JSX.Element;
539
+ declare function DSTable<T extends Record<string, any>>({ columns, data, size, striped, hoverable, bordered, selectable, selectedRows: controlledSelected, onSelectionChange, loading, emptyMessage, stickyHeader, flush, className, }: TableProps<T>): JSX.Element;
460
540
  export { DSTable }
461
541
  export { DSTable as Table }
462
542
 
@@ -469,7 +549,7 @@ declare interface DSTextareaProps extends Omit<default_2.TextareaHTMLAttributes<
469
549
  helperText?: string;
470
550
  errorMessage?: string;
471
551
  successMessage?: string;
472
- inputSize?: InputSize;
552
+ size?: InputSize;
473
553
  variant?: InputVariant;
474
554
  state?: InputState;
475
555
  showCharCount?: boolean;
@@ -816,6 +896,12 @@ export declare interface PageHeaderProps {
816
896
 
817
897
  export declare function Pagination({ currentPage, totalPages, onPageChange, siblingCount, showFirstLast, showPrevNext, showPageSize, pageSizeOptions, pageSize, onPageSizeChange, totalItems, size, variant, disabled, showPageInfo, showItemsInfo, prevLabel, nextLabel, }: PaginationProps): JSX.Element;
818
898
 
899
+ export declare interface PaginationMeta {
900
+ page: number;
901
+ pageSize: number;
902
+ totalCount: number;
903
+ }
904
+
819
905
  export declare interface PaginationProps {
820
906
  /** Current active page (1-indexed) */
821
907
  currentPage: number;
@@ -966,12 +1052,44 @@ declare interface SearchSuggestion {
966
1052
 
967
1053
  export declare type SearchVariant = "default" | "outlined" | "filled";
968
1054
 
969
- export declare function Sidebar({ brand, groups, activeItem, onNavigate, collapsed, onCollapsedChange, className, }: SidebarProps): JSX.Element;
1055
+ export declare function Sidebar({ brand, accountSwitcher, groups, activeItem, onNavigate, collapsed, onCollapsedChange, showCollapseToggle, version, versionDate, className, }: SidebarProps): JSX.Element;
970
1056
 
971
1057
  export declare namespace Sidebar {
972
1058
  var displayName: string;
973
1059
  }
974
1060
 
1061
+ export declare interface SidebarAccountItem {
1062
+ id: string;
1063
+ /** Display name (company / branch / provider) */
1064
+ name: string;
1065
+ /** Handle or sub-label e.g. "@phoenix" */
1066
+ handle?: string;
1067
+ /** Avatar image URL */
1068
+ avatarUrl?: string;
1069
+ /** Fallback initials when no avatarUrl */
1070
+ avatarFallback?: string;
1071
+ }
1072
+
1073
+ export declare function SidebarAccountSwitcher({ company, branch, provider, companies, branches, providers, onCompanyChange, onBranchChange, onProviderChange, collapsed, }: SidebarAccountSwitcherProps): JSX.Element;
1074
+
1075
+ export declare namespace SidebarAccountSwitcher {
1076
+ var displayName: string;
1077
+ }
1078
+
1079
+ export declare interface SidebarAccountSwitcherProps {
1080
+ company?: SidebarAccountItem;
1081
+ branch?: SidebarAccountItem;
1082
+ provider?: SidebarAccountItem;
1083
+ companies?: SidebarAccountItem[];
1084
+ branches?: SidebarAccountItem[];
1085
+ providers?: SidebarAccountItem[];
1086
+ onCompanyChange?: (item: SidebarAccountItem) => void;
1087
+ onBranchChange?: (item: SidebarAccountItem) => void;
1088
+ onProviderChange?: (item: SidebarAccountItem) => void;
1089
+ /** Collapsed icon-only mode */
1090
+ collapsed?: boolean;
1091
+ }
1092
+
975
1093
  export declare interface SidebarBrand {
976
1094
  /** Brand name */
977
1095
  name: string;
@@ -1010,6 +1128,14 @@ export declare interface SidebarProps {
1010
1128
  collapsed?: boolean;
1011
1129
  /** Toggle collapse callback */
1012
1130
  onCollapsedChange?: (collapsed: boolean) => void;
1131
+ /** Show the footer collapse toggle button (default: true). Set false when collapse is controlled from TopNavbar */
1132
+ showCollapseToggle?: boolean;
1133
+ /** Account/Company/Branch switcher shown in header area */
1134
+ accountSwitcher?: SidebarAccountSwitcherProps;
1135
+ /** App version string e.g. "v1.4.0" */
1136
+ version?: string;
1137
+ /** Version date string e.g. "March 10, 2026" */
1138
+ versionDate?: string;
1013
1139
  /** Sidebar width (default: 256px) */
1014
1140
  width?: string;
1015
1141
  /** Additional class name */
@@ -1034,6 +1160,8 @@ export declare function SkeletonTable(): JSX.Element;
1034
1160
 
1035
1161
  export declare type SkeletonVariant = "text" | "rectangular" | "circular" | "rounded";
1036
1162
 
1163
+ export declare type SortOrder = "asc" | "desc";
1164
+
1037
1165
  export declare function Spinner({ size, color, className }: SpinnerProps): JSX.Element;
1038
1166
 
1039
1167
  export declare namespace Spinner {
@@ -1157,6 +1285,8 @@ declare interface TableProps<T = any> {
1157
1285
  loading?: boolean;
1158
1286
  emptyMessage?: string;
1159
1287
  stickyHeader?: boolean;
1288
+ /** Remove border and border-radius — use when table is already inside a bordered container */
1289
+ flush?: boolean;
1160
1290
  className?: string;
1161
1291
  }
1162
1292
 
@@ -1292,7 +1422,7 @@ export declare interface TooltipProps {
1292
1422
  className?: string;
1293
1423
  }
1294
1424
 
1295
- export declare function TopNavbar({ brand, breadcrumbs, actions, user, height, showSearch, searchPlaceholder, onSearchClick, notificationCount, onNotificationClick, onMobileMenuClick, onUserClick, onBreadcrumbClick, className, }: TopNavbarProps): JSX.Element;
1425
+ export declare function TopNavbar({ brand, breadcrumbs, title, actions, user, height, showSearch, searchPlaceholder, onSearchClick, notificationCount, onNotificationClick, onMobileMenuClick, onSidebarToggle, onUserClick, onBreadcrumbClick, className, }: TopNavbarProps): JSX.Element;
1296
1426
 
1297
1427
  export declare namespace TopNavbar {
1298
1428
  var displayName: string;
@@ -1310,6 +1440,8 @@ export declare interface TopNavbarProps {
1310
1440
  brand?: TopNavbarBrand;
1311
1441
  /** Breadcrumb items */
1312
1442
  breadcrumbs?: BreadcrumbItem_2[];
1443
+ /** Page title displayed after brand (used for current page context) */
1444
+ title?: string;
1313
1445
  /** Right-side action area */
1314
1446
  actions?: default_2.ReactNode;
1315
1447
  /** User avatar */
@@ -1326,8 +1458,10 @@ export declare interface TopNavbarProps {
1326
1458
  notificationCount?: number;
1327
1459
  /** Notification click handler */
1328
1460
  onNotificationClick?: () => void;
1329
- /** Mobile menu click handler */
1461
+ /** Mobile menu click handler (shows only on mobile) */
1330
1462
  onMobileMenuClick?: () => void;
1463
+ /** Sidebar toggle handler — shows burger icon (always visible) to collapse/expand sidebar */
1464
+ onSidebarToggle?: () => void;
1331
1465
  /** User click handler */
1332
1466
  onUserClick?: () => void;
1333
1467
  /** Breadcrumb click handler */
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@uxuissk/design-system",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "private": false,
5
5
  "type": "module",
6
+ "workspaces": [
7
+ "packages/*"
8
+ ],
6
9
  "main": "./dist/sellsuki-ds.umd.cjs",
7
10
  "module": "./dist/sellsuki-ds.js",
8
11
  "types": "./dist/types/index.d.ts",
@@ -16,7 +19,11 @@
16
19
  "./styles.css": "./dist/sellsuki-ds.css"
17
20
  },
18
21
  "files": [
19
- "dist",
22
+ "dist/sellsuki-ds.js",
23
+ "dist/sellsuki-ds.umd.cjs",
24
+ "dist/sellsuki-ds.css",
25
+ "dist/fonts",
26
+ "dist/types",
20
27
  "README.md"
21
28
  ],
22
29
  "sideEffects": [
@@ -25,19 +32,20 @@
25
32
  "scripts": {
26
33
  "dev": "vite",
27
34
  "build": "vite build",
28
- "build:lib": "vite build --config vite.lib.config.ts",
35
+ "clean": "node --input-type=module -e \"import{rmSync}from'fs';try{rmSync('dist',{recursive:true,force:true})}catch{}\"",
36
+ "build:lib": "npm run clean && npm run lint:svelte-css && vite build --config vite.lib.config.ts && node scripts/inject-font-face.mjs && npm run hardcode:log",
37
+ "lint:svelte-css": "stylelint 'src/lib/svelte/**/*.svelte' --allow-empty-input",
38
+ "hardcode:log": "node scripts/check-hardcodes.mjs",
29
39
  "storybook": "storybook dev -p 6006",
30
40
  "build-storybook": "storybook build",
31
41
  "prepublishOnly": "npm run build:lib"
32
42
  },
33
- "dependencies": {},
34
43
  "peerDependencies": {
44
+ "lucide-react": ">=0.400.0",
35
45
  "react": "^18.0.0 || ^19.0.0",
36
- "react-dom": "^18.0.0 || ^19.0.0",
37
- "lucide-react": ">=0.400.0"
46
+ "react-dom": "^18.0.0 || ^19.0.0"
38
47
  },
39
48
  "devDependencies": {
40
- "lucide-react": "0.487.0",
41
49
  "@emotion/react": "11.14.0",
42
50
  "@emotion/styled": "11.14.1",
43
51
  "@mui/icons-material": "7.3.5",
@@ -85,8 +93,10 @@
85
93
  "date-fns": "3.6.0",
86
94
  "embla-carousel-react": "8.6.0",
87
95
  "input-otp": "1.4.2",
96
+ "lucide-react": "0.487.0",
88
97
  "motion": "12.23.24",
89
98
  "next-themes": "0.4.6",
99
+ "postcss-html": "^1.8.1",
90
100
  "react-day-picker": "8.10.1",
91
101
  "react-dnd": "16.0.1",
92
102
  "react-dnd-html5-backend": "16.0.1",
@@ -99,13 +109,16 @@
99
109
  "recharts": "2.15.2",
100
110
  "sonner": "2.0.3",
101
111
  "storybook": "^8.4.0",
112
+ "stylelint": "^17.6.0",
113
+ "stylelint-config-standard": "^40.0.0",
102
114
  "tailwind-merge": "3.2.0",
103
115
  "tailwindcss": "4.1.12",
104
116
  "tw-animate-css": "1.3.8",
105
117
  "typescript": "^5.5.0",
106
118
  "vaul": "1.1.2",
107
119
  "vite": "6.3.5",
108
- "vite-plugin-dts": "^4.0.0"
120
+ "vite-plugin-dts": "^4.0.0",
121
+ "vite-plugin-static-copy": "^4.0.0"
109
122
  },
110
123
  "pnpm": {
111
124
  "overrides": {
@@ -1,84 +0,0 @@
1
- {
2
- "name": "Sellsuki Design System",
3
- "version": "1.2.0",
4
- "updated": "2026-03-20",
5
- "url": "https://sellsukidesignsystemv12.vercel.app/ai-rules.json",
6
- "storybook": "https://sellsukidesignsystemv12.vercel.app",
7
- "npm": "@uxuissk/design-system",
8
- "brand": {
9
- "product": "Sellsuki — E-commerce management platform for Thai merchants",
10
- "mood": "Professional, clean, trustworthy, light, airy, functional",
11
- "design": "Clarity over decoration — flat design, minimal shadows"
12
- },
13
- "colors": {
14
- "primary": "#32a9ff",
15
- "primary-hover": "#1b8bf5",
16
- "primary-light": "#f0f9ff",
17
- "text-primary": "#1f2937",
18
- "text-secondary": "#6b7280",
19
- "border": "#e5e7eb",
20
- "surface": "#f9fafb",
21
- "background": "#ffffff",
22
- "success": "#059669",
23
- "success-light": "#d1fae5",
24
- "warning": "#d97706",
25
- "warning-light": "#fef3c7",
26
- "danger": "#e11d48",
27
- "danger-light": "#ffe4e6"
28
- },
29
- "typography": {
30
- "body": "'DB HeaventRounded', 'Noto Sans Thai', sans-serif",
31
- "button": "'Inter', sans-serif"
32
- },
33
- "spacing": {
34
- "page-desktop": "24px",
35
- "page-mobile": "16px",
36
- "card-gap": "16px",
37
- "form-gap": "16px",
38
- "section-gap": "32px"
39
- },
40
- "border": {
41
- "radius": "8px",
42
- "shadow": "0px 1px 2px 0px rgba(0,0,0,0.05)"
43
- },
44
- "layout": {
45
- "navbar-height": "72px",
46
- "sidebar-width": "280px"
47
- },
48
- "button": {
49
- "variants": ["primary", "secondary", "outline", "ghost", "destructive", "link"],
50
- "sizes": { "sm": "32px", "md": "36px", "lg": "40px", "xl": "44px" },
51
- "default": "variant=primary size=md",
52
- "rule": "Max 1 primary button per view"
53
- },
54
- "components": {
55
- "data-entry": ["DSButton", "IconButton", "ButtonGroup", "DSInput", "DSTextarea", "DSCheckbox", "CheckboxGroup", "DSRadio", "RadioGroup", "Switch", "Dropdown", "DatePicker", "SearchField", "ColorPicker", "FileUpload", "TagInput", "Rating", "TransferList"],
56
- "data-display": ["DSTable", "Card", "CardHeader", "CardBody", "CardFooter", "StatCard", "Statistic", "Badge", "Tag", "Avatar", "AvatarGroup", "Timeline", "Tree", "EmptyState", "Skeleton"],
57
- "navigation": ["TopNavbar", "Sidebar", "Breadcrumb", "Tabs", "Stepper", "Pagination"],
58
- "feedback": ["Alert", "Modal", "Drawer", "ConfirmDialog", "Notification", "toast", "ToastContainer", "Tooltip", "Popover", "ProgressBar", "Spinner"],
59
- "layout": ["Divider", "Menu", "ImagePreview"]
60
- },
61
- "rules": [
62
- "Flat clean design — no heavy shadows or gradients",
63
- "Max 1 primary button per view",
64
- "Handle loading, empty, and error states",
65
- "DB HeaventRounded for text, Inter for buttons only",
66
- "Only colors from the defined palette",
67
- "Follow spacing system strictly"
68
- ],
69
- "tailwind_patterns": {
70
- "button-primary": "h-9 px-4 bg-[#32a9ff] hover:bg-[#1b8bf5] text-white text-sm font-semibold rounded-lg font-['Inter']",
71
- "button-secondary": "h-9 px-4 bg-[#f3f4f6] hover:bg-[#e5e7eb] text-[#1f2937] text-sm font-semibold rounded-lg font-['Inter']",
72
- "button-outline": "h-9 px-4 border border-[#32a9ff] text-[#32a9ff] bg-white hover:bg-[#f0f9ff] text-sm font-semibold rounded-lg font-['Inter']",
73
- "button-destructive": "h-9 px-4 bg-[#e11d48] hover:bg-[#be123c] text-white text-sm font-semibold rounded-lg font-['Inter']",
74
- "card": "bg-white rounded-lg border border-[#e5e7eb] p-4",
75
- "input": "w-full h-9 px-3 border border-[#e5e7eb] rounded-lg text-sm text-[#1f2937] placeholder:text-[#9ca3af] focus:border-[#32a9ff] focus:ring-1 focus:ring-[#32a9ff] outline-none",
76
- "badge-success": "px-2 py-0.5 text-xs font-medium rounded-full bg-[#d1fae5] text-[#065f46]",
77
- "badge-warning": "px-2 py-0.5 text-xs font-medium rounded-full bg-[#fef3c7] text-[#92400e]",
78
- "badge-danger": "px-2 py-0.5 text-xs font-medium rounded-full bg-[#ffe4e6] text-[#9f1239]",
79
- "table-header": "px-4 py-3 bg-[#f9fafb] text-[#6b7280] text-xs font-semibold uppercase text-left",
80
- "table-cell": "px-4 py-3 text-sm text-[#1f2937]",
81
- "sidebar-item": "flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm text-[#6b7280] hover:bg-[#f0f9ff] hover:text-[#32a9ff]",
82
- "sidebar-item-active": "flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm bg-[#f0f9ff] text-[#32a9ff] font-medium"
83
- }
84
- }
package/dist/ai-rules.md DELETED
@@ -1,163 +0,0 @@
1
- # Sellsuki Design System — AI Rules (Hosted Version)
2
-
3
- > This file is the single source of truth for all AI tools generating Sellsuki UI.
4
- > URL: https://sellsukidesignsystemv12.vercel.app/ai-rules.md
5
- > Last updated: 2026-03-20
6
-
7
- ## Important: Sandbox vs Full Mode
8
-
9
- **Sandbox mode** (Claude.ai Artifacts, v0, Google AI Studio):
10
- - Use ONLY React + Tailwind CSS + lucide-react + recharts
11
- - DO NOT import from @uxuissk/design-system or any external npm package
12
- - Recreate components inline using Tailwind classes matching tokens below
13
- - For font: use `font-['Inter']` for buttons, system font for body
14
-
15
- **Full mode** (Claude Code, Cursor, Bolt.new, Lovable, Firebase Studio):
16
- - Install: `npm install @uxuissk/design-system`
17
- - CSS: `import "@uxuissk/design-system/styles.css"` (always first)
18
- - Import: `import { DSButton, DSInput, Card, ... } from "@uxuissk/design-system"`
19
-
20
- ## Brand
21
-
22
- - Product: **Sellsuki** — E-commerce management platform for Thai merchants
23
- - Mood: Professional, clean, trustworthy, light, airy, functional
24
- - Design: Clarity over decoration — flat design, minimal shadows
25
-
26
- ## Colors
27
-
28
- | Token | Hex | Tailwind | Usage |
29
- |-------|-----|----------|-------|
30
- | Primary | `#32a9ff` | `bg-[#32a9ff]` | Buttons, links, brand |
31
- | Primary hover | `#1b8bf5` | `hover:bg-[#1b8bf5]` | Hover states |
32
- | Primary light | `#f0f9ff` | `bg-[#f0f9ff]` | Badges, highlights |
33
- | Text primary | `#1f2937` | `text-[#1f2937]` | Headings, body |
34
- | Text secondary | `#6b7280` | `text-[#6b7280]` | Muted, labels |
35
- | Border | `#e5e7eb` | `border-[#e5e7eb]` | Dividers, cards |
36
- | Surface | `#f9fafb` | `bg-[#f9fafb]` | Page background |
37
- | Success | `#059669` | `bg-[#059669]` | Success states |
38
- | Success light | `#d1fae5` | `bg-[#d1fae5]` | Success badges |
39
- | Warning | `#d97706` | `bg-[#d97706]` | Warning states |
40
- | Warning light | `#fef3c7` | `bg-[#fef3c7]` | Warning badges |
41
- | Danger | `#e11d48` | `bg-[#e11d48]` | Error, destructive |
42
- | Danger light | `#ffe4e6` | `bg-[#ffe4e6]` | Error badges |
43
-
44
- ## Typography
45
-
46
- | Element | Font | Weight | Size |
47
- |---------|------|--------|------|
48
- | Body text | DB HeaventRounded, Noto Sans Thai, sans-serif | 400 | 16px |
49
- | Heading | DB HeaventRounded, Noto Sans Thai, sans-serif | 700 | 24-32px |
50
- | Button | Inter, sans-serif | 600 | 14px |
51
- | Label | DB HeaventRounded | 500 | 14px |
52
- | Caption | DB HeaventRounded | 400 | 12px |
53
-
54
- ## Spacing
55
-
56
- - Page padding: `24px` desktop / `16px` mobile
57
- - Card gap: `16px`
58
- - Form field gap: `16px`
59
- - Section gap: `32px`
60
- - Border radius: `8px` (default)
61
- - Shadow: `0px 1px 2px 0px rgba(0,0,0,0.05)` — prefer borders
62
-
63
- ## Layout
64
-
65
- - Navbar: `72px` height, white background, bottom border
66
- - Sidebar: `280px` width, white background, right border
67
- - Content: `flex-1`, `24px` padding
68
-
69
- ## Button System
70
-
71
- | Variant | Background | Text | Border |
72
- |---------|-----------|------|--------|
73
- | Primary | `#32a9ff` | white | none |
74
- | Secondary | `#f3f4f6` | `#1f2937` | none |
75
- | Outline | transparent | `#32a9ff` | `#32a9ff` |
76
- | Ghost | transparent | `#6b7280` | none |
77
- | Destructive | `#e11d48` | white | none |
78
- | Link | transparent | `#32a9ff` | none |
79
-
80
- Sizes: `sm` 32px / `md` 36px (default) / `lg` 40px / `xl` 44px
81
- **Rule: Max 1 primary button per view**
82
-
83
- ## Component Patterns (Tailwind)
84
-
85
- ### Button
86
- ```html
87
- <button class="h-9 px-4 bg-[#32a9ff] hover:bg-[#1b8bf5] text-white text-sm font-semibold rounded-lg font-['Inter']">
88
- ```
89
-
90
- ### Card
91
- ```html
92
- <div class="bg-white rounded-lg border border-[#e5e7eb] p-4">
93
- ```
94
-
95
- ### Input
96
- ```html
97
- <input class="w-full h-9 px-3 border border-[#e5e7eb] rounded-lg text-sm text-[#1f2937] placeholder:text-[#9ca3af] focus:border-[#32a9ff] focus:ring-1 focus:ring-[#32a9ff] outline-none" />
98
- ```
99
-
100
- ### Badge
101
- ```html
102
- <span class="px-2 py-0.5 text-xs font-medium rounded-full bg-[#d1fae5] text-[#065f46]">Active</span>
103
- ```
104
-
105
- ### Table Header
106
- ```html
107
- <th class="px-4 py-3 bg-[#f9fafb] text-[#6b7280] text-xs font-semibold uppercase text-left">
108
- ```
109
-
110
- ### Table Row
111
- ```html
112
- <tr class="border-b border-[#e5e7eb] hover:bg-[#f9fafb]">
113
- <td class="px-4 py-3 text-sm text-[#1f2937]">
114
- ```
115
-
116
- ### Sidebar Menu Item
117
- ```html
118
- <div class="flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm text-[#6b7280] hover:bg-[#f0f9ff] hover:text-[#32a9ff] cursor-pointer">
119
- ```
120
-
121
- ### Active Menu Item
122
- ```html
123
- <div class="flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm bg-[#f0f9ff] text-[#32a9ff] font-medium">
124
- ```
125
-
126
- ## Components (41 total)
127
-
128
- **Data Entry**: DSButton, IconButton, ButtonGroup, DSInput, DSTextarea, DSCheckbox, CheckboxGroup, DSRadio, RadioGroup, Switch, Dropdown, DatePicker, SearchField, ColorPicker, FileUpload, TagInput, Rating, TransferList
129
-
130
- **Data Display**: DSTable, Card, CardHeader, CardBody, CardFooter, StatCard, Statistic, Badge, Tag, Avatar, AvatarGroup, Timeline, Tree, EmptyState, Skeleton
131
-
132
- **Navigation**: TopNavbar, Sidebar, Breadcrumb, Tabs, Stepper, Pagination
133
-
134
- **Feedback**: Alert, Modal, Drawer, ConfirmDialog, Notification, toast, ToastContainer, Tooltip, Popover, ProgressBar, Spinner
135
-
136
- **Layout**: Divider, Menu, ImagePreview
137
-
138
- ## Rules
139
-
140
- 1. Always use flat, clean design — no heavy shadows or gradients
141
- 2. Max 1 primary button per view
142
- 3. Handle loading (skeleton), empty, and error states
143
- 4. Use DB HeaventRounded for text, Inter for buttons only
144
- 5. Only colors from the palette above — no random colors
145
- 6. Spacing must follow the defined system
146
- 7. Support responsive: desktop-first
147
-
148
- ## npm Package (for production code)
149
-
150
- ```bash
151
- npm install @uxuissk/design-system
152
- ```
153
-
154
- ```tsx
155
- import "@uxuissk/design-system/styles.css";
156
- import { DSButton, DSInput, Card } from "@uxuissk/design-system";
157
- ```
158
-
159
- ## Resources
160
-
161
- - Storybook: https://sellsukidesignsystemv12.vercel.app
162
- - npm: @uxuissk/design-system
163
- - GitHub: https://github.com/BearyCenter/Sellsukidesignsystemv12