@elabs-ai/components-ui 4.0.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.
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/dist/index.d.ts +4497 -0
- package/dist/index.js +15192 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cn.d.ts +10 -0
- package/dist/lib/cn.js +20 -0
- package/dist/lib/cn.js.map +1 -0
- package/package.json +106 -0
- package/src/blocks/sidebar-02/app-sidebar.tsx +160 -0
- package/src/blocks/sidebar-02/logo.tsx +18 -0
- package/src/blocks/sidebar-02/nav-main.tsx +13 -0
- package/src/blocks/sidebar-02/nav-notifications.tsx +7 -0
- package/src/blocks/sidebar-02/sidebar-02.stories.tsx +23 -0
- package/src/blocks/sidebar-02/team-switcher.tsx +7 -0
- package/src/blocks/sidebar-04/app-sidebar.tsx +236 -0
- package/src/blocks/sidebar-04/mail-context.tsx +29 -0
- package/src/blocks/sidebar-04/nav-user.tsx +6 -0
- package/src/blocks/sidebar-04/sidebar-04.stories.tsx +150 -0
- package/src/blocks/sidebar-05/app-sidebar.tsx +375 -0
- package/src/blocks/sidebar-05/sidebar-05.stories.tsx +18 -0
- package/src/blocks/sidebar-05/team-switcher.tsx +6 -0
- package/src/blocks-comparison-table.stories.tsx +165 -0
- package/src/components/accordion/accordion.stories.tsx +71 -0
- package/src/components/accordion/accordion.test.tsx +18 -0
- package/src/components/accordion/accordion.tsx +49 -0
- package/src/components/accordion/index.ts +1 -0
- package/src/components/advanced-group/advanced-group.stories.tsx +143 -0
- package/src/components/advanced-group/advanced-group.test.tsx +81 -0
- package/src/components/advanced-group/advanced-group.tsx +111 -0
- package/src/components/advanced-group/index.ts +2 -0
- package/src/components/alert/alert.stories.tsx +156 -0
- package/src/components/alert/alert.test.tsx +57 -0
- package/src/components/alert/alert.tsx +91 -0
- package/src/components/alert/index.ts +8 -0
- package/src/components/alert-dialog/alert-dialog.stories.tsx +73 -0
- package/src/components/alert-dialog/alert-dialog.tsx +104 -0
- package/src/components/alert-dialog/index.ts +12 -0
- package/src/components/app-shell/app-shell.stories.tsx +61 -0
- package/src/components/app-shell/app-shell.tsx +31 -0
- package/src/components/app-shell/index.ts +1 -0
- package/src/components/app-sidebar/app-sidebar.stories.tsx +121 -0
- package/src/components/app-sidebar/app-sidebar.test.tsx +55 -0
- package/src/components/app-sidebar/app-sidebar.tsx +53 -0
- package/src/components/app-sidebar/index.ts +1 -0
- package/src/components/aspect-ratio/aspect-ratio.stories.tsx +46 -0
- package/src/components/aspect-ratio/aspect-ratio.tsx +3 -0
- package/src/components/aspect-ratio/index.ts +1 -0
- package/src/components/attribution-panel/attribution-panel.stories.tsx +83 -0
- package/src/components/attribution-panel/attribution-panel.test.tsx +123 -0
- package/src/components/attribution-panel/attribution-panel.tsx +191 -0
- package/src/components/attribution-panel/attribution-types.ts +44 -0
- package/src/components/attribution-panel/attributions.generated.ts +1422 -0
- package/src/components/attribution-panel/index.ts +3 -0
- package/src/components/avatar/avatar.stories.tsx +45 -0
- package/src/components/avatar/avatar.test.tsx +13 -0
- package/src/components/avatar/avatar.tsx +46 -0
- package/src/components/avatar/index.ts +1 -0
- package/src/components/badge/badge.stories.tsx +44 -0
- package/src/components/badge/badge.test.tsx +10 -0
- package/src/components/badge/badge.tsx +28 -0
- package/src/components/badge/index.ts +1 -0
- package/src/components/bento-grid/bento-grid.stories.tsx +165 -0
- package/src/components/bento-grid/bento-grid.test.tsx +119 -0
- package/src/components/bento-grid/bento-grid.tsx +339 -0
- package/src/components/bento-grid/index.ts +9 -0
- package/src/components/bounded-number/bounded-number.stories.tsx +118 -0
- package/src/components/bounded-number/bounded-number.test.tsx +73 -0
- package/src/components/bounded-number/bounded-number.tsx +110 -0
- package/src/components/bounded-number/index.ts +1 -0
- package/src/components/breadcrumb/breadcrumb.stories.tsx +47 -0
- package/src/components/breadcrumb/breadcrumb.test.tsx +17 -0
- package/src/components/breadcrumb/breadcrumb.tsx +86 -0
- package/src/components/breadcrumb/index.ts +9 -0
- package/src/components/button/button.stories.tsx +70 -0
- package/src/components/button/button.test.tsx +50 -0
- package/src/components/button/button.tsx +63 -0
- package/src/components/button/index.ts +1 -0
- package/src/components/button-group/button-group.stories.tsx +45 -0
- package/src/components/button-group/button-group.tsx +70 -0
- package/src/components/button-group/index.ts +6 -0
- package/src/components/calendar/calendar.stories.tsx +95 -0
- package/src/components/calendar/calendar.test.tsx +140 -0
- package/src/components/calendar/calendar.tsx +70 -0
- package/src/components/calendar/index.ts +1 -0
- package/src/components/card/card.stories.tsx +438 -0
- package/src/components/card/card.test.tsx +153 -0
- package/src/components/card/card.tsx +332 -0
- package/src/components/card/index.ts +13 -0
- package/src/components/carousel/carousel.stories.tsx +102 -0
- package/src/components/carousel/carousel.tsx +225 -0
- package/src/components/carousel/index.ts +8 -0
- package/src/components/change-review/change-review.stories.tsx +288 -0
- package/src/components/change-review/change-review.test.tsx +261 -0
- package/src/components/change-review/change-review.tsx +637 -0
- package/src/components/change-review/index.ts +23 -0
- package/src/components/checkbox/checkbox.stories.tsx +119 -0
- package/src/components/checkbox/checkbox.test.tsx +40 -0
- package/src/components/checkbox/checkbox.tsx +34 -0
- package/src/components/checkbox/index.ts +1 -0
- package/src/components/collapsible/collapsible.stories.tsx +62 -0
- package/src/components/collapsible/collapsible.tsx +22 -0
- package/src/components/collapsible/index.ts +1 -0
- package/src/components/collapsible-panel/index.ts +8 -0
- package/src/components/collapsible-panel/use-collapsible-panel.test.tsx +93 -0
- package/src/components/collapsible-panel/use-collapsible-panel.ts +159 -0
- package/src/components/color-picker/color-picker.stories.tsx +93 -0
- package/src/components/color-picker/color-picker.test.tsx +79 -0
- package/src/components/color-picker/color-picker.tsx +341 -0
- package/src/components/color-picker/index.ts +1 -0
- package/src/components/combobox/combobox.stories.tsx +154 -0
- package/src/components/combobox/combobox.test.tsx +246 -0
- package/src/components/combobox/combobox.tsx +210 -0
- package/src/components/combobox/index.ts +1 -0
- package/src/components/command/command.stories.tsx +371 -0
- package/src/components/command/command.test.tsx +280 -0
- package/src/components/command/command.tsx +301 -0
- package/src/components/command/index.ts +13 -0
- package/src/components/confirm-dialog/confirm-dialog.stories.tsx +183 -0
- package/src/components/confirm-dialog/confirm-dialog.test.tsx +147 -0
- package/src/components/confirm-dialog/confirm-dialog.tsx +146 -0
- package/src/components/confirm-dialog/index.ts +2 -0
- package/src/components/context-menu/context-menu.stories.tsx +70 -0
- package/src/components/context-menu/context-menu.tsx +172 -0
- package/src/components/context-menu/index.ts +16 -0
- package/src/components/copyable-value/copyable-value.stories.tsx +80 -0
- package/src/components/copyable-value/copyable-value.test.tsx +128 -0
- package/src/components/copyable-value/copyable-value.tsx +101 -0
- package/src/components/copyable-value/index.ts +1 -0
- package/src/components/date-picker/date-picker.stories.tsx +42 -0
- package/src/components/date-picker/date-picker.tsx +49 -0
- package/src/components/date-picker/index.ts +1 -0
- package/src/components/date-range-picker/date-range-picker.stories.tsx +151 -0
- package/src/components/date-range-picker/date-range-picker.test.tsx +62 -0
- package/src/components/date-range-picker/date-range-picker.tsx +126 -0
- package/src/components/date-range-picker/index.ts +6 -0
- package/src/components/descriptions/descriptions.stories.tsx +43 -0
- package/src/components/descriptions/descriptions.test.tsx +41 -0
- package/src/components/descriptions/descriptions.tsx +95 -0
- package/src/components/descriptions/index.ts +6 -0
- package/src/components/dialog/dialog.stories.tsx +728 -0
- package/src/components/dialog/dialog.test.tsx +285 -0
- package/src/components/dialog/dialog.tsx +340 -0
- package/src/components/dialog/index.ts +18 -0
- package/src/components/dialog/use-dialog-dismiss-guard.test.tsx +80 -0
- package/src/components/dialog/use-dialog-dismiss-guard.ts +109 -0
- package/src/components/drawer/drawer.stories.tsx +76 -0
- package/src/components/drawer/drawer.tsx +85 -0
- package/src/components/drawer/index.ts +11 -0
- package/src/components/dropdown-menu/dropdown-menu.stories.tsx +176 -0
- package/src/components/dropdown-menu/dropdown-menu.test.tsx +109 -0
- package/src/components/dropdown-menu/dropdown-menu.tsx +179 -0
- package/src/components/dropdown-menu/index.ts +17 -0
- package/src/components/empty-state/empty-state.stories.tsx +54 -0
- package/src/components/empty-state/empty-state.test.tsx +11 -0
- package/src/components/empty-state/empty-state.tsx +30 -0
- package/src/components/empty-state/index.ts +1 -0
- package/src/components/error-state/error-state.stories.tsx +51 -0
- package/src/components/error-state/error-state.tsx +27 -0
- package/src/components/error-state/index.ts +1 -0
- package/src/components/expand-dialog/expand-dialog.stories.tsx +246 -0
- package/src/components/expand-dialog/expand-dialog.test.tsx +185 -0
- package/src/components/expand-dialog/expand-dialog.tsx +387 -0
- package/src/components/expand-dialog/index.ts +11 -0
- package/src/components/field-row/field-row.stories.tsx +114 -0
- package/src/components/field-row/field-row.test.tsx +188 -0
- package/src/components/field-row/field-row.tsx +115 -0
- package/src/components/field-row/index.ts +1 -0
- package/src/components/file-upload/file-upload.stories.tsx +183 -0
- package/src/components/file-upload/file-upload.test.tsx +169 -0
- package/src/components/file-upload/file-upload.tsx +459 -0
- package/src/components/file-upload/index.ts +13 -0
- package/src/components/form/form.stories.tsx +71 -0
- package/src/components/form/form.tsx +141 -0
- package/src/components/form/index.ts +10 -0
- package/src/components/hover-card/hover-card.stories.tsx +57 -0
- package/src/components/hover-card/hover-card.tsx +25 -0
- package/src/components/hover-card/index.ts +1 -0
- package/src/components/icon-button/icon-button.stories.tsx +108 -0
- package/src/components/icon-button/icon-button.test.tsx +93 -0
- package/src/components/icon-button/icon-button.tsx +139 -0
- package/src/components/icon-button/index.ts +1 -0
- package/src/components/input/index.ts +1 -0
- package/src/components/input/input.stories.tsx +44 -0
- package/src/components/input/input.test.tsx +19 -0
- package/src/components/input/input.tsx +26 -0
- package/src/components/input-group/index.ts +11 -0
- package/src/components/input-group/input-group.stories.tsx +87 -0
- package/src/components/input-group/input-group.test.tsx +48 -0
- package/src/components/input-group/input-group.tsx +170 -0
- package/src/components/input-otp/index.ts +1 -0
- package/src/components/input-otp/input-otp.stories.tsx +66 -0
- package/src/components/input-otp/input-otp.tsx +68 -0
- package/src/components/kbd/index.ts +1 -0
- package/src/components/kbd/kbd.stories.tsx +45 -0
- package/src/components/kbd/kbd.tsx +20 -0
- package/src/components/key-value-editor/index.ts +1 -0
- package/src/components/key-value-editor/key-value-editor.stories.tsx +130 -0
- package/src/components/key-value-editor/key-value-editor.test.tsx +231 -0
- package/src/components/key-value-editor/key-value-editor.tsx +263 -0
- package/src/components/label/index.ts +1 -0
- package/src/components/label/label.stories.tsx +35 -0
- package/src/components/label/label.tsx +19 -0
- package/src/components/link-preview/index.ts +2 -0
- package/src/components/link-preview/link-preview.stories.tsx +178 -0
- package/src/components/link-preview/link-preview.test.tsx +123 -0
- package/src/components/link-preview/link-preview.tsx +194 -0
- package/src/components/list-editor/index.ts +1 -0
- package/src/components/list-editor/list-editor.stories.tsx +119 -0
- package/src/components/list-editor/list-editor.test.tsx +96 -0
- package/src/components/list-editor/list-editor.tsx +192 -0
- package/src/components/loading-state/index.ts +1 -0
- package/src/components/loading-state/loading-state.stories.tsx +38 -0
- package/src/components/loading-state/loading-state.tsx +26 -0
- package/src/components/locale-provider/index.ts +8 -0
- package/src/components/locale-provider/locale-provider.stories.tsx +83 -0
- package/src/components/locale-provider/locale-provider.test.tsx +238 -0
- package/src/components/locale-provider/locale-provider.tsx +187 -0
- package/src/components/locale-provider/messages.ts +300 -0
- package/src/components/match-highlight/index.ts +7 -0
- package/src/components/match-highlight/match-highlight.stories.tsx +146 -0
- package/src/components/match-highlight/match-highlight.test.tsx +202 -0
- package/src/components/match-highlight/match-highlight.tsx +145 -0
- package/src/components/mention-input/index.ts +28 -0
- package/src/components/mention-input/mention-input-mirror.stories.tsx +171 -0
- package/src/components/mention-input/mention-input.stories.tsx +463 -0
- package/src/components/mention-input/mention-input.test.tsx +617 -0
- package/src/components/mention-input/mention-input.tsx +1102 -0
- package/src/components/mention-input/mention-value.test.ts +253 -0
- package/src/components/mention-input/mention-value.ts +193 -0
- package/src/components/menubar/index.ts +17 -0
- package/src/components/menubar/menubar.stories.tsx +67 -0
- package/src/components/menubar/menubar.tsx +198 -0
- package/src/components/metric-card/index.ts +1 -0
- package/src/components/metric-card/metric-card.stories.tsx +224 -0
- package/src/components/metric-card/metric-card.test.tsx +198 -0
- package/src/components/metric-card/metric-card.tsx +229 -0
- package/src/components/model-picker/index.ts +11 -0
- package/src/components/model-picker/model-picker-state.ts +85 -0
- package/src/components/model-picker/model-picker.stories.tsx +128 -0
- package/src/components/model-picker/model-picker.test.tsx +241 -0
- package/src/components/model-picker/model-picker.tsx +270 -0
- package/src/components/nav-main/index.ts +1 -0
- package/src/components/nav-main/nav-main.tsx +147 -0
- package/src/components/nav-notifications/index.ts +5 -0
- package/src/components/nav-notifications/nav-notifications.test.tsx +15 -0
- package/src/components/nav-notifications/nav-notifications.tsx +70 -0
- package/src/components/nav-user/index.ts +1 -0
- package/src/components/nav-user/nav-user.test.tsx +29 -0
- package/src/components/nav-user/nav-user.tsx +114 -0
- package/src/components/navigation-menu/index.ts +10 -0
- package/src/components/navigation-menu/navigation-menu.stories.tsx +92 -0
- package/src/components/navigation-menu/navigation-menu.tsx +99 -0
- package/src/components/number-input/index.ts +1 -0
- package/src/components/number-input/number-input.stories.tsx +120 -0
- package/src/components/number-input/number-input.test.tsx +96 -0
- package/src/components/number-input/number-input.tsx +219 -0
- package/src/components/page-shell/index.ts +1 -0
- package/src/components/page-shell/page-shell.stories.tsx +105 -0
- package/src/components/page-shell/page-shell.test.tsx +57 -0
- package/src/components/page-shell/page-shell.tsx +62 -0
- package/src/components/pagination/index.ts +9 -0
- package/src/components/pagination/pagination.stories.tsx +57 -0
- package/src/components/pagination/pagination.tsx +77 -0
- package/src/components/popover/index.ts +1 -0
- package/src/components/popover/popover.stories.tsx +28 -0
- package/src/components/popover/popover.test.tsx +16 -0
- package/src/components/popover/popover.tsx +29 -0
- package/src/components/progress/index.ts +1 -0
- package/src/components/progress/progress.stories.tsx +80 -0
- package/src/components/progress/progress.test.tsx +35 -0
- package/src/components/progress/progress.tsx +50 -0
- package/src/components/radio-group/index.ts +1 -0
- package/src/components/radio-group/radio-group.stories.tsx +75 -0
- package/src/components/radio-group/radio-group.test.tsx +16 -0
- package/src/components/radio-group/radio-group.tsx +33 -0
- package/src/components/rating/index.ts +1 -0
- package/src/components/rating/rating.stories.tsx +111 -0
- package/src/components/rating/rating.test.tsx +41 -0
- package/src/components/rating/rating.tsx +226 -0
- package/src/components/resizable/index.ts +1 -0
- package/src/components/resizable/resizable.stories.tsx +25 -0
- package/src/components/resizable/resizable.tsx +40 -0
- package/src/components/reveal/index.ts +7 -0
- package/src/components/reveal/reveal.stories.tsx +90 -0
- package/src/components/reveal/reveal.test.tsx +43 -0
- package/src/components/reveal/reveal.tsx +95 -0
- package/src/components/revision-timeline/index.ts +10 -0
- package/src/components/revision-timeline/revision-timeline.stories.tsx +785 -0
- package/src/components/revision-timeline/revision-timeline.test.tsx +509 -0
- package/src/components/revision-timeline/revision-timeline.tsx +1107 -0
- package/src/components/scroll-area/index.ts +1 -0
- package/src/components/scroll-area/scroll-area.stories.tsx +45 -0
- package/src/components/scroll-area/scroll-area.tsx +43 -0
- package/src/components/section-header/index.ts +1 -0
- package/src/components/section-header/section-header.stories.tsx +20 -0
- package/src/components/section-header/section-header.tsx +36 -0
- package/src/components/segmented-field/index.ts +5 -0
- package/src/components/segmented-field/segmented-field.stories.tsx +121 -0
- package/src/components/segmented-field/segmented-field.test.tsx +163 -0
- package/src/components/segmented-field/segmented-field.tsx +235 -0
- package/src/components/select/index.ts +10 -0
- package/src/components/select/select.stories.tsx +106 -0
- package/src/components/select/select.test.tsx +98 -0
- package/src/components/select/select.tsx +230 -0
- package/src/components/separator/index.ts +2 -0
- package/src/components/separator/separator.stories.tsx +87 -0
- package/src/components/separator/separator.tsx +51 -0
- package/src/components/sheet/index.ts +12 -0
- package/src/components/sheet/sheet.stories.tsx +65 -0
- package/src/components/sheet/sheet.tsx +109 -0
- package/src/components/sidebar/index.ts +27 -0
- package/src/components/sidebar/sidebar.stories.tsx +69 -0
- package/src/components/sidebar/sidebar.test.tsx +43 -0
- package/src/components/sidebar/sidebar.tsx +688 -0
- package/src/components/skeleton/index.ts +1 -0
- package/src/components/skeleton/skeleton.stories.tsx +28 -0
- package/src/components/skeleton/skeleton.tsx +15 -0
- package/src/components/slider/index.ts +1 -0
- package/src/components/slider/slider.stories.tsx +211 -0
- package/src/components/slider/slider.test.tsx +168 -0
- package/src/components/slider/slider.tsx +136 -0
- package/src/components/slider-number/index.ts +1 -0
- package/src/components/slider-number/slider-number.stories.tsx +123 -0
- package/src/components/slider-number/slider-number.test.tsx +165 -0
- package/src/components/slider-number/slider-number.tsx +191 -0
- package/src/components/sonner/index.ts +1 -0
- package/src/components/sonner/sonner.stories.tsx +124 -0
- package/src/components/sonner/sonner.test.tsx +76 -0
- package/src/components/sonner/sonner.tsx +101 -0
- package/src/components/spinner/index.ts +1 -0
- package/src/components/spinner/spinner.stories.tsx +27 -0
- package/src/components/spinner/spinner.tsx +19 -0
- package/src/components/split-panel/index.ts +1 -0
- package/src/components/split-panel/split-panel.stories.tsx +60 -0
- package/src/components/split-panel/split-panel.test.tsx +38 -0
- package/src/components/split-panel/split-panel.tsx +95 -0
- package/src/components/state-panel/index.ts +1 -0
- package/src/components/state-panel/state-panel.stories.tsx +80 -0
- package/src/components/state-panel/state-panel.test.tsx +64 -0
- package/src/components/state-panel/state-panel.tsx +167 -0
- package/src/components/status-badge/index.ts +18 -0
- package/src/components/status-badge/status-badge.stories.tsx +132 -0
- package/src/components/status-badge/status-badge.test.tsx +189 -0
- package/src/components/status-badge/status-badge.tsx +330 -0
- package/src/components/switch/index.ts +1 -0
- package/src/components/switch/switch.stories.tsx +58 -0
- package/src/components/switch/switch.test.tsx +12 -0
- package/src/components/switch/switch.tsx +29 -0
- package/src/components/table/index.ts +10 -0
- package/src/components/table/table.stories.tsx +53 -0
- package/src/components/table/table.test.tsx +17 -0
- package/src/components/table/table.tsx +106 -0
- package/src/components/tabs/index.ts +1 -0
- package/src/components/tabs/tabs.stories.tsx +267 -0
- package/src/components/tabs/tabs.test.tsx +94 -0
- package/src/components/tabs/tabs.tsx +170 -0
- package/src/components/tag-input/index.ts +1 -0
- package/src/components/tag-input/tag-input.stories.tsx +120 -0
- package/src/components/tag-input/tag-input.test.tsx +97 -0
- package/src/components/tag-input/tag-input.tsx +253 -0
- package/src/components/team-switcher/index.ts +1 -0
- package/src/components/team-switcher/team-switcher.test.tsx +39 -0
- package/src/components/team-switcher/team-switcher.tsx +100 -0
- package/src/components/textarea/index.ts +1 -0
- package/src/components/textarea/textarea.stories.tsx +42 -0
- package/src/components/textarea/textarea.tsx +24 -0
- package/src/components/theme-switcher/index.ts +2 -0
- package/src/components/theme-switcher/theme-switcher.stories.tsx +146 -0
- package/src/components/theme-switcher/theme-switcher.test.tsx +253 -0
- package/src/components/theme-switcher/theme-switcher.tsx +280 -0
- package/src/components/theme-switcher/use-theme-transition.ts +62 -0
- package/src/components/timeline/index.ts +13 -0
- package/src/components/timeline/timeline.stories.tsx +99 -0
- package/src/components/timeline/timeline.test.tsx +196 -0
- package/src/components/timeline/timeline.tsx +188 -0
- package/src/components/toggle/index.ts +1 -0
- package/src/components/toggle/toggle.stories.tsx +116 -0
- package/src/components/toggle/toggle.test.tsx +119 -0
- package/src/components/toggle/toggle.tsx +64 -0
- package/src/components/toggle-group/index.ts +1 -0
- package/src/components/toggle-group/toggle-group.stories.tsx +110 -0
- package/src/components/toggle-group/toggle-group.tsx +59 -0
- package/src/components/toolbar/index.ts +14 -0
- package/src/components/toolbar/toolbar.stories.tsx +126 -0
- package/src/components/toolbar/toolbar.test.tsx +73 -0
- package/src/components/toolbar/toolbar.tsx +177 -0
- package/src/components/tooltip/index.ts +1 -0
- package/src/components/tooltip/tooltip.stories.tsx +67 -0
- package/src/components/tooltip/tooltip.tsx +27 -0
- package/src/components/top-nav/index.ts +1 -0
- package/src/components/top-nav/top-nav.stories.tsx +18 -0
- package/src/components/top-nav/top-nav.tsx +34 -0
- package/src/components/transfer/index.ts +2 -0
- package/src/components/transfer/transfer.stories.tsx +162 -0
- package/src/components/transfer/transfer.test.tsx +177 -0
- package/src/components/transfer/transfer.tsx +481 -0
- package/src/components/tree/index.ts +6 -0
- package/src/components/tree/tree.stories.tsx +618 -0
- package/src/components/tree/tree.test.tsx +699 -0
- package/src/components/tree/tree.tsx +1149 -0
- package/src/components/tree/use-tree-keyboard.ts +314 -0
- package/src/components/tree-select/index.ts +1 -0
- package/src/components/tree-select/tree-select.stories.tsx +127 -0
- package/src/components/tree-select/tree-select.test.tsx +40 -0
- package/src/components/tree-select/tree-select.tsx +137 -0
- package/src/components/typography/index.ts +31 -0
- package/src/components/typography/prose.test.tsx +48 -0
- package/src/components/typography/prose.tsx +194 -0
- package/src/components/typography/typography.stories.tsx +244 -0
- package/src/components/typography/typography.test.tsx +140 -0
- package/src/components/typography/typography.tsx +126 -0
- package/src/components/view-toolbar/index.ts +10 -0
- package/src/components/view-toolbar/view-toolbar.stories.tsx +342 -0
- package/src/components/view-toolbar/view-toolbar.test.tsx +262 -0
- package/src/components/view-toolbar/view-toolbar.tsx +320 -0
- package/src/components/virtual-select/index.ts +2 -0
- package/src/components/virtual-select/use-virtual-listbox.ts +132 -0
- package/src/components/virtual-select/virtual-select.stories.tsx +203 -0
- package/src/components/virtual-select/virtual-select.test.tsx +106 -0
- package/src/components/virtual-select/virtual-select.tsx +361 -0
- package/src/components/wizard/index.ts +12 -0
- package/src/components/wizard/wizard.stories.tsx +148 -0
- package/src/components/wizard/wizard.test.tsx +67 -0
- package/src/components/wizard/wizard.tsx +354 -0
- package/src/decoration.stories.tsx +236 -0
- package/src/index.ts +174 -0
- package/src/lib/cn.test.ts +39 -0
- package/src/lib/cn.ts +31 -0
- package/src/lib/compact-number.ts +61 -0
- package/src/lib/document-address.test.ts +75 -0
- package/src/lib/document-address.ts +265 -0
- package/src/lib/download.ts +93 -0
- package/src/lib/file-icon.test.ts +45 -0
- package/src/lib/file-icon.ts +58 -0
- package/src/lib/file-kind.test.ts +98 -0
- package/src/lib/file-kind.ts +303 -0
- package/src/lib/file-source.test.ts +217 -0
- package/src/lib/file-source.ts +269 -0
- package/src/lib/merge-refs.test.ts +37 -0
- package/src/lib/merge-refs.ts +17 -0
- package/src/lib/streamdown-translations.ts +99 -0
- package/src/lib/use-copy-to-clipboard.ts +75 -0
- package/src/lib/use-mobile.ts +16 -0
- package/src/motion.stories.tsx +266 -0
- package/src/taste-profile.test.tsx +252 -0
- package/src/templates-object-detail-hub.stories.tsx +466 -0
- package/src/templates-screen-states.stories.tsx +306 -0
- package/src/templates-settings.stories.tsx +245 -0
package/dist/lib/cn.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ClassValue } from 'clsx';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Merge class names with conflict resolution. `clsx` handles conditionals;
|
|
5
|
+
* `tailwind-merge` ensures later Tailwind utilities win (e.g. `p-2 p-4` -> `p-4`).
|
|
6
|
+
* Use this in every component that accepts a `className` prop.
|
|
7
|
+
*/
|
|
8
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
9
|
+
|
|
10
|
+
export { cn };
|
package/dist/lib/cn.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/lib/cn.ts
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { extendTailwindMerge } from "tailwind-merge";
|
|
4
|
+
var TEXT_ROLES = ["display", "title", "subtitle", "body", "caption", "meta", "kpi", "code"];
|
|
5
|
+
var twMerge = extendTailwindMerge({
|
|
6
|
+
extend: {
|
|
7
|
+
classGroups: {
|
|
8
|
+
"font-size": [{ text: TEXT_ROLES }],
|
|
9
|
+
// `font-display` is the display-face seam (sibling of font-mono, #187).
|
|
10
|
+
"font-family": [{ font: ["display"] }]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
function cn(...inputs) {
|
|
15
|
+
return twMerge(clsx(inputs));
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
cn
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=cn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\n/**\n * The semantic type roles (`--text-<role>` tokens → `text-<role>` utilities, #187).\n * tailwind-merge doesn't know custom theme keys, so without registration it\n * classifies `text-title` as a text COLOR — and `cn(\"text-kpi\", \"text-foreground\")`\n * would silently drop the role. Registering the roles in the `font-size` class\n * group makes role-vs-role and role-vs-raw-size conflicts resolve correctly while\n * keeping role + color independent.\n */\nconst TEXT_ROLES = [\"display\", \"title\", \"subtitle\", \"body\", \"caption\", \"meta\", \"kpi\", \"code\"];\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n \"font-size\": [{ text: TEXT_ROLES }],\n // `font-display` is the display-face seam (sibling of font-mono, #187).\n \"font-family\": [{ font: [\"display\"] }],\n },\n },\n});\n\n/**\n * Merge class names with conflict resolution. `clsx` handles conditionals;\n * `tailwind-merge` ensures later Tailwind utilities win (e.g. `p-2 p-4` -> `p-4`).\n * Use this in every component that accepts a `className` prop.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAUpC,IAAM,aAAa,CAAC,WAAW,SAAS,YAAY,QAAQ,WAAW,QAAQ,OAAO,MAAM;AAE5F,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa,CAAC,EAAE,MAAM,WAAW,CAAC;AAAA;AAAA,MAElC,eAAe,CAAC,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;AAAA,IACvC;AAAA,EACF;AACF,CAAC;AAOM,SAAS,MAAM,QAA8B;AAClD,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elabs-ai/components-ui",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/mreimitz/elabs-components.git",
|
|
8
|
+
"directory": "packages/ui"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"src"
|
|
14
|
+
],
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./lib/cn": {
|
|
22
|
+
"types": "./dist/lib/cn.d.ts",
|
|
23
|
+
"default": "./dist/lib/cn.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org/"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@hookform/resolvers": "^3.9.1",
|
|
32
|
+
"@radix-ui/react-accordion": "^1.2.2",
|
|
33
|
+
"@radix-ui/react-alert-dialog": "^1.1.4",
|
|
34
|
+
"@radix-ui/react-aspect-ratio": "^1.1.1",
|
|
35
|
+
"@radix-ui/react-avatar": "^1.1.2",
|
|
36
|
+
"@radix-ui/react-checkbox": "^1.1.3",
|
|
37
|
+
"@radix-ui/react-collapsible": "^1.1.2",
|
|
38
|
+
"@radix-ui/react-context-menu": "^2.2.4",
|
|
39
|
+
"@radix-ui/react-dialog": "^1.1.4",
|
|
40
|
+
"@radix-ui/react-direction": "^1.1.1",
|
|
41
|
+
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
|
42
|
+
"@radix-ui/react-hover-card": "^1.1.4",
|
|
43
|
+
"@radix-ui/react-label": "^2.1.1",
|
|
44
|
+
"@radix-ui/react-menubar": "^1.1.4",
|
|
45
|
+
"@radix-ui/react-navigation-menu": "^1.2.3",
|
|
46
|
+
"@radix-ui/react-popover": "^1.1.4",
|
|
47
|
+
"@radix-ui/react-progress": "^1.1.1",
|
|
48
|
+
"@radix-ui/react-radio-group": "^1.2.2",
|
|
49
|
+
"@radix-ui/react-scroll-area": "^1.2.2",
|
|
50
|
+
"@radix-ui/react-select": "^2.1.4",
|
|
51
|
+
"@radix-ui/react-separator": "^1.1.1",
|
|
52
|
+
"@radix-ui/react-slider": "^1.2.2",
|
|
53
|
+
"@radix-ui/react-slot": "^1.1.1",
|
|
54
|
+
"@radix-ui/react-switch": "^1.1.2",
|
|
55
|
+
"@radix-ui/react-tabs": "^1.1.2",
|
|
56
|
+
"@radix-ui/react-toggle": "^1.1.1",
|
|
57
|
+
"@radix-ui/react-toggle-group": "^1.1.1",
|
|
58
|
+
"@radix-ui/react-toolbar": "^1.1.19",
|
|
59
|
+
"@radix-ui/react-tooltip": "^1.1.6",
|
|
60
|
+
"@tanstack/react-virtual": "^3.14.2",
|
|
61
|
+
"class-variance-authority": "^0.7.1",
|
|
62
|
+
"clsx": "^2.1.1",
|
|
63
|
+
"cmdk": "^1.0.4",
|
|
64
|
+
"embla-carousel-react": "^8.5.1",
|
|
65
|
+
"input-otp": "^1.4.1",
|
|
66
|
+
"lucide-react": "^0.577.0",
|
|
67
|
+
"react-day-picker": "^9.4.4",
|
|
68
|
+
"react-hook-form": "^7.54.2",
|
|
69
|
+
"react-resizable-panels": "^2.1.7",
|
|
70
|
+
"sonner": "^1.7.1",
|
|
71
|
+
"tailwind-merge": "^2.6.0",
|
|
72
|
+
"vaul": "^1.1.2",
|
|
73
|
+
"zod": "^3.24.1"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"react": "^18.2.0 || ^19.0.0",
|
|
77
|
+
"react-dom": "^18.2.0 || ^19.0.0",
|
|
78
|
+
"@elabs-ai/components-tokens": "4.0.0"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
82
|
+
"@testing-library/react": "^16.1.0",
|
|
83
|
+
"@testing-library/user-event": "^14.5.2",
|
|
84
|
+
"@types/react": "^19.0.2",
|
|
85
|
+
"@types/react-dom": "^19.0.2",
|
|
86
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
87
|
+
"eslint": "^9.17.0",
|
|
88
|
+
"jsdom": "^25.0.1",
|
|
89
|
+
"react": "^19.0.0",
|
|
90
|
+
"react-dom": "^19.0.0",
|
|
91
|
+
"tsup": "^8.3.5",
|
|
92
|
+
"typescript": "^5.7.3",
|
|
93
|
+
"vitest": "^3.0.2",
|
|
94
|
+
"@elabs-ai/components-eslint-config": "0.1.0",
|
|
95
|
+
"@elabs-ai/components-typescript-config": "0.1.0",
|
|
96
|
+
"@elabs-ai/components-tokens": "4.0.0"
|
|
97
|
+
},
|
|
98
|
+
"scripts": {
|
|
99
|
+
"build": "rm -rf dist && tsup",
|
|
100
|
+
"typecheck": "tsc --noEmit",
|
|
101
|
+
"lint": "eslint .",
|
|
102
|
+
"test": "vitest run",
|
|
103
|
+
"test:watch": "vitest",
|
|
104
|
+
"clean": "rm -rf dist .turbo coverage"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/** sidebar-02 — dashboard sidebar (copy-owned block). Adapted from blocks.so
|
|
2
|
+
* (ephraim duncan). framer-motion removed (plain fade); next/link -> <a>. */
|
|
3
|
+
"use client";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Activity,
|
|
7
|
+
DollarSign,
|
|
8
|
+
Home,
|
|
9
|
+
Infinity as InfinityIcon,
|
|
10
|
+
Link as LinkIcon,
|
|
11
|
+
Package2,
|
|
12
|
+
Percent,
|
|
13
|
+
PieChart,
|
|
14
|
+
Settings,
|
|
15
|
+
ShoppingBag,
|
|
16
|
+
Sparkles,
|
|
17
|
+
Store,
|
|
18
|
+
TrendingUp,
|
|
19
|
+
Users,
|
|
20
|
+
} from "lucide-react";
|
|
21
|
+
import { AppSidebar, SidebarTrigger, cn, useSidebar } from "@elabs-ai/components-ui";
|
|
22
|
+
import { Logo } from "./logo";
|
|
23
|
+
import DashboardNavigation, { type Route } from "./nav-main";
|
|
24
|
+
import { NotificationsPopover } from "./nav-notifications";
|
|
25
|
+
import { TeamSwitcher } from "./team-switcher";
|
|
26
|
+
|
|
27
|
+
const sampleNotifications = [
|
|
28
|
+
{
|
|
29
|
+
id: "1",
|
|
30
|
+
fallback: "OM",
|
|
31
|
+
text: "New order received.",
|
|
32
|
+
time: "10m ago",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "2",
|
|
36
|
+
fallback: "JL",
|
|
37
|
+
text: "Server upgrade completed.",
|
|
38
|
+
time: "1h ago",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "3",
|
|
42
|
+
fallback: "HH",
|
|
43
|
+
text: "New user signed up.",
|
|
44
|
+
time: "2h ago",
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const dashboardRoutes: Route[] = [
|
|
49
|
+
{ id: "home", title: "Home", icon: <Home className="size-4" />, link: "#" },
|
|
50
|
+
{
|
|
51
|
+
id: "products",
|
|
52
|
+
title: "Products",
|
|
53
|
+
icon: <Package2 className="size-4" />,
|
|
54
|
+
link: "#",
|
|
55
|
+
subs: [
|
|
56
|
+
{ title: "Catalogue", link: "#" },
|
|
57
|
+
{ title: "Checkout Links", link: "#" },
|
|
58
|
+
{ title: "Discounts", link: "#" },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "usage-billing",
|
|
63
|
+
title: "Usage Billing",
|
|
64
|
+
icon: <PieChart className="size-4" />,
|
|
65
|
+
link: "#",
|
|
66
|
+
subs: [
|
|
67
|
+
{ title: "Meters", link: "#" },
|
|
68
|
+
{ title: "Events", link: "#" },
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{ id: "benefits", title: "Benefits", icon: <Sparkles className="size-4" />, link: "#" },
|
|
72
|
+
{ id: "customers", title: "Customers", icon: <Users className="size-4" />, link: "#" },
|
|
73
|
+
{
|
|
74
|
+
id: "sales",
|
|
75
|
+
title: "Sales",
|
|
76
|
+
icon: <ShoppingBag className="size-4" />,
|
|
77
|
+
link: "#",
|
|
78
|
+
subs: [
|
|
79
|
+
{ title: "Orders", link: "#" },
|
|
80
|
+
{ title: "Subscriptions", link: "#" },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{ id: "storefront", title: "Storefront", icon: <Store className="size-4" />, link: "#" },
|
|
84
|
+
{ id: "analytics", title: "Analytics", icon: <TrendingUp className="size-4" />, link: "#" },
|
|
85
|
+
{
|
|
86
|
+
id: "finance",
|
|
87
|
+
title: "Finance",
|
|
88
|
+
icon: <DollarSign className="size-4" />,
|
|
89
|
+
link: "#",
|
|
90
|
+
subs: [
|
|
91
|
+
{ title: "Incoming", link: "#" },
|
|
92
|
+
{ title: "Outgoing", link: "#" },
|
|
93
|
+
{ title: "Payout Account", link: "#" },
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: "settings",
|
|
98
|
+
title: "Settings",
|
|
99
|
+
icon: <Settings className="size-4" />,
|
|
100
|
+
link: "#",
|
|
101
|
+
subs: [
|
|
102
|
+
{ title: "General", link: "#" },
|
|
103
|
+
{ title: "Webhooks", link: "#" },
|
|
104
|
+
{ title: "Custom Fields", link: "#" },
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
// Reference icons retained for parity with the source data shape.
|
|
110
|
+
void Activity;
|
|
111
|
+
void InfinityIcon;
|
|
112
|
+
void LinkIcon;
|
|
113
|
+
void Percent;
|
|
114
|
+
|
|
115
|
+
const teams = [
|
|
116
|
+
{ name: "Alpha Inc.", logo: Logo, plan: "Free" },
|
|
117
|
+
{ name: "Beta Corp.", logo: Logo, plan: "Free" },
|
|
118
|
+
{ name: "Gamma Tech", logo: Logo, plan: "Free" },
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
export function DashboardSidebar() {
|
|
122
|
+
const { state } = useSidebar();
|
|
123
|
+
const isCollapsed = state === "collapsed";
|
|
124
|
+
|
|
125
|
+
const header = (
|
|
126
|
+
<div
|
|
127
|
+
className={cn(
|
|
128
|
+
"flex md:pt-3.5",
|
|
129
|
+
isCollapsed
|
|
130
|
+
? "flex-row items-center justify-between gap-y-4 md:flex-col md:items-start md:justify-start"
|
|
131
|
+
: "flex-row items-center justify-between",
|
|
132
|
+
)}
|
|
133
|
+
>
|
|
134
|
+
<a href="#" className="flex items-center gap-2">
|
|
135
|
+
<Logo className="h-8 w-8" />
|
|
136
|
+
{!isCollapsed && <span className="font-semibold text-foreground">Acme</span>}
|
|
137
|
+
</a>
|
|
138
|
+
<div
|
|
139
|
+
className={cn(
|
|
140
|
+
"flex items-center gap-2 animate-in fade-in",
|
|
141
|
+
isCollapsed ? "flex-row md:flex-col-reverse" : "flex-row",
|
|
142
|
+
)}
|
|
143
|
+
>
|
|
144
|
+
<NotificationsPopover notifications={sampleNotifications} />
|
|
145
|
+
<SidebarTrigger />
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<AppSidebar
|
|
152
|
+
variant="inset"
|
|
153
|
+
collapsible="icon"
|
|
154
|
+
header={header}
|
|
155
|
+
footer={<TeamSwitcher teams={teams} />}
|
|
156
|
+
>
|
|
157
|
+
<DashboardNavigation routes={dashboardRoutes} className="gap-4 px-2 py-4" />
|
|
158
|
+
</AppSidebar>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** sidebar-02 — Acme logo mark (copy-owned block). */
|
|
2
|
+
import type { SVGProps } from "react";
|
|
3
|
+
|
|
4
|
+
export const Logo = (props: SVGProps<SVGSVGElement>) => (
|
|
5
|
+
<svg fill="currentColor" height="48" viewBox="0 0 40 48" width="40" {...props}>
|
|
6
|
+
<clipPath id="acme-a">
|
|
7
|
+
<path d="m0 0h40v48h-40z" />
|
|
8
|
+
</clipPath>
|
|
9
|
+
<g clipPath="url(#acme-a)">
|
|
10
|
+
<path d="m25.0887 5.05386-3.933-1.05386-3.3145 12.3696-2.9923-11.16736-3.9331 1.05386 3.233 12.0655-8.05262-8.0526-2.87919 2.8792 8.83271 8.8328-10.99975-2.9474-1.05385625 3.933 12.01860625 3.2204c-.1376-.5935-.2104-1.2119-.2104-1.8473 0-4.4976 3.646-8.1436 8.1437-8.1436 4.4976 0 8.1436 3.646 8.1436 8.1436 0 .6313-.0719 1.2459-.2078 1.8359l10.9227 2.9267 1.0538-3.933-12.0664-3.2332 11.0005-2.9476-1.0539-3.933-12.0659 3.233 8.0526-8.0526-2.8792-2.87916-8.7102 8.71026z" />
|
|
11
|
+
<path d="m27.8723 26.2214c-.3372 1.4256-1.0491 2.7063-2.0259 3.7324l7.913 7.9131 2.8792-2.8792z" />
|
|
12
|
+
<path d="m25.7665 30.0366c-.9886 1.0097-2.2379 1.7632-3.6389 2.1515l2.8794 10.746 3.933-1.0539z" />
|
|
13
|
+
<path d="m21.9807 32.2274c-.65.1671-1.3313.2559-2.0334.2559-.7522 0-1.4806-.102-2.1721-.2929l-2.882 10.7558 3.933 1.0538z" />
|
|
14
|
+
<path d="m17.6361 32.1507c-1.3796-.4076-2.6067-1.1707-3.5751-2.1833l-7.9325 7.9325 2.87919 2.8792z" />
|
|
15
|
+
<path d="m13.9956 29.8973c-.9518-1.019-1.6451-2.2826-1.9751-3.6862l-10.95836 2.9363 1.05385 3.933z" />
|
|
16
|
+
</g>
|
|
17
|
+
</svg>
|
|
18
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sidebar-02 — primary navigation.
|
|
3
|
+
* Re-exports the shared `NavMain` primitive from `@elabs-ai/components-ui` so this block
|
|
4
|
+
* no longer maintains its own copy (issue #99).
|
|
5
|
+
*
|
|
6
|
+
* The block-local alias `DashboardNavigation` is preserved for back-compat
|
|
7
|
+
* so `app-sidebar.tsx` does not need to change its import name.
|
|
8
|
+
*/
|
|
9
|
+
export { NavMain as default, NavMain as DashboardNavigation } from "@elabs-ai/components-ui";
|
|
10
|
+
export type {
|
|
11
|
+
NavMainProps as DashboardNavigationProps,
|
|
12
|
+
NavMainRoute as Route,
|
|
13
|
+
} from "@elabs-ai/components-ui";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sidebar-02 — notifications popover.
|
|
3
|
+
* Re-exports the shared `NavNotifications` primitive from `@elabs-ai/components-ui` so this
|
|
4
|
+
* block no longer maintains its own copy (issue #99).
|
|
5
|
+
*/
|
|
6
|
+
export { NavNotifications as NotificationsPopover } from "@elabs-ai/components-ui";
|
|
7
|
+
export type { NavNotificationsProps, NavNotification } from "@elabs-ai/components-ui";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { SidebarInset, SidebarProvider } from "@elabs-ai/components-ui";
|
|
3
|
+
import { DashboardSidebar } from "./app-sidebar";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Layout/App Shell/Dashboard",
|
|
7
|
+
parameters: { layout: "fullscreen" },
|
|
8
|
+
} satisfies Meta;
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof meta>;
|
|
11
|
+
|
|
12
|
+
export const Default: Story = {
|
|
13
|
+
render: () => (
|
|
14
|
+
<SidebarProvider>
|
|
15
|
+
<div className="relative flex h-dvh w-full">
|
|
16
|
+
<DashboardSidebar />
|
|
17
|
+
<SidebarInset className="flex flex-col p-6 text-body text-muted-foreground">
|
|
18
|
+
Dashboard content area (collapsible icon sidebar — press ⌘/Ctrl+B).
|
|
19
|
+
</SidebarInset>
|
|
20
|
+
</div>
|
|
21
|
+
</SidebarProvider>
|
|
22
|
+
),
|
|
23
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sidebar-02 — team switcher.
|
|
3
|
+
* Re-exports the shared `TeamSwitcher` primitive from `@elabs-ai/components-ui` so this block
|
|
4
|
+
* no longer maintains its own copy (issue #99).
|
|
5
|
+
*/
|
|
6
|
+
export { TeamSwitcher } from "@elabs-ai/components-ui";
|
|
7
|
+
export type { TeamSwitcherProps, TeamSwitcherTeam } from "@elabs-ai/components-ui";
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/** sidebar-04 — double-sided mail sidebar (copy-owned block). Adapted from
|
|
2
|
+
* blocks.so (ephraim duncan). Tabler icons mapped to lucide. */
|
|
3
|
+
"use client";
|
|
4
|
+
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { Archive, Box, Clock, Flag, Inbox, Star } from "lucide-react";
|
|
7
|
+
import {
|
|
8
|
+
Sidebar,
|
|
9
|
+
SidebarContent,
|
|
10
|
+
SidebarFooter,
|
|
11
|
+
SidebarGroup,
|
|
12
|
+
SidebarGroupContent,
|
|
13
|
+
SidebarGroupLabel,
|
|
14
|
+
SidebarHeader,
|
|
15
|
+
SidebarInput,
|
|
16
|
+
SidebarMenu,
|
|
17
|
+
SidebarMenuButton,
|
|
18
|
+
SidebarMenuItem,
|
|
19
|
+
useSidebar,
|
|
20
|
+
} from "@elabs-ai/components-ui";
|
|
21
|
+
import { NavUser } from "@elabs-ai/components-ui";
|
|
22
|
+
import { useMail } from "./mail-context";
|
|
23
|
+
|
|
24
|
+
const data = {
|
|
25
|
+
user: { name: "ephraim", email: "ephraim@blocks.so", avatar: "" },
|
|
26
|
+
navMain: [
|
|
27
|
+
{ title: "Inbox", url: "#", icon: Inbox, isActive: true },
|
|
28
|
+
{ title: "Starred", url: "#", icon: Star, isActive: false },
|
|
29
|
+
{ title: "Important", url: "#", icon: Flag, isActive: false },
|
|
30
|
+
{ title: "Scheduled", url: "#", icon: Clock, isActive: false },
|
|
31
|
+
{ title: "Archive", url: "#", icon: Archive, isActive: false },
|
|
32
|
+
],
|
|
33
|
+
labels: [
|
|
34
|
+
{ title: "Personal", color: "bg-green-400 dark:bg-green-300" },
|
|
35
|
+
{ title: "Work", color: "bg-blue-400 dark:bg-blue-300" },
|
|
36
|
+
{ title: "Travel", color: "bg-orange-400 dark:bg-orange-300" },
|
|
37
|
+
{ title: "Receipts", color: "bg-purple-400 dark:bg-purple-300" },
|
|
38
|
+
],
|
|
39
|
+
mails: [
|
|
40
|
+
{
|
|
41
|
+
name: "Nora Patel",
|
|
42
|
+
email: "nora@acme.co",
|
|
43
|
+
subject: "Welcome to Acme Mail",
|
|
44
|
+
date: "08:15 AM",
|
|
45
|
+
teaser:
|
|
46
|
+
"Hi there — here's a quick tour of your new inbox.\nPin, label, and schedule messages to stay organized.",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "Stripe",
|
|
50
|
+
email: "no-reply@stripe.com",
|
|
51
|
+
subject: "Your payout has arrived",
|
|
52
|
+
date: "Yesterday",
|
|
53
|
+
teaser:
|
|
54
|
+
"A payout of $3,245.90 was sent to your bank account.\nView details in your dashboard.",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "GitHub",
|
|
58
|
+
email: "noreply@github.com",
|
|
59
|
+
subject: "New activity on acme/app",
|
|
60
|
+
date: "Tue",
|
|
61
|
+
teaser:
|
|
62
|
+
"3 pull requests need your review. CI passed on main.\nClick to open the review queue.",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "Ava Chen",
|
|
66
|
+
email: "ava.chen@example.com",
|
|
67
|
+
subject: "Agenda for Friday standup",
|
|
68
|
+
date: "Mon",
|
|
69
|
+
teaser:
|
|
70
|
+
"Let's cover onboarding, billing bugs, and Q4 goals.\nReply with anything you want to add.",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "Figma",
|
|
74
|
+
email: "updates@figma.com",
|
|
75
|
+
subject: "What's new in Figma",
|
|
76
|
+
date: "Sep 12",
|
|
77
|
+
teaser:
|
|
78
|
+
"Variables, auto layout improvements, and dev mode updates.\nWatch the recap to learn more.",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "Linear",
|
|
82
|
+
email: "bot@linear.app",
|
|
83
|
+
subject: "[ACME-432] Edit modal broken",
|
|
84
|
+
date: "Sep 11",
|
|
85
|
+
teaser: "Issue created by Wendy. Repro steps included.\nSeverity: high, priority: P1.",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "Airbnb",
|
|
89
|
+
email: "booking@airbnb.com",
|
|
90
|
+
subject: "Your trip to Kyoto",
|
|
91
|
+
date: "Sep 10",
|
|
92
|
+
teaser: "Get ready for your stay. Check-in details and local recommendations inside.",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "Notion",
|
|
96
|
+
email: "team@notion.so",
|
|
97
|
+
subject: "Weekly team recap",
|
|
98
|
+
date: "Sep 09",
|
|
99
|
+
teaser:
|
|
100
|
+
"Marketing shipped pricing page revamp. Eng closed 14 issues.\nSee full notes in the doc.",
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
|
106
|
+
const [activeItem, setActiveItem] = React.useState(data.navMain[0]);
|
|
107
|
+
const [mails, setMails] = React.useState(data.mails);
|
|
108
|
+
const [query, setQuery] = React.useState("");
|
|
109
|
+
const { setOpen } = useSidebar();
|
|
110
|
+
const { setSelectedMail } = useMail();
|
|
111
|
+
|
|
112
|
+
const filteredMails = React.useMemo(() => {
|
|
113
|
+
const q = query.trim().toLowerCase();
|
|
114
|
+
if (!q) return mails;
|
|
115
|
+
return mails.filter((m) =>
|
|
116
|
+
[m.name, m.email, m.subject, m.teaser].join("\n").toLowerCase().includes(q),
|
|
117
|
+
);
|
|
118
|
+
}, [mails, query]);
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className="flex" {...props}>
|
|
122
|
+
{/* Icon rail */}
|
|
123
|
+
<Sidebar
|
|
124
|
+
style={{ "--sidebar-width": "12rem" } as React.CSSProperties}
|
|
125
|
+
collapsible="none"
|
|
126
|
+
className="border-e p-2 px-1"
|
|
127
|
+
>
|
|
128
|
+
<SidebarHeader>
|
|
129
|
+
<SidebarMenu>
|
|
130
|
+
<SidebarMenuItem>
|
|
131
|
+
<SidebarMenuButton size="lg" asChild className="md:h-8 md:p-0">
|
|
132
|
+
<a href="#">
|
|
133
|
+
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-accent text-sidebar-accent-foreground">
|
|
134
|
+
<Box className="size-4" />
|
|
135
|
+
</div>
|
|
136
|
+
<div className="grid flex-1 text-start text-body leading-tight">
|
|
137
|
+
<span className="truncate font-medium">Acme Inc</span>
|
|
138
|
+
<span className="truncate text-meta">Enterprise</span>
|
|
139
|
+
</div>
|
|
140
|
+
</a>
|
|
141
|
+
</SidebarMenuButton>
|
|
142
|
+
</SidebarMenuItem>
|
|
143
|
+
</SidebarMenu>
|
|
144
|
+
</SidebarHeader>
|
|
145
|
+
<SidebarContent>
|
|
146
|
+
<SidebarGroup>
|
|
147
|
+
<SidebarGroupContent className="px-1.5 md:px-0">
|
|
148
|
+
<SidebarMenu>
|
|
149
|
+
{data.navMain.map((item) => (
|
|
150
|
+
<SidebarMenuItem key={item.title}>
|
|
151
|
+
<SidebarMenuButton
|
|
152
|
+
onClick={() => {
|
|
153
|
+
setActiveItem(item);
|
|
154
|
+
const shuffled = [...data.mails].sort(() => Math.random() - 0.5);
|
|
155
|
+
setMails(shuffled.slice(0, Math.max(5, Math.floor(Math.random() * 8) + 1)));
|
|
156
|
+
setOpen(true);
|
|
157
|
+
}}
|
|
158
|
+
isActive={activeItem?.title === item.title}
|
|
159
|
+
className="px-2.5 md:px-2"
|
|
160
|
+
>
|
|
161
|
+
<item.icon />
|
|
162
|
+
<span>{item.title}</span>
|
|
163
|
+
</SidebarMenuButton>
|
|
164
|
+
</SidebarMenuItem>
|
|
165
|
+
))}
|
|
166
|
+
</SidebarMenu>
|
|
167
|
+
</SidebarGroupContent>
|
|
168
|
+
</SidebarGroup>
|
|
169
|
+
<SidebarGroup>
|
|
170
|
+
<SidebarGroupLabel className="px-1.5 text-meta md:px-0">Labels</SidebarGroupLabel>
|
|
171
|
+
<SidebarGroupContent className="px-1.5 md:px-0">
|
|
172
|
+
<SidebarMenu>
|
|
173
|
+
{data.labels.map((label) => (
|
|
174
|
+
<SidebarMenuItem key={label.title}>
|
|
175
|
+
<SidebarMenuButton asChild className="px-2.5 md:px-2">
|
|
176
|
+
<div className="flex items-center gap-3">
|
|
177
|
+
<div className={`h-3 w-3 rounded ${label.color}`} />
|
|
178
|
+
<span>{label.title}</span>
|
|
179
|
+
</div>
|
|
180
|
+
</SidebarMenuButton>
|
|
181
|
+
</SidebarMenuItem>
|
|
182
|
+
))}
|
|
183
|
+
</SidebarMenu>
|
|
184
|
+
</SidebarGroupContent>
|
|
185
|
+
</SidebarGroup>
|
|
186
|
+
</SidebarContent>
|
|
187
|
+
<SidebarFooter>
|
|
188
|
+
<NavUser user={data.user} />
|
|
189
|
+
</SidebarFooter>
|
|
190
|
+
</Sidebar>
|
|
191
|
+
|
|
192
|
+
{/* Mail list */}
|
|
193
|
+
<Sidebar collapsible="none" className="hidden min-w-96 flex-1 border-e md:flex">
|
|
194
|
+
<SidebarHeader className="gap-3.5 border-b p-4">
|
|
195
|
+
<div className="flex w-full items-center justify-between">
|
|
196
|
+
<div className="text-subtitle font-medium text-foreground">{activeItem?.title}</div>
|
|
197
|
+
</div>
|
|
198
|
+
<SidebarInput
|
|
199
|
+
placeholder="Type to search..."
|
|
200
|
+
value={query}
|
|
201
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
202
|
+
/>
|
|
203
|
+
</SidebarHeader>
|
|
204
|
+
<SidebarContent>
|
|
205
|
+
<SidebarGroup className="px-0 pt-0">
|
|
206
|
+
<SidebarGroupContent>
|
|
207
|
+
{filteredMails.length === 0 && (
|
|
208
|
+
<div className="p-4 text-body text-muted-foreground">No results</div>
|
|
209
|
+
)}
|
|
210
|
+
{filteredMails.map((mail) => (
|
|
211
|
+
<a
|
|
212
|
+
href="#"
|
|
213
|
+
key={mail.email}
|
|
214
|
+
onClick={(e) => {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
setSelectedMail(mail);
|
|
217
|
+
}}
|
|
218
|
+
className="flex flex-col items-start gap-2 whitespace-nowrap border-b p-4 text-body leading-tight hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
|
219
|
+
>
|
|
220
|
+
<div className="flex w-full items-center gap-2">
|
|
221
|
+
<span>{mail.name}</span>
|
|
222
|
+
<span className="ms-auto text-meta">{mail.date}</span>
|
|
223
|
+
</div>
|
|
224
|
+
<span className="font-medium">{mail.subject}</span>
|
|
225
|
+
<span className="line-clamp-2 w-[260px] whitespace-break-spaces text-meta">
|
|
226
|
+
{mail.teaser}
|
|
227
|
+
</span>
|
|
228
|
+
</a>
|
|
229
|
+
))}
|
|
230
|
+
</SidebarGroupContent>
|
|
231
|
+
</SidebarGroup>
|
|
232
|
+
</SidebarContent>
|
|
233
|
+
</Sidebar>
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** sidebar-04 — mail selection context (copy-owned block). */
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
export type Mail = {
|
|
7
|
+
name: string;
|
|
8
|
+
email: string;
|
|
9
|
+
subject: string;
|
|
10
|
+
date: string;
|
|
11
|
+
teaser: string;
|
|
12
|
+
labels?: string[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type MailContextValue = { selectedMail: Mail | null; setSelectedMail: (mail: Mail | null) => void };
|
|
16
|
+
|
|
17
|
+
const MailContext = React.createContext<MailContextValue | undefined>(undefined);
|
|
18
|
+
|
|
19
|
+
export function MailProvider({ children }: { children: React.ReactNode }) {
|
|
20
|
+
const [selectedMail, setSelectedMail] = React.useState<Mail | null>(null);
|
|
21
|
+
const value = React.useMemo(() => ({ selectedMail, setSelectedMail }), [selectedMail]);
|
|
22
|
+
return <MailContext.Provider value={value}>{children}</MailContext.Provider>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useMail() {
|
|
26
|
+
const ctx = React.useContext(MailContext);
|
|
27
|
+
if (!ctx) throw new Error("useMail must be used within MailProvider");
|
|
28
|
+
return ctx;
|
|
29
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sidebar-04 — account menu. The shared `NavUser` nav primitive lives in
|
|
3
|
+
* `@elabs-ai/components-ui` (#99); this block re-exports it rather than forking a local copy
|
|
4
|
+
* (which drifts). The block's `app-sidebar.tsx` already imports it from `@elabs-ai/components-ui`.
|
|
5
|
+
*/
|
|
6
|
+
export { NavUser } from "@elabs-ai/components-ui";
|