create-tanqory-theme 0.0.0-stage → 0.2.2
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,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nova's presentation mapping, shared by the sections' data bindings: which
|
|
3
|
+
* saved blocks a section shows and in what shape, whether the header sits over
|
|
4
|
+
* a media hero, what "add" means for a product card. WHERE the data comes from
|
|
5
|
+
* is the runtime's (it fills the store context; `@tanqory/theme-sdk`'s
|
|
6
|
+
* imageFor / menuFor / collectionFor / productFor … read it); HOW it is
|
|
7
|
+
* presented is decided here.
|
|
8
|
+
*/
|
|
9
|
+
import { NovaImage, NovaMenu, NovaVideo, Product, SavedBlock, SavedSection, SettingIssue, SettingsOf, StoreContext, ThemeActions, imageFor, menuFor, resolveSettings, videoFor } from '@tanqory/theme-kit'
|
|
10
|
+
import { ColumnInstance, columnSchema } from '../components/content/blocks/Column'
|
|
11
|
+
import { imageSchema } from '../components/content/blocks/Image'
|
|
12
|
+
import { footerMenuSchema } from './Footer/blocks/FooterMenu'
|
|
13
|
+
import { heroSchema } from './Hero/schema'
|
|
14
|
+
import { slideSchema } from './Slideshow/blocks/Slide'
|
|
15
|
+
import { videoHeroSchema } from './VideoHero/schema'
|
|
16
|
+
import type { accordionSchema } from './Group/blocks/Accordion'
|
|
17
|
+
import type { buttonSchema } from '../components/content/blocks/Button'
|
|
18
|
+
import type { footerBrandSchema } from './Footer/blocks/FooterBrand'
|
|
19
|
+
import type { footerTextSchema } from './Footer/blocks/FooterText'
|
|
20
|
+
import type { footerLineSchema } from './Footer/blocks/FooterLine'
|
|
21
|
+
import type { headingSchema } from '../components/content/blocks/Heading'
|
|
22
|
+
import type { iconSchema } from '../components/content/blocks/Icon'
|
|
23
|
+
import type { jumboTextSchema } from './Group/blocks/JumboText'
|
|
24
|
+
import { NEWSLETTER_BLOCK, newsletterBlockSchema } from '../components/forms/blocks/Newsletter'
|
|
25
|
+
import type { paymentIconsSchema } from '../components/commerce/blocks/PaymentIcons'
|
|
26
|
+
import type { socialLinksSchema } from '../components/navigation/blocks/SocialLinks'
|
|
27
|
+
import type { spacerSchema } from './Group/blocks/Spacer'
|
|
28
|
+
import type { textSchema } from '../components/content/blocks/Text'
|
|
29
|
+
import type { videoSchema } from '../components/content/blocks/Video'
|
|
30
|
+
|
|
31
|
+
export const blocksOf = (node: SavedSection, type: string) => (node.blocks ?? []).filter((b) => b.type === type)
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 12A header transparentOnHero needs to know whether the page opens with a
|
|
35
|
+
* hero-type section that has media (hero image layouts, slideshow, video-hero).
|
|
36
|
+
*/
|
|
37
|
+
export function isHeroWithMedia(node: SavedSection | undefined, ctx: StoreContext): boolean {
|
|
38
|
+
if (!node) return false
|
|
39
|
+
if (node.type === 'hero') {
|
|
40
|
+
const r = resolveSettings(heroSchema, node.settings)
|
|
41
|
+
return (r.settings.layout === 'image-background' || r.settings.layout === 'contained') && Boolean(imageFor(ctx, r.handles.backgroundImage) || videoFor(ctx, r.handles.video))
|
|
42
|
+
}
|
|
43
|
+
if (node.type === 'slideshow') return (node.blocks ?? []).some((b) => b.type === 'slide' && Boolean(imageFor(ctx, resolveSettings(slideSchema, b.settings).handles.image)))
|
|
44
|
+
if (node.type === 'video-hero') {
|
|
45
|
+
const r = resolveSettings(videoHeroSchema, node.settings)
|
|
46
|
+
return Boolean(r.settings.videoUrl || imageFor(ctx, r.handles.poster))
|
|
47
|
+
}
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function columnsOf(ctx: StoreContext, saved: SavedBlock[] | undefined, issues: SettingIssue[]): ColumnInstance[] {
|
|
52
|
+
return (saved ?? []).filter((b) => b.type === 'column').map((b) => {
|
|
53
|
+
const r = resolveSettings(columnSchema, b.settings)
|
|
54
|
+
issues.push(...r.issues)
|
|
55
|
+
return { settings: r.settings, image: imageFor(ctx, r.handles.image), video: videoFor(ctx, r.handles.video) }
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A placed block, as a section receives it: the block type, its (partial,
|
|
61
|
+
* saved) settings and any resolved data the adapter attached.
|
|
62
|
+
*/
|
|
63
|
+
export type BlockInstance =
|
|
64
|
+
| { type: 'heading'; settings?: Partial<SettingsOf<typeof headingSchema>> }
|
|
65
|
+
| { type: 'text'; settings?: Partial<SettingsOf<typeof textSchema>> }
|
|
66
|
+
| { type: 'button'; settings?: Partial<SettingsOf<typeof buttonSchema>> }
|
|
67
|
+
| { type: 'image'; settings?: Partial<SettingsOf<typeof imageSchema>>; image?: NovaImage | null }
|
|
68
|
+
| { type: 'icon'; settings?: Partial<SettingsOf<typeof iconSchema>> }
|
|
69
|
+
| { type: 'spacer'; settings?: Partial<SettingsOf<typeof spacerSchema>> }
|
|
70
|
+
| { type: 'video'; settings?: Partial<SettingsOf<typeof videoSchema>>; video?: NovaVideo | null }
|
|
71
|
+
| { type: 'jumbo-text'; settings?: Partial<SettingsOf<typeof jumboTextSchema>> }
|
|
72
|
+
| { type: 'accordion'; settings?: Partial<SettingsOf<typeof accordionSchema>> }
|
|
73
|
+
| { type: 'footer-brand'; settings?: Partial<SettingsOf<typeof footerBrandSchema>> }
|
|
74
|
+
| { type: 'footer-menu'; settings?: Partial<Pick<SettingsOf<typeof footerMenuSchema>, 'heading'>>; menu?: NovaMenu | null }
|
|
75
|
+
| { type: 'footer-text'; settings?: Partial<SettingsOf<typeof footerTextSchema>> }
|
|
76
|
+
| { type: 'social-links'; settings?: Partial<SettingsOf<typeof socialLinksSchema>> }
|
|
77
|
+
| { type: 'payment-icons'; settings?: Partial<SettingsOf<typeof paymentIconsSchema>> }
|
|
78
|
+
| { type: 'newsletter-signup'; settings?: Partial<SettingsOf<typeof newsletterBlockSchema>>; endpoint?: string; formResult?: StoreContext['formResult'] }
|
|
79
|
+
| { type: 'footer-line'; settings?: Partial<SettingsOf<typeof footerLineSchema>> }
|
|
80
|
+
|
|
81
|
+
export function adaptBlocks(ctx: StoreContext, saved: SavedBlock[] | undefined, issues: SettingIssue[]): BlockInstance[] {
|
|
82
|
+
return (saved ?? []).map((b) => {
|
|
83
|
+
if (b.type === 'image') {
|
|
84
|
+
const r = resolveSettings(imageSchema, b.settings)
|
|
85
|
+
issues.push(...r.issues)
|
|
86
|
+
return { type: 'image', settings: r.settings, image: ctx.images?.[r.handles.image] ?? null }
|
|
87
|
+
}
|
|
88
|
+
if (b.type === 'footer-menu') {
|
|
89
|
+
const r = resolveSettings(footerMenuSchema, b.settings)
|
|
90
|
+
issues.push(...r.issues)
|
|
91
|
+
const m = menuFor(ctx, r.handles.menu)
|
|
92
|
+
// No saved heading → the menu's own name (what stores saved against), then the default.
|
|
93
|
+
const saved = typeof b.settings?.heading === 'string' ? b.settings.heading.trim() : ''
|
|
94
|
+
return { type: 'footer-menu', settings: { heading: saved || m?.title || r.settings.heading }, menu: m }
|
|
95
|
+
}
|
|
96
|
+
if (b.type === 'video') {
|
|
97
|
+
const video = typeof b.settings?.url === 'string' ? ctx.videos?.[b.settings.url] : undefined
|
|
98
|
+
return { type: 'video', settings: b.settings as never, video: video ?? null }
|
|
99
|
+
}
|
|
100
|
+
if (b.type === NEWSLETTER_BLOCK || newsletterBlockSchema.legacyNames?.includes(b.type)) {
|
|
101
|
+
// The platform's native form endpoint, as the Newsletter section gets it: zero setup in a footer or group.
|
|
102
|
+
// A block saved under its old name (`newsletter`) is the same block (alias on read).
|
|
103
|
+
return { type: NEWSLETTER_BLOCK, settings: b.settings as never, ...(ctx.newsletterEndpoint ? { endpoint: ctx.newsletterEndpoint } : {}), ...(ctx.formResult ? { formResult: ctx.formResult } : {}) }
|
|
104
|
+
}
|
|
105
|
+
// Other blocks carry only settings; the section resolves their defaults.
|
|
106
|
+
return { type: b.type, settings: b.settings } as BlockInstance
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/** Add a product to the cart: its first available variant, else its first. */
|
|
112
|
+
export function addProduct(actions: ThemeActions, product: Product): Promise<boolean> | undefined {
|
|
113
|
+
const v = product.variants?.find((x) => x.available) ?? product.variants?.[0]
|
|
114
|
+
return v ? actions.cart.add(v.id, 1) : undefined
|
|
115
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shipped copy the runtime must NOT localize or fill in (theme `shippedCopy`,
|
|
3
|
+
* @tanqory/theme-kit runtime/render/localized-copy.ts). Each entry names the renderer
|
|
4
|
+
* that depends on it; `tests/localized-copy.test.ts` scans the theme for new
|
|
5
|
+
* cases and fails when one is not listed here.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The renderer compares the value with the shipped English, so a translated
|
|
10
|
+
* value would read as the merchant's own:
|
|
11
|
+
* - footer-brand.title: `title !== 'Your store'` — the default title is not an
|
|
12
|
+
* override; the brand logo / store name shows instead (FooterBrand.tsx).
|
|
13
|
+
* - footer-brand.tagline: `=== TAGLINE_STARTER` — an editor-only placeholder,
|
|
14
|
+
* never shown to shoppers (FooterBrand.tsx).
|
|
15
|
+
* - testimonial.quote: `=== TESTIMONIAL_STARTER` — the editor's starter state
|
|
16
|
+
* (Testimonials.tsx); the live store drops it as starter text.
|
|
17
|
+
*/
|
|
18
|
+
export const KEEP_SHIPPED_COPY = ['block:footer-brand.title', 'block:footer-brand.tagline', 'block:testimonial.quote'] as const
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* An unset value is derived from data, so the default must not be filled in:
|
|
22
|
+
* - footer-menu.heading: no saved heading → the menu's own name
|
|
23
|
+
* (sections/data.ts adaptBlocks). A saved heading is still localized.
|
|
24
|
+
*/
|
|
25
|
+
export const DERIVED_WHEN_UNSET = ['block:footer-menu.heading'] as const
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Starter text: what the starter templates, presets and setting defaults say
|
|
3
|
+
* in place of content, to tell a merchant what to write.
|
|
4
|
+
*
|
|
5
|
+
* The editor shows it as it is. On the live storefront the runtime renders no
|
|
6
|
+
* section whose own settings still hold one of these, and leaves out any block
|
|
7
|
+
* that does (theme `starterText`) — so a store that opens before it is set up
|
|
8
|
+
* shows less, never an instruction or a review nobody wrote.
|
|
9
|
+
*
|
|
10
|
+
* Exact strings, compared trimmed. `tests/starter.test.ts` fails when a
|
|
11
|
+
* template or default carries instruction-like text that is not listed here,
|
|
12
|
+
* so the list and the templates cannot drift apart.
|
|
13
|
+
*/
|
|
14
|
+
import { TESTIMONIAL_STARTER } from './Testimonials/blocks/Testimonial'
|
|
15
|
+
|
|
16
|
+
export const STARTER_TEXT: readonly string[] = [
|
|
17
|
+
// Home
|
|
18
|
+
'Introduce your store in a sentence or two — what you make, and who it is for.',
|
|
19
|
+
'Tell customers how your products are made, and by whom.',
|
|
20
|
+
TESTIMONIAL_STARTER,
|
|
21
|
+
'Customer name',
|
|
22
|
+
'City',
|
|
23
|
+
'Delivery | Describe how and when you ship.\nReturns | Describe your returns window.\nCare | Describe how to look after a piece.\nPayment | List the ways customers can pay.',
|
|
24
|
+
// About
|
|
25
|
+
'Tell the story of your store',
|
|
26
|
+
'Describe the place and the process.',
|
|
27
|
+
'Introduce the people who make or choose what you sell.',
|
|
28
|
+
'<p>A paragraph or two on what you make, where, and why it matters to you.</p>',
|
|
29
|
+
'Milestone 1',
|
|
30
|
+
'Milestone 2',
|
|
31
|
+
'Milestone 3',
|
|
32
|
+
'Milestone 4',
|
|
33
|
+
'A line about this moment in your story.',
|
|
34
|
+
// Contact
|
|
35
|
+
'Add a question customers often ask',
|
|
36
|
+
'Add another question',
|
|
37
|
+
'<p>Answer it here, in your own words.</p>',
|
|
38
|
+
// Bundle product
|
|
39
|
+
'Item 1',
|
|
40
|
+
'Item 2',
|
|
41
|
+
'Item 3',
|
|
42
|
+
'Describe this piece of the set.',
|
|
43
|
+
// Featured collection, blog
|
|
44
|
+
'<p>Say why these pieces belong together.</p>',
|
|
45
|
+
'Tell readers what you will send them, and how often.',
|
|
46
|
+
// Setting defaults
|
|
47
|
+
'Tell your story here…',
|
|
48
|
+
'Describe this step.',
|
|
49
|
+
]
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
.nv-container { width: 100%; margin-inline: auto; padding-inline: var(--page-gutter); }
|
|
2
|
+
.nv-container[data-width='narrow'] { max-width: calc(var(--container-narrow) + 2 * var(--page-gutter)); }
|
|
3
|
+
.nv-container[data-width='content'] { max-width: calc(var(--container-content) + 2 * var(--page-gutter)); }
|
|
4
|
+
.nv-container[data-width='standard'] { max-width: calc(var(--container-standard) + 2 * var(--page-gutter)); }
|
|
5
|
+
.nv-container[data-width='wide'] { max-width: calc(var(--container-wide) + 2 * var(--page-gutter)); }
|
|
6
|
+
.nv-container[data-width='full'] { max-width: none; }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react'
|
|
2
|
+
import './Container.css'
|
|
3
|
+
|
|
4
|
+
/** Nova 02 · Container — narrow 640 · content 960 · standard 1280 · wide 1536 · full; page gutter 16 / 24 / 40. */
|
|
5
|
+
export type ContainerWidth = 'narrow' | 'content' | 'standard' | 'wide' | 'full'
|
|
6
|
+
|
|
7
|
+
export function Container({ width = 'standard', children, className, ...rest }: { width?: ContainerWidth; children: ReactNode } & HTMLAttributes<HTMLDivElement>): JSX.Element {
|
|
8
|
+
return (
|
|
9
|
+
<div className={['nv-container', className].filter(Boolean).join(' ')} data-width={width} {...rest}>
|
|
10
|
+
{children}
|
|
11
|
+
</div>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import './Icon.css'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Nova 02 · Icon — 24px grid, 1.6 stroke (2.0 under iconStyle filled), round
|
|
6
|
+
* caps. Sizes sm 16 · md 20 · lg 24. Decorative by default (aria-hidden);
|
|
7
|
+
* pass `label` for a meaningful standalone icon. Directional icons mirror in RTL.
|
|
8
|
+
*/
|
|
9
|
+
const PATHS: Record<string, ReactNode> = {
|
|
10
|
+
// Nova 02 set
|
|
11
|
+
search: <path d="M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-4-4" />,
|
|
12
|
+
bag: <path d="M5 8h14l-1 12H6L5 8zM9 8V6a3 3 0 0 1 6 0v2" />,
|
|
13
|
+
user: <path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM4 21c1-4 4-6 8-6s7 2 8 6" />,
|
|
14
|
+
menu: <path d="M4 8h16M4 16h16" />,
|
|
15
|
+
close: <path d="M6 6l12 12M18 6L6 18" />,
|
|
16
|
+
'chevron-right': <path d="M9 6l6 6-6 6" />,
|
|
17
|
+
'chevron-left': <path d="M15 6l-6 6 6 6" />,
|
|
18
|
+
'chevron-down': <path d="M6 9l6 6 6-6" />,
|
|
19
|
+
'chevron-up': <path d="M6 15l6-6 6 6" />,
|
|
20
|
+
plus: <path d="M12 5v14M5 12h14" />,
|
|
21
|
+
minus: <path d="M5 12h14" />,
|
|
22
|
+
check: <path d="M5 12l5 5 9-10" />,
|
|
23
|
+
heart: <path d="M12 21s-7-4.5-7-10a4 4 0 0 1 7-2.5A4 4 0 0 1 19 11c0 5.5-7 10-7 10z" />,
|
|
24
|
+
truck: <path d="M3 7h11v9H3zM14 10h4l3 3v3h-7" />,
|
|
25
|
+
return: <path d="M4 12a8 8 0 1 0 3-6.2M4 4v4h4" />,
|
|
26
|
+
shield: <path d="M12 3l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V6l7-3z" />,
|
|
27
|
+
mail: <path d="M4 6h16v12H4zM4 7l8 6 8-6" />,
|
|
28
|
+
globe: <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM2 12h20M12 2c3 3 3 17 0 20M12 2c-3 3-3 17 0 20" />,
|
|
29
|
+
// icon block options (12D)
|
|
30
|
+
chat: <path d="M21 11.5a7.5 7.5 0 0 1-11 6.6L4 19.5l1.4-4.3A7.5 7.5 0 1 1 21 11.5z" />,
|
|
31
|
+
star: <path d="M12 3.5 14.6 9l6 .6-4.5 4 1.4 5.9L12 16.4 6.5 19.5 7.9 13.6 3.4 9.6l6-.6z" />,
|
|
32
|
+
gift: <path d="M4 9h16v11H4zM4 13h16M12 9v11M8.5 9a2.2 2.2 0 1 1 3.5-1.8M15.5 9a2.2 2.2 0 1 0-3.5-1.8" />,
|
|
33
|
+
leaf: <path d="M5 19c0-8 6-13 14-13 0 9-5 14-13 14a8 8 0 0 1 5-7" />,
|
|
34
|
+
clock: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM12 7v5l3.5 2" />,
|
|
35
|
+
card: <path d="M3 6.5h18v11H3zM3 10h18M6.5 14.5h4" />,
|
|
36
|
+
filter: <path d="M4 7h10M18 7h2M4 17h4M12 17h8M16 5v4M10 15v4" />,
|
|
37
|
+
zoom: <path d="M10.5 4a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13zM15.2 15.2 20 20M10.5 8v5M8 10.5h5" />,
|
|
38
|
+
link: <path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1" />,
|
|
39
|
+
share: <path d="M12 3.5v12M7.5 8 12 3.5 16.5 8M5 12.5v7h14v-7" />,
|
|
40
|
+
drop: <path d="M12 3s6 6.5 6 11a6 6 0 0 1-12 0c0-4.5 6-11 6-11z" />,
|
|
41
|
+
// utility
|
|
42
|
+
'arrow-right': <path d="M5 12h14M13 6l6 6-6 6" />,
|
|
43
|
+
'arrow-up-right': <path d="M7 17 17 7M8 7h9v9" />,
|
|
44
|
+
pause: <path d="M9 6v12M15 6v12" />,
|
|
45
|
+
play: <path d="M8 5v14l11-7z" />,
|
|
46
|
+
image: <path d="M4 5h16v14H4zM4 16l5-5 4 4 3-3 4 4M15 9.5a1.5 1.5 0 1 0 0-.01" />,
|
|
47
|
+
alert: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM12 8v5M12 16v.01" />,
|
|
48
|
+
info: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM12 11v5M12 8v.01" />,
|
|
49
|
+
// social (simplified marks)
|
|
50
|
+
instagram: <path d="M8.5 4h7A4.5 4.5 0 0 1 20 8.5v7a4.5 4.5 0 0 1-4.5 4.5h-7A4.5 4.5 0 0 1 4 15.5v-7A4.5 4.5 0 0 1 8.5 4zM12 8.4a3.6 3.6 0 1 0 0 7.2 3.6 3.6 0 0 0 0-7.2zM17 7v.01" />,
|
|
51
|
+
facebook: <path d="M14.5 8.5H16V5.6h-1.9c-1.9 0-3.1 1.2-3.1 3.1v1.8H9v2.9h2v6.1h3v-6.1h2.1l.5-2.9H14v-1.4c0-.4.2-.6.5-.6z" />,
|
|
52
|
+
x: <path d="M5 5l14 14M19 5 5 19" />,
|
|
53
|
+
tiktok: <path d="M13.5 5v9.2a3.3 3.3 0 1 1-2.4-3.18M13.5 5c.4 1.9 1.9 3.2 3.9 3.4" />,
|
|
54
|
+
youtube: <path d="M6.2 6.5h11.6A3.2 3.2 0 0 1 21 9.7v4.6a3.2 3.2 0 0 1-3.2 3.2H6.2A3.2 3.2 0 0 1 3 14.3V9.7a3.2 3.2 0 0 1 3.2-3.2zM11 9.8l4 2.2-4 2.2z" />,
|
|
55
|
+
// Nova 13 · feedback: every status carries an icon and a word (colour is a third signal).
|
|
56
|
+
warning: <path d="M12 4 21.5 20h-19L12 4zM12 10v4.5M12 17.2v.01" />,
|
|
57
|
+
error: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM9.2 9.2l5.6 5.6M14.8 9.2l-5.6 5.6" />,
|
|
58
|
+
trash: <path d="M5 7h14M10 7V5h4v2M7 7l1 12h8l1-12M10.5 10.5v5M13.5 10.5v5" />,
|
|
59
|
+
wifi: <path d="M3.5 9.5a12 12 0 0 1 17 0M6.5 12.8a7.5 7.5 0 0 1 11 0M9.5 16a3.2 3.2 0 0 1 5 0M12 19v.01" />,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Icons that point somewhere and so mirror under RTL. */
|
|
63
|
+
const DIRECTIONAL = new Set(['chevron-right', 'chevron-left', 'arrow-right', 'arrow-up-right', 'return'])
|
|
64
|
+
|
|
65
|
+
export const ICON_NAMES = Object.keys(PATHS) as IconName[]
|
|
66
|
+
export type IconName = keyof typeof PATHS & string
|
|
67
|
+
|
|
68
|
+
export type IconSize = 'sm' | 'md' | 'lg' | number
|
|
69
|
+
|
|
70
|
+
export interface IconProps {
|
|
71
|
+
name: IconName
|
|
72
|
+
size?: IconSize
|
|
73
|
+
/** Accessible name. Omit for decorative icons (the default). */
|
|
74
|
+
label?: string
|
|
75
|
+
className?: string
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const PX: Record<string, number> = { sm: 16, md: 20, lg: 24 }
|
|
79
|
+
|
|
80
|
+
export function Icon({ name, size = 'md', label, className }: IconProps): JSX.Element {
|
|
81
|
+
const px = typeof size === 'number' ? size : PX[size]
|
|
82
|
+
return (
|
|
83
|
+
<svg
|
|
84
|
+
className={['nv-icon', DIRECTIONAL.has(name) ? 'nv-dir' : '', className].filter(Boolean).join(' ')}
|
|
85
|
+
width={px}
|
|
86
|
+
height={px}
|
|
87
|
+
viewBox="0 0 24 24"
|
|
88
|
+
fill="none"
|
|
89
|
+
stroke="currentColor"
|
|
90
|
+
strokeLinecap="round"
|
|
91
|
+
strokeLinejoin="round"
|
|
92
|
+
data-icon={name}
|
|
93
|
+
role={label ? 'img' : undefined}
|
|
94
|
+
aria-label={label}
|
|
95
|
+
aria-hidden={label ? undefined : true}
|
|
96
|
+
focusable="false"
|
|
97
|
+
>
|
|
98
|
+
{PATHS[name]}
|
|
99
|
+
</svg>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { sx, sxJoin } from '@tanqory/theme-kit'
|
|
2
|
+
import { createContext, useContext, useMemo, type CSSProperties, type ReactNode } from 'react'
|
|
3
|
+
import { resolveTheme, type NovaThemeSettings } from './theme'
|
|
4
|
+
import { BUILTIN_STRINGS, STRINGS_EN, type NovaStrings } from './strings'
|
|
5
|
+
import './index.css'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Where a component is rendering:
|
|
9
|
+
* storefront — a shopper's page: an empty section renders nothing.
|
|
10
|
+
* editor — the Studio canvas: an empty section renders its setup frame
|
|
11
|
+
* (Nova 14 · Editor states) so the merchant can fill it.
|
|
12
|
+
*/
|
|
13
|
+
export type NovaMode = 'storefront' | 'editor'
|
|
14
|
+
|
|
15
|
+
export interface NovaContextValue {
|
|
16
|
+
readonly mode: NovaMode
|
|
17
|
+
readonly locale: string
|
|
18
|
+
readonly dir: 'ltr' | 'rtl'
|
|
19
|
+
readonly strings: NovaStrings
|
|
20
|
+
/** Current year, injectable so a copyright line is deterministic in tests. */
|
|
21
|
+
readonly year: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const NovaContext = createContext<NovaContextValue>({
|
|
25
|
+
mode: 'storefront',
|
|
26
|
+
locale: 'en',
|
|
27
|
+
dir: 'ltr',
|
|
28
|
+
strings: STRINGS_EN,
|
|
29
|
+
year: 2026,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
export function useNova(): NovaContextValue {
|
|
33
|
+
return useContext(NovaContext)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface NovaProviderProps {
|
|
37
|
+
mode?: NovaMode
|
|
38
|
+
/** BCP 47 language tag; drives `lang` and the built-in string set. */
|
|
39
|
+
locale?: string
|
|
40
|
+
/**
|
|
41
|
+
* The language the page's CONTENT is in (the store's, `ctx.locale.language`), when it differs from
|
|
42
|
+
* the interface strings' `locale` — a store language Nova ships no strings for falls back to
|
|
43
|
+
* English strings, but its merchant copy is still in its own language. Drives `lang` only.
|
|
44
|
+
*/
|
|
45
|
+
lang?: string
|
|
46
|
+
dir?: 'ltr' | 'rtl'
|
|
47
|
+
/** Overrides for the system strings (a storefront passes its locale file). */
|
|
48
|
+
strings?: Partial<NovaStrings>
|
|
49
|
+
/** Global theme settings (Level 1). Defaults write nothing. */
|
|
50
|
+
theme?: NovaThemeSettings
|
|
51
|
+
year?: number
|
|
52
|
+
className?: string
|
|
53
|
+
children: ReactNode
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The scope every Nova tree renders inside: tokens + base styles, theme
|
|
58
|
+
* settings as CSS variables on this element, `lang` / `dir`, and the context
|
|
59
|
+
* components read their mode and strings from. Presentational: no data.
|
|
60
|
+
*/
|
|
61
|
+
export function NovaProvider({ mode = 'storefront', locale = 'en', lang, dir, strings, theme, year = 2026, className, children }: NovaProviderProps): JSX.Element {
|
|
62
|
+
const base = BUILTIN_STRINGS[locale.split('-')[0]] ?? STRINGS_EN
|
|
63
|
+
const resolvedDir = dir ?? (/^(ar|he|fa|ur)\b/.test(locale) ? 'rtl' : 'ltr')
|
|
64
|
+
const value = useMemo<NovaContextValue>(
|
|
65
|
+
() => ({ mode, locale, dir: resolvedDir, strings: { ...base, ...strings }, year }),
|
|
66
|
+
[mode, locale, resolvedDir, base, strings, year],
|
|
67
|
+
)
|
|
68
|
+
const { vars, attrs } = useMemo(() => resolveTheme(theme), [theme])
|
|
69
|
+
return (
|
|
70
|
+
<NovaContext.Provider value={value}>
|
|
71
|
+
<div
|
|
72
|
+
className={sxJoin(['nv-root', className].filter(Boolean).join(' '), sx(vars as CSSProperties))}
|
|
73
|
+
lang={lang || locale}
|
|
74
|
+
dir={resolvedDir}
|
|
75
|
+
data-mode={mode}
|
|
76
|
+
{...attrs}
|
|
77
|
+
>
|
|
78
|
+
{children}
|
|
79
|
+
</div>
|
|
80
|
+
</NovaContext.Provider>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The theme's root for the platform (ThemeDefinition.Provider): Nova's provider, fed the store's settings. */
|
|
85
|
+
export function ThemeRoot({ mode, locale, contentLanguage, settings, children }: { mode: NovaMode; locale: string; contentLanguage?: string; settings: Readonly<Record<string, unknown>>; children: ReactNode }): JSX.Element {
|
|
86
|
+
return (
|
|
87
|
+
<NovaProvider mode={mode} locale={locale} lang={contentLanguage} theme={settings as NovaThemeSettings}>
|
|
88
|
+
{children}
|
|
89
|
+
</NovaProvider>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Nova base — reset, type roles, focus, long scripts, RTL.
|
|
3
|
+
*
|
|
4
|
+
* Scoped to `.nv-root` (the NovaProvider element) plus the document
|
|
5
|
+
* defaults every storefront needs, so the lab can host Nova inside any page
|
|
6
|
+
* without leaking a reset into it. Values are tokens only.
|
|
7
|
+
* ============================================================================ */
|
|
8
|
+
|
|
9
|
+
/* The storefront document: the page runs edge to edge (the browser's default
|
|
10
|
+
8px body margin framed every page in white). */
|
|
11
|
+
html,
|
|
12
|
+
body { margin: 0; padding: 0; }
|
|
13
|
+
|
|
14
|
+
.nv-root,
|
|
15
|
+
.nv-root *,
|
|
16
|
+
.nv-root *::before,
|
|
17
|
+
.nv-root *::after {
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.nv-root {
|
|
22
|
+
font-family: var(--font-body);
|
|
23
|
+
font-size: var(--type-body);
|
|
24
|
+
line-height: var(--leading-base);
|
|
25
|
+
color: var(--color-fg);
|
|
26
|
+
background: var(--color-bg);
|
|
27
|
+
-webkit-font-smoothing: antialiased;
|
|
28
|
+
-moz-osx-font-smoothing: grayscale;
|
|
29
|
+
text-rendering: optimizeLegibility;
|
|
30
|
+
font-feature-settings: 'kern' 1, 'liga' 1, 'calt' 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.nv-root :where(h1, h2, h3, h4, h5, h6, p, ul, ol, figure, blockquote, dl, dd) {
|
|
34
|
+
margin: 0;
|
|
35
|
+
padding: 0;
|
|
36
|
+
}
|
|
37
|
+
.nv-root :where(ul, ol) { list-style: none; }
|
|
38
|
+
.nv-root :where(img, picture, video, canvas, svg) { display: block; max-width: 100%; }
|
|
39
|
+
.nv-root :where(input, button, textarea, select) { font: inherit; color: inherit; }
|
|
40
|
+
.nv-root :where(button) { background: none; border: 0; padding: 0; cursor: pointer; }
|
|
41
|
+
.nv-root :where(a) { color: inherit; text-decoration: none; }
|
|
42
|
+
|
|
43
|
+
/* Inline links are ALWAYS underlined (02 · Link): inside running copy the
|
|
44
|
+
underline is the only thing that says "link". */
|
|
45
|
+
.nv-root :where(p a, .nv-prose a) {
|
|
46
|
+
text-decoration: underline;
|
|
47
|
+
text-underline-offset: var(--underline-offset);
|
|
48
|
+
text-decoration-thickness: var(--border-width);
|
|
49
|
+
transition: text-decoration-thickness var(--duration-fast) var(--ease-standard);
|
|
50
|
+
}
|
|
51
|
+
.nv-root :where(p a, .nv-prose a):hover { text-decoration-thickness: 2px; }
|
|
52
|
+
|
|
53
|
+
/* Heading roles — the ladder is in tokens.css; weight is the global
|
|
54
|
+
headingWeight setting; h6 is always one step heavier (01 typeRules). */
|
|
55
|
+
.nv-root :where(h1, h2, h3, h4, h5, h6, .nv-h1, .nv-h2, .nv-h3, .nv-h4, .nv-display) {
|
|
56
|
+
font-family: var(--font-display);
|
|
57
|
+
font-weight: var(--weight-heading);
|
|
58
|
+
color: inherit;
|
|
59
|
+
text-wrap: balance;
|
|
60
|
+
}
|
|
61
|
+
.nv-root :where(.nv-display) { font-size: var(--type-display); line-height: var(--leading-display); letter-spacing: var(--tracking-display); }
|
|
62
|
+
.nv-root :where(.nv-h1) { font-size: var(--type-h1); line-height: var(--leading-h1); letter-spacing: var(--tracking-h1); }
|
|
63
|
+
.nv-root :where(.nv-h2) { font-size: var(--type-h2); line-height: var(--leading-h2); letter-spacing: var(--tracking-h2); }
|
|
64
|
+
.nv-root :where(.nv-h3) { font-size: var(--type-h3); line-height: var(--leading-h3); letter-spacing: var(--tracking-h3); }
|
|
65
|
+
.nv-root :where(.nv-h4) { font-size: var(--type-h4); line-height: var(--leading-h4); }
|
|
66
|
+
.nv-root :where(p) { text-wrap: pretty; }
|
|
67
|
+
|
|
68
|
+
.nv-root :where(.nv-eyebrow) {
|
|
69
|
+
font-size: var(--type-label);
|
|
70
|
+
font-weight: var(--weight-medium);
|
|
71
|
+
line-height: var(--leading-tight);
|
|
72
|
+
color: var(--color-fg-muted);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Prices, quantities and counts are tabular everywhere. */
|
|
76
|
+
.nv-root :where(.nv-tabular) { font-variant-numeric: tabular-nums; }
|
|
77
|
+
|
|
78
|
+
/* Focus is ALWAYS a 2px ring at 2px offset in the fixed focus blue — never
|
|
79
|
+
the brand, so it cannot vanish into a brand fill. */
|
|
80
|
+
.nv-root :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
|
|
81
|
+
outline: var(--focus-ring-width) solid var(--color-focus);
|
|
82
|
+
outline-offset: var(--focus-ring-offset);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.nv-visually-hidden {
|
|
86
|
+
position: absolute !important;
|
|
87
|
+
width: 1px !important;
|
|
88
|
+
height: 1px !important;
|
|
89
|
+
padding: 0 !important;
|
|
90
|
+
margin: -1px !important;
|
|
91
|
+
overflow: hidden !important;
|
|
92
|
+
clip: rect(0 0 0 0) !important;
|
|
93
|
+
white-space: nowrap !important;
|
|
94
|
+
border: 0 !important;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Directional glyphs mirror in RTL. */
|
|
98
|
+
[dir='rtl'] .nv-dir { transform: scaleX(-1); }
|
|
99
|
+
|
|
100
|
+
/* ── Long scripts (01 typeRules · Round 2 · D17) ───────────────────────────
|
|
101
|
+
Thai: taller line boxes, tracking 0, no uppercase, never split a cluster. */
|
|
102
|
+
.nv-root:lang(th),
|
|
103
|
+
.nv-root :lang(th) { letter-spacing: 0; }
|
|
104
|
+
.nv-root:lang(th) :where(p, li, dd, .nv-prose),
|
|
105
|
+
.nv-root :lang(th) :where(p, li, dd, .nv-prose) { line-height: var(--leading-body-script); }
|
|
106
|
+
.nv-root:lang(th) :where(h1, h2, h3, .nv-display, .nv-h1, .nv-h2, .nv-h3),
|
|
107
|
+
.nv-root :lang(th) :where(h1, h2, h3, .nv-display, .nv-h1, .nv-h2, .nv-h3) { line-height: var(--leading-h4); letter-spacing: 0; }
|
|
108
|
+
.nv-root:lang(th) :where(p, li, h1, h2, h3, h4, h5, h6, .nv-btn),
|
|
109
|
+
.nv-root :lang(th) :where(p, li, h1, h2, h3, h4, h5, h6, .nv-btn) {
|
|
110
|
+
word-break: keep-all;
|
|
111
|
+
overflow-wrap: anywhere;
|
|
112
|
+
line-break: strict;
|
|
113
|
+
text-transform: none;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* RTL: layout mirrors through logical properties; leading 1.7+, tracking 0. */
|
|
117
|
+
.nv-root[dir='rtl'],
|
|
118
|
+
.nv-root [dir='rtl'] { letter-spacing: 0; }
|
|
119
|
+
.nv-root[dir='rtl'] :where(p, li, dd, .nv-prose) { line-height: var(--leading-body-script); }
|
|
120
|
+
.nv-root[dir='rtl'] :where(h1, h2, h3, .nv-display, .nv-h1, .nv-h2, .nv-h3) { line-height: var(--leading-h4); letter-spacing: 0; }
|
|
121
|
+
/* Merchant text keeps its own direction through <bdi> in the markup (the text
|
|
122
|
+
elements that render merchant or store text, and each RichText paragraph),
|
|
123
|
+
so "Halden & Co." keeps its period on an Arabic storefront while the element
|
|
124
|
+
keeps the page direction and alignment. Deliberately not a page-wide
|
|
125
|
+
unicode-bidi rule: that flipped the theme's own strings, prices and counts
|
|
126
|
+
(a bare "١٢", "English غير متاحة…") to LTR. */
|
|
127
|
+
|
|
128
|
+
/* The skip link — first focusable thing on every page (12A header guardrail). */
|
|
129
|
+
.nv-skip-link {
|
|
130
|
+
position: absolute;
|
|
131
|
+
inset-inline-start: var(--space-4);
|
|
132
|
+
top: var(--space-2);
|
|
133
|
+
z-index: var(--z-skip-link);
|
|
134
|
+
padding: var(--space-2) var(--space-4);
|
|
135
|
+
background: var(--color-bg);
|
|
136
|
+
color: var(--color-fg);
|
|
137
|
+
border-radius: var(--radius-md);
|
|
138
|
+
box-shadow: var(--shadow-popover);
|
|
139
|
+
transform: translateY(-200%);
|
|
140
|
+
}
|
|
141
|
+
.nv-skip-link:focus-visible { transform: none; }
|
|
142
|
+
.nv-scroll-lock, .nv-scroll-lock body { overflow: hidden; }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/* Blocks carry no outer margins; the parent owns spacing by pair (04C). */
|
|
2
|
+
.nv-block { min-width: 0; margin: 0; }
|
|
3
|
+
.nv-block[data-align='left'] { text-align: start; }
|
|
4
|
+
.nv-block[data-align='center'] { text-align: center; }
|
|
5
|
+
.nv-block[data-align='right'] { text-align: end; }
|
|
6
|
+
.nv-block__eyebrow { margin-bottom: var(--space-2); }
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
https://openfontlicense.org
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|