@teamix-evo/ui 0.1.1 → 0.3.0

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.
Files changed (295) hide show
  1. package/README.md +184 -184
  2. package/manifest.json +680 -492
  3. package/package.json +20 -10
  4. package/src/components/accordion/accordion.meta.md +5 -4
  5. package/src/components/accordion/accordion.stories.tsx +14 -9
  6. package/src/components/accordion/accordion.tsx +104 -8
  7. package/src/components/affix/affix.meta.md +20 -2
  8. package/src/components/affix/affix.stories.tsx +102 -25
  9. package/src/components/affix/affix.tsx +79 -9
  10. package/src/components/alert/alert.meta.md +44 -13
  11. package/src/components/alert/alert.stories.tsx +66 -21
  12. package/src/components/alert/alert.tsx +81 -34
  13. package/src/components/alert-dialog/alert-dialog.meta.md +61 -16
  14. package/src/components/alert-dialog/alert-dialog.stories.tsx +145 -3
  15. package/src/components/alert-dialog/alert-dialog.tsx +60 -13
  16. package/src/components/anchor/anchor.meta.md +8 -3
  17. package/src/components/anchor/anchor.stories.tsx +3 -3
  18. package/src/components/anchor/anchor.tsx +2 -2
  19. package/src/components/app/app.meta.md +9 -4
  20. package/src/components/app/app.stories.tsx +9 -7
  21. package/src/components/aspect-ratio/aspect-ratio.meta.md +4 -3
  22. package/src/components/aspect-ratio/aspect-ratio.stories.tsx +3 -3
  23. package/src/components/auto-complete/auto-complete.meta.md +14 -6
  24. package/src/components/auto-complete/auto-complete.stories.tsx +47 -4
  25. package/src/components/auto-complete/auto-complete.tsx +119 -71
  26. package/src/components/avatar/avatar.meta.md +6 -7
  27. package/src/components/avatar/avatar.stories.tsx +21 -3
  28. package/src/components/avatar/avatar.tsx +24 -23
  29. package/src/components/badge/badge.meta.md +10 -9
  30. package/src/components/badge/badge.stories.tsx +2 -2
  31. package/src/components/badge/badge.tsx +9 -15
  32. package/src/components/breadcrumb/breadcrumb.meta.md +27 -7
  33. package/src/components/breadcrumb/breadcrumb.stories.tsx +127 -4
  34. package/src/components/breadcrumb/breadcrumb.tsx +22 -8
  35. package/src/components/button/button.meta.md +258 -21
  36. package/src/components/button/button.stories.tsx +549 -41
  37. package/src/components/button/button.tsx +335 -33
  38. package/src/components/button/demo/as-child.tsx +24 -0
  39. package/src/components/button/demo/basic.tsx +8 -0
  40. package/src/components/button/demo/block.tsx +16 -0
  41. package/src/components/button/demo/loading.tsx +19 -0
  42. package/src/components/button/demo/shapes.tsx +18 -0
  43. package/src/components/button/demo/sizes.tsx +19 -0
  44. package/src/components/button/demo/variants.tsx +19 -0
  45. package/src/components/button/demo/with-icon.tsx +20 -0
  46. package/src/components/calendar/calendar.meta.md +13 -3
  47. package/src/components/calendar/calendar.stories.tsx +6 -6
  48. package/src/components/calendar/calendar.tsx +73 -8
  49. package/src/components/card/card.meta.md +27 -5
  50. package/src/components/card/card.stories.tsx +42 -3
  51. package/src/components/card/card.tsx +146 -63
  52. package/src/components/carousel/carousel.meta.md +4 -3
  53. package/src/components/carousel/carousel.stories.tsx +11 -6
  54. package/src/components/cascader/cascader.meta.md +47 -17
  55. package/src/components/cascader/cascader.stories.tsx +22 -10
  56. package/src/components/cascader/cascader.tsx +428 -85
  57. package/src/components/checkbox/checkbox.meta.md +75 -7
  58. package/src/components/checkbox/checkbox.stories.tsx +161 -3
  59. package/src/components/checkbox/checkbox.tsx +77 -9
  60. package/src/components/collapsible/collapsible.meta.md +14 -6
  61. package/src/components/collapsible/collapsible.stories.tsx +10 -2
  62. package/src/components/collapsible/collapsible.tsx +93 -6
  63. package/src/components/color-picker/color-picker.meta.md +12 -7
  64. package/src/components/color-picker/color-picker.stories.tsx +86 -7
  65. package/src/components/color-picker/color-picker.tsx +20 -9
  66. package/src/components/command/command.meta.md +29 -13
  67. package/src/components/command/command.stories.tsx +4 -4
  68. package/src/components/command/command.tsx +19 -8
  69. package/src/components/context-menu/context-menu.meta.md +11 -8
  70. package/src/components/context-menu/context-menu.stories.tsx +11 -3
  71. package/src/components/context-menu/context-menu.tsx +21 -8
  72. package/src/components/data-table/data-table.meta.md +6 -5
  73. package/src/components/data-table/data-table.stories.tsx +13 -6
  74. package/src/components/data-table/data-table.tsx +2 -2
  75. package/src/components/date-picker/date-picker.meta.md +88 -19
  76. package/src/components/date-picker/date-picker.stories.tsx +55 -5
  77. package/src/components/date-picker/date-picker.tsx +1489 -91
  78. package/src/components/descriptions/descriptions.meta.md +10 -5
  79. package/src/components/descriptions/descriptions.stories.tsx +3 -3
  80. package/src/components/descriptions/descriptions.tsx +22 -14
  81. package/src/components/dialog/dialog.meta.md +76 -13
  82. package/src/components/dialog/dialog.stories.tsx +182 -20
  83. package/src/components/dialog/dialog.tsx +67 -15
  84. package/src/components/dialog/imperative.tsx +252 -0
  85. package/src/components/drawer/drawer.meta.md +33 -34
  86. package/src/components/drawer/drawer.stories.tsx +29 -12
  87. package/src/components/drawer/drawer.tsx +22 -113
  88. package/src/components/dropdown-menu/dropdown-menu.meta.md +78 -10
  89. package/src/components/dropdown-menu/dropdown-menu.stories.tsx +88 -2
  90. package/src/components/dropdown-menu/dropdown-menu.tsx +24 -10
  91. package/src/components/ellipsis/ellipsis.meta.md +87 -0
  92. package/src/components/ellipsis/ellipsis.stories.tsx +72 -0
  93. package/src/components/ellipsis/ellipsis.tsx +153 -0
  94. package/src/components/empty/empty.meta.md +9 -4
  95. package/src/components/empty/empty.stories.tsx +4 -4
  96. package/src/components/empty/empty.tsx +10 -3
  97. package/src/components/field/field.meta.md +47 -9
  98. package/src/components/field/field.stories.tsx +385 -5
  99. package/src/components/field/field.tsx +263 -35
  100. package/src/components/filter-bar/filter-bar.meta.md +92 -0
  101. package/src/components/filter-bar/filter-bar.stories.tsx +1083 -0
  102. package/src/components/filter-bar/filter-bar.tsx +568 -0
  103. package/src/components/flex/flex.meta.md +54 -6
  104. package/src/components/flex/flex.stories.tsx +107 -20
  105. package/src/components/flex/flex.tsx +27 -4
  106. package/src/components/float-button/float-button.meta.md +8 -3
  107. package/src/components/float-button/float-button.stories.tsx +9 -7
  108. package/src/components/float-button/float-button.tsx +1 -1
  109. package/src/components/form/form.meta.md +39 -17
  110. package/src/components/form/form.stories.tsx +350 -3
  111. package/src/components/form/form.tsx +101 -35
  112. package/src/components/grid/grid.meta.md +7 -2
  113. package/src/components/grid/grid.stories.tsx +6 -4
  114. package/src/components/hover-card/hover-card.meta.md +20 -9
  115. package/src/components/hover-card/hover-card.stories.tsx +34 -5
  116. package/src/components/hover-card/hover-card.tsx +51 -13
  117. package/src/components/icon/DEVELOPMENT.md +809 -0
  118. package/src/components/icon/icon.meta.md +170 -0
  119. package/src/components/icon/icon.stories.tsx +344 -0
  120. package/src/components/icon/icon.tsx +248 -0
  121. package/src/components/image/image.meta.md +9 -4
  122. package/src/components/image/image.stories.tsx +3 -3
  123. package/src/components/image/image.tsx +6 -4
  124. package/src/components/input/demo/basic.tsx +12 -0
  125. package/src/components/input/demo/clearable.tsx +21 -0
  126. package/src/components/input/demo/show-count.tsx +18 -0
  127. package/src/components/input/demo/sizes.tsx +15 -0
  128. package/src/components/input/input.meta.md +39 -33
  129. package/src/components/input/input.stories.tsx +62 -35
  130. package/src/components/input/input.tsx +97 -98
  131. package/src/components/input-group/input-group.meta.md +54 -22
  132. package/src/components/input-group/input-group.stories.tsx +49 -16
  133. package/src/components/input-group/input-group.tsx +44 -8
  134. package/src/components/input-number/input-number.meta.md +64 -7
  135. package/src/components/input-number/input-number.stories.tsx +46 -8
  136. package/src/components/input-number/input-number.tsx +99 -26
  137. package/src/components/input-otp/input-otp.meta.md +4 -3
  138. package/src/components/input-otp/input-otp.stories.tsx +3 -3
  139. package/src/components/input-otp/input-otp.tsx +1 -1
  140. package/src/components/item/item.meta.md +8 -3
  141. package/src/components/item/item.stories.tsx +8 -5
  142. package/src/components/item/item.tsx +7 -6
  143. package/src/components/kbd/kbd.meta.md +13 -4
  144. package/src/components/kbd/kbd.stories.tsx +4 -4
  145. package/src/components/kbd/kbd.tsx +10 -5
  146. package/src/components/label/label.meta.md +18 -10
  147. package/src/components/label/label.stories.tsx +64 -6
  148. package/src/components/label/label.tsx +91 -19
  149. package/src/components/masonry/masonry.meta.md +8 -3
  150. package/src/components/masonry/masonry.stories.tsx +7 -5
  151. package/src/components/masonry/masonry.tsx +1 -0
  152. package/src/components/mentions/mentions.meta.md +36 -6
  153. package/src/components/mentions/mentions.stories.tsx +120 -6
  154. package/src/components/mentions/mentions.tsx +11 -5
  155. package/src/components/menubar/menubar.meta.md +30 -12
  156. package/src/components/menubar/menubar.stories.tsx +62 -2
  157. package/src/components/menubar/menubar.tsx +9 -9
  158. package/src/components/native-select/native-select.meta.md +8 -3
  159. package/src/components/native-select/native-select.stories.tsx +8 -5
  160. package/src/components/native-select/native-select.tsx +1 -1
  161. package/src/components/navigation-menu/navigation-menu.meta.md +19 -9
  162. package/src/components/navigation-menu/navigation-menu.stories.tsx +112 -9
  163. package/src/components/navigation-menu/navigation-menu.tsx +8 -4
  164. package/src/components/notification/notification.meta.md +52 -10
  165. package/src/components/notification/notification.stories.tsx +11 -9
  166. package/src/components/notification/notification.tsx +36 -21
  167. package/src/components/page-header/DEVELOPMENT.md +842 -0
  168. package/src/components/page-header/page-header.meta.md +208 -0
  169. package/src/components/page-header/page-header.stories.tsx +421 -0
  170. package/src/components/page-header/page-header.tsx +281 -0
  171. package/src/components/pagination/pagination.meta.md +140 -37
  172. package/src/components/pagination/pagination.stories.tsx +232 -10
  173. package/src/components/pagination/pagination.tsx +355 -63
  174. package/src/components/popconfirm/popconfirm.meta.md +9 -4
  175. package/src/components/popconfirm/popconfirm.stories.tsx +3 -4
  176. package/src/components/popconfirm/popconfirm.tsx +2 -2
  177. package/src/components/popover/popover.meta.md +62 -5
  178. package/src/components/popover/popover.stories.tsx +83 -7
  179. package/src/components/popover/popover.tsx +77 -28
  180. package/src/components/progress/progress.meta.md +38 -6
  181. package/src/components/progress/progress.stories.tsx +3 -3
  182. package/src/components/progress/progress.tsx +24 -16
  183. package/src/components/radio-group/radio-group.meta.md +79 -7
  184. package/src/components/radio-group/radio-group.stories.tsx +39 -3
  185. package/src/components/radio-group/radio-group.tsx +149 -18
  186. package/src/components/rate/rate.meta.md +35 -4
  187. package/src/components/rate/rate.stories.tsx +13 -5
  188. package/src/components/rate/rate.tsx +37 -10
  189. package/src/components/resizable/resizable.meta.md +7 -4
  190. package/src/components/resizable/resizable.stories.tsx +6 -6
  191. package/src/components/resizable/resizable.tsx +1 -1
  192. package/src/components/result/result.meta.md +7 -2
  193. package/src/components/result/result.stories.tsx +4 -8
  194. package/src/components/result/result.tsx +24 -15
  195. package/src/components/scroll-area/scroll-area.meta.md +4 -3
  196. package/src/components/scroll-area/scroll-area.stories.tsx +12 -4
  197. package/src/components/scroll-area/scroll-area.tsx +3 -3
  198. package/src/components/segmented/segmented.meta.md +7 -4
  199. package/src/components/segmented/segmented.stories.tsx +37 -8
  200. package/src/components/segmented/segmented.tsx +15 -7
  201. package/src/components/select/select.meta.md +197 -52
  202. package/src/components/select/select.stories.tsx +238 -63
  203. package/src/components/select/select.tsx +718 -171
  204. package/src/components/separator/separator.meta.md +4 -3
  205. package/src/components/separator/separator.stories.tsx +3 -3
  206. package/src/components/separator/separator.tsx +3 -7
  207. package/src/components/sheet/sheet.meta.md +32 -16
  208. package/src/components/sheet/sheet.stories.tsx +116 -10
  209. package/src/components/sheet/sheet.tsx +116 -29
  210. package/src/components/sidebar/sidebar.meta.md +37 -18
  211. package/src/components/sidebar/sidebar.stories.tsx +701 -29
  212. package/src/components/sidebar/sidebar.tsx +615 -142
  213. package/src/components/skeleton/skeleton.meta.md +4 -5
  214. package/src/components/skeleton/skeleton.stories.tsx +4 -4
  215. package/src/components/skeleton/skeleton.tsx +7 -7
  216. package/src/components/slider/slider.meta.md +57 -5
  217. package/src/components/slider/slider.stories.tsx +58 -6
  218. package/src/components/slider/slider.tsx +154 -13
  219. package/src/components/sonner/sonner.meta.md +58 -7
  220. package/src/components/sonner/sonner.stories.tsx +78 -5
  221. package/src/components/sonner/sonner.tsx +137 -8
  222. package/src/components/spinner/spinner.meta.md +62 -13
  223. package/src/components/spinner/spinner.stories.tsx +66 -14
  224. package/src/components/spinner/spinner.tsx +111 -9
  225. package/src/components/statistic/statistic.meta.md +7 -2
  226. package/src/components/statistic/statistic.stories.tsx +3 -7
  227. package/src/components/statistic/statistic.tsx +5 -6
  228. package/src/components/steps/steps.meta.md +18 -4
  229. package/src/components/steps/steps.stories.tsx +43 -3
  230. package/src/components/steps/steps.tsx +15 -12
  231. package/src/components/switch/switch.meta.md +51 -5
  232. package/src/components/switch/switch.stories.tsx +6 -6
  233. package/src/components/switch/switch.tsx +109 -41
  234. package/src/components/table/table.meta.md +17 -6
  235. package/src/components/table/table.stories.tsx +10 -5
  236. package/src/components/table/table.tsx +4 -4
  237. package/src/components/tabs/tabs.meta.md +38 -25
  238. package/src/components/tabs/tabs.stories.tsx +111 -25
  239. package/src/components/tabs/tabs.tsx +125 -54
  240. package/src/components/tag/tag.meta.md +105 -40
  241. package/src/components/tag/tag.stories.tsx +189 -16
  242. package/src/components/tag/tag.tsx +222 -21
  243. package/src/components/textarea/textarea.meta.md +35 -19
  244. package/src/components/textarea/textarea.stories.tsx +32 -6
  245. package/src/components/textarea/textarea.tsx +33 -9
  246. package/src/components/time-picker/time-picker.meta.md +124 -32
  247. package/src/components/time-picker/time-picker.stories.tsx +85 -15
  248. package/src/components/time-picker/time-picker.tsx +913 -61
  249. package/src/components/timeline/timeline.meta.md +14 -6
  250. package/src/components/timeline/timeline.stories.tsx +37 -7
  251. package/src/components/timeline/timeline.tsx +35 -14
  252. package/src/components/toggle/toggle.meta.md +5 -4
  253. package/src/components/toggle/toggle.stories.tsx +4 -4
  254. package/src/components/toggle/toggle.tsx +4 -3
  255. package/src/components/toggle-group/toggle-group.meta.md +5 -4
  256. package/src/components/toggle-group/toggle-group.stories.tsx +3 -3
  257. package/src/components/toggle-group/toggle-group.tsx +2 -2
  258. package/src/components/tooltip/tooltip.meta.md +55 -5
  259. package/src/components/tooltip/tooltip.stories.tsx +42 -5
  260. package/src/components/tooltip/tooltip.tsx +81 -21
  261. package/src/components/tour/tour.meta.md +9 -4
  262. package/src/components/tour/tour.stories.tsx +3 -3
  263. package/src/components/tour/tour.tsx +4 -4
  264. package/src/components/transfer/transfer.meta.md +11 -6
  265. package/src/components/transfer/transfer.stories.tsx +4 -8
  266. package/src/components/transfer/transfer.tsx +28 -21
  267. package/src/components/tree/tree.meta.md +63 -5
  268. package/src/components/tree/tree.stories.tsx +31 -12
  269. package/src/components/tree/tree.tsx +9 -8
  270. package/src/components/tree-select/tree-select.meta.md +59 -8
  271. package/src/components/tree-select/tree-select.stories.tsx +3 -3
  272. package/src/components/tree-select/tree-select.tsx +42 -7
  273. package/src/components/typography/typography.meta.md +61 -14
  274. package/src/components/typography/typography.stories.tsx +12 -11
  275. package/src/components/typography/typography.tsx +43 -28
  276. package/src/components/upload/upload.meta.md +49 -4
  277. package/src/components/upload/upload.stories.tsx +72 -12
  278. package/src/components/upload/upload.tsx +170 -37
  279. package/src/components/watermark/watermark.meta.md +7 -2
  280. package/src/components/watermark/watermark.stories.tsx +101 -9
  281. package/src/components/watermark/watermark.tsx +1 -0
  282. package/src/hooks/use-breakpoint.ts +117 -0
  283. package/src/hooks/use-debounce-callback.ts +52 -0
  284. package/src/hooks/use-mobile.ts +23 -0
  285. package/src/stories/theme-tokens.stories.tsx +747 -0
  286. package/src/utils/trigger-input.ts +53 -0
  287. package/src/components/button-group/button-group.meta.md +0 -92
  288. package/src/components/button-group/button-group.stories.tsx +0 -90
  289. package/src/components/button-group/button-group.tsx +0 -75
  290. package/src/components/combobox/combobox.meta.md +0 -93
  291. package/src/components/combobox/combobox.stories.tsx +0 -55
  292. package/src/components/combobox/combobox.tsx +0 -130
  293. package/src/components/space/space.meta.md +0 -94
  294. package/src/components/space/space.stories.tsx +0 -94
  295. package/src/components/space/space.tsx +0 -106
@@ -1,42 +1,142 @@
1
1
  import * as React from 'react';
2
- import type { Meta, StoryObj } from '@storybook/react';
3
- import { Home, Inbox, Settings, Users } from 'lucide-react';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ import {
4
+ BookOpen,
5
+ Bot,
6
+ ChevronRight,
7
+ FileText,
8
+ Folder,
9
+ Home,
10
+ Inbox,
11
+ MessageSquare,
12
+ MoreHorizontal,
13
+ Search,
14
+ Settings,
15
+ Star,
16
+ Users,
17
+ } from 'lucide-react';
18
+
19
+ import {
20
+ InputGroup,
21
+ InputGroupAddon,
22
+ InputGroupInput,
23
+ } from '@/components/input-group/input-group';
24
+
4
25
  import {
5
- SidebarProvider,
6
26
  Sidebar,
7
- SidebarHeader,
8
27
  SidebarContent,
28
+ SidebarFooter,
9
29
  SidebarGroup,
30
+ SidebarGroupAction,
10
31
  SidebarGroupLabel,
32
+ SidebarHeader,
33
+ SidebarInput,
34
+ SidebarInset,
11
35
  SidebarMenu,
12
- SidebarMenuItem,
36
+ SidebarMenuAction,
37
+ SidebarMenuBadge,
13
38
  SidebarMenuButton,
14
- SidebarFooter,
39
+ SidebarMenuItem,
40
+ SidebarMenuSkeleton,
41
+ SidebarMenuSub,
42
+ SidebarMenuSubButton,
43
+ SidebarMenuSubItem,
44
+ SidebarProvider,
45
+ SidebarRail,
46
+ SidebarSeparator,
15
47
  SidebarTrigger,
16
- SidebarInset,
17
48
  } from './sidebar';
49
+ import {
50
+ Collapsible,
51
+ CollapsibleContent,
52
+ CollapsibleTrigger,
53
+ } from '@/components/collapsible/collapsible';
18
54
 
19
55
  const meta: Meta<typeof Sidebar> = {
20
- title: '导航 · Navigation/Sidebar',
56
+ title: '布局 · Layout/Sidebar',
21
57
  component: Sidebar,
22
58
  tags: ['autodocs'],
23
- parameters: { layout: 'fullscreen' },
59
+ parameters: {
60
+ layout: 'fullscreen',
61
+ docs: {
62
+ description: {
63
+ component:
64
+ 'Sidebar — shadcn 完整版 25 primitives 复合,等价 antd Layout.Sider + Menu + 移动端 Drawer。\n\n**核心能力**:Provider(open 受控/cookie 持久化/Cmd+B 快捷键/mobile 自动切 Sheet)、`variant=sidebar|floating|inset` × `collapsible=offcanvas|icon|none`、Menu 二级(Sub)+ 徽标(Badge)+ 操作(Action)+ 骨架(Skeleton)+ Rail 拖拽收合、Input 顶部搜索、GroupAction 头部操作槽、折叠态自动 Tooltip。',
65
+ },
66
+ },
67
+ },
68
+ argTypes: {
69
+ side: {
70
+ control: 'inline-radio',
71
+ options: ['left', 'right'],
72
+ },
73
+ variant: {
74
+ control: 'inline-radio',
75
+ options: ['sidebar', 'floating', 'inset'],
76
+ },
77
+ collapsible: {
78
+ control: 'inline-radio',
79
+ options: ['offcanvas', 'icon', 'none'],
80
+ },
81
+ },
82
+ args: { side: 'left', variant: 'sidebar', collapsible: 'icon' },
24
83
  };
25
84
 
26
85
  export default meta;
27
86
  type Story = StoryObj<typeof Sidebar>;
28
87
 
29
- const items = [
88
+ // ─── 复用数据 + 内部小工具 ──────────────────────────────────────────────────
89
+
90
+ const navItems = [
30
91
  { title: '首页', url: '#home', icon: Home },
31
- { title: '收件箱', url: '#inbox', icon: Inbox },
92
+ { title: '收件箱', url: '#inbox', icon: Inbox, badge: 5 },
32
93
  { title: '团队', url: '#team', icon: Users },
33
94
  { title: '设置', url: '#settings', icon: Settings },
34
95
  ];
35
96
 
36
- function DemoLayout({ active }: { active: string }) {
97
+ const kbSubItems = [
98
+ { title: '公开文档', url: '#kb-public' },
99
+ { title: '团队空间', url: '#kb-team' },
100
+ { title: '我的草稿', url: '#kb-mine' },
101
+ ];
102
+
103
+ const favoriteItems = [
104
+ { title: 'React 文档', url: '#fav-react' },
105
+ { title: '发布流程', url: '#fav-release' },
106
+ { title: '故障排查', url: '#fav-debug' },
107
+ ];
108
+
109
+ function MainContent({ children }: { children?: React.ReactNode }) {
37
110
  return (
111
+ <SidebarInset>
112
+ <header className="flex h-12 shrink-0 items-center gap-2 border-b border-border bg-background px-4">
113
+ <SidebarTrigger />
114
+ <h2 className="text-sm font-medium">主内容区</h2>
115
+ <span className="ml-auto text-xs text-muted-foreground">
116
+ 按 ⌘ + B 切换 Sidebar
117
+ </span>
118
+ </header>
119
+ <div className="flex-1 overflow-auto p-6 text-sm text-muted-foreground">
120
+ {children ?? '点击左上角图标可折叠 / 展开 Sidebar。'}
121
+ </div>
122
+ </SidebarInset>
123
+ );
124
+ }
125
+
126
+ // ─── Story 1: Default — 基础导航 + 折叠 ──────────────────────────────────
127
+
128
+ export const Default: Story = {
129
+ parameters: {
130
+ docs: {
131
+ description: {
132
+ story:
133
+ '基础形态:Provider + Header + Content/Group/Menu + Footer + Trigger + Inset。点击左上角 Trigger 或按 `Cmd+B` 切换折叠;`isActive` 由消费方根据路由计算传入。',
134
+ },
135
+ },
136
+ },
137
+ render: (args) => (
38
138
  <SidebarProvider>
39
- <Sidebar>
139
+ <Sidebar {...args}>
40
140
  <SidebarHeader>
41
141
  <h1 className="px-2 text-sm font-semibold">Teamix Evo</h1>
42
142
  </SidebarHeader>
@@ -44,11 +144,12 @@ function DemoLayout({ active }: { active: string }) {
44
144
  <SidebarGroup>
45
145
  <SidebarGroupLabel>导航</SidebarGroupLabel>
46
146
  <SidebarMenu>
47
- {items.map((it) => (
147
+ {navItems.map((it) => (
48
148
  <SidebarMenuItem key={it.title}>
49
149
  <SidebarMenuButton
50
150
  asChild
51
- isActive={active === it.url}
151
+ tooltip={it.title}
152
+ isActive={it.url === '#home'}
52
153
  >
53
154
  <a href={it.url} onClick={(e) => e.preventDefault()}>
54
155
  <it.icon />
@@ -61,22 +162,593 @@ function DemoLayout({ active }: { active: string }) {
61
162
  </SidebarGroup>
62
163
  </SidebarContent>
63
164
  <SidebarFooter>
64
- <p className="px-2 text-xs text-muted-foreground">v0.1.0</p>
165
+ <p className="px-2 text-xs text-muted-foreground">v0.4.0</p>
65
166
  </SidebarFooter>
66
167
  </Sidebar>
67
- <SidebarInset>
68
- <header className="flex h-12 items-center gap-2 border-b px-4">
69
- <SidebarTrigger />
70
- <h2 className="text-sm font-medium">主内容区</h2>
71
- </header>
72
- <div className="flex-1 p-6 text-sm text-muted-foreground">
73
- 点击左上角图标可折叠 / 展开 Sidebar。
74
- </div>
75
- </SidebarInset>
168
+ <MainContent />
76
169
  </SidebarProvider>
77
- );
78
- }
170
+ ),
171
+ };
79
172
 
80
- export const Default: Story = {
81
- render: () => <DemoLayout active="#home" />,
173
+ // ─── Story 2: CollapsibleIcon 折叠态自动 Tooltip ─────────────────────────
174
+
175
+ export const CollapsibleIcon: Story = {
176
+ name: '折叠态 + 自动 Tooltip',
177
+ args: { collapsible: 'icon' },
178
+ parameters: {
179
+ docs: {
180
+ description: {
181
+ story:
182
+ '`collapsible="icon"` + `<SidebarMenuButton tooltip="文字" />`:折叠后只剩 icon 列(3rem),hover icon 自动弹 Tooltip 显示文字,折叠态导航不丢失语义。点击 Trigger 或 `Cmd+B` 切换折叠演示。',
183
+ },
184
+ },
185
+ },
186
+ render: (args) => {
187
+ const [collapsed, setCollapsed] = React.useState(true);
188
+ return (
189
+ <SidebarProvider open={!collapsed} onOpenChange={(o) => setCollapsed(!o)}>
190
+ <Sidebar {...args}>
191
+ <SidebarHeader>
192
+ <h1 className="px-2 text-sm font-semibold group-data-[collapsible=icon]:hidden">
193
+ Teamix Evo
194
+ </h1>
195
+ </SidebarHeader>
196
+ <SidebarContent>
197
+ <SidebarGroup>
198
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
199
+ <SidebarMenu>
200
+ {navItems.map((it) => (
201
+ <SidebarMenuItem key={it.title}>
202
+ <SidebarMenuButton asChild tooltip={it.title}>
203
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
204
+ <it.icon />
205
+ <span>{it.title}</span>
206
+ </a>
207
+ </SidebarMenuButton>
208
+ </SidebarMenuItem>
209
+ ))}
210
+ </SidebarMenu>
211
+ </SidebarGroup>
212
+ </SidebarContent>
213
+ </Sidebar>
214
+ <MainContent>
215
+ <p>
216
+ 当前折叠状态:<strong>{collapsed ? '已折叠' : '已展开'}</strong>
217
+ </p>
218
+ <p className="mt-2">
219
+ 折叠后将鼠标 hover 到任一 icon 上,会看到 Tooltip 弹出对应文字。
220
+ </p>
221
+ </MainContent>
222
+ </SidebarProvider>
223
+ );
224
+ },
225
+ };
226
+
227
+ // ─── Story 3: WithSubMenus — 二级菜单(MenuSub) ─────────────────────────────
228
+
229
+ export const WithSubMenus: Story = {
230
+ name: '二级菜单 SubMenus',
231
+ parameters: {
232
+ docs: {
233
+ description: {
234
+ story:
235
+ '`SidebarMenuSub / SubItem / SubButton` + `Collapsible` 实现二级展开收起。折叠态(`collapsible="icon"`)下二级自动隐藏。常用于知识库 / 多模块工作台。',
236
+ },
237
+ },
238
+ },
239
+ render: (args) => (
240
+ <SidebarProvider>
241
+ <Sidebar {...args}>
242
+ <SidebarHeader>
243
+ <h1 className="px-2 text-sm font-semibold">Teamix Evo</h1>
244
+ </SidebarHeader>
245
+ <SidebarContent>
246
+ <SidebarGroup>
247
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
248
+ <SidebarMenu>
249
+ <SidebarMenuItem>
250
+ <SidebarMenuButton asChild tooltip="首页">
251
+ <a href="#home" onClick={(e) => e.preventDefault()}>
252
+ <Home />
253
+ <span>首页</span>
254
+ </a>
255
+ </SidebarMenuButton>
256
+ </SidebarMenuItem>
257
+ {/* 知识库 + 二级 */}
258
+ <Collapsible defaultOpen asChild className="group/collapsible">
259
+ <SidebarMenuItem>
260
+ <CollapsibleTrigger asChild>
261
+ <SidebarMenuButton tooltip="知识库">
262
+ <BookOpen />
263
+ <span>知识库</span>
264
+ <ChevronRight className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
265
+ </SidebarMenuButton>
266
+ </CollapsibleTrigger>
267
+ <CollapsibleContent>
268
+ <SidebarMenuSub>
269
+ {kbSubItems.map((s) => (
270
+ <SidebarMenuSubItem key={s.title}>
271
+ <SidebarMenuSubButton
272
+ href={s.url}
273
+ isActive={s.url === '#kb-public'}
274
+ onClick={(e) => e.preventDefault()}
275
+ >
276
+ <span>{s.title}</span>
277
+ </SidebarMenuSubButton>
278
+ </SidebarMenuSubItem>
279
+ ))}
280
+ </SidebarMenuSub>
281
+ </CollapsibleContent>
282
+ </SidebarMenuItem>
283
+ </Collapsible>
284
+ <SidebarMenuItem>
285
+ <SidebarMenuButton asChild tooltip="设置">
286
+ <a href="#settings" onClick={(e) => e.preventDefault()}>
287
+ <Settings />
288
+ <span>设置</span>
289
+ </a>
290
+ </SidebarMenuButton>
291
+ </SidebarMenuItem>
292
+ </SidebarMenu>
293
+ </SidebarGroup>
294
+ </SidebarContent>
295
+ </Sidebar>
296
+ <MainContent>
297
+ 知识库展开后,折叠 Sidebar 试试 — 二级菜单会自动隐藏。
298
+ </MainContent>
299
+ </SidebarProvider>
300
+ ),
301
+ };
302
+
303
+ // ─── Story 4: WithBadgeAndAction — 徽标 + 行操作 ─────────────────────────────
304
+
305
+ export const WithBadgeAndAction: Story = {
306
+ name: '徽标 + 行操作',
307
+ parameters: {
308
+ docs: {
309
+ description: {
310
+ story:
311
+ '`SidebarMenuBadge` 展示未读数 / 状态(Tailwind tabular-nums 等宽);`SidebarMenuAction` 是行内操作槽(`showOnHover` 控制是否仅 hover 时显示)。两者位置在 MenuButton 右侧。',
312
+ },
313
+ },
314
+ },
315
+ render: (args) => (
316
+ <SidebarProvider>
317
+ <Sidebar {...args}>
318
+ <SidebarHeader>
319
+ <h1 className="px-2 text-sm font-semibold">Teamix Evo</h1>
320
+ </SidebarHeader>
321
+ <SidebarContent>
322
+ <SidebarGroup>
323
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
324
+ <SidebarMenu>
325
+ {navItems.map((it) => (
326
+ <SidebarMenuItem key={it.title}>
327
+ <SidebarMenuButton asChild tooltip={it.title}>
328
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
329
+ <it.icon />
330
+ <span>{it.title}</span>
331
+ </a>
332
+ </SidebarMenuButton>
333
+ {it.badge ? (
334
+ <SidebarMenuBadge>{it.badge}</SidebarMenuBadge>
335
+ ) : null}
336
+ <SidebarMenuAction
337
+ showOnHover
338
+ aria-label="更多"
339
+ onClick={(e) => e.preventDefault()}
340
+ >
341
+ <MoreHorizontal />
342
+ </SidebarMenuAction>
343
+ </SidebarMenuItem>
344
+ ))}
345
+ </SidebarMenu>
346
+ </SidebarGroup>
347
+ </SidebarContent>
348
+ </Sidebar>
349
+ <MainContent>
350
+ 把鼠标移到任一菜单项上 — 右侧会浮现「⋯」操作按钮。
351
+ </MainContent>
352
+ </SidebarProvider>
353
+ ),
354
+ };
355
+
356
+ // ─── Story 5: VariantFloating — 浮起圆角 ─────────────────────────────────────
357
+
358
+ export const VariantFloating: Story = {
359
+ name: 'variant=floating(浮起圆角)',
360
+ args: { variant: 'floating' },
361
+ parameters: {
362
+ docs: {
363
+ description: {
364
+ story:
365
+ '`variant="floating"`:Sidebar 与边缘留 8px 间距,带圆角 + 阴影 + 边框。视觉更轻盈,适合 dashboard / 营销后台。',
366
+ },
367
+ },
368
+ },
369
+ render: (args) => (
370
+ <SidebarProvider>
371
+ <Sidebar {...args}>
372
+ <SidebarHeader>
373
+ <h1 className="px-2 text-sm font-semibold">Teamix Evo</h1>
374
+ </SidebarHeader>
375
+ <SidebarContent>
376
+ <SidebarGroup>
377
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
378
+ <SidebarMenu>
379
+ {navItems.map((it) => (
380
+ <SidebarMenuItem key={it.title}>
381
+ <SidebarMenuButton asChild tooltip={it.title}>
382
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
383
+ <it.icon />
384
+ <span>{it.title}</span>
385
+ </a>
386
+ </SidebarMenuButton>
387
+ </SidebarMenuItem>
388
+ ))}
389
+ </SidebarMenu>
390
+ </SidebarGroup>
391
+ </SidebarContent>
392
+ </Sidebar>
393
+ <MainContent />
394
+ </SidebarProvider>
395
+ ),
396
+ };
397
+
398
+ // ─── Story 6: VariantInset — 主内容区圆角内嵌 ────────────────────────────────
399
+
400
+ export const VariantInset: Story = {
401
+ name: 'variant=inset(主区圆角)',
402
+ args: { variant: 'inset' },
403
+ parameters: {
404
+ docs: {
405
+ description: {
406
+ story:
407
+ '`variant="inset"`:主内容区 SidebarInset 加圆角 + 阴影 + 留白,Sidebar 退到背景。视觉上"内容卡片化",适合内容密集的工作台。',
408
+ },
409
+ },
410
+ },
411
+ render: (args) => (
412
+ <SidebarProvider>
413
+ <Sidebar {...args}>
414
+ <SidebarHeader>
415
+ <h1 className="px-2 text-sm font-semibold">Teamix Evo</h1>
416
+ </SidebarHeader>
417
+ <SidebarContent>
418
+ <SidebarGroup>
419
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
420
+ <SidebarMenu>
421
+ {navItems.map((it) => (
422
+ <SidebarMenuItem key={it.title}>
423
+ <SidebarMenuButton asChild tooltip={it.title}>
424
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
425
+ <it.icon />
426
+ <span>{it.title}</span>
427
+ </a>
428
+ </SidebarMenuButton>
429
+ </SidebarMenuItem>
430
+ ))}
431
+ </SidebarMenu>
432
+ </SidebarGroup>
433
+ </SidebarContent>
434
+ </Sidebar>
435
+ <MainContent />
436
+ </SidebarProvider>
437
+ ),
438
+ };
439
+
440
+ // ─── Story 7: WithRail — 拖拽收合区 ──────────────────────────────────────────
441
+
442
+ export const WithRail: Story = {
443
+ name: 'Rail 拖拽收合',
444
+ parameters: {
445
+ docs: {
446
+ description: {
447
+ story:
448
+ '`SidebarRail` 替代显式 Trigger 按钮 — 在 Sidebar 右边缘提供窄拖拽区,点击/双击触发折叠。`<SidebarRail />` 放在 `<Sidebar>` 内任意位置即可。',
449
+ },
450
+ },
451
+ },
452
+ render: (args) => (
453
+ <SidebarProvider>
454
+ <Sidebar {...args}>
455
+ <SidebarHeader>
456
+ <h1 className="px-2 text-sm font-semibold">Teamix Evo</h1>
457
+ </SidebarHeader>
458
+ <SidebarContent>
459
+ <SidebarGroup>
460
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
461
+ <SidebarMenu>
462
+ {navItems.map((it) => (
463
+ <SidebarMenuItem key={it.title}>
464
+ <SidebarMenuButton asChild tooltip={it.title}>
465
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
466
+ <it.icon />
467
+ <span>{it.title}</span>
468
+ </a>
469
+ </SidebarMenuButton>
470
+ </SidebarMenuItem>
471
+ ))}
472
+ </SidebarMenu>
473
+ </SidebarGroup>
474
+ </SidebarContent>
475
+ <SidebarRail />
476
+ </Sidebar>
477
+ <MainContent>
478
+ 把鼠标移到 Sidebar 右边缘 — 会出现窄拖拽柄,点击切换折叠。
479
+ </MainContent>
480
+ </SidebarProvider>
481
+ ),
482
+ };
483
+
484
+ // ─── Story 8: WithInputAndGroupAction — 顶部搜索 + 分组操作 ──────────────────
485
+
486
+ export const WithInputAndGroupAction: Story = {
487
+ name: '顶部搜索 + 分组操作',
488
+ parameters: {
489
+ docs: {
490
+ description: {
491
+ story:
492
+ '`SidebarInput` 提供顶部搜索框(常配合 cmdk 做命令面板触发);`SidebarGroupAction` 是分组头右侧操作槽(添加 / 编辑 / 设置)。两者组合常见于"项目列表"等需要管理的分组。',
493
+ },
494
+ },
495
+ },
496
+ render: (args) => (
497
+ <SidebarProvider>
498
+ <Sidebar {...args}>
499
+ <SidebarHeader>
500
+ <div className="flex items-center gap-2 px-2 py-1.5">
501
+ <h1 className="text-sm font-semibold">Teamix Evo</h1>
502
+ </div>
503
+ <div className="px-2 pb-1">
504
+ <InputGroup>
505
+ <InputGroupAddon position="before" variant="icon">
506
+ <Search className="size-4" />
507
+ </InputGroupAddon>
508
+ <InputGroupInput placeholder="搜索…" />
509
+ </InputGroup>
510
+ </div>
511
+ </SidebarHeader>
512
+ <SidebarContent>
513
+ <SidebarGroup>
514
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
515
+ <SidebarMenu>
516
+ {navItems.slice(0, 3).map((it) => (
517
+ <SidebarMenuItem key={it.title}>
518
+ <SidebarMenuButton asChild tooltip={it.title}>
519
+ <a href={it.url} onClick={(e) => e.preventDefault()}>
520
+ <it.icon />
521
+ <span>{it.title}</span>
522
+ </a>
523
+ </SidebarMenuButton>
524
+ </SidebarMenuItem>
525
+ ))}
526
+ </SidebarMenu>
527
+ </SidebarGroup>
528
+
529
+ <SidebarSeparator />
530
+
531
+ <SidebarGroup>
532
+ <SidebarGroupLabel>收藏</SidebarGroupLabel>
533
+ <SidebarGroupAction
534
+ aria-label="管理收藏"
535
+ onClick={(e) => e.preventDefault()}
536
+ >
537
+ <MoreHorizontal />
538
+ </SidebarGroupAction>
539
+ <SidebarMenu>
540
+ {favoriteItems.map((f) => (
541
+ <SidebarMenuItem key={f.title}>
542
+ <SidebarMenuButton asChild tooltip={f.title} size="sm">
543
+ <a href={f.url} onClick={(e) => e.preventDefault()}>
544
+ <Star />
545
+ <span>{f.title}</span>
546
+ </a>
547
+ </SidebarMenuButton>
548
+ </SidebarMenuItem>
549
+ ))}
550
+ </SidebarMenu>
551
+ </SidebarGroup>
552
+ </SidebarContent>
553
+ </Sidebar>
554
+ <MainContent>顶部 Input 搜索 + 收藏分组头部「⋯」管理操作。</MainContent>
555
+ </SidebarProvider>
556
+ ),
557
+ };
558
+
559
+ // ─── Story 9: LoadingSkeleton — 异步加载占位 ─────────────────────────────────
560
+
561
+ export const LoadingSkeleton: Story = {
562
+ name: '加载骨架 MenuSkeleton',
563
+ parameters: {
564
+ docs: {
565
+ description: {
566
+ story:
567
+ '`SidebarMenuSkeleton` 用于异步导航的占位 — 自带随机宽度变化避免视觉死板,`showIcon` 控制是否显示左侧 icon 骨架。',
568
+ },
569
+ },
570
+ },
571
+ render: (args) => (
572
+ <SidebarProvider>
573
+ <Sidebar {...args}>
574
+ <SidebarHeader>
575
+ <h1 className="px-2 text-sm font-semibold">Teamix Evo</h1>
576
+ </SidebarHeader>
577
+ <SidebarContent>
578
+ <SidebarGroup>
579
+ <SidebarGroupLabel>导航(加载中)</SidebarGroupLabel>
580
+ <SidebarMenu>
581
+ {Array.from({ length: 5 }).map((_, i) => (
582
+ <SidebarMenuItem key={i}>
583
+ <SidebarMenuSkeleton showIcon />
584
+ </SidebarMenuItem>
585
+ ))}
586
+ </SidebarMenu>
587
+ </SidebarGroup>
588
+ </SidebarContent>
589
+ </Sidebar>
590
+ <MainContent>
591
+ 真实业务里这层骨架会在数据 ready 后切换为 Menu。
592
+ </MainContent>
593
+ </SidebarProvider>
594
+ ),
595
+ };
596
+
597
+ // ─── Story 10: FullStack — 综合演示(品牌头 + 多分组 + 二级 + 徽标 + 用户区) ───
598
+
599
+ export const FullStack: Story = {
600
+ name: '综合 — 品牌头 + 多分组 + 二级 + 徽标 + 用户区',
601
+ args: { collapsible: 'icon' },
602
+ parameters: {
603
+ docs: {
604
+ description: {
605
+ story:
606
+ '把 Header(品牌)+ 多 Group(导航 / KB 二级 / 收藏)+ Badge / Action + Footer(用户区)拼起来,接近真实后台 layout。注意所有需要在折叠态保留语义的菜单项都传了 `tooltip` prop。',
607
+ },
608
+ },
609
+ },
610
+ render: (args) => (
611
+ <SidebarProvider>
612
+ <Sidebar {...args}>
613
+ <SidebarHeader>
614
+ <div className="flex items-center gap-2 px-2 py-1.5">
615
+ <div className="flex size-8 shrink-0 items-center justify-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground">
616
+ <Bot className="size-4" />
617
+ </div>
618
+ <div className="flex flex-1 flex-col leading-tight group-data-[collapsible=icon]:hidden">
619
+ <span className="truncate text-sm font-semibold">Teamix Evo</span>
620
+ <span className="truncate text-xs text-sidebar-foreground/70">
621
+ v0.4 · OpenTrek
622
+ </span>
623
+ </div>
624
+ </div>
625
+ </SidebarHeader>
626
+
627
+ <SidebarContent>
628
+ <SidebarGroup>
629
+ <SidebarGroupLabel>导航</SidebarGroupLabel>
630
+ <SidebarMenu>
631
+ <SidebarMenuItem>
632
+ <SidebarMenuButton asChild tooltip="首页" isActive>
633
+ <a href="#home" onClick={(e) => e.preventDefault()}>
634
+ <Home />
635
+ <span>首页</span>
636
+ </a>
637
+ </SidebarMenuButton>
638
+ </SidebarMenuItem>
639
+
640
+ <Collapsible defaultOpen asChild className="group/collapsible">
641
+ <SidebarMenuItem>
642
+ <CollapsibleTrigger asChild>
643
+ <SidebarMenuButton tooltip="知识库">
644
+ <BookOpen />
645
+ <span>知识库</span>
646
+ <ChevronRight className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
647
+ </SidebarMenuButton>
648
+ </CollapsibleTrigger>
649
+ <CollapsibleContent>
650
+ <SidebarMenuSub>
651
+ {kbSubItems.map((s) => (
652
+ <SidebarMenuSubItem key={s.title}>
653
+ <SidebarMenuSubButton
654
+ href={s.url}
655
+ isActive={s.url === '#kb-team'}
656
+ onClick={(e) => e.preventDefault()}
657
+ >
658
+ <span>{s.title}</span>
659
+ </SidebarMenuSubButton>
660
+ </SidebarMenuSubItem>
661
+ ))}
662
+ </SidebarMenuSub>
663
+ </CollapsibleContent>
664
+ </SidebarMenuItem>
665
+ </Collapsible>
666
+
667
+ <SidebarMenuItem>
668
+ <SidebarMenuButton asChild tooltip="收件箱">
669
+ <a href="#inbox" onClick={(e) => e.preventDefault()}>
670
+ <Inbox />
671
+ <span>收件箱</span>
672
+ </a>
673
+ </SidebarMenuButton>
674
+ <SidebarMenuBadge>5</SidebarMenuBadge>
675
+ </SidebarMenuItem>
676
+
677
+ <SidebarMenuItem>
678
+ <SidebarMenuButton asChild tooltip="评论">
679
+ <a href="#comments" onClick={(e) => e.preventDefault()}>
680
+ <MessageSquare />
681
+ <span>评论</span>
682
+ </a>
683
+ </SidebarMenuButton>
684
+ <SidebarMenuAction
685
+ showOnHover
686
+ aria-label="评论设置"
687
+ onClick={(e) => e.preventDefault()}
688
+ >
689
+ <MoreHorizontal />
690
+ </SidebarMenuAction>
691
+ </SidebarMenuItem>
692
+ </SidebarMenu>
693
+ </SidebarGroup>
694
+
695
+ <SidebarGroup>
696
+ <SidebarGroupLabel>项目</SidebarGroupLabel>
697
+ <SidebarGroupAction
698
+ aria-label="新建项目"
699
+ onClick={(e) => e.preventDefault()}
700
+ >
701
+ <FileText />
702
+ </SidebarGroupAction>
703
+ <SidebarMenu>
704
+ <SidebarMenuItem>
705
+ <SidebarMenuButton asChild tooltip="移动端" size="sm">
706
+ <a href="#proj-1" onClick={(e) => e.preventDefault()}>
707
+ <Folder />
708
+ <span>移动端 App</span>
709
+ </a>
710
+ </SidebarMenuButton>
711
+ </SidebarMenuItem>
712
+ <SidebarMenuItem>
713
+ <SidebarMenuButton asChild tooltip="后台" size="sm">
714
+ <a href="#proj-2" onClick={(e) => e.preventDefault()}>
715
+ <Folder />
716
+ <span>管理后台</span>
717
+ </a>
718
+ </SidebarMenuButton>
719
+ </SidebarMenuItem>
720
+ </SidebarMenu>
721
+ </SidebarGroup>
722
+ </SidebarContent>
723
+
724
+ <SidebarFooter>
725
+ <div className="flex items-center gap-2 px-2 py-1.5">
726
+ <div className="flex size-7 shrink-0 items-center justify-center rounded-full bg-sidebar-accent text-xs font-medium text-sidebar-accent-foreground">
727
+ U
728
+ </div>
729
+ <div className="flex min-w-0 flex-1 flex-col leading-tight group-data-[collapsible=icon]:hidden">
730
+ <span className="truncate text-sm font-medium">张三</span>
731
+ <span className="truncate text-xs text-sidebar-foreground/70">
732
+ zhangsan@example.com
733
+ </span>
734
+ </div>
735
+ </div>
736
+ </SidebarFooter>
737
+ </Sidebar>
738
+
739
+ <MainContent>
740
+ <p>
741
+ 真实工作台合成:折叠后所有 Tooltip / Badge / SubMenu
742
+ 自动收起,展开后完整呈现。
743
+ </p>
744
+ <p className="mt-2">
745
+ 按{' '}
746
+ <kbd className="rounded-sm border border-border bg-muted px-1 text-xxs">
747
+ ⌘B
748
+ </kbd>{' '}
749
+ 切换折叠;窗口缩小到 768px 以下会自动切换为 Sheet 抽屉形态。
750
+ </p>
751
+ </MainContent>
752
+ </SidebarProvider>
753
+ ),
82
754
  };