@open-mercato/core 0.7.1-develop.7203.1.9396450b78 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/build.mjs +11 -0
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +23 -0
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +2 -1
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +2 -1
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +2 -1
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/lib/detailHelpers.js +4 -0
- package/dist/modules/customers/lib/detailHelpers.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +5 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/design_system/backend/design-system/page.meta.js +3 -2
- package/dist/modules/design_system/backend/design-system/page.meta.js.map +2 -2
- package/dist/modules/design_system/gallery/assets/ai-prompt-image.png +0 -0
- package/dist/modules/design_system/gallery/assets/avatar-illustration.png +0 -0
- package/dist/modules/design_system/gallery/assets/avatar-memoji.png +0 -0
- package/dist/modules/design_system/gallery/assets/avatar-photo.png +0 -0
- package/dist/modules/design_system/gallery/assets/blog-photo-0.png +0 -0
- package/dist/modules/design_system/gallery/assets/contact-support-portrait.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-ada.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-avax.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-bnb.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-brand.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-btc.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-clock.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-crown.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-dot.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-eth.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-hbar.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-history.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-link.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-menu.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-metamask.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-more.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-phantom.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-rewards.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-sad-face.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-sol.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-star.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-status-cancelled.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-status-pending.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-status-success.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-status-warning.svg +3 -0
- package/dist/modules/design_system/gallery/assets/crypto-trx.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-usdc.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-usdt.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-walletconnect.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-wei.png +0 -0
- package/dist/modules/design_system/gallery/assets/crypto-xrp.png +0 -0
- package/dist/modules/design_system/gallery/assets/cryptocurrency-artwork.js +67 -0
- package/dist/modules/design_system/gallery/assets/cryptocurrency-artwork.js.map +7 -0
- package/dist/modules/design_system/gallery/assets/github-logo.png +0 -0
- package/dist/modules/design_system/gallery/assets/images.d.js +1 -0
- package/dist/modules/design_system/gallery/assets/images.d.js.map +7 -0
- package/dist/modules/design_system/gallery/assets/input-european-union.svg +18 -0
- package/dist/modules/design_system/gallery/assets/landing-teams-01.png +0 -0
- package/dist/modules/design_system/gallery/assets/marketing-artwork.js +83 -0
- package/dist/modules/design_system/gallery/assets/marketing-artwork.js.map +7 -0
- package/dist/modules/design_system/gallery/assets/menu-apex.svg +18 -0
- package/dist/modules/design_system/gallery/assets/menu-mastercard.svg +7 -0
- package/dist/modules/design_system/gallery/assets/menu-spotify.svg +4 -0
- package/dist/modules/design_system/gallery/assets/menu-united-states.svg +16 -0
- package/dist/modules/design_system/gallery/assets/select-google.png +0 -0
- package/dist/modules/design_system/gallery/assets/select-poland.png +0 -0
- package/dist/modules/design_system/gallery/assets/selection-artwork.js +5 -0
- package/dist/modules/design_system/gallery/assets/selection-artwork.js.map +7 -0
- package/dist/modules/design_system/gallery/assets/social-apple-filled.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-apple-stroke.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-dropbox-filled.svg +5 -0
- package/dist/modules/design_system/gallery/assets/social-dropbox-stroke.svg +5 -0
- package/dist/modules/design_system/gallery/assets/social-facebook-filled.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-facebook-stroke.svg +10 -0
- package/dist/modules/design_system/gallery/assets/social-github-filled.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-github-stroke.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-google-filled.svg +7 -0
- package/dist/modules/design_system/gallery/assets/social-google-stroke.svg +7 -0
- package/dist/modules/design_system/gallery/assets/social-linkedin-filled.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-linkedin-stroke.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-x-filled.svg +4 -0
- package/dist/modules/design_system/gallery/assets/social-x-stroke.svg +4 -0
- package/dist/modules/design_system/gallery/assets/style-studio-product.png +0 -0
- package/dist/modules/design_system/gallery/assets/upload-images.js +8 -0
- package/dist/modules/design_system/gallery/assets/upload-images.js.map +7 -0
- package/dist/modules/design_system/gallery/components/BrandStylePreview.js +74 -0
- package/dist/modules/design_system/gallery/components/BrandStylePreview.js.map +7 -0
- package/dist/modules/design_system/gallery/components/CodeSnippet.js +31 -31
- package/dist/modules/design_system/gallery/components/CodeSnippet.js.map +2 -2
- package/dist/modules/design_system/gallery/components/ColorPlayground.js +408 -0
- package/dist/modules/design_system/gallery/components/ColorPlayground.js.map +7 -0
- package/dist/modules/design_system/gallery/components/ColorStudioCompositions.js +166 -0
- package/dist/modules/design_system/gallery/components/ColorStudioCompositions.js.map +7 -0
- package/dist/modules/design_system/gallery/components/ColorStudioSpecimen.js +182 -0
- package/dist/modules/design_system/gallery/components/ColorStudioSpecimen.js.map +7 -0
- package/dist/modules/design_system/gallery/components/CompactEntrySpecimen.js +80 -0
- package/dist/modules/design_system/gallery/components/CompactEntrySpecimen.js.map +7 -0
- package/dist/modules/design_system/gallery/components/ComponentIndex.js +42 -0
- package/dist/modules/design_system/gallery/components/ComponentIndex.js.map +7 -0
- package/dist/modules/design_system/gallery/components/DesignSystemHome.js +69 -0
- package/dist/modules/design_system/gallery/components/DesignSystemHome.js.map +7 -0
- package/dist/modules/design_system/gallery/components/EntryCard.js +47 -41
- package/dist/modules/design_system/gallery/components/EntryCard.js.map +2 -2
- package/dist/modules/design_system/gallery/components/EntryHeader.js +68 -0
- package/dist/modules/design_system/gallery/components/EntryHeader.js.map +7 -0
- package/dist/modules/design_system/gallery/components/FamilyEntryPreview.js +19 -0
- package/dist/modules/design_system/gallery/components/FamilyEntryPreview.js.map +7 -0
- package/dist/modules/design_system/gallery/components/FoundationGuide.js +46 -0
- package/dist/modules/design_system/gallery/components/FoundationGuide.js.map +7 -0
- package/dist/modules/design_system/gallery/components/GalleryLink.js +21 -0
- package/dist/modules/design_system/gallery/components/GalleryLink.js.map +7 -0
- package/dist/modules/design_system/gallery/components/GalleryNavigation.js +82 -0
- package/dist/modules/design_system/gallery/components/GalleryNavigation.js.map +7 -0
- package/dist/modules/design_system/gallery/components/GalleryShell.js +147 -67
- package/dist/modules/design_system/gallery/components/GalleryShell.js.map +3 -3
- package/dist/modules/design_system/gallery/components/IconsBrowser.js +33 -0
- package/dist/modules/design_system/gallery/components/IconsBrowser.js.map +7 -0
- package/dist/modules/design_system/gallery/components/SourceLibrary.js +93 -0
- package/dist/modules/design_system/gallery/components/SourceLibrary.js.map +7 -0
- package/dist/modules/design_system/gallery/components/StyleAgents.js +139 -0
- package/dist/modules/design_system/gallery/components/StyleAgents.js.map +7 -0
- package/dist/modules/design_system/gallery/components/ThemeTokenReference.js +101 -0
- package/dist/modules/design_system/gallery/components/ThemeTokenReference.js.map +7 -0
- package/dist/modules/design_system/gallery/components/VariantPreview.js +2 -2
- package/dist/modules/design_system/gallery/components/VariantPreview.js.map +2 -2
- package/dist/modules/design_system/gallery/components/colorPreview.js +58 -0
- package/dist/modules/design_system/gallery/components/colorPreview.js.map +7 -0
- package/dist/modules/design_system/gallery/components/colorStudio.js +218 -0
- package/dist/modules/design_system/gallery/components/colorStudio.js.map +7 -0
- package/dist/modules/design_system/gallery/components/styleAgentBranding.js +46 -0
- package/dist/modules/design_system/gallery/components/styleAgentBranding.js.map +7 -0
- package/dist/modules/design_system/gallery/components/themeTokens.js +32 -0
- package/dist/modules/design_system/gallery/components/themeTokens.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/ai-product-code.generated.js +194 -0
- package/dist/modules/design_system/gallery/demos/ai-product-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/ai-product.js +423 -0
- package/dist/modules/design_system/gallery/demos/ai-product.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/buttons.js +289 -0
- package/dist/modules/design_system/gallery/demos/buttons.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/cryptocurrency.js +1708 -0
- package/dist/modules/design_system/gallery/demos/cryptocurrency.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/feeds-code.generated.js +92 -0
- package/dist/modules/design_system/gallery/demos/feeds-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/feeds.js +148 -0
- package/dist/modules/design_system/gallery/demos/feeds.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/file-upload.js +72 -0
- package/dist/modules/design_system/gallery/demos/file-upload.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/foundation-reference-data.js +4875 -0
- package/dist/modules/design_system/gallery/demos/foundation-reference-data.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/foundation-references.js +188 -0
- package/dist/modules/design_system/gallery/demos/foundation-references.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/key-components-code.generated.js +6 -0
- package/dist/modules/design_system/gallery/demos/key-components-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/key-components.js +127 -0
- package/dist/modules/design_system/gallery/demos/key-components.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/marketing-controls-code.generated.js +98 -0
- package/dist/modules/design_system/gallery/demos/marketing-controls-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/marketing-controls.js +134 -0
- package/dist/modules/design_system/gallery/demos/marketing-controls.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/marketing-widgets-code.generated.js +195 -0
- package/dist/modules/design_system/gallery/demos/marketing-widgets-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/marketing-widgets.js +586 -0
- package/dist/modules/design_system/gallery/demos/marketing-widgets.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/menu-fixtures.js +40 -0
- package/dist/modules/design_system/gallery/demos/menu-fixtures.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/menu-sources.js +295 -0
- package/dist/modules/design_system/gallery/demos/menu-sources.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/menus.js +150 -0
- package/dist/modules/design_system/gallery/demos/menus.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/rating-reviews.js +53 -0
- package/dist/modules/design_system/gallery/demos/rating-reviews.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/registered-icons.js +104 -0
- package/dist/modules/design_system/gallery/demos/registered-icons.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/selection-cards.js +99 -0
- package/dist/modules/design_system/gallery/demos/selection-cards.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/shell-code.generated.js +189 -0
- package/dist/modules/design_system/gallery/demos/shell-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/shell.js +330 -0
- package/dist/modules/design_system/gallery/demos/shell.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/source-artwork.js +120 -0
- package/dist/modules/design_system/gallery/demos/source-artwork.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/source-filters-code.generated.js +125 -0
- package/dist/modules/design_system/gallery/demos/source-filters-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/source-filters.js +185 -0
- package/dist/modules/design_system/gallery/demos/source-filters.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/source-icons.js +69 -0
- package/dist/modules/design_system/gallery/demos/source-icons.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/table-cells-code.generated.js +150 -0
- package/dist/modules/design_system/gallery/demos/table-cells-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/table-cells.js +181 -0
- package/dist/modules/design_system/gallery/demos/table-cells.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/text-inputs.js +113 -0
- package/dist/modules/design_system/gallery/demos/text-inputs.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/time-picker-code.generated.js +41 -0
- package/dist/modules/design_system/gallery/demos/time-picker-code.generated.js.map +7 -0
- package/dist/modules/design_system/gallery/demos/time-picker.js +41 -0
- package/dist/modules/design_system/gallery/demos/time-picker.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/banners.js +123 -60
- package/dist/modules/design_system/gallery/entries/banners.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/buttons-snippets.js +433 -0
- package/dist/modules/design_system/gallery/entries/buttons-snippets.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/buttons.js +127 -148
- package/dist/modules/design_system/gallery/entries/buttons.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/charts.js +532 -186
- package/dist/modules/design_system/gallery/entries/charts.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/dates.js +191 -3
- package/dist/modules/design_system/gallery/entries/dates.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/detail.js +118 -77
- package/dist/modules/design_system/gallery/entries/detail.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/display.js +1449 -240
- package/dist/modules/design_system/gallery/entries/display.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/feedback.js +1058 -132
- package/dist/modules/design_system/gallery/entries/feedback.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/filters.js +231 -103
- package/dist/modules/design_system/gallery/entries/filters.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/foundations.js +368 -57
- package/dist/modules/design_system/gallery/entries/foundations.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/icons.js +29 -91
- package/dist/modules/design_system/gallery/entries/icons.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/inputs-snippets.js +154 -0
- package/dist/modules/design_system/gallery/entries/inputs-snippets.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/inputs.js +2043 -306
- package/dist/modules/design_system/gallery/entries/inputs.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/library.js +20 -0
- package/dist/modules/design_system/gallery/entries/library.js.map +7 -0
- package/dist/modules/design_system/gallery/entries/messages.js +121 -103
- package/dist/modules/design_system/gallery/entries/messages.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/navigation.js +676 -103
- package/dist/modules/design_system/gallery/entries/navigation.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/notifications.js +131 -78
- package/dist/modules/design_system/gallery/entries/notifications.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/overlays.js +611 -203
- package/dist/modules/design_system/gallery/entries/overlays.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/scaffolding.js +1175 -120
- package/dist/modules/design_system/gallery/entries/scaffolding.js.map +2 -2
- package/dist/modules/design_system/gallery/entries/schedule.js +79 -54
- package/dist/modules/design_system/gallery/entries/schedule.js.map +2 -2
- package/dist/modules/design_system/gallery/presentation.js +108 -0
- package/dist/modules/design_system/gallery/presentation.js.map +7 -0
- package/dist/modules/design_system/gallery/registry.js +8 -5
- package/dist/modules/design_system/gallery/registry.js.map +2 -2
- package/dist/modules/design_system/gallery/source-library.generated.js +5 -0
- package/dist/modules/design_system/gallery/source-library.generated.js.map +7 -0
- package/dist/modules/design_system/i18n/de.json +7167 -0
- package/dist/modules/design_system/i18n/en.json +7167 -0
- package/dist/modules/design_system/i18n/es.json +7167 -0
- package/dist/modules/design_system/i18n/ko.json +7167 -0
- package/dist/modules/design_system/i18n/pl.json +7167 -0
- package/dist/modules/push_notifications/lib/queue.js +1 -31
- package/dist/modules/push_notifications/lib/queue.js.map +2 -2
- package/jest.config.cjs +1 -0
- package/jest.mocks/image.js +1 -0
- package/package.json +8 -9
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +50 -0
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +2 -1
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +2 -1
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +2 -2
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +2 -1
- package/src/modules/customers/lib/detailHelpers.ts +4 -0
- package/src/modules/customers/lib/todoCompatibility.ts +10 -0
- package/src/modules/design_system/backend/design-system/page.meta.ts +3 -2
- package/src/modules/design_system/gallery/assets/README.md +30 -0
- package/src/modules/design_system/gallery/assets/ai-prompt-image.png +0 -0
- package/src/modules/design_system/gallery/assets/avatar-illustration.png +0 -0
- package/src/modules/design_system/gallery/assets/avatar-memoji.png +0 -0
- package/src/modules/design_system/gallery/assets/avatar-photo.png +0 -0
- package/src/modules/design_system/gallery/assets/blog-photo-0.png +0 -0
- package/src/modules/design_system/gallery/assets/contact-support-portrait.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-ada.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-avax.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-bnb.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-brand.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-btc.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-clock.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-crown.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-dot.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-eth.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-hbar.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-history.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-link.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-menu.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-metamask.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-more.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-phantom.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-rewards.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-sad-face.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-sol.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-star.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-status-cancelled.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-status-pending.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-status-success.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-status-warning.svg +3 -0
- package/src/modules/design_system/gallery/assets/crypto-trx.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-usdc.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-usdt.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-walletconnect.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-wei.png +0 -0
- package/src/modules/design_system/gallery/assets/crypto-xrp.png +0 -0
- package/src/modules/design_system/gallery/assets/cryptocurrency-artwork.ts +63 -0
- package/src/modules/design_system/gallery/assets/github-logo.png +0 -0
- package/src/modules/design_system/gallery/assets/images.d.ts +9 -0
- package/src/modules/design_system/gallery/assets/input-european-union.svg +18 -0
- package/src/modules/design_system/gallery/assets/landing-teams-01.png +0 -0
- package/src/modules/design_system/gallery/assets/marketing-artwork.ts +79 -0
- package/src/modules/design_system/gallery/assets/menu-apex.svg +18 -0
- package/src/modules/design_system/gallery/assets/menu-mastercard.svg +7 -0
- package/src/modules/design_system/gallery/assets/menu-spotify.svg +4 -0
- package/src/modules/design_system/gallery/assets/menu-united-states.svg +16 -0
- package/src/modules/design_system/gallery/assets/select-google.png +0 -0
- package/src/modules/design_system/gallery/assets/select-poland.png +0 -0
- package/src/modules/design_system/gallery/assets/selection-artwork.ts +1 -0
- package/src/modules/design_system/gallery/assets/social-apple-filled.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-apple-stroke.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-dropbox-filled.svg +5 -0
- package/src/modules/design_system/gallery/assets/social-dropbox-stroke.svg +5 -0
- package/src/modules/design_system/gallery/assets/social-facebook-filled.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-facebook-stroke.svg +10 -0
- package/src/modules/design_system/gallery/assets/social-github-filled.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-github-stroke.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-google-filled.svg +7 -0
- package/src/modules/design_system/gallery/assets/social-google-stroke.svg +7 -0
- package/src/modules/design_system/gallery/assets/social-linkedin-filled.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-linkedin-stroke.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-x-filled.svg +4 -0
- package/src/modules/design_system/gallery/assets/social-x-stroke.svg +4 -0
- package/src/modules/design_system/gallery/assets/style-studio-product.png +0 -0
- package/src/modules/design_system/gallery/assets/upload-images.ts +5 -0
- package/src/modules/design_system/gallery/components/BrandStylePreview.tsx +94 -0
- package/src/modules/design_system/gallery/components/CodeSnippet.tsx +34 -34
- package/src/modules/design_system/gallery/components/ColorPlayground.tsx +324 -0
- package/src/modules/design_system/gallery/components/ColorStudioCompositions.tsx +96 -0
- package/src/modules/design_system/gallery/components/ColorStudioSpecimen.tsx +164 -0
- package/src/modules/design_system/gallery/components/CompactEntrySpecimen.tsx +65 -0
- package/src/modules/design_system/gallery/components/ComponentIndex.tsx +47 -0
- package/src/modules/design_system/gallery/components/DesignSystemHome.tsx +66 -0
- package/src/modules/design_system/gallery/components/EntryCard.tsx +52 -37
- package/src/modules/design_system/gallery/components/EntryHeader.tsx +80 -0
- package/src/modules/design_system/gallery/components/FamilyEntryPreview.tsx +22 -0
- package/src/modules/design_system/gallery/components/FoundationGuide.tsx +43 -0
- package/src/modules/design_system/gallery/components/GalleryLink.tsx +19 -0
- package/src/modules/design_system/gallery/components/GalleryNavigation.tsx +86 -0
- package/src/modules/design_system/gallery/components/GalleryShell.tsx +149 -63
- package/src/modules/design_system/gallery/components/IconsBrowser.tsx +40 -0
- package/src/modules/design_system/gallery/components/SourceLibrary.tsx +90 -0
- package/src/modules/design_system/gallery/components/StyleAgents.tsx +115 -0
- package/src/modules/design_system/gallery/components/ThemeTokenReference.tsx +76 -0
- package/src/modules/design_system/gallery/components/VariantPreview.tsx +2 -2
- package/src/modules/design_system/gallery/components/colorPreview.ts +63 -0
- package/src/modules/design_system/gallery/components/colorStudio.ts +260 -0
- package/src/modules/design_system/gallery/components/styleAgentBranding.ts +42 -0
- package/src/modules/design_system/gallery/components/themeTokens.ts +26 -0
- package/src/modules/design_system/gallery/demos/ai-product-code.generated.ts +3 -0
- package/src/modules/design_system/gallery/demos/ai-product.tsx +188 -0
- package/src/modules/design_system/gallery/demos/buttons.tsx +331 -0
- package/src/modules/design_system/gallery/demos/cryptocurrency.tsx +1943 -0
- package/src/modules/design_system/gallery/demos/feeds-code.generated.ts +4 -0
- package/src/modules/design_system/gallery/demos/feeds.tsx +82 -0
- package/src/modules/design_system/gallery/demos/file-upload.tsx +61 -0
- package/src/modules/design_system/gallery/demos/foundation-reference-data.ts +4872 -0
- package/src/modules/design_system/gallery/demos/foundation-references.tsx +140 -0
- package/src/modules/design_system/gallery/demos/key-components-code.generated.ts +3 -0
- package/src/modules/design_system/gallery/demos/key-components.tsx +106 -0
- package/src/modules/design_system/gallery/demos/marketing-controls-code.generated.ts +3 -0
- package/src/modules/design_system/gallery/demos/marketing-controls.tsx +92 -0
- package/src/modules/design_system/gallery/demos/marketing-widgets-code.generated.ts +3 -0
- package/src/modules/design_system/gallery/demos/marketing-widgets.tsx +189 -0
- package/src/modules/design_system/gallery/demos/menu-fixtures.tsx +48 -0
- package/src/modules/design_system/gallery/demos/menu-sources.ts +5 -0
- package/src/modules/design_system/gallery/demos/menus.tsx +122 -0
- package/src/modules/design_system/gallery/demos/rating-reviews.tsx +44 -0
- package/src/modules/design_system/gallery/demos/registered-icons.tsx +117 -0
- package/src/modules/design_system/gallery/demos/selection-cards.tsx +97 -0
- package/src/modules/design_system/gallery/demos/shell-code.generated.ts +3 -0
- package/src/modules/design_system/gallery/demos/shell.tsx +183 -0
- package/src/modules/design_system/gallery/demos/source-artwork.tsx +88 -0
- package/src/modules/design_system/gallery/demos/source-filters-code.generated.ts +3 -0
- package/src/modules/design_system/gallery/demos/source-filters.tsx +119 -0
- package/src/modules/design_system/gallery/demos/source-icons.tsx +62 -0
- package/src/modules/design_system/gallery/demos/table-cells-code.generated.ts +3 -0
- package/src/modules/design_system/gallery/demos/table-cells.tsx +144 -0
- package/src/modules/design_system/gallery/demos/text-inputs.tsx +90 -0
- package/src/modules/design_system/gallery/demos/time-picker-code.generated.ts +5 -0
- package/src/modules/design_system/gallery/demos/time-picker.tsx +31 -0
- package/src/modules/design_system/gallery/entries/banners.tsx +143 -94
- package/src/modules/design_system/gallery/entries/buttons-snippets.ts +432 -0
- package/src/modules/design_system/gallery/entries/buttons.tsx +125 -196
- package/src/modules/design_system/gallery/entries/charts.tsx +545 -233
- package/src/modules/design_system/gallery/entries/dates.tsx +171 -3
- package/src/modules/design_system/gallery/entries/detail.tsx +142 -115
- package/src/modules/design_system/gallery/entries/display.tsx +1691 -319
- package/src/modules/design_system/gallery/entries/feedback.tsx +1082 -169
- package/src/modules/design_system/gallery/entries/filters.tsx +238 -143
- package/src/modules/design_system/gallery/entries/foundations.tsx +404 -61
- package/src/modules/design_system/gallery/entries/icons.tsx +31 -117
- package/src/modules/design_system/gallery/entries/inputs-snippets.ts +156 -0
- package/src/modules/design_system/gallery/entries/inputs.tsx +2146 -503
- package/src/modules/design_system/gallery/entries/library.tsx +16 -0
- package/src/modules/design_system/gallery/entries/messages.tsx +114 -106
- package/src/modules/design_system/gallery/entries/navigation.tsx +782 -192
- package/src/modules/design_system/gallery/entries/notifications.tsx +145 -120
- package/src/modules/design_system/gallery/entries/overlays.tsx +696 -280
- package/src/modules/design_system/gallery/entries/scaffolding.tsx +1192 -158
- package/src/modules/design_system/gallery/entries/schedule.tsx +72 -58
- package/src/modules/design_system/gallery/presentation.ts +106 -0
- package/src/modules/design_system/gallery/registry.ts +8 -6
- package/src/modules/design_system/gallery/source-library.generated.ts +2 -0
- package/src/modules/design_system/i18n/de.json +7112 -3
- package/src/modules/design_system/i18n/en.json +7112 -3
- package/src/modules/design_system/i18n/es.json +7112 -3
- package/src/modules/design_system/i18n/ko.json +7112 -3
- package/src/modules/design_system/i18n/pl.json +7112 -3
- package/src/modules/push_notifications/AGENTS.md +9 -5
- package/src/modules/push_notifications/lib/queue.ts +15 -44
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { contrastRatio, normalizeHex } from "./colorPreview.js";
|
|
2
|
+
const STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
|
3
|
+
const LIGHTNESS = [0.98, 0.95, 0.9, 0.83, 0.74, 0.64, 0.54, 0.44, 0.35, 0.26, 0.18];
|
|
4
|
+
function linearChannel(channel) {
|
|
5
|
+
return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
|
|
6
|
+
}
|
|
7
|
+
function toOklch(hex) {
|
|
8
|
+
const [red, green, blue] = [1, 3, 5].map((offset) => linearChannel(Number.parseInt(hex.slice(offset, offset + 2), 16) / 255));
|
|
9
|
+
const long = Math.cbrt(0.4122214708 * red + 0.5363325363 * green + 0.0514459929 * blue);
|
|
10
|
+
const medium = Math.cbrt(0.2119034982 * red + 0.6806995451 * green + 0.1073969566 * blue);
|
|
11
|
+
const short = Math.cbrt(0.0883024619 * red + 0.2817188376 * green + 0.6299787005 * blue);
|
|
12
|
+
const lightness = 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short;
|
|
13
|
+
const axisA = 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short;
|
|
14
|
+
const axisB = 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short;
|
|
15
|
+
return { lightness, chroma: Math.hypot(axisA, axisB), hue: Math.atan2(axisB, axisA) };
|
|
16
|
+
}
|
|
17
|
+
function toLinearRgb({ lightness, chroma, hue }) {
|
|
18
|
+
const axisA = chroma * Math.cos(hue);
|
|
19
|
+
const axisB = chroma * Math.sin(hue);
|
|
20
|
+
const long = (lightness + 0.3963377774 * axisA + 0.2158037573 * axisB) ** 3;
|
|
21
|
+
const medium = (lightness - 0.1055613458 * axisA - 0.0638541728 * axisB) ** 3;
|
|
22
|
+
const short = (lightness - 0.0894841775 * axisA - 1.291485548 * axisB) ** 3;
|
|
23
|
+
return [
|
|
24
|
+
4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,
|
|
25
|
+
-1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,
|
|
26
|
+
-0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
function inGamut(channels) {
|
|
30
|
+
return channels.every((channel) => channel >= -1e-7 && channel <= 1.0000001);
|
|
31
|
+
}
|
|
32
|
+
function toHex(color) {
|
|
33
|
+
let channels = toLinearRgb(color);
|
|
34
|
+
if (!inGamut(channels)) {
|
|
35
|
+
let low = 0;
|
|
36
|
+
let high = color.chroma;
|
|
37
|
+
for (let iteration = 0; iteration < 24; iteration += 1) {
|
|
38
|
+
const chroma = (low + high) / 2;
|
|
39
|
+
if (inGamut(toLinearRgb({ ...color, chroma }))) low = chroma;
|
|
40
|
+
else high = chroma;
|
|
41
|
+
}
|
|
42
|
+
channels = toLinearRgb({ ...color, chroma: low });
|
|
43
|
+
}
|
|
44
|
+
return `#${channels.map((channel) => {
|
|
45
|
+
const clamped = Math.max(0, Math.min(1, channel));
|
|
46
|
+
const encoded = clamped <= 31308e-7 ? clamped * 12.92 : 1.055 * clamped ** (1 / 2.4) - 0.055;
|
|
47
|
+
return Math.round(encoded * 255).toString(16).padStart(2, "0");
|
|
48
|
+
}).join("").toUpperCase()}`;
|
|
49
|
+
}
|
|
50
|
+
function subtleSurface(surface, accent) {
|
|
51
|
+
const base = toOklch(surface);
|
|
52
|
+
const tint = toOklch(accent);
|
|
53
|
+
const amount = 0.15;
|
|
54
|
+
const axisA = base.chroma * Math.cos(base.hue) * (1 - amount) + tint.chroma * Math.cos(tint.hue) * amount;
|
|
55
|
+
const axisB = base.chroma * Math.sin(base.hue) * (1 - amount) + tint.chroma * Math.sin(tint.hue) * amount;
|
|
56
|
+
return toHex({
|
|
57
|
+
lightness: base.lightness * (1 - amount) + tint.lightness * amount,
|
|
58
|
+
chroma: Math.hypot(axisA, axisB),
|
|
59
|
+
hue: Math.atan2(axisB, axisA)
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function accentScale(hex) {
|
|
63
|
+
const seed = toOklch(hex);
|
|
64
|
+
const anchor = LIGHTNESS.reduce((closest, value, index) => Math.abs(value - seed.lightness) < Math.abs(LIGHTNESS[closest] - seed.lightness) ? index : closest, 0);
|
|
65
|
+
const seedEnvelope = Math.max(0.25, Math.sin(Math.PI * seed.lightness) ** 0.8);
|
|
66
|
+
return STEPS.map((step, index) => {
|
|
67
|
+
if (index === anchor) return { step, hex };
|
|
68
|
+
const lightness = LIGHTNESS[index];
|
|
69
|
+
const chroma = seed.chroma < 1e-5 ? 0 : Math.min(0.32, seed.chroma * Math.sin(Math.PI * lightness) ** 0.8 / seedEnvelope);
|
|
70
|
+
return { step, hex: toHex({ lightness, chroma, hue: seed.hue }) };
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function neutralScale(tone) {
|
|
74
|
+
const hue = (tone === "warm" ? 75 : 255) * Math.PI / 180;
|
|
75
|
+
return STEPS.map((step, index) => ({
|
|
76
|
+
step,
|
|
77
|
+
hex: toHex({ lightness: LIGHTNESS[index], chroma: tone === "neutral" ? 0 : 0.014 * Math.sin(Math.PI * LIGHTNESS[index]), hue })
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
function atShade(scale, shade) {
|
|
81
|
+
return scale.find((stop) => stop.step === shade).hex;
|
|
82
|
+
}
|
|
83
|
+
function foregroundFor(background) {
|
|
84
|
+
return contrastRatio("#000000", background) >= contrastRatio("#FFFFFF", background) ? "#000000" : "#FFFFFF";
|
|
85
|
+
}
|
|
86
|
+
function nearestReadable(scale, target, background, minimum) {
|
|
87
|
+
const targetIndex = STEPS.indexOf(target);
|
|
88
|
+
return scale.filter((stop) => contrastRatio(stop.hex, background) >= minimum).sort((first, second) => Math.abs(STEPS.indexOf(first.step) - targetIndex) - Math.abs(STEPS.indexOf(second.step) - targetIndex))[0]?.hex ?? foregroundFor(background);
|
|
89
|
+
}
|
|
90
|
+
function themeFor(scale, neutrals, dark, actionStep, secondary, tertiary) {
|
|
91
|
+
const background = atShade(neutrals, dark ? 950 : 50);
|
|
92
|
+
const card = dark ? atShade(neutrals, 900) : "#FFFFFF";
|
|
93
|
+
const foreground = atShade(neutrals, dark ? 50 : 950);
|
|
94
|
+
const muted = atShade(neutrals, dark ? 800 : 100);
|
|
95
|
+
const mutedForeground = nearestReadable(neutrals, dark ? 300 : 600, muted, 4.5);
|
|
96
|
+
const primary = atShade(scale, actionStep);
|
|
97
|
+
const primaryForeground = foregroundFor(primary);
|
|
98
|
+
const actionIndex = STEPS.indexOf(actionStep);
|
|
99
|
+
const hoverIndex = Math.max(0, Math.min(STEPS.length - 1, actionIndex + (primaryForeground === "#FFFFFF" ? 1 : -1)));
|
|
100
|
+
const hoverCandidate = scale[hoverIndex].hex;
|
|
101
|
+
const hover = contrastRatio(primaryForeground, hoverCandidate) >= 4.5 ? hoverCandidate : primary;
|
|
102
|
+
const accent = dark ? subtleSurface(card, primary) : atShade(scale, 100);
|
|
103
|
+
const accentForeground = nearestReadable(scale, dark ? 200 : 800, accent, 4.5);
|
|
104
|
+
const focus = nearestReadable(scale, actionStep, background, 3);
|
|
105
|
+
const input = atShade(neutrals, dark ? 600 : 300);
|
|
106
|
+
const selection = scale.filter((stop) => contrastRatio(stop.hex, input) >= 3 && contrastRatio(stop.hex, background) >= 3).sort((first, second) => Math.abs(STEPS.indexOf(first.step) - actionIndex) - Math.abs(STEPS.indexOf(second.step) - actionIndex))[0]?.hex ?? foregroundFor(background);
|
|
107
|
+
const selectionForeground = foregroundFor(selection);
|
|
108
|
+
const categoryTokens = (name, colors) => {
|
|
109
|
+
const strong = atShade(colors, dark ? 400 : 600);
|
|
110
|
+
const soft = dark ? subtleSurface(card, strong) : atShade(colors, 100);
|
|
111
|
+
return {
|
|
112
|
+
[`--studio-${name}`]: strong,
|
|
113
|
+
[`--studio-${name}-foreground`]: foregroundFor(strong),
|
|
114
|
+
[`--studio-${name}-soft`]: soft,
|
|
115
|
+
[`--studio-${name}-soft-foreground`]: nearestReadable(colors, dark ? 200 : 800, soft, 4.5)
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
const tokens = {
|
|
119
|
+
...categoryTokens("secondary", secondary),
|
|
120
|
+
...categoryTokens("tertiary", tertiary),
|
|
121
|
+
"--background": background,
|
|
122
|
+
"--foreground": foreground,
|
|
123
|
+
"--card": card,
|
|
124
|
+
"--card-foreground": foreground,
|
|
125
|
+
"--popover": card,
|
|
126
|
+
"--popover-foreground": foreground,
|
|
127
|
+
"--muted": muted,
|
|
128
|
+
"--muted-foreground": mutedForeground,
|
|
129
|
+
"--secondary": muted,
|
|
130
|
+
"--secondary-foreground": foreground,
|
|
131
|
+
"--border": atShade(neutrals, dark ? 700 : 200),
|
|
132
|
+
"--input": input,
|
|
133
|
+
"--bg-disabled": muted,
|
|
134
|
+
"--text-disabled": atShade(neutrals, dark ? 500 : 400),
|
|
135
|
+
"--border-disabled": atShade(neutrals, dark ? 700 : 200),
|
|
136
|
+
"--primary": primary,
|
|
137
|
+
"--primary-foreground": primaryForeground,
|
|
138
|
+
"--primary-hover": hover,
|
|
139
|
+
"--accent": accent,
|
|
140
|
+
"--accent-foreground": accentForeground,
|
|
141
|
+
"--accent-indigo": selection,
|
|
142
|
+
"--accent-indigo-foreground": selectionForeground,
|
|
143
|
+
"--ring": focus,
|
|
144
|
+
"--focus-ring-inner": background,
|
|
145
|
+
"--focus-ring-outer": focus
|
|
146
|
+
};
|
|
147
|
+
const pair = (id, text, surface, minimum = 4.5) => ({
|
|
148
|
+
id,
|
|
149
|
+
foreground: text,
|
|
150
|
+
background: surface,
|
|
151
|
+
ratio: contrastRatio(text, surface),
|
|
152
|
+
minimum
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
tokens,
|
|
156
|
+
actionStep,
|
|
157
|
+
pairs: [
|
|
158
|
+
pair("action", primaryForeground, primary),
|
|
159
|
+
pair("hover", primaryForeground, hover),
|
|
160
|
+
pair("body", foreground, background),
|
|
161
|
+
pair("muted", mutedForeground, muted),
|
|
162
|
+
pair("selection", accentForeground, accent),
|
|
163
|
+
pair("focus", focus, background, 3)
|
|
164
|
+
]
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function createHarmonySeeds(seed, harmony) {
|
|
168
|
+
const color = toOklch(normalizeHex(seed) ?? "#F4700D");
|
|
169
|
+
const offset = { analogous: 30, triadic: 120, split: 150 }[harmony] * Math.PI / 180;
|
|
170
|
+
const lightness = Math.max(0.55, Math.min(0.72, color.lightness));
|
|
171
|
+
const chroma = Math.max(0.1, Math.min(0.18, color.chroma));
|
|
172
|
+
const hue = color.chroma < 1e-5 ? 0 : color.hue;
|
|
173
|
+
return {
|
|
174
|
+
secondary: toHex({ lightness, chroma, hue: hue + offset }),
|
|
175
|
+
tertiary: toHex({ lightness, chroma, hue: hue - offset })
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function createColorStudio(seed, neutral, actionShades = {}, colors = {}) {
|
|
179
|
+
const primary = normalizeHex(seed) ?? "#F4700D";
|
|
180
|
+
const derived = createHarmonySeeds(primary, colors.harmony ?? "triadic");
|
|
181
|
+
const seeds = {
|
|
182
|
+
primary,
|
|
183
|
+
secondary: normalizeHex(colors.secondary ?? "") ?? derived.secondary,
|
|
184
|
+
tertiary: normalizeHex(colors.tertiary ?? "") ?? derived.tertiary
|
|
185
|
+
};
|
|
186
|
+
const scale = accentScale(primary);
|
|
187
|
+
const secondary = accentScale(seeds.secondary);
|
|
188
|
+
const tertiary = accentScale(seeds.tertiary);
|
|
189
|
+
const neutrals = neutralScale(neutral);
|
|
190
|
+
return {
|
|
191
|
+
seeds,
|
|
192
|
+
scale,
|
|
193
|
+
secondaryScale: secondary,
|
|
194
|
+
tertiaryScale: tertiary,
|
|
195
|
+
neutralScale: neutrals,
|
|
196
|
+
light: themeFor(scale, neutrals, false, actionShades.light ?? 600, secondary, tertiary),
|
|
197
|
+
dark: themeFor(scale, neutrals, true, actionShades.dark ?? 400, secondary, tertiary)
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function exportColorStudio(studio, format) {
|
|
201
|
+
const scales = {
|
|
202
|
+
accent: Object.fromEntries(studio.scale.map((stop) => [stop.step, stop.hex])),
|
|
203
|
+
secondary: Object.fromEntries(studio.secondaryScale.map((stop) => [stop.step, stop.hex])),
|
|
204
|
+
tertiary: Object.fromEntries(studio.tertiaryScale.map((stop) => [stop.step, stop.hex])),
|
|
205
|
+
neutral: Object.fromEntries(studio.neutralScale.map((stop) => [stop.step, stop.hex]))
|
|
206
|
+
};
|
|
207
|
+
if (format === "json") return JSON.stringify({ seeds: studio.seeds, scales, themes: { light: studio.light.tokens, dark: studio.dark.tokens } }, null, 2);
|
|
208
|
+
const scaleTokens = Object.fromEntries(Object.entries(scales).flatMap(([name, stops]) => Object.entries(stops).map(([step, hex]) => [`--palette-${name}-${step}`, hex])));
|
|
209
|
+
return ["light", "dark"].map((theme) => `.ds-color-preview-${theme} {
|
|
210
|
+
${Object.entries({ ...scaleTokens, ...studio[theme].tokens }).map(([token, value]) => ` ${token}: ${value};`).join("\n")}
|
|
211
|
+
}`).join("\n\n");
|
|
212
|
+
}
|
|
213
|
+
export {
|
|
214
|
+
createColorStudio,
|
|
215
|
+
createHarmonySeeds,
|
|
216
|
+
exportColorStudio
|
|
217
|
+
};
|
|
218
|
+
//# sourceMappingURL=colorStudio.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/design_system/gallery/components/colorStudio.ts"],
|
|
4
|
+
"sourcesContent": ["import { contrastRatio, normalizeHex } from './colorPreview'\n\nexport type Shade = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950\nexport type NeutralTone = 'neutral' | 'warm' | 'cool'\nexport type Harmony = 'analogous' | 'triadic' | 'split'\nexport type ColorStop = { step: Shade; hex: string }\nexport type StudioTheme = {\n tokens: Record<string, string>\n actionStep: Shade\n pairs: Array<{\n id: 'action' | 'hover' | 'body' | 'muted' | 'selection' | 'focus'\n foreground: string\n background: string\n ratio: number\n minimum: number\n }>\n}\nexport type ColorStudio = {\n seeds: { primary: string; secondary: string; tertiary: string }\n scale: ColorStop[]\n secondaryScale: ColorStop[]\n tertiaryScale: ColorStop[]\n neutralScale: ColorStop[]\n light: StudioTheme\n dark: StudioTheme\n}\n\ntype Rgb = [number, number, number]\ntype Oklch = { lightness: number; chroma: number; hue: number }\nconst STEPS: Shade[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]\nconst LIGHTNESS = [0.98, 0.95, 0.9, 0.83, 0.74, 0.64, 0.54, 0.44, 0.35, 0.26, 0.18]\n\nfunction linearChannel(channel: number): number {\n return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4\n}\n\nfunction toOklch(hex: string): Oklch {\n const [red, green, blue] = [1, 3, 5].map((offset) => linearChannel(Number.parseInt(hex.slice(offset, offset + 2), 16) / 255))\n const long = Math.cbrt(0.4122214708 * red + 0.5363325363 * green + 0.0514459929 * blue)\n const medium = Math.cbrt(0.2119034982 * red + 0.6806995451 * green + 0.1073969566 * blue)\n const short = Math.cbrt(0.0883024619 * red + 0.2817188376 * green + 0.6299787005 * blue)\n const lightness = 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short\n const axisA = 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short\n const axisB = 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short\n return { lightness, chroma: Math.hypot(axisA, axisB), hue: Math.atan2(axisB, axisA) }\n}\n\nfunction toLinearRgb({ lightness, chroma, hue }: Oklch): Rgb {\n const axisA = chroma * Math.cos(hue)\n const axisB = chroma * Math.sin(hue)\n const long = (lightness + 0.3963377774 * axisA + 0.2158037573 * axisB) ** 3\n const medium = (lightness - 0.1055613458 * axisA - 0.0638541728 * axisB) ** 3\n const short = (lightness - 0.0894841775 * axisA - 1.291485548 * axisB) ** 3\n return [\n 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,\n -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,\n -0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short,\n ]\n}\n\nfunction inGamut(channels: Rgb): boolean {\n return channels.every((channel) => channel >= -0.0000001 && channel <= 1.0000001)\n}\n\nfunction toHex(color: Oklch): string {\n let channels = toLinearRgb(color)\n if (!inGamut(channels)) {\n let low = 0\n let high = color.chroma\n for (let iteration = 0; iteration < 24; iteration += 1) {\n const chroma = (low + high) / 2\n if (inGamut(toLinearRgb({ ...color, chroma }))) low = chroma\n else high = chroma\n }\n channels = toLinearRgb({ ...color, chroma: low })\n }\n return `#${channels.map((channel) => {\n const clamped = Math.max(0, Math.min(1, channel))\n const encoded = clamped <= 0.0031308 ? clamped * 12.92 : 1.055 * clamped ** (1 / 2.4) - 0.055\n return Math.round(encoded * 255).toString(16).padStart(2, '0')\n }).join('').toUpperCase()}`\n}\n\nfunction subtleSurface(surface: string, accent: string): string {\n const base = toOklch(surface)\n const tint = toOklch(accent)\n const amount = 0.15\n const axisA = base.chroma * Math.cos(base.hue) * (1 - amount) + tint.chroma * Math.cos(tint.hue) * amount\n const axisB = base.chroma * Math.sin(base.hue) * (1 - amount) + tint.chroma * Math.sin(tint.hue) * amount\n return toHex({\n lightness: base.lightness * (1 - amount) + tint.lightness * amount,\n chroma: Math.hypot(axisA, axisB),\n hue: Math.atan2(axisB, axisA),\n })\n}\n\nfunction accentScale(hex: string): ColorStop[] {\n const seed = toOklch(hex)\n const anchor = LIGHTNESS.reduce((closest, value, index) => (\n Math.abs(value - seed.lightness) < Math.abs(LIGHTNESS[closest] - seed.lightness) ? index : closest\n ), 0)\n const seedEnvelope = Math.max(0.25, Math.sin(Math.PI * seed.lightness) ** 0.8)\n return STEPS.map((step, index) => {\n if (index === anchor) return { step, hex }\n const lightness = LIGHTNESS[index]\n const chroma = seed.chroma < 0.00001 ? 0 : Math.min(0.32, seed.chroma * Math.sin(Math.PI * lightness) ** 0.8 / seedEnvelope)\n return { step, hex: toHex({ lightness, chroma, hue: seed.hue }) }\n })\n}\n\nfunction neutralScale(tone: NeutralTone): ColorStop[] {\n const hue = (tone === 'warm' ? 75 : 255) * Math.PI / 180\n return STEPS.map((step, index) => ({\n step,\n hex: toHex({ lightness: LIGHTNESS[index], chroma: tone === 'neutral' ? 0 : 0.014 * Math.sin(Math.PI * LIGHTNESS[index]), hue }),\n }))\n}\n\nfunction atShade(scale: ColorStop[], shade: Shade): string {\n return scale.find((stop) => stop.step === shade)!.hex\n}\n\nfunction foregroundFor(background: string): string {\n return contrastRatio('#000000', background) >= contrastRatio('#FFFFFF', background) ? '#000000' : '#FFFFFF'\n}\n\nfunction nearestReadable(scale: ColorStop[], target: Shade, background: string, minimum: number): string {\n const targetIndex = STEPS.indexOf(target)\n return scale.filter((stop) => contrastRatio(stop.hex, background) >= minimum)\n .sort((first, second) => Math.abs(STEPS.indexOf(first.step) - targetIndex) - Math.abs(STEPS.indexOf(second.step) - targetIndex))[0]?.hex ?? foregroundFor(background)\n}\n\nfunction themeFor(scale: ColorStop[], neutrals: ColorStop[], dark: boolean, actionStep: Shade, secondary: ColorStop[], tertiary: ColorStop[]): StudioTheme {\n const background = atShade(neutrals, dark ? 950 : 50)\n const card = dark ? atShade(neutrals, 900) : '#FFFFFF'\n const foreground = atShade(neutrals, dark ? 50 : 950)\n const muted = atShade(neutrals, dark ? 800 : 100)\n const mutedForeground = nearestReadable(neutrals, dark ? 300 : 600, muted, 4.5)\n const primary = atShade(scale, actionStep)\n const primaryForeground = foregroundFor(primary)\n const actionIndex = STEPS.indexOf(actionStep)\n const hoverIndex = Math.max(0, Math.min(STEPS.length - 1, actionIndex + (primaryForeground === '#FFFFFF' ? 1 : -1)))\n const hoverCandidate = scale[hoverIndex].hex\n const hover = contrastRatio(primaryForeground, hoverCandidate) >= 4.5 ? hoverCandidate : primary\n const accent = dark ? subtleSurface(card, primary) : atShade(scale, 100)\n const accentForeground = nearestReadable(scale, dark ? 200 : 800, accent, 4.5)\n const focus = nearestReadable(scale, actionStep, background, 3)\n const input = atShade(neutrals, dark ? 600 : 300)\n const selection = scale.filter((stop) => contrastRatio(stop.hex, input) >= 3 && contrastRatio(stop.hex, background) >= 3)\n .sort((first, second) => Math.abs(STEPS.indexOf(first.step) - actionIndex) - Math.abs(STEPS.indexOf(second.step) - actionIndex))[0]?.hex ?? foregroundFor(background)\n const selectionForeground = foregroundFor(selection)\n const categoryTokens = (name: string, colors: ColorStop[]) => {\n const strong = atShade(colors, dark ? 400 : 600)\n const soft = dark ? subtleSurface(card, strong) : atShade(colors, 100)\n return {\n [`--studio-${name}`]: strong,\n [`--studio-${name}-foreground`]: foregroundFor(strong),\n [`--studio-${name}-soft`]: soft,\n [`--studio-${name}-soft-foreground`]: nearestReadable(colors, dark ? 200 : 800, soft, 4.5),\n }\n }\n const tokens: Record<string, string> = {\n ...categoryTokens('secondary', secondary),\n ...categoryTokens('tertiary', tertiary),\n '--background': background,\n '--foreground': foreground,\n '--card': card,\n '--card-foreground': foreground,\n '--popover': card,\n '--popover-foreground': foreground,\n '--muted': muted,\n '--muted-foreground': mutedForeground,\n '--secondary': muted,\n '--secondary-foreground': foreground,\n '--border': atShade(neutrals, dark ? 700 : 200),\n '--input': input,\n '--bg-disabled': muted,\n '--text-disabled': atShade(neutrals, dark ? 500 : 400),\n '--border-disabled': atShade(neutrals, dark ? 700 : 200),\n '--primary': primary,\n '--primary-foreground': primaryForeground,\n '--primary-hover': hover,\n '--accent': accent,\n '--accent-foreground': accentForeground,\n '--accent-indigo': selection,\n '--accent-indigo-foreground': selectionForeground,\n '--ring': focus,\n '--focus-ring-inner': background,\n '--focus-ring-outer': focus,\n }\n const pair = (id: StudioTheme['pairs'][number]['id'], text: string, surface: string, minimum = 4.5) => ({\n id, foreground: text, background: surface, ratio: contrastRatio(text, surface), minimum,\n })\n return {\n tokens,\n actionStep,\n pairs: [\n pair('action', primaryForeground, primary),\n pair('hover', primaryForeground, hover),\n pair('body', foreground, background),\n pair('muted', mutedForeground, muted),\n pair('selection', accentForeground, accent),\n pair('focus', focus, background, 3),\n ],\n }\n}\n\nexport function createHarmonySeeds(seed: string, harmony: Harmony): { secondary: string; tertiary: string } {\n const color = toOklch(normalizeHex(seed) ?? '#F4700D')\n const offset = ({ analogous: 30, triadic: 120, split: 150 }[harmony]) * Math.PI / 180\n const lightness = Math.max(0.55, Math.min(0.72, color.lightness))\n const chroma = Math.max(0.1, Math.min(0.18, color.chroma))\n const hue = color.chroma < 0.00001 ? 0 : color.hue\n return {\n secondary: toHex({ lightness, chroma, hue: hue + offset }),\n tertiary: toHex({ lightness, chroma, hue: hue - offset }),\n }\n}\n\nexport function createColorStudio(\n seed: string,\n neutral: NeutralTone,\n actionShades: { light?: Shade; dark?: Shade } = {},\n colors: { secondary?: string; tertiary?: string; harmony?: Harmony } = {},\n): ColorStudio {\n const primary = normalizeHex(seed) ?? '#F4700D'\n const derived = createHarmonySeeds(primary, colors.harmony ?? 'triadic')\n const seeds = {\n primary,\n secondary: normalizeHex(colors.secondary ?? '') ?? derived.secondary,\n tertiary: normalizeHex(colors.tertiary ?? '') ?? derived.tertiary,\n }\n const scale = accentScale(primary)\n const secondary = accentScale(seeds.secondary)\n const tertiary = accentScale(seeds.tertiary)\n const neutrals = neutralScale(neutral)\n return {\n seeds,\n scale,\n secondaryScale: secondary,\n tertiaryScale: tertiary,\n neutralScale: neutrals,\n light: themeFor(scale, neutrals, false, actionShades.light ?? 600, secondary, tertiary),\n dark: themeFor(scale, neutrals, true, actionShades.dark ?? 400, secondary, tertiary),\n }\n}\n\nexport function exportColorStudio(studio: ColorStudio, format: 'css' | 'json'): string {\n const scales = {\n accent: Object.fromEntries(studio.scale.map((stop) => [stop.step, stop.hex])),\n secondary: Object.fromEntries(studio.secondaryScale.map((stop) => [stop.step, stop.hex])),\n tertiary: Object.fromEntries(studio.tertiaryScale.map((stop) => [stop.step, stop.hex])),\n neutral: Object.fromEntries(studio.neutralScale.map((stop) => [stop.step, stop.hex])),\n }\n if (format === 'json') return JSON.stringify({ seeds: studio.seeds, scales, themes: { light: studio.light.tokens, dark: studio.dark.tokens } }, null, 2)\n const scaleTokens = Object.fromEntries(Object.entries(scales).flatMap(([name, stops]) => Object.entries(stops).map(([step, hex]) => [`--palette-${name}-${step}`, hex])))\n return (['light', 'dark'] as const).map((theme) => (\n `.ds-color-preview-${theme} {\\n${Object.entries({ ...scaleTokens, ...studio[theme].tokens }).map(([token, value]) => ` ${token}: ${value};`).join('\\n')}\\n}`\n )).join('\\n\\n')\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function studioBrandStyle(studio, logo) {
|
|
2
|
+
const theme = (mode) => {
|
|
3
|
+
const tokens = studio[mode].tokens;
|
|
4
|
+
return {
|
|
5
|
+
"--primary": tokens["--primary"],
|
|
6
|
+
"--primary-hover": tokens["--primary-hover"],
|
|
7
|
+
"--primary-foreground": tokens["--primary-foreground"],
|
|
8
|
+
"--brand-lime": studio.secondaryScale.find((stop) => stop.step === 200).hex,
|
|
9
|
+
"--brand-yellow": studio.scale.find((stop) => stop.step === 200).hex,
|
|
10
|
+
"--brand-violet": studio.tertiaryScale.find((stop) => stop.step === 200).hex,
|
|
11
|
+
"--brand-violet-foreground": "#000000"
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
return { version: 1, logo, seeds: studio.seeds, actionShades: { light: studio.light.actionStep, dark: studio.dark.actionStep }, light: theme("light"), dark: theme("dark") };
|
|
15
|
+
}
|
|
16
|
+
function readBrandLogo(file) {
|
|
17
|
+
if (!["image/png", "image/jpeg", "image/webp"].includes(file.type)) return Promise.reject(new Error("fileType"));
|
|
18
|
+
if (file.size > 1024 * 1024) return Promise.reject(new Error("fileSize"));
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const reader = new FileReader();
|
|
21
|
+
reader.onerror = () => reject(new Error("fileDecode"));
|
|
22
|
+
reader.onload = () => {
|
|
23
|
+
if (typeof reader.result !== "string") {
|
|
24
|
+
reject(new Error("fileDecode"));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const data = reader.result;
|
|
28
|
+
const image = new Image();
|
|
29
|
+
image.onerror = () => reject(new Error("fileDecode"));
|
|
30
|
+
image.onload = () => {
|
|
31
|
+
if (!image.naturalWidth || !image.naturalHeight || image.naturalWidth > 4096 || image.naturalHeight > 4096) {
|
|
32
|
+
reject(new Error("fileDimensions"));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
resolve(data);
|
|
36
|
+
};
|
|
37
|
+
image.src = data;
|
|
38
|
+
};
|
|
39
|
+
reader.readAsDataURL(file);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
readBrandLogo,
|
|
44
|
+
studioBrandStyle
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=styleAgentBranding.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/design_system/gallery/components/styleAgentBranding.ts"],
|
|
4
|
+
"sourcesContent": ["import type { BrandStyle } from '@open-mercato/ui/theme/brand-style'\nimport type { ColorStudio } from './colorStudio'\n\nexport function studioBrandStyle(studio: ColorStudio, logo: string | null): BrandStyle {\n const theme = (mode: 'light' | 'dark') => {\n const tokens = studio[mode].tokens\n return {\n '--primary': tokens['--primary'],\n '--primary-hover': tokens['--primary-hover'],\n '--primary-foreground': tokens['--primary-foreground'],\n '--brand-lime': studio.secondaryScale.find(stop => stop.step === 200)!.hex,\n '--brand-yellow': studio.scale.find(stop => stop.step === 200)!.hex,\n '--brand-violet': studio.tertiaryScale.find(stop => stop.step === 200)!.hex,\n '--brand-violet-foreground': '#000000',\n }\n }\n return { version: 1, logo, seeds: studio.seeds, actionShades: { light: studio.light.actionStep, dark: studio.dark.actionStep }, light: theme('light'), dark: theme('dark') }\n}\n\nexport function readBrandLogo(file: File): Promise<string> {\n if (!['image/png', 'image/jpeg', 'image/webp'].includes(file.type)) return Promise.reject(new Error('fileType'))\n if (file.size > 1024 * 1024) return Promise.reject(new Error('fileSize'))\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onerror = () => reject(new Error('fileDecode'))\n reader.onload = () => {\n if (typeof reader.result !== 'string') { reject(new Error('fileDecode')); return }\n const data = reader.result\n const image = new Image()\n image.onerror = () => reject(new Error('fileDecode'))\n image.onload = () => {\n if (!image.naturalWidth || !image.naturalHeight || image.naturalWidth > 4096 || image.naturalHeight > 4096) {\n reject(new Error('fileDimensions'))\n return\n }\n resolve(data)\n }\n image.src = data\n }\n reader.readAsDataURL(file)\n })\n}\n"],
|
|
5
|
+
"mappings": "AAGO,SAAS,iBAAiB,QAAqB,MAAiC;AACrF,QAAM,QAAQ,CAAC,SAA2B;AACxC,UAAM,SAAS,OAAO,IAAI,EAAE;AAC5B,WAAO;AAAA,MACL,aAAa,OAAO,WAAW;AAAA,MAC/B,mBAAmB,OAAO,iBAAiB;AAAA,MAC3C,wBAAwB,OAAO,sBAAsB;AAAA,MACrD,gBAAgB,OAAO,eAAe,KAAK,UAAQ,KAAK,SAAS,GAAG,EAAG;AAAA,MACvE,kBAAkB,OAAO,MAAM,KAAK,UAAQ,KAAK,SAAS,GAAG,EAAG;AAAA,MAChE,kBAAkB,OAAO,cAAc,KAAK,UAAQ,KAAK,SAAS,GAAG,EAAG;AAAA,MACxE,6BAA6B;AAAA,IAC/B;AAAA,EACF;AACA,SAAO,EAAE,SAAS,GAAG,MAAM,OAAO,OAAO,OAAO,cAAc,EAAE,OAAO,OAAO,MAAM,YAAY,MAAM,OAAO,KAAK,WAAW,GAAG,OAAO,MAAM,OAAO,GAAG,MAAM,MAAM,MAAM,EAAE;AAC7K;AAEO,SAAS,cAAc,MAA6B;AACzD,MAAI,CAAC,CAAC,aAAa,cAAc,YAAY,EAAE,SAAS,KAAK,IAAI,EAAG,QAAO,QAAQ,OAAO,IAAI,MAAM,UAAU,CAAC;AAC/G,MAAI,KAAK,OAAO,OAAO,KAAM,QAAO,QAAQ,OAAO,IAAI,MAAM,UAAU,CAAC;AACxE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,UAAU,MAAM,OAAO,IAAI,MAAM,YAAY,CAAC;AACrD,WAAO,SAAS,MAAM;AACpB,UAAI,OAAO,OAAO,WAAW,UAAU;AAAE,eAAO,IAAI,MAAM,YAAY,CAAC;AAAG;AAAA,MAAO;AACjF,YAAM,OAAO,OAAO;AACpB,YAAM,QAAQ,IAAI,MAAM;AACxB,YAAM,UAAU,MAAM,OAAO,IAAI,MAAM,YAAY,CAAC;AACpD,YAAM,SAAS,MAAM;AACnB,YAAI,CAAC,MAAM,gBAAgB,CAAC,MAAM,iBAAiB,MAAM,eAAe,QAAQ,MAAM,gBAAgB,MAAM;AAC1G,iBAAO,IAAI,MAAM,gBAAgB,CAAC;AAClC;AAAA,QACF;AACA,gBAAQ,IAAI;AAAA,MACd;AACA,YAAM,MAAM;AAAA,IACd;AACA,WAAO,cAAc,IAAI;AAAA,EAC3B,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function readThemeTokens(sheets) {
|
|
2
|
+
const light = {};
|
|
3
|
+
const dark = {};
|
|
4
|
+
function readRules(rules) {
|
|
5
|
+
for (const rule of Array.from(rules)) {
|
|
6
|
+
if ("selectorText" in rule && "style" in rule) {
|
|
7
|
+
const styleRule = rule;
|
|
8
|
+
const selectors = styleRule.selectorText.split(",").map((selector) => selector.trim());
|
|
9
|
+
const target = selectors.includes(".dark") ? dark : selectors.includes(":root") ? light : null;
|
|
10
|
+
if (target) {
|
|
11
|
+
for (const property of Array.from(styleRule.style)) {
|
|
12
|
+
if (property.startsWith("--")) target[property] = styleRule.style.getPropertyValue(property).trim();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if ("cssRules" in rule) readRules(rule.cssRules);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
for (const sheet of sheets) {
|
|
20
|
+
if (sheet.ownerNode instanceof Element && sheet.ownerNode.id === "om-brand-style") continue;
|
|
21
|
+
try {
|
|
22
|
+
readRules(sheet.cssRules);
|
|
23
|
+
} catch {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { light, dark: { ...light, ...dark } };
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
readThemeTokens
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=themeTokens.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/design_system/gallery/components/themeTokens.ts"],
|
|
4
|
+
"sourcesContent": ["export type ThemeTokens = { light: Record<string, string>; dark: Record<string, string> }\n\nexport function readThemeTokens(sheets: Iterable<CSSStyleSheet>): ThemeTokens {\n const light: Record<string, string> = {}\n const dark: Record<string, string> = {}\n function readRules(rules: CSSRuleList) {\n for (const rule of Array.from(rules)) {\n if ('selectorText' in rule && 'style' in rule) {\n const styleRule = rule as CSSStyleRule\n const selectors = styleRule.selectorText.split(',').map(selector => selector.trim())\n const target = selectors.includes('.dark') ? dark : selectors.includes(':root') ? light : null\n if (target) {\n for (const property of Array.from(styleRule.style)) {\n if (property.startsWith('--')) target[property] = styleRule.style.getPropertyValue(property).trim()\n }\n }\n }\n if ('cssRules' in rule) readRules((rule as CSSGroupingRule).cssRules)\n }\n }\n for (const sheet of sheets) {\n if (sheet.ownerNode instanceof Element && sheet.ownerNode.id === 'om-brand-style') continue\n try { readRules(sheet.cssRules) } catch { continue }\n }\n return { light, dark: { ...light, ...dark } }\n}\n"],
|
|
5
|
+
"mappings": "AAEO,SAAS,gBAAgB,QAA8C;AAC5E,QAAM,QAAgC,CAAC;AACvC,QAAM,OAA+B,CAAC;AACtC,WAAS,UAAU,OAAoB;AACrC,eAAW,QAAQ,MAAM,KAAK,KAAK,GAAG;AACpC,UAAI,kBAAkB,QAAQ,WAAW,MAAM;AAC7C,cAAM,YAAY;AAClB,cAAM,YAAY,UAAU,aAAa,MAAM,GAAG,EAAE,IAAI,cAAY,SAAS,KAAK,CAAC;AACnF,cAAM,SAAS,UAAU,SAAS,OAAO,IAAI,OAAO,UAAU,SAAS,OAAO,IAAI,QAAQ;AAC1F,YAAI,QAAQ;AACV,qBAAW,YAAY,MAAM,KAAK,UAAU,KAAK,GAAG;AAClD,gBAAI,SAAS,WAAW,IAAI,EAAG,QAAO,QAAQ,IAAI,UAAU,MAAM,iBAAiB,QAAQ,EAAE,KAAK;AAAA,UACpG;AAAA,QACF;AAAA,MACF;AACA,UAAI,cAAc,KAAM,WAAW,KAAyB,QAAQ;AAAA,IACtE;AAAA,EACF;AACA,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,qBAAqB,WAAW,MAAM,UAAU,OAAO,iBAAkB;AACnF,QAAI;AAAE,gBAAU,MAAM,QAAQ;AAAA,IAAE,QAAQ;AAAE;AAAA,IAAS;AAAA,EACrD;AACA,SAAO,EAAE,OAAO,MAAM,EAAE,GAAG,OAAO,GAAG,KAAK,EAAE;AAC9C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const source = `import * as React from 'react'
|
|
2
|
+
import { ArrowLeft, BookOpen, ChevronDown, ChevronRight, Folder, Mail, Menu, MoreHorizontal, MoreVertical, PanelLeft, Plus, Search, User, X, Zap } from 'lucide-react'
|
|
3
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
4
|
+
import { cn } from '@open-mercato/shared/lib/utils'
|
|
5
|
+
import { Button } from '@open-mercato/ui/primitives/button'
|
|
6
|
+
import { Input } from '@open-mercato/ui/primitives/input'
|
|
7
|
+
import { SearchInput } from '@open-mercato/ui/primitives/search-input'
|
|
8
|
+
import { FieldLabel } from '@open-mercato/ui/primitives/label'
|
|
9
|
+
import { HintText } from '@open-mercato/ui/primitives/hint-text'
|
|
10
|
+
import { KeyIconGlyph } from '@open-mercato/ui/primitives/key-icon'
|
|
11
|
+
import { DigitInput } from '@open-mercato/ui/primitives/digit-input'
|
|
12
|
+
import { CounterInput } from '@open-mercato/ui/primitives/counter-input'
|
|
13
|
+
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@open-mercato/ui/primitives/select'
|
|
14
|
+
import { Popover, PopoverTrigger, PopoverContent } from '@open-mercato/ui/primitives/popover'
|
|
15
|
+
import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
|
|
16
|
+
import { SocialButton } from '@open-mercato/ui/primitives/social-button'
|
|
17
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
18
|
+
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
19
|
+
import { Sidebar } from '@open-mercato/ui/primitives/sidebar'
|
|
20
|
+
import { PromptArea } from '@open-mercato/ui/primitives/prompt-area'
|
|
21
|
+
import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
|
|
22
|
+
import { aiProductArtwork } from '@open-mercato/ui/assets/ai-product-artwork'
|
|
23
|
+
import promptImage from '../assets/ai-prompt-image.png'
|
|
24
|
+
import avatarPhoto from '../assets/avatar-photo.png'
|
|
25
|
+
import googleIcon from '../assets/select-google.png'
|
|
26
|
+
|
|
27
|
+
type ButtonProps = React.ComponentProps<typeof Button>
|
|
28
|
+
|
|
29
|
+
const prefix = 'design_system.gallery.examples.aiProduct.'
|
|
30
|
+
const source = (asset: string | { readonly src: string }) => typeof asset === 'string' ? asset : asset.src
|
|
31
|
+
|
|
32
|
+
function AiIconButton({ size = 32, tone = 'default', appearance = 'plain', className, children, ...props }: Omit<ButtonProps, 'size'> & { size?: 20 | 24 | 28 | 32; tone?: 'default' | 'error'; appearance?: 'plain' | 'stroke' | 'lighter' }) {
|
|
33
|
+
const content = React.isValidElement<{ className?: string }>(children) && children.type !== 'img'
|
|
34
|
+
? React.cloneElement(children, { className: cn(children.props.className, size === 24 ? 'size-4.5' : 'size-5') })
|
|
35
|
+
: children
|
|
36
|
+
return <Button type="button" variant="ghost" size="icon" data-slot="ai-icon-button" data-size={size} data-tone={tone} data-appearance={appearance} className={cn(
|
|
37
|
+
'shrink-0 p-0',
|
|
38
|
+
size === 32 ? 'size-8 rounded-md' : size === 28 ? 'size-7 rounded-md' : size === 24 ? 'size-6 rounded-sm' : 'size-5 rounded-sm',
|
|
39
|
+
appearance !== 'plain' && 'rounded-ai-control',
|
|
40
|
+
appearance === 'stroke' ? 'bg-background shadow-xs ring-1 ring-inset ring-border' : appearance === 'lighter' ? 'bg-muted' : 'bg-background',
|
|
41
|
+
tone === 'error' ? 'text-status-error-text hover:bg-status-error-bg hover:text-status-error-text aria-pressed:bg-status-error-bg aria-pressed:text-status-error-text' : 'text-muted-foreground hover:bg-muted hover:text-foreground aria-pressed:bg-muted aria-pressed:text-foreground',
|
|
42
|
+
appearance !== 'plain' && 'aria-pressed:bg-primary aria-pressed:text-primary-foreground',
|
|
43
|
+
className,
|
|
44
|
+
)} {...props}>{content}</Button>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function AiModelSelect({ value, onChange, compact = false, className }: { value: string; onChange: (value: string) => void; compact?: boolean; className?: string }) {
|
|
48
|
+
const t = useT()
|
|
49
|
+
return <Select value={value} onValueChange={onChange}><SelectTrigger aria-label={t(\`\${prefix}model\`)} data-slot="ai-model-select" className={cn('h-7 w-auto min-w-19.75 gap-1 rounded-ai-control border-0 bg-muted py-1 pl-2 pr-1 text-sm leading-5 shadow-none hover:bg-accent [&>svg]:size-5', compact && 'h-5 bg-transparent p-0', className)}><SelectValue /></SelectTrigger><SelectContent>{['GPT-4', 'GPT-3.5'].map(model => <SelectItem key={model} value={model}>{model}</SelectItem>)}</SelectContent></Select>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type PromptAttachment = { id: string; name: string; image?: string; objectUrl?: boolean }
|
|
53
|
+
|
|
54
|
+
export function AiPromptExample({ compact = false, attachment = 'none' }: { compact?: boolean; attachment?: 'none' | 'file' | 'image' }) {
|
|
55
|
+
const t = useT()
|
|
56
|
+
const [value, setValue] = React.useState('')
|
|
57
|
+
const [model, setModel] = React.useState('GPT-4')
|
|
58
|
+
const [lastPrompt, setLastPrompt] = React.useState('')
|
|
59
|
+
const [files, setFiles] = React.useState<PromptAttachment[]>(attachment === 'none' ? [] : [{ id: 'source', name: t(\`\${prefix}\${attachment === 'image' ? 'imageName' : 'fileName'}\`), image: attachment === 'image' ? source(promptImage) : undefined }])
|
|
60
|
+
const upload = React.useRef<HTMLInputElement>(null)
|
|
61
|
+
const attachmentId = React.useRef(0)
|
|
62
|
+
const objectUrls = React.useRef(new Set<string>())
|
|
63
|
+
React.useEffect(() => () => { for (const url of objectUrls.current) URL.revokeObjectURL(url) }, [])
|
|
64
|
+
const remove = (id: string) => setFiles(current => current.filter(file => {
|
|
65
|
+
if (file.id !== id) return true
|
|
66
|
+
if (file.objectUrl && file.image) { URL.revokeObjectURL(file.image); objectUrls.current.delete(file.image) }
|
|
67
|
+
return false
|
|
68
|
+
}))
|
|
69
|
+
const submit = (message: string) => { setLastPrompt(\`\${model}: \${message}\`); setValue('') }
|
|
70
|
+
return <div className={cn('grid max-w-full gap-4', compact ? 'w-93.5' : 'w-175')}>
|
|
71
|
+
<PromptArea compact={compact} value={value} onValueChange={setValue} onSubmit={submit} inputLabel={t(\`\${prefix}prompt\`)} submitLabel={t(\`\${prefix}saveDraft\`)} placeholder={t(\`\${prefix}placeholder\`)} information={<><Zap aria-hidden="true" className="size-4 shrink-0" /><span>{t(\`\${prefix}premium\`)}</span><span aria-hidden="true">\xB7</span><Popover><PopoverTrigger asChild><Button type="button" variant="ghost" className="h-4 rounded-sm p-0 text-xs font-medium leading-4">{t(\`\${prefix}upgrade\`)}</Button></PopoverTrigger><PopoverContent className="text-sm">{t(\`\${prefix}localOnly\`)}</PopoverContent></Popover></>}
|
|
72
|
+
toolbar={<><AiIconButton size={28} appearance="lighter" aria-label={t(\`\${prefix}addFile\`)} onClick={() => upload.current?.click()}><Plus aria-hidden="true" /></AiIconButton><AiModelSelect value={model} onChange={setModel} /></>}
|
|
73
|
+
attachments={files.length ? files.map(file => file.image ? <div key={file.id} className="relative size-24 shrink-0"><img src={file.image} alt={file.name} className="size-24 rounded-xl object-cover" /><AiIconButton size={20} aria-label={\`\${t(\`\${prefix}remove\`)} \${file.name}\`} className="absolute right-1.5 top-1.5 rounded-full bg-primary text-primary-foreground hover:bg-primary-hover hover:text-primary-foreground" onClick={() => remove(file.id)}><X aria-hidden="true" /></AiIconButton></div> : <div key={file.id} className="flex h-15 max-w-full items-center gap-3 rounded-xl bg-muted py-2.5 pl-3 pr-4"><FileFormatIcon format={file.name.includes('.') ? file.name.split('.').pop()?.toUpperCase().slice(0, 5) ?? 'FILE' : 'FILE'} /><div className="grid min-w-0 gap-1"><span className="truncate text-sm font-medium">{file.name}</span><span className="text-xs text-muted-foreground">{t(\`\${prefix}localFile\`)}</span></div><AiIconButton size={20} aria-label={\`\${t(\`\${prefix}remove\`)} \${file.name}\`} onClick={() => remove(file.id)}><X aria-hidden="true" /></AiIconButton></div>) : undefined} />
|
|
74
|
+
<input ref={upload} type="file" className="sr-only" tabIndex={-1} aria-label={t(\`\${prefix}attachmentInput\`)} multiple onChange={event => { const selected = Array.from(event.target.files ?? []); setFiles(current => [...current, ...selected.map(file => { const image = file.type.startsWith('image/') ? URL.createObjectURL(file) : undefined; if (image) objectUrls.current.add(image); return { id: \`attachment-\${attachmentId.current++}\`, name: file.name, image, objectUrl: Boolean(image) } })]); event.target.value = '' }} />
|
|
75
|
+
<p className="text-xs leading-4 text-muted-foreground">{t(\`\${prefix}localOnly\`)}</p>
|
|
76
|
+
{lastPrompt ? <output className="rounded-md border border-border p-3 text-sm">{t(\`\${prefix}saved\`)} {lastPrompt}</output> : null}
|
|
77
|
+
</div>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function AiIconButtonExamples({ chat = false }: { chat?: boolean }) {
|
|
81
|
+
const t = useT()
|
|
82
|
+
const [active, setActive] = React.useState<string[]>([])
|
|
83
|
+
const toggle = (key: string) => setActive(items => items.includes(key) ? items.filter(item => item !== key) : [...items, key])
|
|
84
|
+
return <div className="grid gap-5">{chat ? <div className="flex gap-5">{(['stroke', 'lighter'] as const).map(appearance => <AiIconButton key={appearance} size={28} appearance={appearance} aria-label={\`\${t(\`\${prefix}toggleControl\`)} \${appearance}\`} aria-pressed={active.includes(appearance)} onClick={() => toggle(appearance)}><Plus aria-hidden="true" /></AiIconButton>)}</div> : (['default', 'error'] as const).map(tone => <div key={tone} className="flex items-center gap-5">{([32, 28, 24, 20] as const).map(size => <AiIconButton key={size} size={size} tone={tone} aria-label={\`\${t(\`\${prefix}\${tone}\`)} \${size}\`} aria-pressed={active.includes(\`\${tone}-\${size}\`)} onClick={() => toggle(\`\${tone}-\${size}\`)}><ChevronDown aria-hidden="true" /></AiIconButton>)}</div>)}</div>
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function AiNavItem({ children, icon = true, leading, mobile = false, active = false, className, ...props }: ButtonProps & { icon?: boolean; leading?: React.ReactNode; mobile?: boolean; active?: boolean }) {
|
|
88
|
+
return <Button type="button" variant="ghost" size="sm" data-slot="ai-nav-item" data-mobile={mobile} data-leading={icon} aria-current={active ? 'page' : undefined} className={cn('group h-8 w-61 max-w-full justify-start gap-2 rounded-md bg-background py-1.5 pl-1.5 pr-2 text-sm font-medium leading-5 text-muted-foreground hover:bg-muted hover:text-foreground', active && 'bg-muted text-foreground', !icon && 'hover:pl-2.5', !icon && active && 'pl-2.5', className)} {...props}>
|
|
89
|
+
{icon ? leading ?? <Folder aria-hidden="true" className="size-5" /> : null}<span className="min-w-0 flex-1 truncate text-left">{children}</span>{icon ? <ChevronRight aria-hidden="true" className={cn('size-4.5 shrink-0', !mobile && !active && 'hidden group-hover:block group-focus-visible:block')} /> : <MoreVertical aria-hidden="true" className={cn('size-4.5 shrink-0', !mobile && (active ? 'hidden' : 'hidden group-hover:block group-focus-visible:block'))} />}
|
|
90
|
+
</Button>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function AiNavigationExamples() {
|
|
94
|
+
const t = useT()
|
|
95
|
+
const [active, setActive] = React.useState<string[]>([])
|
|
96
|
+
return <div className="grid gap-4">{[false, true].flatMap(mobile => [true, false].map(icon => { const key = \`\${mobile}-\${icon}\`; return <AiNavItem key={key} icon={icon} mobile={mobile} active={active.includes(key)} onClick={() => setActive(values => values.includes(key) ? values.filter(value => value !== key) : [...values, key])}>{t(\`\${prefix}projects\`)}</AiNavItem> }))}</div>
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function AiSearchExamples() {
|
|
100
|
+
const t = useT()
|
|
101
|
+
const [query, setQuery] = React.useState('')
|
|
102
|
+
return <div className="grid w-64 max-w-full gap-4">{(['default', 'sm'] as const).map(size => <SearchInput key={size} size={size} value={query} onChange={setQuery} clearable={false} aria-label={\`\${t(\`\${prefix}search\`)} \${size}\`} placeholder={t(\`\${prefix}searchPlaceholder\`)} className={cn('rounded-lg border-0 px-2 shadow-none focus-within:bg-background [&>svg]:size-5', size === 'sm' ? 'bg-background hover:bg-muted' : 'bg-muted')} />)}<output className="text-xs text-muted-foreground">{t(\`\${prefix}query\`)} {query}</output></div>
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function AiAuthExamples({ kind = 'icons' }: { kind?: 'icons' | 'social' | 'text' | 'digits' }) {
|
|
106
|
+
const t = useT()
|
|
107
|
+
const [value, setValue] = React.useState('')
|
|
108
|
+
const [clicked, setClicked] = React.useState(false)
|
|
109
|
+
const id = React.useId()
|
|
110
|
+
if (kind === 'icons') return <div className="grid w-full max-w-lg grid-cols-2 gap-6 sm:grid-cols-4">{(['signIn', 'signUp', 'reset', 'verification', 'signInGray', 'signUpGray', 'resetGray', 'verificationGray'] as const).map(key => <div key={key} className="grid justify-items-center gap-2"><span className="flex size-14 items-center justify-center rounded-full border border-status-neutral-bg bg-background"><img src={aiProductArtwork[key]} alt="" className="size-8" /></span><span className="text-xs text-muted-foreground">{t(\`\${prefix}\${key.replace('Gray', '')}\`)}{key.endsWith('Gray') ? \` \xB7 \${t(\`\${prefix}gray\`)}\` : ''}</span></div>)}</div>
|
|
111
|
+
if (kind === 'social') return <div className="grid gap-3"><SocialButton type="button" brand="google" appearance="stroke" className="h-auto min-h-10 w-fit max-w-full whitespace-normal py-2 text-left" onClick={() => setClicked(true)}><img src={source(googleIcon)} alt="" className="size-5 shrink-0" /><span className="min-w-0">{t(\`\${prefix}google\`)}</span></SocialButton>{clicked ? <output className="max-w-sm text-xs text-muted-foreground">{t(\`\${prefix}localOnly\`)}</output> : null}</div>
|
|
112
|
+
if (kind === 'digits') return <div className="grid gap-4">{[false, true].map(disabled => <DigitInput key={String(disabled)} length={4} value={disabled ? '1234' : value} onChange={setValue} disabled={disabled} aria-label={\`\${t(\`\${prefix}verification\`)} \${disabled ? t(\`\${prefix}disabled\`) : t(\`\${prefix}editable\`)}\`} cellClassName="size-12 sm:w-12 rounded-ai-input px-2 py-2.5 text-lg leading-6" />)}<output className="text-xs text-muted-foreground">{value}</output></div>
|
|
113
|
+
return <div className="grid w-83 max-w-full gap-5">{[false, true].map(disabled => <div key={String(disabled)} data-slot="ai-text-input" className="grid gap-1"><FieldLabel htmlFor={\`\${id}-\${disabled}\`} disabled={disabled} required>{t(\`\${prefix}email\`)}</FieldLabel><Input id={\`\${id}-\${disabled}\`} type="email" value={disabled ? 'james@example.com' : value} onChange={event => setValue(event.target.value)} disabled={disabled} aria-required aria-describedby={\`\${id}-\${disabled}-hint\`} placeholder="hello@alignui.com" leading={<Mail aria-hidden="true" className="size-5 text-muted-foreground" />} size="lg" className="rounded-ai-input" /><HintText id={\`\${id}-\${disabled}-hint\`} state={disabled ? 'disabled' : 'default'} leading={<KeyIconGlyph name="information" />} className="pt-1">{t(\`\${prefix}hint\`)}</HintText></div>)}</div>
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function AiSettingsExamples() {
|
|
117
|
+
const t = useT()
|
|
118
|
+
const [tab, setTab] = React.useState('people')
|
|
119
|
+
const [size, setSize] = React.useState('medium')
|
|
120
|
+
const [count, setCount] = React.useState<number | null>(30)
|
|
121
|
+
const [model, setModel] = React.useState('GPT-4')
|
|
122
|
+
return <div className="grid gap-6"><div className="grid gap-2">{(['people', 'profile'] as const).map(value => <Button key={value} type="button" variant="ghost" data-slot="ai-settings-item" aria-pressed={tab === value} className="h-auto min-h-10 w-56 max-w-full justify-start gap-2 rounded-lg bg-background px-3 py-2 text-sm text-muted-foreground hover:bg-muted aria-pressed:bg-muted aria-pressed:text-foreground" onClick={() => setTab(value)}>{value === 'profile' ? <span aria-hidden="true"><Avatar size={20} label="James Brown" src={source(avatarPhoto)} /></span> : <User aria-hidden="true" className="size-5" />}<span className="min-w-0 flex-1 whitespace-normal text-left">{value === 'profile' ? 'James Brown' : t(\`\${prefix}people\`)}</span>{tab === value ? <ChevronRight aria-hidden="true" className="size-4.5" /> : null}</Button>)}</div><output className="text-sm text-muted-foreground">{t(\`\${prefix}\${tab}\`)}</output>
|
|
123
|
+
<div className="flex flex-wrap items-center gap-5"><Select value={size} onValueChange={setSize}><SelectTrigger data-slot="ai-size-select" aria-label={t(\`\${prefix}responseLength\`)} className="w-auto min-w-28 gap-2 rounded-lg [&>svg]:size-5"><SelectValue /></SelectTrigger><SelectContent>{['small', 'medium', 'large'].map(value => <SelectItem key={value} value={value}>{t(\`\${prefix}\${value}\`)}</SelectItem>)}</SelectContent></Select><CounterInput data-slot="ai-counter" value={count} min={0} max={99} onChange={setCount} size="default" aria-label={t(\`\${prefix}historyLimit\`)} decrementAriaLabel={t(\`\${prefix}decrease\`)} incrementAriaLabel={t(\`\${prefix}increase\`)} className="w-28 rounded-lg" inputClassName="text-sm" /><AiModelSelect value={model} onChange={setModel} className="h-9 px-3 py-2" /></div>
|
|
124
|
+
</div>
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function AiNewChatButton({ onClick }: { onClick: () => void }) {
|
|
128
|
+
const t = useT()
|
|
129
|
+
return <Button type="button" variant="ghost" data-slot="ai-new-chat" className="h-auto min-h-8 w-61 max-w-full justify-start gap-2 rounded-md p-1.5 text-sm text-status-success-text hover:bg-status-success-bg hover:text-status-success-text" onClick={onClick}><span aria-hidden="true" className="flex size-5 items-center justify-center rounded-full bg-status-success-solid text-status-success-solid-foreground"><Plus className="size-3.5" /></span><span className="min-w-0 whitespace-normal text-left">{t(\`\${prefix}newChat\`)}</span></Button>
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function AiNewChatExample() {
|
|
133
|
+
const t = useT()
|
|
134
|
+
const [draft, setDraft] = React.useState(0)
|
|
135
|
+
return <div className="grid gap-3"><AiNewChatButton onClick={() => setDraft(value => value + 1)} /><output className="text-xs text-muted-foreground">{t(\`\${prefix}draftNumber\`, { number: draft })}</output></div>
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function AiDivider() {
|
|
139
|
+
return <div role="separator" className="flex h-1 shrink-0 items-center px-1.5"><span className="h-px w-full bg-border" /></div>
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function AiSidebarExample({ search = '01', initialCollapsed = false }: { search?: '01' | '02' | '03'; initialCollapsed?: boolean }) {
|
|
143
|
+
const t = useT()
|
|
144
|
+
const [collapsed, setCollapsed] = React.useState(initialCollapsed)
|
|
145
|
+
const [query, setQuery] = React.useState('')
|
|
146
|
+
const [active, setActive] = React.useState('projects')
|
|
147
|
+
const [draft, setDraft] = React.useState(0)
|
|
148
|
+
const newChat = () => { setDraft(value => value + 1); setActive('newChat') }
|
|
149
|
+
const searchControl = <SearchInput value={query} onChange={setQuery} clearable={false} aria-label={t(\`\${prefix}search\`)} placeholder={t(\`\${prefix}searchPlaceholder\`)} className="h-9 w-61 max-w-full rounded-lg border-0 bg-muted px-2 shadow-none [&>svg]:size-5" />
|
|
150
|
+
const searchPopover = <Popover><PopoverTrigger asChild><AiIconButton aria-label={t(\`\${prefix}search\`)}><Search aria-hidden="true" /></AiIconButton></PopoverTrigger><PopoverContent className="w-auto p-3">{searchControl}<p className="mt-2 text-xs text-muted-foreground">{t(\`\${prefix}query\`)} {query}</p></PopoverContent></Popover>
|
|
151
|
+
const groups = [
|
|
152
|
+
{ label: 'pinned', items: ['launchPlan', 'researchNotes', 'contentIdeas'], icon: true },
|
|
153
|
+
{ label: 'recent', items: ['quarterlyReport', 'emailDraft', 'meetingNotes'], icon: false },
|
|
154
|
+
{ label: 'yesterday', items: ['campaignIdeas', 'productBrief', 'supportReply', 'weeklyPlan', 'projectSummary'], icon: false },
|
|
155
|
+
]
|
|
156
|
+
return <div className="flex max-w-full flex-wrap items-start gap-5">
|
|
157
|
+
<Sidebar collapsed={collapsed} aria-label={t(\`\${prefix}sidebar\`)} className={cn('max-w-full rounded-lg border border-border', collapsed ? 'w-18 gap-5 border-0 p-5' : 'w-68 gap-4 border-0 px-3.5 pb-3.5 pt-5')}>
|
|
158
|
+
<div className="flex shrink-0 flex-col gap-5"><div className="flex h-8 items-center justify-between">
|
|
159
|
+
{collapsed ? <AiIconButton aria-label={t(\`\${prefix}expand\`)} onClick={() => setCollapsed(false)}><img src={aiProductArtwork.logo} alt="" className="size-8" /></AiIconButton> : <><img src={aiProductArtwork.logo} alt={t(\`\${prefix}brand\`)} className="size-8" /><div className="flex gap-1">{search === '02' ? searchPopover : null}<AiIconButton aria-label={t(\`\${prefix}collapse\`)} onClick={() => setCollapsed(true)}><PanelLeft aria-hidden="true" /></AiIconButton></div></>}
|
|
160
|
+
</div>{!collapsed && search === '01' ? searchControl : null}</div>
|
|
161
|
+
{collapsed ? <><AiDivider /><div className="flex flex-1 flex-col gap-3"><AiIconButton aria-label={t(\`\${prefix}newChat\`)} onClick={newChat}><Plus aria-hidden="true" /></AiIconButton><AiIconButton aria-label={t(\`\${prefix}projects\`)} aria-pressed={active === 'projects'} onClick={() => setActive('projects')}><Folder aria-hidden="true" /></AiIconButton><AiIconButton aria-label={t(\`\${prefix}library\`)} aria-pressed={active === 'library'} onClick={() => setActive('library')}><BookOpen aria-hidden="true" /></AiIconButton>{searchPopover}</div><AiDivider /></> : <>
|
|
162
|
+
<div className="grid shrink-0 gap-1"><AiNewChatButton onClick={newChat} /><AiNavItem active={active === 'projects'} onClick={() => setActive('projects')}>{t(\`\${prefix}projects\`)}</AiNavItem><AiNavItem leading={<BookOpen aria-hidden="true" className="size-5" />} active={active === 'library'} onClick={() => setActive('library')}>{t(\`\${prefix}library\`)}</AiNavItem>{search === '03' ? <Popover><PopoverTrigger asChild><Button type="button" variant="ghost" className="h-8 justify-start gap-2 rounded-md p-1.5 text-sm text-muted-foreground"><Search aria-hidden="true" className="size-5" />{t(\`\${prefix}search\`)}</Button></PopoverTrigger><PopoverContent className="w-auto p-3">{searchControl}</PopoverContent></Popover> : null}</div>
|
|
163
|
+
<AiDivider /><div className="flex min-h-0 flex-1 flex-col gap-4 overflow-auto">
|
|
164
|
+
{groups.map((group, groupIndex) => <React.Fragment key={group.label}>{groupIndex === 1 ? <AiDivider /> : null}<div className="grid shrink-0 gap-2"><h3 className="px-1.5 text-xs font-medium leading-4 text-muted-foreground">{t(\`\${prefix}\${group.label}\`)}</h3><div className="grid gap-1">{group.items.filter(item => t(\`\${prefix}\${item}\`).toLocaleLowerCase().includes(query.toLocaleLowerCase())).map(item => <AiNavItem key={item} icon={group.icon} active={active === item} onClick={() => setActive(item)}>{t(\`\${prefix}\${item}\`)}</AiNavItem>)}</div></div></React.Fragment>)}
|
|
165
|
+
</div><AiDivider />
|
|
166
|
+
</>}
|
|
167
|
+
<Popover><PopoverTrigger asChild><Button type="button" variant="ghost" aria-label={t(\`\${prefix}profile\`)} data-slot="ai-sidebar-profile" className={cn('shrink-0 justify-start rounded-md text-left', collapsed ? 'size-8 p-0' : 'h-13 gap-3 p-1.5')}><Avatar label="James Brown" size={collapsed ? 32 : 40} />{!collapsed ? <><span className="flex min-w-0 flex-1 flex-col gap-1"><span className="flex items-center gap-1 text-sm font-medium leading-5">James Brown <Badge size={16} appearance="light">Pro</Badge></span><span className="truncate text-xs font-normal leading-4 text-muted-foreground">james@example.com</span></span><MoreVertical aria-hidden="true" className="size-4.5" /></> : null}</Button></PopoverTrigger><PopoverContent className="w-64 text-sm"><p className="font-medium">James Brown</p><p className="mt-2 text-muted-foreground">{t(\`\${prefix}localOnly\`)}</p></PopoverContent></Popover>
|
|
168
|
+
</Sidebar><output aria-live="polite" className="grid max-w-xs gap-2 text-sm text-muted-foreground"><span>{t(\`\${prefix}selected\`)} {t(\`\${prefix}\${active}\`)}</span><span>{t(\`\${prefix}draftNumber\`, { number: draft })}</span>{query ? <span>{t(\`\${prefix}query\`)} {query}</span> : null}</output>
|
|
169
|
+
</div>
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function AiMobileNavigationExample({ kind = 'default' }: { kind?: 'default' | 'in-projects' | 'projects' | 'project-details' }) {
|
|
173
|
+
const t = useT()
|
|
174
|
+
const [model, setModel] = React.useState('GPT-4')
|
|
175
|
+
const [selected, setSelected] = React.useState('projects')
|
|
176
|
+
const [draft, setDraft] = React.useState(0)
|
|
177
|
+
const [project, setProject] = React.useState('')
|
|
178
|
+
const [name, setName] = React.useState('')
|
|
179
|
+
const [createOpen, setCreateOpen] = React.useState(false)
|
|
180
|
+
const [pinned, setPinned] = React.useState(false)
|
|
181
|
+
const id = React.useId()
|
|
182
|
+
const menu = <Popover><PopoverTrigger asChild><AiIconButton aria-label={t(\`\${prefix}menu\`)}><Menu aria-hidden="true" /></AiIconButton></PopoverTrigger><PopoverContent className="grid w-auto gap-1 p-2">{['projects', 'library'].map(item => <AiNavItem key={item} mobile active={selected === item} onClick={() => setSelected(item)}>{t(\`\${prefix}\${item}\`)}</AiNavItem>)}</PopoverContent></Popover>
|
|
183
|
+
const more = <Popover><PopoverTrigger asChild><AiIconButton size={kind === 'project-details' ? 24 : 32} aria-label={t(\`\${prefix}more\`)}><MoreHorizontal aria-hidden="true" /></AiIconButton></PopoverTrigger><PopoverContent className="w-64"><CheckboxField checked={pinned} onCheckedChange={value => setPinned(value === true)} label={t(\`\${prefix}pinProject\`)} /></PopoverContent></Popover>
|
|
184
|
+
const create = () => { if (!name.trim()) return; setProject(name.trim()); setName(''); setCreateOpen(false) }
|
|
185
|
+
return <div className="grid w-full min-w-0 max-w-sm grid-cols-1 gap-4"><header data-slot="ai-mobile-navigation" data-kind={kind} className={cn('flex h-16 w-full min-w-0 items-center gap-2 bg-background px-2 py-3 sm:px-4', kind === 'project-details' ? 'sm:gap-2.5' : 'sm:gap-3.5')}>
|
|
186
|
+
{kind === 'project-details' ? <><AiIconButton size={20} aria-label={t(\`\${prefix}allProjects\`)} onClick={() => setSelected('projects')}><ArrowLeft aria-hidden="true" /></AiIconButton><span className="flex-1 text-sm font-medium">{t(\`\${prefix}allProjects\`)}</span><div className="flex gap-2"><AiIconButton size={24} aria-label={t(\`\${prefix}newChat\`)} onClick={() => setDraft(value => value + 1)}><Plus aria-hidden="true" /></AiIconButton>{more}</div></> : <>{menu}{kind === 'projects' ? <div className="flex flex-1 justify-end"><Popover open={createOpen} onOpenChange={setCreateOpen}><PopoverTrigger asChild><Button type="button" size="sm" variant="outline" className="w-auto shrink-0 gap-2 rounded-lg"><Plus aria-hidden="true" className="size-5" />{t(\`\${prefix}addProject\`)}</Button></PopoverTrigger><PopoverContent className="w-72"><form className="grid gap-3" onSubmit={event => { event.preventDefault(); create() }} onKeyDown={event => { if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) { event.preventDefault(); create() } }}><FieldLabel htmlFor={id} required>{t(\`\${prefix}projectName\`)}</FieldLabel><Input id={id} value={name} onChange={event => setName(event.target.value)} autoFocus /><Button type="submit" size="sm" disabled={!name.trim()}>{t(\`\${prefix}addProject\`)}</Button></form></PopoverContent></Popover></div> : <><div className="flex min-w-0 flex-1 flex-col gap-1"><AiModelSelect value={model} onChange={setModel} compact />{kind === 'in-projects' ? <span className="truncate text-xs leading-4 text-muted-foreground">{t(\`\${prefix}launchPlan\`)}</span> : null}</div><AiIconButton aria-label={t(\`\${prefix}newChat\`)} onClick={() => setDraft(value => value + 1)}><Plus aria-hidden="true" /></AiIconButton>{more}</>}</>}
|
|
187
|
+
</header><output aria-live="polite" className="grid gap-1 text-xs text-muted-foreground"><span>{t(\`\${prefix}selected\`)} {t(\`\${prefix}\${selected}\`)}</span><span>{t(\`\${prefix}draftNumber\`, { number: draft })}</span>{project ? <span>{t(\`\${prefix}createdProject\`)} {project}</span> : null}{pinned ? <span>{t(\`\${prefix}pinProject\`)}</span> : null}</output></div>
|
|
188
|
+
}
|
|
189
|
+
`;
|
|
190
|
+
const aiProductExampleCode = (expression) => source + "\n" + expression + "\n";
|
|
191
|
+
export {
|
|
192
|
+
aiProductExampleCode
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=ai-product-code.generated.js.map
|