@aleph-alpha/ui-library 1.13.0 → 1.14.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 (120) hide show
  1. package/README.md +1 -1
  2. package/config.js +34 -1
  3. package/dist/system/index.d.ts +1728 -234
  4. package/dist/system/lib.js +19804 -16600
  5. package/package.json +1 -1
  6. package/src/components/UiKbd/UiKbd.stories.ts +1 -1
  7. package/src/components/UiNavigationMenu/UiNavigationMenu.stories.ts +1196 -0
  8. package/src/components/UiNavigationMenu/UiNavigationMenu.vue +39 -0
  9. package/src/components/UiNavigationMenu/UiNavigationMenuContent.vue +25 -0
  10. package/src/components/UiNavigationMenu/UiNavigationMenuIndicator.vue +14 -0
  11. package/src/components/UiNavigationMenu/UiNavigationMenuItem.vue +16 -0
  12. package/src/components/UiNavigationMenu/UiNavigationMenuLink.vue +27 -0
  13. package/src/components/UiNavigationMenu/UiNavigationMenuList.vue +16 -0
  14. package/src/components/UiNavigationMenu/UiNavigationMenuTrigger.vue +16 -0
  15. package/src/components/UiNavigationMenu/__tests__/UiNavigationMenu.test.ts +428 -0
  16. package/src/components/UiNavigationMenu/index.ts +11 -0
  17. package/src/components/UiNavigationMenu/types.ts +185 -0
  18. package/src/components/UiSheet/UiSheet.stories.ts +715 -0
  19. package/src/components/UiSheet/__tests__/UiSheet.test.ts +229 -0
  20. package/src/components/UiSheet/index.ts +12 -0
  21. package/src/components/UiSheet/types.ts +83 -0
  22. package/src/components/UiSidebar/UiSidebar.stories.ts +1010 -0
  23. package/src/components/UiSidebar/UiSidebar.vue +20 -0
  24. package/src/components/UiSidebar/UiSidebarGroupAction.vue +18 -0
  25. package/src/components/UiSidebar/UiSidebarGroupLabel.vue +18 -0
  26. package/src/components/UiSidebar/UiSidebarHeaderTrigger.vue +53 -0
  27. package/src/components/UiSidebar/UiSidebarInput.vue +14 -0
  28. package/src/components/UiSidebar/UiSidebarMenuAction.vue +19 -0
  29. package/src/components/UiSidebar/UiSidebarMenuButton.vue +27 -0
  30. package/src/components/UiSidebar/UiSidebarMenuSkeleton.vue +16 -0
  31. package/src/components/UiSidebar/UiSidebarMenuSubButton.vue +24 -0
  32. package/src/components/UiSidebar/UiSidebarProvider.vue +18 -0
  33. package/src/components/UiSidebar/UiSidebarSeparator.vue +13 -0
  34. package/src/components/UiSidebar/__tests__/UiSidebar.test.ts +221 -0
  35. package/src/components/UiSidebar/index.ts +34 -0
  36. package/src/components/UiSidebar/types.ts +168 -0
  37. package/src/components/UiStepper/UiStepper.stories.ts +425 -0
  38. package/src/components/UiStepper/UiStepper.vue +27 -0
  39. package/src/components/UiStepper/UiStepperDescription.vue +20 -0
  40. package/src/components/UiStepper/UiStepperIndicator.vue +13 -0
  41. package/src/components/UiStepper/UiStepperItem.vue +25 -0
  42. package/src/components/UiStepper/UiStepperSeparator.vue +17 -0
  43. package/src/components/UiStepper/UiStepperTitle.vue +19 -0
  44. package/src/components/UiStepper/UiStepperTrigger.vue +18 -0
  45. package/src/components/UiStepper/__tests__/UiStepper.test.ts +167 -0
  46. package/src/components/UiStepper/index.ts +9 -0
  47. package/src/components/UiStepper/types.ts +65 -0
  48. package/src/components/core/alert/index.ts +2 -2
  49. package/src/components/core/alert-dialog/AlertDialogContent.vue +1 -1
  50. package/src/components/core/card/Card.vue +1 -1
  51. package/src/components/core/drawer/DrawerContent.vue +1 -1
  52. package/src/components/core/dropdown-menu/DropdownMenuContent.vue +1 -1
  53. package/src/components/core/dropdown-menu/DropdownMenuSubContent.vue +1 -1
  54. package/src/components/core/input/Input.vue +1 -1
  55. package/src/components/core/native-select/NativeSelect.vue +1 -1
  56. package/src/components/core/native-select/NativeSelectOptGroup.vue +1 -1
  57. package/src/components/core/native-select/NativeSelectOption.vue +1 -1
  58. package/src/components/core/navigation-menu/NavigationMenu.vue +40 -0
  59. package/src/components/core/navigation-menu/NavigationMenuContent.vue +28 -0
  60. package/src/components/core/navigation-menu/NavigationMenuIndicator.vue +26 -0
  61. package/src/components/core/navigation-menu/NavigationMenuItem.vue +19 -0
  62. package/src/components/core/navigation-menu/NavigationMenuLink.vue +27 -0
  63. package/src/components/core/navigation-menu/NavigationMenuList.vue +21 -0
  64. package/src/components/core/navigation-menu/NavigationMenuTrigger.vue +27 -0
  65. package/src/components/core/navigation-menu/NavigationMenuViewport.vue +26 -0
  66. package/src/components/core/navigation-menu/index.ts +14 -0
  67. package/src/components/core/popover/PopoverContent.vue +1 -1
  68. package/src/components/core/select/SelectContent.vue +1 -1
  69. package/src/components/core/select/SelectTrigger.vue +1 -1
  70. package/src/components/core/sheet/Sheet.vue +15 -0
  71. package/src/components/core/sheet/SheetClose.vue +12 -0
  72. package/src/components/core/sheet/SheetContent.vue +56 -0
  73. package/src/components/core/sheet/SheetDescription.vue +19 -0
  74. package/src/components/core/sheet/SheetFooter.vue +9 -0
  75. package/src/components/core/sheet/SheetHeader.vue +9 -0
  76. package/src/components/core/sheet/SheetOverlay.vue +24 -0
  77. package/src/components/core/sheet/SheetTitle.vue +19 -0
  78. package/src/components/core/sheet/SheetTrigger.vue +12 -0
  79. package/src/components/core/sheet/index.ts +8 -0
  80. package/src/components/core/sidebar/Sidebar.vue +105 -0
  81. package/src/components/core/sidebar/SidebarContent.vue +21 -0
  82. package/src/components/core/sidebar/SidebarFooter.vue +16 -0
  83. package/src/components/core/sidebar/SidebarGroup.vue +16 -0
  84. package/src/components/core/sidebar/SidebarGroupAction.vue +25 -0
  85. package/src/components/core/sidebar/SidebarGroupContent.vue +16 -0
  86. package/src/components/core/sidebar/SidebarGroupLabel.vue +23 -0
  87. package/src/components/core/sidebar/SidebarHeader.vue +16 -0
  88. package/src/components/core/sidebar/SidebarInput.vue +17 -0
  89. package/src/components/core/sidebar/SidebarInset.vue +21 -0
  90. package/src/components/core/sidebar/SidebarMenu.vue +16 -0
  91. package/src/components/core/sidebar/SidebarMenuAction.vue +33 -0
  92. package/src/components/core/sidebar/SidebarMenuBadge.vue +26 -0
  93. package/src/components/core/sidebar/SidebarMenuButton.vue +49 -0
  94. package/src/components/core/sidebar/SidebarMenuButtonChild.vue +36 -0
  95. package/src/components/core/sidebar/SidebarMenuItem.vue +16 -0
  96. package/src/components/core/sidebar/SidebarMenuSkeleton.vue +32 -0
  97. package/src/components/core/sidebar/SidebarMenuSub.vue +22 -0
  98. package/src/components/core/sidebar/SidebarMenuSubButton.vue +38 -0
  99. package/src/components/core/sidebar/SidebarMenuSubItem.vue +16 -0
  100. package/src/components/core/sidebar/SidebarProvider.vue +102 -0
  101. package/src/components/core/sidebar/SidebarRail.vue +33 -0
  102. package/src/components/core/sidebar/SidebarSeparator.vue +17 -0
  103. package/src/components/core/sidebar/SidebarTrigger.vue +25 -0
  104. package/src/components/core/sidebar/index.ts +58 -0
  105. package/src/components/core/sidebar/utils.ts +19 -0
  106. package/src/components/core/stepper/Stepper.vue +20 -0
  107. package/src/components/core/stepper/StepperDescription.vue +23 -0
  108. package/src/components/core/stepper/StepperIndicator.vue +34 -0
  109. package/src/components/core/stepper/StepperItem.vue +23 -0
  110. package/src/components/core/stepper/StepperSeparator.vue +29 -0
  111. package/src/components/core/stepper/StepperTitle.vue +24 -0
  112. package/src/components/core/stepper/StepperTrigger.vue +22 -0
  113. package/src/components/core/stepper/index.ts +7 -0
  114. package/src/components/core/tabs/TabsTrigger.vue +1 -1
  115. package/src/components/core/tags-input/TagsInput.vue +1 -1
  116. package/src/components/core/textarea/Textarea.vue +1 -1
  117. package/src/components/index.ts +4 -0
  118. package/src/theme/Background.stories.ts +84 -35
  119. package/src/theme/Extended.stories.ts +4 -4
  120. package/tokens.json +145 -8
@@ -0,0 +1,1010 @@
1
+ import { ref, computed } from 'vue';
2
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
3
+ import {
4
+ UiSidebar,
5
+ UiSidebarContent,
6
+ UiSidebarFooter,
7
+ UiSidebarGroup,
8
+ UiSidebarGroupAction,
9
+ UiSidebarGroupContent,
10
+ UiSidebarGroupLabel,
11
+ UiSidebarHeader,
12
+ UiSidebarHeaderTrigger,
13
+ UiSidebarInput,
14
+ UiSidebarInset,
15
+ UiSidebarMenu,
16
+ UiSidebarMenuAction,
17
+ UiSidebarMenuBadge,
18
+ UiSidebarMenuButton,
19
+ UiSidebarMenuItem,
20
+ UiSidebarMenuSkeleton,
21
+ UiSidebarMenuSub,
22
+ UiSidebarMenuSubButton,
23
+ UiSidebarMenuSubItem,
24
+ UiSidebarProvider,
25
+ UiSidebarRail,
26
+ UiSidebarSeparator,
27
+ UiSidebarTrigger,
28
+ } from '.';
29
+ import { CollapsibleRoot, CollapsibleContent, CollapsibleTrigger } from 'reka-ui';
30
+ import {
31
+ Bot,
32
+ Database,
33
+ BarChart3,
34
+ MessageSquare,
35
+ Settings,
36
+ Command,
37
+ Plus,
38
+ MoreHorizontal,
39
+ FlaskConical,
40
+ Key,
41
+ Activity,
42
+ ChevronRight,
43
+ } from 'lucide-vue-next';
44
+
45
+ const meta: Meta<typeof UiSidebar> = {
46
+ title: 'Components/UiSidebar',
47
+ component: UiSidebar,
48
+ tags: ['autodocs'],
49
+ argTypes: {
50
+ side: {
51
+ control: 'select',
52
+ options: ['left', 'right'],
53
+ },
54
+ variant: {
55
+ control: 'select',
56
+ options: ['sidebar', 'floating', 'inset'],
57
+ description:
58
+ '`sidebar`: fixed with border. `floating`: shadow and rounded corners. `inset`: shares background with content.',
59
+ },
60
+ collapsible: {
61
+ control: 'select',
62
+ options: ['offcanvas', 'icon', 'none'],
63
+ description:
64
+ '`offcanvas`: slides completely off screen. `icon`: collapses to icon-only width. `none`: always expanded.',
65
+ },
66
+ },
67
+ args: {
68
+ side: 'left',
69
+ variant: 'sidebar',
70
+ collapsible: 'icon',
71
+ },
72
+ parameters: {
73
+ layout: 'fullscreen',
74
+ },
75
+ decorators: [
76
+ () => ({
77
+ template: '<div class="-m-4"><story /></div>',
78
+ }),
79
+ ],
80
+ };
81
+
82
+ export default meta;
83
+ type Story = StoryObj<typeof UiSidebar>;
84
+
85
+ const defaultTemplateSource = `<script setup lang="ts">
86
+ import {
87
+ UiSidebar,
88
+ UiSidebarContent,
89
+ UiSidebarFooter,
90
+ UiSidebarGroup,
91
+ UiSidebarGroupContent,
92
+ UiSidebarGroupLabel,
93
+ UiSidebarHeaderTrigger,
94
+ UiSidebarInset,
95
+ UiSidebarMenu,
96
+ UiSidebarMenuBadge,
97
+ UiSidebarMenuButton,
98
+ UiSidebarMenuItem,
99
+ UiSidebarProvider,
100
+ UiSidebarRail,
101
+ } from '@aleph-alpha/ui-library'
102
+ import { Bot, Database, BarChart3, MessageSquare, Settings, Command } from 'lucide-vue-next'
103
+
104
+ const items = [
105
+ { title: 'Playground', url: '#', icon: Bot, badge: null },
106
+ { title: 'Models', url: '#', icon: Database, badge: '5' },
107
+ { title: 'Evaluations', url: '#', icon: BarChart3, badge: '3' },
108
+ { title: 'Conversations', url: '#', icon: MessageSquare, badge: null },
109
+ ]
110
+ </script>
111
+
112
+ <template>
113
+ <UiSidebarProvider :default-open="false">
114
+ <UiSidebar>
115
+ <UiSidebarHeaderTrigger>
116
+ <template #logo>
117
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
118
+ <Command class="size-4" />
119
+ </div>
120
+ </template>
121
+ <span class="truncate font-semibold">Acme AI</span>
122
+ <span class="truncate text-xs">Enterprise</span>
123
+ </UiSidebarHeaderTrigger>
124
+ <UiSidebarContent>
125
+ <UiSidebarGroup>
126
+ <UiSidebarGroupLabel>Platform</UiSidebarGroupLabel>
127
+ <UiSidebarGroupContent>
128
+ <UiSidebarMenu>
129
+ <UiSidebarMenuItem v-for="item in items" :key="item.title">
130
+ <UiSidebarMenuButton :tooltip="item.title">
131
+ <component :is="item.icon" />
132
+ <span>{{ item.title }}</span>
133
+ </UiSidebarMenuButton>
134
+ <UiSidebarMenuBadge v-if="item.badge">
135
+ {{ item.badge }}
136
+ </UiSidebarMenuBadge>
137
+ </UiSidebarMenuItem>
138
+ </UiSidebarMenu>
139
+ </UiSidebarGroupContent>
140
+ </UiSidebarGroup>
141
+ </UiSidebarContent>
142
+ <UiSidebarFooter>
143
+ <UiSidebarMenu>
144
+ <UiSidebarMenuItem>
145
+ <UiSidebarMenuButton>
146
+ <Settings />
147
+ <span>Settings</span>
148
+ </UiSidebarMenuButton>
149
+ </UiSidebarMenuItem>
150
+ </UiSidebarMenu>
151
+ </UiSidebarFooter>
152
+ <UiSidebarRail />
153
+ </UiSidebar>
154
+ <UiSidebarInset>
155
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
156
+ <div class="flex items-center gap-1.5 text-sm">
157
+ <span class="text-muted-foreground">Platform</span>
158
+ <span class="text-muted-foreground">/</span>
159
+ <span class="font-medium">Playground</span>
160
+ </div>
161
+ </header>
162
+ <div class="flex flex-1 flex-col gap-4 p-4">
163
+ <div class="grid auto-rows-min gap-4 md:grid-cols-3">
164
+ <div class="aspect-video rounded-xl bg-muted" />
165
+ <div class="aspect-video rounded-xl bg-muted" />
166
+ <div class="aspect-video rounded-xl bg-muted" />
167
+ </div>
168
+ <div class="min-h-[50vh] flex-1 rounded-xl bg-muted" />
169
+ </div>
170
+ </UiSidebarInset>
171
+ </UiSidebarProvider>
172
+ </template>`;
173
+
174
+ /**
175
+ * AI platform sidebar with a company header, icon-based navigation group with `UiSidebarMenuBadge` counters, footer, and inset content area with breadcrumb header.
176
+ * Uses `collapsible="icon"` — the sidebar collapses to a narrow icon-only rail. Menu items show only their icon with a tooltip on hover. Badges auto-hide in collapsed mode.
177
+ */
178
+ export const Default: Story = {
179
+ render: (args) => ({
180
+ components: {
181
+ UiSidebar,
182
+ UiSidebarContent,
183
+ UiSidebarFooter,
184
+ UiSidebarGroup,
185
+ UiSidebarGroupContent,
186
+ UiSidebarGroupLabel,
187
+ UiSidebarHeaderTrigger,
188
+ UiSidebarInset,
189
+ UiSidebarMenu,
190
+ UiSidebarMenuBadge,
191
+ UiSidebarMenuButton,
192
+ UiSidebarMenuItem,
193
+ UiSidebarProvider,
194
+ UiSidebarRail,
195
+ Bot,
196
+ Database,
197
+ BarChart3,
198
+ MessageSquare,
199
+ Settings,
200
+ Command,
201
+ },
202
+ setup() {
203
+ const items = [
204
+ { title: 'Playground', url: '#', icon: Bot, badge: null },
205
+ { title: 'Models', url: '#', icon: Database, badge: '5' },
206
+ { title: 'Evaluations', url: '#', icon: BarChart3, badge: '3' },
207
+ { title: 'Conversations', url: '#', icon: MessageSquare, badge: null },
208
+ ];
209
+ return { args, items };
210
+ },
211
+ template: `
212
+ <UiSidebarProvider :default-open="false">
213
+ <UiSidebar :side="args.side" :variant="args.variant" :collapsible="args.collapsible">
214
+ <UiSidebarHeaderTrigger>
215
+ <template #logo>
216
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
217
+ <Command class="size-4" />
218
+ </div>
219
+ </template>
220
+ <span class="truncate font-semibold">Acme AI</span>
221
+ <span class="truncate text-xs">Enterprise</span>
222
+ </UiSidebarHeaderTrigger>
223
+ <UiSidebarContent>
224
+ <UiSidebarGroup>
225
+ <UiSidebarGroupLabel>Platform</UiSidebarGroupLabel>
226
+ <UiSidebarGroupContent>
227
+ <UiSidebarMenu>
228
+ <UiSidebarMenuItem v-for="item in items" :key="item.title">
229
+ <UiSidebarMenuButton :tooltip="item.title">
230
+ <component :is="item.icon" />
231
+ <span>{{ item.title }}</span>
232
+ </UiSidebarMenuButton>
233
+ <UiSidebarMenuBadge v-if="item.badge">
234
+ {{ item.badge }}
235
+ </UiSidebarMenuBadge>
236
+ </UiSidebarMenuItem>
237
+ </UiSidebarMenu>
238
+ </UiSidebarGroupContent>
239
+ </UiSidebarGroup>
240
+ </UiSidebarContent>
241
+ <UiSidebarFooter>
242
+ <UiSidebarMenu>
243
+ <UiSidebarMenuItem>
244
+ <UiSidebarMenuButton>
245
+ <Settings />
246
+ <span>Settings</span>
247
+ </UiSidebarMenuButton>
248
+ </UiSidebarMenuItem>
249
+ </UiSidebarMenu>
250
+ </UiSidebarFooter>
251
+ <UiSidebarRail />
252
+ </UiSidebar>
253
+ <UiSidebarInset>
254
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
255
+ <div class="flex items-center gap-1.5 text-sm">
256
+ <span class="text-muted-foreground">Platform</span>
257
+ <span class="text-muted-foreground">/</span>
258
+ <span class="font-medium">Playground</span>
259
+ </div>
260
+ </header>
261
+ <div class="flex flex-1 flex-col gap-4 p-4">
262
+ <div class="grid auto-rows-min gap-4 md:grid-cols-3">
263
+ <div class="aspect-video rounded-xl bg-muted" />
264
+ <div class="aspect-video rounded-xl bg-muted" />
265
+ <div class="aspect-video rounded-xl bg-muted" />
266
+ </div>
267
+ <div class="min-h-[50vh] flex-1 rounded-xl bg-muted" />
268
+ </div>
269
+ </UiSidebarInset>
270
+ </UiSidebarProvider>
271
+ `,
272
+ }),
273
+ parameters: {
274
+ docs: {
275
+ source: {
276
+ code: defaultTemplateSource,
277
+ },
278
+ },
279
+ },
280
+ };
281
+
282
+ const withSearchTemplateSource = `<script setup lang="ts">
283
+ import { ref, computed } from 'vue'
284
+ import {
285
+ UiSidebar,
286
+ UiSidebarContent,
287
+ UiSidebarGroup,
288
+ UiSidebarGroupContent,
289
+ UiSidebarGroupLabel,
290
+ UiSidebarHeader,
291
+ UiSidebarInput,
292
+ UiSidebarInset,
293
+ UiSidebarMenu,
294
+ UiSidebarMenuButton,
295
+ UiSidebarMenuItem,
296
+ UiSidebarProvider,
297
+ UiSidebarTrigger,
298
+ } from '@aleph-alpha/ui-library'
299
+ import { Command } from 'lucide-vue-next'
300
+
301
+ const groups = [
302
+ {
303
+ label: 'Getting Started',
304
+ items: ['Quick Start', 'Authentication', 'API Keys'],
305
+ },
306
+ {
307
+ label: 'Models',
308
+ items: ['Completions', 'Embeddings', 'Chat', 'Multimodal'],
309
+ },
310
+ {
311
+ label: 'Advanced',
312
+ items: ['Fine-tuning', 'Prompt Engineering', 'Evaluation', 'RAG'],
313
+ },
314
+ ]
315
+
316
+ const query = ref('')
317
+ const filteredGroups = computed(() =>
318
+ groups
319
+ .map(group => ({
320
+ ...group,
321
+ items: group.items.filter(item =>
322
+ item.toLowerCase().includes(query.value.toLowerCase())
323
+ ),
324
+ }))
325
+ .filter(group => group.items.length > 0)
326
+ )
327
+ </script>
328
+
329
+ <template>
330
+ <UiSidebarProvider :default-open="true">
331
+ <UiSidebar>
332
+ <UiSidebarHeader>
333
+ <UiSidebarMenu>
334
+ <UiSidebarMenuItem>
335
+ <UiSidebarMenuButton size="lg">
336
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
337
+ <Command class="size-4" />
338
+ </div>
339
+ <div class="grid flex-1 text-left text-sm leading-tight">
340
+ <span class="truncate font-semibold">API Docs</span>
341
+ <span class="truncate text-xs">v2.0.0</span>
342
+ </div>
343
+ </UiSidebarMenuButton>
344
+ </UiSidebarMenuItem>
345
+ </UiSidebarMenu>
346
+ <UiSidebarInput v-model="query" placeholder="Search the docs..." />
347
+ </UiSidebarHeader>
348
+ <UiSidebarContent>
349
+ <UiSidebarGroup v-for="group in filteredGroups" :key="group.label">
350
+ <UiSidebarGroupLabel>{{ group.label }}</UiSidebarGroupLabel>
351
+ <UiSidebarGroupContent>
352
+ <UiSidebarMenu>
353
+ <UiSidebarMenuItem v-for="item in group.items" :key="item">
354
+ <UiSidebarMenuButton>{{ item }}</UiSidebarMenuButton>
355
+ </UiSidebarMenuItem>
356
+ </UiSidebarMenu>
357
+ </UiSidebarGroupContent>
358
+ </UiSidebarGroup>
359
+ </UiSidebarContent>
360
+ </UiSidebar>
361
+ <UiSidebarInset>
362
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
363
+ <UiSidebarTrigger class="-ml-1" />
364
+ <span class="text-sm font-medium">API Documentation</span>
365
+ </header>
366
+ </UiSidebarInset>
367
+ </UiSidebarProvider>
368
+ </template>`;
369
+
370
+ /**
371
+ * Documentation-style sidebar with `UiSidebarInput` that filters navigation items across multiple groups (Models, Advanced, etc.).
372
+ * Uses `collapsible="offcanvas"` — the sidebar slides completely off screen when closed, since text-only items have no icon representation for icon-collapse mode.
373
+ */
374
+ export const WithSearch: Story = {
375
+ render: (args) => ({
376
+ components: {
377
+ UiSidebar,
378
+ UiSidebarContent,
379
+ UiSidebarGroup,
380
+ UiSidebarGroupContent,
381
+ UiSidebarGroupLabel,
382
+ UiSidebarHeader,
383
+ UiSidebarInput,
384
+ UiSidebarInset,
385
+ UiSidebarMenu,
386
+ UiSidebarMenuButton,
387
+ UiSidebarMenuItem,
388
+ UiSidebarProvider,
389
+ UiSidebarTrigger,
390
+ Command,
391
+ },
392
+ setup() {
393
+ const groups = [
394
+ {
395
+ label: 'Getting Started',
396
+ items: ['Quick Start', 'Authentication', 'API Keys'],
397
+ },
398
+ {
399
+ label: 'Models',
400
+ items: ['Completions', 'Embeddings', 'Chat', 'Multimodal'],
401
+ },
402
+ {
403
+ label: 'Advanced',
404
+ items: ['Fine-tuning', 'Prompt Engineering', 'Evaluation', 'RAG'],
405
+ },
406
+ ];
407
+ const query = ref('');
408
+ const matchesQuery = (item: string) => item.toLowerCase().includes(query.value.toLowerCase());
409
+ const filteredGroups = computed(() =>
410
+ groups
411
+ .map((group) => ({ ...group, items: group.items.filter(matchesQuery) }))
412
+ .filter((group) => group.items.length > 0),
413
+ );
414
+ return { args, query, filteredGroups };
415
+ },
416
+ template: `
417
+ <UiSidebarProvider :default-open="true">
418
+ <UiSidebar :side="args.side" :variant="args.variant" :collapsible="args.collapsible">
419
+ <UiSidebarHeader>
420
+ <UiSidebarMenu>
421
+ <UiSidebarMenuItem>
422
+ <UiSidebarMenuButton size="lg">
423
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
424
+ <Command class="size-4" />
425
+ </div>
426
+ <div class="grid flex-1 text-left text-sm leading-tight">
427
+ <span class="truncate font-semibold">API Docs</span>
428
+ <span class="truncate text-xs">v2.0.0</span>
429
+ </div>
430
+ </UiSidebarMenuButton>
431
+ </UiSidebarMenuItem>
432
+ </UiSidebarMenu>
433
+ <UiSidebarInput v-model="query" placeholder="Search the docs..." class="group-data-[collapsible=icon]:hidden" />
434
+ </UiSidebarHeader>
435
+ <UiSidebarContent>
436
+ <UiSidebarGroup v-for="group in filteredGroups" :key="group.label">
437
+ <UiSidebarGroupLabel>{{ group.label }}</UiSidebarGroupLabel>
438
+ <UiSidebarGroupContent>
439
+ <UiSidebarMenu>
440
+ <UiSidebarMenuItem v-for="item in group.items" :key="item">
441
+ <UiSidebarMenuButton>{{ item }}</UiSidebarMenuButton>
442
+ </UiSidebarMenuItem>
443
+ </UiSidebarMenu>
444
+ </UiSidebarGroupContent>
445
+ </UiSidebarGroup>
446
+ </UiSidebarContent>
447
+ </UiSidebar>
448
+ <UiSidebarInset>
449
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
450
+ <UiSidebarTrigger class="-ml-1" />
451
+ <span class="text-sm font-medium">API Documentation</span>
452
+ </header>
453
+ </UiSidebarInset>
454
+ </UiSidebarProvider>
455
+ `,
456
+ }),
457
+ args: {
458
+ collapsible: 'offcanvas',
459
+ },
460
+ parameters: {
461
+ docs: {
462
+ source: {
463
+ code: withSearchTemplateSource,
464
+ },
465
+ },
466
+ },
467
+ };
468
+
469
+ const withActionsTemplateSource = `<script setup lang="ts">
470
+ import { ref } from 'vue'
471
+ import {
472
+ UiSidebar,
473
+ UiSidebarContent,
474
+ UiSidebarGroup,
475
+ UiSidebarGroupAction,
476
+ UiSidebarGroupContent,
477
+ UiSidebarGroupLabel,
478
+ UiSidebarHeaderTrigger,
479
+ UiSidebarInset,
480
+ UiSidebarMenu,
481
+ UiSidebarMenuAction,
482
+ UiSidebarMenuButton,
483
+ UiSidebarMenuItem,
484
+ UiSidebarProvider,
485
+ UiSidebarRail,
486
+ UiSidebarSeparator,
487
+ } from '@aleph-alpha/ui-library'
488
+ import { FlaskConical, MessageSquare, BarChart3, Database, Key, Activity, Settings, Command, Plus, MoreHorizontal } from 'lucide-vue-next'
489
+
490
+ const pipelineItems = ref([
491
+ { title: 'Summarization', icon: FlaskConical },
492
+ { title: 'RAG Chatbot', icon: MessageSquare },
493
+ { title: 'Sentiment Analysis', icon: BarChart3 },
494
+ { title: 'Data Extraction', icon: Database },
495
+ ])
496
+
497
+ let counter = 0
498
+ function addPipeline() {
499
+ counter++
500
+ pipelineItems.value.push({ title: \\\`New Pipeline \\\${counter}\\\`, icon: FlaskConical })
501
+ }
502
+
503
+ const adminItems = [
504
+ { title: 'API Keys', icon: Key },
505
+ { title: 'Usage', icon: Activity },
506
+ { title: 'Settings', icon: Settings },
507
+ ]
508
+ </script>
509
+
510
+ <template>
511
+ <UiSidebarProvider :default-open="true">
512
+ <UiSidebar>
513
+ <UiSidebarHeaderTrigger>
514
+ <template #logo>
515
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
516
+ <Command class="size-4" />
517
+ </div>
518
+ </template>
519
+ <span class="truncate font-semibold">Acme AI</span>
520
+ <span class="truncate text-xs">Enterprise</span>
521
+ </UiSidebarHeaderTrigger>
522
+ <UiSidebarContent>
523
+ <UiSidebarGroup>
524
+ <UiSidebarGroupLabel>Pipelines</UiSidebarGroupLabel>
525
+ <UiSidebarGroupAction title="New Pipeline" @click="addPipeline">
526
+ <Plus />
527
+ </UiSidebarGroupAction>
528
+ <UiSidebarGroupContent>
529
+ <UiSidebarMenu>
530
+ <UiSidebarMenuItem v-for="item in pipelineItems" :key="item.title">
531
+ <UiSidebarMenuButton :tooltip="item.title">
532
+ <component :is="item.icon" />
533
+ <span>{{ item.title }}</span>
534
+ </UiSidebarMenuButton>
535
+ <UiSidebarMenuAction :show-on-hover="true" title="More options">
536
+ <MoreHorizontal />
537
+ </UiSidebarMenuAction>
538
+ </UiSidebarMenuItem>
539
+ </UiSidebarMenu>
540
+ </UiSidebarGroupContent>
541
+ </UiSidebarGroup>
542
+ <UiSidebarSeparator />
543
+ <UiSidebarGroup>
544
+ <UiSidebarGroupLabel>Administration</UiSidebarGroupLabel>
545
+ <UiSidebarGroupContent>
546
+ <UiSidebarMenu>
547
+ <UiSidebarMenuItem v-for="item in adminItems" :key="item.title">
548
+ <UiSidebarMenuButton :tooltip="item.title">
549
+ <component :is="item.icon" />
550
+ <span>{{ item.title }}</span>
551
+ </UiSidebarMenuButton>
552
+ </UiSidebarMenuItem>
553
+ </UiSidebarMenu>
554
+ </UiSidebarGroupContent>
555
+ </UiSidebarGroup>
556
+ </UiSidebarContent>
557
+ <UiSidebarRail />
558
+ </UiSidebar>
559
+ <UiSidebarInset>
560
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
561
+ <span class="text-sm font-medium">Pipelines</span>
562
+ </header>
563
+ </UiSidebarInset>
564
+ </UiSidebarProvider>
565
+ </template>`;
566
+
567
+ /**
568
+ * Sidebar with `UiSidebarGroupAction` (a "+" button on the "Pipelines" group label), `UiSidebarMenuAction` (a "..." button on each pipeline item),
569
+ * and a `UiSidebarSeparator` dividing the "Pipelines" group from an "Administration" group.
570
+ * Menu actions use `show-on-hover` so they only appear when hovering the item. Both action types auto-hide in icon-collapse mode.
571
+ */
572
+ export const WithActions: Story = {
573
+ render: (args) => ({
574
+ components: {
575
+ UiSidebar,
576
+ UiSidebarContent,
577
+ UiSidebarGroup,
578
+ UiSidebarGroupAction,
579
+ UiSidebarGroupContent,
580
+ UiSidebarGroupLabel,
581
+ UiSidebarHeaderTrigger,
582
+ UiSidebarInset,
583
+ UiSidebarMenu,
584
+ UiSidebarMenuAction,
585
+ UiSidebarMenuButton,
586
+ UiSidebarMenuItem,
587
+ UiSidebarProvider,
588
+ UiSidebarRail,
589
+ UiSidebarSeparator,
590
+ FlaskConical,
591
+ MessageSquare,
592
+ BarChart3,
593
+ Database,
594
+ Key,
595
+ Activity,
596
+ Settings,
597
+ Command,
598
+ Plus,
599
+ MoreHorizontal,
600
+ },
601
+ setup() {
602
+ const pipelineItems = ref([
603
+ { title: 'Summarization', icon: FlaskConical },
604
+ { title: 'RAG Chatbot', icon: MessageSquare },
605
+ { title: 'Sentiment Analysis', icon: BarChart3 },
606
+ { title: 'Data Extraction', icon: Database },
607
+ ]);
608
+ let counter = 0;
609
+ const addPipeline = () => {
610
+ counter++;
611
+ pipelineItems.value.push({ title: `New Pipeline ${counter}`, icon: FlaskConical });
612
+ };
613
+ const adminItems = [
614
+ { title: 'API Keys', icon: Key },
615
+ { title: 'Usage', icon: Activity },
616
+ { title: 'Settings', icon: Settings },
617
+ ];
618
+ return { args, pipelineItems, addPipeline, adminItems };
619
+ },
620
+ template: `
621
+ <UiSidebarProvider :default-open="true">
622
+ <UiSidebar :side="args.side" :variant="args.variant" :collapsible="args.collapsible">
623
+ <UiSidebarHeaderTrigger>
624
+ <template #logo>
625
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
626
+ <Command class="size-4" />
627
+ </div>
628
+ </template>
629
+ <span class="truncate font-semibold">Acme AI</span>
630
+ <span class="truncate text-xs">Enterprise</span>
631
+ </UiSidebarHeaderTrigger>
632
+ <UiSidebarContent>
633
+ <UiSidebarGroup>
634
+ <UiSidebarGroupLabel>Pipelines</UiSidebarGroupLabel>
635
+ <UiSidebarGroupAction title="New Pipeline" @click="addPipeline">
636
+ <Plus />
637
+ </UiSidebarGroupAction>
638
+ <UiSidebarGroupContent>
639
+ <UiSidebarMenu>
640
+ <UiSidebarMenuItem v-for="item in pipelineItems" :key="item.title">
641
+ <UiSidebarMenuButton :tooltip="item.title">
642
+ <component :is="item.icon" />
643
+ <span>{{ item.title }}</span>
644
+ </UiSidebarMenuButton>
645
+ <UiSidebarMenuAction :show-on-hover="true" title="More options">
646
+ <MoreHorizontal />
647
+ </UiSidebarMenuAction>
648
+ </UiSidebarMenuItem>
649
+ </UiSidebarMenu>
650
+ </UiSidebarGroupContent>
651
+ </UiSidebarGroup>
652
+ <UiSidebarSeparator />
653
+ <UiSidebarGroup>
654
+ <UiSidebarGroupLabel>Administration</UiSidebarGroupLabel>
655
+ <UiSidebarGroupContent>
656
+ <UiSidebarMenu>
657
+ <UiSidebarMenuItem v-for="item in adminItems" :key="item.title">
658
+ <UiSidebarMenuButton :tooltip="item.title">
659
+ <component :is="item.icon" />
660
+ <span>{{ item.title }}</span>
661
+ </UiSidebarMenuButton>
662
+ </UiSidebarMenuItem>
663
+ </UiSidebarMenu>
664
+ </UiSidebarGroupContent>
665
+ </UiSidebarGroup>
666
+ </UiSidebarContent>
667
+ <UiSidebarRail />
668
+ </UiSidebar>
669
+ <UiSidebarInset>
670
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
671
+ <span class="text-sm font-medium">Pipelines</span>
672
+ </header>
673
+ </UiSidebarInset>
674
+ </UiSidebarProvider>
675
+ `,
676
+ }),
677
+ parameters: {
678
+ docs: {
679
+ source: {
680
+ code: withActionsTemplateSource,
681
+ },
682
+ },
683
+ },
684
+ };
685
+
686
+ const withSubmenuTemplateSource = `<script setup lang="ts">
687
+ import {
688
+ UiSidebar,
689
+ UiSidebarContent,
690
+ UiSidebarGroup,
691
+ UiSidebarGroupContent,
692
+ UiSidebarGroupLabel,
693
+ UiSidebarHeaderTrigger,
694
+ UiSidebarInset,
695
+ UiSidebarMenu,
696
+ UiSidebarMenuButton,
697
+ UiSidebarMenuItem,
698
+ UiSidebarMenuSub,
699
+ UiSidebarMenuSubButton,
700
+ UiSidebarMenuSubItem,
701
+ UiSidebarProvider,
702
+ UiSidebarRail,
703
+ } from '@aleph-alpha/ui-library'
704
+ import { CollapsibleRoot, CollapsibleContent, CollapsibleTrigger } from 'reka-ui'
705
+ import { Bot, Database, BarChart3, MessageSquare, Command, ChevronRight } from 'lucide-vue-next'
706
+
707
+ const navItems = [
708
+ {
709
+ title: 'Models',
710
+ icon: Database,
711
+ children: ['Completions', 'Embeddings', 'Chat', 'Multimodal'],
712
+ },
713
+ {
714
+ title: 'Evaluations',
715
+ icon: BarChart3,
716
+ children: ['Benchmarks', 'Custom Tests', 'Reports'],
717
+ },
718
+ {
719
+ title: 'Playground',
720
+ icon: Bot,
721
+ children: [],
722
+ },
723
+ {
724
+ title: 'Conversations',
725
+ icon: MessageSquare,
726
+ children: [],
727
+ },
728
+ ]
729
+ </script>
730
+
731
+ <template>
732
+ <UiSidebarProvider :default-open="true">
733
+ <UiSidebar>
734
+ <UiSidebarHeaderTrigger>
735
+ <template #logo>
736
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
737
+ <Command class="size-4" />
738
+ </div>
739
+ </template>
740
+ <span class="truncate font-semibold">Acme AI</span>
741
+ <span class="truncate text-xs">Enterprise</span>
742
+ </UiSidebarHeaderTrigger>
743
+ <UiSidebarContent>
744
+ <UiSidebarGroup>
745
+ <UiSidebarGroupLabel>Platform</UiSidebarGroupLabel>
746
+ <UiSidebarGroupContent>
747
+ <UiSidebarMenu>
748
+ <template v-for="item in navItems" :key="item.title">
749
+ <CollapsibleRoot v-if="item.children.length" as-child class="group/collapsible">
750
+ <UiSidebarMenuItem>
751
+ <CollapsibleTrigger as-child>
752
+ <UiSidebarMenuButton :tooltip="item.title">
753
+ <component :is="item.icon" />
754
+ <span>{{ item.title }}</span>
755
+ <ChevronRight class="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
756
+ </UiSidebarMenuButton>
757
+ </CollapsibleTrigger>
758
+ <CollapsibleContent>
759
+ <UiSidebarMenuSub>
760
+ <UiSidebarMenuSubItem v-for="child in item.children" :key="child">
761
+ <UiSidebarMenuSubButton>{{ child }}</UiSidebarMenuSubButton>
762
+ </UiSidebarMenuSubItem>
763
+ </UiSidebarMenuSub>
764
+ </CollapsibleContent>
765
+ </UiSidebarMenuItem>
766
+ </CollapsibleRoot>
767
+ <UiSidebarMenuItem v-else>
768
+ <UiSidebarMenuButton :tooltip="item.title">
769
+ <component :is="item.icon" />
770
+ <span>{{ item.title }}</span>
771
+ </UiSidebarMenuButton>
772
+ </UiSidebarMenuItem>
773
+ </template>
774
+ </UiSidebarMenu>
775
+ </UiSidebarGroupContent>
776
+ </UiSidebarGroup>
777
+ </UiSidebarContent>
778
+ <UiSidebarRail />
779
+ </UiSidebar>
780
+ <UiSidebarInset>
781
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
782
+ <span class="text-sm font-medium">Platform</span>
783
+ </header>
784
+ </UiSidebarInset>
785
+ </UiSidebarProvider>
786
+ </template>`;
787
+
788
+ /**
789
+ * Sidebar with collapsible `UiSidebarMenuSub` submenus using `Collapsible` from reka-ui. "Models" and "Evaluations" expand to reveal nested items via `UiSidebarMenuSubButton`.
790
+ * Submenu items are hidden in icon-collapse mode. A chevron icon rotates to indicate the open/closed state.
791
+ */
792
+ export const WithSubmenu: Story = {
793
+ render: (args) => ({
794
+ components: {
795
+ UiSidebar,
796
+ UiSidebarContent,
797
+ UiSidebarGroup,
798
+ UiSidebarGroupContent,
799
+ UiSidebarGroupLabel,
800
+ UiSidebarHeaderTrigger,
801
+ UiSidebarInset,
802
+ UiSidebarMenu,
803
+ UiSidebarMenuButton,
804
+ UiSidebarMenuItem,
805
+ UiSidebarMenuSub,
806
+ UiSidebarMenuSubButton,
807
+ UiSidebarMenuSubItem,
808
+ UiSidebarProvider,
809
+ UiSidebarRail,
810
+ CollapsibleRoot,
811
+ CollapsibleContent,
812
+ CollapsibleTrigger,
813
+ Bot,
814
+ Database,
815
+ BarChart3,
816
+ MessageSquare,
817
+ Command,
818
+ ChevronRight,
819
+ },
820
+ setup() {
821
+ const navItems = [
822
+ {
823
+ title: 'Models',
824
+ icon: Database,
825
+ children: ['Completions', 'Embeddings', 'Chat', 'Multimodal'],
826
+ },
827
+ {
828
+ title: 'Evaluations',
829
+ icon: BarChart3,
830
+ children: ['Benchmarks', 'Custom Tests', 'Reports'],
831
+ },
832
+ {
833
+ title: 'Playground',
834
+ icon: Bot,
835
+ children: [],
836
+ },
837
+ {
838
+ title: 'Conversations',
839
+ icon: MessageSquare,
840
+ children: [],
841
+ },
842
+ ];
843
+ return { args, navItems };
844
+ },
845
+ template: `
846
+ <UiSidebarProvider :default-open="true">
847
+ <UiSidebar :side="args.side" :variant="args.variant" :collapsible="args.collapsible">
848
+ <UiSidebarHeaderTrigger>
849
+ <template #logo>
850
+ <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
851
+ <Command class="size-4" />
852
+ </div>
853
+ </template>
854
+ <span class="truncate font-semibold">Acme AI</span>
855
+ <span class="truncate text-xs">Enterprise</span>
856
+ </UiSidebarHeaderTrigger>
857
+ <UiSidebarContent>
858
+ <UiSidebarGroup>
859
+ <UiSidebarGroupLabel>Platform</UiSidebarGroupLabel>
860
+ <UiSidebarGroupContent>
861
+ <UiSidebarMenu>
862
+ <template v-for="item in navItems" :key="item.title">
863
+ <CollapsibleRoot v-if="item.children.length" as-child class="group/collapsible">
864
+ <UiSidebarMenuItem>
865
+ <CollapsibleTrigger as-child>
866
+ <UiSidebarMenuButton :tooltip="item.title">
867
+ <component :is="item.icon" />
868
+ <span>{{ item.title }}</span>
869
+ <ChevronRight class="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
870
+ </UiSidebarMenuButton>
871
+ </CollapsibleTrigger>
872
+ <CollapsibleContent>
873
+ <UiSidebarMenuSub>
874
+ <UiSidebarMenuSubItem v-for="child in item.children" :key="child">
875
+ <UiSidebarMenuSubButton>{{ child }}</UiSidebarMenuSubButton>
876
+ </UiSidebarMenuSubItem>
877
+ </UiSidebarMenuSub>
878
+ </CollapsibleContent>
879
+ </UiSidebarMenuItem>
880
+ </CollapsibleRoot>
881
+ <UiSidebarMenuItem v-else>
882
+ <UiSidebarMenuButton :tooltip="item.title">
883
+ <component :is="item.icon" />
884
+ <span>{{ item.title }}</span>
885
+ </UiSidebarMenuButton>
886
+ </UiSidebarMenuItem>
887
+ </template>
888
+ </UiSidebarMenu>
889
+ </UiSidebarGroupContent>
890
+ </UiSidebarGroup>
891
+ </UiSidebarContent>
892
+ <UiSidebarRail />
893
+ </UiSidebar>
894
+ <UiSidebarInset>
895
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
896
+ <span class="text-sm font-medium">Platform</span>
897
+ </header>
898
+ </UiSidebarInset>
899
+ </UiSidebarProvider>
900
+ `,
901
+ }),
902
+ parameters: {
903
+ docs: {
904
+ source: {
905
+ code: withSubmenuTemplateSource,
906
+ },
907
+ },
908
+ },
909
+ };
910
+
911
+ const withSkeletonTemplateSource = `<script setup lang="ts">
912
+ import {
913
+ UiSidebar,
914
+ UiSidebarContent,
915
+ UiSidebarGroup,
916
+ UiSidebarGroupContent,
917
+ UiSidebarGroupLabel,
918
+ UiSidebarInset,
919
+ UiSidebarMenu,
920
+ UiSidebarMenuItem,
921
+ UiSidebarMenuSkeleton,
922
+ UiSidebarProvider,
923
+ UiSidebarRail,
924
+ UiSidebarTrigger,
925
+ } from '@aleph-alpha/ui-library'
926
+ </script>
927
+
928
+ <template>
929
+ <UiSidebarProvider :default-open="true">
930
+ <UiSidebar>
931
+ <UiSidebarContent>
932
+ <UiSidebarGroup>
933
+ <UiSidebarGroupLabel>Platform</UiSidebarGroupLabel>
934
+ <UiSidebarGroupContent>
935
+ <UiSidebarMenu>
936
+ <UiSidebarMenuItem v-for="i in 4" :key="i">
937
+ <UiSidebarMenuSkeleton :show-icon="true" />
938
+ </UiSidebarMenuItem>
939
+ </UiSidebarMenu>
940
+ </UiSidebarGroupContent>
941
+ </UiSidebarGroup>
942
+ </UiSidebarContent>
943
+ <UiSidebarRail />
944
+ </UiSidebar>
945
+ <UiSidebarInset>
946
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
947
+ <UiSidebarTrigger class="-ml-1" />
948
+ <span class="text-sm font-medium">Platform</span>
949
+ </header>
950
+ </UiSidebarInset>
951
+ </UiSidebarProvider>
952
+ </template>`;
953
+
954
+ /**
955
+ * Sidebar with `UiSidebarMenuSkeleton` placeholders showing a loading state.
956
+ * Use `show-icon` to include an icon-sized skeleton circle alongside the text bar. Each skeleton renders a random width for a natural staggered look.
957
+ */
958
+ export const WithSkeleton: Story = {
959
+ render: (args) => ({
960
+ components: {
961
+ UiSidebar,
962
+ UiSidebarContent,
963
+ UiSidebarGroup,
964
+ UiSidebarGroupContent,
965
+ UiSidebarGroupLabel,
966
+ UiSidebarInset,
967
+ UiSidebarMenu,
968
+ UiSidebarMenuItem,
969
+ UiSidebarMenuSkeleton,
970
+ UiSidebarProvider,
971
+ UiSidebarRail,
972
+ UiSidebarTrigger,
973
+ },
974
+ setup() {
975
+ return { args };
976
+ },
977
+ template: `
978
+ <UiSidebarProvider :default-open="true">
979
+ <UiSidebar :side="args.side" :variant="args.variant" :collapsible="args.collapsible">
980
+ <UiSidebarContent>
981
+ <UiSidebarGroup>
982
+ <UiSidebarGroupLabel>Platform</UiSidebarGroupLabel>
983
+ <UiSidebarGroupContent>
984
+ <UiSidebarMenu>
985
+ <UiSidebarMenuItem v-for="i in 4" :key="i">
986
+ <UiSidebarMenuSkeleton :show-icon="true" />
987
+ </UiSidebarMenuItem>
988
+ </UiSidebarMenu>
989
+ </UiSidebarGroupContent>
990
+ </UiSidebarGroup>
991
+ </UiSidebarContent>
992
+ <UiSidebarRail />
993
+ </UiSidebar>
994
+ <UiSidebarInset>
995
+ <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
996
+ <UiSidebarTrigger class="-ml-1" />
997
+ <span class="text-sm font-medium">Platform</span>
998
+ </header>
999
+ </UiSidebarInset>
1000
+ </UiSidebarProvider>
1001
+ `,
1002
+ }),
1003
+ parameters: {
1004
+ docs: {
1005
+ source: {
1006
+ code: withSkeletonTemplateSource,
1007
+ },
1008
+ },
1009
+ },
1010
+ };