From b8243e06d8e0d0eeeee74b884309bc42777fa03e Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Thu, 23 May 2024 17:39:56 +0800 Subject: [PATCH] Feat/design system site (#26586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * init site * add nav menu * add props table component * init all the examples • also includes moving a bunch of ./ui files to ./ui-patterns * update package • might need to remove some of these * Update rehype-component.ts * move nav * more changes * add new source information to contentlayer * fix copy buttons * add text-confirm. start new concept of "fragments" * move base path. add homepage. add theme selection * added colors * add form-item-layout * temporary fix code blocks in light mode. they currently don't switch theme to theme * start adding code themes * Update dark.json * update code block themes * fix animations * add cdmk search * export registry of icons in ./icons package * add comments * add icon copy stuff * Update icons.tsx * more docs * more docs. cleaned up colors and icons docs * Update theming.mdx * add more docs * update * add package * Update tailwind.config.js * update content * Update drawer-demo.tsx * Update aspect-ratio-demo.tsx * add new blocks * Update source-panel.tsx * Update source-panel.tsx * Update source-panel.tsx * add new source block * Update source-panel.tsx * Update _app.tsx * Update page.tsx * Delete layout-old.tsx * remove old themes * remove old ui registry * comment out nav items * Update package-lock.json * Update AssistantChatForm.tsx * move back * move again * update * Update index.tsx * Update package-lock.json * Update package-lock.json * Update package-lock.json * update package * udpate prettier * fix tag issues * Update package-lock.json * update to contentlayer2 * update package-lock.json * fix type errors * ignore spelling * Update avoid-typos.yml * Update avoid-typos.yml * Update package-lock.json * Use ui type definitions. * move tsconfig base stuff. fix content layer issue * Update package-lock.json * Update package-lock.json --------- Co-authored-by: Alaister Young Co-authored-by: Ivan Vasilov --- .prettierignore | 1 + apps/design-system/.eslintrc.json | 3 + apps/design-system/.gitignore | 38 + apps/design-system/README.md | 36 + apps/design-system/__registry__/index.tsx | 1593 ++++++ .../app/(app)/docs/[[...slug]]/page.tsx | 119 + apps/design-system/app/(app)/layout.tsx | 35 + apps/design-system/app/(app)/page.tsx | 113 + apps/design-system/app/Providers.tsx | 18 + apps/design-system/app/favicon.ico | Bin 0 -> 25931 bytes apps/design-system/app/globals.css | 29 + apps/design-system/app/layout.tsx | 38 + apps/design-system/components/callout.tsx | 17 + apps/design-system/components/class-label.tsx | 18 + .../components/click-counter.tsx | 16 + .../components/code-block-wrapper.tsx | 53 + .../components/code-fragment.tsx | 107 + apps/design-system/components/colors.tsx | 155 + .../design-system/components/command-menu.tsx | 132 + .../components/component-example.tsx | 97 + .../components/component-preview.tsx | 260 + .../components/component-props.tsx | 58 + .../components/component-source.tsx | 21 + apps/design-system/components/copy-button.tsx | 179 + .../components/design-system-marks.tsx | 19 + .../components/example-label.tsx | 15 + apps/design-system/components/grid.tsx | 62 + .../components/homepage-svg-handler.tsx | 19 + apps/design-system/components/icons.tsx | 70 + .../components/mdx-components.tsx | 291 ++ apps/design-system/components/pager.tsx | 72 + .../components/side-navigation-item.tsx | 43 + .../components/side-navigation.tsx | 21 + apps/design-system/components/site-footer.tsx | 61 + .../design-system/components/source-panel.tsx | 206 + .../components/style-wrapper.tsx | 20 + .../components/theme-settings.tsx | 54 + .../components/theme-switcher-dropdown.tsx | 92 + apps/design-system/components/toc.tsx | 107 + .../components/top-navigation-search.tsx | 17 + .../components/top-navigation.tsx | 38 + apps/design-system/config/docs.ts | 335 ++ apps/design-system/config/site.ts | 17 + apps/design-system/content/docs/changelog.mdx | 31 + .../content/docs/color-usage.mdx | 74 + .../content/docs/components/accordion.mdx | 139 + .../content/docs/components/alert copy.mdx | 65 + .../content/docs/components/alert-dialog.mdx | 87 + .../content/docs/components/alert.mdx | 79 + .../content/docs/components/aspect-ratio.mdx | 67 + .../content/docs/components/avatar.mdx | 64 + .../content/docs/components/badge.mdx | 87 + .../content/docs/components/breadcrumb.mdx | 190 + .../content/docs/components/button.mdx | 118 + .../content/docs/components/calendar.mdx | 81 + .../content/docs/components/card.mdx | 71 + .../content/docs/components/carousel.mdx | 277 + .../content/docs/components/checkbox.mdx | 77 + .../content/docs/components/collapsible.mdx | 67 + .../content/docs/components/combobox.mdx | 131 + .../content/docs/components/command.mdx | 138 + .../content/docs/components/context-menu.mdx | 74 + .../content/docs/components/data-table.mdx | 842 +++ .../content/docs/components/date-picker.mdx | 74 + .../content/docs/components/dialog.mdx | 120 + .../content/docs/components/drawer.mdx | 95 + .../content/docs/components/dropdown-menu.mdx | 95 + .../content/docs/components/form.mdx | 255 + .../content/docs/components/hover-card.mdx | 64 + .../content/docs/components/input-otp.mdx | 191 + .../content/docs/components/input.mdx | 77 + .../content/docs/components/label.mdx | 61 + .../content/docs/components/menubar.mdx | 83 + .../docs/components/navigation-menu.mdx | 99 + .../content/docs/components/pagination.mdx | 104 + .../content/docs/components/popover.mdx | 64 + .../content/docs/components/progress.mdx | 61 + .../content/docs/components/radio-group.mdx | 77 + .../content/docs/components/resizable.mdx | 110 + .../content/docs/components/scroll-area.mdx | 73 + .../content/docs/components/select.mdx | 87 + .../content/docs/components/separator.mdx | 59 + .../content/docs/components/sheet.mdx | 106 + .../content/docs/components/skeleton.mdx | 57 + .../content/docs/components/slider.mdx | 61 + .../content/docs/components/sonner.mdx | 103 + .../content/docs/components/switch.mdx | 67 + .../content/docs/components/table.mdx | 85 + .../content/docs/components/tabs.mdx | 68 + .../content/docs/components/textarea.mdx | 77 + .../content/docs/components/toast.mdx | 155 + .../content/docs/components/toggle-group.mdx | 91 + .../content/docs/components/toggle.mdx | 87 + .../content/docs/components/tooltip.mdx | 68 + .../content/docs/components/typography.mdx | 61 + apps/design-system/content/docs/figma.mdx | 28 + .../docs/fragments/form-item-layout.mdx | 88 + .../docs/fragments/text-confirm-dialog.mdx | 57 + apps/design-system/content/docs/icons.mdx | 6 + apps/design-system/content/docs/index.mdx | 24 + .../content/docs/tailwind-classes.mdx | 194 + apps/design-system/content/docs/theming.mdx | 30 + apps/design-system/contentlayer.config.js | 201 + apps/design-system/hooks/use-config.ts | 24 + apps/design-system/hooks/use-media-query.tsx | 19 + apps/design-system/hooks/use-mounted.ts | 11 + apps/design-system/lib/rehype-component.ts | 406 ++ apps/design-system/lib/rehype-npm-command.ts | 42 + apps/design-system/lib/sample-component.tsx | 27 + apps/design-system/lib/themes/supabase-2.json | 207 + apps/design-system/lib/toc.ts | 79 + apps/design-system/lib/utils.ts | 20 + apps/design-system/next.config.mjs | 21 + apps/design-system/package.json | 59 + apps/design-system/postcss.config.cjs | 6 + .../atoms-illustration--deep-dark.svg | 100 + .../atoms-illustration--light.svg | 100 + .../design-system-marks--dark.svg | 61 + .../design-system-marks--light.svg | 61 + .../fragments-illustration--deep-dark.svg | 104 + .../fragments-illustration--light.svg | 104 + apps/design-system/public/img/themes/dark.svg | 39 + .../public/img/themes/deep-dark.svg | 39 + .../design-system/public/img/themes/light.svg | 39 + .../public/img/themes/system.svg | 62 + apps/design-system/public/next.svg | 1 + apps/design-system/public/vercel.svg | 1 + apps/design-system/registry/.eslintrc.json | 6 + apps/design-system/registry/colors.ts | 1556 ++++++ .../default/example/accordion-demo.tsx | 31 + .../registry/default/example/alert-demo.tsx | 15 + .../default/example/alert-destructive.tsx | 15 + .../default/example/alert-dialog-demo.tsx | 35 + .../default/example/aspect-ratio-demo.tsx | 16 + .../registry/default/example/avatar-demo.tsx | 10 + .../registry/default/example/badge-demo.tsx | 5 + .../default/example/badge-destructive.tsx | 5 + .../default/example/badge-outline.tsx | 5 + .../default/example/badge-secondary.tsx | 5 + .../default/example/button-as-child.tsx | 11 + .../registry/default/example/button-demo.tsx | 5 + .../default/example/button-destructive.tsx | 5 + .../registry/default/example/button-ghost.tsx | 5 + .../registry/default/example/button-icon.tsx | 7 + .../registry/default/example/button-link.tsx | 5 + .../default/example/button-loading.tsx | 9 + .../default/example/button-outline.tsx | 5 + .../default/example/button-secondary.tsx | 5 + .../default/example/button-with-icon.tsx | 7 + .../default/example/calendar-demo.tsx | 11 + .../default/example/calendar-form.tsx | 92 + .../example/calendar-react-hook-form.tsx | 91 + .../default/example/checkbox-demo.tsx | 17 + .../default/example/checkbox-disabled.tsx | 15 + .../example/checkbox-form-multiple.tsx | 121 + .../default/example/checkbox-form-single.tsx | 69 + .../default/example/checkbox-with-text.tsx | 22 + .../default/example/collapsible-demo.tsx | 30 + .../color-usage-surface-studio-frame.tsx | 50 + .../example/color-usage-surface-studio.tsx | 36 + .../color-usage-surface-www-and-docs.tsx | 19 + .../default/example/combobox-demo.tsx | 88 + .../example/combobox-dropdown-menu.tsx | 109 + .../default/example/combobox-form.tsx | 135 + .../default/example/combobox-popover.tsx | 116 + .../default/example/combobox-responsive.tsx | 116 + .../registry/default/example/command-demo.tsx | 55 + .../default/example/command-dialog.tsx | 80 + .../default/example/context-menu-demo.tsx | 65 + .../default/example/date-picker-demo.tsx | 34 + .../default/example/date-picker-form.tsx | 91 + .../example/date-picker-with-presets.tsx | 54 + .../example/date-picker-with-range.tsx | 58 + .../default/example/dialog-close-button.tsx | 54 + .../registry/default/example/dialog-demo.tsx | 47 + .../registry/default/example/drawer-demo.tsx | 132 + .../default/example/drawer-dialog.tsx | 87 + .../example/dropdown-menu-checkboxes.tsx | 47 + .../default/example/dropdown-menu-demo.tsx | 122 + .../example/dropdown-menu-radio-group.tsx | 35 + .../default/example/form-item-layout-demo.tsx | 54 + .../form-item-layout-with-checkbox-list.tsx | 107 + .../form-item-layout-with-checkbox.tsx | 55 + .../form-item-layout-with-horizontal.tsx | 58 + .../example/form-item-layout-with-select.tsx | 71 + .../example/form-item-layout-with-switch.tsx | 49 + .../default/example/hover-card-demo.tsx | 31 + .../registry/default/example/input-demo.tsx | 5 + .../default/example/input-disabled.tsx | 5 + .../registry/default/example/input-file.tsx | 10 + .../registry/default/example/input-form.tsx | 68 + .../default/example/input-otp-controlled.tsx | 27 + .../default/example/input-otp-demo.tsx | 19 + .../default/example/input-otp-form.tsx | 78 + .../default/example/input-otp-pattern.tsx | 18 + .../default/example/input-otp-separator.tsx | 24 + .../default/example/input-with-button.tsx | 13 + .../default/example/input-with-label.tsx | 10 + .../default/example/input-with-text.tsx | 11 + .../registry/default/example/label-demo.tsx | 12 + .../registry/default/example/menubar-demo.tsx | 105 + .../registry/default/example/mode-toggle.tsx | 29 + .../default/example/navigation-menu-demo.tsx | 135 + .../registry/default/example/popover-demo.tsx | 40 + .../default/example/progress-demo.tsx | 16 + .../default/example/radio-group-demo.tsx | 21 + .../default/example/radio-group-form.tsx | 86 + .../example/resizable-demo-with-handle.tsx | 29 + .../default/example/resizable-demo.tsx | 29 + .../default/example/resizable-handle.tsx | 22 + .../default/example/resizable-vertical.tsx | 19 + .../default/example/scroll-area-demo.tsx | 24 + .../example/scroll-area-horizontal-demo.tsx | 50 + .../registry/default/example/select-demo.tsx | 31 + .../registry/default/example/select-form.tsx | 86 + .../default/example/select-scrollable.tsx | 71 + .../default/example/separator-demo.tsx | 20 + .../registry/default/example/sheet-demo.tsx | 50 + .../registry/default/example/sheet-side.tsx | 62 + .../default/example/skeleton-card.tsx | 13 + .../default/example/skeleton-demo.tsx | 13 + .../registry/default/example/slider-demo.tsx | 16 + .../registry/default/example/switch-demo.tsx | 11 + .../registry/default/example/switch-form.tsx | 96 + .../registry/default/example/table-demo.tsx | 87 + .../registry/default/example/tabs-demo.tsx | 69 + .../example/text-confirm-dialog-demo.tsx | 49 + ...text-confirm-dialog-with-cancel-button.tsx | 50 + .../text-confirm-dialog-with-children.tsx | 71 + ...-confirm-dialog-with-destructive-alert.tsx | 53 + .../text-confirm-dialog-with-info-alert.tsx | 53 + .../example/text-confirm-dialog-with-size.tsx | 50 + ...text-confirm-dialog-with-warning-alert.tsx | 53 + .../default/example/textarea-demo.tsx | 5 + .../default/example/textarea-disabled.tsx | 5 + .../default/example/textarea-form.tsx | 76 + .../default/example/textarea-with-button.tsx | 11 + .../default/example/textarea-with-label.tsx | 11 + .../default/example/textarea-with-text.tsx | 14 + .../registry/default/example/toast-demo.tsx | 24 + .../default/example/toast-destructive.tsx | 25 + .../registry/default/example/toast-simple.tsx | 21 + .../default/example/toast-with-action.tsx | 24 + .../default/example/toast-with-title.tsx | 22 + .../registry/default/example/toggle-demo.tsx | 11 + .../default/example/toggle-disabled.tsx | 11 + .../default/example/toggle-group-demo.tsx | 19 + .../default/example/toggle-group-disabled.tsx | 19 + .../default/example/toggle-group-lg.tsx | 19 + .../default/example/toggle-group-outline.tsx | 19 + .../default/example/toggle-group-single.tsx | 19 + .../default/example/toggle-group-sm.tsx | 19 + .../registry/default/example/toggle-lg.tsx | 11 + .../default/example/toggle-outline.tsx | 10 + .../registry/default/example/toggle-sm.tsx | 11 + .../default/example/toggle-with-text.tsx | 12 + .../registry/default/example/tooltip-demo.tsx | 22 + .../default/example/typography-blockquote.tsx | 8 + .../default/example/typography-demo.tsx | 109 + .../default/example/typography-h1.tsx | 7 + .../default/example/typography-h2.tsx | 7 + .../default/example/typography-h3.tsx | 3 + .../default/example/typography-h4.tsx | 7 + .../example/typography-inline-code.tsx | 7 + .../default/example/typography-large.tsx | 3 + .../default/example/typography-lead.tsx | 7 + .../default/example/typography-list.tsx | 9 + .../default/example/typography-muted.tsx | 3 + .../registry/default/example/typography-p.tsx | 8 + .../default/example/typography-small.tsx | 3 + .../default/example/typography-table.tsx | 44 + apps/design-system/registry/examples.ts | 931 ++++ apps/design-system/registry/fragments.ts | 22 + apps/design-system/registry/registry.ts | 5 + apps/design-system/registry/schema.ts | 68 + apps/design-system/registry/styles.ts | 12 + apps/design-system/registry/themes.ts | 636 +++ apps/design-system/scripts/build-registry.mts | 625 +++ .../styles/code-block-variables.css | 35 + apps/design-system/styles/globals.css | 97 + apps/design-system/styles/mdx.css | 85 + apps/design-system/tailwind.config.js | 20 + apps/design-system/tsconfig.json | 40 + apps/design-system/tsconfig.scripts.json | 13 + apps/design-system/types/nav.ts | 18 + apps/design-system/types/unist.ts | 31 + apps/docs/pages/_app.tsx | 3 +- package-lock.json | 4644 +++++++++++++++-- .../src/building/generateIconFiles.mjs | 79 +- packages/build-icons/src/main.mjs | 2 + packages/config/tailwind.config.js | 20 +- packages/config/ui.config.js | 12 +- packages/icons/__registry__/index.tsx | 197 + .../AssistantChat/AssistantChatForm.tsx | 7 +- .../ui-patterns/Dialogs/ConfirmationModal.tsx | 2 +- .../ui-patterns/Dialogs/TextConfirmModal.tsx | 4 +- .../PromoToast/PromoBg.tsx | 2 +- .../PromoToast/PromoToast.tsx | 5 +- .../PromoToast/index.ts | 0 .../FormItemLayout/FormItemLayout.stories.tsx | 4 - packages/ui-patterns/form/FormLayout.tsx | 6 +- packages/ui-patterns/form/FormLayout2.tsx | 6 +- packages/ui/index.tsx | 54 +- packages/ui/package.json | 2 + packages/ui/src/components/Select/Select.tsx | 1 + .../src/components/shadcn/ui/alert-dialog.tsx | 10 +- .../ui/src/components/shadcn/ui/avatar.tsx | 2 +- .../ui/src/components/shadcn/ui/command.tsx | 5 +- .../ui/src/components/shadcn/ui/dialog.tsx | 2 +- .../ui/src/components/shadcn/ui/drawer.tsx | 98 + .../src/components/shadcn/ui/scroll-area.tsx | 2 +- .../components/shadcn/ui/{tabs => }/tabs.tsx | 2 +- .../src/components/shadcn/ui/toggle-group.tsx | 55 + 313 files changed, 27023 insertions(+), 355 deletions(-) create mode 100644 apps/design-system/.eslintrc.json create mode 100644 apps/design-system/.gitignore create mode 100644 apps/design-system/README.md create mode 100644 apps/design-system/__registry__/index.tsx create mode 100644 apps/design-system/app/(app)/docs/[[...slug]]/page.tsx create mode 100644 apps/design-system/app/(app)/layout.tsx create mode 100644 apps/design-system/app/(app)/page.tsx create mode 100644 apps/design-system/app/Providers.tsx create mode 100644 apps/design-system/app/favicon.ico create mode 100644 apps/design-system/app/globals.css create mode 100644 apps/design-system/app/layout.tsx create mode 100644 apps/design-system/components/callout.tsx create mode 100644 apps/design-system/components/class-label.tsx create mode 100644 apps/design-system/components/click-counter.tsx create mode 100644 apps/design-system/components/code-block-wrapper.tsx create mode 100644 apps/design-system/components/code-fragment.tsx create mode 100644 apps/design-system/components/colors.tsx create mode 100644 apps/design-system/components/command-menu.tsx create mode 100644 apps/design-system/components/component-example.tsx create mode 100644 apps/design-system/components/component-preview.tsx create mode 100644 apps/design-system/components/component-props.tsx create mode 100644 apps/design-system/components/component-source.tsx create mode 100644 apps/design-system/components/copy-button.tsx create mode 100644 apps/design-system/components/design-system-marks.tsx create mode 100644 apps/design-system/components/example-label.tsx create mode 100644 apps/design-system/components/grid.tsx create mode 100644 apps/design-system/components/homepage-svg-handler.tsx create mode 100644 apps/design-system/components/icons.tsx create mode 100644 apps/design-system/components/mdx-components.tsx create mode 100644 apps/design-system/components/pager.tsx create mode 100644 apps/design-system/components/side-navigation-item.tsx create mode 100644 apps/design-system/components/side-navigation.tsx create mode 100644 apps/design-system/components/site-footer.tsx create mode 100644 apps/design-system/components/source-panel.tsx create mode 100644 apps/design-system/components/style-wrapper.tsx create mode 100644 apps/design-system/components/theme-settings.tsx create mode 100644 apps/design-system/components/theme-switcher-dropdown.tsx create mode 100644 apps/design-system/components/toc.tsx create mode 100644 apps/design-system/components/top-navigation-search.tsx create mode 100644 apps/design-system/components/top-navigation.tsx create mode 100644 apps/design-system/config/docs.ts create mode 100644 apps/design-system/config/site.ts create mode 100644 apps/design-system/content/docs/changelog.mdx create mode 100644 apps/design-system/content/docs/color-usage.mdx create mode 100644 apps/design-system/content/docs/components/accordion.mdx create mode 100644 apps/design-system/content/docs/components/alert copy.mdx create mode 100644 apps/design-system/content/docs/components/alert-dialog.mdx create mode 100644 apps/design-system/content/docs/components/alert.mdx create mode 100644 apps/design-system/content/docs/components/aspect-ratio.mdx create mode 100644 apps/design-system/content/docs/components/avatar.mdx create mode 100644 apps/design-system/content/docs/components/badge.mdx create mode 100644 apps/design-system/content/docs/components/breadcrumb.mdx create mode 100644 apps/design-system/content/docs/components/button.mdx create mode 100644 apps/design-system/content/docs/components/calendar.mdx create mode 100644 apps/design-system/content/docs/components/card.mdx create mode 100644 apps/design-system/content/docs/components/carousel.mdx create mode 100644 apps/design-system/content/docs/components/checkbox.mdx create mode 100644 apps/design-system/content/docs/components/collapsible.mdx create mode 100644 apps/design-system/content/docs/components/combobox.mdx create mode 100644 apps/design-system/content/docs/components/command.mdx create mode 100644 apps/design-system/content/docs/components/context-menu.mdx create mode 100644 apps/design-system/content/docs/components/data-table.mdx create mode 100644 apps/design-system/content/docs/components/date-picker.mdx create mode 100644 apps/design-system/content/docs/components/dialog.mdx create mode 100644 apps/design-system/content/docs/components/drawer.mdx create mode 100644 apps/design-system/content/docs/components/dropdown-menu.mdx create mode 100644 apps/design-system/content/docs/components/form.mdx create mode 100644 apps/design-system/content/docs/components/hover-card.mdx create mode 100644 apps/design-system/content/docs/components/input-otp.mdx create mode 100644 apps/design-system/content/docs/components/input.mdx create mode 100644 apps/design-system/content/docs/components/label.mdx create mode 100644 apps/design-system/content/docs/components/menubar.mdx create mode 100644 apps/design-system/content/docs/components/navigation-menu.mdx create mode 100644 apps/design-system/content/docs/components/pagination.mdx create mode 100644 apps/design-system/content/docs/components/popover.mdx create mode 100644 apps/design-system/content/docs/components/progress.mdx create mode 100644 apps/design-system/content/docs/components/radio-group.mdx create mode 100644 apps/design-system/content/docs/components/resizable.mdx create mode 100644 apps/design-system/content/docs/components/scroll-area.mdx create mode 100644 apps/design-system/content/docs/components/select.mdx create mode 100644 apps/design-system/content/docs/components/separator.mdx create mode 100644 apps/design-system/content/docs/components/sheet.mdx create mode 100644 apps/design-system/content/docs/components/skeleton.mdx create mode 100644 apps/design-system/content/docs/components/slider.mdx create mode 100644 apps/design-system/content/docs/components/sonner.mdx create mode 100644 apps/design-system/content/docs/components/switch.mdx create mode 100644 apps/design-system/content/docs/components/table.mdx create mode 100644 apps/design-system/content/docs/components/tabs.mdx create mode 100644 apps/design-system/content/docs/components/textarea.mdx create mode 100644 apps/design-system/content/docs/components/toast.mdx create mode 100644 apps/design-system/content/docs/components/toggle-group.mdx create mode 100644 apps/design-system/content/docs/components/toggle.mdx create mode 100644 apps/design-system/content/docs/components/tooltip.mdx create mode 100644 apps/design-system/content/docs/components/typography.mdx create mode 100644 apps/design-system/content/docs/figma.mdx create mode 100644 apps/design-system/content/docs/fragments/form-item-layout.mdx create mode 100644 apps/design-system/content/docs/fragments/text-confirm-dialog.mdx create mode 100644 apps/design-system/content/docs/icons.mdx create mode 100644 apps/design-system/content/docs/index.mdx create mode 100644 apps/design-system/content/docs/tailwind-classes.mdx create mode 100644 apps/design-system/content/docs/theming.mdx create mode 100644 apps/design-system/contentlayer.config.js create mode 100644 apps/design-system/hooks/use-config.ts create mode 100644 apps/design-system/hooks/use-media-query.tsx create mode 100644 apps/design-system/hooks/use-mounted.ts create mode 100644 apps/design-system/lib/rehype-component.ts create mode 100644 apps/design-system/lib/rehype-npm-command.ts create mode 100644 apps/design-system/lib/sample-component.tsx create mode 100644 apps/design-system/lib/themes/supabase-2.json create mode 100644 apps/design-system/lib/toc.ts create mode 100644 apps/design-system/lib/utils.ts create mode 100644 apps/design-system/next.config.mjs create mode 100644 apps/design-system/package.json create mode 100644 apps/design-system/postcss.config.cjs create mode 100644 apps/design-system/public/img/design-system-marks/atoms-illustration--deep-dark.svg create mode 100644 apps/design-system/public/img/design-system-marks/atoms-illustration--light.svg create mode 100644 apps/design-system/public/img/design-system-marks/design-system-marks--dark.svg create mode 100644 apps/design-system/public/img/design-system-marks/design-system-marks--light.svg create mode 100644 apps/design-system/public/img/design-system-marks/fragments-illustration--deep-dark.svg create mode 100644 apps/design-system/public/img/design-system-marks/fragments-illustration--light.svg create mode 100644 apps/design-system/public/img/themes/dark.svg create mode 100644 apps/design-system/public/img/themes/deep-dark.svg create mode 100644 apps/design-system/public/img/themes/light.svg create mode 100644 apps/design-system/public/img/themes/system.svg create mode 100644 apps/design-system/public/next.svg create mode 100644 apps/design-system/public/vercel.svg create mode 100644 apps/design-system/registry/.eslintrc.json create mode 100644 apps/design-system/registry/colors.ts create mode 100644 apps/design-system/registry/default/example/accordion-demo.tsx create mode 100644 apps/design-system/registry/default/example/alert-demo.tsx create mode 100644 apps/design-system/registry/default/example/alert-destructive.tsx create mode 100644 apps/design-system/registry/default/example/alert-dialog-demo.tsx create mode 100644 apps/design-system/registry/default/example/aspect-ratio-demo.tsx create mode 100644 apps/design-system/registry/default/example/avatar-demo.tsx create mode 100644 apps/design-system/registry/default/example/badge-demo.tsx create mode 100644 apps/design-system/registry/default/example/badge-destructive.tsx create mode 100644 apps/design-system/registry/default/example/badge-outline.tsx create mode 100644 apps/design-system/registry/default/example/badge-secondary.tsx create mode 100644 apps/design-system/registry/default/example/button-as-child.tsx create mode 100644 apps/design-system/registry/default/example/button-demo.tsx create mode 100644 apps/design-system/registry/default/example/button-destructive.tsx create mode 100644 apps/design-system/registry/default/example/button-ghost.tsx create mode 100644 apps/design-system/registry/default/example/button-icon.tsx create mode 100644 apps/design-system/registry/default/example/button-link.tsx create mode 100644 apps/design-system/registry/default/example/button-loading.tsx create mode 100644 apps/design-system/registry/default/example/button-outline.tsx create mode 100644 apps/design-system/registry/default/example/button-secondary.tsx create mode 100644 apps/design-system/registry/default/example/button-with-icon.tsx create mode 100644 apps/design-system/registry/default/example/calendar-demo.tsx create mode 100644 apps/design-system/registry/default/example/calendar-form.tsx create mode 100644 apps/design-system/registry/default/example/calendar-react-hook-form.tsx create mode 100644 apps/design-system/registry/default/example/checkbox-demo.tsx create mode 100644 apps/design-system/registry/default/example/checkbox-disabled.tsx create mode 100644 apps/design-system/registry/default/example/checkbox-form-multiple.tsx create mode 100644 apps/design-system/registry/default/example/checkbox-form-single.tsx create mode 100644 apps/design-system/registry/default/example/checkbox-with-text.tsx create mode 100644 apps/design-system/registry/default/example/collapsible-demo.tsx create mode 100644 apps/design-system/registry/default/example/color-usage-surface-studio-frame.tsx create mode 100644 apps/design-system/registry/default/example/color-usage-surface-studio.tsx create mode 100644 apps/design-system/registry/default/example/color-usage-surface-www-and-docs.tsx create mode 100644 apps/design-system/registry/default/example/combobox-demo.tsx create mode 100644 apps/design-system/registry/default/example/combobox-dropdown-menu.tsx create mode 100644 apps/design-system/registry/default/example/combobox-form.tsx create mode 100644 apps/design-system/registry/default/example/combobox-popover.tsx create mode 100644 apps/design-system/registry/default/example/combobox-responsive.tsx create mode 100644 apps/design-system/registry/default/example/command-demo.tsx create mode 100644 apps/design-system/registry/default/example/command-dialog.tsx create mode 100644 apps/design-system/registry/default/example/context-menu-demo.tsx create mode 100644 apps/design-system/registry/default/example/date-picker-demo.tsx create mode 100644 apps/design-system/registry/default/example/date-picker-form.tsx create mode 100644 apps/design-system/registry/default/example/date-picker-with-presets.tsx create mode 100644 apps/design-system/registry/default/example/date-picker-with-range.tsx create mode 100644 apps/design-system/registry/default/example/dialog-close-button.tsx create mode 100644 apps/design-system/registry/default/example/dialog-demo.tsx create mode 100644 apps/design-system/registry/default/example/drawer-demo.tsx create mode 100644 apps/design-system/registry/default/example/drawer-dialog.tsx create mode 100644 apps/design-system/registry/default/example/dropdown-menu-checkboxes.tsx create mode 100644 apps/design-system/registry/default/example/dropdown-menu-demo.tsx create mode 100644 apps/design-system/registry/default/example/dropdown-menu-radio-group.tsx create mode 100644 apps/design-system/registry/default/example/form-item-layout-demo.tsx create mode 100644 apps/design-system/registry/default/example/form-item-layout-with-checkbox-list.tsx create mode 100644 apps/design-system/registry/default/example/form-item-layout-with-checkbox.tsx create mode 100644 apps/design-system/registry/default/example/form-item-layout-with-horizontal.tsx create mode 100644 apps/design-system/registry/default/example/form-item-layout-with-select.tsx create mode 100644 apps/design-system/registry/default/example/form-item-layout-with-switch.tsx create mode 100644 apps/design-system/registry/default/example/hover-card-demo.tsx create mode 100644 apps/design-system/registry/default/example/input-demo.tsx create mode 100644 apps/design-system/registry/default/example/input-disabled.tsx create mode 100644 apps/design-system/registry/default/example/input-file.tsx create mode 100644 apps/design-system/registry/default/example/input-form.tsx create mode 100644 apps/design-system/registry/default/example/input-otp-controlled.tsx create mode 100644 apps/design-system/registry/default/example/input-otp-demo.tsx create mode 100644 apps/design-system/registry/default/example/input-otp-form.tsx create mode 100644 apps/design-system/registry/default/example/input-otp-pattern.tsx create mode 100644 apps/design-system/registry/default/example/input-otp-separator.tsx create mode 100644 apps/design-system/registry/default/example/input-with-button.tsx create mode 100644 apps/design-system/registry/default/example/input-with-label.tsx create mode 100644 apps/design-system/registry/default/example/input-with-text.tsx create mode 100644 apps/design-system/registry/default/example/label-demo.tsx create mode 100644 apps/design-system/registry/default/example/menubar-demo.tsx create mode 100644 apps/design-system/registry/default/example/mode-toggle.tsx create mode 100644 apps/design-system/registry/default/example/navigation-menu-demo.tsx create mode 100644 apps/design-system/registry/default/example/popover-demo.tsx create mode 100644 apps/design-system/registry/default/example/progress-demo.tsx create mode 100644 apps/design-system/registry/default/example/radio-group-demo.tsx create mode 100644 apps/design-system/registry/default/example/radio-group-form.tsx create mode 100644 apps/design-system/registry/default/example/resizable-demo-with-handle.tsx create mode 100644 apps/design-system/registry/default/example/resizable-demo.tsx create mode 100644 apps/design-system/registry/default/example/resizable-handle.tsx create mode 100644 apps/design-system/registry/default/example/resizable-vertical.tsx create mode 100644 apps/design-system/registry/default/example/scroll-area-demo.tsx create mode 100644 apps/design-system/registry/default/example/scroll-area-horizontal-demo.tsx create mode 100644 apps/design-system/registry/default/example/select-demo.tsx create mode 100644 apps/design-system/registry/default/example/select-form.tsx create mode 100644 apps/design-system/registry/default/example/select-scrollable.tsx create mode 100644 apps/design-system/registry/default/example/separator-demo.tsx create mode 100644 apps/design-system/registry/default/example/sheet-demo.tsx create mode 100644 apps/design-system/registry/default/example/sheet-side.tsx create mode 100644 apps/design-system/registry/default/example/skeleton-card.tsx create mode 100644 apps/design-system/registry/default/example/skeleton-demo.tsx create mode 100644 apps/design-system/registry/default/example/slider-demo.tsx create mode 100644 apps/design-system/registry/default/example/switch-demo.tsx create mode 100644 apps/design-system/registry/default/example/switch-form.tsx create mode 100644 apps/design-system/registry/default/example/table-demo.tsx create mode 100644 apps/design-system/registry/default/example/tabs-demo.tsx create mode 100644 apps/design-system/registry/default/example/text-confirm-dialog-demo.tsx create mode 100644 apps/design-system/registry/default/example/text-confirm-dialog-with-cancel-button.tsx create mode 100644 apps/design-system/registry/default/example/text-confirm-dialog-with-children.tsx create mode 100644 apps/design-system/registry/default/example/text-confirm-dialog-with-destructive-alert.tsx create mode 100644 apps/design-system/registry/default/example/text-confirm-dialog-with-info-alert.tsx create mode 100644 apps/design-system/registry/default/example/text-confirm-dialog-with-size.tsx create mode 100644 apps/design-system/registry/default/example/text-confirm-dialog-with-warning-alert.tsx create mode 100644 apps/design-system/registry/default/example/textarea-demo.tsx create mode 100644 apps/design-system/registry/default/example/textarea-disabled.tsx create mode 100644 apps/design-system/registry/default/example/textarea-form.tsx create mode 100644 apps/design-system/registry/default/example/textarea-with-button.tsx create mode 100644 apps/design-system/registry/default/example/textarea-with-label.tsx create mode 100644 apps/design-system/registry/default/example/textarea-with-text.tsx create mode 100644 apps/design-system/registry/default/example/toast-demo.tsx create mode 100644 apps/design-system/registry/default/example/toast-destructive.tsx create mode 100644 apps/design-system/registry/default/example/toast-simple.tsx create mode 100644 apps/design-system/registry/default/example/toast-with-action.tsx create mode 100644 apps/design-system/registry/default/example/toast-with-title.tsx create mode 100644 apps/design-system/registry/default/example/toggle-demo.tsx create mode 100644 apps/design-system/registry/default/example/toggle-disabled.tsx create mode 100644 apps/design-system/registry/default/example/toggle-group-demo.tsx create mode 100644 apps/design-system/registry/default/example/toggle-group-disabled.tsx create mode 100644 apps/design-system/registry/default/example/toggle-group-lg.tsx create mode 100644 apps/design-system/registry/default/example/toggle-group-outline.tsx create mode 100644 apps/design-system/registry/default/example/toggle-group-single.tsx create mode 100644 apps/design-system/registry/default/example/toggle-group-sm.tsx create mode 100644 apps/design-system/registry/default/example/toggle-lg.tsx create mode 100644 apps/design-system/registry/default/example/toggle-outline.tsx create mode 100644 apps/design-system/registry/default/example/toggle-sm.tsx create mode 100644 apps/design-system/registry/default/example/toggle-with-text.tsx create mode 100644 apps/design-system/registry/default/example/tooltip-demo.tsx create mode 100644 apps/design-system/registry/default/example/typography-blockquote.tsx create mode 100644 apps/design-system/registry/default/example/typography-demo.tsx create mode 100644 apps/design-system/registry/default/example/typography-h1.tsx create mode 100644 apps/design-system/registry/default/example/typography-h2.tsx create mode 100644 apps/design-system/registry/default/example/typography-h3.tsx create mode 100644 apps/design-system/registry/default/example/typography-h4.tsx create mode 100644 apps/design-system/registry/default/example/typography-inline-code.tsx create mode 100644 apps/design-system/registry/default/example/typography-large.tsx create mode 100644 apps/design-system/registry/default/example/typography-lead.tsx create mode 100644 apps/design-system/registry/default/example/typography-list.tsx create mode 100644 apps/design-system/registry/default/example/typography-muted.tsx create mode 100644 apps/design-system/registry/default/example/typography-p.tsx create mode 100644 apps/design-system/registry/default/example/typography-small.tsx create mode 100644 apps/design-system/registry/default/example/typography-table.tsx create mode 100644 apps/design-system/registry/examples.ts create mode 100644 apps/design-system/registry/fragments.ts create mode 100644 apps/design-system/registry/registry.ts create mode 100644 apps/design-system/registry/schema.ts create mode 100644 apps/design-system/registry/styles.ts create mode 100644 apps/design-system/registry/themes.ts create mode 100644 apps/design-system/scripts/build-registry.mts create mode 100644 apps/design-system/styles/code-block-variables.css create mode 100644 apps/design-system/styles/globals.css create mode 100644 apps/design-system/styles/mdx.css create mode 100644 apps/design-system/tailwind.config.js create mode 100644 apps/design-system/tsconfig.json create mode 100644 apps/design-system/tsconfig.scripts.json create mode 100644 apps/design-system/types/nav.ts create mode 100644 apps/design-system/types/unist.ts create mode 100644 packages/icons/__registry__/index.tsx rename packages/{ui/src/components => ui-patterns}/PromoToast/PromoBg.tsx (99%) rename packages/{ui/src/components => ui-patterns}/PromoToast/PromoToast.tsx (89%) rename packages/{ui/src/components => ui-patterns}/PromoToast/index.ts (100%) create mode 100644 packages/ui/src/components/shadcn/ui/drawer.tsx rename packages/ui/src/components/shadcn/ui/{tabs => }/tabs.tsx (97%) create mode 100644 packages/ui/src/components/shadcn/ui/toggle-group.tsx diff --git a/.prettierignore b/.prettierignore index bc42d43c6b..10d155ba31 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,3 +16,4 @@ apps/docs/pages/guides/integrations/*.mdx apps/studio/public apps/**/.turbo apps/docs/CONTRIBUTING.md +apps/design-system/__registry__ \ No newline at end of file diff --git a/apps/design-system/.eslintrc.json b/apps/design-system/.eslintrc.json new file mode 100644 index 0000000000..bffb357a71 --- /dev/null +++ b/apps/design-system/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/apps/design-system/.gitignore b/apps/design-system/.gitignore new file mode 100644 index 0000000000..57c2e5aba2 --- /dev/null +++ b/apps/design-system/.gitignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +.contentlayer \ No newline at end of file diff --git a/apps/design-system/README.md b/apps/design-system/README.md new file mode 100644 index 0000000000..c4033664f8 --- /dev/null +++ b/apps/design-system/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/apps/design-system/__registry__/index.tsx b/apps/design-system/__registry__/index.tsx new file mode 100644 index 0000000000..c5e960a978 --- /dev/null +++ b/apps/design-system/__registry__/index.tsx @@ -0,0 +1,1593 @@ +// @ts-nocheck +// This file is autogenerated by scripts/build-registry.ts +// Do not edit this file directly. +import * as React from "react" + +export const Index: Record = { + "default": { + "ConfirmationModal": { + name: "ConfirmationModal", + type: "components:fragment", + registryDependencies: undefined, + component: React.lazy(() => import("@/../../packages/ui-patterns/Dialogs/ConfirmationModal")), + source: "", + files: ["registry/default//Dialogs/ConfirmationModal.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "TextConfirmModal": { + name: "TextConfirmModal", + type: "components:fragment", + registryDependencies: undefined, + component: React.lazy(() => import("@/../../packages/ui-patterns/Dialogs/TextConfirmModal")), + source: "", + files: ["registry/default//Dialogs/TextConfirmModal.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "ConfirmDialog": { + name: "ConfirmDialog", + type: "components:fragment", + registryDependencies: undefined, + component: React.lazy(() => import("@/../../packages/ui-patterns/Dialogs/ConfirmDialog")), + source: "", + files: ["registry/default//Dialogs/ConfirmDialog.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "accordion-demo": { + name: "accordion-demo", + type: "components:example", + registryDependencies: ["accordion"], + component: React.lazy(() => import("@/registry/default/example/accordion-demo")), + source: "", + files: ["registry/default/example/accordion-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "alert-demo": { + name: "alert-demo", + type: "components:example", + registryDependencies: ["alert"], + component: React.lazy(() => import("@/registry/default/example/alert-demo")), + source: "", + files: ["registry/default/example/alert-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "alert-destructive": { + name: "alert-destructive", + type: "components:example", + registryDependencies: ["alert"], + component: React.lazy(() => import("@/registry/default/example/alert-destructive")), + source: "", + files: ["registry/default/example/alert-destructive.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "alert-dialog-demo": { + name: "alert-dialog-demo", + type: "components:example", + registryDependencies: ["alert-dialog","button"], + component: React.lazy(() => import("@/registry/default/example/alert-dialog-demo")), + source: "", + files: ["registry/default/example/alert-dialog-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "aspect-ratio-demo": { + name: "aspect-ratio-demo", + type: "components:example", + registryDependencies: ["aspect-ratio"], + component: React.lazy(() => import("@/registry/default/example/aspect-ratio-demo")), + source: "", + files: ["registry/default/example/aspect-ratio-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "avatar-demo": { + name: "avatar-demo", + type: "components:example", + registryDependencies: ["avatar"], + component: React.lazy(() => import("@/registry/default/example/avatar-demo")), + source: "", + files: ["registry/default/example/avatar-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "badge-demo": { + name: "badge-demo", + type: "components:example", + registryDependencies: ["badge"], + component: React.lazy(() => import("@/registry/default/example/badge-demo")), + source: "", + files: ["registry/default/example/badge-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "badge-destructive": { + name: "badge-destructive", + type: "components:example", + registryDependencies: ["badge"], + component: React.lazy(() => import("@/registry/default/example/badge-destructive")), + source: "", + files: ["registry/default/example/badge-destructive.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "badge-outline": { + name: "badge-outline", + type: "components:example", + registryDependencies: ["badge"], + component: React.lazy(() => import("@/registry/default/example/badge-outline")), + source: "", + files: ["registry/default/example/badge-outline.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "badge-secondary": { + name: "badge-secondary", + type: "components:example", + registryDependencies: ["badge"], + component: React.lazy(() => import("@/registry/default/example/badge-secondary")), + source: "", + files: ["registry/default/example/badge-secondary.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-demo": { + name: "button-demo", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-demo")), + source: "", + files: ["registry/default/example/button-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-secondary": { + name: "button-secondary", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-secondary")), + source: "", + files: ["registry/default/example/button-secondary.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-destructive": { + name: "button-destructive", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-destructive")), + source: "", + files: ["registry/default/example/button-destructive.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-outline": { + name: "button-outline", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-outline")), + source: "", + files: ["registry/default/example/button-outline.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-ghost": { + name: "button-ghost", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-ghost")), + source: "", + files: ["registry/default/example/button-ghost.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-link": { + name: "button-link", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-link")), + source: "", + files: ["registry/default/example/button-link.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-with-icon": { + name: "button-with-icon", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-with-icon")), + source: "", + files: ["registry/default/example/button-with-icon.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-loading": { + name: "button-loading", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-loading")), + source: "", + files: ["registry/default/example/button-loading.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-icon": { + name: "button-icon", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-icon")), + source: "", + files: ["registry/default/example/button-icon.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "button-as-child": { + name: "button-as-child", + type: "components:example", + registryDependencies: ["button"], + component: React.lazy(() => import("@/registry/default/example/button-as-child")), + source: "", + files: ["registry/default/example/button-as-child.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "calendar-demo": { + name: "calendar-demo", + type: "components:example", + registryDependencies: ["calendar"], + component: React.lazy(() => import("@/registry/default/example/calendar-demo")), + source: "", + files: ["registry/default/example/calendar-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "calendar-form": { + name: "calendar-form", + type: "components:example", + registryDependencies: ["calendar","form","popover"], + component: React.lazy(() => import("@/registry/default/example/calendar-form")), + source: "", + files: ["registry/default/example/calendar-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "checkbox-demo": { + name: "checkbox-demo", + type: "components:example", + registryDependencies: ["checkbox"], + component: React.lazy(() => import("@/registry/default/example/checkbox-demo")), + source: "", + files: ["registry/default/example/checkbox-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "checkbox-disabled": { + name: "checkbox-disabled", + type: "components:example", + registryDependencies: ["checkbox"], + component: React.lazy(() => import("@/registry/default/example/checkbox-disabled")), + source: "", + files: ["registry/default/example/checkbox-disabled.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "checkbox-form-multiple": { + name: "checkbox-form-multiple", + type: "components:example", + registryDependencies: ["checkbox","form"], + component: React.lazy(() => import("@/registry/default/example/checkbox-form-multiple")), + source: "", + files: ["registry/default/example/checkbox-form-multiple.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "checkbox-form-single": { + name: "checkbox-form-single", + type: "components:example", + registryDependencies: ["checkbox","form"], + component: React.lazy(() => import("@/registry/default/example/checkbox-form-single")), + source: "", + files: ["registry/default/example/checkbox-form-single.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "checkbox-with-text": { + name: "checkbox-with-text", + type: "components:example", + registryDependencies: ["checkbox"], + component: React.lazy(() => import("@/registry/default/example/checkbox-with-text")), + source: "", + files: ["registry/default/example/checkbox-with-text.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "collapsible-demo": { + name: "collapsible-demo", + type: "components:example", + registryDependencies: ["collapsible"], + component: React.lazy(() => import("@/registry/default/example/collapsible-demo")), + source: "", + files: ["registry/default/example/collapsible-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "combobox-demo": { + name: "combobox-demo", + type: "components:example", + registryDependencies: ["command"], + component: React.lazy(() => import("@/registry/default/example/combobox-demo")), + source: "", + files: ["registry/default/example/combobox-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "combobox-dropdown-menu": { + name: "combobox-dropdown-menu", + type: "components:example", + registryDependencies: ["command","dropdown-menu","button"], + component: React.lazy(() => import("@/registry/default/example/combobox-dropdown-menu")), + source: "", + files: ["registry/default/example/combobox-dropdown-menu.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "combobox-form": { + name: "combobox-form", + type: "components:example", + registryDependencies: ["command","form"], + component: React.lazy(() => import("@/registry/default/example/combobox-form")), + source: "", + files: ["registry/default/example/combobox-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "combobox-popover": { + name: "combobox-popover", + type: "components:example", + registryDependencies: ["combobox","popover"], + component: React.lazy(() => import("@/registry/default/example/combobox-popover")), + source: "", + files: ["registry/default/example/combobox-popover.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "combobox-responsive": { + name: "combobox-responsive", + type: "components:example", + registryDependencies: ["combobox","popover","drawer"], + component: React.lazy(() => import("@/registry/default/example/combobox-responsive")), + source: "", + files: ["registry/default/example/combobox-responsive.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "command-demo": { + name: "command-demo", + type: "components:example", + registryDependencies: ["command"], + component: React.lazy(() => import("@/registry/default/example/command-demo")), + source: "", + files: ["registry/default/example/command-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "command-dialog": { + name: "command-dialog", + type: "components:example", + registryDependencies: ["command","dialog"], + component: React.lazy(() => import("@/registry/default/example/command-dialog")), + source: "", + files: ["registry/default/example/command-dialog.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "context-menu-demo": { + name: "context-menu-demo", + type: "components:example", + registryDependencies: ["context-menu"], + component: React.lazy(() => import("@/registry/default/example/context-menu-demo")), + source: "", + files: ["registry/default/example/context-menu-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "date-picker-demo": { + name: "date-picker-demo", + type: "components:example", + registryDependencies: ["button","calendar","popover"], + component: React.lazy(() => import("@/registry/default/example/date-picker-demo")), + source: "", + files: ["registry/default/example/date-picker-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "date-picker-form": { + name: "date-picker-form", + type: "components:example", + registryDependencies: ["button","calendar","form","popover"], + component: React.lazy(() => import("@/registry/default/example/date-picker-form")), + source: "", + files: ["registry/default/example/date-picker-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "date-picker-with-presets": { + name: "date-picker-with-presets", + type: "components:example", + registryDependencies: ["button","calendar","popover","select"], + component: React.lazy(() => import("@/registry/default/example/date-picker-with-presets")), + source: "", + files: ["registry/default/example/date-picker-with-presets.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "date-picker-with-range": { + name: "date-picker-with-range", + type: "components:example", + registryDependencies: ["button","calendar","popover"], + component: React.lazy(() => import("@/registry/default/example/date-picker-with-range")), + source: "", + files: ["registry/default/example/date-picker-with-range.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "dialog-demo": { + name: "dialog-demo", + type: "components:example", + registryDependencies: ["dialog"], + component: React.lazy(() => import("@/registry/default/example/dialog-demo")), + source: "", + files: ["registry/default/example/dialog-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "dialog-close-button": { + name: "dialog-close-button", + type: "components:example", + registryDependencies: ["dialog","button"], + component: React.lazy(() => import("@/registry/default/example/dialog-close-button")), + source: "", + files: ["registry/default/example/dialog-close-button.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "drawer-demo": { + name: "drawer-demo", + type: "components:example", + registryDependencies: ["drawer"], + component: React.lazy(() => import("@/registry/default/example/drawer-demo")), + source: "", + files: ["registry/default/example/drawer-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "drawer-dialog": { + name: "drawer-dialog", + type: "components:example", + registryDependencies: ["drawer","dialog"], + component: React.lazy(() => import("@/registry/default/example/drawer-dialog")), + source: "", + files: ["registry/default/example/drawer-dialog.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "dropdown-menu-demo": { + name: "dropdown-menu-demo", + type: "components:example", + registryDependencies: ["dropdown-menu"], + component: React.lazy(() => import("@/registry/default/example/dropdown-menu-demo")), + source: "", + files: ["registry/default/example/dropdown-menu-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "dropdown-menu-checkboxes": { + name: "dropdown-menu-checkboxes", + type: "components:example", + registryDependencies: ["dropdown-menu","checkbox"], + component: React.lazy(() => import("@/registry/default/example/dropdown-menu-checkboxes")), + source: "", + files: ["registry/default/example/dropdown-menu-checkboxes.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "dropdown-menu-radio-group": { + name: "dropdown-menu-radio-group", + type: "components:example", + registryDependencies: ["dropdown-menu","radio-group"], + component: React.lazy(() => import("@/registry/default/example/dropdown-menu-radio-group")), + source: "", + files: ["registry/default/example/dropdown-menu-radio-group.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "hover-card-demo": { + name: "hover-card-demo", + type: "components:example", + registryDependencies: ["hover-card"], + component: React.lazy(() => import("@/registry/default/example/hover-card-demo")), + source: "", + files: ["registry/default/example/hover-card-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-demo": { + name: "input-demo", + type: "components:example", + registryDependencies: ["input"], + component: React.lazy(() => import("@/registry/default/example/input-demo")), + source: "", + files: ["registry/default/example/input-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-disabled": { + name: "input-disabled", + type: "components:example", + registryDependencies: ["input"], + component: React.lazy(() => import("@/registry/default/example/input-disabled")), + source: "", + files: ["registry/default/example/input-disabled.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-file": { + name: "input-file", + type: "components:example", + registryDependencies: ["input"], + component: React.lazy(() => import("@/registry/default/example/input-file")), + source: "", + files: ["registry/default/example/input-file.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-form": { + name: "input-form", + type: "components:example", + registryDependencies: ["input","button","form"], + component: React.lazy(() => import("@/registry/default/example/input-form")), + source: "", + files: ["registry/default/example/input-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-with-button": { + name: "input-with-button", + type: "components:example", + registryDependencies: ["input","button"], + component: React.lazy(() => import("@/registry/default/example/input-with-button")), + source: "", + files: ["registry/default/example/input-with-button.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-with-label": { + name: "input-with-label", + type: "components:example", + registryDependencies: ["input","button","label"], + component: React.lazy(() => import("@/registry/default/example/input-with-label")), + source: "", + files: ["registry/default/example/input-with-label.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-with-text": { + name: "input-with-text", + type: "components:example", + registryDependencies: ["input","button","label"], + component: React.lazy(() => import("@/registry/default/example/input-with-text")), + source: "", + files: ["registry/default/example/input-with-text.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-otp-demo": { + name: "input-otp-demo", + type: "components:example", + registryDependencies: ["input-otp"], + component: React.lazy(() => import("@/registry/default/example/input-otp-demo")), + source: "", + files: ["registry/default/example/input-otp-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-otp-pattern": { + name: "input-otp-pattern", + type: "components:example", + registryDependencies: ["input-otp"], + component: React.lazy(() => import("@/registry/default/example/input-otp-pattern")), + source: "", + files: ["registry/default/example/input-otp-pattern.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-otp-separator": { + name: "input-otp-separator", + type: "components:example", + registryDependencies: ["input-otp"], + component: React.lazy(() => import("@/registry/default/example/input-otp-separator")), + source: "", + files: ["registry/default/example/input-otp-separator.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-otp-controlled": { + name: "input-otp-controlled", + type: "components:example", + registryDependencies: ["input-otp"], + component: React.lazy(() => import("@/registry/default/example/input-otp-controlled")), + source: "", + files: ["registry/default/example/input-otp-controlled.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "input-otp-form": { + name: "input-otp-form", + type: "components:example", + registryDependencies: ["input-otp","form"], + component: React.lazy(() => import("@/registry/default/example/input-otp-form")), + source: "", + files: ["registry/default/example/input-otp-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "label-demo": { + name: "label-demo", + type: "components:example", + registryDependencies: ["label"], + component: React.lazy(() => import("@/registry/default/example/label-demo")), + source: "", + files: ["registry/default/example/label-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "menubar-demo": { + name: "menubar-demo", + type: "components:example", + registryDependencies: ["menubar"], + component: React.lazy(() => import("@/registry/default/example/menubar-demo")), + source: "", + files: ["registry/default/example/menubar-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "navigation-menu-demo": { + name: "navigation-menu-demo", + type: "components:example", + registryDependencies: ["navigation-menu"], + component: React.lazy(() => import("@/registry/default/example/navigation-menu-demo")), + source: "", + files: ["registry/default/example/navigation-menu-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "popover-demo": { + name: "popover-demo", + type: "components:example", + registryDependencies: ["popover"], + component: React.lazy(() => import("@/registry/default/example/popover-demo")), + source: "", + files: ["registry/default/example/popover-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "progress-demo": { + name: "progress-demo", + type: "components:example", + registryDependencies: ["progress"], + component: React.lazy(() => import("@/registry/default/example/progress-demo")), + source: "", + files: ["registry/default/example/progress-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "radio-group-demo": { + name: "radio-group-demo", + type: "components:example", + registryDependencies: ["radio-group"], + component: React.lazy(() => import("@/registry/default/example/radio-group-demo")), + source: "", + files: ["registry/default/example/radio-group-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "radio-group-form": { + name: "radio-group-form", + type: "components:example", + registryDependencies: ["radio-group","form"], + component: React.lazy(() => import("@/registry/default/example/radio-group-form")), + source: "", + files: ["registry/default/example/radio-group-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "resizable-demo": { + name: "resizable-demo", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-demo")), + source: "", + files: ["registry/default/example/resizable-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "resizable-demo-with-handle": { + name: "resizable-demo-with-handle", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-demo-with-handle")), + source: "", + files: ["registry/default/example/resizable-demo-with-handle.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "resizable-vertical": { + name: "resizable-vertical", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-vertical")), + source: "", + files: ["registry/default/example/resizable-vertical.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "resizable-handle": { + name: "resizable-handle", + type: "components:example", + registryDependencies: ["resizable"], + component: React.lazy(() => import("@/registry/default/example/resizable-handle")), + source: "", + files: ["registry/default/example/resizable-handle.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "scroll-area-demo": { + name: "scroll-area-demo", + type: "components:example", + registryDependencies: ["scroll-area"], + component: React.lazy(() => import("@/registry/default/example/scroll-area-demo")), + source: "", + files: ["registry/default/example/scroll-area-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "scroll-area-horizontal-demo": { + name: "scroll-area-horizontal-demo", + type: "components:example", + registryDependencies: ["scroll-area"], + component: React.lazy(() => import("@/registry/default/example/scroll-area-horizontal-demo")), + source: "", + files: ["registry/default/example/scroll-area-horizontal-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "select-demo": { + name: "select-demo", + type: "components:example", + registryDependencies: ["select"], + component: React.lazy(() => import("@/registry/default/example/select-demo")), + source: "", + files: ["registry/default/example/select-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "select-scrollable": { + name: "select-scrollable", + type: "components:example", + registryDependencies: ["select"], + component: React.lazy(() => import("@/registry/default/example/select-scrollable")), + source: "", + files: ["registry/default/example/select-scrollable.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "select-form": { + name: "select-form", + type: "components:example", + registryDependencies: ["select"], + component: React.lazy(() => import("@/registry/default/example/select-form")), + source: "", + files: ["registry/default/example/select-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "separator-demo": { + name: "separator-demo", + type: "components:example", + registryDependencies: ["separator"], + component: React.lazy(() => import("@/registry/default/example/separator-demo")), + source: "", + files: ["registry/default/example/separator-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "sheet-demo": { + name: "sheet-demo", + type: "components:example", + registryDependencies: ["sheet"], + component: React.lazy(() => import("@/registry/default/example/sheet-demo")), + source: "", + files: ["registry/default/example/sheet-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "sheet-side": { + name: "sheet-side", + type: "components:example", + registryDependencies: ["sheet"], + component: React.lazy(() => import("@/registry/default/example/sheet-side")), + source: "", + files: ["registry/default/example/sheet-side.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "skeleton-demo": { + name: "skeleton-demo", + type: "components:example", + registryDependencies: ["skeleton"], + component: React.lazy(() => import("@/registry/default/example/skeleton-demo")), + source: "", + files: ["registry/default/example/skeleton-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "skeleton-card": { + name: "skeleton-card", + type: "components:example", + registryDependencies: ["skeleton"], + component: React.lazy(() => import("@/registry/default/example/skeleton-card")), + source: "", + files: ["registry/default/example/skeleton-card.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "slider-demo": { + name: "slider-demo", + type: "components:example", + registryDependencies: ["slider"], + component: React.lazy(() => import("@/registry/default/example/slider-demo")), + source: "", + files: ["registry/default/example/slider-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "switch-demo": { + name: "switch-demo", + type: "components:example", + registryDependencies: ["switch"], + component: React.lazy(() => import("@/registry/default/example/switch-demo")), + source: "", + files: ["registry/default/example/switch-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "switch-form": { + name: "switch-form", + type: "components:example", + registryDependencies: ["switch","form"], + component: React.lazy(() => import("@/registry/default/example/switch-form")), + source: "", + files: ["registry/default/example/switch-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "table-demo": { + name: "table-demo", + type: "components:example", + registryDependencies: ["table"], + component: React.lazy(() => import("@/registry/default/example/table-demo")), + source: "", + files: ["registry/default/example/table-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "tabs-demo": { + name: "tabs-demo", + type: "components:example", + registryDependencies: ["tabs"], + component: React.lazy(() => import("@/registry/default/example/tabs-demo")), + source: "", + files: ["registry/default/example/tabs-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "textarea-demo": { + name: "textarea-demo", + type: "components:example", + registryDependencies: ["textarea"], + component: React.lazy(() => import("@/registry/default/example/textarea-demo")), + source: "", + files: ["registry/default/example/textarea-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "textarea-disabled": { + name: "textarea-disabled", + type: "components:example", + registryDependencies: ["textarea"], + component: React.lazy(() => import("@/registry/default/example/textarea-disabled")), + source: "", + files: ["registry/default/example/textarea-disabled.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "textarea-form": { + name: "textarea-form", + type: "components:example", + registryDependencies: ["textarea","form"], + component: React.lazy(() => import("@/registry/default/example/textarea-form")), + source: "", + files: ["registry/default/example/textarea-form.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "textarea-with-button": { + name: "textarea-with-button", + type: "components:example", + registryDependencies: ["textarea","button"], + component: React.lazy(() => import("@/registry/default/example/textarea-with-button")), + source: "", + files: ["registry/default/example/textarea-with-button.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "textarea-with-label": { + name: "textarea-with-label", + type: "components:example", + registryDependencies: ["textarea","label"], + component: React.lazy(() => import("@/registry/default/example/textarea-with-label")), + source: "", + files: ["registry/default/example/textarea-with-label.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "textarea-with-text": { + name: "textarea-with-text", + type: "components:example", + registryDependencies: ["textarea","label"], + component: React.lazy(() => import("@/registry/default/example/textarea-with-text")), + source: "", + files: ["registry/default/example/textarea-with-text.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toast-demo": { + name: "toast-demo", + type: "components:example", + registryDependencies: ["toast"], + component: React.lazy(() => import("@/registry/default/example/toast-demo")), + source: "", + files: ["registry/default/example/toast-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toast-destructive": { + name: "toast-destructive", + type: "components:example", + registryDependencies: ["toast"], + component: React.lazy(() => import("@/registry/default/example/toast-destructive")), + source: "", + files: ["registry/default/example/toast-destructive.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toast-simple": { + name: "toast-simple", + type: "components:example", + registryDependencies: ["toast"], + component: React.lazy(() => import("@/registry/default/example/toast-simple")), + source: "", + files: ["registry/default/example/toast-simple.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toast-with-action": { + name: "toast-with-action", + type: "components:example", + registryDependencies: ["toast"], + component: React.lazy(() => import("@/registry/default/example/toast-with-action")), + source: "", + files: ["registry/default/example/toast-with-action.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toast-with-title": { + name: "toast-with-title", + type: "components:example", + registryDependencies: ["toast"], + component: React.lazy(() => import("@/registry/default/example/toast-with-title")), + source: "", + files: ["registry/default/example/toast-with-title.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-group-demo": { + name: "toggle-group-demo", + type: "components:example", + registryDependencies: ["toggle-group"], + component: React.lazy(() => import("@/registry/default/example/toggle-group-demo")), + source: "", + files: ["registry/default/example/toggle-group-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-group-disabled": { + name: "toggle-group-disabled", + type: "components:example", + registryDependencies: ["toggle-group"], + component: React.lazy(() => import("@/registry/default/example/toggle-group-disabled")), + source: "", + files: ["registry/default/example/toggle-group-disabled.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-group-lg": { + name: "toggle-group-lg", + type: "components:example", + registryDependencies: ["toggle-group"], + component: React.lazy(() => import("@/registry/default/example/toggle-group-lg")), + source: "", + files: ["registry/default/example/toggle-group-lg.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-group-outline": { + name: "toggle-group-outline", + type: "components:example", + registryDependencies: ["toggle-group"], + component: React.lazy(() => import("@/registry/default/example/toggle-group-outline")), + source: "", + files: ["registry/default/example/toggle-group-outline.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-group-sm": { + name: "toggle-group-sm", + type: "components:example", + registryDependencies: ["toggle-group"], + component: React.lazy(() => import("@/registry/default/example/toggle-group-sm")), + source: "", + files: ["registry/default/example/toggle-group-sm.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-group-single": { + name: "toggle-group-single", + type: "components:example", + registryDependencies: ["toggle-group"], + component: React.lazy(() => import("@/registry/default/example/toggle-group-single")), + source: "", + files: ["registry/default/example/toggle-group-single.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-demo": { + name: "toggle-demo", + type: "components:example", + registryDependencies: ["toggle"], + component: React.lazy(() => import("@/registry/default/example/toggle-demo")), + source: "", + files: ["registry/default/example/toggle-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-disabled": { + name: "toggle-disabled", + type: "components:example", + registryDependencies: ["toggle"], + component: React.lazy(() => import("@/registry/default/example/toggle-disabled")), + source: "", + files: ["registry/default/example/toggle-disabled.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-lg": { + name: "toggle-lg", + type: "components:example", + registryDependencies: ["toggle"], + component: React.lazy(() => import("@/registry/default/example/toggle-lg")), + source: "", + files: ["registry/default/example/toggle-lg.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-outline": { + name: "toggle-outline", + type: "components:example", + registryDependencies: ["toggle"], + component: React.lazy(() => import("@/registry/default/example/toggle-outline")), + source: "", + files: ["registry/default/example/toggle-outline.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-sm": { + name: "toggle-sm", + type: "components:example", + registryDependencies: ["toggle"], + component: React.lazy(() => import("@/registry/default/example/toggle-sm")), + source: "", + files: ["registry/default/example/toggle-sm.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "toggle-with-text": { + name: "toggle-with-text", + type: "components:example", + registryDependencies: ["toggle"], + component: React.lazy(() => import("@/registry/default/example/toggle-with-text")), + source: "", + files: ["registry/default/example/toggle-with-text.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "tooltip-demo": { + name: "tooltip-demo", + type: "components:example", + registryDependencies: ["tooltip"], + component: React.lazy(() => import("@/registry/default/example/tooltip-demo")), + source: "", + files: ["registry/default/example/tooltip-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-blockquote": { + name: "typography-blockquote", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-blockquote")), + source: "", + files: ["registry/default/example/typography-blockquote.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-demo": { + name: "typography-demo", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-demo")), + source: "", + files: ["registry/default/example/typography-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-h1": { + name: "typography-h1", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-h1")), + source: "", + files: ["registry/default/example/typography-h1.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-h2": { + name: "typography-h2", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-h2")), + source: "", + files: ["registry/default/example/typography-h2.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-h3": { + name: "typography-h3", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-h3")), + source: "", + files: ["registry/default/example/typography-h3.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-h4": { + name: "typography-h4", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-h4")), + source: "", + files: ["registry/default/example/typography-h4.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-inline-code": { + name: "typography-inline-code", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-inline-code")), + source: "", + files: ["registry/default/example/typography-inline-code.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-large": { + name: "typography-large", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-large")), + source: "", + files: ["registry/default/example/typography-large.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-lead": { + name: "typography-lead", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-lead")), + source: "", + files: ["registry/default/example/typography-lead.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-list": { + name: "typography-list", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-list")), + source: "", + files: ["registry/default/example/typography-list.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-muted": { + name: "typography-muted", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-muted")), + source: "", + files: ["registry/default/example/typography-muted.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-p": { + name: "typography-p", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-p")), + source: "", + files: ["registry/default/example/typography-p.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-small": { + name: "typography-small", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-small")), + source: "", + files: ["registry/default/example/typography-small.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "typography-table": { + name: "typography-table", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/typography-table")), + source: "", + files: ["registry/default/example/typography-table.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "mode-toggle": { + name: "mode-toggle", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/mode-toggle")), + source: "", + files: ["registry/default/example/mode-toggle.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "text-confirm-dialog-demo": { + name: "text-confirm-dialog-demo", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/text-confirm-dialog-demo")), + source: "", + files: ["registry/default/example/text-confirm-dialog-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "text-confirm-dialog-with-info-alert": { + name: "text-confirm-dialog-with-info-alert", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/text-confirm-dialog-with-info-alert")), + source: "", + files: ["registry/default/example/text-confirm-dialog-with-info-alert.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "text-confirm-dialog-with-warning-alert": { + name: "text-confirm-dialog-with-warning-alert", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/text-confirm-dialog-with-warning-alert")), + source: "", + files: ["registry/default/example/text-confirm-dialog-with-warning-alert.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "text-confirm-dialog-with-destructive-alert": { + name: "text-confirm-dialog-with-destructive-alert", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/text-confirm-dialog-with-destructive-alert")), + source: "", + files: ["registry/default/example/text-confirm-dialog-with-destructive-alert.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "text-confirm-dialog-with-size": { + name: "text-confirm-dialog-with-size", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/text-confirm-dialog-with-size")), + source: "", + files: ["registry/default/example/text-confirm-dialog-with-size.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "text-confirm-dialog-with-children": { + name: "text-confirm-dialog-with-children", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/text-confirm-dialog-with-children")), + source: "", + files: ["registry/default/example/text-confirm-dialog-with-children.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "text-confirm-dialog-with-cancel-button": { + name: "text-confirm-dialog-with-cancel-button", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/text-confirm-dialog-with-cancel-button")), + source: "", + files: ["registry/default/example/text-confirm-dialog-with-cancel-button.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "form-item-layout-demo": { + name: "form-item-layout-demo", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/form-item-layout-demo")), + source: "", + files: ["registry/default/example/form-item-layout-demo.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "form-item-layout-with-select": { + name: "form-item-layout-with-select", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/form-item-layout-with-select")), + source: "", + files: ["registry/default/example/form-item-layout-with-select.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "form-item-layout-with-horizontal": { + name: "form-item-layout-with-horizontal", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/form-item-layout-with-horizontal")), + source: "", + files: ["registry/default/example/form-item-layout-with-horizontal.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "form-item-layout-with-switch": { + name: "form-item-layout-with-switch", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/form-item-layout-with-switch")), + source: "", + files: ["registry/default/example/form-item-layout-with-switch.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "form-item-layout-with-checkbox": { + name: "form-item-layout-with-checkbox", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/form-item-layout-with-checkbox")), + source: "", + files: ["registry/default/example/form-item-layout-with-switch.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "form-item-layout-with-checkbox-list": { + name: "form-item-layout-with-checkbox-list", + type: "components:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/form-item-layout-with-checkbox-list")), + source: "", + files: ["registry/default/example/form-item-layout-with-switch.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "color-usage-surface-www-and-docs": { + name: "color-usage-surface-www-and-docs", + type: "docs:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/color-usage-surface-www-and-docs")), + source: "", + files: ["registry/default/example/color-usage-surface-www-and-docs.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "color-usage-surface-studio": { + name: "color-usage-surface-studio", + type: "docs:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/color-usage-surface-studio")), + source: "", + files: ["registry/default/example/color-usage-surface-studio.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "color-usage-surface-studio-frame": { + name: "color-usage-surface-studio-frame", + type: "docs:example", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/example/color-usage-surface-studio-frame")), + source: "", + files: ["registry/default/example/color-usage-surface-studio-frame.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + }, +} diff --git a/apps/design-system/app/(app)/docs/[[...slug]]/page.tsx b/apps/design-system/app/(app)/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000000..efa2f74912 --- /dev/null +++ b/apps/design-system/app/(app)/docs/[[...slug]]/page.tsx @@ -0,0 +1,119 @@ +import { Mdx } from '@/components/mdx-components' +import { DocsPager } from '@/components/pager' +import { SourcePanel } from '@/components/source-panel' +import { DashboardTableOfContents } from '@/components/toc' +import { siteConfig } from '@/config/site' +import { getTableOfContents } from '@/lib/toc' +import { absoluteUrl, cn } from '@/lib/utils' +import '@/styles/code-block-variables.css' +import '@/styles/mdx.css' +import { allDocs } from 'contentlayer/generated' +import { ChevronRight } from 'lucide-react' +import type { Metadata } from 'next' +import { notFound } from 'next/navigation' +import Balancer from 'react-wrap-balancer' +import { ScrollArea, Separator } from 'ui' + +interface DocPageProps { + params: { + slug: string[] + } +} + +async function getDocFromParams({ params }: DocPageProps) { + const slug = params.slug?.join('/') || '' + const doc = allDocs.find((doc) => doc.slugAsParams === slug) + + if (!doc) { + return null + } + + return doc +} + +export async function generateMetadata({ params }: DocPageProps): Promise { + const doc = await getDocFromParams({ params }) + + if (!doc) { + return {} + } + + return { + title: doc.title, + description: doc.description, + openGraph: { + title: doc.title, + description: doc.description, + type: 'article', + url: absoluteUrl(doc.slug), + images: [ + { + url: siteConfig.ogImage, + width: 1200, + height: 630, + alt: siteConfig.name, + }, + ], + }, + twitter: { + card: 'summary_large_image', + title: doc.title, + description: doc.description, + images: [siteConfig.ogImage], + creator: '@shadcn', + }, + } +} + +export async function generateStaticParams(): Promise { + return allDocs.map((doc) => ({ + slug: doc.slugAsParams.split('/'), + })) +} + +export default async function DocPage({ params }: DocPageProps) { + const doc = await getDocFromParams({ params }) + + if (!doc) { + notFound() + } + + const toc = await getTableOfContents(doc.body.raw) + + return ( +
+
+
+
Docs
+ +
{doc.title}
+
+
+

{doc.title}

+ {doc.description && ( +

+ {doc.description} +

+ )} +
+ + +
+ +
+ +
+ {doc.toc && ( +
+
+ +
+ +
+
+
+
+ )} +
+ ) +} diff --git a/apps/design-system/app/(app)/layout.tsx b/apps/design-system/app/(app)/layout.tsx new file mode 100644 index 0000000000..49b81a77a8 --- /dev/null +++ b/apps/design-system/app/(app)/layout.tsx @@ -0,0 +1,35 @@ +import SideNavigation from '@/components/side-navigation' +import { SiteFooter } from '@/components/site-footer' +// import ThemeSettings from '@/components/theme-settings' +import TopNavigation from '@/components/top-navigation' +import { ScrollArea } from 'ui' + +interface AppLayoutProps { + children: React.ReactNode +} + +export default function AppLayout({ children }: AppLayoutProps) { + return ( + <> + + {/* main container */} +
+ {/* main content */} +
+ {/* {children} */} +
+
+ + {children} +
+
+
+
+ + + ) +} diff --git a/apps/design-system/app/(app)/page.tsx b/apps/design-system/app/(app)/page.tsx new file mode 100644 index 0000000000..7d22b66af8 --- /dev/null +++ b/apps/design-system/app/(app)/page.tsx @@ -0,0 +1,113 @@ +import { DesignSystemMarks } from '@/components/design-system-marks' +import { HomepageSvgHandler } from '@/components/homepage-svg-handler' +import Image from 'next/image' +import { Separator } from 'ui' + +export default function Home() { + return ( +
+
+
+ {/*
+ +
*/} +
+

Supabase Design System

+

+ Design resources for building consistent user experiences +

+
+
+ + {/* Homepage items */} + +
+
+ +
+

Atom components

+

Building blocks of User interfaces

+
+
+
+ +
+

Fragment components

+

Components assembled from Atoms

+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+

Colors

+

Building blocks of User interfaces

+
+
+
+ +
+

Theming

+

Components assembled from Atoms

+
+
+ +
+ +
+

Background / Surfaces

+

Building blocks of User interfaces

+
+
+
+ +
+

Icons

+

Components assembled from Atoms

+
+
+
+
+
+ ) +} diff --git a/apps/design-system/app/Providers.tsx b/apps/design-system/app/Providers.tsx new file mode 100644 index 0000000000..be3bdf7861 --- /dev/null +++ b/apps/design-system/app/Providers.tsx @@ -0,0 +1,18 @@ +'use client' + +import * as React from 'react' +import { Provider as JotaiProvider } from 'jotai' +import { ThemeProvider as NextThemesProvider } from 'next-themes' +import { ThemeProviderProps } from 'next-themes/dist/types' + +import { TooltipProvider_Shadcn_ } from 'ui' + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return ( + + + {children} + + + ) +} diff --git a/apps/design-system/app/favicon.ico b/apps/design-system/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/apps/design-system/app/globals.css b/apps/design-system/app/globals.css new file mode 100644 index 0000000000..f7f07cd643 --- /dev/null +++ b/apps/design-system/app/globals.css @@ -0,0 +1,29 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* :root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} */ + +body { + /* color: rgb(var(--foreground-rgb)); + background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb))) + rgb(var(--background-start-rgb)); */ +} +/* +@layer utilities { + .text-balance { + text-wrap: balance; + } +} */ diff --git a/apps/design-system/app/layout.tsx b/apps/design-system/app/layout.tsx new file mode 100644 index 0000000000..7e8ff99a5a --- /dev/null +++ b/apps/design-system/app/layout.tsx @@ -0,0 +1,38 @@ +import '@/styles/globals.css' +import type { Metadata } from 'next' +import { Inter } from 'next/font/google' +import { ThemeProvider } from './Providers' + +const inter = Inter({ subsets: ['latin'] }) + +export const metadata: Metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +interface RootLayoutProps { + children: React.ReactNode +} + +export default async function Layout({ children }: RootLayoutProps) { + // console.log('Root Layout mounted or re-rendered') + + return ( + + + + +
+
{children}
+
+
+ + + ) +} diff --git a/apps/design-system/components/callout.tsx b/apps/design-system/components/callout.tsx new file mode 100644 index 0000000000..63ed3afc9b --- /dev/null +++ b/apps/design-system/components/callout.tsx @@ -0,0 +1,17 @@ +import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_ } from 'ui' + +interface CalloutProps { + icon?: string + title?: string + children?: React.ReactNode +} + +export function Callout({ title, children, icon, ...props }: CalloutProps) { + return ( + + {icon && {icon}} + {title && {title}} + {children} + + ) +} diff --git a/apps/design-system/components/class-label.tsx b/apps/design-system/components/class-label.tsx new file mode 100644 index 0000000000..6575c2f437 --- /dev/null +++ b/apps/design-system/components/class-label.tsx @@ -0,0 +1,18 @@ +import * as React from 'react' + +const ClassLabel = React.forwardRef( + ({ children }, ref) => { + return ( + + {children} + + ) + } +) + +ClassLabel.displayName = 'ClassLabel' + +export { ClassLabel } diff --git a/apps/design-system/components/click-counter.tsx b/apps/design-system/components/click-counter.tsx new file mode 100644 index 0000000000..df68cb14cd --- /dev/null +++ b/apps/design-system/components/click-counter.tsx @@ -0,0 +1,16 @@ +'use client' + +import { useState } from 'react' + +export function ClickCounter() { + const [count, setCount] = useState(0) + + return ( + + ) +} diff --git a/apps/design-system/components/code-block-wrapper.tsx b/apps/design-system/components/code-block-wrapper.tsx new file mode 100644 index 0000000000..c347400671 --- /dev/null +++ b/apps/design-system/components/code-block-wrapper.tsx @@ -0,0 +1,53 @@ +'use client' + +import * as React from 'react' + +import { cn } from 'ui' +import { Button } from 'ui' +import { + Collapsible_Shadcn_ as Collapsible, + CollapsibleContent_Shadcn_ as CollapsibleContent, + CollapsibleTrigger_Shadcn_ as CollapsibleTrigger, +} from 'ui' + +interface CodeBlockProps extends React.HTMLAttributes { + expandButtonTitle?: string +} + +export function CodeBlockWrapper({ + expandButtonTitle = 'View Code', + className, + children, + ...props +}: CodeBlockProps) { + const [isOpened, setIsOpened] = React.useState(false) + + return ( + +
+ +
+ {children} +
+
+
+ + + +
+
+
+ ) +} diff --git a/apps/design-system/components/code-fragment.tsx b/apps/design-system/components/code-fragment.tsx new file mode 100644 index 0000000000..afe821331d --- /dev/null +++ b/apps/design-system/components/code-fragment.tsx @@ -0,0 +1,107 @@ +'use client' + +import { Index } from '@/__registry__' +import * as React from 'react' + +import { useConfig } from '@/hooks/use-config' +import { cn } from 'ui' + +import { styles } from '@/registry/styles' + +interface ComponentPreviewProps extends React.HTMLAttributes { + name: string + extractClassname?: boolean + extractedClassNames?: string + align?: 'center' | 'start' | 'end' + peekCode?: boolean + showGrid?: boolean + showDottedGrid?: boolean + wide?: boolean +} + +export function CodeFragment({ + name, + children, + className, + extractClassname, + extractedClassNames, + align = 'center', + peekCode = false, + showGrid = false, + showDottedGrid = true, + wide = false, + ...props +}: ComponentPreviewProps) { + const [config] = useConfig() + const index = styles.findIndex((style) => style.name === config.style) + + const Codes = React.Children.toArray(children) as React.ReactElement[] + const Code = Codes[index] + + const [expand, setExpandState] = React.useState(false) + + const Preview = React.useMemo(() => { + // console.log('Index', Index) + // console.log('name', name) + // console.log('config.style', config.style) + + const Component = Index[config.style][name]?.component + // const Component = Index[name]?.component + + if (!Component) { + return ( +

+ Code fragment{' '} + + {name} + {' '} + not found in registry. +

+ ) + } + + return + }, [name, config.style]) + + const ComponentPreview = React.useMemo(() => { + return ( + <> +
+ Loading...
+ } + > + {Preview} + + + + ) + }, [Preview, align]) + + const wideClasses = wide ? '2xl:-ml-12 2xl:-mr-12' : '' + + return ( +
+
+ {showGrid && ( +
+ )} + {showDottedGrid && ( +
+ )} +
{ComponentPreview}
+
+
+ ) +} diff --git a/apps/design-system/components/colors.tsx b/apps/design-system/components/colors.tsx new file mode 100644 index 0000000000..e1d63267d0 --- /dev/null +++ b/apps/design-system/components/colors.tsx @@ -0,0 +1,155 @@ +import { cn } from 'ui/src/lib/utils/cn' +// import { Card } from '@ui/components/shadcn/ui/card' +import color from 'ui/src/lib/tailwind-demo-classes' +import { Grid, GridItem } from './grid' + +const Colors = ({ + definition, +}: { + definition: 'background' | 'border' | 'text' | 'colors' | 'palletes' +}) => { + const Example = ({ x }: { x: string }) => { + switch (definition) { + case 'background': + return ( +
+ ) + break + + case 'border': + return
+ break + + case 'text': + return ( + + Postgres + + ) + break + + case 'colors': + return ( +
+ ) + break + + case 'palletes': + return ( +
+ ) + break + + default: + break + } + } + + return ( + <> + + {color[definition].map((x: string, i) => { + return ( + + + + {x} + + + ) + })} + + + ) +} + +{ + /*
+
+
+
Background
+
+ {color.background.map((x: string, i) => { + return ( +
+
+
+ {x} +
+
+ ) + })} +
+
+
+
Border
+
+ {color.border.map((x, i) => { + return ( +
+
+
+ {x} +
+
+ ) + })} +
+
+
+
texts
+
+ {color.text.map((x, i) => { + return ( +
+ + ### + +
+ {x} +
+
+ ) + })} +
+
+
+
+
+
Colors
+
+ {color.colors.map((x: string, i) => { + return ( +
+
+
+ {x} +
+
+ ) + })} +
+
+
+
Palletes
+
+ {color.palletes.map((x, i) => { + return ( +
+
+
+ {x} +
+
+ ) + })} +
+
+
+
*/ +} + +export { Colors } diff --git a/apps/design-system/components/command-menu.tsx b/apps/design-system/components/command-menu.tsx new file mode 100644 index 0000000000..bc6aa3c9fa --- /dev/null +++ b/apps/design-system/components/command-menu.tsx @@ -0,0 +1,132 @@ +'use client' + +import * as React from 'react' +import { useRouter } from 'next/navigation' +import { DialogProps } from '@radix-ui/react-alert-dialog' +import { CircleIcon, FileIcon, LaptopIcon, MoonIcon, SunIcon } from 'lucide-react' +import { useTheme } from 'next-themes' + +import { docsConfig } from '@/config/docs' +import { cn } from '@/lib/utils' +import { Button } from 'ui' +import { + CommandDialog, + CommandEmpty_Shadcn_, + CommandGroup_Shadcn_, + CommandInput_Shadcn_, + CommandItem_Shadcn_, + CommandList_Shadcn_, + CommandSeparator_Shadcn_, +} from 'ui' + +export function CommandMenu({ ...props }: DialogProps) { + const router = useRouter() + const [open, setOpen] = React.useState(false) + const { setTheme } = useTheme() + + React.useEffect(() => { + const down = (e: KeyboardEvent) => { + if ((e.key === 'k' && (e.metaKey || e.ctrlKey)) || e.key === '/') { + if ( + (e.target instanceof HTMLElement && e.target.isContentEditable) || + e.target instanceof HTMLInputElement || + e.target instanceof HTMLTextAreaElement || + e.target instanceof HTMLSelectElement + ) { + return + } + + e.preventDefault() + setOpen((open) => !open) + } + } + + document.addEventListener('keydown', down) + return () => document.removeEventListener('keydown', down) + }, []) + + const runCommand = React.useCallback((command: () => unknown) => { + setOpen(false) + command() + }, []) + + return ( + <> + + + + + No results found. + {/* + {docsConfig.mainNav + .filter((navitem) => !navitem.external) + .map((navItem) => ( + { + runCommand(() => router.push(navItem.href as string)) + }} + > + + {navItem.title} + + ))} + */} + {docsConfig.sidebarNav.map((group) => ( + + {group.items.map((navItem) => ( + { + runCommand(() => router.push(navItem.href as string)) + }} + > +
+ +
+ {navItem.title} +
+ ))} +
+ ))} + + + runCommand(() => setTheme('light'))}> + + Light + + runCommand(() => setTheme('dark'))}> + + Dark + + runCommand(() => setTheme('deep-dark'))}> + + Deep Dark + + runCommand(() => setTheme('system'))}> + + System + + +
+
+ + ) +} diff --git a/apps/design-system/components/component-example.tsx b/apps/design-system/components/component-example.tsx new file mode 100644 index 0000000000..4a4ae25ff3 --- /dev/null +++ b/apps/design-system/components/component-example.tsx @@ -0,0 +1,97 @@ +'use client' + +import * as React from 'react' + +import { cn } from 'ui' +import { + // CopyButton, + CopyWithClassNames, +} from '@/components/copy-button' +import { + Tabs_Shadcn_ as Tabs, + TabsContent_Shadcn_ as TabsContent, + TabsList_Shadcn_ as TabsList, + TabsTrigger_Shadcn_ as TabsTrigger, +} from 'ui' + +interface ComponentExampleProps extends React.HTMLAttributes { + extractClassname?: boolean + extractedClassNames?: string + align?: 'center' | 'start' | 'end' + src?: string +} + +export function ComponentExample({ + children, + className, + extractClassname, + extractedClassNames, + align = 'center', + src: _, + ...props +}: ComponentExampleProps) { + const [Example, Code, ...Children] = React.Children.toArray(children) as React.ReactElement[] + + const codeString = React.useMemo(() => { + if (typeof Code?.props['data-rehype-pretty-code-fragment'] !== 'undefined') { + const [, Button] = React.Children.toArray(Code.props.children) as React.ReactElement[] + return Button?.props?.value || Button?.props?.__rawString__ || null + } + }, [Code]) + + return ( +
+ +
+ + + Preview + + + Code + + + { + extractedClassNames ? ( + + ) : undefined + // codeString && + } +
+ +
+ {Example} +
+
+ +
+
+ {Code} +
+ {Children?.length ? ( +
+ {Children} +
+ ) : null} +
+
+
+
+ ) +} diff --git a/apps/design-system/components/component-preview.tsx b/apps/design-system/components/component-preview.tsx new file mode 100644 index 0000000000..744f02e076 --- /dev/null +++ b/apps/design-system/components/component-preview.tsx @@ -0,0 +1,260 @@ +'use client' + +import * as React from 'react' +import { Index } from '@/__registry__' + +import { + Button, + CollapsibleContent_Shadcn_, + CollapsibleTrigger_Shadcn_, + Collapsible_Shadcn_, + cn, +} from 'ui' +import { useConfig } from '@/hooks/use-config' +import { + // CopyButton, + CopyWithClassNames, +} from '@/components/copy-button' +// import { Icons } from '@/components/icons' +// import { StyleSwitcher } from '@/components/style-switcher' +// import { ThemeWrapper } from '@/components/theme-wrapper' +import { + Tabs_Shadcn_ as Tabs, + TabsContent_Shadcn_ as TabsContent, + TabsList_Shadcn_ as TabsList, + TabsTrigger_Shadcn_ as TabsTrigger, +} from 'ui' + +// import { LoaderCircle } from 'lucide-react' + +import { styles } from '@/registry/styles' +import { ChevronRight, Expand } from 'lucide-react' + +interface ComponentPreviewProps extends React.HTMLAttributes { + name: string + extractClassname?: boolean + extractedClassNames?: string + align?: 'center' | 'start' | 'end' + peekCode?: boolean + showGrid?: boolean + showDottedGrid?: boolean + wide?: boolean +} + +export function ComponentPreview({ + name, + children, + className, + extractClassname, + extractedClassNames, + align = 'center', + peekCode = false, + showGrid = false, + showDottedGrid = true, + wide = false, + ...props +}: ComponentPreviewProps) { + const [config] = useConfig() + const index = styles.findIndex((style) => style.name === config.style) + + const Codes = React.Children.toArray(children) as React.ReactElement[] + const Code = Codes[index] + + const [expand, setExpandState] = React.useState(false) + + const Preview = React.useMemo(() => { + // console.log('Index', Index) + // console.log('name', name) + // console.log('config.style', config.style) + + const Component = Index[config.style][name]?.component + // const Component = Index[name]?.component + + if (!Component) { + return ( +

+ Component{' '} + + {name} + {' '} + not found in registry. +

+ ) + } + + return + }, [name, config.style]) + + const codeString = React.useMemo(() => { + if (typeof Code?.props['data-rehype-pretty-code-fragment'] !== 'undefined') { + const [, Button] = React.Children.toArray(Code.props.children) as React.ReactElement[] + return Button?.props?.value || Button?.props?.__rawString__ || null + } + }, [Code]) + + const ComponentPreview = React.useMemo(() => { + return ( + <> + {/* */} +
+ + {/* */} + {/* */} + Loading... +
+ } + > + {Preview} + + + {/*
*/} + + ) + }, [Preview, align]) + + const wideClasses = wide ? '2xl:-ml-12 2xl:-mr-12' : '' + + if (peekCode) { + return ( +
+
+ {showGrid && ( +
+ )} + {showDottedGrid && ( +
+ )} +
{ComponentPreview}
+ {/*
*/} +
+
+
+ {Code} +
+ +
+
+
+
+ ) + } + + return ( +
+
+ {showGrid && ( +
+ )} + {showDottedGrid && ( +
+ )} +
{ComponentPreview}
+ {/*
*/} +
+ + + + View code + + +
+ {Code} +
+
+
+
+ ) + + return ( +
+ +
+ + + Preview + + + Code + + +
+ + {ComponentPreview} + + +
+
+ {Code} +
+
+
+
+
+ ) +} diff --git a/apps/design-system/components/component-props.tsx b/apps/design-system/components/component-props.tsx new file mode 100644 index 0000000000..de41a1ac42 --- /dev/null +++ b/apps/design-system/components/component-props.tsx @@ -0,0 +1,58 @@ +import fs from 'fs' +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from 'ui' +// import { parse } from 'react-docgen' + +export function ComponentProps(props: any) { + // map through all props types for this component DropdownMenu + // return a table with the prop name, type, default value, and description + + // const code = ` + // /** My first component */ + // export default ({ name }: { name: string }) =>
{{name}}
; + // ` + + // const documentation = parse(code) + // + // console.log(documentation) + + // console.log('from the component props', JSON.parse(props.docs)) + + const docs = JSON.parse(props.docs) + + // console.log(docs.props) + + return ( +
+

{props.children}

+ + + + + Prop Name + Required + Type + + Description + + + + + {Object.entries(docs.props).map(([propName, prop], index) => ( + + {propName} + {/* + // @ts-ignore */} + {prop.required ? 'Yes' : 'No'} + {/* + // @ts-ignore */} + {prop.flowType.name} + {/* + // @ts-ignore */} + {prop.description} + + ))} + +
+
+ ) +} diff --git a/apps/design-system/components/component-source.tsx b/apps/design-system/components/component-source.tsx new file mode 100644 index 0000000000..c63d4e4931 --- /dev/null +++ b/apps/design-system/components/component-source.tsx @@ -0,0 +1,21 @@ +'use client' + +import * as React from 'react' + +import { cn } from 'ui' +import { CodeBlockWrapper } from '@/components/code-block-wrapper' + +interface ComponentSourceProps extends React.HTMLAttributes { + src: string +} + +export function ComponentSource({ children, className, ...props }: ComponentSourceProps) { + return ( + + {children} + + ) +} diff --git a/apps/design-system/components/copy-button.tsx b/apps/design-system/components/copy-button.tsx new file mode 100644 index 0000000000..ed823d518c --- /dev/null +++ b/apps/design-system/components/copy-button.tsx @@ -0,0 +1,179 @@ +'use client' + +import * as React from 'react' +import { DropdownMenuTriggerProps } from '@radix-ui/react-dropdown-menu' + +// import { NpmCommands } from 'types/unist' + +// import { Event, trackEvent } from '@/lib/events' +import { cn } from 'ui' +import { Button } from 'ui' +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from 'ui' +import { Check, Copy } from 'lucide-react' + +interface CopyButtonProps extends React.HTMLAttributes { + value: string + src?: string + // event?: Event['name'] +} + +export async function copyToClipboardWithMeta( + value: string + // event?: Event +) { + navigator.clipboard.writeText(value) + if (event) { + // trackEvent(event) + } +} + +export function CopyButton({ + value, + className, + src, + // event, + ...props +}: CopyButtonProps) { + const [hasCopied, setHasCopied] = React.useState(false) + + React.useEffect(() => { + setTimeout(() => { + setHasCopied(false) + }, 2000) + }, [hasCopied]) + + return ( + + ) +} + +interface CopyWithClassNamesProps extends DropdownMenuTriggerProps { + value: string + classNames: string + className?: string +} + +export function CopyWithClassNames({ + value, + classNames, + className, + ...props +}: CopyWithClassNamesProps) { + const [hasCopied, setHasCopied] = React.useState(false) + + React.useEffect(() => { + setTimeout(() => { + setHasCopied(false) + }, 2000) + }, [hasCopied]) + + const copyToClipboard = React.useCallback((value: string) => { + copyToClipboardWithMeta(value) + setHasCopied(true) + }, []) + + return ( + + + + + + copyToClipboard(value)}>Component + copyToClipboard(classNames)}>Classname + + + ) +} + +interface CopyNpmCommandButtonProps extends DropdownMenuTriggerProps { + // commands: Required +} + +// export function CopyNpmCommandButton({ commands, className, ...props }: CopyNpmCommandButtonProps) { +// const [hasCopied, setHasCopied] = React.useState(false) + +// React.useEffect(() => { +// setTimeout(() => { +// setHasCopied(false) +// }, 2000) +// }, [hasCopied]) + +// // const copyCommand = React.useCallback((value: string, pm: 'npm' | 'pnpm' | 'yarn' | 'bun') => { +// // copyToClipboardWithMeta(value, +// // // { +// // // name: 'copy_npm_command', +// // // properties: { +// // // command: value, +// // // pm, +// // // }, +// // }) +// // setHasCopied(true) +// // }, []) + +// return ( +// +// +// +// +// +// copyCommand(commands.__npmCommand__, 'npm')}> +// npm +// +// copyCommand(commands.__yarnCommand__, 'yarn')}> +// yarn +// +// copyCommand(commands.__pnpmCommand__, 'pnpm')}> +// pnpm +// +// copyCommand(commands.__bunCommand__, 'bun')}> +// bun +// +// +// +// ) +// } diff --git a/apps/design-system/components/design-system-marks.tsx b/apps/design-system/components/design-system-marks.tsx new file mode 100644 index 0000000000..fab36f9399 --- /dev/null +++ b/apps/design-system/components/design-system-marks.tsx @@ -0,0 +1,19 @@ +'use client' + +import SVG from 'react-inlinesvg' +import { useTheme } from 'next-themes' + +function DesignSystemMarks() { + const { resolvedTheme } = useTheme() + + const isDark = resolvedTheme?.includes('dark') + + return ( + + ) +} + +export { DesignSystemMarks } diff --git a/apps/design-system/components/example-label.tsx b/apps/design-system/components/example-label.tsx new file mode 100644 index 0000000000..6774d8e1bb --- /dev/null +++ b/apps/design-system/components/example-label.tsx @@ -0,0 +1,15 @@ +import * as React from 'react' + +const ExampleLabel = React.forwardRef( + ({ children }, ref) => { + return ( + + {children} + + ) + } +) + +ExampleLabel.displayName = 'ExampleLabel' + +export { ExampleLabel } diff --git a/apps/design-system/components/grid.tsx b/apps/design-system/components/grid.tsx new file mode 100644 index 0000000000..659117a773 --- /dev/null +++ b/apps/design-system/components/grid.tsx @@ -0,0 +1,62 @@ +import { forwardRef } from 'react' +import { cn } from 'ui' + +const Grid = forwardRef>( + ({ children, ...props }, ref) => { + return ( +
+ {children} +
+ ) + } +) + +Grid.displayName = 'Grid' + +const GridItem = forwardRef>( + ({ children, ...props }, ref) => { + return ( +
+
+ {children} +
+ ) + } +) + +GridItem.displayName = 'GridItem' + +export { Grid, GridItem } diff --git a/apps/design-system/components/homepage-svg-handler.tsx b/apps/design-system/components/homepage-svg-handler.tsx new file mode 100644 index 0000000000..e359eb0e83 --- /dev/null +++ b/apps/design-system/components/homepage-svg-handler.tsx @@ -0,0 +1,19 @@ +'use client' + +import SVG from 'react-inlinesvg' +import { useTheme } from 'next-themes' + +const HomepageSvgHandler = ({ name }: { name: string }) => { + const { resolvedTheme } = useTheme() + + return ( +
+ +
+ ) +} + +export { HomepageSvgHandler } diff --git a/apps/design-system/components/icons.tsx b/apps/design-system/components/icons.tsx new file mode 100644 index 0000000000..8642a9d17c --- /dev/null +++ b/apps/design-system/components/icons.tsx @@ -0,0 +1,70 @@ +import { Index } from 'icons/__registry__/index' +import { Copy } from 'lucide-react' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuTrigger, + IconCopy, +} from 'ui' +import { Grid, GridItem } from './grid' + +function Icons() { + return ( + <> + + {Index.map((icon: any, i: number) => ( + + + + + + {icon.name} + + + + + + navigator.clipboard.writeText(icon.name)} + > + + Copy name + + navigator.clipboard.writeText(icon.jsx)} + > + + Copy JSX + + navigator.clipboard.writeText(icon.import)} + > + + Copy import path + + navigator.clipboard.writeText(icon.svg)} + > + + Copy SVG + + + + + ))} + + + ) +} + +export { Icons } diff --git a/apps/design-system/components/mdx-components.tsx b/apps/design-system/components/mdx-components.tsx new file mode 100644 index 0000000000..691e2edbda --- /dev/null +++ b/apps/design-system/components/mdx-components.tsx @@ -0,0 +1,291 @@ +'use client' + +import * as React from 'react' +import Image from 'next/image' +import Link from 'next/link' +import { useMDXComponent } from 'next-contentlayer2/hooks' +// import { NpmCommands } from 'types/unist' +// import { Event } from '@/lib/events' +import { cn } from 'ui' +import { useConfig } from '@/hooks/use-config' +import { Callout } from '@/components/callout' +import { CodeBlockWrapper } from '@/components/code-block-wrapper' +import { ComponentExample } from '@/components/component-example' +import { ComponentPreview } from '@/components/component-preview' +import { ComponentSource } from '@/components/component-source' +import { + CopyButton, + // CopyNpmCommandButton +} from '@/components/copy-button' +// import { FrameworkDocs } from '@/components/framework-docs' +import { StyleWrapper } from './style-wrapper' +import { + Accordion_Shadcn_ as Accordion, + AccordionContent_Shadcn_ as AccordionContent, + AccordionItem_Shadcn_ as AccordionItem, + AccordionTrigger_Shadcn_ as AccordionTrigger, +} from 'ui' +import { + Alert_Shadcn_ as Alert, + AlertDescription_Shadcn_ as AlertDescription, + AlertTitle_Shadcn_ as AlertTitle, +} from 'ui' +import { AspectRatio } from 'ui' +import { + Tabs_Shadcn_ as Tabs, + TabsContent_Shadcn_ as TabsContent, + TabsList_Shadcn_ as TabsList, + TabsTrigger_Shadcn_ as TabsTrigger, +} from 'ui' +import { ComponentProps } from './component-props' +import { Style } from '@/registry/styles' +import { Colors } from '@/components/colors' +import { Icons } from '@/components/icons' +import { ThemeSettings } from '@/components/theme-settings' +import { CodeFragment } from '@/components/code-fragment' + +const components = { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, + Alert, + AlertTitle, + AlertDescription, + h1: ({ className, ...props }: React.HTMLAttributes) => ( +

+ ), + h2: ({ className, ...props }: React.HTMLAttributes) => ( +

+ ), + h3: ({ className, ...props }: React.HTMLAttributes) => ( +

+ ), + h4: ({ className, ...props }: React.HTMLAttributes) => ( +

+ ), + h5: ({ className, ...props }: React.HTMLAttributes) => ( +
+ ), + h6: ({ className, ...props }: React.HTMLAttributes) => ( +
+ ), + a: ({ className, ...props }: React.HTMLAttributes) => ( + + ), + p: ({ className, ...props }: React.HTMLAttributes) => ( +

+ ), + ul: ({ className, ...props }: React.HTMLAttributes) => ( +

    + ), + ol: ({ className, ...props }: React.HTMLAttributes) => ( +
      + ), + li: ({ className, ...props }: React.HTMLAttributes) => ( +
    1. + ), + blockquote: ({ className, ...props }: React.HTMLAttributes) => ( +
      + ), + img: ({ className, alt, ...props }: React.ImgHTMLAttributes) => ( + // eslint-disable-next-line @next/next/no-img-element + {alt} + ), + hr: ({ ...props }: React.HTMLAttributes) => ( +
      + ), + table: ({ className, ...props }: React.HTMLAttributes) => ( +
      + + + ), + tr: ({ className, ...props }: React.HTMLAttributes) => ( + + ), + th: ({ className, ...props }: React.HTMLAttributes) => ( +
      + ), + td: ({ className, ...props }: React.HTMLAttributes) => ( + + ), + pre: ( + { + className, + __rawString__, + // __npmCommand__, + // __yarnCommand__, + // __pnpmCommand__, + // __bunCommand__, + __withMeta__, + __src__, + // __event__, + __style__, + ...props + }: React.HTMLAttributes & { + __style__?: Style['name'] + __rawString__?: string + __withMeta__?: boolean + __src__?: string + // __event__?: Event['name'] + } + // & NpmCommands + ) => { + return ( + +
      +        {__rawString__ && (
      +          // !__npmCommand__ &&
      +          
      +        )}
      +        {/* {__npmCommand__ && __yarnCommand__ && __pnpmCommand__ && __bunCommand__ && (
      +          
      +        )} */}
      +      
      +    )
      +  },
      +  code: ({ className, ...props }: React.HTMLAttributes) => (
      +    
      +  ),
      +  Image,
      +  Callout,
      +  ComponentPreview,
      +  ComponentExample,
      +  ComponentSource,
      +  ComponentProps,
      +  AspectRatio,
      +  CodeBlockWrapper: ({ ...props }) => ,
      +  Step: ({ className, ...props }: React.ComponentProps<'h3'>) => (
      +    

      + ), + Steps: ({ ...props }) => ( +
      + ), + Tabs: ({ className, ...props }: React.ComponentProps) => ( + + ), + TabsList: ({ className, ...props }: React.ComponentProps) => ( + + ), + TabsTrigger: ({ className, ...props }: React.ComponentProps) => ( + + ), + TabsContent: ({ className, ...props }: React.ComponentProps) => ( + + ), + // FrameworkDocs: ({ className, ...props }: React.ComponentProps) => ( + // + // ), + Link: ({ className, ...props }: React.ComponentProps) => ( + + ), + LinkedCard: ({ className, ...props }: React.ComponentProps) => ( + + ), + Colors, + Icons, + ThemeSettings, + CodeFragment, +} + +interface MdxProps { + code: string +} + +export function Mdx({ code }: MdxProps) { + const [config] = useConfig() + const Component = useMDXComponent(code, { + style: config.style, + }) + + return ( +
      + +
      + ) +} diff --git a/apps/design-system/components/pager.tsx b/apps/design-system/components/pager.tsx new file mode 100644 index 0000000000..9dd476b33d --- /dev/null +++ b/apps/design-system/components/pager.tsx @@ -0,0 +1,72 @@ +import Link from 'next/link' +import { Doc } from 'contentlayer/generated' +import { NavItem, NavItemWithChildren } from '@/types/nav' + +import { docsConfig } from '@/config/docs' +import { cn } from '@/lib/utils' +import { buttonVariants } from 'ui' +import { ChevronLeft, ChevronRight } from 'lucide-react' + +interface DocsPagerProps { + doc: Doc +} + +export function DocsPager({ doc }: DocsPagerProps) { + const pager = getPagerForDoc(doc) + + if (!pager) { + return null + } + + return ( +
      + {pager?.prev?.href && ( + + +
      + + Previous + + {pager.prev.title} +
      + + )} + {pager?.next?.href && ( + +
      + + Next + + {pager.next.title} +
      + + + )} +
      + ) +} + +export function getPagerForDoc(doc: Doc) { + const flattenedLinks = [null, ...flatten(docsConfig.sidebarNav), null] + const activeIndex = flattenedLinks.findIndex((link) => doc.slug === link?.href) + const prev = activeIndex !== 0 ? flattenedLinks[activeIndex - 1] : null + const next = activeIndex !== flattenedLinks.length - 1 ? flattenedLinks[activeIndex + 1] : null + return { + prev, + next, + } +} + +export function flatten(links: NavItemWithChildren[]): NavItem[] { + return links + .reduce((flat, link) => { + return flat.concat(link.items?.length ? flatten(link.items) : link) + }, []) + .filter((link) => !link?.disabled) +} diff --git a/apps/design-system/components/side-navigation-item.tsx b/apps/design-system/components/side-navigation-item.tsx new file mode 100644 index 0000000000..c22e53aa7e --- /dev/null +++ b/apps/design-system/components/side-navigation-item.tsx @@ -0,0 +1,43 @@ +'use client' + +import { SidebarNavItem } from '@/types/nav' +import { cn } from 'ui/src/lib/utils/cn' +import { usePathname } from 'next/navigation' +import Link from 'next/link' +import React from 'react' + +const NavigationItem: React.FC<{ item: SidebarNavItem }> = React.memo(({ item }) => { + const pathname = usePathname() + + const isActive = pathname === item.href + + return ( + +
      + {item.title} + + ) +}) + +NavigationItem.displayName = 'NavigationItem' + +export default NavigationItem diff --git a/apps/design-system/components/side-navigation.tsx b/apps/design-system/components/side-navigation.tsx new file mode 100644 index 0000000000..3924337c37 --- /dev/null +++ b/apps/design-system/components/side-navigation.tsx @@ -0,0 +1,21 @@ +import { docsConfig } from '@/config/docs' +import NavigationItem from '@/components/side-navigation-item' + +function SideNavigation() { + return ( + + ) +} + +export default SideNavigation diff --git a/apps/design-system/components/site-footer.tsx b/apps/design-system/components/site-footer.tsx new file mode 100644 index 0000000000..d05d343575 --- /dev/null +++ b/apps/design-system/components/site-footer.tsx @@ -0,0 +1,61 @@ +import { siteConfig } from '@/config/site' + +export function SiteFooter() { + return ( + + ) +} diff --git a/apps/design-system/components/source-panel.tsx b/apps/design-system/components/source-panel.tsx new file mode 100644 index 0000000000..04dc897204 --- /dev/null +++ b/apps/design-system/components/source-panel.tsx @@ -0,0 +1,206 @@ +import { Doc } from '@/.contentlayer/generated' +import Link from 'next/link' +import { forwardRef } from 'react' + +import { ExternalLink } from 'lucide-react' +import { Button } from 'ui' +import { cn } from 'ui/src/lib/utils/cn' +import Image from 'next/image' + +const SourcePanel = forwardRef & { doc: Doc }>( + ({ doc, children, ...props }, ref) => { + const label = { + radix: 'Radix UI', + vaul: 'Vaul', + shadcn: 'ui.shadcn', + } + + const ShadcnPanel = () => { + if (doc.source?.shadcn) { + return ( +
      +
      + + + + + + shadcn/ui +
      + + This component is based on ui.shadcn + +
      + ) + } + } + + const VaulPanel = () => { + if (doc.source?.vaul) { + return ( +
      +
      + Vaul + vaul +
      + + This component is based on vaul by emilkowalski + +
      + ) + } + } + + const InputOtp = () => { + if (doc.source?.inputOtp) { + return ( +
      +
      + inputOtp + input-otp +
      + + This component is based on input-otp by guilhermerodz + +
      + ) + } + } + + const RadixPanel = () => { + if (doc.source?.radix) { + return ( +
      + + + + + + + +
      + This component uses Radix UI + {doc.links ? ( +
      + {doc.links?.doc && ( + + )} + {doc.links?.api && ( + + )} +
      + ) : null} +
      +
      + ) + } + } + + return ( +
      + + + + {/* */} +
      + ) + } +) + +SourcePanel.displayName = 'SourcePanel' + +export { SourcePanel } diff --git a/apps/design-system/components/style-wrapper.tsx b/apps/design-system/components/style-wrapper.tsx new file mode 100644 index 0000000000..4937cad099 --- /dev/null +++ b/apps/design-system/components/style-wrapper.tsx @@ -0,0 +1,20 @@ +'use client' + +import * as React from 'react' + +import { useConfig } from '@/hooks/use-config' +import { Style } from '@/registry/styles' + +interface StyleWrapperProps extends React.HTMLAttributes { + styleName?: Style['name'] +} + +export function StyleWrapper({ styleName, children }: StyleWrapperProps) { + const [config] = useConfig() + + if (!styleName || config.style === styleName) { + return <>{children} + } + + return null +} diff --git a/apps/design-system/components/theme-settings.tsx b/apps/design-system/components/theme-settings.tsx new file mode 100644 index 0000000000..0d06e68b37 --- /dev/null +++ b/apps/design-system/components/theme-settings.tsx @@ -0,0 +1,54 @@ +'use client' + +import { useTheme } from 'next-themes' +import { useEffect, useState } from 'react' + +import SVG from 'react-inlinesvg' +import { RadioGroupLargeItem_Shadcn_, RadioGroup_Shadcn_, Theme, singleThemes } from 'ui' + +const ThemeSettings = () => { + const [mounted, setMounted] = useState(false) + const { theme, setTheme } = useTheme() + + /** + * Avoid Hydration Mismatch + * https://github.com/pacocoursey/next-themes?tab=readme-ov-file#avoid-hydration-mismatch + */ + // useEffect only runs on the client, so now we can safely show the UI + useEffect(() => { + setMounted(true) + }, []) + + if (!mounted) { + return null + } + + function SingleThemeSelection() { + return ( +
      + + {singleThemes.map((theme: Theme) => ( + + + + ))} + +
      + ) + } + + return ( + <> + + + ) +} + +export { ThemeSettings } diff --git a/apps/design-system/components/theme-switcher-dropdown.tsx b/apps/design-system/components/theme-switcher-dropdown.tsx new file mode 100644 index 0000000000..4796194c07 --- /dev/null +++ b/apps/design-system/components/theme-switcher-dropdown.tsx @@ -0,0 +1,92 @@ +'use client' + +import { Moon, Sun } from 'lucide-react' +import { useTheme } from 'next-themes' +import { useEffect, useState } from 'react' +import SVG from 'react-inlinesvg' +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuTrigger, + RadioGroupLargeItem_Shadcn_, + RadioGroup_Shadcn_, + Theme, + singleThemes, +} from 'ui' + +const ThemeSwitcherDropdown = () => { + const [mounted, setMounted] = useState(false) + const { theme, setTheme, resolvedTheme } = useTheme() + + /** + * Avoid Hydration Mismatch + * https://github.com/pacocoursey/next-themes?tab=readme-ov-file#avoid-hydration-mismatch + */ + // useEffect only runs on the client, so now we can safely show the UI + useEffect(() => { + setMounted(true) + }, []) + + if (!mounted) { + return null + } + + function SingleThemeSelection() { + return ( +
      + +
      + ) + } + + const iconClasses = 'text-foreground-light group-data-[state=open]:text-foreground' + + return ( + <> + + + + + + Theme + + setTheme(themeValue)} + > + {singleThemes.map((theme: Theme) => ( + + {theme.name} + + ))} + + + + + ) +} + +export { ThemeSwitcherDropdown } diff --git a/apps/design-system/components/toc.tsx b/apps/design-system/components/toc.tsx new file mode 100644 index 0000000000..d796b84518 --- /dev/null +++ b/apps/design-system/components/toc.tsx @@ -0,0 +1,107 @@ +// @ts-nocheck +'use client' + +import * as React from 'react' + +import { TableOfContents } from '@/lib/toc' +import { cn } from '@/lib/utils' +import { useMounted } from '@/hooks/use-mounted' + +interface TocProps { + toc: TableOfContents +} + +export function DashboardTableOfContents({ toc }: TocProps) { + const itemIds = React.useMemo( + () => + toc.items + ? toc.items + .flatMap((item) => [item.url, item?.items?.map((item) => item.url)]) + .flat() + .filter(Boolean) + .map((id) => id?.split('#')[1]) + : [], + [toc] + ) + const activeHeading = useActiveItem(itemIds) + const mounted = useMounted() + + if (!toc?.items || !mounted) { + return null + } + + return ( +
      +

      On This Page

      + +
      + ) +} + +function useActiveItem(itemIds: string[]) { + const [activeId, setActiveId] = React.useState(null) + + React.useEffect(() => { + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + setActiveId(entry.target.id) + } + }) + }, + { rootMargin: `0% 0% -80% 0%` } + ) + + itemIds?.forEach((id) => { + const element = document.getElementById(id) + if (element) { + observer.observe(element) + } + }) + + return () => { + itemIds?.forEach((id) => { + const element = document.getElementById(id) + if (element) { + observer.unobserve(element) + } + }) + } + }, [itemIds]) + + return activeId +} + +interface TreeProps { + tree: TableOfContents + level?: number + activeItem?: string +} + +function Tree({ tree, level = 1, activeItem }: TreeProps) { + return tree?.items?.length && level < 3 ? ( +
        + {tree.items.map((item, index) => { + return ( +
      • + + {item.title} + + {item.items?.length ? ( + + ) : null} +
      • + ) + })} +
      + ) : null +} diff --git a/apps/design-system/components/top-navigation-search.tsx b/apps/design-system/components/top-navigation-search.tsx new file mode 100644 index 0000000000..3de4610238 --- /dev/null +++ b/apps/design-system/components/top-navigation-search.tsx @@ -0,0 +1,17 @@ +'use client' + +import { Search } from 'lucide-react' +import { Input } from 'ui-patterns/DataInputs/Input' + +function TopNavigationSearch() { + return ( + } + placeholder="Search Design System..." + /> + ) +} + +export { TopNavigationSearch } diff --git a/apps/design-system/components/top-navigation.tsx b/apps/design-system/components/top-navigation.tsx new file mode 100644 index 0000000000..7301be52fc --- /dev/null +++ b/apps/design-system/components/top-navigation.tsx @@ -0,0 +1,38 @@ +// import { docsConfig } from '@/config/docs' +import Link from 'next/link' +import { DesignSystemMarks } from './design-system-marks' +import { ThemeSwitcherDropdown } from './theme-switcher-dropdown' +import { TopNavigationSearch } from './top-navigation-search' +import { CommandMenu } from './command-menu' + +function TopNavigation() { + return ( +
      +
      + +
      + ) +} + +export default TopNavigation diff --git a/apps/design-system/config/docs.ts b/apps/design-system/config/docs.ts new file mode 100644 index 0000000000..5d56ad87a5 --- /dev/null +++ b/apps/design-system/config/docs.ts @@ -0,0 +1,335 @@ +import { MainNavItem, SidebarNavItem } from 'types/nav' + +interface DocsConfig { + mainNav?: MainNavItem[] + sidebarNav: SidebarNavItem[] +} + +export const docsConfig: DocsConfig = { + // mainNav: [ + // { + // title: 'Documentation', + // href: '/docs', + // }, + // { + // title: 'Components', + // href: '/docs/components/accordion', + // }, + // { + // title: 'Themes', + // href: '/themes', + // }, + // { + // title: 'Examples', + // href: '/examples', + // }, + // { + // title: 'Blocks', + // href: '/blocks', + // }, + // ], + sidebarNav: [ + { + title: 'Getting Started', + items: [ + { + title: 'Introduction', + href: '/docs', + items: [], + }, + { + title: 'Color usage', + href: '/docs/color-usage', + items: [], + }, + { + title: 'Tailwind classes', + href: '/docs/tailwind-classes', + items: [], + }, + { + title: 'Theming', + href: '/docs/theming', + items: [], + }, + { + title: 'Icons', + href: '/docs/icons', + items: [], + }, + { + title: 'Figma', + href: '/docs/figma', + items: [], + }, + { + title: 'Changelog', + href: '/docs/changelog', + items: [], + }, + ], + }, + { + title: 'Fragment Components', + items: [ + { + title: 'Text Confirm Dialog', + href: '/docs/fragments/text-confirm-dialog', + items: [], + }, + { + title: 'Form Item Layout', + href: '/docs/fragments/form-item-layout', + items: [], + }, + ], + }, + { + title: 'Atom Components', + items: [ + { + title: 'Accordion', + href: '/docs/components/accordion', + items: [], + }, + { + title: 'Alert', + href: '/docs/components/alert', + items: [], + }, + { + title: 'Alert Dialog', + href: '/docs/components/alert-dialog', + items: [], + }, + { + title: 'Aspect Ratio', + href: '/docs/components/aspect-ratio', + items: [], + }, + { + title: 'Avatar', + href: '/docs/components/avatar', + items: [], + }, + { + title: 'Badge', + href: '/docs/components/badge', + items: [], + }, + { + title: 'Breadcrumb', + href: '/docs/components/breadcrumb', + items: [], + label: 'New', + }, + { + title: 'Button', + href: '/docs/components/button', + items: [], + }, + { + title: 'Calendar', + href: '/docs/components/calendar', + items: [], + }, + { + title: 'Card', + href: '/docs/components/card', + items: [], + }, + { + title: 'Carousel', + href: '/docs/components/carousel', + items: [], + }, + { + title: 'Checkbox', + href: '/docs/components/checkbox', + items: [], + }, + { + title: 'Collapsible', + href: '/docs/components/collapsible', + items: [], + }, + { + title: 'Combobox', + href: '/docs/components/combobox', + items: [], + }, + { + title: 'Command', + href: '/docs/components/command', + items: [], + }, + { + title: 'Context Menu', + href: '/docs/components/context-menu', + items: [], + }, + { + title: 'Data Table', + href: '/docs/components/data-table', + items: [], + }, + { + title: 'Date Picker', + href: '/docs/components/date-picker', + items: [], + }, + { + title: 'Dialog', + href: '/docs/components/dialog', + items: [], + }, + { + title: 'Drawer', + href: '/docs/components/drawer', + items: [], + }, + { + title: 'Dropdown Menu', + href: '/docs/components/dropdown-menu', + items: [], + }, + { + title: 'Form', + href: '/docs/components/form', + items: [], + }, + { + title: 'Hover Card', + href: '/docs/components/hover-card', + items: [], + }, + { + title: 'Input', + href: '/docs/components/input', + items: [], + }, + { + title: 'Input OTP', + href: '/docs/components/input-otp', + items: [], + label: 'New', + }, + { + title: 'Label', + href: '/docs/components/label', + items: [], + }, + { + title: 'Menubar', + href: '/docs/components/menubar', + items: [], + }, + { + title: 'Navigation Menu', + href: '/docs/components/navigation-menu', + items: [], + }, + { + title: 'Pagination', + href: '/docs/components/pagination', + items: [], + }, + { + title: 'Popover', + href: '/docs/components/popover', + items: [], + }, + { + title: 'Progress', + href: '/docs/components/progress', + items: [], + }, + { + title: 'Radio Group', + href: '/docs/components/radio-group', + items: [], + }, + { + title: 'Resizable', + href: '/docs/components/resizable', + items: [], + }, + { + title: 'Scroll Area', + href: '/docs/components/scroll-area', + items: [], + }, + { + title: 'Select', + href: '/docs/components/select', + items: [], + }, + { + title: 'Separator', + href: '/docs/components/separator', + items: [], + }, + { + title: 'Sheet', + href: '/docs/components/sheet', + items: [], + }, + { + title: 'Skeleton', + href: '/docs/components/skeleton', + items: [], + }, + { + title: 'Slider', + href: '/docs/components/slider', + items: [], + }, + { + title: 'Sonner', + href: '/docs/components/sonner', + items: [], + }, + { + title: 'Switch', + href: '/docs/components/switch', + items: [], + }, + { + title: 'Table', + href: '/docs/components/table', + items: [], + }, + { + title: 'Tabs', + href: '/docs/components/tabs', + items: [], + }, + { + title: 'Textarea', + href: '/docs/components/textarea', + items: [], + }, + { + title: 'Toast', + href: '/docs/components/toast', + items: [], + }, + { + title: 'Toggle', + href: '/docs/components/toggle', + items: [], + }, + { + title: 'Toggle Group', + href: '/docs/components/toggle-group', + items: [], + }, + { + title: 'Tooltip', + href: '/docs/components/tooltip', + items: [], + }, + ], + }, + ], +} diff --git a/apps/design-system/config/site.ts b/apps/design-system/config/site.ts new file mode 100644 index 0000000000..c86298e0e3 --- /dev/null +++ b/apps/design-system/config/site.ts @@ -0,0 +1,17 @@ +export const siteConfig = { + name: 'Supabase Design System', + url: 'https://supabase.com/design-system', + ogImage: 'https://supabase.com/design-system/og.jpg', + description: 'Design System of Supabase', + links: { + twitter: 'https://twitter.com/supabase', + github: 'https://github.com/supabase/supabase/apps/design-system', + credits: { + radix: 'https://www.radix-ui.com/themes/docs/overview/getting-started', + shadcn: 'https://ui.shadcn.com/', + geist: 'https://vercel.com/geist/introduction', + }, + }, +} + +export type SiteConfig = typeof siteConfig diff --git a/apps/design-system/content/docs/changelog.mdx b/apps/design-system/content/docs/changelog.mdx new file mode 100644 index 0000000000..58a251547a --- /dev/null +++ b/apps/design-system/content/docs/changelog.mdx @@ -0,0 +1,31 @@ +--- +title: Changelog +description: Latest updates and announcements. +toc: false +--- + +## May 2024 - Introducing Design System + +We're introducing **Design System**, a home for Design related resources for Supabase + + + Lift Mode + Lift Mode + View the blocks library + + +With Lift Mode, you'll be able to copy the smaller components that make up a block template, like cards, buttons, and forms, and paste them directly into your project. + +Visit the [Blocks](/blocks) page to try it out. diff --git a/apps/design-system/content/docs/color-usage.mdx b/apps/design-system/content/docs/color-usage.mdx new file mode 100644 index 0000000000..aed6907d2b --- /dev/null +++ b/apps/design-system/content/docs/color-usage.mdx @@ -0,0 +1,74 @@ +--- +title: Color usage +description: Colors system breakdown with best practise +--- + +Colors available in the Supabase Design System + +These are examples of using colors with shorthands. + +## Background + + + +### App backgrounds + +We use backgrounds in 2 different ways. In the ./www and ./docs sites, we use a darker background, so we have an extra background color we can use + +```jsx +/** + * ./www background color + * ./docs background color + */ +{children} + +/** + * ./studio background color + */ +{children} +``` + +### Backgrounds and Surfaces + +#### `./apps/www` + `./apps/docs` + +We use surfaces in 2 different ways. In the ./www and ./docs sites, we use a darker background, so we have an extra surface color we can use + + + +#### `./apps/studio` + +For the studio (dashbaord) we can use `bg-surface-100`, `bg-surface-200`, `bg-surface-300` + + + +#### Data grid and frame space + +Data grids use an alternative background color for empty space to add depth to the layout. +The background of the empty space is the same background as used in `./apps/docs` and `./apps/www` - although; the color has been mapped to `bg-alternative` so it works well across different themes. + + + +Dealing with large areas of emmpty space in data display should also be catered for. You can use the `bg-200` or `bg` class to fill the space. + +### Overlays + +We use the `./bg-overlay` background color for overlays. +This is not to be confused with `Dialogs`, they require to use the same app background color as the site. + +## Border + + + +## Text + +These can also be accessed with `foreground`. Like `text-foreground-light`. + + + +## Other Colors + +These can also be accessed with `foreground`. Like `text-foreground-light`. + + +``` diff --git a/apps/design-system/content/docs/components/accordion.mdx b/apps/design-system/content/docs/components/accordion.mdx new file mode 100644 index 0000000000..9190c8c824 --- /dev/null +++ b/apps/design-system/content/docs/components/accordion.mdx @@ -0,0 +1,139 @@ +--- +title: Accordion +description: A vertically stacked set of interactive headings that each reveal a section of content. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/accordion + api: https://www.radix-ui.com/docs/primitives/components/accordion#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + + + + +Run the following command: + +```bash +npx shadcn-ui@latest add accordion +``` + +Update `tailwind.config.js` + +Add the following animations to your `tailwind.config.js` file: + +```js title="tailwind.config.js" {5-18} +/** @type {import('tailwindcss').Config} */ +module.exports = { + theme: { + extend: { + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + }, + }, +} +``` + + + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-accordion +``` + +Copy and paste the following code into your project. + +{/* */} + +Update the import paths to match your project setup. + +Update `tailwind.config.js` + +Add the following animations to your `tailwind.config.js` file: + +```js title="tailwind.config.js" {5-18} +/** @type {import('tailwindcss').Config} */ +module.exports = { + theme: { + extend: { + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, + }, + }, +} +``` + + + + + + + +## Usage + +```tsx +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from '@/components/ui/accordion' +``` + +```tsx + + + Is it accessible? + Yes. It adheres to the WAI-ARIA design pattern. + + +``` diff --git a/apps/design-system/content/docs/components/alert copy.mdx b/apps/design-system/content/docs/components/alert copy.mdx new file mode 100644 index 0000000000..1ada949fd9 --- /dev/null +++ b/apps/design-system/content/docs/components/alert copy.mdx @@ -0,0 +1,65 @@ +--- +title: Alert +description: Displays a callout for user attention. +component: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add alert +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +``` + +```tsx + + + Heads up! + + You can add components and dependencies to your app using the cli. + + +``` + +## Examples + +### Default + + + +### Destructive + + diff --git a/apps/design-system/content/docs/components/alert-dialog.mdx b/apps/design-system/content/docs/components/alert-dialog.mdx new file mode 100644 index 0000000000..10c28d1f13 --- /dev/null +++ b/apps/design-system/content/docs/components/alert-dialog.mdx @@ -0,0 +1,87 @@ +--- +title: Alert Dialog +description: A modal dialog that interrupts the user with important content and expects a response. +featured: true +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/alert-dialog + api: https://www.radix-ui.com/docs/primitives/components/alert-dialog#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add alert-dialog +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-alert-dialog +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@/components/ui/alert-dialog' +``` + +```tsx + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your account and remove your data + from our servers. + + + + Cancel + Continue + + + +``` diff --git a/apps/design-system/content/docs/components/alert.mdx b/apps/design-system/content/docs/components/alert.mdx new file mode 100644 index 0000000000..0f0a031a2a --- /dev/null +++ b/apps/design-system/content/docs/components/alert.mdx @@ -0,0 +1,79 @@ +--- +title: Alert +description: Displays a callout for user attention. +component: true +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add alert +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' +``` + +```tsx + + + Heads up! + + You can add components and dependencies to your app using the cli. + + +``` + +## Examples + +### Default + + + +### Destructive + + diff --git a/apps/design-system/content/docs/components/aspect-ratio.mdx b/apps/design-system/content/docs/components/aspect-ratio.mdx new file mode 100644 index 0000000000..4ddf98dfdd --- /dev/null +++ b/apps/design-system/content/docs/components/aspect-ratio.mdx @@ -0,0 +1,67 @@ +--- +title: Aspect Ratio +description: Displays content within a desired ratio. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/aspect-ratio + api: https://www.radix-ui.com/docs/primitives/components/aspect-ratio#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add aspect-ratio +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-aspect-ratio +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import Image from 'next/image' + +import { AspectRatio } from '@/components/ui/aspect-ratio' +``` + +```tsx +
      + + Image + +
      +``` diff --git a/apps/design-system/content/docs/components/avatar.mdx b/apps/design-system/content/docs/components/avatar.mdx new file mode 100644 index 0000000000..f6fda6a3d8 --- /dev/null +++ b/apps/design-system/content/docs/components/avatar.mdx @@ -0,0 +1,64 @@ +--- +title: Avatar +description: An image element with a fallback for representing the user. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/avatar + api: https://www.radix-ui.com/docs/primitives/components/avatar#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add avatar +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-avatar +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +``` + +```tsx + + + CN + +``` diff --git a/apps/design-system/content/docs/components/badge.mdx b/apps/design-system/content/docs/components/badge.mdx new file mode 100644 index 0000000000..d5b22c47a7 --- /dev/null +++ b/apps/design-system/content/docs/components/badge.mdx @@ -0,0 +1,87 @@ +--- +title: Badge +description: Displays a badge or a component that looks like a badge. +component: true +source: + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add badge +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Badge } from '@/components/ui/badge' +``` + +```tsx +Badge +``` + +### Link + +You can use the `badgeVariants` helper to create a link that looks like a badge. + +```tsx +import { badgeVariants } from '@/components/ui/badge' +``` + +```tsx +Badge +``` + +## Examples + +### Default + + + +--- + +### Secondary + + + +--- + +### Outline + + + +--- + +### Destructive + + diff --git a/apps/design-system/content/docs/components/breadcrumb.mdx b/apps/design-system/content/docs/components/breadcrumb.mdx new file mode 100644 index 0000000000..4665d2938b --- /dev/null +++ b/apps/design-system/content/docs/components/breadcrumb.mdx @@ -0,0 +1,190 @@ +--- +title: Breadcrumb +description: Displays the path to the current resource using a hierarchy of links. +component: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add breadcrumb +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from '@/components/ui/breadcrumb' +``` + +```tsx + + + + Home + + + + Components + + + + Breadcrumb + + + +``` + +## Examples + +### Custom separator + +Use a custom component as `children` for `` to create a custom separator. + + + +```tsx showLineNumbers {1,10-12} +import { Slash } from "lucide-react" + +... + + + + + Home + + + + + + Components + + + +``` + +--- + +### Dropdown + +You can compose `` with a `` to create a dropdown in the breadcrumb. + + + +```tsx showLineNumbers {1-6,11-21} +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +... + + + + + Components + + + + Documentation + Themes + GitHub + + + +``` + +--- + +### Collapsed + +We provide a `` component to show a collapsed state when the breadcrumb is too long. + + + +```tsx showLineNumbers {1,9} +import { BreadcrumbEllipsis } from "@/components/ui/breadcrumb" + +... + + + + {/* ... */} + + + + {/* ... */} + + +``` + +--- + +### Link component + +To use a custom link component from your routing library, you can use the `asChild` prop on ``. + + + +```tsx showLineNumbers {1,8-10} +import { Link } from "next/link" + +... + + + + + + Home + + + {/* ... */} + + +``` + +--- + +### Responsive + +Here's an example of a responsive breadcrumb that composes `` with ``, ``, and ``. + +It displays a dropdown on desktop and a drawer on mobile. + + diff --git a/apps/design-system/content/docs/components/button.mdx b/apps/design-system/content/docs/components/button.mdx new file mode 100644 index 0000000000..f2bb59be55 --- /dev/null +++ b/apps/design-system/content/docs/components/button.mdx @@ -0,0 +1,118 @@ +--- +title: Button +description: Displays a button or a component that looks like a button. +featured: true +component: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add button +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-slot +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Button } from '@/components/ui/button' +``` + +```tsx + +``` + +## Link + +You can use the `buttonVariants` helper to create a link that looks like a button. + +```tsx +import { buttonVariants } from '@/components/ui/button' +``` + +```tsx +Click here +``` + +Alternatively, you can set the `asChild` parameter and nest the link component. + +```tsx + +``` + +## Examples + +### Primary + + + +### Secondary + + + +### Destructive + + + +### Outline + + + +### Ghost + + + +### Link + + + +### Icon + + + +### With Icon + + + +### Loading + + + +### As Child + + diff --git a/apps/design-system/content/docs/components/calendar.mdx b/apps/design-system/content/docs/components/calendar.mdx new file mode 100644 index 0000000000..9b1d4187cb --- /dev/null +++ b/apps/design-system/content/docs/components/calendar.mdx @@ -0,0 +1,81 @@ +--- +title: Calendar +description: A date field component that allows users to enter and edit date. +component: true +links: + doc: https://react-day-picker.js.org +source: + shadcn: true +--- + + + +## About + +The `Calendar` component is built on top of [React DayPicker](https://react-day-picker.js.org). + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add calendar +``` + + + + + + + +Install the following dependencies: + +```bash +npm install react-day-picker date-fns +``` + +Add the `Button` component to your project. + +The `Calendar` component uses the `Button` component. Make sure you have it installed in your project. + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Calendar } from '@/components/ui/calendar' +``` + +```tsx +const [date, setDate] = React.useState(new Date()) + +return +``` + +See the [React DayPicker](https://react-day-picker.js.org) documentation for more information. + +## Date Picker + +You can use the `` component to build a date picker. See the [Date Picker](/docs/components/date-picker) page for more information. + +## Examples + +### Form + + diff --git a/apps/design-system/content/docs/components/card.mdx b/apps/design-system/content/docs/components/card.mdx new file mode 100644 index 0000000000..32bfdc8ec0 --- /dev/null +++ b/apps/design-system/content/docs/components/card.mdx @@ -0,0 +1,71 @@ +--- +title: Card +description: Displays a card with header, content, and footer. +component: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add card +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card' +``` + +```tsx + + + Card Title + Card Description + + +

      Card Content

      +
      + +

      Card Footer

      +
      +
      +``` + +## Examples + + diff --git a/apps/design-system/content/docs/components/carousel.mdx b/apps/design-system/content/docs/components/carousel.mdx new file mode 100644 index 0000000000..71f3806892 --- /dev/null +++ b/apps/design-system/content/docs/components/carousel.mdx @@ -0,0 +1,277 @@ +--- +title: Carousel +description: A carousel with motion and swipe built using Embla. +component: true +links: + doc: https://www.embla-carousel.com/get-started/react + api: https://www.embla-carousel.com/api +--- + + + +## About + +The carousel component is built using the [Embla Carousel](https://www.embla-carousel.com/) library. + +## Installation + + + + + CLI + Manual + + + + +```bash +npx shadcn-ui@latest add carousel +``` + + + + + + + +Install the following dependencies: + +```bash +npm install embla-carousel-react +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Carousel, + CarouselContent, + CarouselItem, + CarouselNext, + CarouselPrevious, +} from '@/components/ui/carousel' +``` + +```tsx + + + ... + ... + ... + + + + +``` + +## Examples + +### Sizes + +To set the size of the items, you can use the `basis` utility class on the ``. + + + +```tsx title="Example" showLineNumbers {4-6} +// 33% of the carousel width. + + + ... + ... + ... + + +``` + +```tsx title="Responsive" showLineNumbers {4-6} +// 50% on small screens and 33% on larger screens. + + + ... + ... + ... + + +``` + +### Spacing + +To set the spacing between the items, we use a `pl-[VALUE]` utility on the `` and a negative `-ml-[VALUE]` on the ``. + + + **Why:** I tried to use the `gap` property or a `grid` layout on the ` + ` but it required a lot of math and mental effort to get the + spacing right. I found `pl-[VALUE]` and `-ml-[VALUE]` utilities much easier to + use. + +You can always adjust this in your own project if you need to. + + + + + +```tsx title="Example" showLineNumbers /-ml-4/ /pl-4/ + + + ... + ... + ... + + +``` + +```tsx title="Responsive" showLineNumbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/ + + + ... + ... + ... + + +``` + +### Orientation + +Use the `orientation` prop to set the orientation of the carousel. + + + +```tsx showLineNumbers /vertical | horizontal/ + + + ... + ... + ... + + +``` + +## Options + +You can pass options to the carousel using the `opts` prop. See the [Embla Carousel docs](https://www.embla-carousel.com/api/options/) for more information. + +```tsx showLineNumbers {2-5} + + + ... + ... + ... + + +``` + +## API + +Use a state and the `setApi` props to get an instance of the carousel API. + + + +```tsx showLineNumbers {1,4,22} +import { type CarouselApi } from '@/components/ui/carousel' + +export function Example() { + const [api, setApi] = React.useState() + const [current, setCurrent] = React.useState(0) + const [count, setCount] = React.useState(0) + + React.useEffect(() => { + if (!api) { + return + } + + setCount(api.scrollSnapList().length) + setCurrent(api.selectedScrollSnap() + 1) + + api.on('select', () => { + setCurrent(api.selectedScrollSnap() + 1) + }) + }, [api]) + + return ( + + + ... + ... + ... + + + ) +} +``` + +## Events + +You can listen to events using the api instance from `setApi`. + +```tsx showLineNumbers {1,4-14,16} +import { type CarouselApi } from '@/components/ui/carousel' + +export function Example() { + const [api, setApi] = React.useState() + + React.useEffect(() => { + if (!api) { + return + } + + api.on('select', () => { + // Do something on select. + }) + }, [api]) + + return ( + + + ... + ... + ... + + + ) +} +``` + +See the [Embla Carousel docs](https://www.embla-carousel.com/api/events/) for more information on using events. + +## Plugins + +You can use the `plugins` prop to add plugins to the carousel. + +```ts showLineNumbers {1,6-10} +import Autoplay from "embla-carousel-autoplay" + +export function Example() { + return ( + + // ... + + ) +} +``` + + + +See the [Embla Carousel docs](https://www.embla-carousel.com/api/plugins/) for more information on using plugins. diff --git a/apps/design-system/content/docs/components/checkbox.mdx b/apps/design-system/content/docs/components/checkbox.mdx new file mode 100644 index 0000000000..fc7b7180d4 --- /dev/null +++ b/apps/design-system/content/docs/components/checkbox.mdx @@ -0,0 +1,77 @@ +--- +title: Checkbox +description: A control that allows the user to toggle between checked and not checked. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/checkbox + api: https://www.radix-ui.com/docs/primitives/components/checkbox#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add checkbox +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-checkbox +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Checkbox } from '@/components/ui/checkbox' +``` + +```tsx + +``` + +## Examples + +### With text + + + +### Disabled + + + +### Form + + + + diff --git a/apps/design-system/content/docs/components/collapsible.mdx b/apps/design-system/content/docs/components/collapsible.mdx new file mode 100644 index 0000000000..3f5be4bb44 --- /dev/null +++ b/apps/design-system/content/docs/components/collapsible.mdx @@ -0,0 +1,67 @@ +--- +title: Collapsible +description: An interactive component which expands/collapses a panel. +component: true +featured: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/collapsible + api: https://www.radix-ui.com/docs/primitives/components/collapsible#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add collapsible +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-collapsible +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' +``` + +```tsx + + Can I use this in my project? + + Yes. Free to use for personal and commercial projects. No attribution required. + + +``` diff --git a/apps/design-system/content/docs/components/combobox.mdx b/apps/design-system/content/docs/components/combobox.mdx new file mode 100644 index 0000000000..209f3a5478 --- /dev/null +++ b/apps/design-system/content/docs/components/combobox.mdx @@ -0,0 +1,131 @@ +--- +title: Combobox +description: Autocomplete input and command palette with a list of suggestions. +component: true +source: + shadcn: true +--- + + + +## Installation + +The Combobox is built using a composition of the `` and the `` components. + +See installation instructions for the [Popover](/docs/components/popover#installation) and the [Command](/docs/components/command#installation) components. + +## Usage + +```tsx +'use client' + +import * as React from 'react' +import { Check, ChevronsUpDown } from 'lucide-react' + +import { cn } from '@/lib/utils' +import { Button } from '@/components/ui/button' +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, +} from '@/components/ui/command' +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' + +const frameworks = [ + { + value: 'next.js', + label: 'Next.js', + }, + { + value: 'sveltekit', + label: 'SvelteKit', + }, + { + value: 'nuxt.js', + label: 'Nuxt.js', + }, + { + value: 'remix', + label: 'Remix', + }, + { + value: 'astro', + label: 'Astro', + }, +] + +export function ComboboxDemo() { + const [open, setOpen] = React.useState(false) + const [value, setValue] = React.useState('') + + return ( + + + + + + + + No framework found. + + {frameworks.map((framework) => ( + { + setValue(currentValue === value ? '' : currentValue) + setOpen(false) + }} + > + + {framework.label} + + ))} + + + + + ) +} +``` + +## Examples + +### Combobox + + + +### Popover + + + +### Dropdown menu + + + +### Responsive + +You can create a responsive combobox by using the `` on desktop and the `` components on mobile. + + + +### Form + + diff --git a/apps/design-system/content/docs/components/command.mdx b/apps/design-system/content/docs/components/command.mdx new file mode 100644 index 0000000000..cae6977b6e --- /dev/null +++ b/apps/design-system/content/docs/components/command.mdx @@ -0,0 +1,138 @@ +--- +title: Command +description: Fast, composable, unstyled command menu for React. +component: true +links: + doc: https://cmdk.paco.me +source: + shadcn: true +--- + + + +## About + +The `` component uses the [`cmdk`](https://cmdk.paco.me) component by [pacocoursey](https://twitter.com/pacocoursey). + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add command +``` + + + + + + + +Install the following dependencies: + +```bash +npm install cmdk +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Command, + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, + CommandShortcut, +} from '@/components/ui/command' +``` + +```tsx + + + + No results found. + + Calendar + Search Emoji + Calculator + + + + Profile + Billing + Settings + + + +``` + +## Examples + +### Dialog + + + +To show the command menu in a dialog, use the `` component. + +```tsx +export function CommandMenu() { + const [open, setOpen] = React.useState(false) + + React.useEffect(() => { + const down = (e: KeyboardEvent) => { + if (e.key === 'k' && (e.metaKey || e.ctrlKey)) { + e.preventDefault() + setOpen((open) => !open) + } + } + document.addEventListener('keydown', down) + return () => document.removeEventListener('keydown', down) + }, []) + + return ( + + + + No results found. + + Calendar + Search Emoji + Calculator + + + + ) +} +``` + +### Combobox + +You can use the `` component as a combobox. See the [Combobox](/docs/components/combobox) page for more information. diff --git a/apps/design-system/content/docs/components/context-menu.mdx b/apps/design-system/content/docs/components/context-menu.mdx new file mode 100644 index 0000000000..4bd06b6baa --- /dev/null +++ b/apps/design-system/content/docs/components/context-menu.mdx @@ -0,0 +1,74 @@ +--- +title: Context Menu +description: Displays a menu to the user — such as a set of actions or functions — triggered by a button. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/context-menu + api: https://www.radix-ui.com/docs/primitives/components/context-menu#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add context-menu +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-context-menu +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuTrigger, +} from '@/components/ui/context-menu' +``` + +```tsx + + Right click + + Profile + Billing + Team + Subscription + + +``` diff --git a/apps/design-system/content/docs/components/data-table.mdx b/apps/design-system/content/docs/components/data-table.mdx new file mode 100644 index 0000000000..d2e6620145 --- /dev/null +++ b/apps/design-system/content/docs/components/data-table.mdx @@ -0,0 +1,842 @@ +--- +title: Data Table +description: Powerful table and datagrids built using TanStack Table. +component: true +links: + doc: https://tanstack.com/table/v8/docs/guide/introduction +--- + + + +## Introduction + +Every data table or datagrid I've created has been unique. They all behave differently, have specific sorting and filtering requirements, and work with different data sources. + +It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/v8/docs/guide/introduction#what-is-headless-ui) provides. + +So instead of a data-table component, I thought it would be more helpful to provide a guide on how to build your own. + +We'll start with the basic `` component and build a complex data table from scratch. + + + +**Tip:** If you find yourself using the same table in multiple places in your app, you can always extract it into a reusable component. + + + +## Table of Contents + +This guide will show you how to use [TanStack Table](https://tanstack.com/table) and the `
      ` component to build your own custom data table. We'll cover the following topics: + +- [Basic Table](#basic-table) +- [Row Actions](#row-actions) +- [Pagination](#pagination) +- [Sorting](#sorting) +- [Filtering](#filtering) +- [Visibility](#visibility) +- [Row Selection](#row-selection) +- [Reusable Components](#reusable-components) + +## Installation + +1. Add the `
      ` component to your project: + +```bash +npx shadcn-ui@latest add table +``` + +2. Add `tanstack/react-table` dependency: + +```bash +npm install @tanstack/react-table +``` + +## Prerequisites + +We are going to build a table to show recent payments. Here's what our data looks like: + +```tsx showLineNumbers +type Payment = { + id: string + amount: number + status: 'pending' | 'processing' | 'success' | 'failed' + email: string +} + +export const payments: Payment[] = [ + { + id: '728ed52f', + amount: 100, + status: 'pending', + email: 'm@example.com', + }, + { + id: '489e1d42', + amount: 125, + status: 'processing', + email: 'example@gmail.com', + }, + // ... +] +``` + +## Project Structure + +Start by creating the following file structure: + +```txt +app +└── payments + ├── columns.tsx + ├── data-table.tsx + └── page.tsx +``` + +I'm using a Next.js example here but this works for any other React framework. + +- `columns.tsx` (client component) will contain our column definitions. +- `data-table.tsx` (client component) will contain our `` component. +- `page.tsx` (server component) is where we'll fetch data and render our table. + +## Basic Table + +Let's start by building a basic table. + + + +### Column Definitions + +First, we'll define our columns. + +```tsx showLineNumbers title="app/payments/columns.tsx" {3,14-27} +'use client' + +import { ColumnDef } from '@tanstack/react-table' + +// This type is used to define the shape of our data. +// You can use a Zod schema here if you want. +export type Payment = { + id: string + amount: number + status: 'pending' | 'processing' | 'success' | 'failed' + email: string +} + +export const columns: ColumnDef[] = [ + { + accessorKey: 'status', + header: 'Status', + }, + { + accessorKey: 'email', + header: 'Email', + }, + { + accessorKey: 'amount', + header: 'Amount', + }, +] +``` + + + +**Note:** Columns are where you define the core of what your table +will look like. They define the data that will be displayed, how it will be +formatted, sorted and filtered. + + + +### `` component + +Next, we'll create a `` component to render our table. + +```tsx showLineNumbers title="app/payments/data-table.tsx" +'use client' + +import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table' + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table' + +interface DataTableProps { + columns: ColumnDef[] + data: TData[] +} + +export function DataTable({ columns, data }: DataTableProps) { + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + }) + + return ( +
      +
      + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender(header.column.columnDef.header, header.getContext())} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
      +
      + ) +} +``` + + + +**Tip**: If you find yourself using `` in multiple places, this is the component you could make reusable by extracting it to `components/ui/data-table.tsx`. + +`` + + + +### Render the table + +Finally, we'll render our table in our page component. + +```tsx showLineNumbers title="app/payments/page.tsx" {22} +import { Payment, columns } from './columns' +import { DataTable } from './data-table' + +async function getData(): Promise { + // Fetch data from your API here. + return [ + { + id: '728ed52f', + amount: 100, + status: 'pending', + email: 'm@example.com', + }, + // ... + ] +} + +export default async function DemoPage() { + const data = await getData() + + return ( +
      + +
      + ) +} +``` + + + +## Cell Formatting + +Let's format the amount cell to display the dollar amount. We'll also align the cell to the right. + + + +### Update columns definition + +Update the `header` and `cell` definitions for amount as follows: + +```tsx showLineNumbers title="app/payments/columns.tsx" {4-15} +export const columns: ColumnDef[] = [ + { + accessorKey: 'amount', + header: () =>
      Amount
      , + cell: ({ row }) => { + const amount = parseFloat(row.getValue('amount')) + const formatted = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + }).format(amount) + + return
      {formatted}
      + }, + }, +] +``` + +You can use the same approach to format other cells and headers. + +
      + +## Row Actions + +Let's add row actions to our table. We'll use a `` component for this. + + + +### Update columns definition + +Update our columns definition to add a new `actions` column. The `actions` cell returns a `` component. + +```tsx showLineNumbers title="app/payments/columns.tsx" {4,6-14,18-45} +'use client' + +import { ColumnDef } from '@tanstack/react-table' +import { MoreHorizontal } from 'lucide-react' + +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' + +export const columns: ColumnDef[] = [ + // ... + { + id: 'actions', + cell: ({ row }) => { + const payment = row.original + + return ( + + + + + + Actions + navigator.clipboard.writeText(payment.id)}> + Copy payment ID + + + View customer + View payment details + + + ) + }, + }, + // ... +] +``` + +You can access the row data using `row.original` in the `cell` function. Use this to handle actions for your row eg. use the `id` to make a DELETE call to your API. + + + +## Pagination + +Next, we'll add pagination to our table. + + + +### Update `` + +```tsx showLineNumbers title="app/payments/data-table.tsx" {5,17} +import { + ColumnDef, + flexRender, + getCoreRowModel, + getPaginationRowModel, + useReactTable, +} from '@tanstack/react-table' + +export function DataTable({ columns, data }: DataTableProps) { + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + }) + + // ... +} +``` + +This will automatically paginate your rows into pages of 10. See the [pagination docs](https://tanstack.com/table/v8/docs/api/features/pagination) for more information on customizing page size and implementing manual pagination. + +### Add pagination controls + +We can add pagination controls to our table using the ` + + + + ) +} +``` + +See [Reusable Components](#reusable-components) section for a more advanced pagination component. + + + +## Sorting + +Let's make the email column sortable. + + + +### Update `` + +```tsx showLineNumbers title="app/payments/data-table.tsx" showLineNumbers {3,6,10,18,25-28} +"use client" + +import * as React from "react" +import { + ColumnDef, + SortingState, + flexRender, + getCoreRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table" + +export function DataTable({ + columns, + data, +}: DataTableProps) { + const [sorting, setSorting] = React.useState([]) + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + state: { + sorting, + }, + }) + + return ( +
      +
      + { ... }
      +
      +
      + ) +} +``` + +### Make header cell sortable + +We can now update the `email` header cell to add sorting controls. + +```tsx showLineNumbers title="app/payments/columns.tsx" {4,9-19} +'use client' + +import { ColumnDef } from '@tanstack/react-table' +import { ArrowUpDown, MoreHorizontal } from 'lucide-react' + +export const columns: ColumnDef[] = [ + { + accessorKey: 'email', + header: ({ column }) => { + return ( + + ) + }, + }, +] +``` + +This will automatically sort the table (asc and desc) when the user toggles on the header cell. + +
      + +## Filtering + +Let's add a search input to filter emails in our table. + + + +### Update `` + +```tsx showLineNumbers title="app/payments/data-table.tsx" {6,10,17,24-26,35-36,39,45-54} +"use client" + +import * as React from "react" +import { + ColumnDef, + ColumnFiltersState, + SortingState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table" + +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" + +export function DataTable({ + columns, + data, +}: DataTableProps) { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState( + [] + ) + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + state: { + sorting, + columnFilters, + }, + }) + + return ( +
      +
      + + table.getColumn("email")?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> +
      +
      + { ... }
      +
      +
      + ) +} +``` + +Filtering is now enabled for the `email` column. You can add filters to other columns as well. See the [filtering docs](https://tanstack.com/table/v8/docs/guide/filters) for more information on customizing filters. + +
      + +## Visibility + +Adding column visibility is fairly simple using `@tanstack/react-table` visibility API. + + + +### Update `` + +```tsx showLineNumbers title="app/payments/data-table.tsx" {8,18-23,33-34,45,49,64-91} +"use client" + +import * as React from "react" +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +export function DataTable({ + columns, + data, +}: DataTableProps) { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState( + [] + ) + const [columnVisibility, setColumnVisibility] = + React.useState({}) + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + state: { + sorting, + columnFilters, + columnVisibility, + }, + }) + + return ( +
      +
      + + table.getColumn("email")?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> + + + + + + {table + .getAllColumns() + .filter( + (column) => column.getCanHide() + ) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ) + })} + + +
      +
      + { ... }
      +
      +
      + ) +} +``` + +This adds a dropdown menu that you can use to toggle column visibility. + +
      + +## Row Selection + +Next, we're going to add row selection to our table. + + + +### Update column definitions + +```tsx showLineNumbers title="app/payments/columns.tsx" {6,9-27} +'use client' + +import { ColumnDef } from '@tanstack/react-table' + +import { Badge } from '@/components/ui/badge' +import { Checkbox } from '@/components/ui/checkbox' + +export const columns: ColumnDef[] = [ + { + id: 'select', + header: ({ table }) => ( + table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, +] +``` + +### Update `` + +```tsx showLineNumbers title="app/payments/data-table.tsx" {11,23,28} +export function DataTable({ columns, data }: DataTableProps) { + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + const [columnVisibility, setColumnVisibility] = React.useState({}) + const [rowSelection, setRowSelection] = React.useState({}) + + const table = useReactTable({ + data, + columns, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + onColumnVisibilityChange: setColumnVisibility, + onRowSelectionChange: setRowSelection, + state: { + sorting, + columnFilters, + columnVisibility, + rowSelection, + }, + }) + + return ( +
      +
      + + + + ) +} +``` + +This adds a checkbox to each row and a checkbox in the header to select all rows. + +### Show selected rows + +You can show the number of selected rows using the `table.getFilteredSelectedRowModel()` API. + +```tsx +
      + {table.getFilteredSelectedRowModel().rows.length} of {table.getFilteredRowModel().rows.length}{' '} + row(s) selected. +
      +``` + + + +## Reusable Components + +Here are some components you can use to build your data tables. This is from the [Tasks](/examples/tasks) demo. + +### Column header + +Make any column header sortable and hideable. + + + +```tsx {5} +export const columns = [ + { + accessorKey: 'email', + header: ({ column }) => , + }, +] +``` + +### Pagination + +Add pagination controls to your table including page size and selection count. + + + +```tsx + +``` + +### Column toggle + +A component to toggle column visibility. + + + +```tsx + +``` diff --git a/apps/design-system/content/docs/components/date-picker.mdx b/apps/design-system/content/docs/components/date-picker.mdx new file mode 100644 index 0000000000..0848ee3bdb --- /dev/null +++ b/apps/design-system/content/docs/components/date-picker.mdx @@ -0,0 +1,74 @@ +--- +title: Date Picker +description: A date picker component with range and presets. +component: true +source: + shadcn: true +--- + + + +## Installation + +The Date Picker is built using a composition of the `` and the `` components. + +See installation instructions for the [Popover](/docs/components/popover#installation) and the [Calendar](/docs/components/calendar#installation) components. + +## Usage + +```tsx +'use client' + +import * as React from 'react' +import { format } from 'date-fns' +import { Calendar as CalendarIcon } from 'lucide-react' + +import { cn } from '@/lib/utils' +import { Button } from '@/components/ui/button' +import { Calendar } from '@/components/ui/calendar' +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' + +export function DatePickerDemo() { + const [date, setDate] = React.useState() + + return ( + + + + + + + + + ) +} +``` + +See the [React DayPicker](https://react-day-picker.js.org) documentation for more information. + +## Examples + +### Date Picker + + + +### Date Range Picker + + + +### With Presets + + + +### Form + + diff --git a/apps/design-system/content/docs/components/dialog.mdx b/apps/design-system/content/docs/components/dialog.mdx new file mode 100644 index 0000000000..47d29e96eb --- /dev/null +++ b/apps/design-system/content/docs/components/dialog.mdx @@ -0,0 +1,120 @@ +--- +title: Dialog +description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. +featured: true +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/dialog + api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add dialog +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-dialog +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' +``` + +```tsx + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your account and remove your data + from our servers. + + + + +``` + +## Examples + +### Custom close button + + + +## Notes + +To activate the `Dialog` component from within a `Context Menu` or `Dropdown Menu`, you must encase the `Context Menu` or +`Dropdown Menu` component in the `Dialog` component. For more information, refer to the linked issue [here](https://github.com/radix-ui/primitives/issues/1836). + +```tsx {14-25} + + + Right click + + Open + Download + + + Delete + + + + + + + Are you absolutely sure? + + This action cannot be undone. Are you sure you want to permanently delete this file from our + servers? + + + + + + + +``` diff --git a/apps/design-system/content/docs/components/drawer.mdx b/apps/design-system/content/docs/components/drawer.mdx new file mode 100644 index 0000000000..1767e43266 --- /dev/null +++ b/apps/design-system/content/docs/components/drawer.mdx @@ -0,0 +1,95 @@ +--- +title: Drawer +description: A drawer component for React. +component: true +links: + doc: https://github.com/emilkowalski/vaul +source: + vaul: true + shadcn: true +--- + + + +## About + +Drawer is built on top of [Vaul](https://github.com/emilkowalski/vaul) by [emilkowalski\_](https://twitter.com/emilkowalski_). + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add drawer +``` + + + + + + + +Install the following dependencies: + +```bash +npm install vaul +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx showLineNumbers +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from '@/components/ui/drawer' +``` + +```tsx showLineNumbers + + Open + + + Are you absolutely sure? + This action cannot be undone. + + + + + + + + + +``` + +## Examples + +### Responsive Dialog + +You can combine the `Dialog` and `Drawer` components to create a responsive dialog. This renders a `Dialog` component on desktop and a `Drawer` on mobile. + + diff --git a/apps/design-system/content/docs/components/dropdown-menu.mdx b/apps/design-system/content/docs/components/dropdown-menu.mdx new file mode 100644 index 0000000000..daccc38aa8 --- /dev/null +++ b/apps/design-system/content/docs/components/dropdown-menu.mdx @@ -0,0 +1,95 @@ +--- +title: Dropdown Menu +description: Displays a menu to the user — such as a set of actions or functions — triggered by a button. +featured: true +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/dropdown-menu + api: https://www.radix-ui.com/docs/primitives/components/dropdown-menu#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + +So I guess I can write anything i want in here. + +## Props + +{/* */} + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add dropdown-menu +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-dropdown-menu +``` + +Copy and paste the following code into your project. + +{/* */} + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +``` + +```tsx + + Open + + My Account + + Profile + Billing + Team + Subscription + + +``` + +## Examples + +### Checkboxes + + + +### Radio Group + + diff --git a/apps/design-system/content/docs/components/form.mdx b/apps/design-system/content/docs/components/form.mdx new file mode 100644 index 0000000000..f69cff2305 --- /dev/null +++ b/apps/design-system/content/docs/components/form.mdx @@ -0,0 +1,255 @@ +--- +title: React Hook Form +description: Building forms with React Hook Form and Zod. +links: + doc: https://react-hook-form.com +source: + shadcn: true +--- + +Forms are tricky. They are one of the most common things you'll build in a web application, but also one of the most complex. + +Well-designed HTML forms are: + +- Well-structured and semantically correct. +- Easy to use and navigate (keyboard). +- Accessible with ARIA attributes and proper labels. +- Has support for client and server side validation. +- Well-styled and consistent with the rest of the application. + +In this guide, we will take a look at building forms with [`react-hook-form`](https://react-hook-form.com/) and [`zod`](https://zod.dev). We're going to use a `` component to compose accessible forms using Radix UI components. + +## Features + +The `
      ` component is a wrapper around the `react-hook-form` library. It provides a few things: + +- Composable components for building forms. +- A `` component for building controlled form fields. +- Form validation using `zod`. +- Handles accessibility and error messages. +- Uses `React.useId()` for generating unique IDs. +- Applies the correct `aria` attributes to form fields based on states. +- Built to work with all Radix UI components. +- Bring your own schema library. We use `zod` but you can use anything you want. +- **You have full control over the markup and styling.** + +## Anatomy + +```tsx + + ( + + + + { /* Your form field */} + + + + + )} + /> + +``` + +## Example + +```tsx +const form = useForm() + + ( + + Username + + + + This is your public display name. + + + )} +/> +``` + +## Installation + + + + + CLI + Manual + + + + + +### Command + +```bash +npx shadcn-ui@latest add form +``` + + + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-label @radix-ui/react-slot react-hook-form @hookform/resolvers zod +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + + + +### Create a form schema + +Define the shape of your form using a Zod schema. You can read more about using Zod in the [Zod documentation](https://zod.dev). + +```tsx showLineNumbers {3,5-7} +'use client' + +import { z } from 'zod' + +const formSchema = z.object({ + username: z.string().min(2).max(50), +}) +``` + +### Define a form + +Use the `useForm` hook from `react-hook-form` to create a form. + +```tsx showLineNumbers {3-4,14-20,22-27} +'use client' + +import { zodResolver } from '@hookform/resolvers/zod' +import { useForm } from 'react-hook-form' +import { z } from 'zod' + +const formSchema = z.object({ + username: z.string().min(2, { + message: 'Username must be at least 2 characters.', + }), +}) + +export function ProfileForm() { + // 1. Define your form. + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + username: '', + }, + }) + + // 2. Define a submit handler. + function onSubmit(values: z.infer) { + // Do something with the form values. + // ✅ This will be type-safe and validated. + console.log(values) + } +} +``` + +Since `FormField` is using a controlled component, you need to provide a default value for the field. See the [React Hook Form docs](https://react-hook-form.com/docs/usecontroller) to learn more about controlled components. + +### Build your form + +We can now use the `
      ` components to build our form. + +```tsx showLineNumbers {7-17,28-50} +'use client' + +import { zodResolver } from '@hookform/resolvers/zod' +import { useForm } from 'react-hook-form' +import { z } from 'zod' + +import { Button } from '@/components/ui/button' +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form' +import { Input } from '@/components/ui/input' + +const formSchema = z.object({ + username: z.string().min(2, { + message: 'Username must be at least 2 characters.', + }), +}) + +export function ProfileForm() { + // ... + + return ( + + + ( + + Username + + + + This is your public display name. + + + )} + /> + + + + ) +} +``` + +### Done + +That's it. You now have a fully accessible form that is type-safe with client-side validation. + + + +
      + +## Examples + +See the following links for more examples on how to use the `
      ` component with other components: + +- [Checkbox](/docs/components/checkbox#form) +- [Date Picker](/docs/components/date-picker#form) +- [Input](/docs/components/input#form) +- [Radio Group](/docs/components/radio-group#form) +- [Select](/docs/components/select#form) +- [Switch](/docs/components/switch#form) +- [Textarea](/docs/components/textarea#form) +- [Combobox](/docs/components/combobox#form) diff --git a/apps/design-system/content/docs/components/hover-card.mdx b/apps/design-system/content/docs/components/hover-card.mdx new file mode 100644 index 0000000000..7d666ede67 --- /dev/null +++ b/apps/design-system/content/docs/components/hover-card.mdx @@ -0,0 +1,64 @@ +--- +title: Hover Card +description: For sighted users to preview content available behind a link. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/hover-card + api: https://www.radix-ui.com/docs/primitives/components/hover-card#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add hover-card +``` + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-hover-card +``` + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card' +``` + +```tsx + + Hover + The React Framework – created and maintained by @vercel. + +``` diff --git a/apps/design-system/content/docs/components/input-otp.mdx b/apps/design-system/content/docs/components/input-otp.mdx new file mode 100644 index 0000000000..6743207ab8 --- /dev/null +++ b/apps/design-system/content/docs/components/input-otp.mdx @@ -0,0 +1,191 @@ +--- +title: Input OTP +description: Accessible one-time password component with copy paste functionality. +component: true +links: + doc: https://input-otp.rodz.dev +source: + shadcn: true + inputOtp: true +--- + + + +## About + +Input OTP is built on top of [input-otp](https://github.com/guilhermerodz/input-otp) by [@guilherme_rodz](https://twitter.com/guilherme_rodz). + +## Installation + + + + + CLI + Manual + + + + + +Run the following command: + +```bash +npx shadcn-ui@latest add input-otp +``` + +Update `tailwind.config.js` + +Add the following animations to your `tailwind.config.js` file: + +```js showLineNumbers title="tailwind.config.js" {6-9,12} +/** @type {import('tailwindcss').Config} */ +module.exports = { + theme: { + extend: { + keyframes: { + 'caret-blink': { + '0%,70%,100%': { opacity: '1' }, + '20%,50%': { opacity: '0' }, + }, + }, + animation: { + 'caret-blink': 'caret-blink 1.25s ease-out infinite', + }, + }, + }, +} +``` + + + + + + + + + +Install the following dependencies: + +```bash +npm install input-otp +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + +Update `tailwind.config.js` + +Add the following animations to your `tailwind.config.js` file: + +```js showLineNumbers title="tailwind.config.js" {6-9,12} +/** @type {import('tailwindcss').Config} */ +module.exports = { + theme: { + extend: { + keyframes: { + 'caret-blink': { + '0%,70%,100%': { opacity: '1' }, + '20%,50%': { opacity: '0' }, + }, + }, + animation: { + 'caret-blink': 'caret-blink 1.25s ease-out infinite', + }, + }, + }, +} +``` + + + + + + + +## Usage + +```tsx +import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from '@/components/ui/input-otp' +``` + +```tsx + + + + + + + + + + + + + +``` + +## Examples + +### Pattern + +Use the `pattern` prop to define a custom pattern for the OTP input. + + + +```tsx showLineNumbers {1,7} +import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp" + +... + + + + + {/* ... */} + + +``` + +### Separator + +You can use the `` component to add a separator between the input groups. + + + +```tsx showLineNumbers {4,15} +import { + InputOTP, + InputOTPGroup, + InputOTPSeparator, + InputOTPSlot, +} from "@/components/ui/input-otp" + +... + + + + + + + + + + + + +``` + +### Controlled + +You can use the `value` and `onChange` props to control the input value. + + + +### Form + + diff --git a/apps/design-system/content/docs/components/input.mdx b/apps/design-system/content/docs/components/input.mdx new file mode 100644 index 0000000000..fdbdd85a6a --- /dev/null +++ b/apps/design-system/content/docs/components/input.mdx @@ -0,0 +1,77 @@ +--- +title: Input +description: Displays a form input field or a component that looks like an input field. +component: true +source: + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add input +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Input } from '@/components/ui/input' +``` + +```tsx + +``` + +## Examples + +### Default + + + +### File + + + +### Disabled + + + +### With Label + + + +### With Button + + + +### Form + + diff --git a/apps/design-system/content/docs/components/label.mdx b/apps/design-system/content/docs/components/label.mdx new file mode 100644 index 0000000000..c2d59c1a99 --- /dev/null +++ b/apps/design-system/content/docs/components/label.mdx @@ -0,0 +1,61 @@ +--- +title: Label +description: Renders an accessible label associated with controls. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/label + api: https://www.radix-ui.com/docs/primitives/components/label#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add label +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-label +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Label } from '@/components/ui/label' +``` + +```tsx + +``` diff --git a/apps/design-system/content/docs/components/menubar.mdx b/apps/design-system/content/docs/components/menubar.mdx new file mode 100644 index 0000000000..ff88641610 --- /dev/null +++ b/apps/design-system/content/docs/components/menubar.mdx @@ -0,0 +1,83 @@ +--- +title: Menubar +description: A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/menubar + api: https://www.radix-ui.com/docs/primitives/components/menubar#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add menubar +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-menubar +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Menubar, + MenubarContent, + MenubarItem, + MenubarMenu, + MenubarSeparator, + MenubarShortcut, + MenubarTrigger, +} from '@/components/ui/menubar' +``` + +```tsx + + + File + + + New Tab ⌘T + + New Window + + Share + + Print + + + +``` diff --git a/apps/design-system/content/docs/components/navigation-menu.mdx b/apps/design-system/content/docs/components/navigation-menu.mdx new file mode 100644 index 0000000000..042dc0945d --- /dev/null +++ b/apps/design-system/content/docs/components/navigation-menu.mdx @@ -0,0 +1,99 @@ +--- +title: Navigation Menu +description: A collection of links for navigating websites. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/navigation-menu + api: https://www.radix-ui.com/docs/primitives/components/navigation-menu#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add navigation-menu +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-navigation-menu +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + NavigationMenu, + NavigationMenuContent, + NavigationMenuIndicator, + NavigationMenuItem, + NavigationMenuLink, + NavigationMenuList, + NavigationMenuTrigger, + NavigationMenuViewport, +} from '@/components/ui/navigation-menu' +``` + +```tsx + + + + Item One + + Link + + + + +``` + +## Examples + +### Link Component + +When using the Next.js `` component, you can use `navigationMenuTriggerStyle()` to apply the correct styles to the trigger. + +```tsx +import { navigationMenuTriggerStyle } from '@/components/ui/navigation-menu' +``` + +```tsx {3-5} + + + Documentation + + +``` + +See also the [Radix UI documentation](https://www.radix-ui.com/docs/primitives/components/navigation-menu#with-client-side-routing) for handling client side routing. diff --git a/apps/design-system/content/docs/components/pagination.mdx b/apps/design-system/content/docs/components/pagination.mdx new file mode 100644 index 0000000000..e5fbf62620 --- /dev/null +++ b/apps/design-system/content/docs/components/pagination.mdx @@ -0,0 +1,104 @@ +--- +title: Pagination +description: Pagination with page navigation, next and previous links. +component: true +source: + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add pagination +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Pagination, + PaginationContent, + PaginationEllipsis, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious, +} from '@/components/ui/pagination' +``` + +```tsx + + + + + + + 1 + + + + + + + + + +``` + +### Next.js + +By default the `` component will render an `` tag. + +To use the Next.js `` component, make the following updates to `pagination.tsx`. + +```diff showLineNumbers /typeof Link/ {1} ++ import Link from "next/link" + +- type PaginationLinkProps = ... & React.ComponentProps<"a"> ++ type PaginationLinkProps = ... & React.ComponentProps + +const PaginationLink = ({...props }: ) => ( + +- ++ + // ... +- ++ + +) + +``` + + + +**Note:** We are making updates to the cli to automatically do this for you. + + diff --git a/apps/design-system/content/docs/components/popover.mdx b/apps/design-system/content/docs/components/popover.mdx new file mode 100644 index 0000000000..f04fe012c8 --- /dev/null +++ b/apps/design-system/content/docs/components/popover.mdx @@ -0,0 +1,64 @@ +--- +title: Popover +description: Displays rich content in a portal, triggered by a button. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/popover + api: https://www.radix-ui.com/docs/primitives/components/popover#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add popover +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-popover +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' +``` + +```tsx + + Open + Place content for the popover here. + +``` diff --git a/apps/design-system/content/docs/components/progress.mdx b/apps/design-system/content/docs/components/progress.mdx new file mode 100644 index 0000000000..a187c3421a --- /dev/null +++ b/apps/design-system/content/docs/components/progress.mdx @@ -0,0 +1,61 @@ +--- +title: Progress +description: Displays an indicator showing the completion progress of a task, typically displayed as a progress bar. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/progress + api: https://www.radix-ui.com/docs/primitives/components/progress#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add progress +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-progress +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Progress } from '@/components/ui/progress' +``` + +```tsx + +``` diff --git a/apps/design-system/content/docs/components/radio-group.mdx b/apps/design-system/content/docs/components/radio-group.mdx new file mode 100644 index 0000000000..8bd7e79ac5 --- /dev/null +++ b/apps/design-system/content/docs/components/radio-group.mdx @@ -0,0 +1,77 @@ +--- +title: Radio Group +description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/radio-group + api: https://www.radix-ui.com/docs/primitives/components/radio-group#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add radio-group +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-radio-group +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Label } from '@/components/ui/label' +import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' +``` + +```tsx + +
      + + +
      +
      + + +
      +
      +``` + +## Examples + +### Form + + diff --git a/apps/design-system/content/docs/components/resizable.mdx b/apps/design-system/content/docs/components/resizable.mdx new file mode 100644 index 0000000000..b06c1af8f2 --- /dev/null +++ b/apps/design-system/content/docs/components/resizable.mdx @@ -0,0 +1,110 @@ +--- +title: Resizable +description: Accessible resizable panel groups and layouts with keyboard support. +component: true +links: + doc: https://github.com/bvaughn/react-resizable-panels + api: https://github.com/bvaughn/react-resizable-panels/tree/main/packages/react-resizable-panels +source: + shadcn: true +--- + + + +## About + +The `Resizable` component is built on top of [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) by [bvaughn](https://github.com/bvaughn). + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add resizable +``` + + + + + + + +Install the following dependencies: + +```bash +npm install react-resizable-panels +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable' +``` + +```tsx + + One + + Two + +``` + +## Examples + +### Vertical + +Use the `direction` prop to set the direction of the resizable panels. + + + +```tsx showLineNumbers {9} +import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable' + +export default function Example() { + return ( + + One + + Two + + ) +} +``` + +### Handle + +You can set or hide the handle by using the `withHandle` prop on the `ResizableHandle` component. + + + +```tsx showLineNumbers {11} +import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable' + +export default function Example() { + return ( + + One + + Two + + ) +} +``` diff --git a/apps/design-system/content/docs/components/scroll-area.mdx b/apps/design-system/content/docs/components/scroll-area.mdx new file mode 100644 index 0000000000..55d039eec5 --- /dev/null +++ b/apps/design-system/content/docs/components/scroll-area.mdx @@ -0,0 +1,73 @@ +--- +title: Scroll-area +description: Augments native scroll functionality for custom, cross-browser styling. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/scroll-area + api: https://www.radix-ui.com/docs/primitives/components/scroll-area#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add scroll-area +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-scroll-area +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { ScrollArea } from '@/components/ui/scroll-area' +``` + +```tsx + + Jokester began sneaking into the castle in the middle of the night and leaving jokes all over the + place: under the king's pillow, in his soup, even in the royal toilet. The king was furious, but + he couldn't seem to stop Jokester. And then, one day, the people of the kingdom discovered that + the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started + laughing, they couldn't stop. + +``` + +## Examples + +### Horizontal Scrolling + + diff --git a/apps/design-system/content/docs/components/select.mdx b/apps/design-system/content/docs/components/select.mdx new file mode 100644 index 0000000000..64a0fd5181 --- /dev/null +++ b/apps/design-system/content/docs/components/select.mdx @@ -0,0 +1,87 @@ +--- +title: Select +description: Displays a list of options for the user to pick from—triggered by a button. +component: true +featured: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/select + api: https://www.radix-ui.com/docs/primitives/components/select#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add select +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-select +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +``` + +```tsx + +``` + +## Examples + +### Scrollable + + + +### Form + + diff --git a/apps/design-system/content/docs/components/separator.mdx b/apps/design-system/content/docs/components/separator.mdx new file mode 100644 index 0000000000..92fa9bc2b4 --- /dev/null +++ b/apps/design-system/content/docs/components/separator.mdx @@ -0,0 +1,59 @@ +--- +title: Separator +description: Visually or semantically separates content. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/separator + api: https://www.radix-ui.com/docs/primitives/components/separator#api-reference +source: + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add separator +``` + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-separator +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Separator } from '@/components/ui/separator' +``` + +```tsx + +``` diff --git a/apps/design-system/content/docs/components/sheet.mdx b/apps/design-system/content/docs/components/sheet.mdx new file mode 100644 index 0000000000..96220e63eb --- /dev/null +++ b/apps/design-system/content/docs/components/sheet.mdx @@ -0,0 +1,106 @@ +--- +title: Sheet +description: Extends the Dialog component to display content that complements the main content of the screen. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/dialog + api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add sheet +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-dialog +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +### Usage + +```tsx +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from '@/components/ui/sheet' +``` + +```tsx + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your account and remove your data + from our servers. + + + + +``` + +## Examples + +### Side + +Use the `side` property to `` to indicate the edge of the screen where the component will appear. The values can be `top`, `right`, `bottom` or `left`. + + + +### Size + +You can adjust the size of the sheet using CSS classes: + +```tsx {3} + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your account and remove your data + from our servers. + + + + +``` diff --git a/apps/design-system/content/docs/components/skeleton.mdx b/apps/design-system/content/docs/components/skeleton.mdx new file mode 100644 index 0000000000..5ab50f0250 --- /dev/null +++ b/apps/design-system/content/docs/components/skeleton.mdx @@ -0,0 +1,57 @@ +--- +title: Skeleton +description: Use to show a placeholder while content is loading. +component: true +source: + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add skeleton +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Skeleton } from '@/components/ui/skeleton' +``` + +```tsx + +``` + +## Examples + +### Card + + diff --git a/apps/design-system/content/docs/components/slider.mdx b/apps/design-system/content/docs/components/slider.mdx new file mode 100644 index 0000000000..e2f1120559 --- /dev/null +++ b/apps/design-system/content/docs/components/slider.mdx @@ -0,0 +1,61 @@ +--- +title: Slider +description: An input where the user selects a value from within a given range. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/slider + api: https://www.radix-ui.com/docs/primitives/components/slider#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add slider +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-slider +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Slider } from '@/components/ui/slider' +``` + +```tsx + +``` diff --git a/apps/design-system/content/docs/components/sonner.mdx b/apps/design-system/content/docs/components/sonner.mdx new file mode 100644 index 0000000000..3af18cfd4a --- /dev/null +++ b/apps/design-system/content/docs/components/sonner.mdx @@ -0,0 +1,103 @@ +--- +title: Sonner +description: An opinionated toast component for React. +component: true +links: + doc: https://sonner.emilkowal.ski +source: + shadcn: true +--- + + + +## About + +Sonner is built and maintained by [emilkowalski\_](https://twitter.com/emilkowalski_). + +## Installation + + + + + CLI + Manual + + + + + +Run the following command: + +```bash +npx shadcn-ui@latest add sonner +``` + +Add the Toaster component + +```tsx title="app/layout.tsx" {1,9} +import { Toaster } from '@/components/ui/sonner' + +export default function RootLayout({ children }) { + return ( + + + +
      {children}
      + + + + ) +} +``` + +
      + +
      + + + + + +Install the following dependencies: + +```bash +npm install sonner next-themes +``` + +Copy and paste the following code into your project. + + + +Add the Toaster component + +```tsx title="app/layout.tsx" {1,9} +import { Toaster } from '@/components/ui/sonner' + +export default function RootLayout({ children }) { + return ( + + + +
      {children}
      + + + + ) +} +``` + +
      + +
      + +
      + +## Usage + +```tsx +import { toast } from 'sonner' +``` + +```tsx +toast('Event has been created.') +``` diff --git a/apps/design-system/content/docs/components/switch.mdx b/apps/design-system/content/docs/components/switch.mdx new file mode 100644 index 0000000000..3dcf332821 --- /dev/null +++ b/apps/design-system/content/docs/components/switch.mdx @@ -0,0 +1,67 @@ +--- +title: Switch +description: A control that allows the user to toggle between checked and not checked. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/switch + api: https://www.radix-ui.com/docs/primitives/components/switch#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add switch +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-switch +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Switch } from '@/components/ui/switch' +``` + +```tsx + +``` + +## Examples + +### Form + + diff --git a/apps/design-system/content/docs/components/table.mdx b/apps/design-system/content/docs/components/table.mdx new file mode 100644 index 0000000000..ff05bebe23 --- /dev/null +++ b/apps/design-system/content/docs/components/table.mdx @@ -0,0 +1,85 @@ +--- +title: Table +description: A responsive table component. +component: true +source: + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add table +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { + Table, + TableBody, + TableCaption, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table' +``` + +```tsx +
      + A list of your recent invoices. + + + Invoice + Status + Method + Amount + + + + + INV001 + Paid + Credit Card + $250.00 + + +
      +``` + +## Data Table + +You can use the `` component to build more complex data tables. Combine it with [@tanstack/react-table](https://tanstack.com/table/v8) to create tables with sorting, filtering and pagination. + +See the [Data Table](/docs/components/data-table) documentation for more information. + +You can also see an example of a data table in the [Tasks](/examples/tasks) demo. diff --git a/apps/design-system/content/docs/components/tabs.mdx b/apps/design-system/content/docs/components/tabs.mdx new file mode 100644 index 0000000000..8085115c24 --- /dev/null +++ b/apps/design-system/content/docs/components/tabs.mdx @@ -0,0 +1,68 @@ +--- +title: Tabs +description: A set of layered sections of content—known as tab panels—that are displayed one at a time. +component: true +links: + doc: https://www.radix-ui.com/docs/primitives/components/tabs + api: https://www.radix-ui.com/docs/primitives/components/tabs#api-reference +source: + radix: true + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add tabs +``` + + + + + + + +Install the following dependencies: + +```bash +npm install @radix-ui/react-tabs +``` + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +``` + +```tsx + + + Account + Password + + Make changes to your account here. + Change your password here. + +``` diff --git a/apps/design-system/content/docs/components/textarea.mdx b/apps/design-system/content/docs/components/textarea.mdx new file mode 100644 index 0000000000..07b91d5896 --- /dev/null +++ b/apps/design-system/content/docs/components/textarea.mdx @@ -0,0 +1,77 @@ +--- +title: Textarea +description: Displays a form textarea or a component that looks like a textarea. +component: true +source: + shadcn: true +--- + + + +## Installation + + + + + CLI + Manual + + + +```bash +npx shadcn-ui@latest add textarea +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { Textarea } from '@/components/ui/textarea' +``` + +```tsx +