create-tanqory-theme 0.0.0-stage → 0.2.3
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/LICENSE +21 -0
- package/README.md +55 -2
- package/bin/create-tanqory-theme.mjs +13 -0
- package/lib/agents.mjs +118 -0
- package/lib/create.mjs +245 -0
- package/package.json +39 -4
- package/templates/blank/README.md +13 -0
- package/templates/blank/config/settings.json +3 -0
- package/templates/blank/locales/en.json +22 -0
- package/templates/blank/locales/th.json +22 -0
- package/templates/blank/package.json +34 -0
- package/templates/blank/regions/footer.json +35 -0
- package/templates/blank/regions/header.json +13 -0
- package/templates/blank/scripts/build.mjs +193 -0
- package/templates/blank/scripts/probe.ts +4 -0
- package/templates/blank/src/bundle.ts +15 -0
- package/templates/blank/src/components/parts.tsx +32 -0
- package/templates/blank/src/entry.client.tsx +6 -0
- package/templates/blank/src/entry.server.tsx +13 -0
- package/templates/blank/src/sections/chrome.tsx +132 -0
- package/templates/blank/src/sections/commerce.tsx +242 -0
- package/templates/blank/src/sections/content.tsx +111 -0
- package/templates/blank/src/sections/editorial.tsx +107 -0
- package/templates/blank/src/settings.ts +15 -0
- package/templates/blank/src/styles/theme.css +195 -0
- package/templates/blank/src/templates.ts +14 -0
- package/templates/blank/src/theme.tsx +76 -0
- package/templates/blank/template.json +24 -0
- package/templates/blank/templates/404.json +14 -0
- package/templates/blank/templates/account.json +14 -0
- package/templates/blank/templates/article.json +14 -0
- package/templates/blank/templates/blog.json +14 -0
- package/templates/blank/templates/cart.json +14 -0
- package/templates/blank/templates/collection.json +14 -0
- package/templates/blank/templates/index.json +36 -0
- package/templates/blank/templates/page.contact.json +18 -0
- package/templates/blank/templates/page.json +14 -0
- package/templates/blank/templates/product.json +18 -0
- package/templates/blank/templates/search.json +14 -0
- package/templates/blank/tests/theme.test.ts +49 -0
- package/templates/blank/tsconfig.json +17 -0
- package/templates/blank/vite.client.config.ts +17 -0
- package/templates/blank/vite.probe.config.ts +16 -0
- package/templates/blank/vite.server.config.ts +32 -0
- package/templates/blank/vitest.config.ts +9 -0
- package/templates/common/.claude/settings.json +8 -0
- package/templates/common/.codex/config.toml +4 -0
- package/templates/common/.gemini/settings.json +12 -0
- package/templates/common/.github/workflows/theme-check.yml +44 -0
- package/templates/common/.mcp.json +12 -0
- package/templates/common/.vscode/mcp.json +9 -0
- package/templates/common/_gitignore +9 -0
- package/templates/common/scripts/check.mjs +44 -0
- package/templates/common/scripts/dev.mjs +30 -0
- package/templates/common/tanqory.config.json +6 -0
- package/templates/nova/.gitattributes +3 -0
- package/templates/nova/.tanqory/contracts/LOCK.json +66 -0
- package/templates/nova/.tanqory/contracts/nova-01.json +1092 -0
- package/templates/nova/.tanqory/contracts/nova-12A.json +2674 -0
- package/templates/nova/.tanqory/contracts/nova-12B.json +2285 -0
- package/templates/nova/.tanqory/contracts/nova-12C.json +2848 -0
- package/templates/nova/.tanqory/contracts/nova-12D.json +3039 -0
- package/templates/nova/.tanqory/contracts/nova-12E.json +1473 -0
- package/templates/nova/.tanqory/contracts/nova-12F.json +1670 -0
- package/templates/nova/.tanqory/contracts/nova-12G.json +1661 -0
- package/templates/nova/.tanqory/contracts/nova-13.json +301 -0
- package/templates/nova/.tanqory/contracts/nova-14.json +172 -0
- package/templates/nova/.tanqory/legacy-settings.json +1121 -0
- package/templates/nova/README.md +150 -0
- package/templates/nova/_gitignore +28 -0
- package/templates/nova/assets/ai-tokens.css +6 -0
- package/templates/nova/assets/starter/starter-art-1200x800-0b773ac4.svg +1 -0
- package/templates/nova/assets/starter/starter-art-1200x900-59600290.svg +1 -0
- package/templates/nova/assets/starter/starter-art-1200x900-c549d496.svg +1 -0
- package/templates/nova/assets/starter/starter-art-1600x900-8f979fcb.svg +1 -0
- package/templates/nova/assets/starter/starter-art-2100x900-cbb71bfd.svg +1 -0
- package/templates/nova/config/legacy-settings.json +438 -0
- package/templates/nova/config/promotion-popup.schema.ts +29 -0
- package/templates/nova/config/settings.json +23 -0
- package/templates/nova/config/settings.schema.ts +231 -0
- package/templates/nova/entry.abi.tsx +27 -0
- package/templates/nova/groups/footer.json +39 -0
- package/templates/nova/groups/header.json +11 -0
- package/templates/nova/lib/abi/abi.css +41 -0
- package/templates/nova/lib/bundle-core.ts +35 -0
- package/templates/nova/lib/bundle.client.ts +15 -0
- package/templates/nova/lib/bundle.ts +15 -0
- package/templates/nova/lib/legacy-settings.ts +104 -0
- package/templates/nova/locales/ar.json +590 -0
- package/templates/nova/locales/en.json +590 -0
- package/templates/nova/locales/th.json +590 -0
- package/templates/nova/main.abi.tsx +12 -0
- package/templates/nova/package.json +44 -0
- package/templates/nova/scripts/abi/build.mjs +145 -0
- package/templates/nova/scripts/abi/check-content.mjs +99 -0
- package/templates/nova/scripts/abi/jcs.mjs +27 -0
- package/templates/nova/scripts/abi/local-host.mjs +294 -0
- package/templates/nova/scripts/abi/manifest.mjs +392 -0
- package/templates/nova/scripts/abi/starter-assets.mjs +32 -0
- package/templates/nova/scripts/compiler/checks/check-a11y.mjs +88 -0
- package/templates/nova/scripts/compiler/checks/check-layout-sanity.mjs +169 -0
- package/templates/nova/scripts/compiler/checks/check-page-headings.mjs +67 -0
- package/templates/nova/scripts/compiler/checks/check-product-jsonld.mjs +80 -0
- package/templates/nova/scripts/compiler/checks/theme-spec/check.mjs +88 -0
- package/templates/nova/scripts/compiler/contracts/extract.mjs +188 -0
- package/templates/nova/scripts/compiler/contracts/index.ts +125 -0
- package/templates/nova/scripts/compiler/contracts/validate.ts +347 -0
- package/templates/nova/scripts/compiler/manifest/gen-manifest.mjs +156 -0
- package/templates/nova/scripts/compiler/manifest/manifest-entry.ts +386 -0
- package/templates/nova/scripts/compiler/manifest/manifest-sections.ts +247 -0
- package/templates/nova/scripts/compiler/migrate/migrate-content.mjs +171 -0
- package/templates/nova/scripts/compiler/migrate/migrate-groups.mjs +159 -0
- package/templates/nova/scripts/parity/case-shim.ts +14 -0
- package/templates/nova/scripts/parity/emit.ts +206 -0
- package/templates/nova/scripts/parity/index.html +12 -0
- package/templates/nova/scripts/parity/main.tsx +23 -0
- package/templates/nova/scripts/parity/pages.tsx +123 -0
- package/templates/nova/scripts/parity/vite.config.ts +29 -0
- package/templates/nova/src/components/base/Accordion.css +20 -0
- package/templates/nova/src/components/base/Accordion.tsx +50 -0
- package/templates/nova/src/components/base/Badge.css +17 -0
- package/templates/nova/src/components/base/Badge.tsx +26 -0
- package/templates/nova/src/components/base/Button.css +73 -0
- package/templates/nova/src/components/base/Button.tsx +64 -0
- package/templates/nova/src/components/base/Checkbox.tsx +18 -0
- package/templates/nova/src/components/base/Chip.css +20 -0
- package/templates/nova/src/components/base/Chip.tsx +33 -0
- package/templates/nova/src/components/base/Divider.css +6 -0
- package/templates/nova/src/components/base/Divider.tsx +28 -0
- package/templates/nova/src/components/base/IconButton.css +34 -0
- package/templates/nova/src/components/base/IconButton.tsx +41 -0
- package/templates/nova/src/components/base/Input.css +21 -0
- package/templates/nova/src/components/base/Input.tsx +24 -0
- package/templates/nova/src/components/base/Link.css +15 -0
- package/templates/nova/src/components/base/Link.tsx +23 -0
- package/templates/nova/src/components/base/Radio.tsx +13 -0
- package/templates/nova/src/components/base/Select.css +18 -0
- package/templates/nova/src/components/base/Select.tsx +34 -0
- package/templates/nova/src/components/base/Skeleton.css +17 -0
- package/templates/nova/src/components/base/Skeleton.tsx +23 -0
- package/templates/nova/src/components/base/Spinner.css +13 -0
- package/templates/nova/src/components/base/Spinner.tsx +8 -0
- package/templates/nova/src/components/base/Switch.tsx +16 -0
- package/templates/nova/src/components/base/Tabs.css +24 -0
- package/templates/nova/src/components/base/Tabs.tsx +61 -0
- package/templates/nova/src/components/base/Textarea.css +1 -0
- package/templates/nova/src/components/base/Textarea.tsx +8 -0
- package/templates/nova/src/components/base/choice-props.ts +9 -0
- package/templates/nova/src/components/base/choice.css +69 -0
- package/templates/nova/src/components/commerce/AddToCart.css +4 -0
- package/templates/nova/src/components/commerce/AddToCart.tsx +77 -0
- package/templates/nova/src/components/commerce/CartLine.css +26 -0
- package/templates/nova/src/components/commerce/CartLine.tsx +82 -0
- package/templates/nova/src/components/commerce/CartSummary.css +23 -0
- package/templates/nova/src/components/commerce/CartSummary.tsx +120 -0
- package/templates/nova/src/components/commerce/CollectionCard.css +66 -0
- package/templates/nova/src/components/commerce/CollectionCard.tsx +57 -0
- package/templates/nova/src/components/commerce/ComparisonTable.css +33 -0
- package/templates/nova/src/components/commerce/ComparisonTable.tsx +113 -0
- package/templates/nova/src/components/commerce/EarnHint.css +3 -0
- package/templates/nova/src/components/commerce/EarnHint.tsx +31 -0
- package/templates/nova/src/components/commerce/Hotspot.css +16 -0
- package/templates/nova/src/components/commerce/Hotspot.tsx +64 -0
- package/templates/nova/src/components/commerce/ListingParts.css +79 -0
- package/templates/nova/src/components/commerce/ListingParts.tsx +211 -0
- package/templates/nova/src/components/commerce/LookItem.css +19 -0
- package/templates/nova/src/components/commerce/LookItem.tsx +41 -0
- package/templates/nova/src/components/commerce/MiniCartLine.css +20 -0
- package/templates/nova/src/components/commerce/MiniCartLine.tsx +93 -0
- package/templates/nova/src/components/commerce/PaymentMark.css +2 -0
- package/templates/nova/src/components/commerce/PaymentMark.tsx +55 -0
- package/templates/nova/src/components/commerce/Price.css +27 -0
- package/templates/nova/src/components/commerce/Price.tsx +55 -0
- package/templates/nova/src/components/commerce/ProductCard.css +66 -0
- package/templates/nova/src/components/commerce/ProductCard.tsx +117 -0
- package/templates/nova/src/components/commerce/ProductGallery.css +72 -0
- package/templates/nova/src/components/commerce/ProductGallery.tsx +98 -0
- package/templates/nova/src/components/commerce/QuantitySelector.css +23 -0
- package/templates/nova/src/components/commerce/QuantitySelector.tsx +45 -0
- package/templates/nova/src/components/commerce/Reviews.css +34 -0
- package/templates/nova/src/components/commerce/Reviews.tsx +112 -0
- package/templates/nova/src/components/commerce/Stars.css +7 -0
- package/templates/nova/src/components/commerce/Stars.tsx +38 -0
- package/templates/nova/src/components/commerce/VariantPicker.css +31 -0
- package/templates/nova/src/components/commerce/VariantPicker.tsx +122 -0
- package/templates/nova/src/components/commerce/blocks/Badge.css +6 -0
- package/templates/nova/src/components/commerce/blocks/Badge.tsx +33 -0
- package/templates/nova/src/components/commerce/blocks/PaymentIcons.tsx +43 -0
- package/templates/nova/src/components/commerce/blocks/Swatches.tsx +17 -0
- package/templates/nova/src/components/commerce/blocks/payment.css +2 -0
- package/templates/nova/src/components/commerce/cart-limit.ts +11 -0
- package/templates/nova/src/components/commerce/money.ts +34 -0
- package/templates/nova/src/components/commerce/swatch.ts +54 -0
- package/templates/nova/src/components/content/ArticleCard.css +22 -0
- package/templates/nova/src/components/content/ArticleCard.tsx +53 -0
- package/templates/nova/src/components/content/BeforeAfterSlider.css +38 -0
- package/templates/nova/src/components/content/BeforeAfterSlider.tsx +87 -0
- package/templates/nova/src/components/content/CardRow.css +80 -0
- package/templates/nova/src/components/content/CardRow.tsx +140 -0
- package/templates/nova/src/components/content/CarouselControls.css +61 -0
- package/templates/nova/src/components/content/CarouselControls.tsx +90 -0
- package/templates/nova/src/components/content/ContentsNav.css +16 -0
- package/templates/nova/src/components/content/ContentsNav.tsx +55 -0
- package/templates/nova/src/components/content/Countdown.css +24 -0
- package/templates/nova/src/components/content/Countdown.tsx +115 -0
- package/templates/nova/src/components/content/HeroCopy.css +92 -0
- package/templates/nova/src/components/content/HeroCopy.tsx +148 -0
- package/templates/nova/src/components/content/HeroFrame.css +75 -0
- package/templates/nova/src/components/content/HeroFrame.tsx +49 -0
- package/templates/nova/src/components/content/HeroMedia.css +40 -0
- package/templates/nova/src/components/content/HeroMedia.tsx +170 -0
- package/templates/nova/src/components/content/LongForm.css +40 -0
- package/templates/nova/src/components/content/LongForm.tsx +56 -0
- package/templates/nova/src/components/content/MediaFrame.css +5 -0
- package/templates/nova/src/components/content/MediaFrame.tsx +52 -0
- package/templates/nova/src/components/content/RichText.tsx +30 -0
- package/templates/nova/src/components/content/SectionHead.css +8 -0
- package/templates/nova/src/components/content/SectionHead.tsx +34 -0
- package/templates/nova/src/components/content/ShareButtons.css +2 -0
- package/templates/nova/src/components/content/ShareButtons.tsx +40 -0
- package/templates/nova/src/components/content/StoreCard.css +14 -0
- package/templates/nova/src/components/content/StoreCard.tsx +60 -0
- package/templates/nova/src/components/content/TestimonialCard.css +36 -0
- package/templates/nova/src/components/content/TestimonialCard.tsx +102 -0
- package/templates/nova/src/components/content/UgcTile.css +8 -0
- package/templates/nova/src/components/content/UgcTile.tsx +33 -0
- package/templates/nova/src/components/content/blocks/Button.tsx +36 -0
- package/templates/nova/src/components/content/blocks/Column.tsx +30 -0
- package/templates/nova/src/components/content/blocks/Heading.tsx +31 -0
- package/templates/nova/src/components/content/blocks/Icon.tsx +25 -0
- package/templates/nova/src/components/content/blocks/Image.tsx +42 -0
- package/templates/nova/src/components/content/blocks/Text.tsx +26 -0
- package/templates/nova/src/components/content/blocks/Video.tsx +44 -0
- package/templates/nova/src/components/content/blocks/content.css +25 -0
- package/templates/nova/src/components/content/blocks/shared.ts +5 -0
- package/templates/nova/src/components/forms/ContactForm.css +19 -0
- package/templates/nova/src/components/forms/ContactForm.tsx +139 -0
- package/templates/nova/src/components/forms/FormField.css +15 -0
- package/templates/nova/src/components/forms/FormField.tsx +77 -0
- package/templates/nova/src/components/forms/GatewayFields.tsx +79 -0
- package/templates/nova/src/components/forms/NewsletterForm.css +9 -0
- package/templates/nova/src/components/forms/NewsletterForm.tsx +141 -0
- package/templates/nova/src/components/forms/SearchField.css +7 -0
- package/templates/nova/src/components/forms/SearchField.tsx +68 -0
- package/templates/nova/src/components/forms/blocks/Newsletter.css +5 -0
- package/templates/nova/src/components/forms/blocks/Newsletter.tsx +71 -0
- package/templates/nova/src/components/forms/validate.ts +4 -0
- package/templates/nova/src/components/listing/ProductListing.tsx +200 -0
- package/templates/nova/src/components/navigation/BrandLogo.tsx +35 -0
- package/templates/nova/src/components/navigation/Breadcrumb.css +16 -0
- package/templates/nova/src/components/navigation/Breadcrumb.tsx +59 -0
- package/templates/nova/src/components/navigation/LineAddFriend.css +5 -0
- package/templates/nova/src/components/navigation/LineAddFriend.tsx +42 -0
- package/templates/nova/src/components/navigation/LocaleSelector.css +33 -0
- package/templates/nova/src/components/navigation/LocaleSelector.tsx +64 -0
- package/templates/nova/src/components/navigation/Menu.tsx +26 -0
- package/templates/nova/src/components/navigation/Pagination.css +24 -0
- package/templates/nova/src/components/navigation/Pagination.tsx +74 -0
- package/templates/nova/src/components/navigation/RecoveryLinks.css +8 -0
- package/templates/nova/src/components/navigation/RecoveryLinks.tsx +23 -0
- package/templates/nova/src/components/navigation/SocialLinks.css +5 -0
- package/templates/nova/src/components/navigation/SocialLinks.tsx +51 -0
- package/templates/nova/src/components/navigation/blocks/SocialLinks.tsx +23 -0
- package/templates/nova/src/components/overlays/AccountMenu.css +11 -0
- package/templates/nova/src/components/overlays/AccountMenu.tsx +91 -0
- package/templates/nova/src/components/overlays/CartDrawer.css +17 -0
- package/templates/nova/src/components/overlays/CartDrawer.tsx +118 -0
- package/templates/nova/src/components/overlays/ConfirmationDialog.tsx +49 -0
- package/templates/nova/src/components/overlays/CookieConsent.css +56 -0
- package/templates/nova/src/components/overlays/CookieConsent.tsx +170 -0
- package/templates/nova/src/components/overlays/Drawer.css +38 -0
- package/templates/nova/src/components/overlays/Drawer.tsx +66 -0
- package/templates/nova/src/components/overlays/FriendOfferPanel.tsx +79 -0
- package/templates/nova/src/components/overlays/MarketSelector.css +111 -0
- package/templates/nova/src/components/overlays/MarketSelector.tsx +450 -0
- package/templates/nova/src/components/overlays/Menu.css +9 -0
- package/templates/nova/src/components/overlays/Menu.tsx +124 -0
- package/templates/nova/src/components/overlays/MobileNavDrawer.css +28 -0
- package/templates/nova/src/components/overlays/MobileNavDrawer.tsx +166 -0
- package/templates/nova/src/components/overlays/Modal.css +52 -0
- package/templates/nova/src/components/overlays/Modal.tsx +88 -0
- package/templates/nova/src/components/overlays/Popover.css +4 -0
- package/templates/nova/src/components/overlays/Popover.tsx +115 -0
- package/templates/nova/src/components/overlays/ProductLightbox.css +20 -0
- package/templates/nova/src/components/overlays/ProductLightbox.tsx +70 -0
- package/templates/nova/src/components/overlays/PromoPopup.css +32 -0
- package/templates/nova/src/components/overlays/PromoPopup.tsx +198 -0
- package/templates/nova/src/components/overlays/QuickView.css +31 -0
- package/templates/nova/src/components/overlays/QuickView.tsx +127 -0
- package/templates/nova/src/components/overlays/ReferralPanel.css +16 -0
- package/templates/nova/src/components/overlays/ReferralPanel.tsx +138 -0
- package/templates/nova/src/components/overlays/RewardsLauncher.css +22 -0
- package/templates/nova/src/components/overlays/RewardsLauncher.tsx +270 -0
- package/templates/nova/src/components/overlays/SearchModal.css +48 -0
- package/templates/nova/src/components/overlays/SearchModal.tsx +302 -0
- package/templates/nova/src/components/overlays/Sheet.css +16 -0
- package/templates/nova/src/components/overlays/Sheet.tsx +48 -0
- package/templates/nova/src/components/overlays/SizeGuide.css +8 -0
- package/templates/nova/src/components/overlays/SizeGuide.tsx +74 -0
- package/templates/nova/src/components/overlays/Toast.css +20 -0
- package/templates/nova/src/components/overlays/Toast.tsx +164 -0
- package/templates/nova/src/components/overlays/Tooltip.css +6 -0
- package/templates/nova/src/components/overlays/Tooltip.tsx +59 -0
- package/templates/nova/src/components/overlays/use-dialog.ts +74 -0
- package/templates/nova/src/components/section/shared.css +42 -0
- package/templates/nova/src/components/section/shared.ts +120 -0
- package/templates/nova/src/components/section/shell.tsx +29 -0
- package/templates/nova/src/components/states/Alert.css +10 -0
- package/templates/nova/src/components/states/Alert.tsx +50 -0
- package/templates/nova/src/components/states/EditorFrame.css +31 -0
- package/templates/nova/src/components/states/EditorFrame.tsx +43 -0
- package/templates/nova/src/components/states/MediaState.css +1 -0
- package/templates/nova/src/components/states/MediaState.tsx +49 -0
- package/templates/nova/src/components/states/OfflineNotice.css +4 -0
- package/templates/nova/src/components/states/OfflineNotice.tsx +24 -0
- package/templates/nova/src/components/states/SkeletonLayout.css +22 -0
- package/templates/nova/src/components/states/SkeletonLayout.tsx +104 -0
- package/templates/nova/src/components/states/StateBlock.css +22 -0
- package/templates/nova/src/components/states/StateBlock.tsx +39 -0
- package/templates/nova/src/components/states/media/MediaError.css +6 -0
- package/templates/nova/src/components/states/media/MediaError.tsx +49 -0
- package/templates/nova/src/components/states/media/MediaPlaceholder.css +24 -0
- package/templates/nova/src/components/states/media/MediaPlaceholder.tsx +101 -0
- package/templates/nova/src/components/states/media/placeholder-art.ts +142 -0
- package/templates/nova/src/layouts/Main.tsx +80 -0
- package/templates/nova/src/sections/Account/Account.tsx +109 -0
- package/templates/nova/src/sections/Account/index.ts +22 -0
- package/templates/nova/src/sections/Account/presets.ts +6 -0
- package/templates/nova/src/sections/Account/schema.ts +29 -0
- package/templates/nova/src/sections/AnnouncementBar/AnnouncementBar.css +37 -0
- package/templates/nova/src/sections/AnnouncementBar/AnnouncementBar.tsx +151 -0
- package/templates/nova/src/sections/AnnouncementBar/index.ts +20 -0
- package/templates/nova/src/sections/AnnouncementBar/presets.ts +10 -0
- package/templates/nova/src/sections/AnnouncementBar/schema.ts +26 -0
- package/templates/nova/src/sections/ArticleBody/ArticleBody.tsx +129 -0
- package/templates/nova/src/sections/ArticleBody/index.ts +21 -0
- package/templates/nova/src/sections/ArticleBody/presets.ts +10 -0
- package/templates/nova/src/sections/ArticleBody/schema.ts +40 -0
- package/templates/nova/src/sections/BeforeAfter/BeforeAfter.tsx +47 -0
- package/templates/nova/src/sections/BeforeAfter/blocks/Comparison.tsx +20 -0
- package/templates/nova/src/sections/BeforeAfter/index.ts +28 -0
- package/templates/nova/src/sections/BeforeAfter/presets.ts +10 -0
- package/templates/nova/src/sections/BeforeAfter/schema.ts +34 -0
- package/templates/nova/src/sections/BlogPosts/BlogPosts.tsx +106 -0
- package/templates/nova/src/sections/BlogPosts/index.ts +30 -0
- package/templates/nova/src/sections/BlogPosts/presets.ts +10 -0
- package/templates/nova/src/sections/BlogPosts/schema.ts +42 -0
- package/templates/nova/src/sections/Breadcrumbs/Breadcrumbs.css +10 -0
- package/templates/nova/src/sections/Breadcrumbs/Breadcrumbs.tsx +41 -0
- package/templates/nova/src/sections/Breadcrumbs/index.ts +20 -0
- package/templates/nova/src/sections/Breadcrumbs/presets.ts +6 -0
- package/templates/nova/src/sections/Breadcrumbs/schema.ts +24 -0
- package/templates/nova/src/sections/CartItems/CartItems.tsx +170 -0
- package/templates/nova/src/sections/CartItems/blocks/CartBadge.tsx +14 -0
- package/templates/nova/src/sections/CartItems/index.ts +37 -0
- package/templates/nova/src/sections/CartItems/presets.ts +8 -0
- package/templates/nova/src/sections/CartItems/schema.ts +34 -0
- package/templates/nova/src/sections/CollectionBanner/CollectionBanner.tsx +120 -0
- package/templates/nova/src/sections/CollectionBanner/index.ts +25 -0
- package/templates/nova/src/sections/CollectionBanner/presets.ts +10 -0
- package/templates/nova/src/sections/CollectionBanner/schema.ts +37 -0
- package/templates/nova/src/sections/CollectionLinks/CollectionLinks.tsx +47 -0
- package/templates/nova/src/sections/CollectionLinks/index.ts +20 -0
- package/templates/nova/src/sections/CollectionLinks/presets.ts +8 -0
- package/templates/nova/src/sections/CollectionLinks/schema.ts +33 -0
- package/templates/nova/src/sections/CollectionList/CollectionList.tsx +89 -0
- package/templates/nova/src/sections/CollectionList/blocks/CollectionItem.tsx +25 -0
- package/templates/nova/src/sections/CollectionList/index.ts +33 -0
- package/templates/nova/src/sections/CollectionList/presets.ts +10 -0
- package/templates/nova/src/sections/CollectionList/schema.ts +41 -0
- package/templates/nova/src/sections/ComparisonTable/ComparisonTable.tsx +52 -0
- package/templates/nova/src/sections/ComparisonTable/blocks/CompareItem.tsx +26 -0
- package/templates/nova/src/sections/ComparisonTable/index.ts +31 -0
- package/templates/nova/src/sections/ComparisonTable/presets.ts +8 -0
- package/templates/nova/src/sections/ComparisonTable/schema.ts +31 -0
- package/templates/nova/src/sections/ContactForm/ContactForm.tsx +83 -0
- package/templates/nova/src/sections/ContactForm/blocks/ContactDetail.tsx +13 -0
- package/templates/nova/src/sections/ContactForm/index.ts +29 -0
- package/templates/nova/src/sections/ContactForm/presets.ts +8 -0
- package/templates/nova/src/sections/ContactForm/schema.ts +34 -0
- package/templates/nova/src/sections/Divider/Divider.css +17 -0
- package/templates/nova/src/sections/Divider/Divider.tsx +21 -0
- package/templates/nova/src/sections/Divider/index.ts +20 -0
- package/templates/nova/src/sections/Divider/presets.ts +10 -0
- package/templates/nova/src/sections/Divider/schema.ts +24 -0
- package/templates/nova/src/sections/Faq/Faq.tsx +51 -0
- package/templates/nova/src/sections/Faq/blocks/FaqItem.tsx +13 -0
- package/templates/nova/src/sections/Faq/index.ts +28 -0
- package/templates/nova/src/sections/Faq/presets.ts +8 -0
- package/templates/nova/src/sections/Faq/schema.ts +32 -0
- package/templates/nova/src/sections/FeatureGridBlocks/FeatureGridBlocks.tsx +90 -0
- package/templates/nova/src/sections/FeatureGridBlocks/index.ts +35 -0
- package/templates/nova/src/sections/FeatureGridBlocks/presets.ts +8 -0
- package/templates/nova/src/sections/FeatureGridBlocks/schema.ts +35 -0
- package/templates/nova/src/sections/FeatureHighlights/FeatureHighlights.tsx +56 -0
- package/templates/nova/src/sections/FeatureHighlights/index.ts +20 -0
- package/templates/nova/src/sections/FeatureHighlights/presets.ts +6 -0
- package/templates/nova/src/sections/FeatureHighlights/schema.ts +27 -0
- package/templates/nova/src/sections/FeaturedCollection/FeaturedCollection.tsx +67 -0
- package/templates/nova/src/sections/FeaturedCollection/index.ts +21 -0
- package/templates/nova/src/sections/FeaturedCollection/presets.ts +10 -0
- package/templates/nova/src/sections/FeaturedCollection/schema.ts +39 -0
- package/templates/nova/src/sections/FeaturedProduct/FeaturedProduct.tsx +107 -0
- package/templates/nova/src/sections/FeaturedProduct/index.ts +23 -0
- package/templates/nova/src/sections/FeaturedProduct/presets.ts +8 -0
- package/templates/nova/src/sections/FeaturedProduct/schema.ts +35 -0
- package/templates/nova/src/sections/Footer/Footer.css +81 -0
- package/templates/nova/src/sections/Footer/Footer.tsx +256 -0
- package/templates/nova/src/sections/Footer/blocks/FooterBrand.tsx +40 -0
- package/templates/nova/src/sections/Footer/blocks/FooterLine.tsx +11 -0
- package/templates/nova/src/sections/Footer/blocks/FooterMenu.tsx +14 -0
- package/templates/nova/src/sections/Footer/blocks/FooterText.tsx +8 -0
- package/templates/nova/src/sections/Footer/blocks/footer.css +7 -0
- package/templates/nova/src/sections/Footer/index.ts +38 -0
- package/templates/nova/src/sections/Footer/presets.ts +10 -0
- package/templates/nova/src/sections/Footer/schema.ts +27 -0
- package/templates/nova/src/sections/Group/Group.css +59 -0
- package/templates/nova/src/sections/Group/Group.tsx +167 -0
- package/templates/nova/src/sections/Group/blocks/Accordion.tsx +26 -0
- package/templates/nova/src/sections/Group/blocks/JumboText.tsx +20 -0
- package/templates/nova/src/sections/Group/blocks/Spacer.tsx +16 -0
- package/templates/nova/src/sections/Group/index.ts +36 -0
- package/templates/nova/src/sections/Group/presets.ts +12 -0
- package/templates/nova/src/sections/Group/schema.ts +35 -0
- package/templates/nova/src/sections/Header/Header.css +185 -0
- package/templates/nova/src/sections/Header/Header.tsx +478 -0
- package/templates/nova/src/sections/Header/index.ts +32 -0
- package/templates/nova/src/sections/Header/presets.ts +10 -0
- package/templates/nova/src/sections/Header/schema.ts +32 -0
- package/templates/nova/src/sections/Hero/Hero.tsx +128 -0
- package/templates/nova/src/sections/Hero/index.ts +24 -0
- package/templates/nova/src/sections/Hero/presets.ts +16 -0
- package/templates/nova/src/sections/Hero/schema.ts +56 -0
- package/templates/nova/src/sections/ImageGallery/ImageGallery.tsx +86 -0
- package/templates/nova/src/sections/ImageGallery/index.ts +28 -0
- package/templates/nova/src/sections/ImageGallery/presets.ts +10 -0
- package/templates/nova/src/sections/ImageGallery/schema.ts +34 -0
- package/templates/nova/src/sections/ImageWithText/ImageWithText.tsx +62 -0
- package/templates/nova/src/sections/ImageWithText/index.ts +23 -0
- package/templates/nova/src/sections/ImageWithText/presets.ts +12 -0
- package/templates/nova/src/sections/ImageWithText/schema.ts +45 -0
- package/templates/nova/src/sections/LineAddFriend/LineAddFriend.tsx +25 -0
- package/templates/nova/src/sections/LineAddFriend/index.ts +20 -0
- package/templates/nova/src/sections/LineAddFriend/presets.ts +3 -0
- package/templates/nova/src/sections/LineAddFriend/schema.ts +25 -0
- package/templates/nova/src/sections/LogoList/LogoList.tsx +40 -0
- package/templates/nova/src/sections/LogoList/blocks/Logo.tsx +18 -0
- package/templates/nova/src/sections/LogoList/index.ts +29 -0
- package/templates/nova/src/sections/LogoList/presets.ts +8 -0
- package/templates/nova/src/sections/LogoList/schema.ts +29 -0
- package/templates/nova/src/sections/MainCollection/MainCollection.tsx +51 -0
- package/templates/nova/src/sections/MainCollection/index.ts +26 -0
- package/templates/nova/src/sections/MainCollection/presets.ts +10 -0
- package/templates/nova/src/sections/MainCollection/schema.ts +29 -0
- package/templates/nova/src/sections/Marquee/Marquee.tsx +114 -0
- package/templates/nova/src/sections/Marquee/index.ts +20 -0
- package/templates/nova/src/sections/Marquee/presets.ts +10 -0
- package/templates/nova/src/sections/Marquee/schema.ts +23 -0
- package/templates/nova/src/sections/Multicolumn/Multicolumn.tsx +56 -0
- package/templates/nova/src/sections/Multicolumn/index.ts +25 -0
- package/templates/nova/src/sections/Multicolumn/presets.ts +8 -0
- package/templates/nova/src/sections/Multicolumn/schema.ts +34 -0
- package/templates/nova/src/sections/Newsletter/Newsletter.tsx +64 -0
- package/templates/nova/src/sections/Newsletter/index.ts +20 -0
- package/templates/nova/src/sections/Newsletter/presets.ts +10 -0
- package/templates/nova/src/sections/Newsletter/schema.ts +36 -0
- package/templates/nova/src/sections/NotFound/NotFound.tsx +41 -0
- package/templates/nova/src/sections/NotFound/index.ts +20 -0
- package/templates/nova/src/sections/NotFound/presets.ts +6 -0
- package/templates/nova/src/sections/NotFound/schema.ts +30 -0
- package/templates/nova/src/sections/PageBody/PageBody.tsx +35 -0
- package/templates/nova/src/sections/PageBody/index.ts +21 -0
- package/templates/nova/src/sections/PageBody/presets.ts +6 -0
- package/templates/nova/src/sections/PageBody/schema.ts +29 -0
- package/templates/nova/src/sections/PolicyPage/PolicyPage.tsx +62 -0
- package/templates/nova/src/sections/PolicyPage/index.ts +23 -0
- package/templates/nova/src/sections/PolicyPage/presets.ts +6 -0
- package/templates/nova/src/sections/PolicyPage/schema.ts +27 -0
- package/templates/nova/src/sections/ProductDetails/ProductDetails.tsx +269 -0
- package/templates/nova/src/sections/ProductDetails/blocks/AddToCartBlock.tsx +15 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductDescription.tsx +15 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductInventory.tsx +38 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductPrice.tsx +19 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductSku.tsx +15 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductTitle.tsx +17 -0
- package/templates/nova/src/sections/ProductDetails/blocks/Quantity.tsx +14 -0
- package/templates/nova/src/sections/ProductDetails/blocks/Tab.tsx +23 -0
- package/templates/nova/src/sections/ProductDetails/blocks/VariantPickerBlock.tsx +44 -0
- package/templates/nova/src/sections/ProductDetails/blocks/commerce-blocks.css +13 -0
- package/templates/nova/src/sections/ProductDetails/index.ts +44 -0
- package/templates/nova/src/sections/ProductDetails/presets.ts +10 -0
- package/templates/nova/src/sections/ProductDetails/schema.ts +44 -0
- package/templates/nova/src/sections/ProductGrid/ProductGrid.tsx +38 -0
- package/templates/nova/src/sections/ProductGrid/index.ts +25 -0
- package/templates/nova/src/sections/ProductGrid/presets.ts +6 -0
- package/templates/nova/src/sections/ProductGrid/schema.ts +37 -0
- package/templates/nova/src/sections/ProductRecommendations/ProductRecommendations.tsx +45 -0
- package/templates/nova/src/sections/ProductRecommendations/index.ts +20 -0
- package/templates/nova/src/sections/ProductRecommendations/presets.ts +8 -0
- package/templates/nova/src/sections/ProductRecommendations/schema.ts +28 -0
- package/templates/nova/src/sections/ProductReviews/ProductReviews.tsx +136 -0
- package/templates/nova/src/sections/ProductReviews/index.ts +22 -0
- package/templates/nova/src/sections/ProductReviews/presets.ts +6 -0
- package/templates/nova/src/sections/ProductReviews/schema.ts +31 -0
- package/templates/nova/src/sections/PromoBanner/PromoBanner.tsx +78 -0
- package/templates/nova/src/sections/PromoBanner/index.ts +20 -0
- package/templates/nova/src/sections/PromoBanner/presets.ts +10 -0
- package/templates/nova/src/sections/PromoBanner/schema.ts +38 -0
- package/templates/nova/src/sections/RecentlyViewed/RecentlyViewed.tsx +53 -0
- package/templates/nova/src/sections/RecentlyViewed/index.ts +20 -0
- package/templates/nova/src/sections/RecentlyViewed/presets.ts +6 -0
- package/templates/nova/src/sections/RecentlyViewed/schema.ts +26 -0
- package/templates/nova/src/sections/RichText/RichText.tsx +38 -0
- package/templates/nova/src/sections/RichText/index.ts +20 -0
- package/templates/nova/src/sections/RichText/presets.ts +10 -0
- package/templates/nova/src/sections/RichText/schema.ts +37 -0
- package/templates/nova/src/sections/SearchResults/SearchResults.tsx +112 -0
- package/templates/nova/src/sections/SearchResults/index.ts +26 -0
- package/templates/nova/src/sections/SearchResults/presets.ts +8 -0
- package/templates/nova/src/sections/SearchResults/schema.ts +30 -0
- package/templates/nova/src/sections/ShopTheLook/ShopTheLook.tsx +112 -0
- package/templates/nova/src/sections/ShopTheLook/blocks/Hotspot.tsx +22 -0
- package/templates/nova/src/sections/ShopTheLook/index.ts +33 -0
- package/templates/nova/src/sections/ShopTheLook/presets.ts +8 -0
- package/templates/nova/src/sections/ShopTheLook/schema.ts +31 -0
- package/templates/nova/src/sections/Slideshow/Slideshow.tsx +199 -0
- package/templates/nova/src/sections/Slideshow/blocks/Slide.tsx +93 -0
- package/templates/nova/src/sections/Slideshow/index.ts +30 -0
- package/templates/nova/src/sections/Slideshow/presets.ts +10 -0
- package/templates/nova/src/sections/Slideshow/schema.ts +36 -0
- package/templates/nova/src/sections/StoreLocator/StoreLocator.tsx +66 -0
- package/templates/nova/src/sections/StoreLocator/index.ts +20 -0
- package/templates/nova/src/sections/StoreLocator/presets.ts +6 -0
- package/templates/nova/src/sections/StoreLocator/schema.ts +34 -0
- package/templates/nova/src/sections/TeamFounders/TeamFounders.tsx +74 -0
- package/templates/nova/src/sections/TeamFounders/blocks/Person.tsx +28 -0
- package/templates/nova/src/sections/TeamFounders/index.ts +28 -0
- package/templates/nova/src/sections/TeamFounders/presets.ts +10 -0
- package/templates/nova/src/sections/TeamFounders/schema.ts +36 -0
- package/templates/nova/src/sections/Testimonials/Testimonials.tsx +83 -0
- package/templates/nova/src/sections/Testimonials/blocks/Testimonial.tsx +30 -0
- package/templates/nova/src/sections/Testimonials/index.ts +29 -0
- package/templates/nova/src/sections/Testimonials/presets.ts +10 -0
- package/templates/nova/src/sections/Testimonials/schema.ts +35 -0
- package/templates/nova/src/sections/Timeline/Timeline.tsx +43 -0
- package/templates/nova/src/sections/Timeline/blocks/Step.tsx +19 -0
- package/templates/nova/src/sections/Timeline/index.ts +28 -0
- package/templates/nova/src/sections/Timeline/presets.ts +8 -0
- package/templates/nova/src/sections/Timeline/schema.ts +31 -0
- package/templates/nova/src/sections/TrustBadges/TrustBadges.tsx +42 -0
- package/templates/nova/src/sections/TrustBadges/index.ts +29 -0
- package/templates/nova/src/sections/TrustBadges/presets.ts +8 -0
- package/templates/nova/src/sections/TrustBadges/schema.ts +29 -0
- package/templates/nova/src/sections/UgcGallery/UgcGallery.tsx +58 -0
- package/templates/nova/src/sections/UgcGallery/blocks/UgcImage.tsx +27 -0
- package/templates/nova/src/sections/UgcGallery/index.ts +31 -0
- package/templates/nova/src/sections/UgcGallery/presets.ts +8 -0
- package/templates/nova/src/sections/UgcGallery/schema.ts +35 -0
- package/templates/nova/src/sections/VideoHero/VideoHero.tsx +75 -0
- package/templates/nova/src/sections/VideoHero/index.ts +22 -0
- package/templates/nova/src/sections/VideoHero/presets.ts +8 -0
- package/templates/nova/src/sections/VideoHero/schema.ts +43 -0
- package/templates/nova/src/sections/data.ts +115 -0
- package/templates/nova/src/sections/shipped-copy.ts +25 -0
- package/templates/nova/src/sections/starter.ts +49 -0
- package/templates/nova/src/styles/Container.css +6 -0
- package/templates/nova/src/styles/Container.tsx +13 -0
- package/templates/nova/src/styles/Icon.css +2 -0
- package/templates/nova/src/styles/Icon.tsx +101 -0
- package/templates/nova/src/styles/NovaProvider.tsx +91 -0
- package/templates/nova/src/styles/base.css +142 -0
- package/templates/nova/src/styles/blocks.css +6 -0
- package/templates/nova/src/styles/fonts/OFL.txt +93 -0
- package/templates/nova/src/styles/fonts/geist-cyrillic-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-cyrillic.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-latin-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-latin.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-cyrillic-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-cyrillic.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-latin-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-latin.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-vietnamese.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-vietnamese.woff2 +0 -0
- package/templates/nova/src/styles/fonts.css +95 -0
- package/templates/nova/src/styles/global-settings.css +88 -0
- package/templates/nova/src/styles/index.css +6 -0
- package/templates/nova/src/styles/motion.ts +53 -0
- package/templates/nova/src/styles/scroll.ts +24 -0
- package/templates/nova/src/styles/sections/commerce.css +147 -0
- package/templates/nova/src/styles/sections/content.css +304 -0
- package/templates/nova/src/styles/sections/editorial.css +131 -0
- package/templates/nova/src/styles/sections/promotion.css +336 -0
- package/templates/nova/src/styles/sections/trust.css +117 -0
- package/templates/nova/src/styles/sections/utility.css +190 -0
- package/templates/nova/src/styles/strings.ts +492 -0
- package/templates/nova/src/styles/text.ts +4 -0
- package/templates/nova/src/styles/theme.ts +171 -0
- package/templates/nova/src/styles/tokens.css +600 -0
- package/templates/nova/src/styles/viewport.ts +23 -0
- package/templates/nova/template.json +94 -0
- package/templates/nova/templates/404.json +30 -0
- package/templates/nova/templates/account.json +15 -0
- package/templates/nova/templates/article.json +41 -0
- package/templates/nova/templates/article.longform.json +17 -0
- package/templates/nova/templates/blog.featured.json +22 -0
- package/templates/nova/templates/blog.json +29 -0
- package/templates/nova/templates/cart.json +67 -0
- package/templates/nova/templates/collection.featured.json +43 -0
- package/templates/nova/templates/collection.json +30 -0
- package/templates/nova/templates/contact.json +65 -0
- package/templates/nova/templates/index.json +167 -0
- package/templates/nova/templates/list-collections.json +19 -0
- package/templates/nova/templates/page.about.json +134 -0
- package/templates/nova/templates/page.contact.json +27 -0
- package/templates/nova/templates/page.json +27 -0
- package/templates/nova/templates/policy.json +23 -0
- package/templates/nova/templates/product.bundle.json +145 -0
- package/templates/nova/templates/product.json +119 -0
- package/templates/nova/templates/search.json +17 -0
- package/templates/nova/tests/abi-ai-contract.test.ts +99 -0
- package/templates/nova/tests/abi-forms.test.tsx +269 -0
- package/templates/nova/tests/abi-inventory.test.tsx +197 -0
- package/templates/nova/tests/abi-legacy-settings.test.tsx +105 -0
- package/templates/nova/tests/abi-opt-in.test.tsx +100 -0
- package/templates/nova/tests/abi-parity.test.tsx +95 -0
- package/templates/nova/tests/abi-r5-store-settings.test.tsx +337 -0
- package/templates/nova/tests/abi-render.test.tsx +178 -0
- package/templates/nova/tests/abi-shop-links.test.tsx +141 -0
- package/templates/nova/tests/abi-storefront-basics.test.tsx +233 -0
- package/templates/nova/tests/abi-variant-url.test.tsx +73 -0
- package/templates/nova/tests/add-refused-no-success.test.tsx +193 -0
- package/templates/nova/tests/architecture.test.ts +63 -0
- package/templates/nova/tests/architecture.ts +160 -0
- package/templates/nova/tests/audit-guards.test.ts +31 -0
- package/templates/nova/tests/bundle-split.test.ts +29 -0
- package/templates/nova/tests/cart-limit-message.test.tsx +212 -0
- package/templates/nova/tests/cart-link-message.test.tsx +98 -0
- package/templates/nova/tests/cases/components/Overview.cases.tsx +8 -0
- package/templates/nova/tests/cases/components/base/Accordion.cases.tsx +40 -0
- package/templates/nova/tests/cases/components/base/Badge.cases.tsx +30 -0
- package/templates/nova/tests/cases/components/base/Button.cases.tsx +73 -0
- package/templates/nova/tests/cases/components/base/Checkbox.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/base/Chip.cases.tsx +37 -0
- package/templates/nova/tests/cases/components/base/Divider.cases.tsx +26 -0
- package/templates/nova/tests/cases/components/base/IconButton.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/base/Input.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/base/Link.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/base/Radio.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/base/Select.cases.tsx +26 -0
- package/templates/nova/tests/cases/components/base/Skeleton.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/base/Spinner.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/base/Switch.cases.tsx +26 -0
- package/templates/nova/tests/cases/components/base/Tabs.cases.tsx +39 -0
- package/templates/nova/tests/cases/components/base/Textarea.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/commerce/AddToCart.cases.tsx +36 -0
- package/templates/nova/tests/cases/components/commerce/CartLine.cases.tsx +20 -0
- package/templates/nova/tests/cases/components/commerce/CartSummary.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/commerce/CollectionCard.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/commerce/ComparisonTable.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/commerce/Hotspot.cases.tsx +25 -0
- package/templates/nova/tests/cases/components/commerce/LookItem.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/commerce/PaymentMark.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/commerce/Price.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/commerce/ProductCard.cases.tsx +67 -0
- package/templates/nova/tests/cases/components/commerce/ProductGallery.cases.tsx +39 -0
- package/templates/nova/tests/cases/components/commerce/QuantitySelector.cases.tsx +31 -0
- package/templates/nova/tests/cases/components/commerce/Reviews.cases.tsx +35 -0
- package/templates/nova/tests/cases/components/commerce/Stars.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/commerce/VariantPicker.cases.tsx +38 -0
- package/templates/nova/tests/cases/components/commerce/blocks/Badge.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/commerce/blocks/PaymentIcons.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/commerce/blocks/Swatches.cases.tsx +22 -0
- package/templates/nova/tests/cases/components/content/ArticleCard.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/BeforeAfterSlider.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/CardRow.cases.tsx +23 -0
- package/templates/nova/tests/cases/components/content/CarouselControls.cases.tsx +48 -0
- package/templates/nova/tests/cases/components/content/ContentsNav.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/Countdown.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/content/HeroCopy.cases.tsx +42 -0
- package/templates/nova/tests/cases/components/content/HeroFrame.cases.tsx +22 -0
- package/templates/nova/tests/cases/components/content/HeroMedia.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/LongForm.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/MediaFrame.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/content/RichText.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/content/SectionHead.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/content/ShareButtons.cases.tsx +24 -0
- package/templates/nova/tests/cases/components/content/StoreCard.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/TestimonialCard.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/content/UgcTile.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/blocks/Button.cases.tsx +20 -0
- package/templates/nova/tests/cases/components/content/blocks/Column.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/blocks/Heading.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/blocks/Icon.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/blocks/Image.cases.tsx +22 -0
- package/templates/nova/tests/cases/components/content/blocks/Text.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/blocks/Video.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/forms/ContactForm.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/forms/FormField.cases.tsx +61 -0
- package/templates/nova/tests/cases/components/forms/NewsletterForm.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/forms/SearchField.cases.tsx +25 -0
- package/templates/nova/tests/cases/components/forms/blocks/Newsletter.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/navigation/BrandLogo.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/navigation/Breadcrumb.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/navigation/LocaleSelector.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/navigation/Menu.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/navigation/Pagination.cases.tsx +25 -0
- package/templates/nova/tests/cases/components/navigation/RecoveryLinks.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/navigation/SocialLinks.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/navigation/blocks/SocialLinks.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/overlays/AccountMenu.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/overlays/CartDrawer.cases.tsx +30 -0
- package/templates/nova/tests/cases/components/overlays/ConfirmationDialog.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/overlays/CookieConsent.cases.tsx +23 -0
- package/templates/nova/tests/cases/components/overlays/CookiePreferences.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/overlays/Drawer.cases.tsx +52 -0
- package/templates/nova/tests/cases/components/overlays/MarketSelector.cases.tsx +82 -0
- package/templates/nova/tests/cases/components/overlays/Menu.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/overlays/MobileNavDrawer.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/overlays/Modal.cases.tsx +71 -0
- package/templates/nova/tests/cases/components/overlays/Popover.cases.tsx +50 -0
- package/templates/nova/tests/cases/components/overlays/PromoPopup.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/overlays/QuickView.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/overlays/SearchModal.cases.tsx +60 -0
- package/templates/nova/tests/cases/components/overlays/Sheet.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/overlays/SizeGuide.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/overlays/Toast.cases.tsx +48 -0
- package/templates/nova/tests/cases/components/overlays/Tooltip.cases.tsx +33 -0
- package/templates/nova/tests/cases/components/states/Alert.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/states/EditorFrame.cases.tsx +36 -0
- package/templates/nova/tests/cases/components/states/Empty.cases.tsx +30 -0
- package/templates/nova/tests/cases/components/states/Error.cases.tsx +38 -0
- package/templates/nova/tests/cases/components/states/Loading.cases.tsx +15 -0
- package/templates/nova/tests/cases/components/states/MediaState.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/states/SkeletonLayout.cases.tsx +20 -0
- package/templates/nova/tests/cases/components/states/Unavailable.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/states/media/MediaError.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/states/media/MediaPlaceholder.cases.tsx +87 -0
- package/templates/nova/tests/cases/sections/Overview.cases.tsx +8 -0
- package/templates/nova/tests/cases/sections/commerce/collection-list/CollectionList.cases.tsx +46 -0
- package/templates/nova/tests/cases/sections/commerce/collection-list/blocks/CollectionItem.cases.tsx +18 -0
- package/templates/nova/tests/cases/sections/commerce/featured-collection/FeaturedCollection.cases.tsx +46 -0
- package/templates/nova/tests/cases/sections/commerce/featured-product/FeaturedProduct.cases.tsx +40 -0
- package/templates/nova/tests/cases/sections/commerce/main-collection/MainCollection.cases.tsx +81 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/ProductDetails.cases.tsx +110 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/AddToCartBlock.cases.tsx +21 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductDescription.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductInventory.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductPrice.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductSku.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductTitle.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/Quantity.cases.tsx +20 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/Tab.cases.tsx +29 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/VariantPickerBlock.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/commerce/product-grid/ProductGrid.cases.tsx +48 -0
- package/templates/nova/tests/cases/sections/commerce/product-recommendations/ProductRecommendations.cases.tsx +27 -0
- package/templates/nova/tests/cases/sections/commerce/recently-viewed/RecentlyViewed.cases.tsx +36 -0
- package/templates/nova/tests/cases/sections/content/article-body/ArticleBody.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/content/before-after/BeforeAfter.cases.tsx +40 -0
- package/templates/nova/tests/cases/sections/content/before-after/blocks/Comparison.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/content/blog-posts/BlogPosts.cases.tsx +47 -0
- package/templates/nova/tests/cases/sections/content/collection-links/CollectionLinks.cases.tsx +36 -0
- package/templates/nova/tests/cases/sections/content/faq/Faq.cases.tsx +38 -0
- package/templates/nova/tests/cases/sections/content/faq/blocks/FaqItem.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/content/feature-grid-blocks/FeatureGridBlocks.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/feature-highlights/FeatureHighlights.cases.tsx +26 -0
- package/templates/nova/tests/cases/sections/content/image-gallery/ImageGallery.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/image-with-text/ImageWithText.cases.tsx +35 -0
- package/templates/nova/tests/cases/sections/content/multicolumn/Multicolumn.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/content/page-body/PageBody.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/rich-text/RichTextSection.cases.tsx +33 -0
- package/templates/nova/tests/cases/sections/content/team-founders/TeamFounders.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/team-founders/blocks/Person.cases.tsx +18 -0
- package/templates/nova/tests/cases/sections/content/timeline/Timeline.cases.tsx +27 -0
- package/templates/nova/tests/cases/sections/content/timeline/blocks/Step.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/layout/announcement-bar/AnnouncementBar.cases.tsx +119 -0
- package/templates/nova/tests/cases/sections/layout/breadcrumbs/Breadcrumbs.cases.tsx +73 -0
- package/templates/nova/tests/cases/sections/layout/divider/Divider.cases.tsx +81 -0
- package/templates/nova/tests/cases/sections/layout/footer/Footer.cases.tsx +116 -0
- package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterBrand.cases.tsx +27 -0
- package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterMenu.cases.tsx +22 -0
- package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterText.cases.tsx +20 -0
- package/templates/nova/tests/cases/sections/layout/group/Group.cases.tsx +185 -0
- package/templates/nova/tests/cases/sections/layout/group/blocks/Accordion.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/layout/group/blocks/JumboText.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/layout/group/blocks/Spacer.cases.tsx +33 -0
- package/templates/nova/tests/cases/sections/layout/header/Header.cases.tsx +277 -0
- package/templates/nova/tests/cases/sections/marketing/collection-banner/CollectionBanner.cases.tsx +62 -0
- package/templates/nova/tests/cases/sections/marketing/hero/Hero.cases.tsx +138 -0
- package/templates/nova/tests/cases/sections/marketing/marquee/Marquee.cases.tsx +63 -0
- package/templates/nova/tests/cases/sections/marketing/promo-banner/PromoBanner.cases.tsx +87 -0
- package/templates/nova/tests/cases/sections/marketing/slideshow/Slideshow.cases.tsx +113 -0
- package/templates/nova/tests/cases/sections/marketing/slideshow/blocks/Slide.cases.tsx +26 -0
- package/templates/nova/tests/cases/sections/marketing/video-hero/VideoHero.cases.tsx +72 -0
- package/templates/nova/tests/cases/sections/trust/comparison-table/ComparisonTableSection.cases.tsx +42 -0
- package/templates/nova/tests/cases/sections/trust/comparison-table/blocks/CompareItem.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/logo-list/LogoList.cases.tsx +29 -0
- package/templates/nova/tests/cases/sections/trust/logo-list/blocks/Logo.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/product-reviews/ProductReviews.cases.tsx +51 -0
- package/templates/nova/tests/cases/sections/trust/shop-the-look/ShopTheLook.cases.tsx +51 -0
- package/templates/nova/tests/cases/sections/trust/shop-the-look/blocks/Hotspot.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/testimonials/Testimonials.cases.tsx +61 -0
- package/templates/nova/tests/cases/sections/trust/testimonials/blocks/Testimonial.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/trust-badges/TrustBadges.cases.tsx +30 -0
- package/templates/nova/tests/cases/sections/trust/ugc-gallery/UgcGallery.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/trust/ugc-gallery/blocks/UgcImage.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/utility/account/Account.cases.tsx +44 -0
- package/templates/nova/tests/cases/sections/utility/cart-items/CartItems.cases.tsx +43 -0
- package/templates/nova/tests/cases/sections/utility/cart-items/blocks/CartBadge.cases.tsx +16 -0
- package/templates/nova/tests/cases/sections/utility/contact-form/ContactFormSection.cases.tsx +52 -0
- package/templates/nova/tests/cases/sections/utility/contact-form/blocks/ContactDetail.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/utility/newsletter/NewsletterSection.cases.tsx +109 -0
- package/templates/nova/tests/cases/sections/utility/not-found/NotFound.cases.tsx +28 -0
- package/templates/nova/tests/cases/sections/utility/policy-page/PolicyPage.cases.tsx +29 -0
- package/templates/nova/tests/cases/sections/utility/search-results/SearchResultsSection.cases.tsx +39 -0
- package/templates/nova/tests/cases/sections/utility/store-locator/StoreLocator.cases.tsx +40 -0
- package/templates/nova/tests/cases/styles/Borders.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Breakpoints.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Colors.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Elevation.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Icon.cases.tsx +23 -0
- package/templates/nova/tests/cases/styles/Layout.cases.tsx +8 -0
- package/templates/nova/tests/cases/styles/Motion.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Overview.cases.tsx +8 -0
- package/templates/nova/tests/cases/styles/Radius.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/SharedThemeSettings.cases.tsx +19 -0
- package/templates/nova/tests/cases/styles/Spacing.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Typography.cases.tsx +10 -0
- package/templates/nova/tests/cases.test.tsx +38 -0
- package/templates/nova/tests/components/PromoPopup.test.ts +21 -0
- package/templates/nova/tests/components/RichText.test.tsx +65 -0
- package/templates/nova/tests/components/formatDate.test.ts +10 -0
- package/templates/nova/tests/contract-locks.test.ts +23 -0
- package/templates/nova/tests/contracts.test.ts +153 -0
- package/templates/nova/tests/cookie-consent-privacy.test.tsx +128 -0
- package/templates/nova/tests/empty-store.test.tsx +81 -0
- package/templates/nova/tests/fixtures/commerce.ts +128 -0
- package/templates/nova/tests/fixtures/content.ts +58 -0
- package/templates/nova/tests/fixtures/index.ts +8 -0
- package/templates/nova/tests/fixtures/merch.ts +161 -0
- package/templates/nova/tests/fixtures/navigation.ts +125 -0
- package/templates/nova/tests/fixtures/promotion.ts +43 -0
- package/templates/nova/tests/fixtures/sample-store.json +1674 -0
- package/templates/nova/tests/fixtures/shop.ts +88 -0
- package/templates/nova/tests/fixtures/stress.ts +21 -0
- package/templates/nova/tests/inert.test.tsx +285 -0
- package/templates/nova/tests/line-add-friend.test.tsx +108 -0
- package/templates/nova/tests/localized-copy.test.ts +330 -0
- package/templates/nova/tests/product-template-blocks.test.ts +28 -0
- package/templates/nova/tests/rewards-launcher.test.tsx +401 -0
- package/templates/nova/tests/schema.test.ts +65 -0
- package/templates/nova/tests/schema.typetest.ts +7 -0
- package/templates/nova/tests/section-groups.test.ts +189 -0
- package/templates/nova/tests/sections/Group.test.tsx +37 -0
- package/templates/nova/tests/setup.ts +30 -0
- package/templates/nova/tests/starter.test.ts +56 -0
- package/templates/nova/tests/storefront-click-path.test.tsx +157 -0
- package/templates/nova/tests/styles/button-brand.test.ts +24 -0
- package/templates/nova/tests/styles/theme.test.ts +43 -0
- package/templates/nova/tests/styles/tokens.test.ts +35 -0
- package/templates/nova/tests/support/abi-ctx.ts +136 -0
- package/templates/nova/tests/support/block-stories.tsx +13 -0
- package/templates/nova/tests/support/case.tsx +102 -0
- package/templates/nova/tests/support/contracts.ts +30 -0
- package/templates/nova/tests/support/foundation-pages.tsx +260 -0
- package/templates/nova/tests/support/ia-pages.tsx +154 -0
- package/templates/nova/tests/support/listing-demo.tsx +29 -0
- package/templates/nova/tests/support/presets.ts +14 -0
- package/templates/nova/tests/support/sections.ts +36 -0
- package/templates/nova/tests/support/story-content.ts +321 -0
- package/templates/nova/tests/support/story-helpers.tsx +37 -0
- package/templates/nova/tests/support/with-nova.tsx +26 -0
- package/templates/nova/tests/theme-config.test.ts +82 -0
- package/templates/nova/tests/theme-integrity.test.ts +315 -0
- package/templates/nova/theme.config.ts +134 -0
- package/templates/nova/theme.manifest.json +17495 -0
- package/templates/nova/tsconfig.json +19 -0
- package/templates/nova/vite.abi-ssr.config.ts +37 -0
- package/templates/nova/vite.abi.config.ts +26 -0
- package/templates/nova/vitest.config.ts +20 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { placeholderImage, type PlaceholderFamily } from '../../src/components/states/media/MediaPlaceholder'
|
|
2
|
+
import type { Cart, Collection, Money, NovaImage, Product, ProductVariant, SearchResults } from '@tanqory/theme-kit'
|
|
3
|
+
|
|
4
|
+
const THB = (amount: number): Money => ({ amount, currencyCode: 'THB' })
|
|
5
|
+
|
|
6
|
+
interface Spec {
|
|
7
|
+
handle: string
|
|
8
|
+
title: string
|
|
9
|
+
price: number
|
|
10
|
+
compareAt?: number
|
|
11
|
+
vendor?: string
|
|
12
|
+
type: string
|
|
13
|
+
options?: { name: string; values: string[] }[]
|
|
14
|
+
soldOut?: boolean
|
|
15
|
+
lowStock?: number
|
|
16
|
+
badge?: string | null
|
|
17
|
+
image?: NovaImage | null
|
|
18
|
+
images?: NovaImage[]
|
|
19
|
+
rating?: { value: number; count: number }
|
|
20
|
+
description?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let seq = 0
|
|
24
|
+
function variantsFor(s: Spec): ProductVariant[] {
|
|
25
|
+
const opts = s.options ?? []
|
|
26
|
+
const combos: { name: string; value: string }[][] = opts.reduce<{ name: string; value: string }[][]>(
|
|
27
|
+
(acc, o) => acc.flatMap((c) => o.values.map((v) => [...c, { name: o.name, value: v }])),
|
|
28
|
+
[[]],
|
|
29
|
+
)
|
|
30
|
+
return combos.map((sel, i) => ({
|
|
31
|
+
id: `gid://variant/${++seq}`,
|
|
32
|
+
title: sel.length ? sel.map((x) => x.value).join(' / ') : 'Default',
|
|
33
|
+
sku: `HAL-${s.handle.slice(0, 6).toUpperCase()}-${String(i + 1).padStart(2, '0')}`,
|
|
34
|
+
price: THB(s.price),
|
|
35
|
+
compareAtPrice: s.compareAt ? THB(s.compareAt) : null,
|
|
36
|
+
available: !s.soldOut && !(i === combos.length - 1 && opts.length > 0 && combos.length > 2),
|
|
37
|
+
quantityAvailable: s.soldOut ? 0 : (s.lowStock ?? 24),
|
|
38
|
+
selectedOptions: sel,
|
|
39
|
+
}))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function makeProduct(s: Spec): Product {
|
|
43
|
+
const image = s.image === undefined ? placeholderImage('product', 800, 800, s.title) : s.image
|
|
44
|
+
const variants = variantsFor(s)
|
|
45
|
+
return {
|
|
46
|
+
id: `gid://product/${s.handle}`,
|
|
47
|
+
handle: s.handle,
|
|
48
|
+
title: s.title,
|
|
49
|
+
vendor: s.vendor ?? 'Halden & Co.',
|
|
50
|
+
productType: s.type,
|
|
51
|
+
description: s.description ?? `${s.title}, made in small batches in our Chiang Mai studio.`,
|
|
52
|
+
url: `/products/${s.handle}`,
|
|
53
|
+
featuredImage: image,
|
|
54
|
+
images: s.images ?? (image ? [image, placeholderImage('editorial', 800, 600, `${s.title} in use`)] : []),
|
|
55
|
+
options: s.options ?? [],
|
|
56
|
+
variants,
|
|
57
|
+
priceRange: { min: THB(s.price), max: THB(s.price) },
|
|
58
|
+
compareAtPriceRange: s.compareAt ? { min: THB(s.compareAt), max: THB(s.compareAt) } : null,
|
|
59
|
+
available: !s.soldOut,
|
|
60
|
+
badge: s.badge ?? null,
|
|
61
|
+
rating: s.rating ?? null,
|
|
62
|
+
tags: [s.type.toLowerCase()],
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const colour = { name: 'Colour', values: ['Oat', 'Chalk', 'Charcoal'] }
|
|
67
|
+
const bedSize = { name: 'Size', values: ['Single', 'Queen', 'King'] }
|
|
68
|
+
|
|
69
|
+
export const products: Product[] = [
|
|
70
|
+
makeProduct({ handle: 'speckled-stoneware-mug', title: 'Speckled Stoneware Mug', price: 690, type: 'Mugs', options: [colour], rating: { value: 4.8, count: 212 } }),
|
|
71
|
+
makeProduct({ handle: 'washed-linen-duvet-cover', title: 'Washed Linen Duvet Cover', price: 5900, type: 'Bedding', options: [bedSize, colour], rating: { value: 4.7, count: 96 } }),
|
|
72
|
+
makeProduct({ handle: 'sea-salt-dinner-plate', title: 'Sea Salt Dinner Plate', price: 890, compareAt: 1190, type: 'Plates', badge: null }),
|
|
73
|
+
makeProduct({ handle: 'linen-tea-towel-set', title: 'Linen Tea Towel, Set of 2', price: 790, type: 'Linen', options: [colour] }),
|
|
74
|
+
makeProduct({ handle: 'hand-thrown-carafe', title: 'Hand-thrown Carafe', price: 1450, type: 'Drinkware', soldOut: true }),
|
|
75
|
+
makeProduct({ handle: 'wild-honey-jar', title: 'Wild Longan Honey', price: 420, type: 'Pantry', lowStock: 3 }),
|
|
76
|
+
makeProduct({ handle: 'lemongrass-candle', title: 'Lemongrass & Vetiver Candle', price: 1150, type: 'Candles', badge: 'Bestseller' }),
|
|
77
|
+
makeProduct({ handle: 'linen-apron', title: 'Cross-back Linen Apron', price: 1690, type: 'Linen', options: [colour] }),
|
|
78
|
+
makeProduct({ handle: 'serving-bowl', title: 'Wide Serving Bowl', price: 1890, type: 'Serving' }),
|
|
79
|
+
makeProduct({ handle: 'waffle-bath-towel', title: 'Waffle Bath Towel', price: 1290, compareAt: 1590, type: 'Bath', options: [colour] }),
|
|
80
|
+
makeProduct({ handle: 'jasmine-tea', title: 'Jasmine Green Tea, 50 g', price: 380, type: 'Tea' }),
|
|
81
|
+
makeProduct({ handle: 'gift-card', title: 'Gift Card', price: 1000, type: 'Gift card', options: [{ name: 'Amount', values: ['฿1,000', '฿2,500', '฿5,000'] }] }),
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
export const variants: ProductVariant[] = products[1].variants
|
|
85
|
+
|
|
86
|
+
const col = (handle: string, title: string, count: number, fam: PlaceholderFamily = 'collection'): Collection => ({
|
|
87
|
+
id: `gid://collection/${handle}`,
|
|
88
|
+
handle,
|
|
89
|
+
title,
|
|
90
|
+
url: `/collections/${handle}`,
|
|
91
|
+
description: `${title} from the Halden studio.`,
|
|
92
|
+
image: placeholderImage(fam, 800, 1000, title),
|
|
93
|
+
productsCount: count,
|
|
94
|
+
products: products.slice(0, Math.min(8, count)),
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
export const collections: Collection[] = [
|
|
98
|
+
col('kitchen-table', 'Kitchen & Table', 48),
|
|
99
|
+
col('bedroom-bath', 'Bedroom & Bath', 31),
|
|
100
|
+
col('pantry', 'Pantry', 12),
|
|
101
|
+
col('candles', 'Candles & Scent', 9),
|
|
102
|
+
col('gifts', 'Gifts', 22),
|
|
103
|
+
col('studio-seconds', 'Studio Seconds', 0),
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
export const cart: Cart = {
|
|
107
|
+
id: 'gid://cart/1',
|
|
108
|
+
itemCount: 3,
|
|
109
|
+
note: '',
|
|
110
|
+
lines: [
|
|
111
|
+
{ id: 'l1', quantity: 2, product: products[0], variant: products[0].variants[0], cost: { total: THB(1380) } },
|
|
112
|
+
{ id: 'l2', quantity: 1, product: products[2], variant: products[2].variants[0], cost: { total: THB(890), compareAtTotal: THB(1190) } },
|
|
113
|
+
],
|
|
114
|
+
subtotal: THB(2270),
|
|
115
|
+
total: THB(2270),
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const cartEmpty: Cart = { id: 'gid://cart/2', itemCount: 0, lines: [], subtotal: THB(0), total: THB(0) }
|
|
119
|
+
|
|
120
|
+
export const searchResults: SearchResults = {
|
|
121
|
+
query: 'linen',
|
|
122
|
+
products: products.filter((p) => /linen/i.test(p.title)),
|
|
123
|
+
articles: [],
|
|
124
|
+
pages: [{ title: 'Linen care', url: '/pages/linen-care', excerpt: 'Wash cool, line dry, skip the iron.' }],
|
|
125
|
+
total: 4,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { THB }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { placeholderImage } from '../../src/components/states/media/MediaPlaceholder'
|
|
2
|
+
import type { Article, Blog, CustomerAccount, Policy, Review, StoreLocation, TeamMember, Testimonial, UgcPost } from '@tanqory/theme-kit'
|
|
3
|
+
import { THB } from './commerce'
|
|
4
|
+
|
|
5
|
+
export const articles: Article[] = [
|
|
6
|
+
{ id: 'a1', handle: 'how-to-wash-linen', title: 'How to wash linen so it lasts twenty years', excerpt: "Heat and softener are linen's only real enemies. A four-step routine for sheets, napkins and everything between.", url: '/blogs/journal/how-to-wash-linen', image: placeholderImage('editorial', 1200, 900, 'Linen on a drying line'), author: 'Mali Srisuk', publishedAt: '2026-08-14', readingMinutes: 6, tags: ['care'], blogHandle: 'journal' },
|
|
7
|
+
{ id: 'a2', handle: 'inside-the-kiln', title: 'Inside the kiln: a Sea Salt firing', excerpt: 'Forty pieces, one glaze, fourteen hours.', url: '/blogs/journal/inside-the-kiln', image: placeholderImage('editorial', 1200, 900, 'Kiln shelves'), author: 'Arun Pattana', publishedAt: '2026-07-02', readingMinutes: 4, tags: ['studio'], blogHandle: 'journal' },
|
|
8
|
+
{ id: 'a3', handle: 'setting-a-slow-table', title: 'Setting a slow table', excerpt: 'Three layers, no rules.', url: '/blogs/journal/setting-a-slow-table', image: null, author: 'Mali Srisuk', publishedAt: '2026-05-20', readingMinutes: 3, tags: ['home'], blogHandle: 'journal' },
|
|
9
|
+
]
|
|
10
|
+
export const blog: Blog = { id: 'b1', handle: 'journal', title: 'Journal', url: '/blogs/journal', articles }
|
|
11
|
+
|
|
12
|
+
export const reviews: Review[] = [
|
|
13
|
+
{ id: 'r1', author: 'Ploy K.', rating: 5, title: 'Softer every wash', body: 'Six months in and the duvet cover is softer than the day it arrived.', createdAt: '2026-06-02', verified: true },
|
|
14
|
+
{ id: 'r2', author: 'James W.', rating: 4, body: 'Lovely weight. The oat is a touch warmer than the photos.', createdAt: '2026-05-11', verified: true },
|
|
15
|
+
{ id: 'r3', author: 'Nok', rating: 3, title: 'Runs large', body: 'Beautiful mug but bigger than I expected.', createdAt: '2026-04-28' },
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
export const testimonials: Testimonial[] = [
|
|
19
|
+
{ id: 't1', quote: 'The only mugs our whole team fights over.', name: 'Anya Petrova', role: 'Café owner, Nimman', avatar: placeholderImage('avatar', 300, 300), rating: 5 },
|
|
20
|
+
{ id: 't2', quote: 'Linen that actually gets better. I have bought three sets.', name: 'Somchai R.', role: 'Customer since 2021', avatar: null, rating: 5 },
|
|
21
|
+
{ id: 't3', quote: 'Thoughtful packaging, no plastic, arrived in two days.', name: 'Lena M.', rating: null },
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
export const team: TeamMember[] = [
|
|
25
|
+
{ id: 'p1', name: 'Mali Srisuk', role: 'Founder & potter', bio: 'Started Halden with one wheel in a rented garage.', image: placeholderImage('avatar', 600, 750) },
|
|
26
|
+
{ id: 'p2', name: 'Arun Pattana', role: 'Kiln & glaze', image: placeholderImage('avatar', 600, 750) },
|
|
27
|
+
{ id: 'p3', name: 'Dao Chaiyaporn', role: 'Linen & textiles', image: null },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
export const ugc: UgcPost[] = Array.from({ length: 8 }, (_, i) => ({
|
|
31
|
+
id: `u${i}`,
|
|
32
|
+
image: placeholderImage('ugc', 800, 800, `Customer photo ${i + 1}`),
|
|
33
|
+
handle: ['@ploy.home', '@slowtable', '@nimman.eats', '@linenlove'][i % 4],
|
|
34
|
+
caption: i % 2 ? 'Sunday breakfast.' : undefined,
|
|
35
|
+
productHandles: ['speckled-stoneware-mug'],
|
|
36
|
+
}))
|
|
37
|
+
|
|
38
|
+
export const locations: StoreLocation[] = [
|
|
39
|
+
{ id: 's1', name: 'Chiang Mai Studio', address: ['88 Nimmanhaemin Soi 9', 'Chiang Mai 50200'], phone: '+66 53 123 456', email: 'studio@halden.co', hours: 'Tue–Sun 10:00–18:00', image: placeholderImage('store', 800, 600) },
|
|
40
|
+
{ id: 's2', name: 'Bangkok · Siam Discovery', address: ['Siam Discovery, 3rd floor', '194 Phaya Thai Rd', 'Bangkok 10330'], hours: 'Daily 10:00–22:00', image: placeholderImage('store', 800, 600) },
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
export const account: CustomerAccount = {
|
|
44
|
+
firstName: 'Mali',
|
|
45
|
+
lastName: 'Srisuk',
|
|
46
|
+
email: 'mali@halden.co',
|
|
47
|
+
phone: '+66 81 234 5678',
|
|
48
|
+
orders: [
|
|
49
|
+
{ id: 'o1', number: '#1042', processedAt: '2026-09-02', status: 'fulfilled', total: THB(2270), itemCount: 3 },
|
|
50
|
+
{ id: 'o2', number: '#1017', processedAt: '2026-07-18', status: 'paid', total: THB(5900), itemCount: 1 },
|
|
51
|
+
],
|
|
52
|
+
addresses: [{ id: 'ad1', lines: ['88 Nimmanhaemin Soi 9', 'Chiang Mai 50200', 'Thailand'], default: true }],
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const policies: Policy[] = [
|
|
56
|
+
{ handle: 'privacy-policy', title: 'Privacy policy', url: '/policies/privacy-policy', bodyHtml: '<p>This is sample policy text for the lab. A real store supplies its own policy.</p>' },
|
|
57
|
+
{ handle: 'terms-of-service', title: 'Terms of service', url: '/policies/terms-of-service', bodyHtml: '<p>Sample terms for the lab.</p>' },
|
|
58
|
+
]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Realistic, offline, deterministic data for stories and tests. Never call a live API. */
|
|
2
|
+
export * from './shop'
|
|
3
|
+
export * from './navigation'
|
|
4
|
+
export * from './commerce'
|
|
5
|
+
export * from './content'
|
|
6
|
+
export * from './stress'
|
|
7
|
+
export * from './promotion'
|
|
8
|
+
export * from './merch'
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { placeholderImage } from '../../src/components/states/media/MediaPlaceholder'
|
|
2
|
+
import type { Collection, Money, NovaImage, Product, ProductVariant } from '@tanqory/theme-kit'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 12C · the approved canvas products (Halden, USD). Deterministic: the same
|
|
6
|
+
* ids, prices and stock every run. The duvet carries the canvas buy box:
|
|
7
|
+
* Size × Colour, "King is not made in Oat", only 3 left in Queen.
|
|
8
|
+
*/
|
|
9
|
+
const USD = (amount: number): Money => ({ amount, currencyCode: 'USD' })
|
|
10
|
+
const img = (family: Parameters<typeof placeholderImage>[0], alt: string, w = 800, h = 800): NovaImage => placeholderImage(family, w, h, alt)
|
|
11
|
+
|
|
12
|
+
interface MerchSpec {
|
|
13
|
+
handle: string
|
|
14
|
+
title: string
|
|
15
|
+
price: number
|
|
16
|
+
maxPrice?: number
|
|
17
|
+
compareAt?: number
|
|
18
|
+
vendor?: string
|
|
19
|
+
options?: { name: string; values: string[] }[]
|
|
20
|
+
/** Combinations the maker does not make (value per option, in order). */
|
|
21
|
+
notMade?: string[][]
|
|
22
|
+
soldOut?: boolean
|
|
23
|
+
stock?: Record<string, number>
|
|
24
|
+
tags?: string[]
|
|
25
|
+
images?: NovaImage[] | null
|
|
26
|
+
description?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let n = 0
|
|
30
|
+
function merch(s: MerchSpec): Product {
|
|
31
|
+
const opts = s.options ?? []
|
|
32
|
+
const combos = opts.reduce<string[][]>((acc, o) => acc.flatMap((c) => o.values.map((v) => [...c, v])), [[]])
|
|
33
|
+
const variants: ProductVariant[] = combos
|
|
34
|
+
.filter((c) => !s.notMade?.some((m) => m.every((v, i) => v === c[i])))
|
|
35
|
+
.map((c, i) => {
|
|
36
|
+
const title = c.length ? c.join(' / ') : 'Default Title'
|
|
37
|
+
const qty = s.soldOut ? 0 : (s.stock?.[title] ?? s.stock?.[c[0]] ?? 24)
|
|
38
|
+
return {
|
|
39
|
+
id: `gid://merch-variant/${++n}`,
|
|
40
|
+
title,
|
|
41
|
+
sku: `HAL-${s.handle.slice(0, 5).toUpperCase()}-${String(i + 1).padStart(2, '0')}`,
|
|
42
|
+
price: USD(s.price),
|
|
43
|
+
compareAtPrice: s.compareAt ? USD(s.compareAt) : null,
|
|
44
|
+
available: qty > 0,
|
|
45
|
+
quantityAvailable: qty,
|
|
46
|
+
selectedOptions: c.map((value, k) => ({ name: opts[k].name, value })),
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
const images = s.images === null ? [] : (s.images ?? [img('product', s.title), img('editorial', `${s.title} in use`, 800, 1000)])
|
|
50
|
+
return {
|
|
51
|
+
id: `gid://merch/${s.handle}`,
|
|
52
|
+
handle: s.handle,
|
|
53
|
+
title: s.title,
|
|
54
|
+
vendor: s.vendor ?? 'Halden Studio',
|
|
55
|
+
productType: 'Home',
|
|
56
|
+
description: s.description ?? `${s.title}, made in small batches.`,
|
|
57
|
+
descriptionHtml: `<p>${s.description ?? `${s.title}, made in small batches.`}</p>`,
|
|
58
|
+
url: `/products/${s.handle}`,
|
|
59
|
+
featuredImage: images[0] ?? null,
|
|
60
|
+
images,
|
|
61
|
+
options: opts,
|
|
62
|
+
variants,
|
|
63
|
+
priceRange: { min: USD(s.price), max: USD(s.maxPrice ?? s.price) },
|
|
64
|
+
compareAtPriceRange: s.compareAt ? { min: USD(s.compareAt), max: USD(s.compareAt) } : null,
|
|
65
|
+
available: !s.soldOut && variants.some((v) => v.available),
|
|
66
|
+
tags: s.tags ?? [],
|
|
67
|
+
badge: null,
|
|
68
|
+
rating: null,
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const sixColours = { name: 'Colour', values: ['Oat', 'Charcoal', 'Sage', 'Sand', 'Chalk', 'Clay'] }
|
|
73
|
+
|
|
74
|
+
export const merchMug = merch({ handle: 'speckled-stoneware-mug', title: 'Speckled Stoneware Mug, 350 ml', price: 28, options: [sixColours], description: 'Thrown on the wheel and dipped in a speckled glaze that breaks brown at the rim. Dishwasher-safe.' })
|
|
75
|
+
export const merchDuvet = merch({
|
|
76
|
+
handle: 'washed-linen-duvet-cover',
|
|
77
|
+
title: 'Washed Linen Duvet Cover — Queen, Oat',
|
|
78
|
+
price: 189,
|
|
79
|
+
compareAt: 240,
|
|
80
|
+
vendor: 'Halden Linen',
|
|
81
|
+
options: [
|
|
82
|
+
{ name: 'Size', values: ['Twin', 'Full', 'Queen', 'King'] },
|
|
83
|
+
{ name: 'Colour', values: ['Oat', 'Chalk', 'Clay', 'Charcoal', 'Sage'] },
|
|
84
|
+
],
|
|
85
|
+
notMade: [['King', 'Oat']],
|
|
86
|
+
stock: { 'Queen / Oat': 3 },
|
|
87
|
+
images: [img('product', 'Duvet on a made bed', 800, 1000), img('editorial', 'Linen weave, close up', 800, 1000), img('store', 'Folded duvet cover', 800, 1000), img('generic', 'Hidden button closure', 800, 1000), img('hero', 'Bedroom in morning light', 800, 1000), img('collection', 'The five colours', 800, 1000)],
|
|
88
|
+
description: 'Stonewashed for a lived-in softness from the first night. 100% European flax, woven in Portugal. Hidden button closure and inner corner ties.',
|
|
89
|
+
})
|
|
90
|
+
export const merchOil = merch({ handle: 'early-harvest-olive-oil', title: 'Early Harvest Cold-Pressed Olive Oil, 500 ml', price: 24, tags: ['new'] })
|
|
91
|
+
export const merchCandle = merch({ handle: 'soy-candle-cedar', title: 'Hand-Poured Soy Candle — Cedar & Smoke, 220 g', price: 36, soldOut: true })
|
|
92
|
+
export const merchBoard = merch({ handle: 'walnut-serving-board', title: 'Walnut Serving Board, Large', price: 74, maxPrice: 96, options: [{ name: 'Size', values: ['Large', 'Extra large'] }] })
|
|
93
|
+
export const merchPlatter = merch({ handle: 'speckled-serving-platter', title: 'Extra-Large Hand-Thrown Speckled Stoneware Serving Platter with Reactive Sea Salt Glaze', price: 1249 })
|
|
94
|
+
export const merchNapkins = merch({ handle: 'linen-napkins-chalk', title: 'Linen Napkins, Set of 4 — Chalk', price: 32, images: null })
|
|
95
|
+
export const merchPourOver = merch({
|
|
96
|
+
handle: 'ceramic-pour-over-set',
|
|
97
|
+
title: 'Ceramic Pour-Over Coffee Set with Walnut Stand',
|
|
98
|
+
price: 58,
|
|
99
|
+
compareAt: 72,
|
|
100
|
+
options: [{ name: 'Glaze', values: ['Sand', 'Chalk', 'Clay', 'Charcoal', 'Sage'] }],
|
|
101
|
+
description: 'Brews two cups in four minutes. The stand is oiled FSC walnut, the dripper hand-thrown and glazed in Sea Salt. Filters included for the first month of mornings.',
|
|
102
|
+
})
|
|
103
|
+
export const merchCarafe = merch({ handle: 'glass-carafe', title: 'Mouth-Blown Glass Carafe, 1 L', price: 42 })
|
|
104
|
+
|
|
105
|
+
/** The canvas's card-states row, in order. */
|
|
106
|
+
export const merchProducts: Product[] = [merchMug, merchDuvet, merchOil, merchCandle, merchBoard, merchPlatter, merchNapkins, merchPourOver, merchCarafe]
|
|
107
|
+
/** "New this season" — the canonical featured row. */
|
|
108
|
+
export const merchNewSeason: Product[] = [merchMug, merchDuvet, merchOil, merchCandle]
|
|
109
|
+
/** A single-variant product with one image and no options. */
|
|
110
|
+
export const merchSimple = merch({ handle: 'linen-tea-towel', title: 'Linen Tea Towel', price: 18, images: [img('product', 'Linen tea towel')] })
|
|
111
|
+
/** Every price in JPY (0 decimals) — currency stress. */
|
|
112
|
+
export const merchJpy: Product = { ...merchMug, priceRange: { min: { amount: 4800, currencyCode: 'JPY' }, max: { amount: 4800, currencyCode: 'JPY' } }, compareAtPriceRange: null }
|
|
113
|
+
/** KWD (3 decimals). */
|
|
114
|
+
export const merchKwd: Product = { ...merchCarafe, priceRange: { min: { amount: 8.75, currencyCode: 'KWD' }, max: { amount: 8.75, currencyCode: 'KWD' } } }
|
|
115
|
+
/** A price of 0 (free sample). */
|
|
116
|
+
export const merchFree: Product = { ...merchSimple, handle: 'sample', title: 'Glaze Sample Tile', priceRange: { min: USD(0), max: USD(0) } }
|
|
117
|
+
|
|
118
|
+
const room = (handle: string, title: string, count: number, family: Parameters<typeof placeholderImage>[0], products: Product[], description?: string): Collection => ({
|
|
119
|
+
id: `gid://merch-collection/${handle}`,
|
|
120
|
+
handle,
|
|
121
|
+
title,
|
|
122
|
+
url: `/collections/${handle}`,
|
|
123
|
+
description: description ?? `${title} from the Halden studio.`,
|
|
124
|
+
image: placeholderImage(family, 800, 1000, title),
|
|
125
|
+
productsCount: count,
|
|
126
|
+
products,
|
|
127
|
+
})
|
|
128
|
+
export const merchRooms: Collection[] = [
|
|
129
|
+
room('kitchen-table', 'Kitchen & Table', 48, 'collection', merchProducts, 'Everyday stoneware, glass and wood for cooking, pouring and gathering. Dishwasher-safe unless noted.'),
|
|
130
|
+
room('bedroom-bath', 'Bedroom & Bath', 32, 'editorial', [merchDuvet]),
|
|
131
|
+
room('pantry', 'Pantry', 27, 'product', [merchOil]),
|
|
132
|
+
room('candles-scent', 'Candles & Scent', 19, 'store', [merchCandle]),
|
|
133
|
+
room('studio-seconds', 'Studio Seconds', 12, 'generic', [merchMug]),
|
|
134
|
+
]
|
|
135
|
+
/** A collection without an image: the first product image stands in. */
|
|
136
|
+
export const merchRoomNoImage: Collection = { ...merchRooms[2], handle: 'pantry-no-image', image: null }
|
|
137
|
+
|
|
138
|
+
/** 12C · the canvas facets for Kitchen & Table (Stoneware on, Textiles 0 → disabled). */
|
|
139
|
+
export const merchFacets: import('@tanqory/theme-kit').Facet[] = [
|
|
140
|
+
{ id: 'availability', label: 'Availability', type: 'list', values: [{ id: 'in-stock', label: 'In stock', count: 18, active: false }, { id: 'out', label: 'Out of stock', count: 3, active: false }] },
|
|
141
|
+
{ id: 'type', label: 'Product type', type: 'list', values: [{ id: 'stoneware', label: 'Stoneware', count: 21, active: true }, { id: 'glassware', label: 'Glassware', count: 9, active: false }, { id: 'textiles', label: 'Textiles', count: 0, active: false }] },
|
|
142
|
+
{ id: 'price', label: 'Price', type: 'price', range: { min: 0, max: 1250, currencyCode: 'USD' } },
|
|
143
|
+
{ id: 'colour', label: 'Colour', type: 'list', values: [{ id: 'oat', label: 'Oat', count: 12, active: false }, { id: 'charcoal', label: 'Charcoal', count: 8, active: false }, { id: 'sage', label: 'Sage', count: 5, active: false }] },
|
|
144
|
+
]
|
|
145
|
+
export const merchSortOptions: import('@tanqory/theme-kit').SortOption[] = [
|
|
146
|
+
{ id: 'featured', label: 'Featured' },
|
|
147
|
+
{ id: 'best-selling', label: 'Best selling' },
|
|
148
|
+
{ id: 'price-asc', label: 'Price ↑' },
|
|
149
|
+
{ id: 'price-desc', label: 'Price ↓' },
|
|
150
|
+
{ id: 'newest', label: 'Newest' },
|
|
151
|
+
]
|
|
152
|
+
/** 21 products for a listing (the canvas shows "Showing 6 of 21"). */
|
|
153
|
+
export const merchListing: Product[] = Array.from({ length: 21 }, (_, i) => {
|
|
154
|
+
const p = merchProducts[i % merchProducts.length]
|
|
155
|
+
return { ...p, id: `${p.id}-${i}`, handle: `${p.handle}-${i}` }
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
/** 12F · shop-the-look and comparison-table products (appended: earlier ids stay stable). */
|
|
159
|
+
export const merchThrow = merch({ handle: 'washed-linen-throw', title: 'Washed Linen Throw — Oat', price: 148, vendor: 'Halden Linen', images: [img('collection', 'Oat linen throw over a sofa arm')] })
|
|
160
|
+
export const merchDuvetBlend = merch({ handle: 'linen-cotton-duvet-cover', title: 'Linen-Cotton Duvet Cover', price: 149, vendor: 'Halden Linen', images: [img('store', 'Linen-cotton duvet cover, folded')] })
|
|
161
|
+
export const merchDuvetPercale = merch({ handle: 'organic-percale-duvet-cover', title: 'Organic Percale Duvet Cover', price: 129, vendor: 'Halden Linen', images: [img('generic', 'Organic percale duvet cover, folded')] })
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { BreadcrumbItem, NovaMenu } from '@tanqory/theme-kit'
|
|
2
|
+
|
|
3
|
+
const u = (s: string) => `/collections/${s}`
|
|
4
|
+
|
|
5
|
+
/** 12A canonical main menu — five top-level items; the first carries a mega panel (L2 headings, L3 links). */
|
|
6
|
+
export const mainMenu: NovaMenu = {
|
|
7
|
+
handle: 'main-menu',
|
|
8
|
+
title: 'Main menu',
|
|
9
|
+
items: [
|
|
10
|
+
{
|
|
11
|
+
title: 'Kitchen & Table',
|
|
12
|
+
url: u('kitchen-table'),
|
|
13
|
+
active: true,
|
|
14
|
+
items: [
|
|
15
|
+
{ title: 'Tableware', url: u('tableware'), items: [{ title: 'Mugs & Cups', url: u('mugs') }, { title: 'Plates & Bowls', url: u('plates-bowls') }, { title: 'Serving', url: u('serving') }] },
|
|
16
|
+
{ title: 'Drinkware', url: u('drinkware'), items: [{ title: 'Glassware', url: u('glassware') }, { title: 'Carafes', url: u('carafes') }, { title: 'Coffee & Tea', url: u('coffee-tea') }] },
|
|
17
|
+
{ title: 'Linen', url: u('table-linen'), items: [{ title: 'Table Linen', url: u('table-linen') }, { title: 'Aprons', url: u('aprons') }, { title: 'Tea Towels', url: u('tea-towels') }] },
|
|
18
|
+
{ title: 'Gifts', url: u('gifts'), items: [{ title: 'Gift Sets', url: u('gift-sets') }, { title: 'Gift Cards', url: '/products/gift-card' }] },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
title: 'Bedroom & Bath',
|
|
23
|
+
url: u('bedroom-bath'),
|
|
24
|
+
items: [
|
|
25
|
+
{ title: 'Bedding', url: u('bedding'), items: [{ title: 'Duvet Covers', url: u('duvet-covers') }, { title: 'Sheets', url: u('sheets') }, { title: 'Pillowcases', url: u('pillowcases') }] },
|
|
26
|
+
{ title: 'Bath', url: u('bath'), items: [{ title: 'Towels', url: u('towels') }, { title: 'Robes', url: u('robes') }] },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
{ title: 'Pantry', url: u('pantry'), items: [{ title: 'Honey & Preserves', url: u('preserves') }, { title: 'Tea', url: u('tea') }, { title: 'Spices', url: u('spices') }] },
|
|
30
|
+
{ title: 'Candles & Scent', url: u('candles') },
|
|
31
|
+
{ title: 'Journal', url: '/blogs/journal' },
|
|
32
|
+
],
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Two levels only (no L3) — the simple dropdown's natural data. */
|
|
36
|
+
export const mainMenuShort: NovaMenu = {
|
|
37
|
+
handle: 'main-menu',
|
|
38
|
+
title: 'Main menu',
|
|
39
|
+
items: [
|
|
40
|
+
{ title: 'Shop', url: u('all'), items: [{ title: 'Kitchen', url: u('kitchen-table') }, { title: 'Bedroom', url: u('bedroom-bath') }, { title: 'Pantry', url: u('pantry') }] },
|
|
41
|
+
{ title: 'Journal', url: '/blogs/journal' },
|
|
42
|
+
{ title: 'About', url: '/pages/about' },
|
|
43
|
+
],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Flat — one level; menuStyle has nothing to open. */
|
|
47
|
+
export const mainMenuFlat: NovaMenu = {
|
|
48
|
+
handle: 'main-menu',
|
|
49
|
+
title: 'Main menu',
|
|
50
|
+
items: mainMenu.items.map(({ title, url }) => ({ title, url })),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const mainMenuThai: NovaMenu = {
|
|
54
|
+
handle: 'main-menu',
|
|
55
|
+
title: 'เมนูหลัก',
|
|
56
|
+
items: [
|
|
57
|
+
{
|
|
58
|
+
title: 'ห้องครัวและโต๊ะอาหาร',
|
|
59
|
+
url: u('kitchen-table'),
|
|
60
|
+
items: [
|
|
61
|
+
{ title: 'แก้วและถ้วย', url: u('mugs') },
|
|
62
|
+
{ title: 'จานและชาม', url: u('plates-bowls') },
|
|
63
|
+
{ title: 'ภาชนะเสิร์ฟ', url: u('serving') },
|
|
64
|
+
{ title: 'ผ้าปูโต๊ะ ผ้ากันเปื้อน และผ้าเช็ดจาน', url: u('table-linen') },
|
|
65
|
+
{ title: 'ชุดของขวัญ', url: u('gift-sets') },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{ title: 'ห้องนอนและห้องน้ำ', url: u('bedroom-bath'), items: [{ title: 'ปลอกผ้านวม', url: u('duvet-covers') }] },
|
|
69
|
+
{ title: 'ของแห้งและเครื่องปรุง', url: u('pantry') },
|
|
70
|
+
{ title: 'เทียนหอมและกลิ่น', url: u('candles') },
|
|
71
|
+
],
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const mainMenuArabic: NovaMenu = {
|
|
75
|
+
handle: 'main-menu',
|
|
76
|
+
title: 'القائمة الرئيسية',
|
|
77
|
+
items: [
|
|
78
|
+
{ title: 'المطبخ والمائدة', url: u('kitchen-table'), items: [{ title: 'أكواب وفناجين', url: u('mugs') }, { title: 'أطباق وأوعية', url: u('plates-bowls') }] },
|
|
79
|
+
{ title: 'غرفة النوم والحمام', url: u('bedroom-bath'), items: [{ title: 'أغطية لحاف', url: u('duvet-covers') }] },
|
|
80
|
+
{ title: 'المؤن', url: u('pantry'), items: [{ title: 'شاي', url: u('tea') }] },
|
|
81
|
+
{ title: 'الشموع والعطور', url: u('candles') },
|
|
82
|
+
{ title: 'المجلة', url: '/blogs/journal' },
|
|
83
|
+
],
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Nine long top-level items: overflows every desktop width → the header collapses to the drawer. */
|
|
87
|
+
export const mainMenuLong: NovaMenu = {
|
|
88
|
+
handle: 'main-menu',
|
|
89
|
+
title: 'Main menu',
|
|
90
|
+
items: [
|
|
91
|
+
'Kitchen & Table Essentials',
|
|
92
|
+
'Bedroom & Bath Linen',
|
|
93
|
+
'Pantry & Preserves',
|
|
94
|
+
'Candles, Scent & Home Fragrance',
|
|
95
|
+
'Gifts for Every Occasion',
|
|
96
|
+
'Studio Seconds',
|
|
97
|
+
'Collaborations',
|
|
98
|
+
'Journal & Care Guides',
|
|
99
|
+
'Visit the Studio',
|
|
100
|
+
].map((title, i) => ({ title, url: `/pages/item-${i}` })),
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const footerShop: NovaMenu = { handle: 'footer-shop', title: 'Shop', items: [{ title: 'Kitchen & Table', url: u('kitchen-table') }, { title: 'Bedroom & Bath', url: u('bedroom-bath') }, { title: 'Pantry', url: u('pantry') }, { title: 'Gift cards', url: '/products/gift-card' }] }
|
|
104
|
+
export const footerHelp: NovaMenu = { handle: 'footer-help', title: 'Help', items: [{ title: 'Shipping', url: '/policies/shipping-policy' }, { title: 'Returns', url: '/policies/refund-policy' }, { title: 'Care guides', url: '/blogs/journal/tagged/care' }, { title: 'Contact', url: '/pages/contact' }] }
|
|
105
|
+
export const footerCompany: NovaMenu = { handle: 'footer-company', title: 'Studio', items: [{ title: 'Our story', url: '/pages/about' }, { title: 'Journal', url: '/blogs/journal' }, { title: 'Stockists', url: '/pages/stockists' }, { title: 'Careers', url: '/pages/careers' }] }
|
|
106
|
+
export const footerMinimal: NovaMenu = { handle: 'footer', title: 'Footer', items: [{ title: 'Shop', url: u('all') }, { title: 'Journal', url: '/blogs/journal' }, { title: 'Shipping', url: '/policies/shipping-policy' }, { title: 'Returns', url: '/policies/refund-policy' }, { title: 'Contact', url: '/pages/contact' }] }
|
|
107
|
+
export const legalMenu: NovaMenu = { handle: 'legal', title: 'Legal', items: [{ title: 'Privacy policy', url: '/policies/privacy-policy' }, { title: 'Terms of service', url: '/policies/terms-of-service' }, { title: 'Refund policy', url: '/policies/refund-policy' }] }
|
|
108
|
+
/** The centered / minimal footer's short legal line. */
|
|
109
|
+
export const legalMenuShort: NovaMenu = { handle: 'legal', title: 'Legal', items: [{ title: 'Privacy', url: '/policies/privacy-policy' }, { title: 'Terms', url: '/policies/terms-of-service' }] }
|
|
110
|
+
export const footerShopThai: NovaMenu = { handle: 'footer-shop', title: 'ร้านค้า', items: [{ title: 'ห้องครัวและโต๊ะอาหาร', url: u('kitchen-table') }, { title: 'ห้องนอนและห้องน้ำ', url: u('bedroom-bath') }, { title: 'บัตรของขวัญ', url: '/products/gift-card' }] }
|
|
111
|
+
export const footerHelpThai: NovaMenu = { handle: 'footer-help', title: 'ช่วยเหลือ', items: [{ title: 'การจัดส่ง', url: '/policies/shipping-policy' }, { title: 'การคืนสินค้า', url: '/policies/refund-policy' }, { title: 'ติดต่อเรา', url: '/pages/contact' }] }
|
|
112
|
+
export const legalMenuThai: NovaMenu = { handle: 'legal', title: 'กฎหมาย', items: [{ title: 'นโยบายความเป็นส่วนตัว', url: '/policies/privacy-policy' }, { title: 'ข้อกำหนด', url: '/policies/terms-of-service' }] }
|
|
113
|
+
export const footerShopArabic: NovaMenu = { handle: 'footer-shop', title: 'تسوق', items: [{ title: 'المطبخ والمائدة', url: u('kitchen-table') }, { title: 'غرفة النوم والحمام', url: u('bedroom-bath') }] }
|
|
114
|
+
export const footerHelpArabic: NovaMenu = { handle: 'footer-help', title: 'مساعدة', items: [{ title: 'الشحن', url: '/policies/shipping-policy' }, { title: 'الإرجاع', url: '/policies/refund-policy' }] }
|
|
115
|
+
|
|
116
|
+
export const trails = {
|
|
117
|
+
collection: [{ title: 'Home', url: '/' }, { title: 'Collections', url: '/collections' }, { title: 'Kitchen & Table' }] as BreadcrumbItem[],
|
|
118
|
+
product: [{ title: 'Home', url: '/' }, { title: 'Bedroom & Bath', url: u('bedroom-bath') }, { title: 'Washed Linen Duvet Cover — Queen, Oat' }] as BreadcrumbItem[],
|
|
119
|
+
longTitle: [{ title: 'Home', url: '/' }, { title: 'Kitchen & Table', url: u('kitchen-table') }, { title: 'Extra-Large Hand-Thrown Speckled Stoneware Serving Platter with Reactive Glaze' }] as BreadcrumbItem[],
|
|
120
|
+
article: [{ title: 'Home', url: '/' }, { title: 'Journal', url: '/blogs/journal' }, { title: 'How to wash linen' }] as BreadcrumbItem[],
|
|
121
|
+
deep: [{ title: 'Home', url: '/' }, { title: 'Collections', url: '/collections' }, { title: 'Kitchen & Table', url: u('kitchen-table') }, { title: 'Tableware', url: u('tableware') }, { title: 'Speckled Stoneware Mug' }] as BreadcrumbItem[],
|
|
122
|
+
thai: [{ title: 'หน้าแรก', url: '/' }, { title: 'ห้องนอนและห้องน้ำ', url: u('bedroom-bath') }, { title: 'ปลอกผ้านวมลินินซัก — ควีน สีโอ๊ต' }] as BreadcrumbItem[],
|
|
123
|
+
arabic: [{ title: 'الرئيسية', url: '/' }, { title: 'غرفة النوم', url: u('bedroom-bath') }, { title: 'غطاء لحاف من الكتان' }] as BreadcrumbItem[],
|
|
124
|
+
home: [{ title: 'Home' }] as BreadcrumbItem[],
|
|
125
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { placeholderImage } from '../../src/components/states/media/MediaPlaceholder'
|
|
2
|
+
import type { Collection, NovaImage, NovaVideo } from '@tanqory/theme-kit'
|
|
3
|
+
import { collections } from './commerce'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Heroes & promotion fixtures (12B). Images are the Nova 14 placeholder art;
|
|
7
|
+
* videos are short muted VP9 loops served by the lab (apps/nova-storybook/
|
|
8
|
+
* public/media) whose FIRST FRAME is the same art as their poster, so a
|
|
9
|
+
* paused capture and the poster are the same picture.
|
|
10
|
+
*/
|
|
11
|
+
export const heroPortrait: NovaImage = placeholderImage('hero', 800, 1000, 'Linen drying in the Chiang Mai studio')
|
|
12
|
+
export const heroEditorial: NovaImage = placeholderImage('editorial', 1600, 900, 'A potter trimming a bowl at the wheel')
|
|
13
|
+
export const heroProduct: NovaImage = placeholderImage('product', 1000, 1250, 'Sea Salt glaze mug on a linen runner')
|
|
14
|
+
|
|
15
|
+
export const heroVideo: NovaVideo = { src: 'media/hero-loop.webm', poster: placeholderImage('hero', 1600, 900, 'Linen drying in the Chiang Mai studio') }
|
|
16
|
+
export const heroVideoPortrait: NovaVideo = { src: 'media/hero-loop-portrait.webm', poster: heroPortrait }
|
|
17
|
+
export const studioVideo: NovaVideo = { src: 'media/studio-loop.webm', poster: heroEditorial }
|
|
18
|
+
/** A video whose file never loads — the failure state (poster stays, controls hide). */
|
|
19
|
+
export const brokenVideo: NovaVideo = { src: 'media/does-not-exist.webm', poster: heroEditorial }
|
|
20
|
+
|
|
21
|
+
export const slideImages: NovaImage[] = [
|
|
22
|
+
placeholderImage('hero', 1600, 900, 'Sea Salt glaze mugs in morning light'),
|
|
23
|
+
placeholderImage('editorial', 1600, 900, 'Linen napkins folded on an oak table'),
|
|
24
|
+
placeholderImage('store', 1600, 900, 'Gift boxes wrapped in kraft paper'),
|
|
25
|
+
placeholderImage('collection', 1600, 900, 'Stoneware bowls stacked by colour'),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
export const bannerCollection: Collection = {
|
|
29
|
+
...collections[0],
|
|
30
|
+
description: 'Everyday stoneware, glass and wood for cooking, pouring and gathering. Dishwasher-safe unless noted.',
|
|
31
|
+
image: placeholderImage('collection', 1600, 700, 'Stoneware and glass on a kitchen shelf'),
|
|
32
|
+
}
|
|
33
|
+
export const bannerCollectionLong: Collection = {
|
|
34
|
+
...bannerCollection,
|
|
35
|
+
description:
|
|
36
|
+
'Everyday stoneware, glass and wood for cooking, pouring and gathering. Dishwasher-safe unless noted. Every piece is made in batches of forty in our Chiang Mai studio, glazed by hand and fired twice, so no two are quite the same — and that is the point.',
|
|
37
|
+
}
|
|
38
|
+
export const bannerCollectionNoImage: Collection = { ...bannerCollection, image: null }
|
|
39
|
+
export const bannerCollectionThai: Collection = {
|
|
40
|
+
...bannerCollection,
|
|
41
|
+
title: 'ภาชนะเซรามิกเคลือบมือสำหรับโต๊ะอาหารทุกวัน',
|
|
42
|
+
description: 'เครื่องปั้นดินเผา แก้ว และไม้ สำหรับการทำอาหารและการรวมตัวทุกวัน',
|
|
43
|
+
}
|