@open-mercato/core 0.7.1-develop.7203.1.9396450b78 → 0.8.1-develop.7204.1.83330e271e
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 -8
- 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
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import {
|
|
4
|
+
import { GalleryLink as Link, navigateGallery } from './GalleryLink'
|
|
5
|
+
import { ArrowLeft, Home, BookOpen, Grid2X2, Palette } from 'lucide-react'
|
|
6
|
+
import { useRouter, useSearchParams } from 'next/navigation'
|
|
5
7
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
6
|
-
import {
|
|
8
|
+
import { GalleryNavigation } from './GalleryNavigation'
|
|
7
9
|
import type { SectionNavGroup } from '@open-mercato/ui/backend/section-page'
|
|
8
10
|
import { SearchInput } from '@open-mercato/ui/primitives/search-input'
|
|
9
11
|
import { Skeleton } from '@open-mercato/ui/primitives/skeleton'
|
|
@@ -13,6 +15,12 @@ import { ErrorMessage } from '@open-mercato/ui/backend/detail'
|
|
|
13
15
|
import type { GalleryEntry, GalleryFamily } from '../types'
|
|
14
16
|
import { GALLERY_BASE_PATH, galleryFamilies } from '../registry'
|
|
15
17
|
import { EntryCard } from './EntryCard'
|
|
18
|
+
import { DesignSystemHome, DesignSystemPrinciples } from './DesignSystemHome'
|
|
19
|
+
import { StyleAgents } from './StyleAgents'
|
|
20
|
+
import { ComponentIndex } from './ComponentIndex'
|
|
21
|
+
import { FoundationGuide } from './FoundationGuide'
|
|
22
|
+
import { IconsBrowser } from './IconsBrowser'
|
|
23
|
+
import { fullWidthEntryIds } from '../presentation'
|
|
16
24
|
|
|
17
25
|
/** 'buttons' → 'Buttons' — untranslated fallback when a family labelKey has no message. */
|
|
18
26
|
function familyLabelFallback(id: string): string {
|
|
@@ -28,27 +36,77 @@ function matchesQuery(entry: GalleryEntry, query: string): boolean {
|
|
|
28
36
|
return needle.includes(entry.id.toLowerCase()) || needle.includes(entry.title.toLowerCase())
|
|
29
37
|
}
|
|
30
38
|
|
|
39
|
+
/** A half-width card with no neighbour before the next full-width card would leave a hole, so it spans the row too. */
|
|
40
|
+
export function resolveFullWidthIds(entryIds: string[], fullWidthIds: ReadonlySet<string>): Set<string> {
|
|
41
|
+
const resolved = new Set(entryIds.filter(id => fullWidthIds.has(id)))
|
|
42
|
+
let unpaired: string | null = null
|
|
43
|
+
for (const id of entryIds) {
|
|
44
|
+
if (resolved.has(id)) {
|
|
45
|
+
if (unpaired) resolved.add(unpaired)
|
|
46
|
+
unpaired = null
|
|
47
|
+
} else {
|
|
48
|
+
unpaired = unpaired ? null : id
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (unpaired) resolved.add(unpaired)
|
|
52
|
+
return resolved
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The backend shell centres `main` once the viewport outgrows its max width, which would leave the
|
|
57
|
+
* library navigation floating mid-screen. Pull the gallery back by that centring margin so the
|
|
58
|
+
* navigation stays docked next to the application sidebar at every width.
|
|
59
|
+
*/
|
|
60
|
+
function useShellDockOffset(rootRef: React.RefObject<HTMLElement | null>): number {
|
|
61
|
+
const [offset, setOffset] = React.useState(0)
|
|
62
|
+
React.useLayoutEffect(() => {
|
|
63
|
+
const main = rootRef.current?.closest('main')
|
|
64
|
+
const column = main?.parentElement
|
|
65
|
+
if (!main || !column || typeof ResizeObserver === 'undefined') return
|
|
66
|
+
const measure = () => setOffset(Math.max(0, Math.round(main.getBoundingClientRect().left - column.getBoundingClientRect().left)))
|
|
67
|
+
measure()
|
|
68
|
+
const observer = new ResizeObserver(measure)
|
|
69
|
+
observer.observe(column)
|
|
70
|
+
return () => observer.disconnect()
|
|
71
|
+
}, [rootRef])
|
|
72
|
+
return offset
|
|
73
|
+
}
|
|
74
|
+
|
|
31
75
|
type LoadedEntries = Record<string, GalleryEntry[]>
|
|
32
76
|
|
|
77
|
+
const componentFamilies = galleryFamilies.filter(family => !['foundations', 'library'].includes(family.id))
|
|
78
|
+
|
|
33
79
|
export function GalleryShell() {
|
|
34
80
|
const t = useT()
|
|
81
|
+
const router = useRouter()
|
|
35
82
|
const searchParams = useSearchParams()
|
|
36
83
|
const [loaded, setLoaded] = React.useState<LoadedEntries>({})
|
|
37
84
|
const [failed, setFailed] = React.useState<Record<string, boolean>>({})
|
|
38
85
|
const [search, setSearch] = React.useState('')
|
|
39
86
|
const pendingRef = React.useRef(new Set<string>())
|
|
87
|
+
const rootRef = React.useRef<HTMLDivElement>(null)
|
|
88
|
+
const dockOffset = useShellDockOffset(rootRef)
|
|
40
89
|
|
|
41
90
|
const familyParam = searchParams?.get('family') ?? null
|
|
42
91
|
const entryParam = searchParams?.get('entry') ?? null
|
|
92
|
+
const variantParam = searchParams?.get('variant') ?? null
|
|
93
|
+
const showingPrinciples = searchParams?.get('view') === 'principles' && !familyParam
|
|
94
|
+
const showingComponents = searchParams?.get('view') === 'components' && !familyParam
|
|
95
|
+
const showingStyleAgents = searchParams?.get('view') === 'style-agents' && !familyParam
|
|
96
|
+
const showingHome = !familyParam && !showingPrinciples && !showingComponents && !showingStyleAgents
|
|
97
|
+
const showingFoundations = familyParam === 'foundations'
|
|
98
|
+
const showingAssets = familyParam === 'icons'
|
|
99
|
+
const showingInventory = familyParam === 'library'
|
|
100
|
+
const showingEntry = Boolean(entryParam) && !showingFoundations && !showingAssets && !showingInventory
|
|
101
|
+
|
|
43
102
|
|
|
44
|
-
// Clicking a family in the section nav exits search mode — otherwise the
|
|
45
|
-
// query keeps precedence and family navigation appears dead.
|
|
46
103
|
React.useEffect(() => {
|
|
47
104
|
setSearch('')
|
|
48
|
-
}, [familyParam])
|
|
105
|
+
}, [familyParam, entryParam, showingPrinciples, showingComponents, showingStyleAgents])
|
|
49
106
|
const activeFamily: GalleryFamily | undefined =
|
|
50
107
|
galleryFamilies.find((family) => family.id === familyParam) ?? galleryFamilies[0]
|
|
51
108
|
const activeFamilyId = activeFamily?.id ?? null
|
|
109
|
+
const activeNavigationPath = showingStyleAgents ? `${GALLERY_BASE_PATH}?view=style-agents` : showingHome ? GALLERY_BASE_PATH : showingPrinciples ? `${GALLERY_BASE_PATH}?view=principles` : showingComponents ? `${GALLERY_BASE_PATH}?view=components` : `${GALLERY_BASE_PATH}?family=${activeFamilyId}${(showingFoundations || showingEntry) && entryParam ? `&entry=${entryParam}` : ''}`
|
|
52
110
|
|
|
53
111
|
const loadFamily = React.useCallback((family: GalleryFamily) => {
|
|
54
112
|
if (pendingRef.current.has(family.id)) return
|
|
@@ -71,36 +129,54 @@ export function GalleryShell() {
|
|
|
71
129
|
React.useEffect(() => {
|
|
72
130
|
if (searching) {
|
|
73
131
|
for (const family of galleryFamilies) loadFamily(family)
|
|
74
|
-
} else if (
|
|
132
|
+
} else if (showingComponents) {
|
|
133
|
+
for (const family of componentFamilies) loadFamily(family)
|
|
134
|
+
} else if (activeFamily && !showingHome && !showingPrinciples && !showingStyleAgents) {
|
|
75
135
|
loadFamily(activeFamily)
|
|
76
136
|
}
|
|
77
|
-
}, [searching, activeFamily, loadFamily])
|
|
137
|
+
}, [searching, activeFamily, loadFamily, showingHome, showingPrinciples, showingComponents, showingStyleAgents])
|
|
78
138
|
|
|
79
|
-
// Deep link: ?entry=<id> scrolls the entry into view once its family loaded.
|
|
80
139
|
const activeEntries = activeFamilyId ? loaded[activeFamilyId] : undefined
|
|
81
140
|
React.useEffect(() => {
|
|
82
|
-
if (
|
|
83
|
-
const
|
|
141
|
+
if (searching || (showingFoundations && entryParam && !activeEntries)) return
|
|
142
|
+
const variantId = entryParam === 'file-upload' && variantParam === 'drag-and-drop' ? 'default' : variantParam
|
|
143
|
+
const targetId = showingFoundations && entryParam ? `gallery-entry-${entryParam}` : entryParam && variantId && variantId !== '__all' ? `gallery-variant-${entryParam}-${variantId}` : 'gallery-page-heading'
|
|
144
|
+
const node = document.getElementById(targetId) ?? document.getElementById('gallery-page-heading')
|
|
84
145
|
node?.scrollIntoView({ block: 'start' })
|
|
85
|
-
}, [entryParam, searching, activeEntries])
|
|
86
|
-
|
|
87
|
-
const sections: SectionNavGroup[] = React.useMemo(
|
|
88
|
-
() =>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
146
|
+
}, [familyParam, entryParam, variantParam, searching, activeEntries, showingFoundations, showingHome, showingPrinciples, showingComponents, showingStyleAgents])
|
|
147
|
+
|
|
148
|
+
const sections: SectionNavGroup[] = React.useMemo(() => {
|
|
149
|
+
const familyItem = (family: GalleryFamily) => ({
|
|
150
|
+
id: family.id,
|
|
151
|
+
label: familyLabelFallback(family.id),
|
|
152
|
+
labelKey: family.labelKey,
|
|
153
|
+
icon: family.icon,
|
|
154
|
+
href: `${GALLERY_BASE_PATH}?family=${family.id}`,
|
|
155
|
+
...(!['library', 'icons'].includes(family.id) ? { children: (loaded[family.id] ?? []).map(entry => ({
|
|
156
|
+
id: `entry:${entry.id}`, label: entry.title,
|
|
157
|
+
...(family.id === 'foundations' ? { labelKey: `design_system.foundations.${entry.id}.title` } : {}),
|
|
158
|
+
href: `${GALLERY_BASE_PATH}?family=${family.id}&entry=${entry.id}`,
|
|
159
|
+
})) } : {}),
|
|
160
|
+
})
|
|
161
|
+
return [
|
|
162
|
+
{ id: 'guide', label: '', items: [
|
|
163
|
+
{ id: '__home', label: 'Start', labelKey: 'design_system.portal.nav.home', icon: <Home className="size-4" />, href: GALLERY_BASE_PATH },
|
|
164
|
+
{ id: '__style-agents', label: 'Style agents', labelKey: 'design_system.styleAgents.title', icon: <Palette className="size-4" />, href: `${GALLERY_BASE_PATH}?view=style-agents` },
|
|
165
|
+
...galleryFamilies.filter(family => family.id === 'foundations').map(familyItem),
|
|
166
|
+
] },
|
|
167
|
+
{ id: 'families', label: 'Components', labelKey: 'design_system.portal.nav.components', items: [
|
|
168
|
+
{ id: '__components', label: 'All components', labelKey: 'design_system.gallery.navigation.allComponents', icon: <Grid2X2 className="size-4" />, href: `${GALLERY_BASE_PATH}?view=components` },
|
|
169
|
+
...componentFamilies.map(familyItem),
|
|
170
|
+
] },
|
|
171
|
+
{ id: 'resources', label: 'Resources', labelKey: 'design_system.gallery.navigation.resources', items: [
|
|
172
|
+
{ id: '__principles', label: 'Guidelines', labelKey: 'design_system.portal.nav.principles', icon: <BookOpen className="size-4" />, href: `${GALLERY_BASE_PATH}?view=principles` },
|
|
173
|
+
...galleryFamilies.filter(family => family.id === 'library').map(familyItem),
|
|
174
|
+
] },
|
|
175
|
+
]
|
|
176
|
+
}, [loaded])
|
|
177
|
+
const selectedEntry = entryParam ? activeEntries?.find(entry => entry.id === entryParam) : undefined
|
|
178
|
+
const familyTitle = activeFamily ? t(activeFamily.labelKey, familyLabelFallback(activeFamily.id)) : t('design_system.nav.title')
|
|
179
|
+
const pageTitle = showingComponents ? t('design_system.portal.nav.components') : showingEntry && selectedEntry ? selectedEntry.title : familyTitle
|
|
104
180
|
|
|
105
181
|
const renderFamilySkeleton = () => (
|
|
106
182
|
<div className="space-y-4" data-testid="gallery-family-skeleton">
|
|
@@ -133,7 +209,7 @@ export function GalleryShell() {
|
|
|
133
209
|
{t(family.labelKey, familyLabelFallback(family.id))}
|
|
134
210
|
</h2>
|
|
135
211
|
{entries.map((entry) => (
|
|
136
|
-
<EntryCard key={entry.id} entry={entry} />
|
|
212
|
+
<EntryCard key={entry.id} entry={entry} summary href={`${GALLERY_BASE_PATH}?family=${family.id}&entry=${entry.id}`} onNavigate={() => setSearch('')} />
|
|
137
213
|
))}
|
|
138
214
|
</div>
|
|
139
215
|
))}
|
|
@@ -157,50 +233,60 @@ export function GalleryShell() {
|
|
|
157
233
|
)
|
|
158
234
|
}
|
|
159
235
|
if (!entries) return renderFamilySkeleton()
|
|
236
|
+
if (activeFamily.id === 'icons') return <IconsBrowser entryId={entryParam ?? undefined} variantId={variantParam ?? undefined} onNavigate={(entryId, variantId) => {
|
|
237
|
+
const href = `${GALLERY_BASE_PATH}?family=icons&entry=${entryId}${variantId ? `&variant=${variantId}` : ''}`
|
|
238
|
+
if (!navigateGallery(href)) router.push(href, { scroll: false })
|
|
239
|
+
}} />
|
|
240
|
+
if (activeFamily.id === 'foundations') return <FoundationGuide entries={entries} />
|
|
241
|
+
const sourceLibraryRender = activeFamily.id === 'library' && entries.length === 1 && !entryParam
|
|
242
|
+
? entries[0]?.variants[0]?.render
|
|
243
|
+
: undefined
|
|
244
|
+
if (sourceLibraryRender) {
|
|
245
|
+
const SourceLibraryRender = sourceLibraryRender
|
|
246
|
+
return <div className="space-y-4">
|
|
247
|
+
<SourceLibraryRender />
|
|
248
|
+
</div>
|
|
249
|
+
}
|
|
250
|
+
const selectedEntry = entries.find(entry => entry.id === entryParam) ?? (entries.length === 1 ? entries[0] : undefined)
|
|
251
|
+
const familyFullWidthIds = resolveFullWidthIds(entries.map(entry => entry.id), fullWidthEntryIds)
|
|
160
252
|
return (
|
|
161
253
|
<div className="space-y-4">
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
</
|
|
165
|
-
{entries.length > 1 ? (
|
|
166
|
-
<nav
|
|
167
|
-
aria-label={t('design_system.gallery.familyContents', 'Components in this family')}
|
|
168
|
-
className="flex flex-wrap items-center gap-1.5 rounded-md border border-border bg-muted/30 p-2"
|
|
169
|
-
>
|
|
170
|
-
{entries.map((entry) => (
|
|
171
|
-
<a
|
|
172
|
-
key={entry.id}
|
|
173
|
-
href={`#gallery-entry-${entry.id}`}
|
|
174
|
-
className="rounded-md border border-border bg-background px-2 py-1 text-xs text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:shadow-focus"
|
|
175
|
-
>
|
|
176
|
-
{entry.title}
|
|
177
|
-
</a>
|
|
178
|
-
))}
|
|
179
|
-
</nav>
|
|
180
|
-
) : null}
|
|
181
|
-
{entries.map((entry) => (
|
|
182
|
-
<EntryCard key={entry.id} entry={entry} />
|
|
183
|
-
))}
|
|
254
|
+
{selectedEntry ? <>
|
|
255
|
+
<EntryCard key={selectedEntry.id} entry={selectedEntry} hideTitle fullWidth={fullWidthEntryIds.has(selectedEntry.id)} />
|
|
256
|
+
</> : <div className="grid grid-cols-1 gap-4 @3xl:grid-cols-2">{entries.map(entry => <EntryCard key={entry.id} entry={entry} summary summaryPreview fullWidth={familyFullWidthIds.has(entry.id)} href={`${GALLERY_BASE_PATH}?family=${activeFamily.id}&entry=${entry.id}`} />)}</div>}
|
|
184
257
|
</div>
|
|
185
258
|
)
|
|
186
259
|
}
|
|
187
260
|
|
|
188
261
|
return (
|
|
189
|
-
<
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
262
|
+
<div ref={rootRef} className="flex min-w-0 flex-col lg:flex-row" style={dockOffset ? { marginLeft: -dockOffset, width: `calc(100% + ${dockOffset}px)` } : undefined}>
|
|
263
|
+
<GalleryNavigation sections={sections} activePath={activeNavigationPath} activeFamilyId={familyParam} onNavigate={() => setSearch('')} failed={failed} onExpand={id => {
|
|
264
|
+
const family = galleryFamilies.find(family => family.id === id)
|
|
265
|
+
if (family) loadFamily(family)
|
|
266
|
+
}} onRetry={id => {
|
|
267
|
+
const family = galleryFamilies.find(family => family.id === id)
|
|
268
|
+
if (family) loadFamily(family)
|
|
269
|
+
}} />
|
|
270
|
+
<div className="min-w-0 flex-1 py-4 lg:pl-6">
|
|
271
|
+
<div className="@container mx-auto w-full max-w-6xl space-y-6">
|
|
272
|
+
{showingStyleAgents ? <StyleAgents /> : showingHome ? <DesignSystemHome /> : showingPrinciples ? <div id="gallery-page-heading" className="scroll-mt-36 lg:scroll-mt-24 space-y-8 py-8"><h1 className="text-3xl font-medium tracking-tight">{t('design_system.portal.nav.principles')}</h1><DesignSystemPrinciples /></div> : <>
|
|
273
|
+
<header id="gallery-page-heading" className="scroll-mt-36 lg:scroll-mt-24 space-y-3">
|
|
274
|
+
{selectedEntry && showingEntry ? <Button asChild variant="outline" size="sm"><Link href={`${GALLERY_BASE_PATH}?family=${activeFamilyId}`}><ArrowLeft aria-hidden />{t('design_system.gallery.backToNamedFamily', { family: familyTitle })}</Link></Button> : null}
|
|
275
|
+
{!showingComponents && (!selectedEntry || !showingEntry) ? <Button asChild variant="outline" size="sm"><Link href={`${GALLERY_BASE_PATH}?view=components`}><ArrowLeft aria-hidden />{t('design_system.gallery.backToNamedFamily', { family: t('design_system.portal.nav.components') })}</Link></Button> : null}
|
|
276
|
+
<h1 className="text-3xl font-semibold tracking-tight">{pageTitle}</h1>
|
|
277
|
+
{showingEntry && selectedEntry?.descriptionKey ? <p className="max-w-prose text-sm leading-relaxed text-muted-foreground">{t(selectedEntry.descriptionKey)}</p> : null}
|
|
278
|
+
{showingComponents ? <p className="text-base text-muted-foreground">{t('design_system.portal.componentsDescription')}</p> : null}
|
|
279
|
+
</header>
|
|
280
|
+
{!showingAssets && !showingInventory && !showingEntry ? <SearchInput
|
|
197
281
|
value={search}
|
|
198
282
|
onChange={setSearch}
|
|
199
283
|
placeholder={t('design_system.gallery.searchPlaceholder', 'Search components…')}
|
|
200
284
|
aria-label={t('design_system.gallery.searchPlaceholder', 'Search components…')}
|
|
201
|
-
/>
|
|
202
|
-
{searching ? renderSearchResults() : renderActiveFamily()}
|
|
285
|
+
/> : null}
|
|
286
|
+
{searching ? renderSearchResults() : showingComponents ? <ComponentIndex families={componentFamilies} loaded={loaded} failed={failed} onRetry={loadFamily} /> : renderActiveFamily()}
|
|
287
|
+
</>}
|
|
203
288
|
</div>
|
|
204
|
-
|
|
289
|
+
</div>
|
|
290
|
+
</div>
|
|
205
291
|
)
|
|
206
292
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
5
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'
|
|
6
|
+
import { SourceIconCatalogue } from '../demos/source-icons'
|
|
7
|
+
import { SourceArtworkCatalogue } from '../demos/source-artwork'
|
|
8
|
+
import { IconGrid } from '../demos/registered-icons'
|
|
9
|
+
import type { SourceArtworkGroup } from '@open-mercato/ui/assets/source-artwork'
|
|
10
|
+
|
|
11
|
+
const collections: { id: string; entryId: string; variantId: string; group?: SourceArtworkGroup }[] = [
|
|
12
|
+
{ id: 'icons', entryId: 'source-icons', variantId: 'catalogue' },
|
|
13
|
+
{ id: 'brands', entryId: 'source-artwork', variantId: 'brands', group: 'brand' },
|
|
14
|
+
{ id: 'flags', entryId: 'source-artwork', variantId: 'flags', group: 'country-flags' },
|
|
15
|
+
{ id: 'emoji', entryId: 'source-artwork', variantId: 'emoji', group: 'emojies' },
|
|
16
|
+
{ id: 'badges', entryId: 'source-artwork', variantId: 'store-badges', group: 'appstore-badges' },
|
|
17
|
+
{ id: 'thumbnails', entryId: 'source-artwork', variantId: 'thumbnails', group: 'thumbnails' },
|
|
18
|
+
{ id: 'cursors', entryId: 'source-artwork', variantId: 'cursors', group: 'others' },
|
|
19
|
+
{ id: 'registered', entryId: 'icon-registry', variantId: 'registry' },
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
export function IconsBrowser({ entryId, variantId, onNavigate }: {
|
|
23
|
+
entryId?: string
|
|
24
|
+
variantId?: string
|
|
25
|
+
onNavigate: (entryId: string, variantId?: string) => void
|
|
26
|
+
}) {
|
|
27
|
+
const t = useT()
|
|
28
|
+
const collection = collections.find(item => item.entryId === entryId && item.variantId === variantId)
|
|
29
|
+
?? collections.find(item => item.entryId === entryId)
|
|
30
|
+
?? collections[0]
|
|
31
|
+
const collectionControl = <Select value={collection.id} onValueChange={value => {
|
|
32
|
+
const next = collections.find(item => item.id === value)
|
|
33
|
+
if (next) onNavigate(next.entryId, next.variantId)
|
|
34
|
+
}}>
|
|
35
|
+
<SelectTrigger className="w-64 max-w-full" aria-label={t('design_system.gallery.assets.collection')}><SelectValue /></SelectTrigger>
|
|
36
|
+
<SelectContent>{collections.map(item => <SelectItem key={item.id} value={item.id}>{t(`design_system.gallery.assets.${item.id}`)}</SelectItem>)}</SelectContent>
|
|
37
|
+
</Select>
|
|
38
|
+
return collection.group ? <SourceArtworkCatalogue key={collection.id} group={collection.group} collectionControl={collectionControl} />
|
|
39
|
+
: collection.id === 'registered' ? <IconGrid collectionControl={collectionControl} /> : <SourceIconCatalogue collectionControl={collectionControl} />
|
|
40
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { GalleryLink as Link } from './GalleryLink'
|
|
5
|
+
import { ArrowRight } from 'lucide-react'
|
|
6
|
+
import { LinkButton } from '@open-mercato/ui/primitives/link-button'
|
|
7
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
8
|
+
import { EmptyState } from '@open-mercato/ui/primitives/empty-state'
|
|
9
|
+
import { Pagination } from '@open-mercato/ui/primitives/pagination'
|
|
10
|
+
import { SearchInput } from '@open-mercato/ui/primitives/search-input'
|
|
11
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'
|
|
12
|
+
import { GALLERY_BASE_PATH } from '../registry'
|
|
13
|
+
import { sourceLibrary } from '../source-library.generated'
|
|
14
|
+
|
|
15
|
+
const pageSize = 12
|
|
16
|
+
const allGroups = '__all'
|
|
17
|
+
const groupTranslationKey = (group: string) => `design_system.gallery.sourceLibrary.groups.${group.toLowerCase().replace(/\s+/g, '-')}`
|
|
18
|
+
|
|
19
|
+
export function SourceLibrary() {
|
|
20
|
+
const t = useT()
|
|
21
|
+
const storyTitle = (story: { family: string; entryId: string; title: string }) => story.family === 'foundations'
|
|
22
|
+
? t(`design_system.foundations.${story.entryId}.title`, story.title)
|
|
23
|
+
: story.title
|
|
24
|
+
const [query, setQuery] = React.useState('')
|
|
25
|
+
const [group, setGroup] = React.useState(allGroups)
|
|
26
|
+
const [page, setPage] = React.useState(1)
|
|
27
|
+
const groups = React.useMemo(() => Array.from(new Set(sourceLibrary.pages.map(item => item.group))), [])
|
|
28
|
+
const needle = query.trim().toLowerCase()
|
|
29
|
+
const filtered = sourceLibrary.pages.filter(item => {
|
|
30
|
+
const matchesGroup = group === allGroups || item.group === group
|
|
31
|
+
const translatedName = t(`design_system.gallery.sourceLibrary.names.${item.id}`, item.name)
|
|
32
|
+
const translatedGroup = t(groupTranslationKey(item.group), item.group)
|
|
33
|
+
const searchTerms = t(`design_system.gallery.sourceLibrary.searchTerms.${item.id}`, '')
|
|
34
|
+
const searchable = `${item.name} ${translatedName} ${item.group} ${translatedGroup} ${searchTerms} ${item.stories.map(story => `${story.title} ${storyTitle(story)}`).join(' ')} ${item.sets.map(set => `${set.name} ${Object.values(set.axes).flat().join(' ')}`).join(' ')} ${item.standalone.map(asset => asset.name).join(' ')}`
|
|
35
|
+
return matchesGroup && searchable.toLowerCase().includes(needle)
|
|
36
|
+
})
|
|
37
|
+
const visible = filtered.slice((page - 1) * pageSize, page * pageSize)
|
|
38
|
+
|
|
39
|
+
return <div className="w-full min-w-0 space-y-4" data-example="native-source-library">
|
|
40
|
+
<p className="text-sm text-muted-foreground">{t('design_system.gallery.sourceLibrary.boundary')}</p>
|
|
41
|
+
<div className="flex flex-col gap-3 sm:flex-row">
|
|
42
|
+
<SearchInput className="sm:flex-1" value={query} onChange={value => { setQuery(value); setPage(1) }} aria-label={t('design_system.gallery.sourceLibrary.search')} placeholder={t('design_system.gallery.sourceLibrary.search')} />
|
|
43
|
+
<Select value={group} onValueChange={value => { setGroup(value); setPage(1) }}>
|
|
44
|
+
<SelectTrigger className="w-full sm:w-64" aria-label={t('design_system.gallery.sourceLibrary.group')}><SelectValue /></SelectTrigger>
|
|
45
|
+
<SelectContent>
|
|
46
|
+
<SelectItem value={allGroups}>{t('design_system.gallery.sourceLibrary.allGroups')}</SelectItem>
|
|
47
|
+
{groups.map(value => <SelectItem key={value} value={value}>{t(groupTranslationKey(value), value)}</SelectItem>)}
|
|
48
|
+
</SelectContent>
|
|
49
|
+
</Select>
|
|
50
|
+
</div>
|
|
51
|
+
<p role="status" className="text-sm text-muted-foreground">{t('design_system.gallery.sourceLibrary.count', { visible: filtered.length, total: sourceLibrary.pages.length })}</p>
|
|
52
|
+
{visible.length ? <div className="divide-y divide-border rounded-lg border border-border bg-card">{visible.map(item => {
|
|
53
|
+
const variantCount = item.sets.reduce((total, set) => total + set.count, 0)
|
|
54
|
+
const hasInventory = item.sets.length > 0 || item.standaloneCount > 0 || item.frameCount > 0
|
|
55
|
+
return <article key={item.id} className="grid min-w-0 gap-4 p-5 lg:grid-cols-3">
|
|
56
|
+
<header className="space-y-1">
|
|
57
|
+
<h3 className="text-base font-semibold leading-tight">{t(`design_system.gallery.sourceLibrary.names.${item.id}`, item.name)}</h3>
|
|
58
|
+
<p className="text-xs text-muted-foreground">{t(groupTranslationKey(item.group), item.group)}</p>
|
|
59
|
+
</header>
|
|
60
|
+
<div className="min-w-0 space-y-3 lg:col-span-2">
|
|
61
|
+
{item.stories.length ? <ul className="flex flex-wrap gap-x-6 gap-y-3" aria-label={t('design_system.gallery.sourceLibrary.examples')}>
|
|
62
|
+
{item.stories.map(story => <li key={`${story.family}:${story.entryId}`}>
|
|
63
|
+
<LinkButton asChild variant="black">
|
|
64
|
+
<Link href={`${GALLERY_BASE_PATH}?family=${story.family}&entry=${story.entryId}`}>
|
|
65
|
+
{storyTitle(story)}<ArrowRight className="size-4 text-muted-foreground" aria-hidden="true" />
|
|
66
|
+
</Link>
|
|
67
|
+
</LinkButton>
|
|
68
|
+
</li>)}
|
|
69
|
+
</ul> : <p className="text-sm text-muted-foreground">{t('design_system.gallery.sourceLibrary.referenceOnly')}</p>}
|
|
70
|
+
{hasInventory ? <section className="text-sm">
|
|
71
|
+
<h4 className="text-xs font-medium text-muted-foreground">{t('design_system.gallery.sourceLibrary.details')}</h4>
|
|
72
|
+
<div className="mt-3 space-y-4 border-l border-border pl-4">
|
|
73
|
+
<div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground">
|
|
74
|
+
{item.sets.length ? <span>{t('design_system.gallery.sourceLibrary.componentSets', { count: item.sets.length })}</span> : null}
|
|
75
|
+
{variantCount ? <span>{t('design_system.gallery.sourceLibrary.variants', { count: variantCount })}</span> : null}
|
|
76
|
+
{item.frameCount ? <span>{t('design_system.gallery.sourceLibrary.frames', { count: item.frameCount })}</span> : null}
|
|
77
|
+
{item.standaloneCount ? <span>{t('design_system.gallery.sourceLibrary.assets', { count: item.standaloneCount })}</span> : null}
|
|
78
|
+
</div>
|
|
79
|
+
{item.sets.map(set => <section key={set.id} className="space-y-2">
|
|
80
|
+
<h4 className="text-sm font-medium">{set.name}</h4>
|
|
81
|
+
<dl className="space-y-2">{Object.entries(set.axes).map(([axis, values]) => <div key={axis} className="text-xs"><dt className="font-medium">{axis}</dt><dd className="break-words text-muted-foreground">{(values as string[]).join(' · ')}</dd></div>)}</dl>
|
|
82
|
+
</section>)}
|
|
83
|
+
</div>
|
|
84
|
+
</section> : null}
|
|
85
|
+
</div>
|
|
86
|
+
</article>
|
|
87
|
+
})}</div> : <EmptyState title={t('design_system.gallery.noResults')} />}
|
|
88
|
+
{filtered.length > pageSize ? <Pagination page={page} pageSize={pageSize} total={filtered.length} showPageSize={false} onPageChange={setPage} aria-label={t('design_system.gallery.sourceLibrary.pages')} /> : null}
|
|
89
|
+
</div>
|
|
90
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Check, ImagePlus, RotateCcw, Upload, X } from 'lucide-react'
|
|
5
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
6
|
+
import { Button } from '@open-mercato/ui/primitives/button'
|
|
7
|
+
import { SimpleTooltip } from '@open-mercato/ui/primitives/tooltip'
|
|
8
|
+
import { getBrandStyle, saveBrandStyle, type BrandStyle } from '@open-mercato/ui/theme/brand-style'
|
|
9
|
+
import { ColorPlayground } from './ColorPlayground'
|
|
10
|
+
import { BrandStylePreview } from './BrandStylePreview'
|
|
11
|
+
import { readThemeTokens, type ThemeTokens } from './themeTokens'
|
|
12
|
+
import type { Shade } from './colorStudio'
|
|
13
|
+
import type { ColorStudio } from './colorStudio'
|
|
14
|
+
import { readBrandLogo, studioBrandStyle } from './styleAgentBranding'
|
|
15
|
+
|
|
16
|
+
function brandPreview(studio: ColorStudio, logo: string | null) {
|
|
17
|
+
const style = studioBrandStyle(studio, logo)
|
|
18
|
+
return { light: style.light, dark: style.dark }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function StyleAgents() {
|
|
22
|
+
const t = useT()
|
|
23
|
+
const input = React.useRef<HTMLInputElement>(null)
|
|
24
|
+
const uploadVersion = React.useRef(0)
|
|
25
|
+
const [initial, setInitial] = React.useState<BrandStyle | null | undefined>(undefined)
|
|
26
|
+
const [hostTokens, setHostTokens] = React.useState<ThemeTokens | null>(null)
|
|
27
|
+
const [logo, setLogo] = React.useState<string | null>(null)
|
|
28
|
+
const [draft, setDraft] = React.useState<{ studio: ColorStudio; valid: boolean } | null>(null)
|
|
29
|
+
const [uploading, setUploading] = React.useState(false)
|
|
30
|
+
const [notice, setNotice] = React.useState('')
|
|
31
|
+
const [error, setError] = React.useState('')
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
setHostTokens(readThemeTokens(document.styleSheets))
|
|
34
|
+
const applied = getBrandStyle()
|
|
35
|
+
setInitial(applied)
|
|
36
|
+
setLogo(applied?.logo ?? null)
|
|
37
|
+
return () => { uploadVersion.current += 1 }
|
|
38
|
+
}, [])
|
|
39
|
+
const updateStudio = React.useCallback((studio: ColorStudio, valid: boolean) => {
|
|
40
|
+
setDraft({ studio, valid })
|
|
41
|
+
setNotice('')
|
|
42
|
+
}, [])
|
|
43
|
+
|
|
44
|
+
async function upload(file: File | undefined) {
|
|
45
|
+
if (!file) return
|
|
46
|
+
const version = ++uploadVersion.current
|
|
47
|
+
setUploading(true)
|
|
48
|
+
setError('')
|
|
49
|
+
setNotice('')
|
|
50
|
+
try {
|
|
51
|
+
const data = await readBrandLogo(file)
|
|
52
|
+
if (uploadVersion.current === version) setLogo(data)
|
|
53
|
+
} catch (failure) {
|
|
54
|
+
if (uploadVersion.current === version) setError(failure instanceof Error ? failure.message : 'fileDecode')
|
|
55
|
+
} finally {
|
|
56
|
+
if (uploadVersion.current === version) setUploading(false)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function apply() {
|
|
61
|
+
if (!draft?.valid || uploading) return
|
|
62
|
+
try {
|
|
63
|
+
saveBrandStyle(studioBrandStyle(draft.studio, logo))
|
|
64
|
+
setError('')
|
|
65
|
+
setNotice('applied')
|
|
66
|
+
} catch { setError('saveFailed'); setNotice('') }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function restore() {
|
|
70
|
+
try {
|
|
71
|
+
saveBrandStyle(null)
|
|
72
|
+
setError('')
|
|
73
|
+
setNotice('restored')
|
|
74
|
+
} catch { setError('saveFailed'); setNotice('') }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return <div className="space-y-8 pb-8" data-example="style-agents">
|
|
78
|
+
<header id="gallery-page-heading" className="scroll-mt-36 space-y-3 lg:scroll-mt-24">
|
|
79
|
+
<div className="flex flex-wrap items-start justify-between gap-4">
|
|
80
|
+
<div className="space-y-3">
|
|
81
|
+
<h1 className="text-3xl font-medium tracking-tight">{t('design_system.styleAgents.title')}</h1>
|
|
82
|
+
<p className="max-w-3xl text-sm leading-relaxed text-muted-foreground">{t('design_system.styleAgents.description')}</p>
|
|
83
|
+
</div>
|
|
84
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
85
|
+
<SimpleTooltip content={t('design_system.styleAgents.restoreHint')}>
|
|
86
|
+
<Button type="button" variant="ghost" onClick={restore}><RotateCcw aria-hidden />{t('design_system.styleAgents.restore')}</Button>
|
|
87
|
+
</SimpleTooltip>
|
|
88
|
+
<Button type="button" onClick={apply} disabled={!draft?.valid || uploading}><Check aria-hidden />{t('design_system.styleAgents.apply')}</Button>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
{notice ? <p role="status" className="text-sm text-status-success-text">{t(`design_system.styleAgents.${notice}`)}</p> : null}
|
|
92
|
+
{error ? <p role="alert" className="text-sm text-status-error-text">{t(`design_system.styleAgents.${error}`)}</p> : null}
|
|
93
|
+
</header>
|
|
94
|
+
<section className="grid gap-6 rounded-xl border border-border bg-card p-5 sm:p-6 lg:grid-cols-2" aria-label={t('design_system.styleAgents.identity')}>
|
|
95
|
+
<div className="space-y-4">
|
|
96
|
+
<div className="space-y-1"><h2 className="text-lg font-medium">{t('design_system.styleAgents.logo')}</h2><p className="text-xs leading-relaxed text-muted-foreground">{t('design_system.styleAgents.logoHint')}</p></div>
|
|
97
|
+
<div className="flex min-h-28 items-center justify-center rounded-lg border border-dashed border-border bg-background p-6">
|
|
98
|
+
{logo ? <img src={logo} alt={t('design_system.styleAgents.logoPreview')} className="max-h-20 max-w-full object-contain" /> : <ImagePlus className="size-8 text-muted-foreground" aria-hidden />}
|
|
99
|
+
</div>
|
|
100
|
+
<input ref={input} type="file" accept="image/png,image/jpeg,image/webp" className="sr-only" aria-label={t('design_system.styleAgents.upload')} onChange={event => { void upload(event.target.files?.[0]); event.target.value = '' }} />
|
|
101
|
+
<div className="flex flex-wrap gap-2">
|
|
102
|
+
<Button type="button" variant="outline" onClick={() => input.current?.click()}><Upload aria-hidden />{t(`design_system.styleAgents.${uploading ? 'uploading' : 'upload'}`)}</Button>
|
|
103
|
+
{logo ? <Button type="button" variant="ghost" onClick={() => { uploadVersion.current += 1; setUploading(false); setLogo(null); setNotice(''); setError('') }}><X aria-hidden />{t('design_system.styleAgents.removeLogo')}</Button> : null}
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<div className="flex flex-col justify-between gap-5">
|
|
107
|
+
<div className="space-y-3"><h2 className="text-lg font-medium">{t('design_system.styleAgents.applyTitle')}</h2><p className="text-sm leading-relaxed text-muted-foreground">{t('design_system.styleAgents.scope')}</p><p className="text-xs leading-relaxed text-muted-foreground">{t('design_system.styleAgents.tokenScope')}</p></div>
|
|
108
|
+
|
|
109
|
+
</div>
|
|
110
|
+
</section>
|
|
111
|
+
{draft ? <BrandStylePreview {...brandPreview(draft.studio, logo)} hostTokens={hostTokens} logo={logo} /> : null}
|
|
112
|
+
{initial !== undefined ? <ColorPlayground initialView="light" initialSeeds={initial?.seeds} initialActionShades={initial?.actionShades as { light?: Shade; dark?: Shade } | undefined} logo={logo} onStudioChange={updateStudio} /> : null}
|
|
113
|
+
|
|
114
|
+
</div>
|
|
115
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'
|
|
5
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
6
|
+
import { DataTable } from '@open-mercato/ui/backend/DataTable'
|
|
7
|
+
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
|
+
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
9
|
+
import { readThemeTokens, type ThemeTokens } from './themeTokens'
|
|
10
|
+
|
|
11
|
+
const referenceTokens = [
|
|
12
|
+
'brand-lime', 'brand-yellow', 'brand-violet', 'background', 'foreground',
|
|
13
|
+
'card', 'card-foreground', 'muted', 'muted-foreground', 'primary', 'primary-foreground',
|
|
14
|
+
'primary-hover', 'border', 'input', 'ring', 'destructive',
|
|
15
|
+
'status-info-bg', 'status-info-text', 'status-success-bg', 'status-success-text',
|
|
16
|
+
'status-warning-bg', 'status-warning-text', 'status-error-bg', 'status-error-text',
|
|
17
|
+
]
|
|
18
|
+
type TokenRow = { token: string; light: string; dark: string }
|
|
19
|
+
|
|
20
|
+
function displayColor(value: string, context: CanvasRenderingContext2D | null) {
|
|
21
|
+
if (!context || !CSS.supports('color', value)) return value
|
|
22
|
+
context.clearRect(0, 0, 1, 1)
|
|
23
|
+
context.fillStyle = value
|
|
24
|
+
context.fillRect(0, 0, 1, 1)
|
|
25
|
+
const [red, green, blue, alpha] = context.getImageData(0, 0, 1, 1).data
|
|
26
|
+
return '#' + [red, green, blue, ...(alpha === 255 ? [] : [alpha])].map(channel => channel.toString(16).padStart(2, '0')).join('').toUpperCase()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function ThemeTokenReference() {
|
|
30
|
+
const t = useT()
|
|
31
|
+
const [tokens, setTokens] = React.useState<ThemeTokens | null>(null)
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
const values = readThemeTokens(document.styleSheets)
|
|
34
|
+
const canvas = document.createElement('canvas')
|
|
35
|
+
canvas.width = 1
|
|
36
|
+
canvas.height = 1
|
|
37
|
+
const context = canvas.getContext('2d', { willReadFrequently: true })
|
|
38
|
+
for (const theme of ['light', 'dark'] as const) {
|
|
39
|
+
for (const token of referenceTokens) {
|
|
40
|
+
const value = values[theme][`--${token}`]
|
|
41
|
+
if (value) values[theme][`--${token}`] = displayColor(value, context)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
setTokens(values)
|
|
45
|
+
}, [])
|
|
46
|
+
const rows = referenceTokens.map(token => ({ token: `--${token}`, light: tokens?.light[`--${token}`] ?? '—', dark: tokens?.dark[`--${token}`] ?? '—' }))
|
|
47
|
+
async function copyToken(token: string) {
|
|
48
|
+
try {
|
|
49
|
+
await navigator.clipboard.writeText(token)
|
|
50
|
+
flash(t('design_system.gallery.tokenCopied', { token }), 'success')
|
|
51
|
+
} catch { flash(t('design_system.gallery.tokenCopyFailed'), 'error') }
|
|
52
|
+
}
|
|
53
|
+
const columns: ColumnDef<TokenRow, unknown>[] = [
|
|
54
|
+
{ accessorKey: 'token', header: t('design_system.foundations.token'), cell: ({ row }) => <Button type="button" variant="ghost" className="h-auto justify-start px-0 py-2 font-mono text-xs" aria-label={t('design_system.gallery.copyToken', { token: row.original.token })} onClick={() => copyToken(row.original.token)}>{row.original.token}</Button> },
|
|
55
|
+
...(['light', 'dark'] as const).map(theme => ({
|
|
56
|
+
accessorKey: theme,
|
|
57
|
+
header: t(`design_system.foundations.${theme}`),
|
|
58
|
+
cell: ({ row }: { row: { original: TokenRow } }) => <span className="flex items-center gap-3 py-2"><span aria-hidden className="size-6 shrink-0 rounded-full border border-border" style={{ backgroundColor: row.original[theme] === '—' ? undefined : row.original[theme] }} /><code className="text-xs text-muted-foreground">{row.original[theme]}</code></span>,
|
|
59
|
+
})),
|
|
60
|
+
]
|
|
61
|
+
return <div className="space-y-4">
|
|
62
|
+
<h3 className="text-xl font-medium">{t('design_system.foundations.themeReference')}</h3>
|
|
63
|
+
<p className="max-w-prose text-sm leading-relaxed text-muted-foreground">{t('design_system.foundations.themeDescription')}</p>
|
|
64
|
+
{tokens ? <div className="grid gap-4 sm:grid-cols-2">
|
|
65
|
+
{(['light', 'dark'] as const).map(theme => <div key={theme} className="space-y-6 rounded-lg border p-6" style={{ backgroundColor: tokens[theme]['--background'], color: tokens[theme]['--foreground'], borderColor: tokens[theme]['--border'] }}>
|
|
66
|
+
<p className="text-base font-medium">{t(`design_system.foundations.${theme}`)}</p>
|
|
67
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
68
|
+
<Button type="button" style={{ backgroundColor: tokens[theme]['--primary'], color: tokens[theme]['--primary-foreground'] }}>{t('design_system.gallery.samples.primaryAction')}</Button>
|
|
69
|
+
<span className="inline-flex h-9 items-center rounded-md border px-4 text-sm" style={{ borderColor: tokens[theme]['--border'] }}>Aa</span>
|
|
70
|
+
</div>
|
|
71
|
+
<code className="text-xs" style={{ color: tokens[theme]['--muted-foreground'] }}>{tokens[theme]['--background']} / {tokens[theme]['--foreground']}</code>
|
|
72
|
+
</div>)}
|
|
73
|
+
</div> : null}
|
|
74
|
+
<DataTable columns={columns} data={rows} isLoading={!tokens} />
|
|
75
|
+
</div>
|
|
76
|
+
}
|
|
@@ -6,9 +6,9 @@ import * as React from 'react'
|
|
|
6
6
|
* Bordered stage a variant renders inside. Chrome uses semantic tokens only —
|
|
7
7
|
* the stage must never impose colors of its own on the previewed component.
|
|
8
8
|
*/
|
|
9
|
-
export function VariantPreview({ children }: { children: React.ReactNode }) {
|
|
9
|
+
export function VariantPreview({ children, framed = true }: { children: React.ReactNode; framed?: boolean }) {
|
|
10
10
|
return (
|
|
11
|
-
<div className=
|
|
11
|
+
<div className={framed ? 'flex min-w-0 flex-wrap items-start gap-4 rounded-lg border border-border bg-background p-4 sm:p-6 [&>*]:min-w-0' : 'min-w-0 [&>*]:min-w-0'}>
|
|
12
12
|
{children}
|
|
13
13
|
</div>
|
|
14
14
|
)
|