@sableui/react 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +315 -0
- package/CONTRIBUTING.md +16 -10
- package/DESIGN.md +3 -3
- package/README.md +3 -3
- package/bin/sable-lint.mjs +18 -0
- package/bin/sable.mjs +470 -62
- package/dist/blocks/api-keys-block.js +44 -0
- package/dist/blocks/api-keys-block.meta.js +21 -0
- package/dist/blocks/chat-thread-block.js +17 -0
- package/dist/blocks/chat-thread-block.meta.js +20 -0
- package/dist/blocks/command-palette-block.js +24 -0
- package/dist/blocks/command-palette-block.meta.js +21 -0
- package/dist/blocks/cta-band-block.js +27 -0
- package/dist/blocks/cta-band-block.meta.js +20 -0
- package/dist/blocks/danger-zone-block.js +39 -0
- package/dist/blocks/danger-zone-block.meta.js +21 -0
- package/dist/blocks/device-comparison-block.js +69 -0
- package/dist/blocks/device-comparison-block.meta.js +21 -0
- package/dist/blocks/event-card-block.js +40 -0
- package/dist/blocks/event-card-block.meta.js +21 -0
- package/dist/blocks/faq-block.js +38 -0
- package/dist/blocks/faq-block.meta.js +20 -0
- package/dist/blocks/feature-grid-block.js +38 -0
- package/dist/blocks/feature-grid-block.meta.js +21 -0
- package/dist/blocks/feedback-form-block.js +30 -0
- package/dist/blocks/feedback-form-block.meta.js +21 -0
- package/dist/blocks/goal-progress-block.js +24 -0
- package/dist/blocks/goal-progress-block.meta.js +21 -0
- package/dist/blocks/hero-block.js +33 -0
- package/dist/blocks/hero-block.meta.js +21 -0
- package/dist/blocks/index.js +162 -1964
- package/dist/blocks/invite-team-block.js +36 -0
- package/dist/blocks/invite-team-block.meta.js +20 -0
- package/dist/blocks/invoice-history-block.js +41 -0
- package/dist/blocks/invoice-history-block.meta.js +21 -0
- package/dist/blocks/kpi-sparkline-block.js +29 -0
- package/dist/blocks/kpi-sparkline-block.meta.js +20 -0
- package/dist/blocks/media-player-block.js +68 -0
- package/dist/blocks/media-player-block.meta.js +21 -0
- package/dist/blocks/newsletter-block.js +35 -0
- package/dist/blocks/newsletter-block.meta.js +21 -0
- package/dist/blocks/not-found-block.js +27 -0
- package/dist/blocks/not-found-block.meta.js +20 -0
- package/dist/blocks/notification-list-block.js +32 -0
- package/dist/blocks/notification-list-block.meta.js +21 -0
- package/dist/blocks/notification-settings-block.js +25 -0
- package/dist/blocks/notification-settings-block.meta.js +20 -0
- package/dist/blocks/order-tracking-block.js +26 -0
- package/dist/blocks/order-tracking-block.meta.js +20 -0
- package/dist/blocks/pricing-card-block.js +46 -0
- package/dist/blocks/pricing-card-block.meta.js +21 -0
- package/dist/blocks/pricing-table-block.js +88 -0
- package/dist/blocks/pricing-table-block.meta.js +20 -0
- package/dist/blocks/product-card-block.js +26 -0
- package/dist/blocks/product-card-block.meta.js +21 -0
- package/dist/blocks/profile-card-block.js +58 -0
- package/dist/blocks/profile-card-block.meta.js +21 -0
- package/dist/blocks/profile-form-block.js +70 -0
- package/dist/blocks/profile-form-block.meta.js +21 -0
- package/dist/blocks/revenue-breakdown-block.js +38 -0
- package/dist/blocks/revenue-breakdown-block.meta.js +21 -0
- package/dist/blocks/sign-in-block.js +38 -0
- package/dist/blocks/sign-in-block.meta.js +21 -0
- package/dist/blocks/sign-up-block.js +48 -0
- package/dist/blocks/sign-up-block.meta.js +21 -0
- package/dist/blocks/site-footer-block.js +54 -0
- package/dist/blocks/site-footer-block.meta.js +20 -0
- package/dist/blocks/stat-row-block.js +28 -0
- package/dist/blocks/stat-row-block.meta.js +21 -0
- package/dist/blocks/steps-block.js +37 -0
- package/dist/blocks/steps-block.meta.js +20 -0
- package/dist/blocks/task-list-block.js +52 -0
- package/dist/blocks/task-list-block.meta.js +21 -0
- package/dist/blocks/team-members-block.js +49 -0
- package/dist/blocks/team-members-block.meta.js +21 -0
- package/dist/blocks/testimonial-block.js +49 -0
- package/dist/blocks/testimonial-block.meta.js +20 -0
- package/dist/blocks/traffic-sources-block.js +39 -0
- package/dist/blocks/traffic-sources-block.meta.js +21 -0
- package/dist/blocks/traffic-trend-block.js +61 -0
- package/dist/blocks/traffic-trend-block.meta.js +21 -0
- package/dist/blocks/upload-list-block.js +39 -0
- package/dist/blocks/upload-list-block.meta.js +21 -0
- package/dist/blocks/verify-code-block.js +28 -0
- package/dist/blocks/verify-code-block.meta.js +21 -0
- package/dist/blocks/wallet-block.js +48 -0
- package/dist/blocks/wallet-block.meta.js +21 -0
- package/dist/components/accordion/accordion.js +63 -0
- package/dist/components/accordion/accordion.meta.js +155 -0
- package/dist/components/accordion/index.js +15 -0
- package/dist/components/app-header/app-header.js +30 -0
- package/dist/components/app-header/app-header.meta.js +88 -0
- package/dist/components/app-header/index.js +7 -0
- package/dist/components/app-shell/app-shell-dock.js +37 -0
- package/dist/components/app-shell/app-shell.js +67 -0
- package/dist/components/app-shell/app-shell.meta.js +176 -0
- package/dist/components/app-shell/index.js +7 -0
- package/dist/components/area-chart/area-chart.js +10 -0
- package/dist/components/area-chart/area-chart.meta.js +218 -0
- package/dist/components/area-chart/index.js +7 -0
- package/dist/components/attachment/attachment.js +176 -0
- package/dist/components/attachment/attachment.meta.js +179 -0
- package/dist/components/attachment/attachment.variants.js +47 -0
- package/dist/components/attachment/index.js +7 -0
- package/dist/components/avatar/avatar.js +192 -0
- package/dist/components/avatar/avatar.meta.js +233 -0
- package/dist/components/avatar/avatar.variants.js +44 -0
- package/dist/components/avatar/index.js +22 -0
- package/dist/components/badge/badge.js +26 -0
- package/dist/components/badge/badge.meta.js +171 -0
- package/dist/components/badge/badge.variants.js +103 -0
- package/dist/components/badge/index.js +11 -0
- package/dist/components/banner/banner.js +76 -0
- package/dist/components/banner/banner.meta.js +172 -0
- package/dist/components/banner/banner.variants.js +44 -0
- package/dist/components/banner/index.js +9 -0
- package/dist/components/bar-chart/bar-chart.js +10 -0
- package/dist/components/bar-chart/bar-chart.meta.js +245 -0
- package/dist/components/bar-chart/index.js +7 -0
- package/dist/components/bottom-nav/bottom-nav.js +63 -0
- package/dist/components/bottom-nav/bottom-nav.meta.js +95 -0
- package/dist/components/bottom-nav/index.js +11 -0
- package/dist/components/breadcrumbs/breadcrumbs.js +90 -0
- package/dist/components/breadcrumbs/breadcrumbs.meta.js +111 -0
- package/dist/components/breadcrumbs/index.js +17 -0
- package/dist/components/browser/browser.js +39 -0
- package/dist/components/browser/browser.meta.js +80 -0
- package/dist/components/browser/index.js +7 -0
- package/dist/components/bubble/bubble.js +110 -0
- package/dist/components/bubble/bubble.meta.js +158 -0
- package/dist/components/bubble/bubble.variants.js +90 -0
- package/dist/components/bubble/index.js +13 -0
- package/dist/components/button/button.js +87 -0
- package/dist/components/button/button.meta.js +302 -0
- package/dist/components/button/button.variants.js +137 -0
- package/dist/components/button/index.js +9 -0
- package/dist/components/calendar/calendar.js +89 -0
- package/dist/components/calendar/calendar.meta.js +136 -0
- package/dist/components/calendar/index.js +7 -0
- package/dist/components/card/card.js +203 -0
- package/dist/components/card/card.meta.js +212 -0
- package/dist/components/card/index.js +23 -0
- package/dist/components/carousel/carousel.js +428 -0
- package/dist/components/carousel/carousel.meta.js +100 -0
- package/dist/components/carousel/index.js +7 -0
- package/dist/components/chat-composer/chat-composer.js +174 -0
- package/dist/components/chat-composer/chat-composer.meta.js +241 -0
- package/dist/components/chat-composer/chat-composer.variants.js +17 -0
- package/dist/components/chat-composer/index.js +7 -0
- package/dist/components/checkbox/checkbox-mark.js +28 -0
- package/dist/components/checkbox/checkbox.js +30 -0
- package/dist/components/checkbox/checkbox.meta.js +127 -0
- package/dist/components/checkbox/index.js +7 -0
- package/dist/components/checkbox-card/checkbox-card.js +94 -0
- package/dist/components/checkbox-card/checkbox-card.meta.js +154 -0
- package/dist/components/checkbox-card/checkbox-card.variants.js +43 -0
- package/dist/components/checkbox-card/index.js +11 -0
- package/dist/components/code/code.js +19 -0
- package/dist/components/code/code.meta.js +71 -0
- package/dist/components/code/index.js +7 -0
- package/dist/components/code-block/code-block.js +84 -0
- package/dist/components/code-block/code-block.meta.js +103 -0
- package/dist/components/code-block/index.js +8 -0
- package/dist/components/collapsible/collapsible.js +38 -0
- package/dist/components/collapsible/collapsible.meta.js +117 -0
- package/dist/components/collapsible/index.js +15 -0
- package/dist/components/color-field/color-field.js +293 -0
- package/dist/components/color-field/color-field.meta.js +142 -0
- package/dist/components/color-field/color.js +69 -0
- package/dist/components/color-field/index.js +15 -0
- package/dist/components/combobox/combobox.js +486 -0
- package/dist/components/combobox/combobox.meta.js +217 -0
- package/dist/components/combobox/index.js +37 -0
- package/dist/components/command-menu/command-menu-trigger.js +122 -0
- package/dist/components/command-menu/command-menu.js +433 -0
- package/dist/components/command-menu/command-menu.meta.js +279 -0
- package/dist/components/command-menu/index.js +21 -0
- package/dist/components/context-card/context-card.js +62 -0
- package/dist/components/context-card/context-card.meta.js +106 -0
- package/dist/components/context-card/index.js +17 -0
- package/dist/components/context-menu/context-menu.js +92 -0
- package/dist/components/context-menu/context-menu.meta.js +138 -0
- package/dist/components/context-menu/index.js +23 -0
- package/dist/components/data-table/data-table.js +142 -0
- package/dist/components/data-table/data-table.meta.js +146 -0
- package/dist/components/data-table/index.js +9 -0
- package/dist/components/date-picker/date-picker.js +196 -0
- package/dist/components/date-picker/date-picker.meta.js +164 -0
- package/dist/components/date-picker/index.js +7 -0
- package/dist/components/date-tile/date-tile.js +29 -0
- package/dist/components/date-tile/date-tile.meta.js +72 -0
- package/dist/components/date-tile/index.js +7 -0
- package/dist/components/destructive-action-modal/destructive-action-modal.js +130 -0
- package/dist/components/destructive-action-modal/destructive-action-modal.meta.js +136 -0
- package/dist/components/destructive-action-modal/index.js +9 -0
- package/dist/components/dialog/dialog.js +207 -0
- package/dist/components/dialog/dialog.meta.js +239 -0
- package/dist/components/dialog/index.js +45 -0
- package/dist/components/disclosure-picker/disclosure-picker.js +417 -0
- package/dist/components/disclosure-picker/disclosure-picker.meta.js +213 -0
- package/dist/components/disclosure-picker/index.js +21 -0
- package/dist/components/empty-state/empty-state.js +52 -0
- package/dist/components/empty-state/empty-state.meta.js +158 -0
- package/dist/components/empty-state/index.js +7 -0
- package/dist/components/entity/entity.js +70 -0
- package/dist/components/entity/entity.meta.js +108 -0
- package/dist/components/entity/entity.variants.js +16 -0
- package/dist/components/entity/index.js +7 -0
- package/dist/components/feedback/feedback.js +93 -0
- package/dist/components/feedback/feedback.meta.js +109 -0
- package/dist/components/feedback/index.js +7 -0
- package/dist/components/fieldset/fieldset.js +80 -0
- package/dist/components/fieldset/fieldset.meta.js +160 -0
- package/dist/components/fieldset/index.js +17 -0
- package/dist/components/file-dropzone/file-dropzone.js +193 -0
- package/dist/components/file-dropzone/file-dropzone.meta.js +210 -0
- package/dist/components/file-dropzone/file-dropzone.variants.js +26 -0
- package/dist/components/file-dropzone/index.js +13 -0
- package/dist/components/font-picker/font-picker.js +77 -0
- package/dist/components/font-picker/font-picker.meta.js +119 -0
- package/dist/components/font-picker/index.js +7 -0
- package/dist/components/form/form.js +145 -0
- package/dist/components/form/form.meta.js +142 -0
- package/dist/components/form/index.js +11 -0
- package/dist/components/gliding-highlight/gliding-highlight.js +50 -0
- package/dist/components/gliding-highlight/gliding-highlight.meta.js +135 -0
- package/dist/components/gliding-highlight/index.js +9 -0
- package/dist/components/gradient-art/gradient-art.js +168 -0
- package/dist/components/gradient-art/gradient-art.meta.js +81 -0
- package/dist/components/gradient-art/index.js +7 -0
- package/dist/components/gradient-art/renderer.js +336 -0
- package/dist/components/inline-status/index.js +7 -0
- package/dist/components/inline-status/inline-status.js +33 -0
- package/dist/components/inline-status/inline-status.meta.js +83 -0
- package/dist/components/inline-status/inline-status.variants.js +18 -0
- package/dist/components/input/index.js +7 -0
- package/dist/components/input/input.js +33 -0
- package/dist/components/input/input.meta.js +155 -0
- package/dist/components/kbd/index.js +8 -0
- package/dist/components/kbd/kbd.js +54 -0
- package/dist/components/kbd/kbd.meta.js +95 -0
- package/dist/components/label/index.js +7 -0
- package/dist/components/label/label.js +51 -0
- package/dist/components/label/label.meta.js +98 -0
- package/dist/components/line-chart/index.js +7 -0
- package/dist/components/line-chart/line-chart.js +10 -0
- package/dist/components/line-chart/line-chart.meta.js +222 -0
- package/dist/components/marker/index.js +7 -0
- package/dist/components/marker/marker.js +39 -0
- package/dist/components/marker/marker.meta.js +132 -0
- package/dist/components/marker/marker.variants.js +25 -0
- package/dist/components/marquee/index.js +7 -0
- package/dist/components/marquee/marquee.js +146 -0
- package/dist/components/marquee/marquee.meta.js +106 -0
- package/dist/components/media-image/index.js +7 -0
- package/dist/components/media-image/media-image.js +56 -0
- package/dist/components/media-image/media-image.meta.js +92 -0
- package/dist/components/media-tile/index.js +7 -0
- package/dist/components/media-tile/media-tile.js +135 -0
- package/dist/components/media-tile/media-tile.meta.js +133 -0
- package/dist/components/media-tile/media-tile.variants.js +48 -0
- package/dist/components/menu/index.js +33 -0
- package/dist/components/menu/menu.js +168 -0
- package/dist/components/menu/menu.meta.js +176 -0
- package/dist/components/message/index.js +7 -0
- package/dist/components/message/message.js +83 -0
- package/dist/components/message/message.meta.js +150 -0
- package/dist/components/message/message.variants.js +41 -0
- package/dist/components/message-scroller/index.js +9 -0
- package/dist/components/message-scroller/message-scroller.js +300 -0
- package/dist/components/message-scroller/message-scroller.meta.js +172 -0
- package/dist/components/meter/index.js +20 -0
- package/dist/components/meter/meter.js +112 -0
- package/dist/components/meter/meter.meta.js +227 -0
- package/dist/components/meter/meter.variants.js +61 -0
- package/dist/components/middle-truncate/index.js +7 -0
- package/dist/components/middle-truncate/middle-truncate.js +28 -0
- package/dist/components/middle-truncate/middle-truncate.meta.js +77 -0
- package/dist/components/note/index.js +9 -0
- package/dist/components/note/note.js +73 -0
- package/dist/components/note/note.meta.js +112 -0
- package/dist/components/note/note.variants.js +22 -0
- package/dist/components/notification-badge/index.js +15 -0
- package/dist/components/notification-badge/notification-badge.js +48 -0
- package/dist/components/notification-badge/notification-badge.meta.js +107 -0
- package/dist/components/notification-badge/notification-badge.variants.js +57 -0
- package/dist/components/number-field/index.js +7 -0
- package/dist/components/number-field/number-field.js +70 -0
- package/dist/components/number-field/number-field.meta.js +109 -0
- package/dist/components/otp-field/index.js +7 -0
- package/dist/components/otp-field/otp-field.js +70 -0
- package/dist/components/otp-field/otp-field.meta.js +197 -0
- package/dist/components/overflow-menu/index.js +7 -0
- package/dist/components/overflow-menu/overflow-menu.js +26 -0
- package/dist/components/overflow-menu/overflow-menu.meta.js +100 -0
- package/dist/components/page-header/index.js +7 -0
- package/dist/components/page-header/page-header.js +34 -0
- package/dist/components/page-header/page-header.meta.js +104 -0
- package/dist/components/page-loader/index.js +7 -0
- package/dist/components/page-loader/page-loader.js +37 -0
- package/dist/components/page-loader/page-loader.meta.js +85 -0
- package/dist/components/pagination/index.js +7 -0
- package/dist/components/pagination/pagination.js +105 -0
- package/dist/components/pagination/pagination.meta.js +141 -0
- package/dist/components/panel-group/index.js +10 -0
- package/dist/components/panel-group/panel-group.js +168 -0
- package/dist/components/panel-group/panel-group.meta.js +153 -0
- package/dist/components/panel-section/index.js +9 -0
- package/dist/components/panel-section/panel-section.js +115 -0
- package/dist/components/panel-section/panel-section.meta.js +156 -0
- package/dist/components/phone/index.js +7 -0
- package/dist/components/phone/phone.js +50 -0
- package/dist/{chunk-KFZ43RKU.js → components/phone/phone.meta.js} +3 -50
- package/dist/{chunk-NEQNXI2G.js → components/phone/status-icons.js} +4 -4
- package/dist/components/pie-chart/index.js +7 -0
- package/dist/components/pie-chart/pie-chart.js +191 -0
- package/dist/components/pie-chart/pie-chart.meta.js +210 -0
- package/dist/components/pill/index.js +9 -0
- package/dist/components/pill/pill.js +24 -0
- package/dist/components/pill/pill.meta.js +108 -0
- package/dist/components/pill/pill.variants.js +65 -0
- package/dist/components/popover/index.js +23 -0
- package/dist/components/popover/popover.js +100 -0
- package/dist/components/popover/popover.meta.js +136 -0
- package/dist/components/progress/index.js +19 -0
- package/dist/components/progress/progress.js +70 -0
- package/dist/components/progress/progress.meta.js +171 -0
- package/dist/components/progress/progress.variants.js +17 -0
- package/dist/components/radar-chart/index.js +7 -0
- package/dist/components/radar-chart/radar-chart.js +161 -0
- package/dist/components/radar-chart/radar-chart.meta.js +204 -0
- package/dist/components/radial-chart/index.js +7 -0
- package/dist/components/radial-chart/radial-chart.js +175 -0
- package/dist/components/radial-chart/radial-chart.meta.js +216 -0
- package/dist/components/radio/index.js +8 -0
- package/dist/components/radio/radio.js +39 -0
- package/dist/components/radio/radio.meta.js +104 -0
- package/dist/components/radio-card/index.js +7 -0
- package/dist/components/radio-card/radio-card.js +81 -0
- package/dist/components/radio-card/radio-card.meta.js +144 -0
- package/dist/components/radio-card/radio-card.variants.js +43 -0
- package/dist/components/relative-time/index.js +7 -0
- package/dist/components/relative-time/relative-time.js +47 -0
- package/dist/components/relative-time/relative-time.meta.js +77 -0
- package/dist/components/scroller/index.js +7 -0
- package/dist/components/scroller/scroller.js +111 -0
- package/dist/components/scroller/scroller.meta.js +118 -0
- package/dist/components/scrub-field/index.js +7 -0
- package/dist/components/scrub-field/scrub-field.js +124 -0
- package/dist/components/scrub-field/scrub-field.meta.js +139 -0
- package/dist/components/search-input/index.js +7 -0
- package/dist/components/search-input/search-input.js +91 -0
- package/dist/components/search-input/search-input.meta.js +129 -0
- package/dist/components/section-header/index.js +7 -0
- package/dist/components/section-header/section-header.js +39 -0
- package/dist/components/section-header/section-header.meta.js +174 -0
- package/dist/components/segmented-bar/index.js +14 -0
- package/dist/components/segmented-bar/segmented-bar.js +26 -0
- package/dist/components/segmented-bar/segmented-bar.meta.js +108 -0
- package/dist/components/segmented-bar/segmented-bar.variants.js +39 -0
- package/dist/components/select/index.js +25 -0
- package/dist/components/select/select.js +191 -0
- package/dist/components/select/select.meta.js +189 -0
- package/dist/components/separator/index.js +7 -0
- package/dist/components/separator/separator.js +42 -0
- package/dist/components/separator/separator.meta.js +84 -0
- package/dist/components/settings-menu/index.js +11 -0
- package/dist/components/settings-menu/settings-menu.js +101 -0
- package/dist/components/settings-menu/settings-menu.meta.js +177 -0
- package/dist/components/settings-menu/settings-menu.variants.js +15 -0
- package/dist/components/sheet/index.js +29 -0
- package/dist/components/sheet/sheet.js +121 -0
- package/dist/components/sheet/sheet.meta.js +167 -0
- package/dist/components/sheet/sheet.variants.js +21 -0
- package/dist/components/show-more/index.js +7 -0
- package/dist/components/show-more/show-more.js +87 -0
- package/dist/components/show-more/show-more.meta.js +79 -0
- package/dist/components/side-nav/index.js +13 -0
- package/dist/components/side-nav/side-nav.js +75 -0
- package/dist/components/side-nav/side-nav.meta.js +139 -0
- package/dist/components/side-nav/side-nav.variants.js +34 -0
- package/dist/components/sidebar/index.js +21 -0
- package/dist/components/sidebar/sidebar.js +196 -0
- package/dist/components/sidebar/sidebar.meta.js +118 -0
- package/dist/components/skeleton/index.js +7 -0
- package/dist/components/skeleton/skeleton.js +16 -0
- package/dist/components/skeleton/skeleton.meta.js +90 -0
- package/dist/components/slider/index.js +21 -0
- package/dist/components/slider/slider.js +115 -0
- package/dist/components/slider/slider.meta.js +214 -0
- package/dist/components/sparkline/index.js +7 -0
- package/dist/components/sparkline/sparkline.js +84 -0
- package/dist/components/sparkline/sparkline.meta.js +147 -0
- package/dist/components/spinner/index.js +7 -0
- package/dist/components/spinner/spinner.js +59 -0
- package/dist/components/spinner/spinner.meta.js +118 -0
- package/dist/components/status-bar/index.js +9 -0
- package/dist/components/status-bar/status-bar.js +40 -0
- package/dist/components/status-bar/status-bar.meta.js +117 -0
- package/dist/components/status-dot/index.js +9 -0
- package/dist/components/status-dot/status-dot.js +40 -0
- package/dist/components/status-dot/status-dot.meta.js +113 -0
- package/dist/components/status-dot/status-dot.variants.js +28 -0
- package/dist/components/stepper/index.js +17 -0
- package/dist/components/stepper/stepper.js +161 -0
- package/dist/components/stepper/stepper.meta.js +190 -0
- package/dist/components/stepper/stepper.variants.js +72 -0
- package/dist/components/streaming-text/index.js +7 -0
- package/dist/components/streaming-text/streaming-text.js +55 -0
- package/dist/components/streaming-text/streaming-text.meta.js +147 -0
- package/dist/components/switch/index.js +7 -0
- package/dist/components/switch/switch.js +26 -0
- package/dist/components/switch/switch.meta.js +133 -0
- package/dist/components/table/index.js +23 -0
- package/dist/components/table/table.js +117 -0
- package/dist/components/table/table.meta.js +143 -0
- package/dist/components/tabs/index.js +17 -0
- package/dist/components/tabs/tabs.js +58 -0
- package/dist/components/tabs/tabs.meta.js +120 -0
- package/dist/components/textarea/index.js +7 -0
- package/dist/components/textarea/textarea.js +38 -0
- package/dist/components/textarea/textarea.meta.js +117 -0
- package/dist/components/theme-selector/index.js +11 -0
- package/dist/components/theme-selector/theme-selector.js +145 -0
- package/dist/components/theme-selector/theme-selector.meta.js +181 -0
- package/dist/components/theme-switcher/index.js +7 -0
- package/dist/components/theme-switcher/theme-switcher.js +106 -0
- package/dist/components/theme-switcher/theme-switcher.meta.js +99 -0
- package/dist/components/thinking-orb/index.js +9 -0
- package/dist/components/thinking-orb/thinking-orb.js +126 -0
- package/dist/components/thinking-orb/thinking-orb.meta.js +142 -0
- package/dist/components/thinking-orb/thinking-orb.render.js +252 -0
- package/dist/components/toast/index.js +29 -0
- package/dist/components/toast/toast.js +254 -0
- package/dist/components/toast/toast.meta.js +261 -0
- package/dist/components/toggle/index.js +13 -0
- package/dist/components/toggle/toggle.js +51 -0
- package/dist/components/toggle/toggle.meta.js +129 -0
- package/dist/components/toolbar/index.js +27 -0
- package/dist/components/toolbar/toolbar.js +80 -0
- package/dist/components/toolbar/toolbar.meta.js +272 -0
- package/dist/components/toolbar/toolbar.variants.js +16 -0
- package/dist/components/tooltip/index.js +21 -0
- package/dist/components/tooltip/tooltip.js +74 -0
- package/dist/components/tooltip/tooltip.meta.js +156 -0
- package/dist/components/tree/index.js +12 -0
- package/dist/components/tree/tree.js +364 -0
- package/dist/components/tree/tree.meta.js +334 -0
- package/dist/components/video/index.js +7 -0
- package/dist/components/video/video.js +59 -0
- package/dist/components/video/video.meta.js +81 -0
- package/dist/components/workspace/index.js +9 -0
- package/dist/components/workspace/workspace.js +79 -0
- package/dist/components/workspace/workspace.meta.js +183 -0
- package/dist/foundations/accessibility.js +107 -0
- package/dist/foundations/index.js +25 -792
- package/dist/foundations/motion.js +135 -0
- package/dist/foundations/scrolling.js +62 -0
- package/dist/foundations/shape.js +113 -0
- package/dist/foundations/spacing.js +121 -0
- package/dist/foundations/surfaces.js +107 -0
- package/dist/foundations/types.js +0 -0
- package/dist/foundations/typography.js +152 -0
- package/dist/icon/Icon.js +30 -0
- package/dist/icon/IconProvider.js +27 -0
- package/dist/icon/compose.js +13 -0
- package/dist/icon/index.d.ts +13 -5
- package/dist/icon/index.js +13 -2
- package/dist/icon/registry.js +0 -0
- package/dist/icon-sets/brands.generated.js +123 -0
- package/dist/icon-sets/brands.js +10 -123
- package/dist/icon-sets/reicon.d.ts +3 -1
- package/dist/icon-sets/reicon.js +209 -1
- package/dist/index.d.ts +618 -34
- package/dist/index.js +211 -11351
- package/dist/ios/chrome.js +36 -0
- package/dist/ios/index.js +19 -315
- package/dist/ios/liquid-glass.js +103 -0
- package/dist/ios/native-app.js +46 -0
- package/dist/ios/navigation.js +63 -0
- package/dist/ios/phone-frame.js +64 -0
- package/dist/ios/preview-theme.js +83 -0
- package/dist/ios/preview.js +10 -137
- package/dist/ios/sheet.js +85 -0
- package/dist/ios/theme.js +19 -0
- package/dist/layout/AspectBox.js +27 -0
- package/dist/layout/Bleed.js +15 -0
- package/dist/layout/Center.js +21 -0
- package/dist/layout/Columns.js +70 -0
- package/dist/layout/Grid.js +50 -0
- package/dist/layout/GridOverlay.js +41 -0
- package/dist/layout/Page.js +11 -0
- package/dist/layout/Region.js +39 -0
- package/dist/layout/Row.js +45 -0
- package/dist/layout/SafeArea.js +26 -0
- package/dist/layout/Spacer.js +9 -0
- package/dist/layout/SplitPane.js +55 -0
- package/dist/layout/Stack.js +42 -0
- package/dist/layout/_responsive.js +16 -0
- package/dist/layout/_safeArea.js +18 -0
- package/dist/layout/index.d.ts +30 -8
- package/dist/layout/index.js +14 -2
- package/dist/lib/anchored-scroll.js +7 -0
- package/dist/lib/bleed.js +7 -0
- package/dist/lib/chart/cartesian.js +365 -0
- package/dist/lib/chart/chart-frame.js +163 -0
- package/dist/lib/chart/chart-legend.js +13 -0
- package/dist/lib/chart/chart-tooltip.js +38 -0
- package/dist/lib/chart/format.js +24 -0
- package/dist/lib/chart/geometry.js +114 -0
- package/dist/lib/chart/motion.js +34 -0
- package/dist/lib/chart/scale.js +72 -0
- package/dist/lib/chart/types.js +45 -0
- package/dist/lib/chart/use-arrival.js +41 -0
- package/dist/{chunk-SRQWQUTW.js → lib/cn.js} +5 -5
- package/dist/lib/component-guidance.js +215 -0
- package/dist/lib/density.js +54 -0
- package/dist/lib/field-shell.js +11 -0
- package/dist/lib/glyphs.js +9 -0
- package/dist/lib/heading-row.js +36 -0
- package/dist/lib/highlight-glide.js +84 -0
- package/dist/lib/hit-target.js +5 -0
- package/dist/lib/meta.js +0 -0
- package/dist/lib/portal-theme-scope.js +74 -0
- package/dist/{chunk-FKZXAFIY.js → lib/presentation.js} +8 -3
- package/dist/lib/refs.js +14 -0
- package/dist/lib/scrub-gesture.js +50 -0
- package/dist/lib/segmented.js +13 -0
- package/dist/lib/selection-card.js +41 -0
- package/dist/lib/status-tone.js +13 -0
- package/dist/lib/taxonomy.js +214 -0
- package/dist/lib/trim-label.js +20 -0
- package/dist/lib/use-copy.js +27 -0
- package/dist/lib/use-edge-fade.js +32 -0
- package/dist/lib/use-isomorphic-layout-effect.js +8 -0
- package/dist/lib/use-resize-observer.js +18 -0
- package/dist/lib/use-scroll-activity.js +52 -0
- package/dist/lib/use-wheel-to-horizontal.js +65 -0
- package/dist/motion/MotionProvider.js +75 -0
- package/dist/motion/Presence.js +112 -0
- package/dist/motion/Reveal.js +42 -0
- package/dist/motion/TextReveal.js +61 -0
- package/dist/motion/index.js +24 -0
- package/dist/motion/useInView.js +36 -0
- package/dist/motion/useReducedMotion.js +25 -0
- package/dist/motion/viewTransition.js +47 -0
- package/dist/patterns/auth-page.js +90 -0
- package/dist/patterns/auth-page.meta.js +27 -0
- package/dist/patterns/brand-landing-page.js +341 -0
- package/dist/patterns/brand-landing-page.meta.js +28 -0
- package/dist/patterns/chat-panel.js +185 -0
- package/dist/patterns/chat-panel.meta.js +31 -0
- package/dist/patterns/dashboard-page.js +332 -0
- package/dist/patterns/dashboard-page.meta.js +29 -0
- package/dist/patterns/feed-page.js +205 -0
- package/dist/patterns/feed-page.meta.js +25 -0
- package/dist/patterns/index.js +34 -2140
- package/dist/patterns/landing-page.js +356 -0
- package/dist/patterns/landing-page.meta.js +26 -0
- package/dist/patterns/list-detail-page.js +373 -0
- package/dist/patterns/list-detail-page.meta.js +24 -0
- package/dist/patterns/settings-page.js +268 -0
- package/dist/patterns/settings-page.meta.js +27 -0
- package/dist/presets/index.d.ts +7 -1
- package/dist/presets/index.js +53 -185
- package/dist/styles.css +118 -3
- package/dist/{theme-provider-kQszHYji.d.ts → theme-provider-S0NVJs2Y.d.ts} +6 -1
- package/dist/{chunk-NETUFI34.js → themes/_contract.js} +14 -2
- package/dist/themes/atelier/index.js +17 -1
- package/dist/themes/contrast.js +288 -0
- package/dist/themes/ember/ember.css +6 -6
- package/dist/themes/ember/index.js +16 -1
- package/dist/themes/index.d.ts +1 -1
- package/dist/themes/index.js +3 -8
- package/dist/themes/meridian/index.js +16 -1
- package/dist/themes/poppy/index.js +17 -1
- package/dist/themes/prism/index.js +17 -1
- package/dist/themes/prism/prism.css +2 -2
- package/dist/themes/registry.js +59 -0
- package/dist/themes/sable/index.js +16 -1
- package/dist/{chunk-EFLC4NA3.js → themes/theme-provider.js} +38 -54
- package/dist/themes/verdant/index.js +17 -1
- package/llms/blocks/media-player-block.md +20 -7
- package/llms/blocks/product-card-block.md +6 -4
- package/llms/blocks/task-list-block.md +1 -1
- package/llms/blocks/traffic-sources-block.md +1 -1
- package/llms/blocks/traffic-trend-block.md +5 -3
- package/llms/blocks/verify-code-block.md +1 -1
- package/llms/components/app-shell.md +5 -2
- package/llms/components/avatar.md +25 -3
- package/llms/components/button.md +20 -1
- package/llms/components/card.md +1 -1
- package/llms/components/disclosure-picker.md +168 -0
- package/llms/components/font-picker.md +104 -0
- package/llms/components/media-image.md +98 -0
- package/llms/components/media-tile.md +143 -0
- package/llms/components/page-header.md +6 -5
- package/llms/components/pie-chart.md +2 -2
- package/llms/components/radial-chart.md +1 -1
- package/llms/components/section-header.md +144 -0
- package/llms/components/sheet.md +10 -0
- package/llms/components/sidebar.md +4 -3
- package/llms/components/slider.md +14 -2
- package/llms/components/theme-selector.md +44 -4
- package/llms/components/tree.md +3 -3
- package/llms/layout/grid.md +24 -3
- package/llms/layout/region.md +16 -3
- package/llms/patterns/dashboard-page.md +3 -6
- package/llms/patterns/feed-page.md +4 -4
- package/llms/patterns/list-detail-page.md +1 -0
- package/llms/patterns/settings-page.md +2 -5
- package/llms/reference/utilities.md +84 -4
- package/llms/tasks/building-a-page.md +34 -3
- package/llms/tasks/converting-an-app.md +14 -4
- package/llms/tasks/creating-a-preset.md +4 -1
- package/llms/tasks/reviewing-a-design.md +19 -0
- package/llms/tasks/using-presets.md +19 -0
- package/llms-full.txt +1066 -78
- package/llms.txt +26 -9
- package/package.json +1 -1
- package/registry.json +2342 -164
- package/scripts/agent-setup.mjs +90 -0
- package/scripts/design-presets.mjs +59 -6
- package/scripts/grade.mjs +195 -29
- package/scripts/lint-rules.mjs +486 -10
- package/scripts/review-evidence.mjs +28 -1
- package/skills/sable/SKILL.md +67 -24
- package/targets/ios.json +45 -0
- package/dist/chunk-3IWZYBGH.js +0 -398
- package/dist/chunk-7MG4SHYX.js +0 -15
- package/dist/chunk-7QSDYBXO.js +0 -7421
- package/dist/chunk-ADLLDWLW.js +0 -15
- package/dist/chunk-C4Z3CF54.js +0 -15
- package/dist/chunk-EDXLM7YL.js +0 -5078
- package/dist/chunk-EHH4MHO6.js +0 -14
- package/dist/chunk-K7RUHUGC.js +0 -14
- package/dist/chunk-KO3NAEBF.js +0 -15
- package/dist/chunk-L4IEIQQA.js +0 -14
- package/dist/chunk-QJ6FWTUG.js +0 -40
- package/dist/chunk-VVW4UCDI.js +0 -4908
- package/dist/chunk-XAZGMY73.js +0 -187
package/dist/blocks/index.js
CHANGED
|
@@ -1,1965 +1,163 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
1
|
+
// src/blocks/index.ts
|
|
2
|
+
import { ApiKeysBlock } from "./api-keys-block.js";
|
|
3
|
+
import { apiKeysBlockMeta } from "./api-keys-block.meta.js";
|
|
4
|
+
import { ChatThreadBlock } from "./chat-thread-block.js";
|
|
5
|
+
import { chatThreadBlockMeta } from "./chat-thread-block.meta.js";
|
|
6
|
+
import { CommandPaletteBlock } from "./command-palette-block.js";
|
|
7
|
+
import { commandPaletteBlockMeta } from "./command-palette-block.meta.js";
|
|
8
|
+
import { CtaBandBlock } from "./cta-band-block.js";
|
|
9
|
+
import { ctaBandBlockMeta } from "./cta-band-block.meta.js";
|
|
10
|
+
import { DangerZoneBlock } from "./danger-zone-block.js";
|
|
11
|
+
import { dangerZoneBlockMeta } from "./danger-zone-block.meta.js";
|
|
12
|
+
import { DeviceComparisonBlock } from "./device-comparison-block.js";
|
|
13
|
+
import { deviceComparisonBlockMeta } from "./device-comparison-block.meta.js";
|
|
14
|
+
import { EventCardBlock } from "./event-card-block.js";
|
|
15
|
+
import { eventCardBlockMeta } from "./event-card-block.meta.js";
|
|
16
|
+
import { FaqBlock } from "./faq-block.js";
|
|
17
|
+
import { faqBlockMeta } from "./faq-block.meta.js";
|
|
18
|
+
import { FeatureGridBlock } from "./feature-grid-block.js";
|
|
19
|
+
import { featureGridBlockMeta } from "./feature-grid-block.meta.js";
|
|
20
|
+
import { FeedbackFormBlock } from "./feedback-form-block.js";
|
|
21
|
+
import { feedbackFormBlockMeta } from "./feedback-form-block.meta.js";
|
|
22
|
+
import { GoalProgressBlock } from "./goal-progress-block.js";
|
|
23
|
+
import { goalProgressBlockMeta } from "./goal-progress-block.meta.js";
|
|
24
|
+
import { HeroBlock } from "./hero-block.js";
|
|
25
|
+
import { heroBlockMeta } from "./hero-block.meta.js";
|
|
26
|
+
import { InviteTeamBlock } from "./invite-team-block.js";
|
|
27
|
+
import { inviteTeamBlockMeta } from "./invite-team-block.meta.js";
|
|
28
|
+
import { InvoiceHistoryBlock } from "./invoice-history-block.js";
|
|
29
|
+
import { invoiceHistoryBlockMeta } from "./invoice-history-block.meta.js";
|
|
30
|
+
import { KpiSparklineBlock } from "./kpi-sparkline-block.js";
|
|
31
|
+
import { kpiSparklineBlockMeta } from "./kpi-sparkline-block.meta.js";
|
|
32
|
+
import { MediaPlayerBlock } from "./media-player-block.js";
|
|
33
|
+
import { mediaPlayerBlockMeta } from "./media-player-block.meta.js";
|
|
34
|
+
import { NewsletterBlock } from "./newsletter-block.js";
|
|
35
|
+
import { newsletterBlockMeta } from "./newsletter-block.meta.js";
|
|
36
|
+
import { NotFoundBlock } from "./not-found-block.js";
|
|
37
|
+
import { notFoundBlockMeta } from "./not-found-block.meta.js";
|
|
38
|
+
import { NotificationListBlock } from "./notification-list-block.js";
|
|
39
|
+
import { notificationListBlockMeta } from "./notification-list-block.meta.js";
|
|
40
|
+
import { NotificationSettingsBlock } from "./notification-settings-block.js";
|
|
41
|
+
import { notificationSettingsBlockMeta } from "./notification-settings-block.meta.js";
|
|
42
|
+
import { OrderTrackingBlock } from "./order-tracking-block.js";
|
|
43
|
+
import { orderTrackingBlockMeta } from "./order-tracking-block.meta.js";
|
|
44
|
+
import { PricingCardBlock } from "./pricing-card-block.js";
|
|
45
|
+
import { pricingCardBlockMeta } from "./pricing-card-block.meta.js";
|
|
46
|
+
import { PricingTableBlock } from "./pricing-table-block.js";
|
|
47
|
+
import { pricingTableBlockMeta } from "./pricing-table-block.meta.js";
|
|
48
|
+
import { ProductCardBlock } from "./product-card-block.js";
|
|
49
|
+
import { productCardBlockMeta } from "./product-card-block.meta.js";
|
|
50
|
+
import { ProfileCardBlock } from "./profile-card-block.js";
|
|
51
|
+
import { profileCardBlockMeta } from "./profile-card-block.meta.js";
|
|
52
|
+
import { ProfileFormBlock } from "./profile-form-block.js";
|
|
53
|
+
import { profileFormBlockMeta } from "./profile-form-block.meta.js";
|
|
54
|
+
import { RevenueBreakdownBlock } from "./revenue-breakdown-block.js";
|
|
55
|
+
import { revenueBreakdownBlockMeta } from "./revenue-breakdown-block.meta.js";
|
|
56
|
+
import { SignInBlock } from "./sign-in-block.js";
|
|
57
|
+
import { signInBlockMeta } from "./sign-in-block.meta.js";
|
|
58
|
+
import { SignUpBlock } from "./sign-up-block.js";
|
|
59
|
+
import { signUpBlockMeta } from "./sign-up-block.meta.js";
|
|
60
|
+
import { SiteFooterBlock } from "./site-footer-block.js";
|
|
61
|
+
import { siteFooterBlockMeta } from "./site-footer-block.meta.js";
|
|
62
|
+
import { StatRowBlock } from "./stat-row-block.js";
|
|
63
|
+
import { statRowBlockMeta } from "./stat-row-block.meta.js";
|
|
64
|
+
import { StepsBlock } from "./steps-block.js";
|
|
65
|
+
import { stepsBlockMeta } from "./steps-block.meta.js";
|
|
66
|
+
import { TaskListBlock } from "./task-list-block.js";
|
|
67
|
+
import { taskListBlockMeta } from "./task-list-block.meta.js";
|
|
68
|
+
import { TeamMembersBlock } from "./team-members-block.js";
|
|
69
|
+
import { teamMembersBlockMeta } from "./team-members-block.meta.js";
|
|
70
|
+
import { TestimonialBlock } from "./testimonial-block.js";
|
|
71
|
+
import { testimonialBlockMeta } from "./testimonial-block.meta.js";
|
|
72
|
+
import { TrafficSourcesBlock } from "./traffic-sources-block.js";
|
|
73
|
+
import { trafficSourcesBlockMeta } from "./traffic-sources-block.meta.js";
|
|
74
|
+
import { TrafficTrendBlock } from "./traffic-trend-block.js";
|
|
75
|
+
import { trafficTrendBlockMeta } from "./traffic-trend-block.meta.js";
|
|
76
|
+
import { UploadListBlock } from "./upload-list-block.js";
|
|
77
|
+
import { uploadListBlockMeta } from "./upload-list-block.meta.js";
|
|
78
|
+
import { VerifyCodeBlock } from "./verify-code-block.js";
|
|
79
|
+
import { verifyCodeBlockMeta } from "./verify-code-block.meta.js";
|
|
80
|
+
import { WalletBlock } from "./wallet-block.js";
|
|
81
|
+
import { walletBlockMeta } from "./wallet-block.meta.js";
|
|
82
|
+
export {
|
|
83
|
+
ApiKeysBlock,
|
|
84
|
+
ChatThreadBlock,
|
|
85
|
+
CommandPaletteBlock,
|
|
86
|
+
CtaBandBlock,
|
|
87
|
+
DangerZoneBlock,
|
|
88
|
+
DeviceComparisonBlock,
|
|
89
|
+
EventCardBlock,
|
|
90
|
+
FaqBlock,
|
|
91
|
+
FeatureGridBlock,
|
|
92
|
+
FeedbackFormBlock,
|
|
93
|
+
GoalProgressBlock,
|
|
94
|
+
HeroBlock,
|
|
95
|
+
InviteTeamBlock,
|
|
96
|
+
InvoiceHistoryBlock,
|
|
97
|
+
KpiSparklineBlock,
|
|
98
|
+
MediaPlayerBlock,
|
|
99
|
+
NewsletterBlock,
|
|
100
|
+
NotFoundBlock,
|
|
101
|
+
NotificationListBlock,
|
|
102
|
+
NotificationSettingsBlock,
|
|
103
|
+
OrderTrackingBlock,
|
|
104
|
+
PricingCardBlock,
|
|
105
|
+
PricingTableBlock,
|
|
106
|
+
ProductCardBlock,
|
|
107
|
+
ProfileCardBlock,
|
|
108
|
+
ProfileFormBlock,
|
|
109
|
+
RevenueBreakdownBlock,
|
|
110
|
+
SignInBlock,
|
|
111
|
+
SignUpBlock,
|
|
112
|
+
SiteFooterBlock,
|
|
113
|
+
StatRowBlock,
|
|
114
|
+
StepsBlock,
|
|
115
|
+
TaskListBlock,
|
|
116
|
+
TeamMembersBlock,
|
|
117
|
+
TestimonialBlock,
|
|
118
|
+
TrafficSourcesBlock,
|
|
119
|
+
TrafficTrendBlock,
|
|
120
|
+
UploadListBlock,
|
|
121
|
+
VerifyCodeBlock,
|
|
122
|
+
WalletBlock,
|
|
123
|
+
apiKeysBlockMeta,
|
|
124
|
+
chatThreadBlockMeta,
|
|
125
|
+
commandPaletteBlockMeta,
|
|
126
|
+
ctaBandBlockMeta,
|
|
127
|
+
dangerZoneBlockMeta,
|
|
128
|
+
deviceComparisonBlockMeta,
|
|
129
|
+
eventCardBlockMeta,
|
|
130
|
+
faqBlockMeta,
|
|
131
|
+
featureGridBlockMeta,
|
|
132
|
+
feedbackFormBlockMeta,
|
|
133
|
+
goalProgressBlockMeta,
|
|
134
|
+
heroBlockMeta,
|
|
135
|
+
inviteTeamBlockMeta,
|
|
136
|
+
invoiceHistoryBlockMeta,
|
|
137
|
+
kpiSparklineBlockMeta,
|
|
138
|
+
mediaPlayerBlockMeta,
|
|
139
|
+
newsletterBlockMeta,
|
|
140
|
+
notFoundBlockMeta,
|
|
141
|
+
notificationListBlockMeta,
|
|
142
|
+
notificationSettingsBlockMeta,
|
|
143
|
+
orderTrackingBlockMeta,
|
|
144
|
+
pricingCardBlockMeta,
|
|
145
|
+
pricingTableBlockMeta,
|
|
146
|
+
productCardBlockMeta,
|
|
147
|
+
profileCardBlockMeta,
|
|
148
|
+
profileFormBlockMeta,
|
|
149
|
+
revenueBreakdownBlockMeta,
|
|
150
|
+
signInBlockMeta,
|
|
151
|
+
signUpBlockMeta,
|
|
152
|
+
siteFooterBlockMeta,
|
|
153
|
+
statRowBlockMeta,
|
|
154
|
+
stepsBlockMeta,
|
|
155
|
+
taskListBlockMeta,
|
|
156
|
+
teamMembersBlockMeta,
|
|
157
|
+
testimonialBlockMeta,
|
|
158
|
+
trafficSourcesBlockMeta,
|
|
159
|
+
trafficTrendBlockMeta,
|
|
160
|
+
uploadListBlockMeta,
|
|
161
|
+
verifyCodeBlockMeta,
|
|
162
|
+
walletBlockMeta
|
|
60
163
|
};
|
|
61
|
-
var messages = [
|
|
62
|
-
{ id: "m1", text: "Is the new cover ready?", mine: false },
|
|
63
|
-
{ id: "m2", text: "Uploading it now \u{1F389}", mine: true },
|
|
64
|
-
{ id: "m3", text: "Perfect, thank you!", mine: false }
|
|
65
|
-
];
|
|
66
|
-
function ChatThreadBlock({ className, framed = true }) {
|
|
67
|
-
return /* @__PURE__ */ jsx(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: /* @__PURE__ */ jsx(CardContent, { className: "flex flex-col gap-2", children: messages.map((m) => /* @__PURE__ */ jsx(Message, { messageId: m.id, align: m.mine ? "end" : void 0, children: /* @__PURE__ */ jsx(Bubble, { variant: m.mine ? "primary" : void 0, align: m.mine ? "end" : void 0, children: m.text }) }, m.id)) }) });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// src/blocks/chat-thread-block.meta.ts
|
|
71
|
-
var chatThreadBlockMeta = {
|
|
72
|
-
name: "ChatThreadBlock",
|
|
73
|
-
family: "Social & messaging",
|
|
74
|
-
kind: "card",
|
|
75
|
-
width: { min: "16rem", max: "20rem" },
|
|
76
|
-
summary: "A short message thread on a card: Message rows with incoming muted Bubbles on the start side and your own primary Bubbles on the end.",
|
|
77
|
-
intent: "Reach for this to show a conversation excerpt \u2014 a support preview, a comment thread on a dashboard, a recent-DM card. A working chat with a composer, streaming and history is the ChatPanel page shell.",
|
|
78
|
-
notes: [
|
|
79
|
-
"Sit it on a card, not straight on a muted page: incoming bubbles are the muted surface, and would vanish into it.",
|
|
80
|
-
"Your own messages align to the end with the primary Bubble; everyone else's align to the start."
|
|
81
|
-
],
|
|
82
|
-
a11y: [
|
|
83
|
-
"Each Message carries a messageId, so a thread can be addressed and announced item by item.",
|
|
84
|
-
"Direction is shown by alignment and colour; when senders matter, add the sender's name to each Message."
|
|
85
|
-
]
|
|
86
|
-
};
|
|
87
|
-
var commands = [
|
|
88
|
-
{ id: "new-project", icon: "plus", label: "New project", key: "N" },
|
|
89
|
-
{ id: "invite", icon: "user", label: "Invite teammate", key: "I" },
|
|
90
|
-
{ id: "settings", icon: "gear", label: "Open settings", key: "," }
|
|
91
|
-
];
|
|
92
|
-
function CommandPaletteBlock({ className, onCommand }) {
|
|
93
|
-
const items = commands.map((c) => ({
|
|
94
|
-
id: c.id,
|
|
95
|
-
group: "Actions",
|
|
96
|
-
icon: c.icon,
|
|
97
|
-
label: c.label,
|
|
98
|
-
hint: /* @__PURE__ */ jsx(Kbd, { children: c.key }),
|
|
99
|
-
onSelect: () => onCommand?.(c.id)
|
|
100
|
-
}));
|
|
101
|
-
return /* @__PURE__ */ jsx(CommandMenuPanel, { className: cn("w-full max-w-xs shadow-sm", className), placeholder: "Type a command\u2026", items });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// src/blocks/command-palette-block.meta.ts
|
|
105
|
-
var commandPaletteBlockMeta = {
|
|
106
|
-
name: "CommandPaletteBlock",
|
|
107
|
-
family: "Navigation",
|
|
108
|
-
kind: "card",
|
|
109
|
-
width: { min: "18rem", max: "20rem" },
|
|
110
|
-
summary: "An inline command palette: CommandMenuPanel with a filter field and grouped actions, each with an icon and its keyboard shortcut.",
|
|
111
|
-
intent: "Reach for this to show a command list in place \u2014 an empty state that teaches shortcuts, an onboarding step, a quick-actions card. The \u2318K palette that opens over the app is CommandMenu; this is its panel without the dialog.",
|
|
112
|
-
notes: [
|
|
113
|
-
"Each command shows its shortcut as a Kbd hint, so the palette also teaches the keys.",
|
|
114
|
-
"`onCommand` receives the command's id; ids also key the rows, so two commands may share a label.",
|
|
115
|
-
"No card around it: the panel is its own surface, lifted with `shadow-sm` when it sits on a muted section."
|
|
116
|
-
],
|
|
117
|
-
a11y: [
|
|
118
|
-
"CommandMenuPanel wires the filter input to the list as a combobox, with arrow-key navigation and the active row announced.",
|
|
119
|
-
"Shortcut hints are Kbd elements, read as keys."
|
|
120
|
-
]
|
|
121
|
-
};
|
|
122
|
-
var cta = {
|
|
123
|
-
title: "Build the product, not another component library",
|
|
124
|
-
lede: "Install Sable, pick a preset, and ship the first screen today.",
|
|
125
|
-
primary: { label: "Get started", href: "/docs/getting-started" },
|
|
126
|
-
secondary: { label: "Star on GitHub", href: "/github" }
|
|
127
|
-
};
|
|
128
|
-
function CtaBandBlock({ className }) {
|
|
129
|
-
const titleId = useId();
|
|
130
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", "aria-labelledby": titleId, max: "wide", className: cn("w-full py-16", className), children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", className: "py-8 text-center sm:py-12", children: [
|
|
131
|
-
/* @__PURE__ */ jsx("h2", { id: titleId, className: "max-w-2xl text-balance text-heading-1", children: cta.title }),
|
|
132
|
-
/* @__PURE__ */ jsx("p", { className: "max-w-(--measure-prose) text-body-lg text-muted-foreground", children: cta.lede }),
|
|
133
|
-
/* @__PURE__ */ jsxs(Row, { gap: 2, justify: "center", wrap: true, className: "pt-2", children: [
|
|
134
|
-
/* @__PURE__ */ jsx(Button, { size: "cta", render: /* @__PURE__ */ jsx("a", { href: cta.primary.href }), children: cta.primary.label }),
|
|
135
|
-
/* @__PURE__ */ jsx(Button, { size: "cta", variant: "outline", render: /* @__PURE__ */ jsx("a", { href: cta.secondary.href }), children: cta.secondary.label })
|
|
136
|
-
] })
|
|
137
|
-
] }) }) }) });
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// src/blocks/cta-band-block.meta.ts
|
|
141
|
-
var ctaBandBlockMeta = {
|
|
142
|
-
name: "CtaBandBlock",
|
|
143
|
-
family: "Marketing",
|
|
144
|
-
kind: "section",
|
|
145
|
-
summary: "A closing call to action: a centred h2 and one-line lede on a card, with a primary and an outline action.",
|
|
146
|
-
intent: "Reach for this as the last section before the footer, repeating the hero's primary action once the reader has seen the case. Mid-page prompts to sign up belong inline, not in a band.",
|
|
147
|
-
notes: [
|
|
148
|
-
"Copied from the LandingPage page shell's closing call to action.",
|
|
149
|
-
"The primary action matches the hero's, so the page asks for one thing twice rather than two things once.",
|
|
150
|
-
"Sitting on a Card lifts it from the page without a coloured band, so it follows any preset."
|
|
151
|
-
],
|
|
152
|
-
a11y: [
|
|
153
|
-
"The section is labelled by its h2.",
|
|
154
|
-
"Both actions are links styled as Buttons, because they navigate."
|
|
155
|
-
]
|
|
156
|
-
};
|
|
157
|
-
var account = { handle: "ada", editions: 12 };
|
|
158
|
-
function DangerZoneBlock({ className, framed = true, onDelete }) {
|
|
159
|
-
const [open, setOpen] = useState(false);
|
|
160
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
161
|
-
/* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-2xl", className), children: [
|
|
162
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
163
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Delete account" }),
|
|
164
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Permanently remove your profile, editions, and sales history. Collectors keep the editions they own." })
|
|
165
|
-
] }),
|
|
166
|
-
/* @__PURE__ */ jsx(CardFooter, { actions: true, className: "justify-end", children: /* @__PURE__ */ jsx(Button, { variant: "destructive", onClick: () => setOpen(true), children: "Delete account" }) })
|
|
167
|
-
] }),
|
|
168
|
-
/* @__PURE__ */ jsx(
|
|
169
|
-
DestructiveActionModal,
|
|
170
|
-
{
|
|
171
|
-
open,
|
|
172
|
-
onOpenChange: setOpen,
|
|
173
|
-
title: "Delete your account?",
|
|
174
|
-
description: `This permanently removes your profile, ${account.editions} editions, and sales history. Pending payouts are still sent. This can't be undone.`,
|
|
175
|
-
confirmLabel: "Delete account",
|
|
176
|
-
confirmingLabel: "Deleting\u2026",
|
|
177
|
-
confirmText: account.handle,
|
|
178
|
-
onConfirm: () => {
|
|
179
|
-
setOpen(false);
|
|
180
|
-
onDelete?.();
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
)
|
|
184
|
-
] });
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// src/blocks/danger-zone-block.meta.ts
|
|
188
|
-
var dangerZoneBlockMeta = {
|
|
189
|
-
name: "DangerZoneBlock",
|
|
190
|
-
family: "Settings & team",
|
|
191
|
-
kind: "card",
|
|
192
|
-
width: { min: "20rem", max: "42rem" },
|
|
193
|
-
summary: "A delete-account card: what deleting removes and what survives, one destructive Button, and a DestructiveActionModal that asks for the handle to be typed before it acts.",
|
|
194
|
-
intent: "Reach for this as the last section of account, workspace or project settings. Deleting a single record from a list is an OverflowMenu item that opens DestructiveActionModal directly, not a card.",
|
|
195
|
-
notes: [
|
|
196
|
-
"Copied from the SettingsPage page shell's Delete account section.",
|
|
197
|
-
"The button never acts directly: it opens the modal, whose confirm stays disabled until the handle is typed.",
|
|
198
|
-
'The description says what is lost AND what is kept ("Collectors keep the editions they own"), which is what people want to know before they decide.'
|
|
199
|
-
],
|
|
200
|
-
a11y: [
|
|
201
|
-
"DestructiveActionModal is an alertdialog: focus opens on Cancel and the backdrop does not dismiss it.",
|
|
202
|
-
"The CardTitle is an h2, so the section is reachable by heading."
|
|
203
|
-
]
|
|
204
|
-
};
|
|
205
|
-
var days = Array.from({ length: 30 }, (_, i) => ({
|
|
206
|
-
date: new Date(2026, 8, 1 + i).toISOString().slice(0, 10),
|
|
207
|
-
desktop: Math.round(320 + Math.sin(i / 3) * 90 + i % 5 * 14),
|
|
208
|
-
mobile: Math.round(260 + Math.cos(i / 4) * 80 + i % 4 * 18)
|
|
209
|
-
}));
|
|
210
|
-
var series = [
|
|
211
|
-
{ key: "desktop", label: "Desktop" },
|
|
212
|
-
{ key: "mobile", label: "Mobile" }
|
|
213
|
-
];
|
|
214
|
-
var shortDate = (iso) => (/* @__PURE__ */ new Date(`${iso}T00:00:00`)).toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
215
|
-
function DeviceComparisonBlock({ className, framed = true }) {
|
|
216
|
-
const [active, setActive] = useState("desktop");
|
|
217
|
-
const totals = Object.fromEntries(series.map((s) => [s.key, days.reduce((sum, d) => sum + d[s.key], 0)]));
|
|
218
|
-
const current = series.find((s) => s.key === active) ?? series[0];
|
|
219
|
-
return (
|
|
220
|
-
// overflow-hidden: the square tiles meet the card's rounded corner.
|
|
221
|
-
/* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-3xl overflow-hidden", className), children: [
|
|
222
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col border-b border-border sm:flex-row", children: [
|
|
223
|
-
/* @__PURE__ */ jsxs(CardHeader, { className: "flex-1 pb-[var(--card-p,--spacing(6))]", children: [
|
|
224
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Visitors by device" }),
|
|
225
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "The last 30 days. Pick a device to plot it." })
|
|
226
|
-
] }),
|
|
227
|
-
/* @__PURE__ */ jsx(
|
|
228
|
-
ToggleGroup,
|
|
229
|
-
{
|
|
230
|
-
value: [active],
|
|
231
|
-
onValueChange: (v) => v[0] && setActive(String(v[0])),
|
|
232
|
-
"aria-label": "Device",
|
|
233
|
-
className: "items-stretch gap-0",
|
|
234
|
-
children: series.map((s) => /* @__PURE__ */ jsxs(
|
|
235
|
-
Toggle,
|
|
236
|
-
{
|
|
237
|
-
value: s.key,
|
|
238
|
-
className: "h-auto flex-1 flex-col items-start justify-center gap-1 rounded-none border-border px-6 py-4 text-start text-foreground max-sm:border-t sm:border-s",
|
|
239
|
-
children: [
|
|
240
|
-
/* @__PURE__ */ jsx("span", { className: "text-caption text-muted-foreground", children: s.label }),
|
|
241
|
-
/* @__PURE__ */ jsx("span", { className: "text-mono-lg", children: totals[s.key].toLocaleString("en-US") })
|
|
242
|
-
]
|
|
243
|
-
},
|
|
244
|
-
s.key
|
|
245
|
-
))
|
|
246
|
-
}
|
|
247
|
-
)
|
|
248
|
-
] }),
|
|
249
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(
|
|
250
|
-
BarChart,
|
|
251
|
-
{
|
|
252
|
-
label: `${current.label} visitors per day, last 30 days`,
|
|
253
|
-
data: days,
|
|
254
|
-
index: "date",
|
|
255
|
-
series: [current],
|
|
256
|
-
indexFormatter: shortDate,
|
|
257
|
-
radius: 3,
|
|
258
|
-
className: "h-64"
|
|
259
|
-
}
|
|
260
|
-
) })
|
|
261
|
-
] })
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// src/blocks/device-comparison-block.meta.ts
|
|
266
|
-
var deviceComparisonBlockMeta = {
|
|
267
|
-
name: "DeviceComparisonBlock",
|
|
268
|
-
family: "Dashboard",
|
|
269
|
-
kind: "card",
|
|
270
|
-
width: { min: "20rem", max: "48rem" },
|
|
271
|
-
summary: "A comparison card: each series' total sits in the header as a pressable tile, and the one pressed is plotted below as a daily BarChart.",
|
|
272
|
-
intent: "Reach for this when two or three measures share a page and the reader looks at one at a time \u2014 devices, regions, plans. To see them together, plot both in one BarChart or LineChart instead.",
|
|
273
|
-
notes: [
|
|
274
|
-
"The totals are the switch: Toggles in a labelled ToggleGroup, so the number and the control are one thing, with the group's own pressed and hover states.",
|
|
275
|
-
"Switching eases every bar to its new height rather than redrawing.",
|
|
276
|
-
"Below sm the tiles stack under the title and divide with a top rule instead of a side rule."
|
|
277
|
-
],
|
|
278
|
-
a11y: [
|
|
279
|
-
'Each total is a Toggle (aria-pressed) named by its label and value, in a ToggleGroup labelled "Device" with arrow-key movement between tiles.',
|
|
280
|
-
"The chart's name says which series is plotted, so the data table is unambiguous."
|
|
281
|
-
]
|
|
282
|
-
};
|
|
283
|
-
var event = {
|
|
284
|
-
title: "Design review",
|
|
285
|
-
date: new Date(2026, 9, 14),
|
|
286
|
-
when: "Tuesday, 2:00 \u2013 2:45 PM",
|
|
287
|
-
starts: "In 10 min",
|
|
288
|
-
attendees: ["MO", "SR", "JL"],
|
|
289
|
-
total: 7
|
|
290
|
-
};
|
|
291
|
-
function EventCardBlock({ className, framed = true, onRespond }) {
|
|
292
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
293
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex gap-4", children: [
|
|
294
|
-
/* @__PURE__ */ jsx(DateTile, { date: event.date }),
|
|
295
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
296
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-x-2 text-title-lg", children: [
|
|
297
|
-
/* @__PURE__ */ jsx(CardTitle, { children: event.title }),
|
|
298
|
-
/* @__PURE__ */ jsx("span", { className: "flex h-[1lh] shrink-0 items-center", children: /* @__PURE__ */ jsx(Badge, { tone: "info", size: "sm", children: event.starts }) })
|
|
299
|
-
] }),
|
|
300
|
-
/* @__PURE__ */ jsx(CardDescription, { children: event.when })
|
|
301
|
-
] })
|
|
302
|
-
] }),
|
|
303
|
-
/* @__PURE__ */ jsxs(CardFooter, { className: "flex-wrap justify-between gap-3", children: [
|
|
304
|
-
/* @__PURE__ */ jsx(AvatarGroup, { "aria-label": `${event.total} attendees`, total: event.total, size: "sm", surface: framed ? "card" : void 0, fit: true, children: event.attendees.map((initials) => /* @__PURE__ */ jsx(Avatar, { variant: "art", fallback: initials, alt: initials }, initials)) }),
|
|
305
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
306
|
-
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onRespond?.("decline"), children: "Decline" }),
|
|
307
|
-
/* @__PURE__ */ jsx(Button, { size: "sm", onClick: () => onRespond?.("join"), children: "Join" })
|
|
308
|
-
] })
|
|
309
|
-
] })
|
|
310
|
-
] });
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// src/blocks/event-card-block.meta.ts
|
|
314
|
-
var eventCardBlockMeta = {
|
|
315
|
-
name: "EventCardBlock",
|
|
316
|
-
family: "Dashboard",
|
|
317
|
-
kind: "card",
|
|
318
|
-
width: { min: "18rem", max: "20rem" },
|
|
319
|
-
summary: 'An upcoming-event card: a DateTile beside the title and time, a "starts in" Badge, attendees as an AvatarGroup, and Decline / Join.',
|
|
320
|
-
intent: "Reach for this for the next meeting, booking or live session on a dashboard or home screen. For a list of many upcoming events, use Entity rows with a DateTile as `leading`.",
|
|
321
|
-
notes: [
|
|
322
|
-
"The DateTile names the day; the full weekday and time range sit in text beside it.",
|
|
323
|
-
"The Badge is one title line tall and wraps under the title rather than squeezing it onto two lines.",
|
|
324
|
-
"AvatarGroup `fit` trades avatars for the +N count before it pushes the actions to their own line."
|
|
325
|
-
],
|
|
326
|
-
a11y: [
|
|
327
|
-
"DateTile is a <time> with a machine-readable date; the time range is plain text read in order after the title.",
|
|
328
|
-
"The AvatarGroup's aria-label states the total attendee count."
|
|
329
|
-
]
|
|
330
|
-
};
|
|
331
|
-
var intro = {
|
|
332
|
-
title: "Questions, answered",
|
|
333
|
-
lede: "Can't find what you need?",
|
|
334
|
-
contact: { label: "Write to us", href: "/contact" }
|
|
335
|
-
};
|
|
336
|
-
var questions = [
|
|
337
|
-
{ q: "Is there a free plan?", a: "Yes. Starter is free forever for three live editions, with no fees on your first $1,000 in sales." },
|
|
338
|
-
{ q: "Can I change plans later?", a: "Any time. Upgrades apply immediately and are prorated; downgrades take effect at the end of the billing period." },
|
|
339
|
-
{ q: "Who owns the work I sell?", a: "You do. Collectors own the editions they buy, and you keep the rights to the work itself." },
|
|
340
|
-
{ q: "How do payouts work?", a: "Sales clear after seven days and are paid out every Friday to the account you connect in settings." }
|
|
341
|
-
];
|
|
342
|
-
function FaqBlock({ className }) {
|
|
343
|
-
const titleId = useId();
|
|
344
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", "aria-labelledby": titleId, max: "content", className: cn("w-full py-16", className), children: /* @__PURE__ */ jsxs("div", { className: "grid gap-10 md:grid-cols-[1fr_2fr]", children: [
|
|
345
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
|
|
346
|
-
/* @__PURE__ */ jsx("h2", { id: titleId, className: "text-balance text-heading-2", children: intro.title }),
|
|
347
|
-
/* @__PURE__ */ jsxs("p", { className: "text-body-md text-muted-foreground", children: [
|
|
348
|
-
intro.lede,
|
|
349
|
-
" ",
|
|
350
|
-
/* @__PURE__ */ jsx("a", { href: intro.contact.href, className: "text-foreground underline underline-offset-4 motion-interactive hover:text-muted-foreground", children: intro.contact.label }),
|
|
351
|
-
"."
|
|
352
|
-
] })
|
|
353
|
-
] }),
|
|
354
|
-
/* @__PURE__ */ jsx(Accordion, { children: questions.map((item) => /* @__PURE__ */ jsxs(AccordionItem, { value: item.q, children: [
|
|
355
|
-
/* @__PURE__ */ jsx(AccordionTrigger, { children: item.q }),
|
|
356
|
-
/* @__PURE__ */ jsx(AccordionPanel, { children: item.a })
|
|
357
|
-
] }, item.q)) })
|
|
358
|
-
] }) });
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// src/blocks/faq-block.meta.ts
|
|
362
|
-
var faqBlockMeta = {
|
|
363
|
-
name: "FaqBlock",
|
|
364
|
-
family: "Marketing",
|
|
365
|
-
kind: "section",
|
|
366
|
-
summary: "A FAQ section: the heading and a way to ask beside an Accordion of questions, each answer one or two sentences.",
|
|
367
|
-
intent: "Reach for this near pricing or at the end of a landing page, for the questions that block a decision. Long help content belongs in docs, not an accordion.",
|
|
368
|
-
notes: [
|
|
369
|
-
"Every question starts closed: the list of questions is itself the useful summary.",
|
|
370
|
-
"The way to ask a human sits beside the heading, so it is found before the reader scrolls the list.",
|
|
371
|
-
"Capped at the `content` region width; questions wider than that are hard to scan."
|
|
372
|
-
],
|
|
373
|
-
a11y: [
|
|
374
|
-
"Accordion triggers are buttons with aria-expanded, inside headings, so the questions are navigable by heading and operable by keyboard.",
|
|
375
|
-
"The contact link is a real <a> inside the lede sentence."
|
|
376
|
-
]
|
|
377
|
-
};
|
|
378
|
-
var intro2 = {
|
|
379
|
-
eyebrow: "Why Sable",
|
|
380
|
-
title: "A design system with the rules written down",
|
|
381
|
-
lede: "The decisions a senior designer would make are encoded once, so every screen your team or your agent builds starts from them."
|
|
382
|
-
};
|
|
383
|
-
var features = [
|
|
384
|
-
{ icon: "component", title: "Behavior built in", body: "Focus management, keyboard navigation, and ARIA come from Base UI primitives under every control." },
|
|
385
|
-
{ icon: "eyedropper", title: "Semantic tokens end to end", body: "Re-theme the whole product, light and dark, from one preset without touching a component." },
|
|
386
|
-
{ icon: "layout", title: "Pages, not just parts", body: "Landing, dashboard, settings, auth, and list-detail shells to copy and adapt." },
|
|
387
|
-
{ icon: "book", title: "A contract agents can read", body: "registry.json, llms.txt, and a CLI hand agents the exact props, examples, and rules." },
|
|
388
|
-
{ icon: "circle-check", title: "Lint that knows the design", body: "sable-lint flags raw colors, hand-built controls, and motion that ignores reduced motion." },
|
|
389
|
-
{ icon: "play", title: "Motion with an off switch", body: "Named recipes run on one scale variable, so reduced motion stops every transition at once." }
|
|
390
|
-
];
|
|
391
|
-
function FeatureGridBlock({ className }) {
|
|
392
|
-
const titleId = useId();
|
|
393
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", "aria-labelledby": titleId, max: "wide", className: cn("w-full py-16 sm:py-24", className), children: /* @__PURE__ */ jsxs(Stack, { gap: 10, children: [
|
|
394
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 3, className: "max-w-2xl", children: [
|
|
395
|
-
/* @__PURE__ */ jsx("p", { className: "text-overline text-muted-foreground", children: intro2.eyebrow }),
|
|
396
|
-
/* @__PURE__ */ jsx("h2", { id: titleId, className: "text-balance text-heading-1", children: intro2.title }),
|
|
397
|
-
/* @__PURE__ */ jsx("p", { className: "text-body-lg text-muted-foreground", children: intro2.lede })
|
|
398
|
-
] }),
|
|
399
|
-
/* @__PURE__ */ jsx(Grid, { cols: { base: 1, sm: 2, lg: 3 }, gap: 4, children: features.map((feature) => /* @__PURE__ */ jsx(Card, { render: /* @__PURE__ */ jsx("article", {}), className: "h-full", children: /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-3", children: [
|
|
400
|
-
/* @__PURE__ */ jsx("span", { className: "grid size-10 place-items-center rounded-md sable-well", children: /* @__PURE__ */ jsx(Icon, { name: feature.icon, className: "text-xl" }) }),
|
|
401
|
-
/* @__PURE__ */ jsx("h3", { className: "pt-2 text-title-lg", children: feature.title }),
|
|
402
|
-
/* @__PURE__ */ jsx("p", { className: "text-body-sm text-muted-foreground", children: feature.body })
|
|
403
|
-
] }) }, feature.title)) })
|
|
404
|
-
] }) });
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// src/blocks/feature-grid-block.meta.ts
|
|
408
|
-
var featureGridBlockMeta = {
|
|
409
|
-
name: "FeatureGridBlock",
|
|
410
|
-
family: "Marketing",
|
|
411
|
-
kind: "section",
|
|
412
|
-
summary: "A feature section: an overline, an h2 and a lede over a grid of article cards, each with an icon in a well, a title and one sentence \u2014 1, 2 then 3 columns.",
|
|
413
|
-
intent: "Reach for this to explain what a product does in six or fewer points. For a sequence (first this, then that), use StepsBlock; for one proof point with numbers, TestimonialBlock.",
|
|
414
|
-
notes: [
|
|
415
|
-
"Copied from the LandingPage page shell's features section.",
|
|
416
|
-
"Six features fill 3 \xD7 2 evenly; keep the count a multiple of three, or drop to cols={{ lg: 2 }}.",
|
|
417
|
-
"Each body is one sentence. A feature that needs a paragraph needs its own section.",
|
|
418
|
-
"Icons sit in a `sable-well`, which derives its fill from the card surface it is on."
|
|
419
|
-
],
|
|
420
|
-
a11y: [
|
|
421
|
-
"Each feature is an <article> with an h3 under the section's h2.",
|
|
422
|
-
"The icons are decorative; each title says what the feature is."
|
|
423
|
-
]
|
|
424
|
-
};
|
|
425
|
-
var scale = ["1", "2", "3", "4", "5"];
|
|
426
|
-
function FeedbackFormBlock({ className, framed = true, onDone }) {
|
|
427
|
-
const [score, setScore] = useState("4");
|
|
428
|
-
const [notes, setNotes] = useState("");
|
|
429
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
430
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
431
|
-
/* @__PURE__ */ jsx(CardTitle, { children: "How was the session?" }),
|
|
432
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "One tap is enough. Notes help us more." })
|
|
433
|
-
] }),
|
|
434
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
|
|
435
|
-
/* @__PURE__ */ jsx(ToggleGroup, { value: [score], onValueChange: (v) => v[0] && setScore(String(v[0])), "aria-label": "Rating", className: "w-full", children: scale.map((n) => /* @__PURE__ */ jsx(Toggle, { value: n, className: "flex-1", children: n }, n)) }),
|
|
436
|
-
/* @__PURE__ */ jsx(Textarea, { placeholder: "What worked, what didn\u2019t\u2026", "aria-label": "Notes", rows: 3, value: notes, onChange: (e) => setNotes(e.target.value) })
|
|
437
|
-
] }),
|
|
438
|
-
/* @__PURE__ */ jsxs(CardFooter, { actions: true, className: "justify-end", children: [
|
|
439
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => onDone?.(false), children: "Skip" }),
|
|
440
|
-
/* @__PURE__ */ jsx(Button, { size: "sm", onClick: () => onDone?.(true, { score: Number(score), notes }), children: "Send feedback" })
|
|
441
|
-
] })
|
|
442
|
-
] });
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// src/blocks/feedback-form-block.meta.ts
|
|
446
|
-
var feedbackFormBlockMeta = {
|
|
447
|
-
name: "FeedbackFormBlock",
|
|
448
|
-
family: "Social & messaging",
|
|
449
|
-
kind: "card",
|
|
450
|
-
width: { min: "18rem", max: "20rem" },
|
|
451
|
-
summary: "A feedback card: a one-to-five rating as a full-width ToggleGroup, an optional notes field, and Skip / Send feedback.",
|
|
452
|
-
intent: "Reach for this for a post-session or post-purchase survey in a Sheet, Dialog or end-of-flow screen. For a feedback control anchored to a button in the app chrome, use the Feedback component (a popover).",
|
|
453
|
-
notes: [
|
|
454
|
-
"The rating is preselected, so one tap on Send is a complete answer; the notes are optional and say so.",
|
|
455
|
-
"Skip is a ghost Button before the primary, so dismissing is always available and never competes with sending.",
|
|
456
|
-
"`onDone` reports whether feedback was sent and, if so, the score and notes."
|
|
457
|
-
],
|
|
458
|
-
a11y: [
|
|
459
|
-
`The ToggleGroup carries aria-label="Rating"; each Toggle's number is its name.`,
|
|
460
|
-
'The Textarea carries aria-label="Notes"; its placeholder is a prompt, not the label.'
|
|
461
|
-
]
|
|
462
|
-
};
|
|
463
|
-
var goals = [
|
|
464
|
-
{ goal: "Releases", progress: 82 },
|
|
465
|
-
{ goal: "Collectors", progress: 64 },
|
|
466
|
-
{ goal: "Revenue", progress: 91 }
|
|
467
|
-
];
|
|
468
|
-
function GoalProgressBlock({ className, framed = true }) {
|
|
469
|
-
const behind = goals.filter((g) => g.progress < 70);
|
|
470
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-sm", className), children: [
|
|
471
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
472
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Quarter goals" }),
|
|
473
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Progress toward each target, in percent." })
|
|
474
|
-
] }),
|
|
475
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(RadialChart, { label: "Progress toward quarter goals", data: goals, index: "goal", valueKey: "progress", max: 100, className: "h-64", valueFormatter: (v) => `${v}%` }) }),
|
|
476
|
-
/* @__PURE__ */ jsx(CardFooter, { className: "text-body-sm text-muted-foreground", children: behind.length ? `${behind.map((g) => g.goal).join(" and ")} behind pace.` : "Every goal on pace." })
|
|
477
|
-
] });
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// src/blocks/goal-progress-block.meta.ts
|
|
481
|
-
var goalProgressBlockMeta = {
|
|
482
|
-
name: "GoalProgressBlock",
|
|
483
|
-
family: "Dashboard",
|
|
484
|
-
kind: "card",
|
|
485
|
-
width: { min: "18rem", max: "24rem" },
|
|
486
|
-
summary: "A goals card: a ring per goal in a RadialChart against its track (a full ring is 100%), a legend, and which goals are behind in the footer.",
|
|
487
|
-
intent: "Reach for this for progress toward two to four targets \u2014 a quarter's goals, a plan's limits, onboarding steps. A single reading in a settings row is a Meter; many goals are a list of Progress bars.",
|
|
488
|
-
notes: [
|
|
489
|
-
"max={100} makes a full ring mean done; each ring draws round from 12 o'clock as the card scrolls into view.",
|
|
490
|
-
"The footer names what is behind, so the card is actionable without reading the rings.",
|
|
491
|
-
"Values are formatted as percents in the tooltip and data table."
|
|
492
|
-
],
|
|
493
|
-
a11y: [
|
|
494
|
-
"The rings' data table lists each goal and its percent.",
|
|
495
|
-
"Arrowing through the rings announces each goal; the legend names every ring's colour."
|
|
496
|
-
]
|
|
497
|
-
};
|
|
498
|
-
var hero = {
|
|
499
|
-
eyebrow: "Open source \xB7 MIT licensed",
|
|
500
|
-
title: "Product UI your agents can't get wrong",
|
|
501
|
-
lede: "Sable is a themeable React component library with enforced tokens, typography, and motion, documented for coding agents as carefully as for people.",
|
|
502
|
-
primary: { label: "Get started", href: "/docs/getting-started" },
|
|
503
|
-
secondary: { label: "Browse components", href: "/components" },
|
|
504
|
-
install: "pnpm add @sableui/react"
|
|
505
|
-
};
|
|
506
|
-
function HeroBlock({ className }) {
|
|
507
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", max: "wide", className: cn("w-full py-16 sm:py-24", className), children: /* @__PURE__ */ jsxs(Stack, { gap: 8, align: "center", children: [
|
|
508
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", className: "text-center", children: [
|
|
509
|
-
/* @__PURE__ */ jsx(Badge, { appearance: "outline", size: "sm", icon: /* @__PURE__ */ jsx(Icon, { name: "sparkles" }), children: hero.eyebrow }),
|
|
510
|
-
/* @__PURE__ */ jsx("h1", { className: "max-w-4xl text-balance text-display-lg sm:text-display-2xl", children: hero.title }),
|
|
511
|
-
/* @__PURE__ */ jsx("p", { className: "max-w-(--measure-prose) text-pretty text-body-lg text-muted-foreground", children: hero.lede }),
|
|
512
|
-
/* @__PURE__ */ jsxs(Row, { gap: 2, justify: "center", wrap: true, className: "pt-2", children: [
|
|
513
|
-
/* @__PURE__ */ jsx(Button, { size: "cta", render: /* @__PURE__ */ jsx("a", { href: hero.primary.href }), children: hero.primary.label }),
|
|
514
|
-
/* @__PURE__ */ jsx(Button, { size: "cta", variant: "outline", render: /* @__PURE__ */ jsx("a", { href: hero.secondary.href }), children: hero.secondary.label })
|
|
515
|
-
] })
|
|
516
|
-
] }),
|
|
517
|
-
/* @__PURE__ */ jsx("div", { className: "w-full max-w-sm", children: /* @__PURE__ */ jsx(CodeBlock, { prompt: "$", code: hero.install }) })
|
|
518
|
-
] }) });
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// src/blocks/hero-block.meta.ts
|
|
522
|
-
var heroBlockMeta = {
|
|
523
|
-
name: "HeroBlock",
|
|
524
|
-
family: "Marketing",
|
|
525
|
-
kind: "section",
|
|
526
|
-
summary: "A centred hero: an outline Badge eyebrow, the page's h1 at display size, a lede, a primary and an outline call to action, and an install command in a CodeBlock.",
|
|
527
|
-
intent: "Reach for this to open a product or developer-tool landing page. A brand page that leads with a product scene beside the headline is the BrandLandingPage page shell's hero.",
|
|
528
|
-
notes: [
|
|
529
|
-
"Copied from the LandingPage page shell's hero.",
|
|
530
|
-
"The headline is the page's only h1 \u2014 place one HeroBlock per page.",
|
|
531
|
-
"Two actions, one primary. The install command is the third, quieter way in for developers who already decided.",
|
|
532
|
-
"The lede is capped at the prose measure and the headline at max-w-4xl, so both stay readable on wide screens."
|
|
533
|
-
],
|
|
534
|
-
a11y: [
|
|
535
|
-
"Calls to action are links styled as Buttons (render={<a />}), because they navigate.",
|
|
536
|
-
"The CodeBlock's copy button is labelled and announces when it has copied."
|
|
537
|
-
]
|
|
538
|
-
};
|
|
539
|
-
var collaborators = ["MO", "SR", "JL", "AK"];
|
|
540
|
-
function InviteTeamBlock({ className, framed = true, onSend }) {
|
|
541
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
542
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
543
|
-
/* @__PURE__ */ jsx(CardTitle, { children: "Invite your team" }),
|
|
544
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Collaborators can edit every project." })
|
|
545
|
-
] }),
|
|
546
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
|
|
547
|
-
/* @__PURE__ */ jsx(AvatarGroup, { "aria-label": `${collaborators.length} collaborators`, size: "sm", surface: framed ? "card" : void 0, children: collaborators.map((initials) => /* @__PURE__ */ jsx(Avatar, { variant: "art", fallback: initials, alt: initials }, initials)) }),
|
|
548
|
-
/* @__PURE__ */ jsxs(
|
|
549
|
-
"form",
|
|
550
|
-
{
|
|
551
|
-
className: "flex gap-2",
|
|
552
|
-
onSubmit: (event2) => {
|
|
553
|
-
event2.preventDefault();
|
|
554
|
-
onSend?.(String(new FormData(event2.currentTarget).get("email") ?? ""));
|
|
555
|
-
},
|
|
556
|
-
children: [
|
|
557
|
-
/* @__PURE__ */ jsx(Input, { name: "email", type: "email", placeholder: "name@company.com", "aria-label": "Email address" }),
|
|
558
|
-
/* @__PURE__ */ jsx(Button, { type: "submit", children: "Send" })
|
|
559
|
-
]
|
|
560
|
-
}
|
|
561
|
-
)
|
|
562
|
-
] })
|
|
563
|
-
] });
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// src/blocks/invite-team-block.meta.ts
|
|
567
|
-
var inviteTeamBlockMeta = {
|
|
568
|
-
name: "InviteTeamBlock",
|
|
569
|
-
family: "Settings & team",
|
|
570
|
-
kind: "card",
|
|
571
|
-
width: { min: "18rem", max: "20rem" },
|
|
572
|
-
summary: "An invite card: who is already on the team as an AvatarGroup, and an email field with Send.",
|
|
573
|
-
intent: "Reach for this for team or project invites in onboarding, an empty workspace, or a settings section. For managing an existing member list with roles, use a CardList of Entity rows instead.",
|
|
574
|
-
notes: [
|
|
575
|
-
"The field and Send are a <form>, so Enter sends; `onSend` receives the typed address.",
|
|
576
|
-
"The AvatarGroup ring matches the card surface when framed and inherits the host surface when not."
|
|
577
|
-
],
|
|
578
|
-
a11y: [
|
|
579
|
-
"The AvatarGroup carries an aria-label with the count, so the stack reads as one item, not four initials.",
|
|
580
|
-
"The email Input carries aria-label; there is no visible label in this compact layout."
|
|
581
|
-
]
|
|
582
|
-
};
|
|
583
|
-
var invoices = [
|
|
584
|
-
{ id: "INV-0042", date: "Oct 1, 2026", plan: "Studio \xB7 yearly", amount: "$192.00", status: "Paid" },
|
|
585
|
-
{ id: "INV-0031", date: "Sep 1, 2026", plan: "Studio \xB7 monthly", amount: "$20.00", status: "Paid" },
|
|
586
|
-
{ id: "INV-0027", date: "Aug 1, 2026", plan: "Studio \xB7 monthly", amount: "$20.00", status: "Refunded" },
|
|
587
|
-
{ id: "INV-0019", date: "Jul 1, 2026", plan: "Starter", amount: "$0.00", status: "Paid" }
|
|
588
|
-
];
|
|
589
|
-
function InvoiceHistoryBlock({ className, framed = true, onDownload }) {
|
|
590
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-2xl", className), children: [
|
|
591
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
592
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Invoices" }),
|
|
593
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Sent to billing@studio.com on the 1st of each month." })
|
|
594
|
-
] }),
|
|
595
|
-
/* @__PURE__ */ jsx(CardContent, { flush: true, className: "overflow-x-auto scrollbar-quiet", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
596
|
-
/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
597
|
-
/* @__PURE__ */ jsx(TableHead, { children: "Date" }),
|
|
598
|
-
/* @__PURE__ */ jsx(TableHead, { children: "Plan" }),
|
|
599
|
-
/* @__PURE__ */ jsx(TableHead, { numeric: true, children: "Amount" }),
|
|
600
|
-
/* @__PURE__ */ jsx(TableHead, { children: "Status" }),
|
|
601
|
-
/* @__PURE__ */ jsx(TableHead, { className: "w-0", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Download" }) })
|
|
602
|
-
] }) }),
|
|
603
|
-
/* @__PURE__ */ jsx(TableBody, { children: invoices.map((invoice) => /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
604
|
-
/* @__PURE__ */ jsx(TableCell, { className: "whitespace-nowrap", children: invoice.date }),
|
|
605
|
-
/* @__PURE__ */ jsx(TableCell, { className: "text-muted-foreground", children: invoice.plan }),
|
|
606
|
-
/* @__PURE__ */ jsx(TableCell, { numeric: true, children: invoice.amount }),
|
|
607
|
-
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { appearance: "plain", tone: invoice.status === "Paid" ? "success" : "neutral", dot: true, children: invoice.status }) }),
|
|
608
|
-
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": `Download ${invoice.id}`, onClick: () => onDownload?.(invoice.id), children: /* @__PURE__ */ jsx(Icon, { name: "download" }) }) })
|
|
609
|
-
] }, invoice.id)) })
|
|
610
|
-
] }) })
|
|
611
|
-
] });
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// src/blocks/invoice-history-block.meta.ts
|
|
615
|
-
var invoiceHistoryBlockMeta = {
|
|
616
|
-
name: "InvoiceHistoryBlock",
|
|
617
|
-
family: "Commerce",
|
|
618
|
-
kind: "card",
|
|
619
|
-
width: { min: "20rem", max: "42rem" },
|
|
620
|
-
summary: "A billing history card: a flush Table of date, plan, amount and status per invoice, with a download button on each row.",
|
|
621
|
-
intent: "Reach for this in billing settings, under the current plan. For a long, filterable history (hundreds of rows, date ranges, export), use DataTable on its own page.",
|
|
622
|
-
notes: [
|
|
623
|
-
"The table runs edge to edge (CardContent flush); its first and last columns still line up with the card header's padding.",
|
|
624
|
-
"Amounts are a numeric column \u2014 right-aligned with tabular figures \u2014 so they compare by eye.",
|
|
625
|
-
"On a narrow screen the table scrolls sideways inside the card (with a quiet scrollbar) rather than squeezing its columns."
|
|
626
|
-
],
|
|
627
|
-
a11y: [
|
|
628
|
-
'The download column has a screen-reader-only header, and each button names its invoice ("Download INV-0042").',
|
|
629
|
-
"Status is text in a Badge; the dot's colour only reinforces it."
|
|
630
|
-
]
|
|
631
|
-
};
|
|
632
|
-
var kpis = [
|
|
633
|
-
{ label: "Revenue", value: "$18,240", delta: "+8.2%", up: true, trend: [12, 14, 13, 17, 16, 19, 18, 21, 20, 24, 23, 26], tone: "success" },
|
|
634
|
-
{ label: "Active users", value: "3,912", delta: "+3.1%", up: true, trend: [30, 31, 29, 33, 34, 33, 36, 35, 37, 38, 37, 39], tone: "info" },
|
|
635
|
-
{ label: "Churn", value: "4.1%", delta: "\u22120.6%", up: false, trend: [9, 8, 9, 7, 8, 6, 7, 5, 6, 4, 5, 4], tone: "warning" }
|
|
636
|
-
];
|
|
637
|
-
function KpiSparklineBlock({ className }) {
|
|
638
|
-
return /* @__PURE__ */ jsx(Grid, { cols: { base: 1, sm: 3 }, gap: 3, className: cn("w-full", className), children: kpis.map((kpi) => /* @__PURE__ */ jsxs(Card, { children: [
|
|
639
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
640
|
-
/* @__PURE__ */ jsx(CardDescription, { children: kpi.label }),
|
|
641
|
-
/* @__PURE__ */ jsx(CardTitle, { className: "text-mono-xl", children: kpi.value }),
|
|
642
|
-
/* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Sparkline, { label: `${kpi.label}, last 12 weeks`, data: [...kpi.trend], variant: "area", tone: kpi.tone }) })
|
|
643
|
-
] }),
|
|
644
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Badge, { tone: kpi.up ? "success" : "neutral", size: "sm", icon: /* @__PURE__ */ jsx(Icon, { name: kpi.up ? "arrow-up" : "arrow-down" }), children: [
|
|
645
|
-
kpi.delta,
|
|
646
|
-
" vs last quarter"
|
|
647
|
-
] }) })
|
|
648
|
-
] }, kpi.label)) });
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// src/blocks/kpi-sparkline-block.meta.ts
|
|
652
|
-
var kpiSparklineBlockMeta = {
|
|
653
|
-
name: "KpiSparklineBlock",
|
|
654
|
-
family: "Dashboard",
|
|
655
|
-
kind: "section",
|
|
656
|
-
summary: "A KPI row with trends: three stat cards, each the value in the metric mono tier, a Sparkline of its last twelve weeks, and the change as a Badge.",
|
|
657
|
-
intent: "Reach for this at the top of a dashboard or a landing page's proof section, where each number needs its recent shape. Without the trend, StatRowBlock is calmer; for one headline trend, TrafficTrendBlock.",
|
|
658
|
-
notes: [
|
|
659
|
-
"Each sparkline is coloured by what its measure is, and the change Badge by whether it is good: churn falling is good news in a warning-toned trend.",
|
|
660
|
-
"The sparklines draw on as the row scrolls into view.",
|
|
661
|
-
"One column on a phone, three from sm."
|
|
662
|
-
],
|
|
663
|
-
a11y: [
|
|
664
|
-
"Each Sparkline is an image named by the measure and the period, with its range spoken.",
|
|
665
|
-
"The change is stated in text (+8.2% vs last quarter) with an arrow icon; colour only reinforces it."
|
|
666
|
-
]
|
|
667
|
-
};
|
|
668
|
-
var track = { title: "Low tide, high noon", artist: "Juno Avery", position: 38, elapsed: "1:24", remaining: "-2:16" };
|
|
669
|
-
function MediaPlayerBlock({ className, framed = true, onPlayingChange, onPrevious, onNext }) {
|
|
670
|
-
const [playing, setPlaying] = useState(true);
|
|
671
|
-
return /* @__PURE__ */ jsx(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4", children: [
|
|
672
|
-
/* @__PURE__ */ jsx(
|
|
673
|
-
Entity,
|
|
674
|
-
{
|
|
675
|
-
className: "p-0",
|
|
676
|
-
leading: /* @__PURE__ */ jsx(GradientArt, { "aria-hidden": true, seed: track.title, className: "size-14 rounded-md" }),
|
|
677
|
-
title: track.title,
|
|
678
|
-
subtitle: track.artist,
|
|
679
|
-
action: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Like", children: /* @__PURE__ */ jsx(Icon, { name: "heart" }) })
|
|
680
|
-
}
|
|
681
|
-
),
|
|
682
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
683
|
-
/* @__PURE__ */ jsx(Slider, { defaultValue: track.position, "aria-label": "Position" }),
|
|
684
|
-
/* @__PURE__ */ jsxs("div", { className: "flex justify-between text-mono-caption text-muted-foreground", children: [
|
|
685
|
-
/* @__PURE__ */ jsx("span", { children: track.elapsed }),
|
|
686
|
-
/* @__PURE__ */ jsx("span", { children: track.remaining })
|
|
687
|
-
] })
|
|
688
|
-
] }),
|
|
689
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-3", children: [
|
|
690
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Previous", onClick: onPrevious, children: /* @__PURE__ */ jsx(Icon, { name: "previous", variant: "solid" }) }),
|
|
691
|
-
/* @__PURE__ */ jsx(
|
|
692
|
-
Button,
|
|
693
|
-
{
|
|
694
|
-
size: "icon",
|
|
695
|
-
"aria-label": playing ? "Pause" : "Play",
|
|
696
|
-
onClick: () => {
|
|
697
|
-
setPlaying(!playing);
|
|
698
|
-
onPlayingChange?.(!playing);
|
|
699
|
-
},
|
|
700
|
-
children: /* @__PURE__ */ jsx(Icon, { name: playing ? "pause" : "play", variant: "solid" })
|
|
701
|
-
}
|
|
702
|
-
),
|
|
703
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Next", onClick: onNext, children: /* @__PURE__ */ jsx(Icon, { name: "next", variant: "solid" }) })
|
|
704
|
-
] })
|
|
705
|
-
] }) });
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// src/blocks/media-player-block.meta.ts
|
|
709
|
-
var mediaPlayerBlockMeta = {
|
|
710
|
-
name: "MediaPlayerBlock",
|
|
711
|
-
family: "Media & files",
|
|
712
|
-
kind: "card",
|
|
713
|
-
width: { min: "18rem", max: "20rem" },
|
|
714
|
-
summary: "A now-playing card: cover, title and artist as an Entity with a Like action, a position Slider with elapsed and remaining time, and previous / play-pause / next.",
|
|
715
|
-
intent: "Reach for this for audio or video playback controls outside the media itself \u2014 a mini player, a podcast card, a preview in a feed. Playback over the video frame is the Video component's own chrome.",
|
|
716
|
-
notes: [
|
|
717
|
-
"Play/pause is the one filled control, centred between two ghost skips.",
|
|
718
|
-
"Times are `text-mono-caption`, so the digits do not shift as they count.",
|
|
719
|
-
"The cover is painted from the palette as a placeholder; swap it for the real artwork."
|
|
720
|
-
],
|
|
721
|
-
a11y: [
|
|
722
|
-
"Every icon-only Button carries aria-label, and play/pause's label follows its state.",
|
|
723
|
-
'The Slider carries aria-label="Position". Give it aria-valuetext in your player ("1:24 of 3:40") so the position is read as time, not a percentage.'
|
|
724
|
-
]
|
|
725
|
-
};
|
|
726
|
-
var newsletter = { title: "The Cove digest", body: "One note a month on trusted workflows and product releases." };
|
|
727
|
-
function NewsletterBlock({ className, framed = true, onSubscribe }) {
|
|
728
|
-
const emailId = useId();
|
|
729
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-sm", className), children: [
|
|
730
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
731
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: newsletter.title }),
|
|
732
|
-
/* @__PURE__ */ jsx(CardDescription, { children: newsletter.body })
|
|
733
|
-
] }),
|
|
734
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(
|
|
735
|
-
"form",
|
|
736
|
-
{
|
|
737
|
-
className: "grid gap-2 sm:grid-cols-[1fr_auto]",
|
|
738
|
-
onSubmit: (event2) => {
|
|
739
|
-
event2.preventDefault();
|
|
740
|
-
onSubscribe?.(String(new FormData(event2.currentTarget).get("email") ?? ""));
|
|
741
|
-
},
|
|
742
|
-
children: [
|
|
743
|
-
/* @__PURE__ */ jsx("label", { htmlFor: emailId, className: "sr-only", children: "Work email" }),
|
|
744
|
-
/* @__PURE__ */ jsx(Input, { id: emailId, name: "email", type: "email", autoComplete: "email", placeholder: "you@company.com", required: true }),
|
|
745
|
-
/* @__PURE__ */ jsx(Button, { type: "submit", className: "w-full sm:w-auto", children: "Subscribe" })
|
|
746
|
-
]
|
|
747
|
-
}
|
|
748
|
-
) })
|
|
749
|
-
] });
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// src/blocks/newsletter-block.meta.ts
|
|
753
|
-
var newsletterBlockMeta = {
|
|
754
|
-
name: "NewsletterBlock",
|
|
755
|
-
family: "Marketing",
|
|
756
|
-
kind: "card",
|
|
757
|
-
width: { min: "18rem", max: "24rem" },
|
|
758
|
-
summary: "A newsletter sign-up card: the list's name, what it sends and how often, and an email field with Subscribe.",
|
|
759
|
-
intent: "Reach for this in a footer, at the end of an article, or beside a changelog. Creating an account is SignUpBlock; inviting a teammate is InviteTeamBlock.",
|
|
760
|
-
notes: [
|
|
761
|
-
"Copied from the BrandLandingPage page shell's footer.",
|
|
762
|
-
"The description says how often mail arrives \u2014 the one thing people want to know before they subscribe.",
|
|
763
|
-
"The field and button sit side by side from sm up and stack on a phone, where the button goes full width."
|
|
764
|
-
],
|
|
765
|
-
a11y: [
|
|
766
|
-
"The input has a real (visually hidden) <label>, not just a placeholder.",
|
|
767
|
-
"The CardTitle renders an h2, so the sign-up is reachable by heading in a footer."
|
|
768
|
-
]
|
|
769
|
-
};
|
|
770
|
-
var notFound = {
|
|
771
|
-
code: "404",
|
|
772
|
-
title: "This page isn't here",
|
|
773
|
-
body: "It may have moved, or the link may be mistyped. Check the address, or head back to somewhere you know.",
|
|
774
|
-
home: { label: "Go home", href: "/" },
|
|
775
|
-
help: { label: "Search the docs", href: "/docs" }
|
|
776
|
-
};
|
|
777
|
-
function NotFoundBlock({ className }) {
|
|
778
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", max: "form", className: cn("w-full py-16 sm:py-24", className), children: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", className: "text-center", children: [
|
|
779
|
-
/* @__PURE__ */ jsx("p", { className: "text-mono-md text-muted-foreground", children: notFound.code }),
|
|
780
|
-
/* @__PURE__ */ jsx("h1", { className: "text-balance text-heading-1", children: notFound.title }),
|
|
781
|
-
/* @__PURE__ */ jsx("p", { className: "text-pretty text-body-md text-muted-foreground", children: notFound.body }),
|
|
782
|
-
/* @__PURE__ */ jsxs(Row, { gap: 2, justify: "center", wrap: true, className: "pt-2", children: [
|
|
783
|
-
/* @__PURE__ */ jsx(Button, { iconStart: /* @__PURE__ */ jsx(Icon, { name: "home" }), render: /* @__PURE__ */ jsx("a", { href: notFound.home.href }), children: notFound.home.label }),
|
|
784
|
-
/* @__PURE__ */ jsx(Button, { variant: "outline", iconStart: /* @__PURE__ */ jsx(Icon, { name: "search" }), render: /* @__PURE__ */ jsx("a", { href: notFound.help.href }), children: notFound.help.label })
|
|
785
|
-
] })
|
|
786
|
-
] }) });
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// src/blocks/not-found-block.meta.ts
|
|
790
|
-
var notFoundBlockMeta = {
|
|
791
|
-
name: "NotFoundBlock",
|
|
792
|
-
family: "System",
|
|
793
|
-
kind: "section",
|
|
794
|
-
summary: "A not-found page body: the status code in mono, a plain-language h1, what probably happened, and two ways on \u2014 home and search.",
|
|
795
|
-
intent: "Reach for this as the body of a 404 route. An empty list or a search with no results inside a working page is EmptyState, not this.",
|
|
796
|
-
notes: [
|
|
797
|
-
"The heading says what happened in words; the code is a small mono label for people who look for it.",
|
|
798
|
-
"Two ways on, one primary. Never a dead end with only the browser's back button.",
|
|
799
|
-
"Capped at the `form` region width, so the short message stays a tight, centred column."
|
|
800
|
-
],
|
|
801
|
-
a11y: [
|
|
802
|
-
"It renders the page's h1 \u2014 use it as the route's main content, inside <main>.",
|
|
803
|
-
"Both actions are links styled as Buttons, because they navigate."
|
|
804
|
-
]
|
|
805
|
-
};
|
|
806
|
-
var notifications = [
|
|
807
|
-
{ initials: "MO", name: "Mara Okafor", what: "collected your edition", when: "2m", unread: true },
|
|
808
|
-
{ initials: "SR", name: "Sam Rivera", what: "left a comment on Dusk", when: "1h", unread: false }
|
|
809
|
-
];
|
|
810
|
-
function NotificationListBlock({ className, framed = true }) {
|
|
811
|
-
return /* @__PURE__ */ jsx(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs overflow-hidden", className), children: /* @__PURE__ */ jsx(CardList, { children: notifications.map((n) => /* @__PURE__ */ jsx(
|
|
812
|
-
Entity,
|
|
813
|
-
{
|
|
814
|
-
leading: /* @__PURE__ */ jsx(Avatar, { variant: "art", size: "sm", fallback: n.initials, alt: n.name }),
|
|
815
|
-
title: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
816
|
-
n.name,
|
|
817
|
-
n.unread ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: " (unread)" }) : null
|
|
818
|
-
] }),
|
|
819
|
-
subtitle: n.what,
|
|
820
|
-
action: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-caption text-muted-foreground", children: [
|
|
821
|
-
n.unread ? /* @__PURE__ */ jsx(StatusDot, { tone: "info" }) : null,
|
|
822
|
-
n.when
|
|
823
|
-
] })
|
|
824
|
-
},
|
|
825
|
-
n.name
|
|
826
|
-
)) }) });
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// src/blocks/notification-list-block.meta.ts
|
|
830
|
-
var notificationListBlockMeta = {
|
|
831
|
-
name: "NotificationListBlock",
|
|
832
|
-
family: "Social & messaging",
|
|
833
|
-
kind: "card",
|
|
834
|
-
width: { min: "18rem", max: "20rem" },
|
|
835
|
-
summary: "An activity list: Entity rows with the actor's Avatar, who did what, and a compact time with an unread StatusDot.",
|
|
836
|
-
intent: "Reach for this for a notifications popover, a recent-activity card or an inbox preview. A full inbox with selection and bulk actions is a ListDetailPage.",
|
|
837
|
-
notes: [
|
|
838
|
-
"Rows are Card + CardList + Entity, inset from the card's padding at any density.",
|
|
839
|
-
"Unread is a quiet info dot before the time, so the times keep one right edge \u2014 the list stays calm when most items are unread.",
|
|
840
|
-
"framed={false} drops the surface for a Popover, which already is one."
|
|
841
|
-
],
|
|
842
|
-
a11y: [
|
|
843
|
-
'The unread dot is decorative; each unread row also carries a screen-reader-only "(unread)" after the name.',
|
|
844
|
-
"Each Avatar's alt is the actor's name."
|
|
845
|
-
]
|
|
846
|
-
};
|
|
847
|
-
var preferences = [
|
|
848
|
-
{ id: "email", title: "Email notifications", detail: "Replies and mentions", on: true },
|
|
849
|
-
{ id: "push", title: "Push notifications", detail: "On this device", on: false },
|
|
850
|
-
{ id: "digest", title: "Weekly digest", detail: "Every Monday", on: true }
|
|
851
|
-
];
|
|
852
|
-
function NotificationSettingsBlock({ className, framed = true, onChange }) {
|
|
853
|
-
return /* @__PURE__ */ jsx(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs overflow-hidden", className), children: /* @__PURE__ */ jsx(CardList, { children: preferences.map((p) => /* @__PURE__ */ jsx(
|
|
854
|
-
Entity,
|
|
855
|
-
{
|
|
856
|
-
title: p.title,
|
|
857
|
-
subtitle: p.detail,
|
|
858
|
-
action: /* @__PURE__ */ jsx(Switch, { defaultChecked: p.on, "aria-label": p.title, onCheckedChange: (on) => onChange?.(p.id, on) })
|
|
859
|
-
},
|
|
860
|
-
p.id
|
|
861
|
-
)) }) });
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
// src/blocks/notification-settings-block.meta.ts
|
|
865
|
-
var notificationSettingsBlockMeta = {
|
|
866
|
-
name: "NotificationSettingsBlock",
|
|
867
|
-
family: "Settings & team",
|
|
868
|
-
kind: "card",
|
|
869
|
-
width: { min: "18rem", max: "20rem" },
|
|
870
|
-
summary: "A preferences card: Entity rows in a CardList, each with a title, a one-line detail and a Switch that applies instantly.",
|
|
871
|
-
intent: "Reach for this for any short list of on/off preferences \u2014 notifications, privacy, feature flags in a settings section. For a full settings route with a section rail, start from the SettingsPage page shell.",
|
|
872
|
-
notes: [
|
|
873
|
-
"Switches apply the moment they change; never pair them with a Save button. `onChange` receives the row id and the new state.",
|
|
874
|
-
"Rows are Card + CardList + Entity, so they inset with the card's padding at any density."
|
|
875
|
-
],
|
|
876
|
-
a11y: [
|
|
877
|
-
"Each Switch takes its row title as aria-label, since the Entity title is not a <label>.",
|
|
878
|
-
"Keep details to one line \u2014 Entity truncates its subtitle."
|
|
879
|
-
]
|
|
880
|
-
};
|
|
881
|
-
var order = { number: "Order #2048", item: "Gicl\xE9e print, 18 \xD7 24 in", status: "In transit", current: 2 };
|
|
882
|
-
var steps = [
|
|
883
|
-
{ title: "Order placed", detail: "Oct 9, 10:14 AM" },
|
|
884
|
-
{ title: "Printed and packed", detail: "Oct 10, 4:02 PM" },
|
|
885
|
-
{ title: "Out for delivery", detail: "Arriving today by 6 PM" },
|
|
886
|
-
{ title: "Delivered", detail: void 0 }
|
|
887
|
-
];
|
|
888
|
-
function OrderTrackingBlock({ className, framed = true }) {
|
|
889
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
890
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
891
|
-
/* @__PURE__ */ jsx(CardTitle, { children: order.number }),
|
|
892
|
-
/* @__PURE__ */ jsx(CardDescription, { children: order.item }),
|
|
893
|
-
/* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Badge, { tone: "warning", size: "sm", children: order.status }) })
|
|
894
|
-
] }),
|
|
895
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(Stepper, { orientation: "vertical", indicator: "dot", current: order.current, "aria-label": "Delivery status", children: steps.map((step) => /* @__PURE__ */ jsx(StepperItem, { title: step.title, description: step.detail }, step.title)) }) })
|
|
896
|
-
] });
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
// src/blocks/order-tracking-block.meta.ts
|
|
900
|
-
var orderTrackingBlockMeta = {
|
|
901
|
-
name: "OrderTrackingBlock",
|
|
902
|
-
family: "Commerce",
|
|
903
|
-
kind: "card",
|
|
904
|
-
width: { min: "18rem", max: "20rem" },
|
|
905
|
-
summary: "An order status card: order number, item and a status Badge in the header over a vertical dot Stepper of delivery milestones.",
|
|
906
|
-
intent: "Reach for this for anything that moves through known stages \u2014 a delivery, an application, a review, a deployment. For an open-ended activity log, use a list of Entity rows with timestamps instead.",
|
|
907
|
-
notes: [
|
|
908
|
-
"The Stepper's `current` is the step under way; finished steps show their timestamp and future steps show none.",
|
|
909
|
-
"The status Badge restates the current stage in one word so the card scans without reading the steps."
|
|
910
|
-
],
|
|
911
|
-
a11y: [
|
|
912
|
-
'The Stepper is labelled "Delivery status" and marks the current step for assistive tech.',
|
|
913
|
-
"The Badge's tone is backed by its text; colour alone never carries the status."
|
|
914
|
-
]
|
|
915
|
-
};
|
|
916
|
-
var plan = {
|
|
917
|
-
monthly: { price: "$20", note: "Billed monthly. Cancel anytime." },
|
|
918
|
-
yearly: { price: "$16", note: "Billed $192 yearly. You save 20%." },
|
|
919
|
-
features: ["Unlimited projects", "Version history", "Priority support"]
|
|
920
|
-
};
|
|
921
|
-
function PricingCardBlock({ className, framed = true, onStart }) {
|
|
922
|
-
const [period, setPeriod] = useState("yearly");
|
|
923
|
-
return /* @__PURE__ */ jsx(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-5", children: [
|
|
924
|
-
/* @__PURE__ */ jsxs(
|
|
925
|
-
ToggleGroup,
|
|
926
|
-
{
|
|
927
|
-
value: [period],
|
|
928
|
-
onValueChange: (v) => v[0] && setPeriod(v[0]),
|
|
929
|
-
"aria-label": "Billing period",
|
|
930
|
-
className: "w-full",
|
|
931
|
-
children: [
|
|
932
|
-
/* @__PURE__ */ jsx(Toggle, { value: "monthly", className: "flex-1", children: "Monthly" }),
|
|
933
|
-
/* @__PURE__ */ jsx(Toggle, { value: "yearly", className: "flex-1", children: "Yearly" })
|
|
934
|
-
]
|
|
935
|
-
}
|
|
936
|
-
),
|
|
937
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
938
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1.5", children: [
|
|
939
|
-
/* @__PURE__ */ jsx("span", { className: "text-heading-2", children: plan[period].price }),
|
|
940
|
-
/* @__PURE__ */ jsx("span", { className: "text-body-sm text-muted-foreground", children: "per seat / month" })
|
|
941
|
-
] }),
|
|
942
|
-
/* @__PURE__ */ jsx("span", { className: "text-body-sm text-muted-foreground", children: plan[period].note })
|
|
943
|
-
] }),
|
|
944
|
-
/* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2 text-body-sm", children: plan.features.map((feature) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2", children: [
|
|
945
|
-
/* @__PURE__ */ jsx(Icon, { name: "check", className: "text-success" }),
|
|
946
|
-
feature
|
|
947
|
-
] }, feature)) }),
|
|
948
|
-
/* @__PURE__ */ jsx(Button, { className: "w-full", onClick: () => onStart?.(period), children: "Start free trial" })
|
|
949
|
-
] }) });
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// src/blocks/pricing-card-block.meta.ts
|
|
953
|
-
var pricingCardBlockMeta = {
|
|
954
|
-
name: "PricingCardBlock",
|
|
955
|
-
family: "Commerce",
|
|
956
|
-
kind: "card",
|
|
957
|
-
width: { min: "18rem", max: "20rem" },
|
|
958
|
-
summary: "A single-plan pricing card: a Monthly/Yearly ToggleGroup, the price and billing note, a checked feature list, and one full-width call to action.",
|
|
959
|
-
intent: "Reach for this when one plan is on offer \u2014 an upgrade prompt, a paywall, a plan summary in billing settings. Comparing several tiers side by side is a pricing table, not three of these.",
|
|
960
|
-
notes: [
|
|
961
|
-
"The period switch is a ToggleGroup (a segmented control), not Tabs: it changes a value in place rather than showing another panel.",
|
|
962
|
-
"The price is a heading tier because it is the card's headline; its unit and billing note sit beside and below it in muted body text.",
|
|
963
|
-
"`onStart` receives the period showing, so checkout opens on the plan the person was looking at."
|
|
964
|
-
],
|
|
965
|
-
a11y: [
|
|
966
|
-
`The ToggleGroup carries aria-label="Billing period"; each Toggle's text is its name.`,
|
|
967
|
-
"The check icons are decorative beside each feature's text."
|
|
968
|
-
]
|
|
969
|
-
};
|
|
970
|
-
var tiers = [
|
|
971
|
-
{
|
|
972
|
-
id: "starter",
|
|
973
|
-
name: "Starter",
|
|
974
|
-
blurb: "For one person shipping their first editions.",
|
|
975
|
-
monthly: 0,
|
|
976
|
-
yearly: 0,
|
|
977
|
-
cta: "Start for free",
|
|
978
|
-
featured: false,
|
|
979
|
-
features: ["3 live editions", "Collector profiles", "Community support"]
|
|
980
|
-
},
|
|
981
|
-
{
|
|
982
|
-
id: "studio",
|
|
983
|
-
name: "Studio",
|
|
984
|
-
blurb: "For working artists with a steady release schedule.",
|
|
985
|
-
monthly: 20,
|
|
986
|
-
yearly: 16,
|
|
987
|
-
cta: "Start free trial",
|
|
988
|
-
featured: true,
|
|
989
|
-
features: ["Unlimited editions", "Scheduled drops", "Sales analytics", "Priority support"]
|
|
990
|
-
},
|
|
991
|
-
{
|
|
992
|
-
id: "collective",
|
|
993
|
-
name: "Collective",
|
|
994
|
-
blurb: "For galleries and teams releasing together.",
|
|
995
|
-
monthly: 48,
|
|
996
|
-
yearly: 40,
|
|
997
|
-
cta: "Talk to sales",
|
|
998
|
-
featured: false,
|
|
999
|
-
features: ["Everything in Studio", "Up to 10 seats", "Shared payouts", "Roles and approvals"]
|
|
1000
|
-
}
|
|
1001
|
-
];
|
|
1002
|
-
function PricingTableBlock({ className, onChoose }) {
|
|
1003
|
-
const [period, setPeriod] = useState("yearly");
|
|
1004
|
-
const titleId = useId();
|
|
1005
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", "aria-labelledby": titleId, max: "wide", className: cn("w-full py-16", className), children: /* @__PURE__ */ jsxs(Stack, { gap: 10, children: [
|
|
1006
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", className: "text-center", children: [
|
|
1007
|
-
/* @__PURE__ */ jsx("h2", { id: titleId, className: "text-balance text-heading-1", children: "Pricing that grows with your practice" }),
|
|
1008
|
-
/* @__PURE__ */ jsx("p", { className: "max-w-(--measure-prose) text-body-lg text-muted-foreground", children: "Every plan includes unlimited collectors and no fees on your first $1,000 in sales." }),
|
|
1009
|
-
/* @__PURE__ */ jsxs(ToggleGroup, { value: [period], onValueChange: (v) => v[0] && setPeriod(v[0]), "aria-label": "Billing period", children: [
|
|
1010
|
-
/* @__PURE__ */ jsx(Toggle, { value: "monthly", children: "Monthly" }),
|
|
1011
|
-
/* @__PURE__ */ jsx(Toggle, { value: "yearly", children: "Yearly \xB7 save 20%" })
|
|
1012
|
-
] })
|
|
1013
|
-
] }),
|
|
1014
|
-
/* @__PURE__ */ jsx(Grid, { cols: { base: 1, md: 3 }, gap: 4, className: "items-stretch", children: tiers.map((tier) => /* @__PURE__ */ jsxs(
|
|
1015
|
-
Card,
|
|
1016
|
-
{
|
|
1017
|
-
render: /* @__PURE__ */ jsx("article", {}),
|
|
1018
|
-
className: cn("flex flex-col", tier.featured && "border-primary ring-1 ring-primary"),
|
|
1019
|
-
children: [
|
|
1020
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1021
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h3", {}), children: tier.name }),
|
|
1022
|
-
/* @__PURE__ */ jsx(CardDescription, { children: tier.blurb }),
|
|
1023
|
-
tier.featured ? /* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Badge, { tone: "edition", size: "sm", children: "Most popular" }) }) : null
|
|
1024
|
-
] }),
|
|
1025
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-1 flex-col gap-5", children: [
|
|
1026
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1027
|
-
/* @__PURE__ */ jsxs("span", { className: "text-heading-2", children: [
|
|
1028
|
-
"$",
|
|
1029
|
-
tier[period]
|
|
1030
|
-
] }),
|
|
1031
|
-
/* @__PURE__ */ jsx("span", { className: "text-body-sm text-muted-foreground", children: "per seat / month" })
|
|
1032
|
-
] }),
|
|
1033
|
-
/* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2 text-body-sm", children: tier.features.map((feature) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2", children: [
|
|
1034
|
-
/* @__PURE__ */ jsx(Icon, { name: "check", className: "text-success" }),
|
|
1035
|
-
feature
|
|
1036
|
-
] }, feature)) })
|
|
1037
|
-
] }),
|
|
1038
|
-
/* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(Button, { className: "w-full", variant: tier.featured ? "primary" : "outline", onClick: () => onChoose?.(tier.id, period), children: tier.cta }) })
|
|
1039
|
-
]
|
|
1040
|
-
},
|
|
1041
|
-
tier.id
|
|
1042
|
-
)) })
|
|
1043
|
-
] }) });
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
// src/blocks/pricing-table-block.meta.ts
|
|
1047
|
-
var pricingTableBlockMeta = {
|
|
1048
|
-
name: "PricingTableBlock",
|
|
1049
|
-
family: "Commerce",
|
|
1050
|
-
kind: "section",
|
|
1051
|
-
summary: 'A three-tier pricing section: heading, a Monthly/Yearly ToggleGroup, and three equal-height plan cards with the recommended one outlined in primary and badged "Most popular".',
|
|
1052
|
-
intent: "Reach for this on a pricing page or the pricing band of a landing page, to compare plans side by side. A single plan on offer (an upgrade prompt, a paywall) is PricingCardBlock.",
|
|
1053
|
-
notes: [
|
|
1054
|
-
"One featured tier at most: it takes the primary button and a primary outline; the others take outline buttons so the recommendation is unmistakable.",
|
|
1055
|
-
"Cards stretch to the tallest one and push their buttons to the bottom, so the calls to action line up across the row.",
|
|
1056
|
-
"The yearly saving is stated in the toggle itself, where the choice is made. `onChoose` receives the tier id and the period showing."
|
|
1057
|
-
],
|
|
1058
|
-
a11y: [
|
|
1059
|
-
"Each plan is an <article> with an h3 under the section's h2, so the tiers are navigable by heading.",
|
|
1060
|
-
'The ToggleGroup is labelled "Billing period"; prices update in place and stay in the reading order of each card.'
|
|
1061
|
-
]
|
|
1062
|
-
};
|
|
1063
|
-
var product = { title: "Untitled (gold rush)", maker: "Mara Okafor", edition: "12 of 50", price: "0.42 SOL" };
|
|
1064
|
-
function ProductCardBlock({ className, framed = true, onCollect }) {
|
|
1065
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs overflow-hidden", className), children: [
|
|
1066
|
-
/* @__PURE__ */ jsx(GradientArt, { "aria-hidden": true, seed: product.title, className: "aspect-[4/3]" }),
|
|
1067
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1068
|
-
/* @__PURE__ */ jsx(CardTitle, { children: product.title }),
|
|
1069
|
-
/* @__PURE__ */ jsx(CardDescription, { children: product.maker }),
|
|
1070
|
-
/* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Badge, { tone: "edition", children: product.edition }) })
|
|
1071
|
-
] }),
|
|
1072
|
-
/* @__PURE__ */ jsxs(CardFooter, { className: "justify-between pt-4", children: [
|
|
1073
|
-
/* @__PURE__ */ jsx("span", { className: "text-mono-lg", children: product.price }),
|
|
1074
|
-
/* @__PURE__ */ jsx(Button, { onClick: onCollect, children: "Collect" })
|
|
1075
|
-
] })
|
|
1076
|
-
] });
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
// src/blocks/product-card-block.meta.ts
|
|
1080
|
-
var productCardBlockMeta = {
|
|
1081
|
-
name: "ProductCardBlock",
|
|
1082
|
-
family: "Commerce",
|
|
1083
|
-
kind: "card",
|
|
1084
|
-
width: { min: "16rem", max: "20rem" },
|
|
1085
|
-
summary: "A product card: edge-to-edge artwork, title and maker, an edition Badge, and the price beside a single buy action.",
|
|
1086
|
-
intent: "Reach for this for a product, edition or listing in a grid or a featured slot. For a row in a dense list, use an Entity with the image as `leading` instead.",
|
|
1087
|
-
notes: [
|
|
1088
|
-
"The artwork runs to the card's edges; the card clips it to its own corners (overflow-hidden).",
|
|
1089
|
-
"Prices are `text-mono-lg` \u2014 the metric mono tier with tabular figures \u2014 never a heading tier.",
|
|
1090
|
-
"The placeholder art is painted from the palette's decorative tones so it follows the theme; swap it for the product image with real alt text."
|
|
1091
|
-
],
|
|
1092
|
-
a11y: [
|
|
1093
|
-
"The placeholder art is aria-hidden. A real product image needs alt text naming the product.",
|
|
1094
|
-
"The card is not a link: it holds its own button. To make the whole card navigate, move the action to the detail page and render the Card as an <a>."
|
|
1095
|
-
]
|
|
1096
|
-
};
|
|
1097
|
-
var profile = {
|
|
1098
|
-
name: "Juno Avery",
|
|
1099
|
-
initials: "JA",
|
|
1100
|
-
handle: "@juno \xB7 Sound and light",
|
|
1101
|
-
bio: "Field recordings, slowed down. New edition every full moon.",
|
|
1102
|
-
stats: [
|
|
1103
|
-
{ value: "128", label: "posts" },
|
|
1104
|
-
{ value: "4.2k", label: "followers" }
|
|
1105
|
-
]
|
|
1106
|
-
};
|
|
1107
|
-
function ProfileCardBlock({ className, framed = true, onFollowChange, onShare }) {
|
|
1108
|
-
const [following, setFollowing] = useState(false);
|
|
1109
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs overflow-hidden", className), children: [
|
|
1110
|
-
/* @__PURE__ */ jsx(GradientArt, { "aria-hidden": true, seed: profile.handle, className: "h-20" }),
|
|
1111
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-3 pt-0", children: [
|
|
1112
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
1113
|
-
/* @__PURE__ */ jsx(Avatar, { variant: "art", size: "lg", fallback: profile.initials, alt: profile.name, className: "-mt-6 ring-4 ring-card" }),
|
|
1114
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-1.5 pt-3", children: [
|
|
1115
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Share profile", onClick: onShare, children: /* @__PURE__ */ jsx(Icon, { name: "share" }) }),
|
|
1116
|
-
/* @__PURE__ */ jsx(
|
|
1117
|
-
Button,
|
|
1118
|
-
{
|
|
1119
|
-
size: "sm",
|
|
1120
|
-
variant: following ? "secondary" : "primary",
|
|
1121
|
-
onClick: () => {
|
|
1122
|
-
setFollowing(!following);
|
|
1123
|
-
onFollowChange?.(!following);
|
|
1124
|
-
},
|
|
1125
|
-
children: following ? "Following" : "Follow"
|
|
1126
|
-
}
|
|
1127
|
-
)
|
|
1128
|
-
] })
|
|
1129
|
-
] }),
|
|
1130
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
1131
|
-
/* @__PURE__ */ jsx(CardTitle, { children: profile.name }),
|
|
1132
|
-
/* @__PURE__ */ jsx(CardDescription, { children: profile.handle })
|
|
1133
|
-
] }),
|
|
1134
|
-
/* @__PURE__ */ jsx("p", { className: "text-body-sm", children: profile.bio }),
|
|
1135
|
-
/* @__PURE__ */ jsx("div", { className: "flex gap-4 text-body-sm", children: profile.stats.map((s) => /* @__PURE__ */ jsxs("span", { children: [
|
|
1136
|
-
/* @__PURE__ */ jsx("span", { className: "text-label-lg", children: s.value }),
|
|
1137
|
-
" ",
|
|
1138
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: s.label })
|
|
1139
|
-
] }, s.label)) })
|
|
1140
|
-
] })
|
|
1141
|
-
] });
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
// src/blocks/profile-card-block.meta.ts
|
|
1145
|
-
var profileCardBlockMeta = {
|
|
1146
|
-
name: "ProfileCardBlock",
|
|
1147
|
-
family: "Social & messaging",
|
|
1148
|
-
kind: "card",
|
|
1149
|
-
width: { min: "18rem", max: "20rem" },
|
|
1150
|
-
summary: "A profile card: a cover banner, an avatar rising into it, Share and Follow, the name and handle, a one-line bio and two counts.",
|
|
1151
|
-
intent: "Reach for this for a person or creator summary \u2014 a suggested-follow card, a hover target's full view, the top of a profile sidebar. For a small inline preview on hover, use ContextCard; for a row in a list of people, use Entity.",
|
|
1152
|
-
notes: [
|
|
1153
|
-
"The avatar overlaps the banner by half its height with a ring in the card colour, so it reads as sitting on the card, not pasted over the art.",
|
|
1154
|
-
"Follow is the one primary action and flips to a secondary Following once pressed; Share is an icon-only ghost Button beside it.",
|
|
1155
|
-
"Counts pair a label-tier number with muted body text, so the numbers scan as a row."
|
|
1156
|
-
],
|
|
1157
|
-
a11y: [
|
|
1158
|
-
"The Share button carries aria-label; Follow's visible text changes with its state.",
|
|
1159
|
-
"The banner is decorative (aria-hidden); the Avatar's alt is the person's name."
|
|
1160
|
-
]
|
|
1161
|
-
};
|
|
1162
|
-
var profile2 = {
|
|
1163
|
-
name: "Ada Lovelace",
|
|
1164
|
-
initials: "AL",
|
|
1165
|
-
handle: "ada",
|
|
1166
|
-
bio: "Generative artist working in plotted ink and code. New editions of 25 to 100 every month.",
|
|
1167
|
-
timezone: "europe-london"
|
|
1168
|
-
};
|
|
1169
|
-
var timezones = [
|
|
1170
|
-
{ value: "europe-london", label: "London (GMT+1)" },
|
|
1171
|
-
{ value: "europe-paris", label: "Paris (GMT+2)" },
|
|
1172
|
-
{ value: "america-new-york", label: "New York (GMT\u22124)" },
|
|
1173
|
-
{ value: "america-los-angeles", label: "Los Angeles (GMT\u22127)" },
|
|
1174
|
-
{ value: "asia-tokyo", label: "Tokyo (GMT+9)" }
|
|
1175
|
-
];
|
|
1176
|
-
function ProfileFormBlock({ className, framed = true, onSave }) {
|
|
1177
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-2xl", className), children: [
|
|
1178
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1179
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Profile" }),
|
|
1180
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "How collectors see you." })
|
|
1181
|
-
] }),
|
|
1182
|
-
/* @__PURE__ */ jsxs(
|
|
1183
|
-
Form,
|
|
1184
|
-
{
|
|
1185
|
-
className: "gap-0",
|
|
1186
|
-
onSubmit: (event2) => {
|
|
1187
|
-
event2.preventDefault();
|
|
1188
|
-
onSave?.(new FormData(event2.currentTarget));
|
|
1189
|
-
},
|
|
1190
|
-
children: [
|
|
1191
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Stack, { gap: 3, children: [
|
|
1192
|
-
/* @__PURE__ */ jsxs(Row, { gap: 2, children: [
|
|
1193
|
-
/* @__PURE__ */ jsx(Avatar, { variant: "art", size: "lg", fallback: profile2.initials, alt: profile2.name }),
|
|
1194
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 0.5, align: "start", children: [
|
|
1195
|
-
/* @__PURE__ */ jsxs(Row, { gap: 1, children: [
|
|
1196
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", children: "Upload photo" }),
|
|
1197
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", children: "Remove" })
|
|
1198
|
-
] }),
|
|
1199
|
-
/* @__PURE__ */ jsx("p", { className: "text-caption text-muted-foreground", children: "Square PNG or JPG, at least 400 px." })
|
|
1200
|
-
] })
|
|
1201
|
-
] }),
|
|
1202
|
-
/* @__PURE__ */ jsxs(Grid, { cols: { base: 1, sm: 2 }, gap: 3, children: [
|
|
1203
|
-
/* @__PURE__ */ jsx(Field, { label: "Display name", name: "displayName", required: true, children: /* @__PURE__ */ jsx(Input, { defaultValue: profile2.name, autoComplete: "name" }) }),
|
|
1204
|
-
/* @__PURE__ */ jsx(Field, { label: "Handle", name: "handle", description: `atelier.com/@${profile2.handle}`, required: true, children: /* @__PURE__ */ jsx(Input, { defaultValue: profile2.handle, autoComplete: "username", spellCheck: false }) })
|
|
1205
|
-
] }),
|
|
1206
|
-
/* @__PURE__ */ jsx(Field, { label: "Bio", name: "bio", description: "Shown on your profile and edition pages.", children: /* @__PURE__ */ jsx(Textarea, { rows: 3, defaultValue: profile2.bio }) }),
|
|
1207
|
-
/* @__PURE__ */ jsx(Grid, { cols: { base: 1, sm: 2 }, gap: 3, children: /* @__PURE__ */ jsx(Field, { label: "Timezone", name: "timezone", description: "Release times use this zone.", children: /* @__PURE__ */ jsxs(Select, { defaultValue: profile2.timezone, items: timezones, children: [
|
|
1208
|
-
/* @__PURE__ */ jsx(SelectTrigger, {}),
|
|
1209
|
-
/* @__PURE__ */ jsx(SelectContent, { children: timezones.map((zone) => /* @__PURE__ */ jsx(SelectItem, { value: zone.value, children: zone.label }, zone.value)) })
|
|
1210
|
-
] }) }) })
|
|
1211
|
-
] }) }),
|
|
1212
|
-
/* @__PURE__ */ jsx(CardFooter, { actions: true, className: "justify-end", children: /* @__PURE__ */ jsx(Button, { type: "submit", children: "Save profile" }) })
|
|
1213
|
-
]
|
|
1214
|
-
}
|
|
1215
|
-
)
|
|
1216
|
-
] });
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
// src/blocks/profile-form-block.meta.ts
|
|
1220
|
-
var profileFormBlockMeta = {
|
|
1221
|
-
name: "ProfileFormBlock",
|
|
1222
|
-
family: "Settings & team",
|
|
1223
|
-
kind: "card",
|
|
1224
|
-
width: { min: "20rem", max: "42rem" },
|
|
1225
|
-
summary: "A profile settings card: avatar with upload/remove, name and handle side by side, a bio, a timezone Select, and one Save profile in the footer.",
|
|
1226
|
-
intent: "Reach for this for the profile or account section of settings, or any form of drafted text that is committed together. Toggles that apply instantly belong in NotificationSettingsBlock, never behind this Save.",
|
|
1227
|
-
notes: [
|
|
1228
|
-
"Copied from the SettingsPage page shell's Profile section; the shell keeps its own copy so it stays one self-contained file.",
|
|
1229
|
-
"One explicit save for the whole card. Short pairs (name + handle) sit side by side from sm up with Grid cols={{ base: 1, sm: 2 }}.",
|
|
1230
|
-
"The CardTitle renders an h2, so the section joins the page outline under its h1."
|
|
1231
|
-
],
|
|
1232
|
-
a11y: [
|
|
1233
|
-
"Field wires label, description and error to each control; the handle's URL preview is its description.",
|
|
1234
|
-
'The photo actions are type="button", so neither one submits the form.'
|
|
1235
|
-
]
|
|
1236
|
-
};
|
|
1237
|
-
var revenue = { label: "Revenue this month", total: "$12,480", change: "+8.2%" };
|
|
1238
|
-
var segments = [
|
|
1239
|
-
{ label: "Editions", value: 42, tone: "edition" },
|
|
1240
|
-
{ label: "Collectibles", value: 27, tone: "collectible" },
|
|
1241
|
-
{ label: "Standard", value: 19, tone: "standard" },
|
|
1242
|
-
{ label: "Commissions", value: 12, tone: "info" }
|
|
1243
|
-
];
|
|
1244
|
-
function RevenueBreakdownBlock({ className, framed = true }) {
|
|
1245
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
1246
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1247
|
-
/* @__PURE__ */ jsx(CardDescription, { children: revenue.label }),
|
|
1248
|
-
/* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Badge, { tone: "success", size: "sm", children: revenue.change }) })
|
|
1249
|
-
] }),
|
|
1250
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4 pt-2", children: [
|
|
1251
|
-
/* @__PURE__ */ jsx("span", { className: "text-mono-xl", children: revenue.total }),
|
|
1252
|
-
/* @__PURE__ */ jsx(SegmentedBar, { label: "Revenue by type", segments: [...segments], size: "lg" }),
|
|
1253
|
-
/* @__PURE__ */ jsx(Grid, { "aria-hidden": true, minItemWidth: "9.5em", gap: "calc(var(--spacing) * 1.5) calc(var(--spacing) * 4)", children: segments.map((s) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-body-sm", children: [
|
|
1254
|
-
/* @__PURE__ */ jsx(StatusDot, { tone: s.tone }),
|
|
1255
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1 text-muted-foreground", children: s.label }),
|
|
1256
|
-
/* @__PURE__ */ jsxs("span", { className: "text-mono-caption", children: [
|
|
1257
|
-
s.value,
|
|
1258
|
-
"%"
|
|
1259
|
-
] })
|
|
1260
|
-
] }, s.label)) })
|
|
1261
|
-
] })
|
|
1262
|
-
] });
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
// src/blocks/revenue-breakdown-block.meta.ts
|
|
1266
|
-
var revenueBreakdownBlockMeta = {
|
|
1267
|
-
name: "RevenueBreakdownBlock",
|
|
1268
|
-
family: "Dashboard",
|
|
1269
|
-
kind: "card",
|
|
1270
|
-
width: { min: "18rem", max: "20rem" },
|
|
1271
|
-
summary: "A stat card with a breakdown: the KPI in the metric mono tier, its trend Badge, a SegmentedBar of how the total divides, and a StatusDot legend.",
|
|
1272
|
-
intent: "Reach for this when a headline number is worth splitting into a few categories \u2014 revenue by product, storage by type, tickets by priority. A plain KPI with no split is a smaller stat card (see DashboardPage's stat row).",
|
|
1273
|
-
notes: [
|
|
1274
|
-
"The value is `text-mono-xl` \u2014 tabular figures, never a heading tier \u2014 and the label above it is CardDescription.",
|
|
1275
|
-
"The legend reflows from two columns to one by measuring in em, so larger type or a narrower card never truncates a label.",
|
|
1276
|
-
"Each category keeps the same tone in the bar and its legend dot; reuse those tones wherever the category appears."
|
|
1277
|
-
],
|
|
1278
|
-
a11y: [
|
|
1279
|
-
"The SegmentedBar is one image whose name reads every share; the legend repeats it visually and is aria-hidden so it is not announced twice.",
|
|
1280
|
-
"The trend Badge states the change as text (+8.2%), not by colour."
|
|
1281
|
-
]
|
|
1282
|
-
};
|
|
1283
|
-
function SignInBlock({ className, framed = true, onSignIn }) {
|
|
1284
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
1285
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1286
|
-
/* @__PURE__ */ jsx(CardTitle, { children: "Welcome back" }),
|
|
1287
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Sign in to pick up where you left off." })
|
|
1288
|
-
] }),
|
|
1289
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(
|
|
1290
|
-
"form",
|
|
1291
|
-
{
|
|
1292
|
-
className: "flex flex-col gap-4",
|
|
1293
|
-
onSubmit: (event2) => {
|
|
1294
|
-
event2.preventDefault();
|
|
1295
|
-
onSignIn?.("password");
|
|
1296
|
-
},
|
|
1297
|
-
children: [
|
|
1298
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1299
|
-
/* @__PURE__ */ jsx(Input, { name: "email", type: "email", autoComplete: "email", placeholder: "you@studio.com", "aria-label": "Email" }),
|
|
1300
|
-
/* @__PURE__ */ jsx(Input, { name: "password", type: "password", autoComplete: "current-password", placeholder: "Password", "aria-label": "Password" })
|
|
1301
|
-
] }),
|
|
1302
|
-
/* @__PURE__ */ jsx(Button, { type: "submit", className: "w-full", children: "Sign in" }),
|
|
1303
|
-
/* @__PURE__ */ jsx(Separator, { label: "or" }),
|
|
1304
|
-
/* @__PURE__ */ jsx(Button, { variant: "outline", className: "w-full", iconStart: /* @__PURE__ */ jsx(Icon, { name: "lock" }), onClick: () => onSignIn?.("passkey"), children: "Use a passkey" })
|
|
1305
|
-
]
|
|
1306
|
-
}
|
|
1307
|
-
) })
|
|
1308
|
-
] });
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
// src/blocks/sign-in-block.meta.ts
|
|
1312
|
-
var signInBlockMeta = {
|
|
1313
|
-
name: "SignInBlock",
|
|
1314
|
-
family: "Auth",
|
|
1315
|
-
kind: "card",
|
|
1316
|
-
width: { min: "18rem", max: "20rem" },
|
|
1317
|
-
summary: 'A sign-in card: email and password, a primary Sign in, and a passkey alternative under an "or" separator.',
|
|
1318
|
-
intent: "Reach for this wherever someone signs in inside a surface you already have \u2014 a Sheet, a Dialog, a gated panel. For a whole sign-in route with brand art beside the form, start from the AuthPage page shell instead.",
|
|
1319
|
-
notes: [
|
|
1320
|
-
"One primary action. The passkey is an outline Button under a labelled Separator, so it reads as an alternative, not a second submit.",
|
|
1321
|
-
"The fields are a real <form>: Enter submits, and the browser's password manager recognises the autocomplete hints.",
|
|
1322
|
-
"framed={false} keeps the padding and drops the surface, for a Sheet or Dialog that is already the frame."
|
|
1323
|
-
],
|
|
1324
|
-
a11y: [
|
|
1325
|
-
"Inputs carry aria-label because the design shows placeholders, not visible labels; add Field labels if your brief wants them visible.",
|
|
1326
|
-
'`onSignIn` receives "password" or "passkey", so focus and error handling stay with the caller\'s auth flow.'
|
|
1327
|
-
]
|
|
1328
|
-
};
|
|
1329
|
-
function SignUpBlock({ className, framed = true, onSignUp }) {
|
|
1330
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-sm", className), children: [
|
|
1331
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1332
|
-
/* @__PURE__ */ jsx(CardTitle, { children: "Create your account" }),
|
|
1333
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Free for 14 days. No card needed." })
|
|
1334
|
-
] }),
|
|
1335
|
-
/* @__PURE__ */ jsxs(
|
|
1336
|
-
Form,
|
|
1337
|
-
{
|
|
1338
|
-
className: "gap-0",
|
|
1339
|
-
onSubmit: (event2) => {
|
|
1340
|
-
event2.preventDefault();
|
|
1341
|
-
const data = new FormData(event2.currentTarget);
|
|
1342
|
-
onSignUp?.({
|
|
1343
|
-
name: String(data.get("name") ?? ""),
|
|
1344
|
-
email: String(data.get("email") ?? ""),
|
|
1345
|
-
password: String(data.get("password") ?? "")
|
|
1346
|
-
});
|
|
1347
|
-
},
|
|
1348
|
-
children: [
|
|
1349
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-3", children: [
|
|
1350
|
-
/* @__PURE__ */ jsx(Field, { label: "Name", name: "name", required: true, children: /* @__PURE__ */ jsx(Input, { autoComplete: "name" }) }),
|
|
1351
|
-
/* @__PURE__ */ jsx(Field, { label: "Work email", name: "email", required: true, children: /* @__PURE__ */ jsx(Input, { type: "email", autoComplete: "email", placeholder: "you@studio.com" }) }),
|
|
1352
|
-
/* @__PURE__ */ jsx(Field, { label: "Password", name: "password", description: "At least 12 characters.", required: true, children: /* @__PURE__ */ jsx(Input, { type: "password", autoComplete: "new-password", minLength: 12 }) })
|
|
1353
|
-
] }),
|
|
1354
|
-
/* @__PURE__ */ jsxs(CardFooter, { className: "flex-col items-stretch gap-3", children: [
|
|
1355
|
-
/* @__PURE__ */ jsx(Button, { type: "submit", className: "w-full", children: "Create account" }),
|
|
1356
|
-
/* @__PURE__ */ jsxs("p", { className: "text-center text-caption text-muted-foreground", children: [
|
|
1357
|
-
"Already have an account?",
|
|
1358
|
-
" ",
|
|
1359
|
-
/* @__PURE__ */ jsx("a", { href: "/sign-in", className: "text-foreground underline underline-offset-4 motion-interactive hover:text-muted-foreground", children: "Sign in" })
|
|
1360
|
-
] })
|
|
1361
|
-
] })
|
|
1362
|
-
]
|
|
1363
|
-
}
|
|
1364
|
-
)
|
|
1365
|
-
] });
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
// src/blocks/sign-up-block.meta.ts
|
|
1369
|
-
var signUpBlockMeta = {
|
|
1370
|
-
name: "SignUpBlock",
|
|
1371
|
-
family: "Auth",
|
|
1372
|
-
kind: "card",
|
|
1373
|
-
width: { min: "18rem", max: "24rem" },
|
|
1374
|
-
summary: "A sign-up card: name, work email and password as labelled Fields, one full-width Create account, and a link to sign in instead.",
|
|
1375
|
-
intent: "Reach for this to create an account inside a surface you already have, or as the form of a sign-up route. For the whole route with brand art beside it, start from the AuthPage page shell and drop this card in.",
|
|
1376
|
-
notes: [
|
|
1377
|
-
"Visible labels, not placeholders: someone filling a new form needs to see what each field is after typing in it.",
|
|
1378
|
-
"The password rule is stated up front in the Field description, before anyone fails it.",
|
|
1379
|
-
"`onSignUp` receives the fields only after the browser's own validation (required, type=email, minLength) passes."
|
|
1380
|
-
],
|
|
1381
|
-
a11y: [
|
|
1382
|
-
"Field wires each label, description and error to its input; never hand-roll <label> + <input> pairs.",
|
|
1383
|
-
"autoComplete hints (name, email, new-password) let password managers offer to generate and save the password."
|
|
1384
|
-
]
|
|
1385
|
-
};
|
|
1386
|
-
var brand = { name: "Sable", tagline: "React components, patterns, and tokens for products built with AI agents." };
|
|
1387
|
-
var groups = [
|
|
1388
|
-
{
|
|
1389
|
-
title: "Product",
|
|
1390
|
-
links: [
|
|
1391
|
-
{ label: "Components", href: "/components" },
|
|
1392
|
-
{ label: "Patterns", href: "/patterns" },
|
|
1393
|
-
{ label: "Themes", href: "/themes" },
|
|
1394
|
-
{ label: "Canvas", href: "/canvas" }
|
|
1395
|
-
]
|
|
1396
|
-
},
|
|
1397
|
-
{
|
|
1398
|
-
title: "Resources",
|
|
1399
|
-
links: [
|
|
1400
|
-
{ label: "Documentation", href: "/docs" },
|
|
1401
|
-
{ label: "Changelog", href: "/changelog" },
|
|
1402
|
-
{ label: "llms.txt", href: "/llms.txt" }
|
|
1403
|
-
]
|
|
1404
|
-
},
|
|
1405
|
-
{
|
|
1406
|
-
title: "Community",
|
|
1407
|
-
links: [
|
|
1408
|
-
{ label: "GitHub", href: "/github" },
|
|
1409
|
-
{ label: "npm", href: "/npm" },
|
|
1410
|
-
{ label: "Discussions", href: "/discussions" }
|
|
1411
|
-
]
|
|
1412
|
-
}
|
|
1413
|
-
];
|
|
1414
|
-
function SiteFooterBlock({ className }) {
|
|
1415
|
-
return /* @__PURE__ */ jsx("footer", { className: cn("w-full border-t border-border", className), children: /* @__PURE__ */ jsxs(Region, { max: "wide", className: "py-12", children: [
|
|
1416
|
-
/* @__PURE__ */ jsxs("div", { className: "grid gap-10 md:grid-cols-[minmax(0,2fr)_minmax(0,3fr)]", children: [
|
|
1417
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 3, className: "max-w-xs", children: [
|
|
1418
|
-
/* @__PURE__ */ jsx("a", { href: "/", className: "w-fit text-title-lg motion-interactive hover:text-muted-foreground", children: brand.name }),
|
|
1419
|
-
/* @__PURE__ */ jsx("p", { className: "text-body-sm text-muted-foreground", children: brand.tagline })
|
|
1420
|
-
] }),
|
|
1421
|
-
/* @__PURE__ */ jsx("nav", { "aria-label": "Footer", className: "grid grid-cols-2 gap-8 sm:grid-cols-3", children: groups.map((group) => /* @__PURE__ */ jsxs("div", { children: [
|
|
1422
|
-
/* @__PURE__ */ jsx("h2", { className: "text-label-md text-muted-foreground", children: group.title }),
|
|
1423
|
-
/* @__PURE__ */ jsx("ul", { className: "mt-3 flex flex-col gap-1", children: group.links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: link.href, className: "flex min-h-9 items-center text-body-sm motion-interactive hover:text-muted-foreground", children: link.label }) }, link.label)) })
|
|
1424
|
-
] }, group.title)) })
|
|
1425
|
-
] }),
|
|
1426
|
-
/* @__PURE__ */ jsx("div", { className: "mt-12 border-t border-border pt-6", children: /* @__PURE__ */ jsxs("p", { className: "text-caption text-muted-foreground", children: [
|
|
1427
|
-
"\xA9 2026 ",
|
|
1428
|
-
brand.name,
|
|
1429
|
-
". Released under the MIT license."
|
|
1430
|
-
] }) })
|
|
1431
|
-
] }) });
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
// src/blocks/site-footer-block.meta.ts
|
|
1435
|
-
var siteFooterBlockMeta = {
|
|
1436
|
-
name: "SiteFooterBlock",
|
|
1437
|
-
family: "Marketing",
|
|
1438
|
-
kind: "section",
|
|
1439
|
-
summary: "A site footer: the brand and a one-line tagline beside link groups in a labelled Footer nav, over a copyright line.",
|
|
1440
|
-
intent: "Reach for this at the foot of a marketing or docs site. App screens inside an AppShell take no footer; their navigation lives in the sidebar.",
|
|
1441
|
-
notes: [
|
|
1442
|
-
"Copied from the LandingPage page shell's footer.",
|
|
1443
|
-
"Every link is at least 36px tall (min-h-9), so the dense list is still an easy touch target.",
|
|
1444
|
-
"Groups go two up on a phone and three up from sm; add a group only if it has three links or more."
|
|
1445
|
-
],
|
|
1446
|
-
a11y: [
|
|
1447
|
-
`Renders <footer> with a <nav aria-label="Footer">, distinct from the page's main navigation.`,
|
|
1448
|
-
"Group titles are h2s, so the footer's structure is navigable by heading."
|
|
1449
|
-
]
|
|
1450
|
-
};
|
|
1451
|
-
var stats = [
|
|
1452
|
-
{ label: "Revenue", value: "$18,240", delta: "+8.2%", up: true, note: "vs. $16,857" },
|
|
1453
|
-
{ label: "Collects", value: "1,284", delta: "+3.1%", up: true, note: "182 first-time" },
|
|
1454
|
-
{ label: "Collectors", value: "312", delta: "+12.4%", up: true, note: "Best month yet" },
|
|
1455
|
-
{ label: "Sell-through", value: "64%", delta: "\u22121.8%", up: false, note: "6 open editions" }
|
|
1456
|
-
];
|
|
1457
|
-
function StatRowBlock({ className }) {
|
|
1458
|
-
return /* @__PURE__ */ jsx(Grid, { cols: { base: 2, xl: 4 }, gap: 3, className: cn("w-full", className), children: stats.map((stat) => /* @__PURE__ */ jsxs(Card, { children: [
|
|
1459
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1460
|
-
/* @__PURE__ */ jsx(CardDescription, { children: stat.label }),
|
|
1461
|
-
/* @__PURE__ */ jsx(CardTitle, { className: "text-mono-xl", children: stat.value })
|
|
1462
|
-
] }),
|
|
1463
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Row, { gap: 1, wrap: true, children: [
|
|
1464
|
-
/* @__PURE__ */ jsx(Badge, { tone: stat.up ? "success" : "warning", size: "sm", icon: /* @__PURE__ */ jsx(Icon, { name: stat.up ? "arrow-up" : "arrow-down" }), children: stat.delta }),
|
|
1465
|
-
/* @__PURE__ */ jsx("span", { className: "text-caption text-muted-foreground", children: stat.note })
|
|
1466
|
-
] }) })
|
|
1467
|
-
] }, stat.label)) });
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
// src/blocks/stat-row-block.meta.ts
|
|
1471
|
-
var statRowBlockMeta = {
|
|
1472
|
-
name: "StatRowBlock",
|
|
1473
|
-
family: "Dashboard",
|
|
1474
|
-
kind: "section",
|
|
1475
|
-
summary: "A KPI row: four stat cards, each a label, the value in the metric mono tier, and a trend Badge with its comparison note \u2014 2 \xD7 2 on a phone, one row from xl.",
|
|
1476
|
-
intent: "Reach for this at the top of a dashboard or report, above the tables and charts it summarises. One headline number worth splitting into categories is RevenueBreakdownBlock.",
|
|
1477
|
-
notes: [
|
|
1478
|
-
"Copied from the DashboardPage page shell's stat row.",
|
|
1479
|
-
"Values are `text-mono-xl` \u2014 tabular figures, never a heading tier \u2014 so the four numbers align digit for digit.",
|
|
1480
|
-
"The trend Badge sits with its note in CardContent, so the value keeps the full card width when the row folds to 2 \xD7 2.",
|
|
1481
|
-
"Keep it to four. A fifth stat is a sign one of them belongs in a table."
|
|
1482
|
-
],
|
|
1483
|
-
a11y: [
|
|
1484
|
-
"The trend is stated in text (+8.2%) with an arrow icon; the tone is reinforcement, not the signal.",
|
|
1485
|
-
"Each card's label is read before its value, in source order."
|
|
1486
|
-
]
|
|
1487
|
-
};
|
|
1488
|
-
var intro3 = {
|
|
1489
|
-
eyebrow: "How it works",
|
|
1490
|
-
title: "From request to sealed record.",
|
|
1491
|
-
lede: "Teams are usually live within a week. Cove adapts to the routes you already run instead of asking you to start over.",
|
|
1492
|
-
link: { label: "Read the rollout guide", href: "/guides/rollout" }
|
|
1493
|
-
};
|
|
1494
|
-
var steps2 = [
|
|
1495
|
-
{ title: "Connect your spaces", body: "Bring teams, vendors, and record stores into one workspace, with roles that mirror how you already work." },
|
|
1496
|
-
{ title: "Route every approval", body: "Requests follow the path you define, with reviewers, deadlines, and escalation built in from the start." },
|
|
1497
|
-
{ title: "Seal the record", body: "Approved work is archived with its full context and is ready for review the moment it closes." }
|
|
1498
|
-
];
|
|
1499
|
-
function StepsBlock({ className }) {
|
|
1500
|
-
const titleId = useId();
|
|
1501
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", "aria-labelledby": titleId, max: "wide", className: cn("w-full py-16 sm:py-24", className), children: /* @__PURE__ */ jsxs("div", { className: "grid gap-12 lg:grid-cols-[1fr_2fr] lg:gap-16", children: [
|
|
1502
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 2, className: "max-w-md", children: [
|
|
1503
|
-
/* @__PURE__ */ jsx("p", { className: "text-overline text-muted-foreground", children: intro3.eyebrow }),
|
|
1504
|
-
/* @__PURE__ */ jsx("h2", { id: titleId, className: "text-balance text-heading-1", children: intro3.title }),
|
|
1505
|
-
/* @__PURE__ */ jsx("p", { className: "text-body-md text-muted-foreground", children: intro3.lede }),
|
|
1506
|
-
/* @__PURE__ */ jsx("div", { className: "pt-3", children: /* @__PURE__ */ jsx(Button, { variant: "outline", iconEnd: /* @__PURE__ */ jsx(Icon, { name: "arrow-right" }), render: /* @__PURE__ */ jsx("a", { href: intro3.link.href }), children: intro3.link.label }) })
|
|
1507
|
-
] }),
|
|
1508
|
-
/* @__PURE__ */ jsx("ol", { className: "grid gap-10 sm:grid-cols-3 sm:gap-6", children: steps2.map((step, index) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-2 border-t border-border-strong pt-6", children: [
|
|
1509
|
-
/* @__PURE__ */ jsx("span", { className: "text-mono-sm text-muted-foreground", children: String(index + 1).padStart(2, "0") }),
|
|
1510
|
-
/* @__PURE__ */ jsx("h3", { className: "mt-3 text-title-lg sm:mt-6", children: step.title }),
|
|
1511
|
-
/* @__PURE__ */ jsx("p", { className: "text-body-sm text-muted-foreground", children: step.body })
|
|
1512
|
-
] }, step.title)) })
|
|
1513
|
-
] }) });
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
// src/blocks/steps-block.meta.ts
|
|
1517
|
-
var stepsBlockMeta = {
|
|
1518
|
-
name: "StepsBlock",
|
|
1519
|
-
family: "Marketing",
|
|
1520
|
-
kind: "section",
|
|
1521
|
-
summary: "A how-it-works section: the heading, lede and a guide link on the left; three numbered steps on the right, each under a strong rule.",
|
|
1522
|
-
intent: "Reach for this when the pitch is a sequence \u2014 onboarding, a workflow, a setup. Parallel benefits with no order are FeatureGridBlock; progress through a live process is a Stepper.",
|
|
1523
|
-
notes: [
|
|
1524
|
-
"Copied from the BrandLandingPage page shell's how-it-works section.",
|
|
1525
|
-
"The steps are an <ol>, so the order is semantic and the 01 / 02 / 03 numbers are its visual echo, set in the mono tier.",
|
|
1526
|
-
"Three steps fit the 1 : 2 split on desktop; on a phone everything stacks with the intro first."
|
|
1527
|
-
],
|
|
1528
|
-
a11y: [
|
|
1529
|
-
"Each step has an h3 under the section's h2.",
|
|
1530
|
-
"The guide link is an <a> styled as an outline Button, because it navigates."
|
|
1531
|
-
]
|
|
1532
|
-
};
|
|
1533
|
-
var tasks = [
|
|
1534
|
-
{ title: "Pick the cover type", tag: "Design", tone: "collectible", done: true },
|
|
1535
|
-
{ title: "Wire up checkout", tag: "Engineering", tone: "info", done: false },
|
|
1536
|
-
{ title: "Draft launch post", tag: "Launch", tone: "edition", done: false }
|
|
1537
|
-
];
|
|
1538
|
-
function TaskListBlock({ className, framed = true, onAddTask }) {
|
|
1539
|
-
const [done, setDone] = useState(tasks.map((t) => t.done));
|
|
1540
|
-
const id = useId();
|
|
1541
|
-
const left = done.filter((d) => !d).length;
|
|
1542
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
1543
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1544
|
-
/* @__PURE__ */ jsx(CardTitle, { children: "This week" }),
|
|
1545
|
-
/* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsxs("span", { className: "text-caption text-muted-foreground", children: [
|
|
1546
|
-
left,
|
|
1547
|
-
" left"
|
|
1548
|
-
] }) })
|
|
1549
|
-
] }),
|
|
1550
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1", children: tasks.map((task, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-3 py-1.5", children: [
|
|
1551
|
-
/* @__PURE__ */ jsx(
|
|
1552
|
-
Checkbox,
|
|
1553
|
-
{
|
|
1554
|
-
id: `${id}-${i}`,
|
|
1555
|
-
checked: done[i],
|
|
1556
|
-
onCheckedChange: (v) => setDone(done.map((d, j) => j === i ? v : d))
|
|
1557
|
-
}
|
|
1558
|
-
),
|
|
1559
|
-
/* @__PURE__ */ jsx(
|
|
1560
|
-
Label,
|
|
1561
|
-
{
|
|
1562
|
-
htmlFor: `${id}-${i}`,
|
|
1563
|
-
className: cn("min-w-0 flex-1 motion-interactive", done[i] && "text-muted-foreground line-through"),
|
|
1564
|
-
children: task.title
|
|
1565
|
-
}
|
|
1566
|
-
),
|
|
1567
|
-
/* @__PURE__ */ jsx(Badge, { tone: task.tone, size: "sm", children: task.tag })
|
|
1568
|
-
] }, task.title)) }) }),
|
|
1569
|
-
/* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", iconStart: /* @__PURE__ */ jsx(Icon, { name: "plus" }), onClick: onAddTask, children: "Add task" }) })
|
|
1570
|
-
] });
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
// src/blocks/task-list-block.meta.ts
|
|
1574
|
-
var taskListBlockMeta = {
|
|
1575
|
-
name: "TaskListBlock",
|
|
1576
|
-
family: "Dashboard",
|
|
1577
|
-
kind: "card",
|
|
1578
|
-
width: { min: "18rem", max: "20rem" },
|
|
1579
|
-
summary: "A checklist card: a titled list of Checkbox rows with a category Badge each, a live count of what is left, and a quiet Add task action.",
|
|
1580
|
-
intent: "Reach for this for a short, personal to-do list on a dashboard or in onboarding. A team's task board with assignees and status columns needs a Table or DataTable.",
|
|
1581
|
-
notes: [
|
|
1582
|
-
"Finishing a task strikes it through and mutes it rather than removing it, so the list does not jump under the pointer.",
|
|
1583
|
-
"The count in CardAction updates with every check, so progress reads without counting rows.",
|
|
1584
|
-
"Add task is a ghost Button in the footer \u2014 present, but quieter than the list."
|
|
1585
|
-
],
|
|
1586
|
-
a11y: [
|
|
1587
|
-
"Every Checkbox has a real <Label htmlFor>, so the whole title is the click target and the accessible name.",
|
|
1588
|
-
"Category Badges carry text; the tone only groups them visually."
|
|
1589
|
-
]
|
|
1590
|
-
};
|
|
1591
|
-
var members = [
|
|
1592
|
-
{ id: "u1", name: "Ada Lovelace", initials: "AL", email: "ada@studio.com", role: "Owner" },
|
|
1593
|
-
{ id: "u2", name: "Mara Okafor", initials: "MO", email: "mara@studio.com", role: "Admin" },
|
|
1594
|
-
{ id: "u3", name: "Sam Rivera", initials: "SR", email: "sam@studio.com", role: "Member" },
|
|
1595
|
-
{ id: "u4", name: "jun@studio.com", initials: "J", email: "Invited 2 days ago", role: "Pending" }
|
|
1596
|
-
];
|
|
1597
|
-
function TeamMembersBlock({ className, framed = true, onInvite, onMemberAction }) {
|
|
1598
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-2xl", className), children: [
|
|
1599
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1600
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Members" }),
|
|
1601
|
-
/* @__PURE__ */ jsxs(CardDescription, { children: [
|
|
1602
|
-
members.length,
|
|
1603
|
-
" people in this workspace."
|
|
1604
|
-
] }),
|
|
1605
|
-
/* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(Button, { size: "sm", iconStart: /* @__PURE__ */ jsx(Icon, { name: "plus" }), onClick: onInvite, children: "Invite" }) })
|
|
1606
|
-
] }),
|
|
1607
|
-
/* @__PURE__ */ jsx(CardList, { children: members.map((m) => /* @__PURE__ */ jsx(
|
|
1608
|
-
Entity,
|
|
1609
|
-
{
|
|
1610
|
-
leading: /* @__PURE__ */ jsx(Avatar, { variant: "art", size: "sm", fallback: m.initials, alt: m.name }),
|
|
1611
|
-
title: m.name,
|
|
1612
|
-
subtitle: m.email,
|
|
1613
|
-
action: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1614
|
-
/* @__PURE__ */ jsx(Badge, { appearance: m.role === "Pending" ? "outline" : "plain", tone: m.role === "Owner" ? "edition" : "neutral", size: "sm", children: m.role }),
|
|
1615
|
-
m.role === "Owner" ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "size-(--control-sm)" }) : /* @__PURE__ */ jsxs(OverflowMenu, { label: `Manage ${m.name}`, size: "icon-sm", children: [
|
|
1616
|
-
m.role === "Pending" ? /* @__PURE__ */ jsx(MenuItem, { onClick: () => onMemberAction?.(m.id, "resend"), children: "Resend invite" }) : m.role === "Admin" ? /* @__PURE__ */ jsx(MenuItem, { onClick: () => onMemberAction?.(m.id, "make-member"), children: "Make member" }) : /* @__PURE__ */ jsx(MenuItem, { onClick: () => onMemberAction?.(m.id, "make-admin"), children: "Make admin" }),
|
|
1617
|
-
/* @__PURE__ */ jsx(MenuSeparator, {}),
|
|
1618
|
-
/* @__PURE__ */ jsx(MenuItem, { variant: "destructive", onClick: () => onMemberAction?.(m.id, "remove"), children: m.role === "Pending" ? "Cancel invite" : "Remove from workspace" })
|
|
1619
|
-
] })
|
|
1620
|
-
] })
|
|
1621
|
-
},
|
|
1622
|
-
m.id
|
|
1623
|
-
)) })
|
|
1624
|
-
] });
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
// src/blocks/team-members-block.meta.ts
|
|
1628
|
-
var teamMembersBlockMeta = {
|
|
1629
|
-
name: "TeamMembersBlock",
|
|
1630
|
-
family: "Settings & team",
|
|
1631
|
-
kind: "card",
|
|
1632
|
-
width: { min: "20rem", max: "42rem" },
|
|
1633
|
-
summary: "A members card: Entity rows with avatar, name and email, a role Badge, and an OverflowMenu of role changes and removal; pending invites sit in the same list.",
|
|
1634
|
-
intent: "Reach for this to manage who is in a workspace, project or team. For inviting people when the list is empty or short, InviteTeamBlock is the lighter shape; for hundreds of members with filters, use a DataTable.",
|
|
1635
|
-
notes: [
|
|
1636
|
-
"Each row's menu offers only what applies to it: Make admin or Make member, Resend invite for pending rows, then the destructive action after a separator.",
|
|
1637
|
-
"The owner has no menu \u2014 ownership is transferred elsewhere \u2014 and a control-sized spacer keeps the role badges aligned.",
|
|
1638
|
-
"Pending invites are outline Badges in the same list, so the team's full size reads in one place."
|
|
1639
|
-
],
|
|
1640
|
-
a11y: [
|
|
1641
|
-
`Each OverflowMenu is labelled with the member's name ("Manage Mara Okafor"), so the triggers are distinguishable in a list.`,
|
|
1642
|
-
"Roles are text in a Badge; tone only distinguishes the owner."
|
|
1643
|
-
]
|
|
1644
|
-
};
|
|
1645
|
-
var story = {
|
|
1646
|
-
quote: "We used to chase approvals across four tools. Now every request has an owner, a deadline, and a record, and our auditors stopped asking for screenshots.",
|
|
1647
|
-
name: "Maya Okafor",
|
|
1648
|
-
initials: "MO",
|
|
1649
|
-
role: "Head of operations, Fielddesk"
|
|
1650
|
-
};
|
|
1651
|
-
var outcomes = [
|
|
1652
|
-
{ value: "3.2\xD7", label: "faster approvals in the first quarter" },
|
|
1653
|
-
{ value: "68%", label: "fewer follow-ups on handoffs" },
|
|
1654
|
-
{ value: "1 day", label: "to prepare a quarterly audit" }
|
|
1655
|
-
];
|
|
1656
|
-
function TestimonialBlock({ className }) {
|
|
1657
|
-
return /* @__PURE__ */ jsx(Region, { as: "section", "aria-label": "Customer story", max: "wide", className: cn("w-full py-16", className), children: /* @__PURE__ */ jsx(Card, { render: /* @__PURE__ */ jsx("figure", {}), children: /* @__PURE__ */ jsxs("div", { className: "grid lg:grid-cols-[1.5fr_1fr]", children: [
|
|
1658
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col justify-between gap-10 sm:p-10", children: [
|
|
1659
|
-
/* @__PURE__ */ jsxs(Stack, { gap: 3, children: [
|
|
1660
|
-
/* @__PURE__ */ jsx("p", { className: "text-overline text-muted-foreground", children: "Customer story" }),
|
|
1661
|
-
/* @__PURE__ */ jsxs("blockquote", { className: "text-balance text-heading-3 sm:text-heading-2", children: [
|
|
1662
|
-
"\u201C",
|
|
1663
|
-
story.quote,
|
|
1664
|
-
"\u201D"
|
|
1665
|
-
] })
|
|
1666
|
-
] }),
|
|
1667
|
-
/* @__PURE__ */ jsxs("figcaption", { className: "flex items-center gap-3", children: [
|
|
1668
|
-
/* @__PURE__ */ jsx(Avatar, { variant: "art", size: "lg", fallback: story.initials, alt: story.name }),
|
|
1669
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
1670
|
-
/* @__PURE__ */ jsx("p", { className: "text-title-sm", children: story.name }),
|
|
1671
|
-
/* @__PURE__ */ jsx("p", { className: "text-body-sm text-muted-foreground", children: story.role })
|
|
1672
|
-
] })
|
|
1673
|
-
] })
|
|
1674
|
-
] }),
|
|
1675
|
-
/* @__PURE__ */ jsx("div", { className: "border-border max-lg:border-t lg:border-s", children: /* @__PURE__ */ jsx(CardContent, { className: "flex h-full flex-col justify-center gap-6 sm:p-10", children: outcomes.map((outcome, index) => /* @__PURE__ */ jsxs(Stack, { gap: 3, children: [
|
|
1676
|
-
index > 0 && /* @__PURE__ */ jsx(Separator, {}),
|
|
1677
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
1678
|
-
/* @__PURE__ */ jsx("p", { className: "text-heading-1 sm:text-display-lg", children: outcome.value }),
|
|
1679
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-body-sm text-muted-foreground", children: outcome.label })
|
|
1680
|
-
] })
|
|
1681
|
-
] }, outcome.label)) }) })
|
|
1682
|
-
] }) }) });
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
// src/blocks/testimonial-block.meta.ts
|
|
1686
|
-
var testimonialBlockMeta = {
|
|
1687
|
-
name: "TestimonialBlock",
|
|
1688
|
-
family: "Marketing",
|
|
1689
|
-
kind: "section",
|
|
1690
|
-
summary: "A customer story: one large blockquote with the person's avatar, name and role, beside three outcome figures separated by rules.",
|
|
1691
|
-
intent: "Reach for this for one strong, attributable quote backed by numbers. A wall of short quotes is a different section; a logo row is Marquee.",
|
|
1692
|
-
notes: [
|
|
1693
|
-
"Copied from the BrandLandingPage page shell's customer story.",
|
|
1694
|
-
"The quote and the outcomes share one Card as a <figure>; the outcomes move under the quote below lg.",
|
|
1695
|
-
"Outcome values use display sizes because they are the proof; their labels say what each number counts."
|
|
1696
|
-
],
|
|
1697
|
-
a11y: [
|
|
1698
|
-
"<figure> + <blockquote> + <figcaption> tie the quote to the person who said it.",
|
|
1699
|
-
'The section is labelled "Customer story" so it is reachable as a landmark.'
|
|
1700
|
-
]
|
|
1701
|
-
};
|
|
1702
|
-
var sources = [
|
|
1703
|
-
{ source: "Search", visitors: 4280 },
|
|
1704
|
-
{ source: "Direct", visitors: 2910 },
|
|
1705
|
-
{ source: "Social", visitors: 1840 },
|
|
1706
|
-
{ source: "Email", visitors: 960 }
|
|
1707
|
-
];
|
|
1708
|
-
var total = sources.reduce((sum, s) => sum + s.visitors, 0);
|
|
1709
|
-
function TrafficSourcesBlock({ className, framed = true }) {
|
|
1710
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-sm", className), children: [
|
|
1711
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1712
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Traffic sources" }),
|
|
1713
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Where this month's visitors came from." })
|
|
1714
|
-
] }),
|
|
1715
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(
|
|
1716
|
-
PieChart,
|
|
1717
|
-
{
|
|
1718
|
-
label: "Visitors by source, this month",
|
|
1719
|
-
data: sources,
|
|
1720
|
-
index: "source",
|
|
1721
|
-
valueKey: "visitors",
|
|
1722
|
-
donut: true,
|
|
1723
|
-
centerLabel: { value: total.toLocaleString("en-US"), label: "Visitors" }
|
|
1724
|
-
}
|
|
1725
|
-
) }),
|
|
1726
|
-
/* @__PURE__ */ jsxs(CardFooter, { className: "text-body-sm text-muted-foreground", children: [
|
|
1727
|
-
"Search brings ",
|
|
1728
|
-
Math.round(sources[0].visitors / total * 100),
|
|
1729
|
-
"% of visitors."
|
|
1730
|
-
] })
|
|
1731
|
-
] });
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
// src/blocks/traffic-sources-block.meta.ts
|
|
1735
|
-
var trafficSourcesBlockMeta = {
|
|
1736
|
-
name: "TrafficSourcesBlock",
|
|
1737
|
-
family: "Dashboard",
|
|
1738
|
-
kind: "card",
|
|
1739
|
-
width: { min: "18rem", max: "24rem" },
|
|
1740
|
-
summary: "A share card: a donut PieChart of where a total comes from, the total in the hole, a legend, and the headline share in words in the footer.",
|
|
1741
|
-
intent: "Reach for this for a split of one total into four or fewer parts \u2014 traffic sources, revenue by plan, tickets by channel. More parts, or values to compare exactly, belong in a horizontal BarChart.",
|
|
1742
|
-
notes: [
|
|
1743
|
-
`The total sits in the donut's hole, so the card answers "how many" and "from where" at once.`,
|
|
1744
|
-
"The footer puts the biggest share in a sentence \u2014 the takeaway does not depend on reading the slices.",
|
|
1745
|
-
"The slices sweep in clockwise as the card scrolls into view."
|
|
1746
|
-
],
|
|
1747
|
-
a11y: [
|
|
1748
|
-
"The chart's data table lists every source and its count; the legend repeats it visually.",
|
|
1749
|
-
"Hovering or arrowing through the slices pulls each out and announces it."
|
|
1750
|
-
]
|
|
1751
|
-
};
|
|
1752
|
-
var days2 = Array.from({ length: 90 }, (_, i) => {
|
|
1753
|
-
const wave = Math.sin(i / 6) * 60 + Math.sin(i / 2.3) * 25;
|
|
1754
|
-
return {
|
|
1755
|
-
date: new Date(2026, 6, 1 + i).toISOString().slice(0, 10),
|
|
1756
|
-
desktop: Math.round(240 + wave + i % 7 * 9),
|
|
1757
|
-
mobile: Math.round(160 + wave * 0.7 + i * 3 % 11 * 6)
|
|
1758
|
-
};
|
|
1759
|
-
});
|
|
1760
|
-
var series2 = [
|
|
1761
|
-
{ key: "desktop", label: "Desktop" },
|
|
1762
|
-
{ key: "mobile", label: "Mobile" }
|
|
1763
|
-
];
|
|
1764
|
-
var ranges = [
|
|
1765
|
-
{ id: "90d", label: "3 months", days: 90 },
|
|
1766
|
-
{ id: "30d", label: "30 days", days: 30 },
|
|
1767
|
-
{ id: "7d", label: "7 days", days: 7 }
|
|
1768
|
-
];
|
|
1769
|
-
var shortDate2 = (iso) => (/* @__PURE__ */ new Date(`${iso}T00:00:00`)).toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
1770
|
-
function TrafficTrendBlock({ className, framed = true }) {
|
|
1771
|
-
const [range, setRange] = useState("90d");
|
|
1772
|
-
const shown = days2.slice(-(ranges.find((r) => r.id === range)?.days ?? 90));
|
|
1773
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-3xl", className), children: [
|
|
1774
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1775
|
-
/* @__PURE__ */ jsx(CardTitle, { render: /* @__PURE__ */ jsx("h2", {}), children: "Visitors" }),
|
|
1776
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Desktop and mobile, by day." }),
|
|
1777
|
-
/* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx(ToggleGroup, { value: [range], onValueChange: (v) => v[0] && setRange(String(v[0])), "aria-label": "Time range", children: ranges.map((r) => /* @__PURE__ */ jsx(Toggle, { value: r.id, children: r.label }, r.id)) }) })
|
|
1778
|
-
] }),
|
|
1779
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(
|
|
1780
|
-
AreaChart,
|
|
1781
|
-
{
|
|
1782
|
-
label: `Visitors per day, last ${ranges.find((r) => r.id === range)?.label}`,
|
|
1783
|
-
data: shown,
|
|
1784
|
-
index: "date",
|
|
1785
|
-
series: series2,
|
|
1786
|
-
indexFormatter: shortDate2,
|
|
1787
|
-
tooltip: { labelFormatter: (d) => (/* @__PURE__ */ new Date(`${d}T00:00:00`)).toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" }) },
|
|
1788
|
-
stacked: true,
|
|
1789
|
-
gradient: true,
|
|
1790
|
-
className: "h-64"
|
|
1791
|
-
}
|
|
1792
|
-
) }),
|
|
1793
|
-
/* @__PURE__ */ jsxs(CardFooter, { className: "gap-1.5 text-body-sm", children: [
|
|
1794
|
-
/* @__PURE__ */ jsx(Icon, { name: "arrow-up", className: "text-success" }),
|
|
1795
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
1796
|
-
"Up 5.2% on the previous period ",
|
|
1797
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\xB7 desktop leads every week" })
|
|
1798
|
-
] })
|
|
1799
|
-
] })
|
|
1800
|
-
] });
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
// src/blocks/traffic-trend-block.meta.ts
|
|
1804
|
-
var trafficTrendBlockMeta = {
|
|
1805
|
-
name: "TrafficTrendBlock",
|
|
1806
|
-
family: "Dashboard",
|
|
1807
|
-
kind: "card",
|
|
1808
|
-
width: { min: "20rem", max: "48rem" },
|
|
1809
|
-
summary: "A trend card: a stacked gradient AreaChart of two series by day, a time-range ToggleGroup in the header, and a one-line takeaway with its direction in the footer.",
|
|
1810
|
-
intent: "Reach for this as the headline chart of a dashboard or an analytics section on a landing page. For a single number with a small trend beside it, KpiSparklineBlock is lighter.",
|
|
1811
|
-
notes: [
|
|
1812
|
-
"Switching the range eases the chart from one shape to the next instead of redrawing it.",
|
|
1813
|
-
"The footer states the takeaway in words, so the card says something even before the chart is read.",
|
|
1814
|
-
"The tooltip heading spells out the weekday; the axis keeps short dates so they fit."
|
|
1815
|
-
],
|
|
1816
|
-
a11y: [
|
|
1817
|
-
"The chart's accessible name includes the range showing, and its data table updates with it.",
|
|
1818
|
-
"The range control is a labelled ToggleGroup; the chart is one tab stop with arrow-key navigation."
|
|
1819
|
-
]
|
|
1820
|
-
};
|
|
1821
|
-
var uploading = { name: "brand-guidelines.pdf", meta: "4.2 MB of 6.8 MB", progress: 62 };
|
|
1822
|
-
var uploaded = { name: "cover-final.png", meta: "Uploaded \xB7 2.1 MB" };
|
|
1823
|
-
function UploadListBlock({ className, onCancel }) {
|
|
1824
|
-
return (
|
|
1825
|
-
// An upload list, not chips: rows fill the block's width.
|
|
1826
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex w-full max-w-xs flex-col gap-2", className), children: [
|
|
1827
|
-
/* @__PURE__ */ jsx(
|
|
1828
|
-
Attachment,
|
|
1829
|
-
{
|
|
1830
|
-
className: "max-w-none",
|
|
1831
|
-
name: uploading.name,
|
|
1832
|
-
meta: uploading.meta,
|
|
1833
|
-
status: "uploading",
|
|
1834
|
-
progress: uploading.progress,
|
|
1835
|
-
actions: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Cancel upload", onClick: onCancel, children: /* @__PURE__ */ jsx(Icon, { name: "xmark" }) })
|
|
1836
|
-
}
|
|
1837
|
-
),
|
|
1838
|
-
/* @__PURE__ */ jsx(
|
|
1839
|
-
Attachment,
|
|
1840
|
-
{
|
|
1841
|
-
className: "max-w-none",
|
|
1842
|
-
name: uploaded.name,
|
|
1843
|
-
icon: "image-stack",
|
|
1844
|
-
meta: uploaded.meta,
|
|
1845
|
-
actions: /* @__PURE__ */ jsx("span", { className: "grid size-(--control-sm) place-items-center", children: /* @__PURE__ */ jsx(Icon, { name: "circle-check", className: "text-success", "aria-label": "Uploaded" }) })
|
|
1846
|
-
}
|
|
1847
|
-
)
|
|
1848
|
-
] })
|
|
1849
|
-
);
|
|
1850
|
-
}
|
|
1851
|
-
|
|
1852
|
-
// src/blocks/upload-list-block.meta.ts
|
|
1853
|
-
var uploadListBlockMeta = {
|
|
1854
|
-
name: "UploadListBlock",
|
|
1855
|
-
family: "Media & files",
|
|
1856
|
-
kind: "card",
|
|
1857
|
-
width: { min: "16rem", max: "20rem" },
|
|
1858
|
-
summary: "An upload queue: full-width Attachment rows \u2014 one uploading with progress and a cancel button, one finished with a success check.",
|
|
1859
|
-
intent: "Reach for this under a FileDropzone, or anywhere files are in flight \u2014 a composer, an import step, a document form. For files attached to a message, Attachment chips in the composer fit better.",
|
|
1860
|
-
notes: [
|
|
1861
|
-
"Rows, not chips: each Attachment drops its chip cap (`max-w-none`) to fill the block's width.",
|
|
1862
|
-
"The success check sits in a control-sized box so it lines up with the cancel button on the row above.",
|
|
1863
|
-
"No card: Attachment rows are their own surfaces. Wrap the block in a Card if it needs a header."
|
|
1864
|
-
],
|
|
1865
|
-
a11y: [
|
|
1866
|
-
"Attachment announces upload progress; the cancel Button carries aria-label.",
|
|
1867
|
-
`The finished row's check carries aria-label="Uploaded", so the state is spoken, not only coloured.`
|
|
1868
|
-
]
|
|
1869
|
-
};
|
|
1870
|
-
var sentTo = "ada@studio.com";
|
|
1871
|
-
function VerifyCodeBlock({ className, framed = true, onVerify, onResend }) {
|
|
1872
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-sm", className), children: [
|
|
1873
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1874
|
-
/* @__PURE__ */ jsx(CardTitle, { children: "Check your email" }),
|
|
1875
|
-
/* @__PURE__ */ jsxs(CardDescription, { children: [
|
|
1876
|
-
"We sent a 6-digit code to ",
|
|
1877
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground", children: sentTo }),
|
|
1878
|
-
"."
|
|
1879
|
-
] })
|
|
1880
|
-
] }),
|
|
1881
|
-
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(Field, { label: "Verification code", description: "The code expires in 10 minutes.", children: /* @__PURE__ */ jsx(OtpField, { length: 6, groupSize: 3, onValueComplete: (code) => onVerify?.(code) }) }) }),
|
|
1882
|
-
/* @__PURE__ */ jsxs(CardFooter, { className: "justify-between gap-3", children: [
|
|
1883
|
-
/* @__PURE__ */ jsx("span", { className: "text-caption text-muted-foreground", children: "Didn\u2019t get it?" }),
|
|
1884
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onResend, children: "Resend code" })
|
|
1885
|
-
] })
|
|
1886
|
-
] });
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
// src/blocks/verify-code-block.meta.ts
|
|
1890
|
-
var verifyCodeBlockMeta = {
|
|
1891
|
-
name: "VerifyCodeBlock",
|
|
1892
|
-
family: "Auth",
|
|
1893
|
-
kind: "card",
|
|
1894
|
-
width: { min: "18rem", max: "24rem" },
|
|
1895
|
-
summary: "A one-time-code card: where the code went, a six-slot OtpField grouped 3 + 3 under a visible label, and a quiet Resend.",
|
|
1896
|
-
intent: "Reach for this for email or SMS verification, two-factor sign-in, or confirming a sensitive change. For a code someone copies out (a recovery key), show it with Code and a copy button instead.",
|
|
1897
|
-
notes: [
|
|
1898
|
-
"No submit button: the code verifies the moment the last slot fills, which is what people expect from a code field.",
|
|
1899
|
-
"The destination is named in the description, so a mistyped address is caught before the wait.",
|
|
1900
|
-
"Resend is a ghost Button \u2014 present for the stuck case, never competing with the field."
|
|
1901
|
-
],
|
|
1902
|
-
a11y: [
|
|
1903
|
-
'OtpField names each slot ("Character 1 of 6") and accepts a pasted code into all six at once.',
|
|
1904
|
-
"Field labels the group and reads the expiry as its description."
|
|
1905
|
-
]
|
|
1906
|
-
};
|
|
1907
|
-
var balance = "14.62 SOL";
|
|
1908
|
-
var activity = [
|
|
1909
|
-
{ title: "Sold \u201CDusk, no. 4\u201D", detail: "Edition \xB7 2h ago", amount: "+0.80", tone: "edition" },
|
|
1910
|
-
{ title: "Royalty", detail: "Collectible \xB7 Yesterday", amount: "+0.12", tone: "collectible" },
|
|
1911
|
-
{ title: "Withdrawal", detail: "To Phantom \xB7 Mon", amount: "-1.50", tone: "standard" }
|
|
1912
|
-
];
|
|
1913
|
-
function WalletBlock({ className, framed = true, onSend, onReceive }) {
|
|
1914
|
-
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
1915
|
-
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
1916
|
-
/* @__PURE__ */ jsx(CardDescription, { children: "Balance" }),
|
|
1917
|
-
/* @__PURE__ */ jsx(CardTitle, { className: "text-mono-xl", children: balance })
|
|
1918
|
-
] }),
|
|
1919
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-3", children: [
|
|
1920
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
1921
|
-
/* @__PURE__ */ jsx(Button, { iconStart: /* @__PURE__ */ jsx(Icon, { name: "arrow-up" }), onClick: onSend, children: "Send" }),
|
|
1922
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", iconStart: /* @__PURE__ */ jsx(Icon, { name: "arrow-down" }), onClick: onReceive, children: "Receive" })
|
|
1923
|
-
] }),
|
|
1924
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-col", children: activity.map((item) => /* @__PURE__ */ jsx(
|
|
1925
|
-
Entity,
|
|
1926
|
-
{
|
|
1927
|
-
className: "px-0",
|
|
1928
|
-
leading: /* @__PURE__ */ jsx(
|
|
1929
|
-
"span",
|
|
1930
|
-
{
|
|
1931
|
-
"aria-hidden": true,
|
|
1932
|
-
className: "block size-8 rounded-full",
|
|
1933
|
-
style: { background: `oklch(from var(--tone-${item.tone}) clamp(0.5, calc(l + 0.16), 0.9) max(calc(c * 1.25), 0.1) h)` }
|
|
1934
|
-
}
|
|
1935
|
-
),
|
|
1936
|
-
title: item.title,
|
|
1937
|
-
subtitle: item.detail,
|
|
1938
|
-
action: /* @__PURE__ */ jsx("span", { className: cn("text-mono-md", item.amount.startsWith("+") ? "text-success" : "text-muted-foreground"), children: item.amount })
|
|
1939
|
-
},
|
|
1940
|
-
item.title
|
|
1941
|
-
)) })
|
|
1942
|
-
] })
|
|
1943
|
-
] });
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
// src/blocks/wallet-block.meta.ts
|
|
1947
|
-
var walletBlockMeta = {
|
|
1948
|
-
name: "WalletBlock",
|
|
1949
|
-
family: "Commerce",
|
|
1950
|
-
kind: "card",
|
|
1951
|
-
width: { min: "18rem", max: "20rem" },
|
|
1952
|
-
summary: "A balance card: the balance in the metric mono tier, Send and Receive as an equal pair, and recent activity as Entity rows with signed amounts.",
|
|
1953
|
-
intent: "Reach for this for a wallet, account balance or credits summary with its latest movements. For a full transaction history with filters, use a DataTable.",
|
|
1954
|
-
notes: [
|
|
1955
|
-
"The balance is CardTitle at `text-mono-xl` \u2014 tabular figures, never a heading tier \u2014 under its label as CardDescription.",
|
|
1956
|
-
"Send is primary and Receive secondary, side by side at equal width: two directions of one action, with sending the riskier and more frequent.",
|
|
1957
|
-
"Incoming amounts are `text-success`; outgoing stay muted rather than red, because a withdrawal is not an error."
|
|
1958
|
-
],
|
|
1959
|
-
a11y: [
|
|
1960
|
-
"Each activity row's leading swatch is aria-hidden; the title and detail carry the meaning.",
|
|
1961
|
-
"Amounts keep their sign in text (+0.80 / -1.50), so the direction does not depend on colour."
|
|
1962
|
-
]
|
|
1963
|
-
};
|
|
1964
|
-
|
|
1965
|
-
export { ApiKeysBlock, ChatThreadBlock, CommandPaletteBlock, CtaBandBlock, DangerZoneBlock, DeviceComparisonBlock, EventCardBlock, FaqBlock, FeatureGridBlock, FeedbackFormBlock, GoalProgressBlock, HeroBlock, InviteTeamBlock, InvoiceHistoryBlock, KpiSparklineBlock, MediaPlayerBlock, NewsletterBlock, NotFoundBlock, NotificationListBlock, NotificationSettingsBlock, OrderTrackingBlock, PricingCardBlock, PricingTableBlock, ProductCardBlock, ProfileCardBlock, ProfileFormBlock, RevenueBreakdownBlock, SignInBlock, SignUpBlock, SiteFooterBlock, StatRowBlock, StepsBlock, TaskListBlock, TeamMembersBlock, TestimonialBlock, TrafficSourcesBlock, TrafficTrendBlock, UploadListBlock, VerifyCodeBlock, WalletBlock, apiKeysBlockMeta, chatThreadBlockMeta, commandPaletteBlockMeta, ctaBandBlockMeta, dangerZoneBlockMeta, deviceComparisonBlockMeta, eventCardBlockMeta, faqBlockMeta, featureGridBlockMeta, feedbackFormBlockMeta, goalProgressBlockMeta, heroBlockMeta, inviteTeamBlockMeta, invoiceHistoryBlockMeta, kpiSparklineBlockMeta, mediaPlayerBlockMeta, newsletterBlockMeta, notFoundBlockMeta, notificationListBlockMeta, notificationSettingsBlockMeta, orderTrackingBlockMeta, pricingCardBlockMeta, pricingTableBlockMeta, productCardBlockMeta, profileCardBlockMeta, profileFormBlockMeta, revenueBreakdownBlockMeta, signInBlockMeta, signUpBlockMeta, siteFooterBlockMeta, statRowBlockMeta, stepsBlockMeta, taskListBlockMeta, teamMembersBlockMeta, testimonialBlockMeta, trafficSourcesBlockMeta, trafficTrendBlockMeta, uploadListBlockMeta, verifyCodeBlockMeta, walletBlockMeta };
|