@open-mercato/core 0.7.1-develop.7202.1.a52dc6707c → 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,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/design_system/gallery/demos/marketing-controls-code.generated.ts"],
|
|
4
|
+
"sourcesContent": ["// Generated by yarn storybook:generate from marketing-controls.tsx.\nconst source = \"import * as React from 'react'\\nimport { CheckCircle2, ChevronRight, Info, Pencil, UserRound } from 'lucide-react'\\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\\nimport { cn } from '@open-mercato/shared/lib/utils'\\nimport { Button } from '@open-mercato/ui/primitives/button'\\nimport { Input } from '@open-mercato/ui/primitives/input'\\nimport { InlineInput } from '@open-mercato/ui/primitives/inline-input'\\nimport { InlineSelectTrigger } from '@open-mercato/ui/primitives/inline-select'\\nimport { Label } from '@open-mercato/ui/primitives/label'\\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@open-mercato/ui/primitives/tooltip'\\nimport { marketingProducts } from '../assets/marketing-artwork'\\n\\nexport type MarketingControlState = 'default' | 'hover' | 'active' | 'filled' | 'placeholder' | 'focus' | 'disabled' | 'complete' | 'selected'\\nexport type MarketingControlKind = 'step-item' | 'select' | 'input' | 'textarea' | 'amount' | 'tab-menu' | 'inline-input' | 'inline-select' | 'chart-tooltip' | 'selected-button' | 'product-image'\\ntype ControlProps = { kind: MarketingControlKind; state?: MarketingControlState; size?: 'medium' | 'large'; side?: 'right' | 'left' | 'bottom' | 'top'; product?: number }\\nconst key = (name: string) => `design_system.gallery.samples.marketing.${name}`\\nconst focusStyle = 'focus-within:border-accent-orange-border focus-within:shadow-none'\\n\\nfunction UnderlineField({ kind, state = 'default', size = 'medium' }: ControlProps) {\\n const t = useT()\\n const id = React.useId()\\n const large = size === 'large' || kind === 'amount'\\n const label = t(key(kind === 'textarea' ? 'description' : kind === 'amount' ? 'productPricing' : kind === 'select' ? 'category' : 'productName'))\\n const placeholder = t(key(kind === 'textarea' ? 'productDescriptionPlaceholder' : kind === 'select' ? 'categoryPlaceholder' : 'productNamePlaceholder'))\\n const [value, setValue] = React.useState(state === 'filled' ? kind === 'select' ? 'accessories' : kind === 'amount' ? '800' : t(key(kind === 'textarea' ? 'productDescription' : 'productNameExample')) : '')\\n const active = state === 'active'\\n return <div data-slot=\\\"marketing-control\\\" data-kind={kind} className={cn('relative flex w-93 max-w-full flex-col gap-1.5 pb-3.5 after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-border focus-within:after:h-0.5 focus-within:after:bg-accent-orange-border', large ? 'h-20' : 'h-16', active && 'after:h-0.5 after:bg-accent-orange-border')}>\\n <Label htmlFor={id} className=\\\"flex h-5 shrink-0 items-center gap-1 text-sm font-medium text-muted-foreground\\\">{label}<Info aria-hidden=\\\"true\\\" className=\\\"size-3 text-text-disabled\\\" /></Label>\\n {kind === 'select' ? <Select value={value} onValueChange={setValue}><SelectTrigger id={id} aria-label={label} className={cn('h-6 rounded-none border-0 bg-transparent p-0 text-lg font-medium shadow-none hover:bg-transparent focus:border-0 focus:shadow-none', state === 'hover' && 'text-muted-foreground', active && '[&_svg]:text-accent-orange-text')}><SelectValue placeholder={placeholder} /></SelectTrigger><SelectContent>{['accessories','computers','audio'].map(option => <SelectItem key={option} value={option}>{t(key(option))}</SelectItem>)}</SelectContent></Select> : kind === 'textarea' ? <Textarea id={id} aria-label={label} rows={1} value={value} onChange={event => setValue(event.target.value)} placeholder={placeholder} autoFocus={active} className={cn('h-6 min-h-6 resize-none rounded-none border-0 bg-transparent p-0 text-lg font-medium leading-6 shadow-none hover:bg-transparent focus-visible:shadow-none', state === 'hover' && 'placeholder:text-muted-foreground')} /> : <Input id={id} aria-label={label} value={value} onChange={event => setValue(event.target.value)} type={kind === 'amount' ? 'number' : 'text'} min={kind === 'amount' ? 0 : undefined} step={kind === 'amount' ? '0.01' : undefined} autoFocus={active} placeholder={kind === 'amount' ? '0.00' : placeholder} leading={kind === 'amount' ? <span aria-hidden=\\\"true\\\" className={cn('text-title-4 font-medium', !value && !active && 'text-text-disabled')}>$</span> : undefined} className={cn('rounded-none border-0 bg-transparent p-0 shadow-none hover:bg-transparent focus-within:shadow-none', large ? 'h-10' : 'h-6')} inputClassName={cn('font-medium placeholder:text-text-disabled', large ? 'text-title-4 leading-10' : 'text-lg leading-6', state === 'hover' && 'placeholder:text-muted-foreground')} />}\\n </div>\\n}\\n\\nfunction InlineEditor({ state = 'placeholder' }: { state?: MarketingControlState }) {\\n const t = useT()\\n const [value, setValue] = React.useState(state === 'filled' ? 'James Brown' : '')\\n const [draft, setDraft] = React.useState(value)\\n const [editing, setEditing] = React.useState(state === 'focus')\\n const disabled = state === 'disabled'\\n const save = () => { setValue(draft.trim()); setEditing(false) }\\n const cancel = () => { setDraft(value); setEditing(false) }\\n return <div data-slot=\\\"marketing-control\\\" data-kind=\\\"inline-input\\\" className=\\\"w-78 max-w-full\\\">\\n {editing ? <InlineInput autoFocus value={draft} onChange={event => setDraft(event.target.value)} aria-label={t(key('name'))} placeholder={t(key('namePlaceholder'))} className={cn('h-10 gap-2 rounded-lg border-accent-orange-border bg-background px-3', focusStyle)} onKeyDown={event => { if (event.key === 'Escape') { event.preventDefault(); cancel() } if (event.key === 'Enter') { event.preventDefault(); save() } }} trailing={<div className=\\\"flex gap-2\\\"><Button variant=\\\"ghost\\\" className=\\\"h-5 p-0 text-sm font-normal\\\" onClick={cancel}>{t(key('cancel'))}</Button><Button variant=\\\"ghost\\\" className=\\\"h-5 p-0 text-sm font-normal text-accent-orange-text\\\" onClick={save}>{t(key('save'))}</Button></div>} /> : <Button disabled={disabled} variant=\\\"ghost\\\" onClick={() => setEditing(true)} className={cn('h-10 w-full justify-between rounded-lg px-3 text-sm font-normal', state === 'hover' && 'bg-muted', !value && 'text-muted-foreground')}><span className=\\\"truncate\\\">{value || t(key('namePlaceholder'))}</span><Pencil aria-hidden=\\\"true\\\" className=\\\"size-4 shrink-0 text-text-disabled\\\" /></Button>}\\n </div>\\n}\\n\\nfunction InlineLanguage({ state = 'placeholder' }: { state?: MarketingControlState }) {\\n const t = useT()\\n const [value, setValue] = React.useState(state === 'filled' ? 'en' : '')\\n const [open, setOpen] = React.useState(false)\\n return <div data-slot=\\\"marketing-control\\\" data-kind=\\\"inline-select\\\" className=\\\"w-64 max-w-full\\\"><Select value={value} onValueChange={setValue} open={open} onOpenChange={setOpen} disabled={state === 'disabled'}><InlineSelectTrigger aria-label={t(key('language'))} className={cn('h-10 rounded-lg px-3 focus:border-accent-orange-border focus:shadow-none', state === 'hover' && 'bg-muted', state === 'focus' && 'border-accent-orange-border')}><SelectValue placeholder={t(key('languagePlaceholder'))} /></InlineSelectTrigger><SelectContent>{['en','pl','de','es','ko'].map(language => <SelectItem key={language} value={language}>{t(key(`language${language}`))}</SelectItem>)}</SelectContent></Select></div>\\n}\\n\\nfunction StepItem({ state = 'default' }: { state?: MarketingControlState }) {\\n const t = useT()\\n const [selected, setSelected] = React.useState(state === 'active')\\n return <Button data-slot=\\\"marketing-control\\\" data-kind=\\\"step-item\\\" variant=\\\"ghost\\\" aria-pressed={selected} onClick={() => setSelected(current => !current)} className={cn('h-11 w-45 max-w-full flex-col items-start justify-start gap-1 rounded-none border-r-2 border-transparent p-0 pr-6 text-sm font-normal hover:bg-transparent', selected && 'border-r-accent-orange')}><span className={cn('flex h-5 items-center gap-1', selected ? 'text-accent-orange-text' : 'text-muted-foreground')}>{t(key('step'), undefined, { current: 1, total: 5 })}{state === 'complete' ? <CheckCircle2 aria-hidden=\\\"true\\\" className=\\\"size-3.5 fill-status-success-icon text-status-success-foreground\\\" /> : null}</span><span className=\\\"h-5\\\">{t(key('generalInformation'))}</span></Button>\\n}\\n\\nfunction SelectedAmount({ state = 'default' }: { state?: MarketingControlState }) {\\n const locale = useLocale()\\n const [selected,setSelected] = React.useState(state === 'selected')\\n return <Button data-slot=\\\"marketing-control\\\" data-kind=\\\"selected-button\\\" aria-pressed={selected} disabled={state === 'disabled'} variant={selected ? 'default' : 'outline'} onClick={() => setSelected(current => !current)} className={cn('h-7 gap-1.5 rounded-md border border-border px-2.5 py-1 font-normal', state === 'hover' && 'bg-muted', selected && 'border-transparent bg-accent-orange/10 text-accent-orange-text hover:bg-accent-orange/20')}>\\n {selected ? <CheckCircle2 aria-hidden=\\\"true\\\" className=\\\"size-3.5\\\" /> : null}{new Intl.NumberFormat(locale).format(800)}\\n </Button>\\n}\\n\\nfunction MenuItem({ state = 'default' }: { state?: MarketingControlState }) {\\n const t = useT()\\n const [selected,setSelected] = React.useState(state === 'active')\\n return <Button data-slot=\\\"marketing-control\\\" data-kind=\\\"tab-menu\\\" variant=\\\"ghost\\\" aria-pressed={selected} onClick={() => setSelected(current => !current)} className={cn('h-9 w-56 max-w-full justify-start gap-2 rounded-lg p-2 text-sm font-medium', (state === 'hover' || selected) && 'bg-muted')}><UserRound aria-hidden=\\\"true\\\" className={cn('size-5', selected ? 'text-accent-orange-text' : 'text-muted-foreground')} /><span className=\\\"flex-1 text-left\\\">{t(key('accountSettings'))}</span><ChevronRight aria-hidden=\\\"true\\\" className=\\\"size-4 text-muted-foreground\\\" /></Button>\\n}\\n\\nfunction ChartTooltipExample({ side = 'right' }: { side?: 'right' | 'left' | 'bottom' | 'top' }) {\\n const t = useT()\\n const locale = useLocale()\\n const [open,setOpen] = React.useState(true)\\n return <div data-slot=\\\"marketing-control\\\" data-kind=\\\"chart-tooltip\\\" className=\\\"flex h-40 w-80 max-w-full items-center justify-center\\\"><TooltipProvider delayDuration={0}><Tooltip open={open} onOpenChange={setOpen}><Button asChild variant=\\\"ghost\\\" size=\\\"sm\\\"><TooltipTrigger>{t(key('chartPoint'))}</TooltipTrigger></Button><TooltipContent side={side === 'right' ? 'left' : side === 'left' ? 'right' : side === 'bottom' ? 'top' : 'bottom'} variant=\\\"light\\\" className=\\\"h-16 w-39.5 rounded-lg p-3 shadow-lg\\\"><p className=\\\"text-xs leading-4 text-muted-foreground\\\">{new Intl.DateTimeFormat(locale,{weekday:'short',month:'short',day:'numeric',timeZone:'UTC'}).format(new Date('2026-01-08T00:00:00Z'))}</p><div className=\\\"mt-1 flex items-center gap-1.5\\\"><span className=\\\"text-lg font-medium leading-6\\\">{new Intl.NumberFormat(locale).format(3484)}</span><span className=\\\"text-xs text-status-success-icon\\\">+7.1%</span><span className=\\\"text-xs text-muted-foreground\\\">{t(key('versusPrevious'))}</span></div></TooltipContent></Tooltip></TooltipProvider></div>\\n}\\n\\nexport function MarketingControlDemo(props: ControlProps) {\\n if (['input','select','textarea','amount'].includes(props.kind)) return <UnderlineField {...props} />\\n if (props.kind === 'inline-input') return <InlineEditor state={props.state} />\\n if (props.kind === 'inline-select') return <InlineLanguage state={props.state} />\\n if (props.kind === 'step-item') return <StepItem state={props.state} />\\n if (props.kind === 'selected-button') return <SelectedAmount state={props.state} />\\n if (props.kind === 'tab-menu') return <MenuItem state={props.state} />\\n if (props.kind === 'chart-tooltip') return <ChartTooltipExample side={props.side} />\\n const product = marketingProducts[props.product ?? 0]\\n return <img data-slot=\\\"marketing-control\\\" data-kind=\\\"product-image\\\" src={product.src} alt={product.name} className=\\\"size-50 max-w-full object-contain\\\" />\\n}\\n\"\nexport const marketingControlExampleCode = (expression: string) => source + \"\\n\" + expression + \"\\n\"\n"],
|
|
5
|
+
"mappings": "AACA,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACR,MAAM,8BAA8B,CAAC,eAAuB,SAAS,OAAO,aAAa;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { CheckCircle2, ChevronRight, Info, Pencil, UserRound } from "lucide-react";
|
|
4
|
+
import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
|
|
5
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
8
|
+
import { InlineInput } from "@open-mercato/ui/primitives/inline-input";
|
|
9
|
+
import { InlineSelectTrigger } from "@open-mercato/ui/primitives/inline-select";
|
|
10
|
+
import { Label } from "@open-mercato/ui/primitives/label";
|
|
11
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@open-mercato/ui/primitives/select";
|
|
12
|
+
import { Textarea } from "@open-mercato/ui/primitives/textarea";
|
|
13
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@open-mercato/ui/primitives/tooltip";
|
|
14
|
+
import { marketingProducts } from "../assets/marketing-artwork.js";
|
|
15
|
+
const key = (name) => `design_system.gallery.samples.marketing.${name}`;
|
|
16
|
+
const focusStyle = "focus-within:border-accent-orange-border focus-within:shadow-none";
|
|
17
|
+
function UnderlineField({ kind, state = "default", size = "medium" }) {
|
|
18
|
+
const t = useT();
|
|
19
|
+
const id = React.useId();
|
|
20
|
+
const large = size === "large" || kind === "amount";
|
|
21
|
+
const label = t(key(kind === "textarea" ? "description" : kind === "amount" ? "productPricing" : kind === "select" ? "category" : "productName"));
|
|
22
|
+
const placeholder = t(key(kind === "textarea" ? "productDescriptionPlaceholder" : kind === "select" ? "categoryPlaceholder" : "productNamePlaceholder"));
|
|
23
|
+
const [value, setValue] = React.useState(state === "filled" ? kind === "select" ? "accessories" : kind === "amount" ? "800" : t(key(kind === "textarea" ? "productDescription" : "productNameExample")) : "");
|
|
24
|
+
const active = state === "active";
|
|
25
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "marketing-control", "data-kind": kind, className: cn("relative flex w-93 max-w-full flex-col gap-1.5 pb-3.5 after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-border focus-within:after:h-0.5 focus-within:after:bg-accent-orange-border", large ? "h-20" : "h-16", active && "after:h-0.5 after:bg-accent-orange-border"), children: [
|
|
26
|
+
/* @__PURE__ */ jsxs(Label, { htmlFor: id, className: "flex h-5 shrink-0 items-center gap-1 text-sm font-medium text-muted-foreground", children: [
|
|
27
|
+
label,
|
|
28
|
+
/* @__PURE__ */ jsx(Info, { "aria-hidden": "true", className: "size-3 text-text-disabled" })
|
|
29
|
+
] }),
|
|
30
|
+
kind === "select" ? /* @__PURE__ */ jsxs(Select, { value, onValueChange: setValue, children: [
|
|
31
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id, "aria-label": label, className: cn("h-6 rounded-none border-0 bg-transparent p-0 text-lg font-medium shadow-none hover:bg-transparent focus:border-0 focus:shadow-none", state === "hover" && "text-muted-foreground", active && "[&_svg]:text-accent-orange-text"), children: /* @__PURE__ */ jsx(SelectValue, { placeholder }) }),
|
|
32
|
+
/* @__PURE__ */ jsx(SelectContent, { children: ["accessories", "computers", "audio"].map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option, children: t(key(option)) }, option)) })
|
|
33
|
+
] }) : kind === "textarea" ? /* @__PURE__ */ jsx(Textarea, { id, "aria-label": label, rows: 1, value, onChange: (event) => setValue(event.target.value), placeholder, autoFocus: active, className: cn("h-6 min-h-6 resize-none rounded-none border-0 bg-transparent p-0 text-lg font-medium leading-6 shadow-none hover:bg-transparent focus-visible:shadow-none", state === "hover" && "placeholder:text-muted-foreground") }) : /* @__PURE__ */ jsx(Input, { id, "aria-label": label, value, onChange: (event) => setValue(event.target.value), type: kind === "amount" ? "number" : "text", min: kind === "amount" ? 0 : void 0, step: kind === "amount" ? "0.01" : void 0, autoFocus: active, placeholder: kind === "amount" ? "0.00" : placeholder, leading: kind === "amount" ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("text-title-4 font-medium", !value && !active && "text-text-disabled"), children: "$" }) : void 0, className: cn("rounded-none border-0 bg-transparent p-0 shadow-none hover:bg-transparent focus-within:shadow-none", large ? "h-10" : "h-6"), inputClassName: cn("font-medium placeholder:text-text-disabled", large ? "text-title-4 leading-10" : "text-lg leading-6", state === "hover" && "placeholder:text-muted-foreground") })
|
|
34
|
+
] });
|
|
35
|
+
}
|
|
36
|
+
function InlineEditor({ state = "placeholder" }) {
|
|
37
|
+
const t = useT();
|
|
38
|
+
const [value, setValue] = React.useState(state === "filled" ? "James Brown" : "");
|
|
39
|
+
const [draft, setDraft] = React.useState(value);
|
|
40
|
+
const [editing, setEditing] = React.useState(state === "focus");
|
|
41
|
+
const disabled = state === "disabled";
|
|
42
|
+
const save = () => {
|
|
43
|
+
setValue(draft.trim());
|
|
44
|
+
setEditing(false);
|
|
45
|
+
};
|
|
46
|
+
const cancel = () => {
|
|
47
|
+
setDraft(value);
|
|
48
|
+
setEditing(false);
|
|
49
|
+
};
|
|
50
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "marketing-control", "data-kind": "inline-input", className: "w-78 max-w-full", children: editing ? /* @__PURE__ */ jsx(InlineInput, { autoFocus: true, value: draft, onChange: (event) => setDraft(event.target.value), "aria-label": t(key("name")), placeholder: t(key("namePlaceholder")), className: cn("h-10 gap-2 rounded-lg border-accent-orange-border bg-background px-3", focusStyle), onKeyDown: (event) => {
|
|
51
|
+
if (event.key === "Escape") {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
cancel();
|
|
54
|
+
}
|
|
55
|
+
if (event.key === "Enter") {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
save();
|
|
58
|
+
}
|
|
59
|
+
}, trailing: /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
60
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", className: "h-5 p-0 text-sm font-normal", onClick: cancel, children: t(key("cancel")) }),
|
|
61
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", className: "h-5 p-0 text-sm font-normal text-accent-orange-text", onClick: save, children: t(key("save")) })
|
|
62
|
+
] }) }) : /* @__PURE__ */ jsxs(Button, { disabled, variant: "ghost", onClick: () => setEditing(true), className: cn("h-10 w-full justify-between rounded-lg px-3 text-sm font-normal", state === "hover" && "bg-muted", !value && "text-muted-foreground"), children: [
|
|
63
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: value || t(key("namePlaceholder")) }),
|
|
64
|
+
/* @__PURE__ */ jsx(Pencil, { "aria-hidden": "true", className: "size-4 shrink-0 text-text-disabled" })
|
|
65
|
+
] }) });
|
|
66
|
+
}
|
|
67
|
+
function InlineLanguage({ state = "placeholder" }) {
|
|
68
|
+
const t = useT();
|
|
69
|
+
const [value, setValue] = React.useState(state === "filled" ? "en" : "");
|
|
70
|
+
const [open, setOpen] = React.useState(false);
|
|
71
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "marketing-control", "data-kind": "inline-select", className: "w-64 max-w-full", children: /* @__PURE__ */ jsxs(Select, { value, onValueChange: setValue, open, onOpenChange: setOpen, disabled: state === "disabled", children: [
|
|
72
|
+
/* @__PURE__ */ jsx(InlineSelectTrigger, { "aria-label": t(key("language")), className: cn("h-10 rounded-lg px-3 focus:border-accent-orange-border focus:shadow-none", state === "hover" && "bg-muted", state === "focus" && "border-accent-orange-border"), children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t(key("languagePlaceholder")) }) }),
|
|
73
|
+
/* @__PURE__ */ jsx(SelectContent, { children: ["en", "pl", "de", "es", "ko"].map((language) => /* @__PURE__ */ jsx(SelectItem, { value: language, children: t(key(`language${language}`)) }, language)) })
|
|
74
|
+
] }) });
|
|
75
|
+
}
|
|
76
|
+
function StepItem({ state = "default" }) {
|
|
77
|
+
const t = useT();
|
|
78
|
+
const [selected, setSelected] = React.useState(state === "active");
|
|
79
|
+
return /* @__PURE__ */ jsxs(Button, { "data-slot": "marketing-control", "data-kind": "step-item", variant: "ghost", "aria-pressed": selected, onClick: () => setSelected((current) => !current), className: cn("h-11 w-45 max-w-full flex-col items-start justify-start gap-1 rounded-none border-r-2 border-transparent p-0 pr-6 text-sm font-normal hover:bg-transparent", selected && "border-r-accent-orange"), children: [
|
|
80
|
+
/* @__PURE__ */ jsxs("span", { className: cn("flex h-5 items-center gap-1", selected ? "text-accent-orange-text" : "text-muted-foreground"), children: [
|
|
81
|
+
t(key("step"), void 0, { current: 1, total: 5 }),
|
|
82
|
+
state === "complete" ? /* @__PURE__ */ jsx(CheckCircle2, { "aria-hidden": "true", className: "size-3.5 fill-status-success-icon text-status-success-foreground" }) : null
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ jsx("span", { className: "h-5", children: t(key("generalInformation")) })
|
|
85
|
+
] });
|
|
86
|
+
}
|
|
87
|
+
function SelectedAmount({ state = "default" }) {
|
|
88
|
+
const locale = useLocale();
|
|
89
|
+
const [selected, setSelected] = React.useState(state === "selected");
|
|
90
|
+
return /* @__PURE__ */ jsxs(Button, { "data-slot": "marketing-control", "data-kind": "selected-button", "aria-pressed": selected, disabled: state === "disabled", variant: selected ? "default" : "outline", onClick: () => setSelected((current) => !current), className: cn("h-7 gap-1.5 rounded-md border border-border px-2.5 py-1 font-normal", state === "hover" && "bg-muted", selected && "border-transparent bg-accent-orange/10 text-accent-orange-text hover:bg-accent-orange/20"), children: [
|
|
91
|
+
selected ? /* @__PURE__ */ jsx(CheckCircle2, { "aria-hidden": "true", className: "size-3.5" }) : null,
|
|
92
|
+
new Intl.NumberFormat(locale).format(800)
|
|
93
|
+
] });
|
|
94
|
+
}
|
|
95
|
+
function MenuItem({ state = "default" }) {
|
|
96
|
+
const t = useT();
|
|
97
|
+
const [selected, setSelected] = React.useState(state === "active");
|
|
98
|
+
return /* @__PURE__ */ jsxs(Button, { "data-slot": "marketing-control", "data-kind": "tab-menu", variant: "ghost", "aria-pressed": selected, onClick: () => setSelected((current) => !current), className: cn("h-9 w-56 max-w-full justify-start gap-2 rounded-lg p-2 text-sm font-medium", (state === "hover" || selected) && "bg-muted"), children: [
|
|
99
|
+
/* @__PURE__ */ jsx(UserRound, { "aria-hidden": "true", className: cn("size-5", selected ? "text-accent-orange-text" : "text-muted-foreground") }),
|
|
100
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: t(key("accountSettings")) }),
|
|
101
|
+
/* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 text-muted-foreground" })
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
function ChartTooltipExample({ side = "right" }) {
|
|
105
|
+
const t = useT();
|
|
106
|
+
const locale = useLocale();
|
|
107
|
+
const [open, setOpen] = React.useState(true);
|
|
108
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "marketing-control", "data-kind": "chart-tooltip", className: "flex h-40 w-80 max-w-full items-center justify-center", children: /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs(Tooltip, { open, onOpenChange: setOpen, children: [
|
|
109
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: /* @__PURE__ */ jsx(TooltipTrigger, { children: t(key("chartPoint")) }) }),
|
|
110
|
+
/* @__PURE__ */ jsxs(TooltipContent, { side: side === "right" ? "left" : side === "left" ? "right" : side === "bottom" ? "top" : "bottom", variant: "light", className: "h-16 w-39.5 rounded-lg p-3 shadow-lg", children: [
|
|
111
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs leading-4 text-muted-foreground", children: new Intl.DateTimeFormat(locale, { weekday: "short", month: "short", day: "numeric", timeZone: "UTC" }).format(/* @__PURE__ */ new Date("2026-01-08T00:00:00Z")) }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("span", { className: "text-lg font-medium leading-6", children: new Intl.NumberFormat(locale).format(3484) }),
|
|
114
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-status-success-icon", children: "+7.1%" }),
|
|
115
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(key("versusPrevious")) })
|
|
116
|
+
] })
|
|
117
|
+
] })
|
|
118
|
+
] }) }) });
|
|
119
|
+
}
|
|
120
|
+
function MarketingControlDemo(props) {
|
|
121
|
+
if (["input", "select", "textarea", "amount"].includes(props.kind)) return /* @__PURE__ */ jsx(UnderlineField, { ...props });
|
|
122
|
+
if (props.kind === "inline-input") return /* @__PURE__ */ jsx(InlineEditor, { state: props.state });
|
|
123
|
+
if (props.kind === "inline-select") return /* @__PURE__ */ jsx(InlineLanguage, { state: props.state });
|
|
124
|
+
if (props.kind === "step-item") return /* @__PURE__ */ jsx(StepItem, { state: props.state });
|
|
125
|
+
if (props.kind === "selected-button") return /* @__PURE__ */ jsx(SelectedAmount, { state: props.state });
|
|
126
|
+
if (props.kind === "tab-menu") return /* @__PURE__ */ jsx(MenuItem, { state: props.state });
|
|
127
|
+
if (props.kind === "chart-tooltip") return /* @__PURE__ */ jsx(ChartTooltipExample, { side: props.side });
|
|
128
|
+
const product = marketingProducts[props.product ?? 0];
|
|
129
|
+
return /* @__PURE__ */ jsx("img", { "data-slot": "marketing-control", "data-kind": "product-image", src: product.src, alt: product.name, className: "size-50 max-w-full object-contain" });
|
|
130
|
+
}
|
|
131
|
+
export {
|
|
132
|
+
MarketingControlDemo
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=marketing-controls.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/design_system/gallery/demos/marketing-controls.tsx"],
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport { CheckCircle2, ChevronRight, Info, Pencil, UserRound } from 'lucide-react'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { InlineInput } from '@open-mercato/ui/primitives/inline-input'\nimport { InlineSelectTrigger } from '@open-mercato/ui/primitives/inline-select'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@open-mercato/ui/primitives/tooltip'\nimport { marketingProducts } from '../assets/marketing-artwork'\n\nexport type MarketingControlState = 'default' | 'hover' | 'active' | 'filled' | 'placeholder' | 'focus' | 'disabled' | 'complete' | 'selected'\nexport type MarketingControlKind = 'step-item' | 'select' | 'input' | 'textarea' | 'amount' | 'tab-menu' | 'inline-input' | 'inline-select' | 'chart-tooltip' | 'selected-button' | 'product-image'\ntype ControlProps = { kind: MarketingControlKind; state?: MarketingControlState; size?: 'medium' | 'large'; side?: 'right' | 'left' | 'bottom' | 'top'; product?: number }\nconst key = (name: string) => `design_system.gallery.samples.marketing.${name}`\nconst focusStyle = 'focus-within:border-accent-orange-border focus-within:shadow-none'\n\nfunction UnderlineField({ kind, state = 'default', size = 'medium' }: ControlProps) {\n const t = useT()\n const id = React.useId()\n const large = size === 'large' || kind === 'amount'\n const label = t(key(kind === 'textarea' ? 'description' : kind === 'amount' ? 'productPricing' : kind === 'select' ? 'category' : 'productName'))\n const placeholder = t(key(kind === 'textarea' ? 'productDescriptionPlaceholder' : kind === 'select' ? 'categoryPlaceholder' : 'productNamePlaceholder'))\n const [value, setValue] = React.useState(state === 'filled' ? kind === 'select' ? 'accessories' : kind === 'amount' ? '800' : t(key(kind === 'textarea' ? 'productDescription' : 'productNameExample')) : '')\n const active = state === 'active'\n return <div data-slot=\"marketing-control\" data-kind={kind} className={cn('relative flex w-93 max-w-full flex-col gap-1.5 pb-3.5 after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-border focus-within:after:h-0.5 focus-within:after:bg-accent-orange-border', large ? 'h-20' : 'h-16', active && 'after:h-0.5 after:bg-accent-orange-border')}>\n <Label htmlFor={id} className=\"flex h-5 shrink-0 items-center gap-1 text-sm font-medium text-muted-foreground\">{label}<Info aria-hidden=\"true\" className=\"size-3 text-text-disabled\" /></Label>\n {kind === 'select' ? <Select value={value} onValueChange={setValue}><SelectTrigger id={id} aria-label={label} className={cn('h-6 rounded-none border-0 bg-transparent p-0 text-lg font-medium shadow-none hover:bg-transparent focus:border-0 focus:shadow-none', state === 'hover' && 'text-muted-foreground', active && '[&_svg]:text-accent-orange-text')}><SelectValue placeholder={placeholder} /></SelectTrigger><SelectContent>{['accessories','computers','audio'].map(option => <SelectItem key={option} value={option}>{t(key(option))}</SelectItem>)}</SelectContent></Select> : kind === 'textarea' ? <Textarea id={id} aria-label={label} rows={1} value={value} onChange={event => setValue(event.target.value)} placeholder={placeholder} autoFocus={active} className={cn('h-6 min-h-6 resize-none rounded-none border-0 bg-transparent p-0 text-lg font-medium leading-6 shadow-none hover:bg-transparent focus-visible:shadow-none', state === 'hover' && 'placeholder:text-muted-foreground')} /> : <Input id={id} aria-label={label} value={value} onChange={event => setValue(event.target.value)} type={kind === 'amount' ? 'number' : 'text'} min={kind === 'amount' ? 0 : undefined} step={kind === 'amount' ? '0.01' : undefined} autoFocus={active} placeholder={kind === 'amount' ? '0.00' : placeholder} leading={kind === 'amount' ? <span aria-hidden=\"true\" className={cn('text-title-4 font-medium', !value && !active && 'text-text-disabled')}>$</span> : undefined} className={cn('rounded-none border-0 bg-transparent p-0 shadow-none hover:bg-transparent focus-within:shadow-none', large ? 'h-10' : 'h-6')} inputClassName={cn('font-medium placeholder:text-text-disabled', large ? 'text-title-4 leading-10' : 'text-lg leading-6', state === 'hover' && 'placeholder:text-muted-foreground')} />}\n </div>\n}\n\nfunction InlineEditor({ state = 'placeholder' }: { state?: MarketingControlState }) {\n const t = useT()\n const [value, setValue] = React.useState(state === 'filled' ? 'James Brown' : '')\n const [draft, setDraft] = React.useState(value)\n const [editing, setEditing] = React.useState(state === 'focus')\n const disabled = state === 'disabled'\n const save = () => { setValue(draft.trim()); setEditing(false) }\n const cancel = () => { setDraft(value); setEditing(false) }\n return <div data-slot=\"marketing-control\" data-kind=\"inline-input\" className=\"w-78 max-w-full\">\n {editing ? <InlineInput autoFocus value={draft} onChange={event => setDraft(event.target.value)} aria-label={t(key('name'))} placeholder={t(key('namePlaceholder'))} className={cn('h-10 gap-2 rounded-lg border-accent-orange-border bg-background px-3', focusStyle)} onKeyDown={event => { if (event.key === 'Escape') { event.preventDefault(); cancel() } if (event.key === 'Enter') { event.preventDefault(); save() } }} trailing={<div className=\"flex gap-2\"><Button variant=\"ghost\" className=\"h-5 p-0 text-sm font-normal\" onClick={cancel}>{t(key('cancel'))}</Button><Button variant=\"ghost\" className=\"h-5 p-0 text-sm font-normal text-accent-orange-text\" onClick={save}>{t(key('save'))}</Button></div>} /> : <Button disabled={disabled} variant=\"ghost\" onClick={() => setEditing(true)} className={cn('h-10 w-full justify-between rounded-lg px-3 text-sm font-normal', state === 'hover' && 'bg-muted', !value && 'text-muted-foreground')}><span className=\"truncate\">{value || t(key('namePlaceholder'))}</span><Pencil aria-hidden=\"true\" className=\"size-4 shrink-0 text-text-disabled\" /></Button>}\n </div>\n}\n\nfunction InlineLanguage({ state = 'placeholder' }: { state?: MarketingControlState }) {\n const t = useT()\n const [value, setValue] = React.useState(state === 'filled' ? 'en' : '')\n const [open, setOpen] = React.useState(false)\n return <div data-slot=\"marketing-control\" data-kind=\"inline-select\" className=\"w-64 max-w-full\"><Select value={value} onValueChange={setValue} open={open} onOpenChange={setOpen} disabled={state === 'disabled'}><InlineSelectTrigger aria-label={t(key('language'))} className={cn('h-10 rounded-lg px-3 focus:border-accent-orange-border focus:shadow-none', state === 'hover' && 'bg-muted', state === 'focus' && 'border-accent-orange-border')}><SelectValue placeholder={t(key('languagePlaceholder'))} /></InlineSelectTrigger><SelectContent>{['en','pl','de','es','ko'].map(language => <SelectItem key={language} value={language}>{t(key(`language${language}`))}</SelectItem>)}</SelectContent></Select></div>\n}\n\nfunction StepItem({ state = 'default' }: { state?: MarketingControlState }) {\n const t = useT()\n const [selected, setSelected] = React.useState(state === 'active')\n return <Button data-slot=\"marketing-control\" data-kind=\"step-item\" variant=\"ghost\" aria-pressed={selected} onClick={() => setSelected(current => !current)} className={cn('h-11 w-45 max-w-full flex-col items-start justify-start gap-1 rounded-none border-r-2 border-transparent p-0 pr-6 text-sm font-normal hover:bg-transparent', selected && 'border-r-accent-orange')}><span className={cn('flex h-5 items-center gap-1', selected ? 'text-accent-orange-text' : 'text-muted-foreground')}>{t(key('step'), undefined, { current: 1, total: 5 })}{state === 'complete' ? <CheckCircle2 aria-hidden=\"true\" className=\"size-3.5 fill-status-success-icon text-status-success-foreground\" /> : null}</span><span className=\"h-5\">{t(key('generalInformation'))}</span></Button>\n}\n\nfunction SelectedAmount({ state = 'default' }: { state?: MarketingControlState }) {\n const locale = useLocale()\n const [selected,setSelected] = React.useState(state === 'selected')\n return <Button data-slot=\"marketing-control\" data-kind=\"selected-button\" aria-pressed={selected} disabled={state === 'disabled'} variant={selected ? 'default' : 'outline'} onClick={() => setSelected(current => !current)} className={cn('h-7 gap-1.5 rounded-md border border-border px-2.5 py-1 font-normal', state === 'hover' && 'bg-muted', selected && 'border-transparent bg-accent-orange/10 text-accent-orange-text hover:bg-accent-orange/20')}>\n {selected ? <CheckCircle2 aria-hidden=\"true\" className=\"size-3.5\" /> : null}{new Intl.NumberFormat(locale).format(800)}\n </Button>\n}\n\nfunction MenuItem({ state = 'default' }: { state?: MarketingControlState }) {\n const t = useT()\n const [selected,setSelected] = React.useState(state === 'active')\n return <Button data-slot=\"marketing-control\" data-kind=\"tab-menu\" variant=\"ghost\" aria-pressed={selected} onClick={() => setSelected(current => !current)} className={cn('h-9 w-56 max-w-full justify-start gap-2 rounded-lg p-2 text-sm font-medium', (state === 'hover' || selected) && 'bg-muted')}><UserRound aria-hidden=\"true\" className={cn('size-5', selected ? 'text-accent-orange-text' : 'text-muted-foreground')} /><span className=\"flex-1 text-left\">{t(key('accountSettings'))}</span><ChevronRight aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" /></Button>\n}\n\nfunction ChartTooltipExample({ side = 'right' }: { side?: 'right' | 'left' | 'bottom' | 'top' }) {\n const t = useT()\n const locale = useLocale()\n const [open,setOpen] = React.useState(true)\n return <div data-slot=\"marketing-control\" data-kind=\"chart-tooltip\" className=\"flex h-40 w-80 max-w-full items-center justify-center\"><TooltipProvider delayDuration={0}><Tooltip open={open} onOpenChange={setOpen}><Button asChild variant=\"ghost\" size=\"sm\"><TooltipTrigger>{t(key('chartPoint'))}</TooltipTrigger></Button><TooltipContent side={side === 'right' ? 'left' : side === 'left' ? 'right' : side === 'bottom' ? 'top' : 'bottom'} variant=\"light\" className=\"h-16 w-39.5 rounded-lg p-3 shadow-lg\"><p className=\"text-xs leading-4 text-muted-foreground\">{new Intl.DateTimeFormat(locale,{weekday:'short',month:'short',day:'numeric',timeZone:'UTC'}).format(new Date('2026-01-08T00:00:00Z'))}</p><div className=\"mt-1 flex items-center gap-1.5\"><span className=\"text-lg font-medium leading-6\">{new Intl.NumberFormat(locale).format(3484)}</span><span className=\"text-xs text-status-success-icon\">+7.1%</span><span className=\"text-xs text-muted-foreground\">{t(key('versusPrevious'))}</span></div></TooltipContent></Tooltip></TooltipProvider></div>\n}\n\nexport function MarketingControlDemo(props: ControlProps) {\n if (['input','select','textarea','amount'].includes(props.kind)) return <UnderlineField {...props} />\n if (props.kind === 'inline-input') return <InlineEditor state={props.state} />\n if (props.kind === 'inline-select') return <InlineLanguage state={props.state} />\n if (props.kind === 'step-item') return <StepItem state={props.state} />\n if (props.kind === 'selected-button') return <SelectedAmount state={props.state} />\n if (props.kind === 'tab-menu') return <MenuItem state={props.state} />\n if (props.kind === 'chart-tooltip') return <ChartTooltipExample side={props.side} />\n const product = marketingProducts[props.product ?? 0]\n return <img data-slot=\"marketing-control\" data-kind=\"product-image\" src={product.src} alt={product.name} className=\"size-50 max-w-full object-contain\" />\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
const source = `import * as React from 'react'
|
|
2
|
+
import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, Line, LineChart, Pie, PieChart, PolarAngleAxis, PolarGrid, Radar, RadarChart, ReferenceLine, ResponsiveContainer, Tooltip, XAxis } from 'recharts'
|
|
3
|
+
import { ArrowDownLeft, ArrowUp, ArrowUpRight, CheckCircle2, ChevronLeft, ChevronRight, Clock3, Code, Info, Minus, Plus, Store, Target, UserRound } from 'lucide-react'
|
|
4
|
+
import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
|
|
5
|
+
import { cn } from '@open-mercato/shared/lib/utils'
|
|
6
|
+
import { ChartContainer, ChartTooltipContent } from '@open-mercato/ui/backend/charts'
|
|
7
|
+
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
8
|
+
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
9
|
+
import { Button } from '@open-mercato/ui/primitives/button'
|
|
10
|
+
import { Card } from '@open-mercato/ui/primitives/card'
|
|
11
|
+
import { CompactButton } from '@open-mercato/ui/primitives/compact-button'
|
|
12
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@open-mercato/ui/primitives/dialog'
|
|
13
|
+
import { ScrollArea } from '@open-mercato/ui/primitives/scroll-area'
|
|
14
|
+
import { SearchInput } from '@open-mercato/ui/primitives/search-input'
|
|
15
|
+
import { SegmentedControl, SegmentedControlItem } from '@open-mercato/ui/primitives/segmented-control'
|
|
16
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'
|
|
17
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
|
|
18
|
+
import { marketingBrands, marketingProducts, marketingWorldMap, marketingActivityIcons } from '../assets/marketing-artwork'
|
|
19
|
+
|
|
20
|
+
export type MarketingWidgetKind = 'total-sales' | 'total-visitors' | 'conversion-rate' | 'user-retention' | 'weekly-visitors' | 'visitor-channels' | 'geography' | 'realtime-visitors' | 'marketing-channels' | 'product-performance' | 'shipping-tracking' | 'my-products' | 'product-categories' | 'customer-segments' | 'sales-channels' | 'campaign-data' | 'support-analytics' | 'recent-activities'
|
|
21
|
+
const key = (name: string) => \`design_system.gallery.samples.marketing.\${name}\`
|
|
22
|
+
const chartColor = 'var(--chart-orange)'
|
|
23
|
+
const palette = ['var(--chart-orange)','var(--chart-amber)','var(--chart-teal)','var(--chart-cyan)','var(--chart-violet)','var(--chart-indigo)']
|
|
24
|
+
function useMarketing() {
|
|
25
|
+
const t = useT()
|
|
26
|
+
const locale = useLocale()
|
|
27
|
+
const number = (value: number, digits = 0) => new Intl.NumberFormat(locale,{maximumFractionDigits:digits,minimumFractionDigits:digits}).format(value)
|
|
28
|
+
const money = (value: number) => new Intl.NumberFormat(locale,{style:'currency',currency:'USD',maximumFractionDigits:value % 1 ? 2 : 0}).format(value)
|
|
29
|
+
const date = (value: string, options: Intl.DateTimeFormatOptions = {month:'short',day:'numeric',year:'numeric'}) => new Intl.DateTimeFormat(locale,{...options,timeZone:'UTC'}).format(new Date(value))
|
|
30
|
+
return { t, locale, number, money, date }
|
|
31
|
+
}
|
|
32
|
+
function Trend({ value, badge = false, previous = false }: { value: number; badge?: boolean; previous?: boolean }) {
|
|
33
|
+
const { t, number } = useMarketing()
|
|
34
|
+
const label = \`\${value > 0 ? '+' : ''}\${number(value,1)}%\`
|
|
35
|
+
return <span className="inline-flex items-center gap-1 whitespace-nowrap text-sm">{badge ? <Badge appearance="light" tone={value < 0 ? 'error' : 'success'} size={20}>{label}</Badge> : <span className={value < 0 ? 'text-status-error-icon' : 'text-status-success-icon'}>{label}</span>}{previous ? <span className="text-muted-foreground">{t(key('versusWeek'))}</span> : null}</span>
|
|
36
|
+
}
|
|
37
|
+
function MarketingFrame({ children, compact = false, tall = false, flush = false, className }: { children: React.ReactNode; compact?: boolean; tall?: boolean; flush?: boolean; className?: string }) {
|
|
38
|
+
return <Card data-slot="marketing-widget" className={cn('relative w-88 max-w-full overflow-hidden rounded-xl border-0 bg-background ring-1 ring-inset ring-border shadow-xs',tall ? 'h-196' : compact ? 'h-44.5' : 'h-95',flush ? 'gap-0 p-0' : 'gap-5 p-5',className)}>{children}</Card>
|
|
39
|
+
}
|
|
40
|
+
function Header({ title, value, action, children, info = false, className }: { title: string; value?: React.ReactNode; action?: React.ReactNode; children?: React.ReactNode; info?: boolean; className?: string }) {
|
|
41
|
+
return <div className={cn('flex h-14 shrink-0 items-start gap-2',className)}><div className="min-w-0 flex-1"><h3 className="flex items-center gap-1 text-sm font-medium leading-5 text-muted-foreground">{title}{info ? <Info aria-hidden="true" className="size-3 shrink-0 text-text-disabled" /> : null}</h3><div className="mt-1 flex items-center gap-2"><span className="whitespace-nowrap text-2xl font-medium leading-8 tracking-tight">{value}</span>{children}</div></div>{action}</div>
|
|
42
|
+
}
|
|
43
|
+
function Details({ title, children, label, className }: { title: string; children: React.ReactNode; label?: string; className?: string }) {
|
|
44
|
+
const {t} = useMarketing()
|
|
45
|
+
const [open,setOpen] = React.useState(false)
|
|
46
|
+
return <Dialog open={open} onOpenChange={setOpen}><Button asChild variant="outline" className={cn('h-7 shrink-0 rounded-lg px-2.5 text-sm font-normal',className)}><DialogTrigger>{label ?? t(key('details'))}</DialogTrigger></Button><DialogContent onKeyDownCapture={event=>{if(event.key==='Enter'&&(event.ctrlKey||event.metaKey)){event.preventDefault();setOpen(false)}}}><DialogHeader><DialogTitle>{title}</DialogTitle><DialogDescription>{t(key('localData'))}</DialogDescription></DialogHeader><ScrollArea className="max-h-96" scrollbarSize="sm">{children}</ScrollArea><DialogFooter><Button variant="outline" onClick={()=>setOpen(false)}>{t(key('close'))}</Button></DialogFooter></DialogContent></Dialog>
|
|
47
|
+
}
|
|
48
|
+
function Period({ value, onChange, compact = false }: { value: string; onChange: (value: string)=>void; compact?: boolean }) {
|
|
49
|
+
const {t}=useMarketing()
|
|
50
|
+
return compact ? <Select value={value} onValueChange={onChange}><SelectTrigger aria-label={t(key('period'))} className="h-7 w-auto gap-2 rounded-lg px-2.5 text-sm"><SelectValue /></SelectTrigger><SelectContent>{['weekly','monthly','yearly'].map(option=><SelectItem key={option} value={option}>{t(key(option))}</SelectItem>)}</SelectContent></Select> : <SegmentedControl value={value} onValueChange={onChange} aria-label={t(key('period'))} className="h-6 w-full shrink-0 rounded-sm bg-background p-0">{['1d','1w','1m','3m','1y'].map(option=><SegmentedControlItem key={option} value={option} className="h-6 flex-1 rounded-none border-r border-border p-0 text-xs last:border-0 data-[state=checked]:bg-muted data-[state=checked]:font-medium data-[state=checked]:shadow-none">{t(key(\`period\${option}\`))}</SegmentedControlItem>)}</SegmentedControl>
|
|
51
|
+
}
|
|
52
|
+
function Choices({ values, value, onChange, label }: { values: string[]; value: string; onChange: (value:string)=>void; label: string }) {
|
|
53
|
+
const {t}=useMarketing()
|
|
54
|
+
return <SegmentedControl value={value} onValueChange={onChange} aria-label={label} className="h-7 max-w-full gap-2 rounded-none border-0 bg-transparent p-0">{values.map(option=><SegmentedControlItem key={option} value={option} className="h-7 rounded-lg bg-muted px-2.5 text-sm font-normal data-[state=checked]:bg-accent-orange/10 data-[state=checked]:font-normal data-[state=checked]:text-accent-orange-text data-[state=checked]:shadow-none data-[state=unchecked]:bg-muted">{t(key(option))}</SegmentedControlItem>)}</SegmentedControl>
|
|
55
|
+
}
|
|
56
|
+
function DataList({ rows }: { rows: { label: string; value: React.ReactNode; detail?: React.ReactNode; icon?: React.ReactNode }[] }) {
|
|
57
|
+
return <div className="flex flex-col gap-4">{rows.map(row=><div key={row.label} className="flex min-h-5 items-center gap-2 text-sm text-muted-foreground">{row.icon}<span className="min-w-0 flex-1">{row.label}</span><span>{row.value}</span>{row.detail ? <span className="ml-3 flex w-18 items-center justify-end gap-1">{row.detail}</span> : null}</div>)}</div>
|
|
58
|
+
}
|
|
59
|
+
const salesSeries = [28,14,33,11,57,26,57,7,42,39,24,44,31,36,15,25,13,21,41,46,15,30,24,44,18]
|
|
60
|
+
function TotalSales() {
|
|
61
|
+
const {t,money}=useMarketing()
|
|
62
|
+
const [period,setPeriod]=React.useState('1w')
|
|
63
|
+
const factor = {'1d':0.4,'1w':1,'1m':2,'3m':3,'1y':7}[period] ?? 1
|
|
64
|
+
const rows=[{label:t(key('onlineStore')),value:money(52.12*factor),icon:<Store aria-hidden="true" className="size-5" />,delta:4.5},{label:'Facebook',value:money(38.45*factor),icon:<img src={marketingBrands.facebook} alt="" className="size-5" />,delta:-2.8},{label:'Instagram',value:money(37.75*factor),icon:<img src={marketingBrands.instagram} alt="" className="size-5" />,delta:3.2}].map(row=>({...row,detail:<><ArrowUp aria-hidden="true" className={cn('size-4',row.delta < 0 ? 'rotate-180 text-status-error-icon':'text-status-success-icon')} />{row.delta>0?'+':''}{row.delta}%</>}))
|
|
65
|
+
return <MarketingFrame><Header title={t(key('totalSales'))} value={money(128.32*factor)} action={<Details title={t(key('totalSales'))} label={t(key('report'))}><DataList rows={rows} /></Details>}><Trend value={2} badge /></Header><Period value={period} onChange={setPeriod}/><ChartContainer config={{value:{label:t(key('sales')),color:chartColor}}} className="h-27 min-h-0 w-full shrink-0" aria-label={t(key('totalSales'))}><ResponsiveContainer width="100%" height="100%"><LineChart data={salesSeries.map((value,index)=>({index,value:value*factor}))} margin={{top:0,right:0,bottom:0,left:0}}><CartesianGrid stroke="var(--border)" strokeDasharray="3 3"/><Tooltip content={<ChartTooltipContent/>}/><Line dataKey="value" type="linear" stroke={chartColor} strokeWidth={1.5} dot={false} isAnimationActive={false}/></LineChart></ResponsiveContainer></ChartContainer><DataList rows={rows}/></MarketingFrame>
|
|
66
|
+
}
|
|
67
|
+
function TotalVisitors() {
|
|
68
|
+
const {t,number}=useMarketing()
|
|
69
|
+
const values=[{key:'desktop',value:27,delta:-3.2,color:'bg-chart-amber'},{key:'tablet',value:12,delta:-6.4,color:'bg-chart-cyan'},{key:'mobile',value:61,delta:0.8,color:'bg-chart-violet'}]
|
|
70
|
+
return <MarketingFrame><Header title={t(key('totalVisitors'))} value={number(237456)}><Trend value={-1.4} badge/></Header><div className="flex min-h-0 flex-1 border-t border-border pt-5">{values.map(item=><div key={item.key} className="flex min-w-0 flex-1 flex-col border-r border-dashed border-border px-4 first:pl-0 last:border-0 last:pr-0"><p className="text-sm text-muted-foreground">{t(key(item.key))}</p><p className="mt-1 text-xl font-medium">{item.value}%</p><span className="mt-auto flex items-center gap-1 text-sm text-muted-foreground">{item.delta>0?'+':''}{number(item.delta,1)}%{item.delta<0?<ArrowDownLeft aria-hidden="true" className="size-3 text-status-error-icon"/>:<ArrowUpRight aria-hidden="true" className="size-3 text-status-success-icon"/>}</span><span className={cn('mt-4 h-2 w-full rounded-sm',item.color)}/></div>)}</div></MarketingFrame>
|
|
71
|
+
}
|
|
72
|
+
function ConversionRate() {
|
|
73
|
+
const {t,number}=useMarketing()
|
|
74
|
+
const rows=[['addedToCart',3842,1.8],['reachedCheckout',1256,-1.2],['purchased',649,2.4]] as const
|
|
75
|
+
const list=<DataList rows={rows.map(([label,value,delta])=>({label:t(key(label)),value:number(value),detail:<Trend value={delta}/>}))}/>
|
|
76
|
+
const series=[12,9,6,12,3,8,7,6,23,19,28,3,14,4].map((value,index)=>({month:index,value,previous:value+8+(index%3)*5}))
|
|
77
|
+
return <MarketingFrame><Header title={t(key('conversionRate'))} value={\`\${number(16.9,1)}%\`} action={<Details title={t(key('conversionRate'))}>{list}</Details>}><Trend value={2.1} badge/></Header><div className="border-t border-border pt-5">{list}</div><ChartContainer config={{value:{label:t(key('purchased')),color:chartColor},previous:{label:t(key('previousPeriod')),color:'var(--chart-orange)'}}} className="min-h-0 flex-1" aria-label={t(key('conversionRate'))}><ResponsiveContainer width="100%" height="100%"><AreaChart data={series} margin={{top:0,right:0,left:0,bottom:0}}><CartesianGrid stroke="var(--border)"/><Tooltip content={<ChartTooltipContent/>}/><Area dataKey="previous" stroke="none" fill={chartColor} fillOpacity={0.18} isAnimationActive={false}/><Area dataKey="value" stroke="none" fill={chartColor} fillOpacity={1} isAnimationActive={false}/></AreaChart></ResponsiveContainer></ChartContainer><div className="-mt-3 flex justify-between text-overline text-muted-foreground">{['feb','mar','apr','may','jun','jul'].map(month=><span key={month}>{t(key(month))}</span>)}</div></MarketingFrame>
|
|
78
|
+
}
|
|
79
|
+
function Retention() {
|
|
80
|
+
const {t,number}=useMarketing()
|
|
81
|
+
const [selected,setSelected]=React.useState<[number,number]|null>(null)
|
|
82
|
+
const cells=Array.from({length:12},(_,row)=>Array.from({length:12-row},(_,column)=>({row,column,value:Math.max(8,100-row*6-column*4+(row*column%5)*5)}))).flat()
|
|
83
|
+
return <MarketingFrame><Header title={t(key('retention'))} value="24%" action={<Details title={t(key('retention'))}><DataList rows={cells.filter(cell=>cell.column===0).map(cell=>({label:t(key('month'),undefined,{month:cell.row+1}),value:\`\${cell.value}%\`}))}/></Details>}><Trend value={2} badge/></Header><div className="grid h-48 shrink-0 grid-cols-12 grid-rows-12 gap-0.5" role="group" aria-label={t(key('retentionCohorts'))}>{cells.map(cell=><button key={\`\${cell.row}-\${cell.column}\`} type="button" aria-label={t(key('cohortCell'),undefined,{cohort:cell.row+1,month:cell.column+1,value:cell.value})} aria-pressed={selected?.[0]===cell.row&&selected?.[1]===cell.column} className="min-h-0 min-w-0 bg-chart-orange outline-none focus-visible:ring-2 focus-visible:ring-foreground focus-visible:ring-offset-1" style={{gridRow:cell.row+1,gridColumn:cell.column+1,opacity:cell.value/100}} onClick={()=>setSelected([cell.row,cell.column])}/>)}</div><div className="-mt-3 grid grid-cols-12 text-center text-overline text-muted-foreground">{Array.from({length:12},(_,index)=><span key={index}>{index+1}</span>)}</div><p aria-live="polite" className="mt-auto flex h-7 items-center gap-2 rounded-lg border border-border px-2 text-xs text-muted-foreground"><Info aria-hidden="true" className="size-3 shrink-0"/><span className="truncate">{selected?t(key('cohortCell'),undefined,{cohort:selected[0]+1,month:selected[1]+1,value:number(cells.find(cell=>cell.row===selected[0]&&cell.column===selected[1])?.value??0)}):t(key('retentionUpdated'))}</span></p></MarketingFrame>
|
|
84
|
+
}
|
|
85
|
+
function WeeklyVisitors() {
|
|
86
|
+
const {t,number}=useMarketing()
|
|
87
|
+
const values=['happiness','sadness','anger','fear','surprise','disgust','love','excitement']
|
|
88
|
+
const [series,setSeries]=React.useState({fresh:true,returning:true})
|
|
89
|
+
return <MarketingFrame className="gap-4"><Header title={t(key('weeklyVisitors'))} value={number(16008)}><Trend value={1.1} badge/></Header><div className="flex h-7 shrink-0 rounded-lg border border-border">{(['fresh','returning'] as const).map((item,index)=><Button key={item} variant="ghost" aria-pressed={series[item]} onClick={()=>setSeries(current=>({...current,[item]:!current[item]}))} className="h-7 min-w-0 flex-1 gap-2 p-0 text-xs font-normal"><span className={cn('size-2 rounded-full',index?'bg-chart-emerald':'bg-chart-orange',!series[item]&&'opacity-30')}/>{t(key(item==='fresh'?'newVisitors':'returningVisitors'))}</Button>)}</div><ChartContainer config={{fresh:{label:t(key('newVisitors')),color:chartColor},returning:{label:t(key('returningVisitors')),color:'var(--chart-emerald)'}}} className="min-h-0 flex-1" aria-label={t(key('weeklyVisitors'))}><ResponsiveContainer width="100%" height="100%"><RadarChart data={values.map((label,index)=>({label:t(key(label)),fresh:[76,39,84,72,40,70,74,32][index],returning:[43,75,39,40,0,54,39,75][index]}))} outerRadius="62%"><PolarGrid stroke="var(--border)"/><PolarAngleAxis dataKey="label" tick={{fontSize:11,fill:'var(--muted-foreground)'}}/>{series.fresh?<Radar name={t(key('newVisitors'))} dataKey="fresh" stroke={chartColor} fill={chartColor} fillOpacity={0.08} dot={{r:2}} isAnimationActive={false}/>:null}{series.returning?<Radar name={t(key('returningVisitors'))} dataKey="returning" stroke="var(--chart-emerald)" fill="var(--chart-emerald)" fillOpacity={0.08} dot={{r:2}} isAnimationActive={false}/>:null}<Tooltip content={<ChartTooltipContent/>}/></RadarChart></ResponsiveContainer></ChartContainer></MarketingFrame>
|
|
90
|
+
}
|
|
91
|
+
function ChannelRows({ marketing = false }: { marketing?: boolean }) {
|
|
92
|
+
const {t,money,number}=useMarketing()
|
|
93
|
+
const names=marketing?['acquisition','conversion','roi']:['Facebook','Instagram','Google']
|
|
94
|
+
return <div className="flex flex-col gap-4"><div className="flex items-center text-xs text-muted-foreground"><span className="flex-1">{t(key('channels'))}</span><span className="w-22">{t(key(marketing?'metric':'percent'))}</span><span className="w-12">{t(key('total'))}</span></div>{names.map((name,index)=><div key={name} className="flex h-5 items-center gap-2 text-sm text-muted-foreground">{marketing ? index===0?<UserRound aria-hidden="true" className="size-5"/>:index===1?<Clock3 aria-hidden="true" className="size-5"/>:<Target aria-hidden="true" className="size-5"/>:<img src={marketingBrands[name.toLowerCase() as 'facebook'|'instagram'|'google']} alt="" className="size-5"/>}<span className="min-w-0 flex-1">{marketing?t(key(name)):name}</span><span className="w-18">{marketing?[money(38.25),t(key('days'),undefined,{count:4.2}),'324%'][index]:\`\${[28,23,32][index]}%\`}</span><span className="w-12 text-right">{marketing?<Trend value={[5.2,3.8,4.5][index]}/>:number([6958,5716,7952][index])}</span></div>)}</div>
|
|
95
|
+
}
|
|
96
|
+
function Channels({ marketing = false }: { marketing?: boolean }) {
|
|
97
|
+
const {t}=useMarketing()
|
|
98
|
+
const title=t(key(marketing?'marketingChannels':'visitorChannels'))
|
|
99
|
+
return <MarketingFrame><Header title={title} info={marketing} value={marketing?'82%':'78%'} action={marketing?<Details title={title}><ChannelRows marketing/></Details>:undefined}><Trend value={marketing?2.1:-0.4} badge={!marketing} previous={marketing}/></Header><div className="space-y-4"><div className="flex h-2 gap-1">{[41,41,16].map((width,index)=><span key={index} className="rounded-sm" style={{width:\`\${width}%\`,background:marketing?palette[index]:['var(--chart-amber)','var(--chart-cyan)','var(--chart-violet)'][index]}}/>)}</div><div className="flex justify-between gap-1 text-xs text-muted-foreground">{(marketing?['organicSearch','socialMedia','direct']:['organic','referral','direct']).map((name,index)=><span key={name} className="flex items-center gap-2"><span className="size-2 shrink-0 rounded-full" style={{background:marketing?palette[index]:['var(--chart-amber)','var(--chart-cyan)','var(--chart-violet)'][index]}}/>{t(key(name))}</span>)}</div></div><div className={cn('border-t border-border pt-5',marketing&&'border-dashed')}><ChannelRows marketing={marketing}/></div><Details title={title} label={t(key('viewReports'))} className="mt-auto h-8 w-full"><ChannelRows marketing={marketing}/></Details></MarketingFrame>
|
|
100
|
+
}
|
|
101
|
+
const mapPoints=[{key:'greenland',x:161,y:7,visitors:1032},{key:'usa',x:80,y:69,visitors:8530},{key:'brazil',x:129,y:126,visitors:3240},{key:'turkey',x:222,y:110,visitors:6504},{key:'china',x:276,y:57,visitors:9322}]
|
|
102
|
+
function Geography() {
|
|
103
|
+
const {t,number}=useMarketing()
|
|
104
|
+
const [selected,setSelected]=React.useState('turkey')
|
|
105
|
+
const [zoom,setZoom]=React.useState(1)
|
|
106
|
+
const place=mapPoints.find(point=>point.key===selected)??mapPoints[3]
|
|
107
|
+
return <MarketingFrame className="gap-4"><Header title={t(key('geography'))} value={number(place.visitors)} action={<Details title={t(key('geography'))}><DataList rows={mapPoints.map(point=>({label:t(key(point.key)),value:number(point.visitors)}))}/></Details>}><span className="flex h-6 items-center gap-1 rounded-sm border border-border px-1 text-xs text-muted-foreground">{selected==='turkey'?<img src={marketingBrands.turkey} alt="" className="size-4"/>:null}{t(key(selected))}</span></Header><div className="flex h-7 shrink-0 items-center justify-around rounded-lg border border-border text-xs text-muted-foreground">{['men','women','other'].map((item,index)=><span key={item}>{t(key(item))} <span className="text-foreground">{[32,60,8][index]}%</span></span>)}</div><div data-slot="marketing-map" className="relative h-56 w-full shrink-0 overflow-hidden"><div className="absolute inset-0 origin-center transition-transform" style={{transform:\`scale(\${zoom})\`}}><span aria-hidden="true" className="absolute left-0 top-0 h-56 w-83 bg-text-disabled" style={{maskImage:\`url("\${marketingWorldMap}")\`,WebkitMaskImage:\`url("\${marketingWorldMap}")\`,maskSize:'100% 100%',WebkitMaskSize:'100% 100%'}}/>{mapPoints.map(point=><button key={point.key} type="button" aria-label={t(key(point.key))} aria-pressed={selected===point.key} onClick={()=>setSelected(point.key)} style={{left:\`\${point.x/312*100}%\`,top:\`\${point.y/224*100}%\`}} className={cn('absolute flex size-4 items-center justify-center rounded-full bg-background ring-1 ring-inset ring-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground',selected===point.key&&'bg-accent-orange ring-4 ring-accent-orange/20')}><span className={cn('size-2 rounded-full',selected===point.key?'bg-accent-orange-foreground':'bg-text-disabled')}/></button>)}</div><div className="absolute bottom-0 left-0 flex flex-col gap-2"><CompactButton aria-label={t(key('zoomIn'))} disabled={zoom>=2} onClick={()=>setZoom(current=>Math.min(2,current+0.25))}><Plus aria-hidden="true"/></CompactButton><CompactButton aria-label={t(key('zoomOut'))} disabled={zoom<=1} onClick={()=>setZoom(current=>Math.max(1,current-0.25))}><Minus aria-hidden="true"/></CompactButton></div><CompactButton className="absolute bottom-0 right-0" aria-label={t(key('resetMap'))} onClick={()=>{setZoom(1);setSelected('turkey')}}><Code aria-hidden="true"/></CompactButton></div></MarketingFrame>
|
|
108
|
+
}
|
|
109
|
+
function RealtimeVisitors() {
|
|
110
|
+
const {t,number}=useMarketing()
|
|
111
|
+
return <MarketingFrame><Header title={t(key('realtimeVisitors'))} value={t(key('millions'),undefined,{value:number(32.6,1)})}><Trend value={8.4} badge/></Header><div className="relative h-39 shrink-0" aria-label={t(key('regionalVisitors'))}><div className="absolute left-1/2 top-1/2 -ml-10.5 -mt-9.5 flex size-20 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-chart-emerald/25 text-xl text-status-success-foreground">20%</div><div className="absolute left-1/2 top-1/2 ml-10 mt-1 flex size-33 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-chart-orange/25 text-title-4 font-medium text-accent-orange-text">48%</div><div className="absolute left-1/2 top-1/2 -ml-14.5 mt-7.5 flex size-24 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-chart-amber/25 text-2xl font-medium text-status-warning-foreground">32%</div></div><DataList rows={['europe','asia','americas'].map((region,index)=>({label:t(key(region)),value:t(key('millions'),undefined,{value:number([15.8,10.2,6.6][index],1)}),icon:<span className="ml-1 size-2 rounded-full" style={{background:[palette[0],palette[1],'var(--chart-emerald)'][index]}}/>,detail:<><ArrowUpRight aria-hidden="true" className={cn('size-4',index===1?'rotate-90 text-status-error-icon':'text-status-success-icon')}/>+{number([4.7,6.2,3.8][index],1)}%</>}))}/></MarketingFrame>
|
|
112
|
+
}
|
|
113
|
+
function ProductPerformance() {
|
|
114
|
+
const {t,number}=useMarketing()
|
|
115
|
+
const [period,setPeriod]=React.useState('1w')
|
|
116
|
+
const factor=period==='1w'?1:period==='1d'?0.6:0.85
|
|
117
|
+
return <MarketingFrame><Header title={t(key('productPerformance'))} value={\`\${number(22.8*factor,1)}%\`}><Trend value={8.4} badge/></Header><Period value={period} onChange={setPeriod}/><div className="flex h-39.5 shrink-0 items-end gap-2.5" aria-label={t(key('productPerformance'))}>{[50,80,100,60,40].map((value,index)=><div key={index} className="flex min-w-0 flex-1 flex-col items-center justify-between rounded-lg bg-chart-orange px-1 py-2 text-xs font-medium text-accent-orange-foreground" style={{height:\`\${value*factor}%\`}}><span>{Math.round(value*factor)}%</span><span>{String.fromCharCode(65+index)}</span></div>)}</div><div className="flex flex-1">{['averageRating','satisfaction','returnRate'].map((name,index)=><div key={name} className="flex min-w-0 flex-1 flex-col items-center justify-center border-r border-border last:border-0"><p className="text-base font-medium text-muted-foreground">{[number(4.7,1),'92%',\`\${number(4.2,1)}%\`][index]}</p><p className="mt-1 text-xs text-muted-foreground">{t(key(name))}</p></div>)}</div></MarketingFrame>
|
|
118
|
+
}
|
|
119
|
+
const productData=[{image:0,name:'Apple Watch S5 GPS 40MM',count:500},{image:4,name:'AirPods Max Green',count:960},{image:6,name:'iMac M1 24-inch Purple',count:45},{image:8,name:'iPhone 15 Pro 512GB',count:150},{image:1,name:'MacBook Air',count:380},{image:3,name:'AirPods Pro',count:780}]
|
|
120
|
+
function ProductRows({ query = '' }: { query?: string }) {
|
|
121
|
+
const {t,number}=useMarketing()
|
|
122
|
+
const matches=productData.filter(product=>product.name.toLocaleLowerCase().includes(query.toLocaleLowerCase()))
|
|
123
|
+
return matches.length ? <div>{matches.map(product=><div key={product.name} className="flex min-h-17 items-center gap-3 border-b border-border px-5 py-3 last:border-0"><img src={marketingProducts[product.image].src} alt="" className="size-8 shrink-0 object-contain"/><div className="min-w-0"><p className="truncate text-sm font-medium">{product.name}</p><p className="mt-1 text-xs text-muted-foreground">{t(key('unitsSold'),undefined,{count:number(product.count)})}</p></div></div>)}</div> : <p role="status" className="p-5 text-sm text-muted-foreground">{t(key('noProducts'))}</p>
|
|
124
|
+
}
|
|
125
|
+
function MyProducts() {
|
|
126
|
+
const {t,number}=useMarketing()
|
|
127
|
+
const [query,setQuery]=React.useState('')
|
|
128
|
+
return <MarketingFrame flush><Header title={t(key('myProducts'))} info value={number(468)} className="h-23 px-5 py-5" action={<Details title={t(key('myProducts'))} label={t(key('seeAll'))}><ProductRows query={query}/></Details>}><Trend value={2.1} previous/></Header><div className="border-y border-border px-5"><SearchInput aria-label={t(key('searchProducts'))} placeholder={t(key('searchProducts'))} value={query} onChange={setQuery} className="h-11 rounded-none border-0 px-0 shadow-none"/></div><ScrollArea className="min-h-0 flex-1" scrollbarSize="xs"><ProductRows query={query}/></ScrollArea></MarketingFrame>
|
|
129
|
+
}
|
|
130
|
+
function ShippingTracking() {
|
|
131
|
+
const {t,number,date}=useMarketing()
|
|
132
|
+
const [period,setPeriod]=React.useState('weekly')
|
|
133
|
+
const [status,setStatus]=React.useState('delivered')
|
|
134
|
+
const [product,setProduct]=React.useState(0)
|
|
135
|
+
const factor=(status==='delivered'?1:status==='inTransit'?0.55:0.2)*(period==='weekly'?1:period==='monthly'?3:12)
|
|
136
|
+
const data=[0,10,44,59,0,29,0,0,45,29,29,10,29,29,0,59,29,29].map((value,index)=>({day:date(\`2024-02-\${String(19+Math.floor(index/3)).padStart(2,'0')}T00:00:00Z\`,{weekday:'short'}),value:(value+product*3)*factor}))
|
|
137
|
+
return <MarketingFrame flush><div className="flex h-35 shrink-0 flex-col gap-4 p-5"><Header title={t(key('shippingTracking'))} value={number(Math.round(3844*factor))} info action={<Period compact value={period} onChange={setPeriod}/>}><Trend value={1.8} badge/></Header><Choices values={['delivered','inTransit','returned']} value={status} onChange={setStatus} label={t(key('shippingStatus'))}/></div><div className="flex h-12 shrink-0 items-center gap-2 border-y border-border px-5"><img src={marketingProducts[product].src} alt="" className="size-6"/><span className="min-w-0 flex-1 truncate text-sm text-muted-foreground">{marketingProducts[product].name}</span><div className="flex"><CompactButton aria-label={t(key('previousProduct'))} onClick={()=>setProduct(current=>(current+marketingProducts.length-1)%marketingProducts.length)}><ChevronLeft aria-hidden="true"/></CompactButton><CompactButton aria-label={t(key('nextProduct'))} onClick={()=>setProduct(current=>(current+1)%marketingProducts.length)}><ChevronRight aria-hidden="true"/></CompactButton></div></div><ChartContainer config={{value:{label:t(key(status)),color:chartColor}}} className="min-h-0 flex-1" aria-label={t(key('shippingTracking'))}><ResponsiveContainer width="100%" height="100%"><LineChart data={data} margin={{top:0,right:20,left:20,bottom:0}}><CartesianGrid stroke="var(--border)"/><XAxis dataKey="day" interval={2} tickLine={false} axisLine={false} tick={{fontSize:12,fill:'var(--muted-foreground)'}}/><Tooltip content={<ChartTooltipContent/>}/><Line type="stepAfter" dataKey="value" dot={false} stroke={chartColor} strokeWidth={1.5} isAnimationActive={false}/></LineChart></ResponsiveContainer></ChartContainer></MarketingFrame>
|
|
138
|
+
}
|
|
139
|
+
function ProductCategories() {
|
|
140
|
+
const {t,number}=useMarketing()
|
|
141
|
+
const [category,setCategory]=React.useState(0)
|
|
142
|
+
const categories=['accessories','computers','audio']
|
|
143
|
+
const percentage=[58,72,34][category]
|
|
144
|
+
const details=<DataList rows={categories.map((name,index)=>({label:t(key(name)),value:t(key('productsCount'),undefined,{count:[45,32,18][index]})}))}/>
|
|
145
|
+
return <MarketingFrame compact className="gap-4"><Header title={t(key('productCategories'))} value={\`\${percentage}%\`} info action={<Details title={t(key('productCategories'))}>{details}</Details>}><Trend value={2.1} previous/></Header><div className="flex h-7.5 shrink-0 gap-0.5" role="meter" aria-label={t(key('productCategories'))} aria-valuemin={0} aria-valuemax={100} aria-valuenow={percentage}>{Array.from({length:36},(_,index)=><span key={index} className={cn('min-w-0 flex-1',index<Math.round(percentage/100*36)?'bg-chart-orange':'bg-border')}/>)}</div><div className="flex min-h-5 items-center gap-2 text-sm text-muted-foreground"><span>{t(key(categories[category]))}</span><div className="flex"><CompactButton aria-label={t(key('previousCategory'))} onClick={()=>setCategory(current=>(current+2)%3)}><ChevronLeft aria-hidden="true"/></CompactButton><CompactButton aria-label={t(key('nextCategory'))} onClick={()=>setCategory(current=>(current+1)%3)}><ChevronRight aria-hidden="true"/></CompactButton></div><span className="ml-auto whitespace-nowrap">{t(key('productsCount'),undefined,{count:number([45,32,18][category])})}</span><Trend value={3.2}/></div></MarketingFrame>
|
|
146
|
+
}
|
|
147
|
+
function CustomerSegments() {
|
|
148
|
+
const {t,money}=useMarketing()
|
|
149
|
+
const data=[{label:'premium',value:32,amount:9450},{label:'regular',value:46,amount:8320},{label:'new',value:20,amount:3280}]
|
|
150
|
+
return <MarketingFrame compact><div className="flex h-5 shrink-0 items-center justify-between gap-2"><h3 className="flex items-center gap-1 text-sm font-medium text-muted-foreground">{t(key('customerSegments'))}<Info aria-hidden="true" className="size-3 text-text-disabled"/></h3><Trend value={5.8} previous/></div><div className="flex h-25 items-center gap-5"><ChartContainer config={Object.fromEntries(data.map((item,index)=>[item.label,{label:t(key(item.label)),color:palette[index]}]))} className="size-25 shrink-0" aria-label={t(key('customerSegments'))}><PieChart width={100} height={100}><Pie data={data} dataKey="value" nameKey="label" cx={45} cy={45} innerRadius={34} outerRadius={49} paddingAngle={3} stroke="none" startAngle={90} endAngle={450} isAnimationActive={false}>{data.map((item,index)=><Cell key={item.label} fill={palette[index]}/>)}</Pie><Tooltip content={<ChartTooltipContent/>}/></PieChart></ChartContainer><div className="flex min-w-0 flex-1 flex-col gap-3">{data.map((item,index)=><div key={item.label} className="flex items-center gap-2 text-sm text-muted-foreground"><span className="size-2 shrink-0 rounded-full" style={{background:palette[index]}}/><span className="min-w-0 flex-1 truncate">{t(key(item.label))}</span><span>{money(item.amount)}</span><span className="text-xs">{item.value}%</span></div>)}</div></div></MarketingFrame>
|
|
151
|
+
}
|
|
152
|
+
function SalesChannels() {
|
|
153
|
+
const {t,number,date}=useMarketing()
|
|
154
|
+
const [period,setPeriod]=React.useState('weekly')
|
|
155
|
+
const multiplier=period==='weekly'?1:period==='monthly'?4:52
|
|
156
|
+
return <MarketingFrame compact className="gap-4"><Header title={t(key('salesChannels'))} value={number(246*multiplier)} info action={<Period compact value={period} onChange={setPeriod}/>}><Trend value={2.1} previous/></Header><div className="space-y-2"><div className="flex justify-between text-xs text-muted-foreground"><span>{date('2024-02-21T00:00:00Z')}</span><span>{date(period==='weekly'?'2024-02-28T00:00:00Z':period==='monthly'?'2024-03-21T00:00:00Z':'2025-02-21T00:00:00Z')}</span></div><div className="flex h-10.5 gap-1" aria-label={t(key('salesChannels'))}>{[26,21,16,13,10,5,2].map((width,index)=><span key={index} className="rounded-sm" style={{flex:width,background:['var(--chart-indigo)','var(--chart-cyan)','var(--chart-violet)','var(--chart-orange)','var(--chart-amber)','var(--chart-emerald)','var(--chart-teal)'][index]}}/>)}</div></div></MarketingFrame>
|
|
157
|
+
}
|
|
158
|
+
function CampaignData() {
|
|
159
|
+
const {t,money}=useMarketing()
|
|
160
|
+
return <MarketingFrame compact flush><Header title={t(key('campaignData'))} value={money(1750)} info className="h-23.5 px-5 py-5" action={<Details title={t(key('campaignData'))}><DataList rows={[{label:t(key('campaignBudget')),value:money(1750)},{label:t(key('usedBudget')),value:money(32900)},{label:t(key('campaignProgress')),value:'45%'}]}/></Details>}><Badge size={20} appearance="lighter" tone="success">{t(key('lastDays'),undefined,{count:15})}</Badge></Header><div className="flex min-h-0 flex-1 border-t border-border"><ChartContainer config={{value:{label:t(key('campaignData')),color:chartColor}}} className="w-44 min-w-0 shrink-0 border-r border-accent-orange-border" aria-label={t(key('campaignData'))}><ResponsiveContainer width="100%" height="100%"><AreaChart data={salesSeries.slice(0,18).map((value,index)=>({index,value:value+index*2}))} margin={{top:0,left:0,right:0,bottom:0}}><Tooltip content={<ChartTooltipContent/>}/><Area dataKey="value" type="linear" stroke={chartColor} strokeWidth={1.5} fill={chartColor} fillOpacity={0.18} isAnimationActive={false}/></AreaChart></ResponsiveContainer></ChartContainer><div className="flex min-w-0 flex-1 flex-col justify-end p-4"><p className="text-base font-medium">45%</p><p className="text-xs text-muted-foreground">{t(key('budgetUsed'),undefined,{amount:money(32900)})}</p></div></div></MarketingFrame>
|
|
161
|
+
}
|
|
162
|
+
type TicketStatus = 'solved' | 'inProgress' | 'pending'
|
|
163
|
+
const ticketSamples: {name:string;status:TicketStatus;minutes:number;priority:string;id:number}[]=[{name:'James Brown',status:'solved',minutes:12,priority:'high',id:98745},{name:'Sophia Williams',status:'inProgress',minutes:48,priority:'medium',id:98744},{name:'Matthew Johnson',status:'pending',minutes:19,priority:'low',id:98743}]
|
|
164
|
+
function SupportAnalytics() {
|
|
165
|
+
const {t,number,date}=useMarketing()
|
|
166
|
+
const [period,setPeriod]=React.useState('weekly')
|
|
167
|
+
const [category,setCategory]=React.useState('technical')
|
|
168
|
+
const [tab,setTab]=React.useState('allTickets')
|
|
169
|
+
const [tickets,setTickets]=React.useState(ticketSamples)
|
|
170
|
+
const [selected,setSelected]=React.useState<number|null>(null)
|
|
171
|
+
const factor=(['technical','billing','account','product'].indexOf(category)+4)/4*(period==='weekly'?1:period==='monthly'?4:52)
|
|
172
|
+
const current=tickets.find(ticket=>ticket.id===selected)
|
|
173
|
+
const visible=tickets.filter(ticket=>tab==='allTickets'||(tab==='openTickets'?ticket.status!=='solved':ticket.status==='solved'))
|
|
174
|
+
const metrics=[{label:'firstResponse',detail:'belowSla',value:t(key('minutes'),undefined,{count:Math.round(15*factor)}),delta:-22},{label:'resolutionTime',detail:'meetingSla',value:t(key('minutes'),undefined,{count:Math.round(48*factor)}),delta:-18},{label:'csat',detail:'aboveTarget',value:'4.8/5',delta:-0.3}]
|
|
175
|
+
return <><MarketingFrame tall flush><div className="flex h-34 shrink-0 flex-col gap-3 p-5"><Header title={t(key('supportAnalytics'))} value={number(Math.round(2450*factor))} info action={<Period compact value={period} onChange={setPeriod}/>}><Trend value={5.4}/><span className="text-sm text-muted-foreground">{t(key('totalTickets'))}</span></Header><Choices values={['technical','billing','account','product']} value={category} onChange={setCategory} label={t(key('ticketCategory'))}/></div><ChartContainer config={{value:{label:t(key('responseTime')),color:chartColor}}} className="h-44 shrink-0 border-y border-border px-3 pt-4" aria-label={t(key('responseTime'))}><ResponsiveContainer width="100%" height="100%"><BarChart data={[10,34,44,58,44,34,34].map((value,index)=>({day:date(\`2024-02-\${19+index}T00:00:00Z\`,{weekday:'short'}),value:Math.round(value*factor)}))} margin={{top:0,right:0,left:0,bottom:0}}><XAxis dataKey="day" axisLine={false} tickLine={false} tick={{fontSize:12,fill:'var(--muted-foreground)'}}/><Tooltip content={<ChartTooltipContent/>}/><ReferenceLine y={30*factor} stroke="var(--muted-foreground)" strokeDasharray="4 4" label={{value:t(key('targetMinutes'),undefined,{count:30}),fill:'var(--foreground)',fontSize:12,position:'insideTopLeft'}}/><Bar dataKey="value" radius={[6,6,6,6]} isAnimationActive={false}>{Array.from({length:7},(_,index)=><Cell key={index} fill={index===4?chartColor:'var(--border)'}/>)}</Bar></BarChart></ResponsiveContainer></ChartContainer><Tabs value={tab} onValueChange={setTab} variant="underline" className="min-h-0 flex-1 gap-0"><TabsList className="h-12 w-full shrink-0 justify-start gap-4 px-5"><TabsTrigger value="allTickets" className="min-w-0 flex-auto justify-center px-0 text-sm font-normal data-[state=active]:border-accent-orange-border hover:text-accent-orange-text">{t(key('allTickets'))}</TabsTrigger><TabsTrigger value="openTickets" className="min-w-0 flex-auto justify-center px-0 text-sm font-normal data-[state=active]:border-accent-orange-border hover:text-accent-orange-text">{t(key('openTickets'))}</TabsTrigger><TabsTrigger value="solvedTickets" className="min-w-0 flex-auto justify-center px-0 text-sm font-normal data-[state=active]:border-accent-orange-border hover:text-accent-orange-text">{t(key('solvedTickets'))}</TabsTrigger></TabsList>{['allTickets','openTickets','solvedTickets'].map(value=><TabsContent key={value} value={value} className="m-0 flex min-h-0 flex-1 flex-col"><div className="flex shrink-0 flex-col gap-4 px-5 pb-5 pt-4"><div className="flex text-xs text-muted-foreground"><span className="flex-1">{t(key('channels'))}</span><span className="w-18">{t(key('actual'))}</span><span className="w-10">{t(key('average'))}</span></div>{metrics.map((metric,index)=><div key={metric.label} className="flex items-center text-sm"><div className="min-w-0 flex-1"><p>{t(key(metric.label))}</p><p className="mt-1 text-xs text-muted-foreground">{t(key(metric.detail))}</p></div><span className="w-18 text-muted-foreground">{metric.value}</span><span className={cn('w-10',index===2?'text-status-error-icon':'text-status-success-icon')}>{number(metric.delta,index===2?1:0)}%</span></div>)}</div><div className="min-h-0 flex-1 border-t border-border px-5 pt-4"><p className="mb-3 text-xs text-muted-foreground">{t(key('recentTickets'))}</p><ScrollArea className="h-40" scrollbarSize="xs"><div className="flex flex-col gap-4">{visible.map((ticket,index)=><Button key={ticket.id} variant="ghost" onClick={()=>setSelected(ticket.id)} className="h-auto min-h-10 w-full justify-start gap-3 p-0 text-left font-normal hover:bg-muted"><Avatar label={ticket.name} size={32} className={index===1?'bg-chart-amber/20 text-status-warning-foreground':index===2?'bg-chart-violet/20 text-accent-indigo':'bg-muted'}/><div className="min-w-0 flex-1"><p className="truncate text-sm font-medium">{ticket.name}</p><p className="mt-1 flex items-center gap-1 text-xs text-muted-foreground">{t(key(ticket.priority))} \xB7 <span className={ticket.status==='solved'?'text-status-success-icon':'text-status-warning-icon'}>{t(key(ticket.status))}</span></p></div><div className="text-right"><p className="text-sm">{t(key('minutes'),undefined,{count:ticket.minutes})}</p><p className="mt-1 text-xs text-muted-foreground">#TKT-{ticket.id}</p></div></Button>)}</div></ScrollArea></div></TabsContent>)}</Tabs></MarketingFrame><Dialog open={selected!==null} onOpenChange={open=>{if(!open)setSelected(null)}}><DialogContent onKeyDownCapture={event=>{if(event.key==='Enter'&&(event.ctrlKey||event.metaKey)){event.preventDefault();setSelected(null)}}}><DialogHeader><DialogTitle>{current?.name}</DialogTitle><DialogDescription>{current?\`#TKT-\${current.id}\`:t(key('recentTickets'))}</DialogDescription></DialogHeader>{current?<DataList rows={[{label:t(key('status')),value:t(key(current.status))},{label:t(key('priority')),value:t(key(current.priority))}]}/>:null}<DialogFooter><Button variant="outline" onClick={()=>setSelected(null)}>{t(key('close'))}</Button><Button disabled={current?.status==='solved'} onClick={()=>{setTickets(items=>items.map(ticket=>ticket.id===selected?{...ticket,status:'solved'}:ticket));setSelected(null)}}>{t(key('resolveTicket'))}</Button></DialogFooter></DialogContent></Dialog></>
|
|
176
|
+
}
|
|
177
|
+
const activityKinds=[{key:'inventory',icon:'stack-line',color:'text-chart-violet',detail:'inventoryDetail'},{key:'price',icon:'price-tag-line',color:'text-status-success-icon',detail:'priceDetail'},{key:'newProduct',icon:'add-circle-line',color:'text-chart-violet',detail:'newProductDetail'},{key:'images',icon:'image-line',color:'text-status-warning-icon',detail:'imagesDetail'},{key:'descriptionUpdated',icon:'pencil-line',color:'text-muted-foreground',detail:'descriptionDetail'}] satisfies {key:string;icon:string;color:string;detail:string}[]
|
|
178
|
+
function RecentActivities() {
|
|
179
|
+
const {t,date}=useMarketing()
|
|
180
|
+
const [period,setPeriod]=React.useState('today')
|
|
181
|
+
const [query,setQuery]=React.useState('')
|
|
182
|
+
const records=Array.from({length:period==='today'?7:period==='yesterday'?2:9},(_,index)=>({id:index,...activityKinds[index%5]})).filter(item=>[t(key(item.key)),t(key(item.detail)),t(key('activityProduct'))].join(' ').toLocaleLowerCase().includes(query.toLocaleLowerCase()))
|
|
183
|
+
const list=<div className="flex flex-col gap-5">{records.map((item,index)=><div key={item.id} className="relative flex gap-4"><div className="relative flex w-7 shrink-0 justify-center"><span className="z-10 flex size-7 items-center justify-center rounded-full border border-border bg-background shadow-xs"><span aria-hidden="true" className={cn('size-4 bg-current',item.color)} style={{maskImage:\`url("\${marketingActivityIcons[item.key as keyof typeof marketingActivityIcons]}")\`,WebkitMaskImage:\`url("\${marketingActivityIcons[item.key as keyof typeof marketingActivityIcons]}")\`,maskSize:'contain',WebkitMaskSize:'contain'}}/></span>{index<records.length-1?<span aria-hidden="true" className="absolute bottom-0 top-8 w-px bg-border"/>:null}</div><div className="min-w-0 flex-1"><div className="flex items-center gap-2"><p className="min-w-0 flex-1 text-sm font-medium">{t(key(item.key))}</p><time className="text-overline text-muted-foreground">{date('2024-02-21T11:30:00Z',{hour:'numeric',minute:'2-digit'})}</time></div><p className="mt-1 text-xs text-muted-foreground">{item.key==='price'?t(key('seasonalDiscount')):t(key('activityProduct'))}</p><p className="mt-1 text-xs text-muted-foreground">{t(key(item.detail))}</p></div></div>)}{!records.length?<p role="status" className="text-sm text-muted-foreground">{t(key('noActivities'))}</p>:null}</div>
|
|
184
|
+
return <MarketingFrame tall flush><div className="flex h-33 shrink-0 flex-col gap-4 p-5"><div className="flex items-start"><div className="flex-1"><h3 className="text-sm font-medium">{t(key('recentActivities'))}</h3><p className="mt-1 text-sm text-muted-foreground">{t(key('newActivities'),undefined,{count:5})}</p></div><Details title={t(key('recentActivities'))}>{list}</Details></div><Choices values={['today','yesterday','thisWeek']} value={period} onChange={setPeriod} label={t(key('activityPeriod'))}/></div><div className="border-y border-border px-5"><SearchInput aria-label={t(key('searchActivities'))} placeholder={t(key('searchActivities'))} value={query} onChange={setQuery} className="h-12 rounded-none border-0 px-0 shadow-none"/></div><ScrollArea className="min-h-0 flex-1 px-5 py-5" scrollbarSize="xs">{list}</ScrollArea></MarketingFrame>
|
|
185
|
+
}
|
|
186
|
+
const widgets: Record<MarketingWidgetKind, React.ComponentType> = {
|
|
187
|
+
'total-sales':TotalSales,'total-visitors':TotalVisitors,'conversion-rate':ConversionRate,'user-retention':Retention,'weekly-visitors':WeeklyVisitors,'visitor-channels':Channels,geography:Geography,'realtime-visitors':RealtimeVisitors,'marketing-channels':()=> <Channels marketing/>,'product-performance':ProductPerformance,'shipping-tracking':ShippingTracking,'my-products':MyProducts,'product-categories':ProductCategories,'customer-segments':CustomerSegments,'sales-channels':SalesChannels,'campaign-data':CampaignData,'support-analytics':SupportAnalytics,'recent-activities':RecentActivities,
|
|
188
|
+
}
|
|
189
|
+
export function MarketingWidgetDemo({kind}:{kind:MarketingWidgetKind}) { const Widget=widgets[kind]; return <Widget/> }
|
|
190
|
+
`;
|
|
191
|
+
const marketingWidgetExampleCode = (expression) => source + "\n" + expression + "\n";
|
|
192
|
+
export {
|
|
193
|
+
marketingWidgetExampleCode
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=marketing-widgets-code.generated.js.map
|