create-tanqory-theme 0.0.0-stage → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +55 -2
- package/bin/create-tanqory-theme.mjs +13 -0
- package/lib/agents.mjs +118 -0
- package/lib/create.mjs +245 -0
- package/package.json +39 -4
- package/templates/blank/README.md +13 -0
- package/templates/blank/config/settings.json +3 -0
- package/templates/blank/locales/en.json +22 -0
- package/templates/blank/locales/th.json +22 -0
- package/templates/blank/package.json +34 -0
- package/templates/blank/regions/footer.json +35 -0
- package/templates/blank/regions/header.json +13 -0
- package/templates/blank/scripts/build.mjs +193 -0
- package/templates/blank/scripts/probe.ts +4 -0
- package/templates/blank/src/bundle.ts +15 -0
- package/templates/blank/src/components/parts.tsx +32 -0
- package/templates/blank/src/entry.client.tsx +6 -0
- package/templates/blank/src/entry.server.tsx +13 -0
- package/templates/blank/src/sections/chrome.tsx +132 -0
- package/templates/blank/src/sections/commerce.tsx +242 -0
- package/templates/blank/src/sections/content.tsx +111 -0
- package/templates/blank/src/sections/editorial.tsx +107 -0
- package/templates/blank/src/settings.ts +15 -0
- package/templates/blank/src/styles/theme.css +195 -0
- package/templates/blank/src/templates.ts +14 -0
- package/templates/blank/src/theme.tsx +76 -0
- package/templates/blank/template.json +24 -0
- package/templates/blank/templates/404.json +14 -0
- package/templates/blank/templates/account.json +14 -0
- package/templates/blank/templates/article.json +14 -0
- package/templates/blank/templates/blog.json +14 -0
- package/templates/blank/templates/cart.json +14 -0
- package/templates/blank/templates/collection.json +14 -0
- package/templates/blank/templates/index.json +36 -0
- package/templates/blank/templates/page.contact.json +18 -0
- package/templates/blank/templates/page.json +14 -0
- package/templates/blank/templates/product.json +18 -0
- package/templates/blank/templates/search.json +14 -0
- package/templates/blank/tests/theme.test.ts +49 -0
- package/templates/blank/tsconfig.json +17 -0
- package/templates/blank/vite.client.config.ts +17 -0
- package/templates/blank/vite.probe.config.ts +16 -0
- package/templates/blank/vite.server.config.ts +32 -0
- package/templates/blank/vitest.config.ts +9 -0
- package/templates/common/.claude/settings.json +8 -0
- package/templates/common/.codex/config.toml +4 -0
- package/templates/common/.gemini/settings.json +12 -0
- package/templates/common/.github/workflows/theme-check.yml +44 -0
- package/templates/common/.mcp.json +12 -0
- package/templates/common/.vscode/mcp.json +9 -0
- package/templates/common/_gitignore +9 -0
- package/templates/common/scripts/check.mjs +44 -0
- package/templates/common/scripts/dev.mjs +30 -0
- package/templates/common/tanqory.config.json +6 -0
- package/templates/nova/.gitattributes +3 -0
- package/templates/nova/.tanqory/contracts/LOCK.json +66 -0
- package/templates/nova/.tanqory/contracts/nova-01.json +1092 -0
- package/templates/nova/.tanqory/contracts/nova-12A.json +2674 -0
- package/templates/nova/.tanqory/contracts/nova-12B.json +2285 -0
- package/templates/nova/.tanqory/contracts/nova-12C.json +2848 -0
- package/templates/nova/.tanqory/contracts/nova-12D.json +3039 -0
- package/templates/nova/.tanqory/contracts/nova-12E.json +1473 -0
- package/templates/nova/.tanqory/contracts/nova-12F.json +1670 -0
- package/templates/nova/.tanqory/contracts/nova-12G.json +1661 -0
- package/templates/nova/.tanqory/contracts/nova-13.json +301 -0
- package/templates/nova/.tanqory/contracts/nova-14.json +172 -0
- package/templates/nova/.tanqory/legacy-settings.json +1121 -0
- package/templates/nova/README.md +150 -0
- package/templates/nova/_gitignore +28 -0
- package/templates/nova/assets/ai-tokens.css +6 -0
- package/templates/nova/assets/starter/starter-art-1200x800-0b773ac4.svg +1 -0
- package/templates/nova/assets/starter/starter-art-1200x900-59600290.svg +1 -0
- package/templates/nova/assets/starter/starter-art-1200x900-c549d496.svg +1 -0
- package/templates/nova/assets/starter/starter-art-1600x900-8f979fcb.svg +1 -0
- package/templates/nova/assets/starter/starter-art-2100x900-cbb71bfd.svg +1 -0
- package/templates/nova/config/legacy-settings.json +438 -0
- package/templates/nova/config/promotion-popup.schema.ts +29 -0
- package/templates/nova/config/settings.json +23 -0
- package/templates/nova/config/settings.schema.ts +231 -0
- package/templates/nova/entry.abi.tsx +27 -0
- package/templates/nova/groups/footer.json +39 -0
- package/templates/nova/groups/header.json +11 -0
- package/templates/nova/lib/abi/abi.css +41 -0
- package/templates/nova/lib/bundle-core.ts +35 -0
- package/templates/nova/lib/bundle.client.ts +15 -0
- package/templates/nova/lib/bundle.ts +15 -0
- package/templates/nova/lib/legacy-settings.ts +104 -0
- package/templates/nova/locales/ar.json +590 -0
- package/templates/nova/locales/en.json +590 -0
- package/templates/nova/locales/th.json +590 -0
- package/templates/nova/main.abi.tsx +12 -0
- package/templates/nova/package.json +44 -0
- package/templates/nova/scripts/abi/build.mjs +145 -0
- package/templates/nova/scripts/abi/check-content.mjs +99 -0
- package/templates/nova/scripts/abi/jcs.mjs +27 -0
- package/templates/nova/scripts/abi/local-host.mjs +294 -0
- package/templates/nova/scripts/abi/manifest.mjs +392 -0
- package/templates/nova/scripts/abi/starter-assets.mjs +32 -0
- package/templates/nova/scripts/compiler/checks/check-a11y.mjs +88 -0
- package/templates/nova/scripts/compiler/checks/check-layout-sanity.mjs +169 -0
- package/templates/nova/scripts/compiler/checks/check-page-headings.mjs +67 -0
- package/templates/nova/scripts/compiler/checks/check-product-jsonld.mjs +80 -0
- package/templates/nova/scripts/compiler/checks/theme-spec/check.mjs +88 -0
- package/templates/nova/scripts/compiler/contracts/extract.mjs +188 -0
- package/templates/nova/scripts/compiler/contracts/index.ts +125 -0
- package/templates/nova/scripts/compiler/contracts/validate.ts +347 -0
- package/templates/nova/scripts/compiler/manifest/gen-manifest.mjs +156 -0
- package/templates/nova/scripts/compiler/manifest/manifest-entry.ts +386 -0
- package/templates/nova/scripts/compiler/manifest/manifest-sections.ts +247 -0
- package/templates/nova/scripts/compiler/migrate/migrate-content.mjs +171 -0
- package/templates/nova/scripts/compiler/migrate/migrate-groups.mjs +159 -0
- package/templates/nova/scripts/parity/case-shim.ts +14 -0
- package/templates/nova/scripts/parity/emit.ts +206 -0
- package/templates/nova/scripts/parity/index.html +12 -0
- package/templates/nova/scripts/parity/main.tsx +23 -0
- package/templates/nova/scripts/parity/pages.tsx +123 -0
- package/templates/nova/scripts/parity/vite.config.ts +29 -0
- package/templates/nova/src/components/base/Accordion.css +20 -0
- package/templates/nova/src/components/base/Accordion.tsx +50 -0
- package/templates/nova/src/components/base/Badge.css +17 -0
- package/templates/nova/src/components/base/Badge.tsx +26 -0
- package/templates/nova/src/components/base/Button.css +73 -0
- package/templates/nova/src/components/base/Button.tsx +64 -0
- package/templates/nova/src/components/base/Checkbox.tsx +18 -0
- package/templates/nova/src/components/base/Chip.css +20 -0
- package/templates/nova/src/components/base/Chip.tsx +33 -0
- package/templates/nova/src/components/base/Divider.css +6 -0
- package/templates/nova/src/components/base/Divider.tsx +28 -0
- package/templates/nova/src/components/base/IconButton.css +34 -0
- package/templates/nova/src/components/base/IconButton.tsx +41 -0
- package/templates/nova/src/components/base/Input.css +21 -0
- package/templates/nova/src/components/base/Input.tsx +24 -0
- package/templates/nova/src/components/base/Link.css +15 -0
- package/templates/nova/src/components/base/Link.tsx +23 -0
- package/templates/nova/src/components/base/Radio.tsx +13 -0
- package/templates/nova/src/components/base/Select.css +18 -0
- package/templates/nova/src/components/base/Select.tsx +34 -0
- package/templates/nova/src/components/base/Skeleton.css +17 -0
- package/templates/nova/src/components/base/Skeleton.tsx +23 -0
- package/templates/nova/src/components/base/Spinner.css +13 -0
- package/templates/nova/src/components/base/Spinner.tsx +8 -0
- package/templates/nova/src/components/base/Switch.tsx +16 -0
- package/templates/nova/src/components/base/Tabs.css +24 -0
- package/templates/nova/src/components/base/Tabs.tsx +61 -0
- package/templates/nova/src/components/base/Textarea.css +1 -0
- package/templates/nova/src/components/base/Textarea.tsx +8 -0
- package/templates/nova/src/components/base/choice-props.ts +9 -0
- package/templates/nova/src/components/base/choice.css +69 -0
- package/templates/nova/src/components/commerce/AddToCart.css +4 -0
- package/templates/nova/src/components/commerce/AddToCart.tsx +77 -0
- package/templates/nova/src/components/commerce/CartLine.css +26 -0
- package/templates/nova/src/components/commerce/CartLine.tsx +82 -0
- package/templates/nova/src/components/commerce/CartSummary.css +23 -0
- package/templates/nova/src/components/commerce/CartSummary.tsx +120 -0
- package/templates/nova/src/components/commerce/CollectionCard.css +66 -0
- package/templates/nova/src/components/commerce/CollectionCard.tsx +57 -0
- package/templates/nova/src/components/commerce/ComparisonTable.css +33 -0
- package/templates/nova/src/components/commerce/ComparisonTable.tsx +113 -0
- package/templates/nova/src/components/commerce/EarnHint.css +3 -0
- package/templates/nova/src/components/commerce/EarnHint.tsx +31 -0
- package/templates/nova/src/components/commerce/Hotspot.css +16 -0
- package/templates/nova/src/components/commerce/Hotspot.tsx +64 -0
- package/templates/nova/src/components/commerce/ListingParts.css +79 -0
- package/templates/nova/src/components/commerce/ListingParts.tsx +211 -0
- package/templates/nova/src/components/commerce/LookItem.css +19 -0
- package/templates/nova/src/components/commerce/LookItem.tsx +41 -0
- package/templates/nova/src/components/commerce/MiniCartLine.css +20 -0
- package/templates/nova/src/components/commerce/MiniCartLine.tsx +93 -0
- package/templates/nova/src/components/commerce/PaymentMark.css +2 -0
- package/templates/nova/src/components/commerce/PaymentMark.tsx +55 -0
- package/templates/nova/src/components/commerce/Price.css +27 -0
- package/templates/nova/src/components/commerce/Price.tsx +55 -0
- package/templates/nova/src/components/commerce/ProductCard.css +66 -0
- package/templates/nova/src/components/commerce/ProductCard.tsx +117 -0
- package/templates/nova/src/components/commerce/ProductGallery.css +72 -0
- package/templates/nova/src/components/commerce/ProductGallery.tsx +98 -0
- package/templates/nova/src/components/commerce/QuantitySelector.css +23 -0
- package/templates/nova/src/components/commerce/QuantitySelector.tsx +45 -0
- package/templates/nova/src/components/commerce/Reviews.css +34 -0
- package/templates/nova/src/components/commerce/Reviews.tsx +112 -0
- package/templates/nova/src/components/commerce/Stars.css +7 -0
- package/templates/nova/src/components/commerce/Stars.tsx +38 -0
- package/templates/nova/src/components/commerce/VariantPicker.css +31 -0
- package/templates/nova/src/components/commerce/VariantPicker.tsx +122 -0
- package/templates/nova/src/components/commerce/blocks/Badge.css +6 -0
- package/templates/nova/src/components/commerce/blocks/Badge.tsx +33 -0
- package/templates/nova/src/components/commerce/blocks/PaymentIcons.tsx +43 -0
- package/templates/nova/src/components/commerce/blocks/Swatches.tsx +17 -0
- package/templates/nova/src/components/commerce/blocks/payment.css +2 -0
- package/templates/nova/src/components/commerce/cart-limit.ts +11 -0
- package/templates/nova/src/components/commerce/money.ts +34 -0
- package/templates/nova/src/components/commerce/swatch.ts +54 -0
- package/templates/nova/src/components/content/ArticleCard.css +22 -0
- package/templates/nova/src/components/content/ArticleCard.tsx +53 -0
- package/templates/nova/src/components/content/BeforeAfterSlider.css +38 -0
- package/templates/nova/src/components/content/BeforeAfterSlider.tsx +87 -0
- package/templates/nova/src/components/content/CardRow.css +80 -0
- package/templates/nova/src/components/content/CardRow.tsx +140 -0
- package/templates/nova/src/components/content/CarouselControls.css +61 -0
- package/templates/nova/src/components/content/CarouselControls.tsx +90 -0
- package/templates/nova/src/components/content/ContentsNav.css +16 -0
- package/templates/nova/src/components/content/ContentsNav.tsx +55 -0
- package/templates/nova/src/components/content/Countdown.css +24 -0
- package/templates/nova/src/components/content/Countdown.tsx +115 -0
- package/templates/nova/src/components/content/HeroCopy.css +92 -0
- package/templates/nova/src/components/content/HeroCopy.tsx +148 -0
- package/templates/nova/src/components/content/HeroFrame.css +75 -0
- package/templates/nova/src/components/content/HeroFrame.tsx +49 -0
- package/templates/nova/src/components/content/HeroMedia.css +40 -0
- package/templates/nova/src/components/content/HeroMedia.tsx +170 -0
- package/templates/nova/src/components/content/LongForm.css +40 -0
- package/templates/nova/src/components/content/LongForm.tsx +56 -0
- package/templates/nova/src/components/content/MediaFrame.css +5 -0
- package/templates/nova/src/components/content/MediaFrame.tsx +52 -0
- package/templates/nova/src/components/content/RichText.tsx +30 -0
- package/templates/nova/src/components/content/SectionHead.css +8 -0
- package/templates/nova/src/components/content/SectionHead.tsx +34 -0
- package/templates/nova/src/components/content/ShareButtons.css +2 -0
- package/templates/nova/src/components/content/ShareButtons.tsx +40 -0
- package/templates/nova/src/components/content/StoreCard.css +14 -0
- package/templates/nova/src/components/content/StoreCard.tsx +60 -0
- package/templates/nova/src/components/content/TestimonialCard.css +36 -0
- package/templates/nova/src/components/content/TestimonialCard.tsx +102 -0
- package/templates/nova/src/components/content/UgcTile.css +8 -0
- package/templates/nova/src/components/content/UgcTile.tsx +33 -0
- package/templates/nova/src/components/content/blocks/Button.tsx +36 -0
- package/templates/nova/src/components/content/blocks/Column.tsx +30 -0
- package/templates/nova/src/components/content/blocks/Heading.tsx +31 -0
- package/templates/nova/src/components/content/blocks/Icon.tsx +25 -0
- package/templates/nova/src/components/content/blocks/Image.tsx +42 -0
- package/templates/nova/src/components/content/blocks/Text.tsx +26 -0
- package/templates/nova/src/components/content/blocks/Video.tsx +44 -0
- package/templates/nova/src/components/content/blocks/content.css +25 -0
- package/templates/nova/src/components/content/blocks/shared.ts +5 -0
- package/templates/nova/src/components/forms/ContactForm.css +19 -0
- package/templates/nova/src/components/forms/ContactForm.tsx +139 -0
- package/templates/nova/src/components/forms/FormField.css +15 -0
- package/templates/nova/src/components/forms/FormField.tsx +77 -0
- package/templates/nova/src/components/forms/GatewayFields.tsx +79 -0
- package/templates/nova/src/components/forms/NewsletterForm.css +9 -0
- package/templates/nova/src/components/forms/NewsletterForm.tsx +141 -0
- package/templates/nova/src/components/forms/SearchField.css +7 -0
- package/templates/nova/src/components/forms/SearchField.tsx +68 -0
- package/templates/nova/src/components/forms/blocks/Newsletter.css +5 -0
- package/templates/nova/src/components/forms/blocks/Newsletter.tsx +71 -0
- package/templates/nova/src/components/forms/validate.ts +4 -0
- package/templates/nova/src/components/listing/ProductListing.tsx +200 -0
- package/templates/nova/src/components/navigation/BrandLogo.tsx +35 -0
- package/templates/nova/src/components/navigation/Breadcrumb.css +16 -0
- package/templates/nova/src/components/navigation/Breadcrumb.tsx +59 -0
- package/templates/nova/src/components/navigation/LineAddFriend.css +5 -0
- package/templates/nova/src/components/navigation/LineAddFriend.tsx +42 -0
- package/templates/nova/src/components/navigation/LocaleSelector.css +33 -0
- package/templates/nova/src/components/navigation/LocaleSelector.tsx +64 -0
- package/templates/nova/src/components/navigation/Menu.tsx +26 -0
- package/templates/nova/src/components/navigation/Pagination.css +24 -0
- package/templates/nova/src/components/navigation/Pagination.tsx +74 -0
- package/templates/nova/src/components/navigation/RecoveryLinks.css +8 -0
- package/templates/nova/src/components/navigation/RecoveryLinks.tsx +23 -0
- package/templates/nova/src/components/navigation/SocialLinks.css +5 -0
- package/templates/nova/src/components/navigation/SocialLinks.tsx +51 -0
- package/templates/nova/src/components/navigation/blocks/SocialLinks.tsx +23 -0
- package/templates/nova/src/components/overlays/AccountMenu.css +11 -0
- package/templates/nova/src/components/overlays/AccountMenu.tsx +91 -0
- package/templates/nova/src/components/overlays/CartDrawer.css +17 -0
- package/templates/nova/src/components/overlays/CartDrawer.tsx +118 -0
- package/templates/nova/src/components/overlays/ConfirmationDialog.tsx +49 -0
- package/templates/nova/src/components/overlays/CookieConsent.css +56 -0
- package/templates/nova/src/components/overlays/CookieConsent.tsx +170 -0
- package/templates/nova/src/components/overlays/Drawer.css +38 -0
- package/templates/nova/src/components/overlays/Drawer.tsx +66 -0
- package/templates/nova/src/components/overlays/FriendOfferPanel.tsx +79 -0
- package/templates/nova/src/components/overlays/MarketSelector.css +111 -0
- package/templates/nova/src/components/overlays/MarketSelector.tsx +450 -0
- package/templates/nova/src/components/overlays/Menu.css +9 -0
- package/templates/nova/src/components/overlays/Menu.tsx +124 -0
- package/templates/nova/src/components/overlays/MobileNavDrawer.css +28 -0
- package/templates/nova/src/components/overlays/MobileNavDrawer.tsx +166 -0
- package/templates/nova/src/components/overlays/Modal.css +52 -0
- package/templates/nova/src/components/overlays/Modal.tsx +88 -0
- package/templates/nova/src/components/overlays/Popover.css +4 -0
- package/templates/nova/src/components/overlays/Popover.tsx +115 -0
- package/templates/nova/src/components/overlays/ProductLightbox.css +20 -0
- package/templates/nova/src/components/overlays/ProductLightbox.tsx +70 -0
- package/templates/nova/src/components/overlays/PromoPopup.css +32 -0
- package/templates/nova/src/components/overlays/PromoPopup.tsx +198 -0
- package/templates/nova/src/components/overlays/QuickView.css +31 -0
- package/templates/nova/src/components/overlays/QuickView.tsx +127 -0
- package/templates/nova/src/components/overlays/ReferralPanel.css +16 -0
- package/templates/nova/src/components/overlays/ReferralPanel.tsx +138 -0
- package/templates/nova/src/components/overlays/RewardsLauncher.css +22 -0
- package/templates/nova/src/components/overlays/RewardsLauncher.tsx +270 -0
- package/templates/nova/src/components/overlays/SearchModal.css +48 -0
- package/templates/nova/src/components/overlays/SearchModal.tsx +302 -0
- package/templates/nova/src/components/overlays/Sheet.css +16 -0
- package/templates/nova/src/components/overlays/Sheet.tsx +48 -0
- package/templates/nova/src/components/overlays/SizeGuide.css +8 -0
- package/templates/nova/src/components/overlays/SizeGuide.tsx +74 -0
- package/templates/nova/src/components/overlays/Toast.css +20 -0
- package/templates/nova/src/components/overlays/Toast.tsx +164 -0
- package/templates/nova/src/components/overlays/Tooltip.css +6 -0
- package/templates/nova/src/components/overlays/Tooltip.tsx +59 -0
- package/templates/nova/src/components/overlays/use-dialog.ts +74 -0
- package/templates/nova/src/components/section/shared.css +42 -0
- package/templates/nova/src/components/section/shared.ts +120 -0
- package/templates/nova/src/components/section/shell.tsx +29 -0
- package/templates/nova/src/components/states/Alert.css +10 -0
- package/templates/nova/src/components/states/Alert.tsx +50 -0
- package/templates/nova/src/components/states/EditorFrame.css +31 -0
- package/templates/nova/src/components/states/EditorFrame.tsx +43 -0
- package/templates/nova/src/components/states/MediaState.css +1 -0
- package/templates/nova/src/components/states/MediaState.tsx +49 -0
- package/templates/nova/src/components/states/OfflineNotice.css +4 -0
- package/templates/nova/src/components/states/OfflineNotice.tsx +24 -0
- package/templates/nova/src/components/states/SkeletonLayout.css +22 -0
- package/templates/nova/src/components/states/SkeletonLayout.tsx +104 -0
- package/templates/nova/src/components/states/StateBlock.css +22 -0
- package/templates/nova/src/components/states/StateBlock.tsx +39 -0
- package/templates/nova/src/components/states/media/MediaError.css +6 -0
- package/templates/nova/src/components/states/media/MediaError.tsx +49 -0
- package/templates/nova/src/components/states/media/MediaPlaceholder.css +24 -0
- package/templates/nova/src/components/states/media/MediaPlaceholder.tsx +101 -0
- package/templates/nova/src/components/states/media/placeholder-art.ts +142 -0
- package/templates/nova/src/layouts/Main.tsx +80 -0
- package/templates/nova/src/sections/Account/Account.tsx +109 -0
- package/templates/nova/src/sections/Account/index.ts +22 -0
- package/templates/nova/src/sections/Account/presets.ts +6 -0
- package/templates/nova/src/sections/Account/schema.ts +29 -0
- package/templates/nova/src/sections/AnnouncementBar/AnnouncementBar.css +37 -0
- package/templates/nova/src/sections/AnnouncementBar/AnnouncementBar.tsx +151 -0
- package/templates/nova/src/sections/AnnouncementBar/index.ts +20 -0
- package/templates/nova/src/sections/AnnouncementBar/presets.ts +10 -0
- package/templates/nova/src/sections/AnnouncementBar/schema.ts +26 -0
- package/templates/nova/src/sections/ArticleBody/ArticleBody.tsx +129 -0
- package/templates/nova/src/sections/ArticleBody/index.ts +21 -0
- package/templates/nova/src/sections/ArticleBody/presets.ts +10 -0
- package/templates/nova/src/sections/ArticleBody/schema.ts +40 -0
- package/templates/nova/src/sections/BeforeAfter/BeforeAfter.tsx +47 -0
- package/templates/nova/src/sections/BeforeAfter/blocks/Comparison.tsx +20 -0
- package/templates/nova/src/sections/BeforeAfter/index.ts +28 -0
- package/templates/nova/src/sections/BeforeAfter/presets.ts +10 -0
- package/templates/nova/src/sections/BeforeAfter/schema.ts +34 -0
- package/templates/nova/src/sections/BlogPosts/BlogPosts.tsx +106 -0
- package/templates/nova/src/sections/BlogPosts/index.ts +30 -0
- package/templates/nova/src/sections/BlogPosts/presets.ts +10 -0
- package/templates/nova/src/sections/BlogPosts/schema.ts +42 -0
- package/templates/nova/src/sections/Breadcrumbs/Breadcrumbs.css +10 -0
- package/templates/nova/src/sections/Breadcrumbs/Breadcrumbs.tsx +41 -0
- package/templates/nova/src/sections/Breadcrumbs/index.ts +20 -0
- package/templates/nova/src/sections/Breadcrumbs/presets.ts +6 -0
- package/templates/nova/src/sections/Breadcrumbs/schema.ts +24 -0
- package/templates/nova/src/sections/CartItems/CartItems.tsx +170 -0
- package/templates/nova/src/sections/CartItems/blocks/CartBadge.tsx +14 -0
- package/templates/nova/src/sections/CartItems/index.ts +37 -0
- package/templates/nova/src/sections/CartItems/presets.ts +8 -0
- package/templates/nova/src/sections/CartItems/schema.ts +34 -0
- package/templates/nova/src/sections/CollectionBanner/CollectionBanner.tsx +120 -0
- package/templates/nova/src/sections/CollectionBanner/index.ts +25 -0
- package/templates/nova/src/sections/CollectionBanner/presets.ts +10 -0
- package/templates/nova/src/sections/CollectionBanner/schema.ts +37 -0
- package/templates/nova/src/sections/CollectionLinks/CollectionLinks.tsx +47 -0
- package/templates/nova/src/sections/CollectionLinks/index.ts +20 -0
- package/templates/nova/src/sections/CollectionLinks/presets.ts +8 -0
- package/templates/nova/src/sections/CollectionLinks/schema.ts +33 -0
- package/templates/nova/src/sections/CollectionList/CollectionList.tsx +89 -0
- package/templates/nova/src/sections/CollectionList/blocks/CollectionItem.tsx +25 -0
- package/templates/nova/src/sections/CollectionList/index.ts +33 -0
- package/templates/nova/src/sections/CollectionList/presets.ts +10 -0
- package/templates/nova/src/sections/CollectionList/schema.ts +41 -0
- package/templates/nova/src/sections/ComparisonTable/ComparisonTable.tsx +52 -0
- package/templates/nova/src/sections/ComparisonTable/blocks/CompareItem.tsx +26 -0
- package/templates/nova/src/sections/ComparisonTable/index.ts +31 -0
- package/templates/nova/src/sections/ComparisonTable/presets.ts +8 -0
- package/templates/nova/src/sections/ComparisonTable/schema.ts +31 -0
- package/templates/nova/src/sections/ContactForm/ContactForm.tsx +83 -0
- package/templates/nova/src/sections/ContactForm/blocks/ContactDetail.tsx +13 -0
- package/templates/nova/src/sections/ContactForm/index.ts +29 -0
- package/templates/nova/src/sections/ContactForm/presets.ts +8 -0
- package/templates/nova/src/sections/ContactForm/schema.ts +34 -0
- package/templates/nova/src/sections/Divider/Divider.css +17 -0
- package/templates/nova/src/sections/Divider/Divider.tsx +21 -0
- package/templates/nova/src/sections/Divider/index.ts +20 -0
- package/templates/nova/src/sections/Divider/presets.ts +10 -0
- package/templates/nova/src/sections/Divider/schema.ts +24 -0
- package/templates/nova/src/sections/Faq/Faq.tsx +51 -0
- package/templates/nova/src/sections/Faq/blocks/FaqItem.tsx +13 -0
- package/templates/nova/src/sections/Faq/index.ts +28 -0
- package/templates/nova/src/sections/Faq/presets.ts +8 -0
- package/templates/nova/src/sections/Faq/schema.ts +32 -0
- package/templates/nova/src/sections/FeatureGridBlocks/FeatureGridBlocks.tsx +90 -0
- package/templates/nova/src/sections/FeatureGridBlocks/index.ts +35 -0
- package/templates/nova/src/sections/FeatureGridBlocks/presets.ts +8 -0
- package/templates/nova/src/sections/FeatureGridBlocks/schema.ts +35 -0
- package/templates/nova/src/sections/FeatureHighlights/FeatureHighlights.tsx +56 -0
- package/templates/nova/src/sections/FeatureHighlights/index.ts +20 -0
- package/templates/nova/src/sections/FeatureHighlights/presets.ts +6 -0
- package/templates/nova/src/sections/FeatureHighlights/schema.ts +27 -0
- package/templates/nova/src/sections/FeaturedCollection/FeaturedCollection.tsx +67 -0
- package/templates/nova/src/sections/FeaturedCollection/index.ts +21 -0
- package/templates/nova/src/sections/FeaturedCollection/presets.ts +10 -0
- package/templates/nova/src/sections/FeaturedCollection/schema.ts +39 -0
- package/templates/nova/src/sections/FeaturedProduct/FeaturedProduct.tsx +107 -0
- package/templates/nova/src/sections/FeaturedProduct/index.ts +23 -0
- package/templates/nova/src/sections/FeaturedProduct/presets.ts +8 -0
- package/templates/nova/src/sections/FeaturedProduct/schema.ts +35 -0
- package/templates/nova/src/sections/Footer/Footer.css +81 -0
- package/templates/nova/src/sections/Footer/Footer.tsx +256 -0
- package/templates/nova/src/sections/Footer/blocks/FooterBrand.tsx +40 -0
- package/templates/nova/src/sections/Footer/blocks/FooterLine.tsx +11 -0
- package/templates/nova/src/sections/Footer/blocks/FooterMenu.tsx +14 -0
- package/templates/nova/src/sections/Footer/blocks/FooterText.tsx +8 -0
- package/templates/nova/src/sections/Footer/blocks/footer.css +7 -0
- package/templates/nova/src/sections/Footer/index.ts +38 -0
- package/templates/nova/src/sections/Footer/presets.ts +10 -0
- package/templates/nova/src/sections/Footer/schema.ts +27 -0
- package/templates/nova/src/sections/Group/Group.css +59 -0
- package/templates/nova/src/sections/Group/Group.tsx +167 -0
- package/templates/nova/src/sections/Group/blocks/Accordion.tsx +26 -0
- package/templates/nova/src/sections/Group/blocks/JumboText.tsx +20 -0
- package/templates/nova/src/sections/Group/blocks/Spacer.tsx +16 -0
- package/templates/nova/src/sections/Group/index.ts +36 -0
- package/templates/nova/src/sections/Group/presets.ts +12 -0
- package/templates/nova/src/sections/Group/schema.ts +35 -0
- package/templates/nova/src/sections/Header/Header.css +185 -0
- package/templates/nova/src/sections/Header/Header.tsx +478 -0
- package/templates/nova/src/sections/Header/index.ts +32 -0
- package/templates/nova/src/sections/Header/presets.ts +10 -0
- package/templates/nova/src/sections/Header/schema.ts +32 -0
- package/templates/nova/src/sections/Hero/Hero.tsx +128 -0
- package/templates/nova/src/sections/Hero/index.ts +24 -0
- package/templates/nova/src/sections/Hero/presets.ts +16 -0
- package/templates/nova/src/sections/Hero/schema.ts +56 -0
- package/templates/nova/src/sections/ImageGallery/ImageGallery.tsx +86 -0
- package/templates/nova/src/sections/ImageGallery/index.ts +28 -0
- package/templates/nova/src/sections/ImageGallery/presets.ts +10 -0
- package/templates/nova/src/sections/ImageGallery/schema.ts +34 -0
- package/templates/nova/src/sections/ImageWithText/ImageWithText.tsx +62 -0
- package/templates/nova/src/sections/ImageWithText/index.ts +23 -0
- package/templates/nova/src/sections/ImageWithText/presets.ts +12 -0
- package/templates/nova/src/sections/ImageWithText/schema.ts +45 -0
- package/templates/nova/src/sections/LineAddFriend/LineAddFriend.tsx +25 -0
- package/templates/nova/src/sections/LineAddFriend/index.ts +20 -0
- package/templates/nova/src/sections/LineAddFriend/presets.ts +3 -0
- package/templates/nova/src/sections/LineAddFriend/schema.ts +25 -0
- package/templates/nova/src/sections/LogoList/LogoList.tsx +40 -0
- package/templates/nova/src/sections/LogoList/blocks/Logo.tsx +18 -0
- package/templates/nova/src/sections/LogoList/index.ts +29 -0
- package/templates/nova/src/sections/LogoList/presets.ts +8 -0
- package/templates/nova/src/sections/LogoList/schema.ts +29 -0
- package/templates/nova/src/sections/MainCollection/MainCollection.tsx +51 -0
- package/templates/nova/src/sections/MainCollection/index.ts +26 -0
- package/templates/nova/src/sections/MainCollection/presets.ts +10 -0
- package/templates/nova/src/sections/MainCollection/schema.ts +29 -0
- package/templates/nova/src/sections/Marquee/Marquee.tsx +114 -0
- package/templates/nova/src/sections/Marquee/index.ts +20 -0
- package/templates/nova/src/sections/Marquee/presets.ts +10 -0
- package/templates/nova/src/sections/Marquee/schema.ts +23 -0
- package/templates/nova/src/sections/Multicolumn/Multicolumn.tsx +56 -0
- package/templates/nova/src/sections/Multicolumn/index.ts +25 -0
- package/templates/nova/src/sections/Multicolumn/presets.ts +8 -0
- package/templates/nova/src/sections/Multicolumn/schema.ts +34 -0
- package/templates/nova/src/sections/Newsletter/Newsletter.tsx +64 -0
- package/templates/nova/src/sections/Newsletter/index.ts +20 -0
- package/templates/nova/src/sections/Newsletter/presets.ts +10 -0
- package/templates/nova/src/sections/Newsletter/schema.ts +36 -0
- package/templates/nova/src/sections/NotFound/NotFound.tsx +41 -0
- package/templates/nova/src/sections/NotFound/index.ts +20 -0
- package/templates/nova/src/sections/NotFound/presets.ts +6 -0
- package/templates/nova/src/sections/NotFound/schema.ts +30 -0
- package/templates/nova/src/sections/PageBody/PageBody.tsx +35 -0
- package/templates/nova/src/sections/PageBody/index.ts +21 -0
- package/templates/nova/src/sections/PageBody/presets.ts +6 -0
- package/templates/nova/src/sections/PageBody/schema.ts +29 -0
- package/templates/nova/src/sections/PolicyPage/PolicyPage.tsx +62 -0
- package/templates/nova/src/sections/PolicyPage/index.ts +23 -0
- package/templates/nova/src/sections/PolicyPage/presets.ts +6 -0
- package/templates/nova/src/sections/PolicyPage/schema.ts +27 -0
- package/templates/nova/src/sections/ProductDetails/ProductDetails.tsx +269 -0
- package/templates/nova/src/sections/ProductDetails/blocks/AddToCartBlock.tsx +15 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductDescription.tsx +15 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductInventory.tsx +38 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductPrice.tsx +19 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductSku.tsx +15 -0
- package/templates/nova/src/sections/ProductDetails/blocks/ProductTitle.tsx +17 -0
- package/templates/nova/src/sections/ProductDetails/blocks/Quantity.tsx +14 -0
- package/templates/nova/src/sections/ProductDetails/blocks/Tab.tsx +23 -0
- package/templates/nova/src/sections/ProductDetails/blocks/VariantPickerBlock.tsx +44 -0
- package/templates/nova/src/sections/ProductDetails/blocks/commerce-blocks.css +13 -0
- package/templates/nova/src/sections/ProductDetails/index.ts +44 -0
- package/templates/nova/src/sections/ProductDetails/presets.ts +10 -0
- package/templates/nova/src/sections/ProductDetails/schema.ts +44 -0
- package/templates/nova/src/sections/ProductGrid/ProductGrid.tsx +38 -0
- package/templates/nova/src/sections/ProductGrid/index.ts +25 -0
- package/templates/nova/src/sections/ProductGrid/presets.ts +6 -0
- package/templates/nova/src/sections/ProductGrid/schema.ts +37 -0
- package/templates/nova/src/sections/ProductRecommendations/ProductRecommendations.tsx +45 -0
- package/templates/nova/src/sections/ProductRecommendations/index.ts +20 -0
- package/templates/nova/src/sections/ProductRecommendations/presets.ts +8 -0
- package/templates/nova/src/sections/ProductRecommendations/schema.ts +28 -0
- package/templates/nova/src/sections/ProductReviews/ProductReviews.tsx +136 -0
- package/templates/nova/src/sections/ProductReviews/index.ts +22 -0
- package/templates/nova/src/sections/ProductReviews/presets.ts +6 -0
- package/templates/nova/src/sections/ProductReviews/schema.ts +31 -0
- package/templates/nova/src/sections/PromoBanner/PromoBanner.tsx +78 -0
- package/templates/nova/src/sections/PromoBanner/index.ts +20 -0
- package/templates/nova/src/sections/PromoBanner/presets.ts +10 -0
- package/templates/nova/src/sections/PromoBanner/schema.ts +38 -0
- package/templates/nova/src/sections/RecentlyViewed/RecentlyViewed.tsx +53 -0
- package/templates/nova/src/sections/RecentlyViewed/index.ts +20 -0
- package/templates/nova/src/sections/RecentlyViewed/presets.ts +6 -0
- package/templates/nova/src/sections/RecentlyViewed/schema.ts +26 -0
- package/templates/nova/src/sections/RichText/RichText.tsx +38 -0
- package/templates/nova/src/sections/RichText/index.ts +20 -0
- package/templates/nova/src/sections/RichText/presets.ts +10 -0
- package/templates/nova/src/sections/RichText/schema.ts +37 -0
- package/templates/nova/src/sections/SearchResults/SearchResults.tsx +112 -0
- package/templates/nova/src/sections/SearchResults/index.ts +26 -0
- package/templates/nova/src/sections/SearchResults/presets.ts +8 -0
- package/templates/nova/src/sections/SearchResults/schema.ts +30 -0
- package/templates/nova/src/sections/ShopTheLook/ShopTheLook.tsx +112 -0
- package/templates/nova/src/sections/ShopTheLook/blocks/Hotspot.tsx +22 -0
- package/templates/nova/src/sections/ShopTheLook/index.ts +33 -0
- package/templates/nova/src/sections/ShopTheLook/presets.ts +8 -0
- package/templates/nova/src/sections/ShopTheLook/schema.ts +31 -0
- package/templates/nova/src/sections/Slideshow/Slideshow.tsx +199 -0
- package/templates/nova/src/sections/Slideshow/blocks/Slide.tsx +93 -0
- package/templates/nova/src/sections/Slideshow/index.ts +30 -0
- package/templates/nova/src/sections/Slideshow/presets.ts +10 -0
- package/templates/nova/src/sections/Slideshow/schema.ts +36 -0
- package/templates/nova/src/sections/StoreLocator/StoreLocator.tsx +66 -0
- package/templates/nova/src/sections/StoreLocator/index.ts +20 -0
- package/templates/nova/src/sections/StoreLocator/presets.ts +6 -0
- package/templates/nova/src/sections/StoreLocator/schema.ts +34 -0
- package/templates/nova/src/sections/TeamFounders/TeamFounders.tsx +74 -0
- package/templates/nova/src/sections/TeamFounders/blocks/Person.tsx +28 -0
- package/templates/nova/src/sections/TeamFounders/index.ts +28 -0
- package/templates/nova/src/sections/TeamFounders/presets.ts +10 -0
- package/templates/nova/src/sections/TeamFounders/schema.ts +36 -0
- package/templates/nova/src/sections/Testimonials/Testimonials.tsx +83 -0
- package/templates/nova/src/sections/Testimonials/blocks/Testimonial.tsx +30 -0
- package/templates/nova/src/sections/Testimonials/index.ts +29 -0
- package/templates/nova/src/sections/Testimonials/presets.ts +10 -0
- package/templates/nova/src/sections/Testimonials/schema.ts +35 -0
- package/templates/nova/src/sections/Timeline/Timeline.tsx +43 -0
- package/templates/nova/src/sections/Timeline/blocks/Step.tsx +19 -0
- package/templates/nova/src/sections/Timeline/index.ts +28 -0
- package/templates/nova/src/sections/Timeline/presets.ts +8 -0
- package/templates/nova/src/sections/Timeline/schema.ts +31 -0
- package/templates/nova/src/sections/TrustBadges/TrustBadges.tsx +42 -0
- package/templates/nova/src/sections/TrustBadges/index.ts +29 -0
- package/templates/nova/src/sections/TrustBadges/presets.ts +8 -0
- package/templates/nova/src/sections/TrustBadges/schema.ts +29 -0
- package/templates/nova/src/sections/UgcGallery/UgcGallery.tsx +58 -0
- package/templates/nova/src/sections/UgcGallery/blocks/UgcImage.tsx +27 -0
- package/templates/nova/src/sections/UgcGallery/index.ts +31 -0
- package/templates/nova/src/sections/UgcGallery/presets.ts +8 -0
- package/templates/nova/src/sections/UgcGallery/schema.ts +35 -0
- package/templates/nova/src/sections/VideoHero/VideoHero.tsx +75 -0
- package/templates/nova/src/sections/VideoHero/index.ts +22 -0
- package/templates/nova/src/sections/VideoHero/presets.ts +8 -0
- package/templates/nova/src/sections/VideoHero/schema.ts +43 -0
- package/templates/nova/src/sections/data.ts +115 -0
- package/templates/nova/src/sections/shipped-copy.ts +25 -0
- package/templates/nova/src/sections/starter.ts +49 -0
- package/templates/nova/src/styles/Container.css +6 -0
- package/templates/nova/src/styles/Container.tsx +13 -0
- package/templates/nova/src/styles/Icon.css +2 -0
- package/templates/nova/src/styles/Icon.tsx +101 -0
- package/templates/nova/src/styles/NovaProvider.tsx +91 -0
- package/templates/nova/src/styles/base.css +142 -0
- package/templates/nova/src/styles/blocks.css +6 -0
- package/templates/nova/src/styles/fonts/OFL.txt +93 -0
- package/templates/nova/src/styles/fonts/geist-cyrillic-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-cyrillic.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-latin-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-latin.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-cyrillic-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-cyrillic.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-latin-ext.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-latin.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-mono-vietnamese.woff2 +0 -0
- package/templates/nova/src/styles/fonts/geist-vietnamese.woff2 +0 -0
- package/templates/nova/src/styles/fonts.css +95 -0
- package/templates/nova/src/styles/global-settings.css +88 -0
- package/templates/nova/src/styles/index.css +6 -0
- package/templates/nova/src/styles/motion.ts +53 -0
- package/templates/nova/src/styles/scroll.ts +24 -0
- package/templates/nova/src/styles/sections/commerce.css +147 -0
- package/templates/nova/src/styles/sections/content.css +304 -0
- package/templates/nova/src/styles/sections/editorial.css +131 -0
- package/templates/nova/src/styles/sections/promotion.css +336 -0
- package/templates/nova/src/styles/sections/trust.css +117 -0
- package/templates/nova/src/styles/sections/utility.css +190 -0
- package/templates/nova/src/styles/strings.ts +492 -0
- package/templates/nova/src/styles/text.ts +4 -0
- package/templates/nova/src/styles/theme.ts +171 -0
- package/templates/nova/src/styles/tokens.css +600 -0
- package/templates/nova/src/styles/viewport.ts +23 -0
- package/templates/nova/template.json +94 -0
- package/templates/nova/templates/404.json +30 -0
- package/templates/nova/templates/account.json +15 -0
- package/templates/nova/templates/article.json +41 -0
- package/templates/nova/templates/article.longform.json +17 -0
- package/templates/nova/templates/blog.featured.json +22 -0
- package/templates/nova/templates/blog.json +29 -0
- package/templates/nova/templates/cart.json +67 -0
- package/templates/nova/templates/collection.featured.json +43 -0
- package/templates/nova/templates/collection.json +30 -0
- package/templates/nova/templates/contact.json +65 -0
- package/templates/nova/templates/index.json +167 -0
- package/templates/nova/templates/list-collections.json +19 -0
- package/templates/nova/templates/page.about.json +134 -0
- package/templates/nova/templates/page.contact.json +27 -0
- package/templates/nova/templates/page.json +27 -0
- package/templates/nova/templates/policy.json +23 -0
- package/templates/nova/templates/product.bundle.json +145 -0
- package/templates/nova/templates/product.json +119 -0
- package/templates/nova/templates/search.json +17 -0
- package/templates/nova/tests/abi-ai-contract.test.ts +99 -0
- package/templates/nova/tests/abi-forms.test.tsx +269 -0
- package/templates/nova/tests/abi-inventory.test.tsx +197 -0
- package/templates/nova/tests/abi-legacy-settings.test.tsx +105 -0
- package/templates/nova/tests/abi-opt-in.test.tsx +100 -0
- package/templates/nova/tests/abi-parity.test.tsx +95 -0
- package/templates/nova/tests/abi-r5-store-settings.test.tsx +337 -0
- package/templates/nova/tests/abi-render.test.tsx +178 -0
- package/templates/nova/tests/abi-shop-links.test.tsx +141 -0
- package/templates/nova/tests/abi-storefront-basics.test.tsx +233 -0
- package/templates/nova/tests/abi-variant-url.test.tsx +73 -0
- package/templates/nova/tests/add-refused-no-success.test.tsx +193 -0
- package/templates/nova/tests/architecture.test.ts +63 -0
- package/templates/nova/tests/architecture.ts +160 -0
- package/templates/nova/tests/audit-guards.test.ts +31 -0
- package/templates/nova/tests/bundle-split.test.ts +29 -0
- package/templates/nova/tests/cart-limit-message.test.tsx +212 -0
- package/templates/nova/tests/cart-link-message.test.tsx +98 -0
- package/templates/nova/tests/cases/components/Overview.cases.tsx +8 -0
- package/templates/nova/tests/cases/components/base/Accordion.cases.tsx +40 -0
- package/templates/nova/tests/cases/components/base/Badge.cases.tsx +30 -0
- package/templates/nova/tests/cases/components/base/Button.cases.tsx +73 -0
- package/templates/nova/tests/cases/components/base/Checkbox.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/base/Chip.cases.tsx +37 -0
- package/templates/nova/tests/cases/components/base/Divider.cases.tsx +26 -0
- package/templates/nova/tests/cases/components/base/IconButton.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/base/Input.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/base/Link.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/base/Radio.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/base/Select.cases.tsx +26 -0
- package/templates/nova/tests/cases/components/base/Skeleton.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/base/Spinner.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/base/Switch.cases.tsx +26 -0
- package/templates/nova/tests/cases/components/base/Tabs.cases.tsx +39 -0
- package/templates/nova/tests/cases/components/base/Textarea.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/commerce/AddToCart.cases.tsx +36 -0
- package/templates/nova/tests/cases/components/commerce/CartLine.cases.tsx +20 -0
- package/templates/nova/tests/cases/components/commerce/CartSummary.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/commerce/CollectionCard.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/commerce/ComparisonTable.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/commerce/Hotspot.cases.tsx +25 -0
- package/templates/nova/tests/cases/components/commerce/LookItem.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/commerce/PaymentMark.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/commerce/Price.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/commerce/ProductCard.cases.tsx +67 -0
- package/templates/nova/tests/cases/components/commerce/ProductGallery.cases.tsx +39 -0
- package/templates/nova/tests/cases/components/commerce/QuantitySelector.cases.tsx +31 -0
- package/templates/nova/tests/cases/components/commerce/Reviews.cases.tsx +35 -0
- package/templates/nova/tests/cases/components/commerce/Stars.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/commerce/VariantPicker.cases.tsx +38 -0
- package/templates/nova/tests/cases/components/commerce/blocks/Badge.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/commerce/blocks/PaymentIcons.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/commerce/blocks/Swatches.cases.tsx +22 -0
- package/templates/nova/tests/cases/components/content/ArticleCard.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/BeforeAfterSlider.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/CardRow.cases.tsx +23 -0
- package/templates/nova/tests/cases/components/content/CarouselControls.cases.tsx +48 -0
- package/templates/nova/tests/cases/components/content/ContentsNav.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/Countdown.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/content/HeroCopy.cases.tsx +42 -0
- package/templates/nova/tests/cases/components/content/HeroFrame.cases.tsx +22 -0
- package/templates/nova/tests/cases/components/content/HeroMedia.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/LongForm.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/MediaFrame.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/content/RichText.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/content/SectionHead.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/content/ShareButtons.cases.tsx +24 -0
- package/templates/nova/tests/cases/components/content/StoreCard.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/TestimonialCard.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/content/UgcTile.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/blocks/Button.cases.tsx +20 -0
- package/templates/nova/tests/cases/components/content/blocks/Column.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/blocks/Heading.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/blocks/Icon.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/content/blocks/Image.cases.tsx +22 -0
- package/templates/nova/tests/cases/components/content/blocks/Text.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/content/blocks/Video.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/forms/ContactForm.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/forms/FormField.cases.tsx +61 -0
- package/templates/nova/tests/cases/components/forms/NewsletterForm.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/forms/SearchField.cases.tsx +25 -0
- package/templates/nova/tests/cases/components/forms/blocks/Newsletter.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/navigation/BrandLogo.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/navigation/Breadcrumb.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/navigation/LocaleSelector.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/navigation/Menu.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/navigation/Pagination.cases.tsx +25 -0
- package/templates/nova/tests/cases/components/navigation/RecoveryLinks.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/navigation/SocialLinks.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/navigation/blocks/SocialLinks.cases.tsx +17 -0
- package/templates/nova/tests/cases/components/overlays/AccountMenu.cases.tsx +28 -0
- package/templates/nova/tests/cases/components/overlays/CartDrawer.cases.tsx +30 -0
- package/templates/nova/tests/cases/components/overlays/ConfirmationDialog.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/overlays/CookieConsent.cases.tsx +23 -0
- package/templates/nova/tests/cases/components/overlays/CookiePreferences.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/overlays/Drawer.cases.tsx +52 -0
- package/templates/nova/tests/cases/components/overlays/MarketSelector.cases.tsx +82 -0
- package/templates/nova/tests/cases/components/overlays/Menu.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/overlays/MobileNavDrawer.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/overlays/Modal.cases.tsx +71 -0
- package/templates/nova/tests/cases/components/overlays/Popover.cases.tsx +50 -0
- package/templates/nova/tests/cases/components/overlays/PromoPopup.cases.tsx +19 -0
- package/templates/nova/tests/cases/components/overlays/QuickView.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/overlays/SearchModal.cases.tsx +60 -0
- package/templates/nova/tests/cases/components/overlays/Sheet.cases.tsx +32 -0
- package/templates/nova/tests/cases/components/overlays/SizeGuide.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/overlays/Toast.cases.tsx +48 -0
- package/templates/nova/tests/cases/components/overlays/Tooltip.cases.tsx +33 -0
- package/templates/nova/tests/cases/components/states/Alert.cases.tsx +27 -0
- package/templates/nova/tests/cases/components/states/EditorFrame.cases.tsx +36 -0
- package/templates/nova/tests/cases/components/states/Empty.cases.tsx +30 -0
- package/templates/nova/tests/cases/components/states/Error.cases.tsx +38 -0
- package/templates/nova/tests/cases/components/states/Loading.cases.tsx +15 -0
- package/templates/nova/tests/cases/components/states/MediaState.cases.tsx +29 -0
- package/templates/nova/tests/cases/components/states/SkeletonLayout.cases.tsx +20 -0
- package/templates/nova/tests/cases/components/states/Unavailable.cases.tsx +16 -0
- package/templates/nova/tests/cases/components/states/media/MediaError.cases.tsx +18 -0
- package/templates/nova/tests/cases/components/states/media/MediaPlaceholder.cases.tsx +87 -0
- package/templates/nova/tests/cases/sections/Overview.cases.tsx +8 -0
- package/templates/nova/tests/cases/sections/commerce/collection-list/CollectionList.cases.tsx +46 -0
- package/templates/nova/tests/cases/sections/commerce/collection-list/blocks/CollectionItem.cases.tsx +18 -0
- package/templates/nova/tests/cases/sections/commerce/featured-collection/FeaturedCollection.cases.tsx +46 -0
- package/templates/nova/tests/cases/sections/commerce/featured-product/FeaturedProduct.cases.tsx +40 -0
- package/templates/nova/tests/cases/sections/commerce/main-collection/MainCollection.cases.tsx +81 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/ProductDetails.cases.tsx +110 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/AddToCartBlock.cases.tsx +21 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductDescription.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductInventory.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductPrice.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductSku.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductTitle.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/Quantity.cases.tsx +20 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/Tab.cases.tsx +29 -0
- package/templates/nova/tests/cases/sections/commerce/product-details/blocks/VariantPickerBlock.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/commerce/product-grid/ProductGrid.cases.tsx +48 -0
- package/templates/nova/tests/cases/sections/commerce/product-recommendations/ProductRecommendations.cases.tsx +27 -0
- package/templates/nova/tests/cases/sections/commerce/recently-viewed/RecentlyViewed.cases.tsx +36 -0
- package/templates/nova/tests/cases/sections/content/article-body/ArticleBody.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/content/before-after/BeforeAfter.cases.tsx +40 -0
- package/templates/nova/tests/cases/sections/content/before-after/blocks/Comparison.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/content/blog-posts/BlogPosts.cases.tsx +47 -0
- package/templates/nova/tests/cases/sections/content/collection-links/CollectionLinks.cases.tsx +36 -0
- package/templates/nova/tests/cases/sections/content/faq/Faq.cases.tsx +38 -0
- package/templates/nova/tests/cases/sections/content/faq/blocks/FaqItem.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/content/feature-grid-blocks/FeatureGridBlocks.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/feature-highlights/FeatureHighlights.cases.tsx +26 -0
- package/templates/nova/tests/cases/sections/content/image-gallery/ImageGallery.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/image-with-text/ImageWithText.cases.tsx +35 -0
- package/templates/nova/tests/cases/sections/content/multicolumn/Multicolumn.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/content/page-body/PageBody.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/rich-text/RichTextSection.cases.tsx +33 -0
- package/templates/nova/tests/cases/sections/content/team-founders/TeamFounders.cases.tsx +31 -0
- package/templates/nova/tests/cases/sections/content/team-founders/blocks/Person.cases.tsx +18 -0
- package/templates/nova/tests/cases/sections/content/timeline/Timeline.cases.tsx +27 -0
- package/templates/nova/tests/cases/sections/content/timeline/blocks/Step.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/layout/announcement-bar/AnnouncementBar.cases.tsx +119 -0
- package/templates/nova/tests/cases/sections/layout/breadcrumbs/Breadcrumbs.cases.tsx +73 -0
- package/templates/nova/tests/cases/sections/layout/divider/Divider.cases.tsx +81 -0
- package/templates/nova/tests/cases/sections/layout/footer/Footer.cases.tsx +116 -0
- package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterBrand.cases.tsx +27 -0
- package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterMenu.cases.tsx +22 -0
- package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterText.cases.tsx +20 -0
- package/templates/nova/tests/cases/sections/layout/group/Group.cases.tsx +185 -0
- package/templates/nova/tests/cases/sections/layout/group/blocks/Accordion.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/layout/group/blocks/JumboText.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/layout/group/blocks/Spacer.cases.tsx +33 -0
- package/templates/nova/tests/cases/sections/layout/header/Header.cases.tsx +277 -0
- package/templates/nova/tests/cases/sections/marketing/collection-banner/CollectionBanner.cases.tsx +62 -0
- package/templates/nova/tests/cases/sections/marketing/hero/Hero.cases.tsx +138 -0
- package/templates/nova/tests/cases/sections/marketing/marquee/Marquee.cases.tsx +63 -0
- package/templates/nova/tests/cases/sections/marketing/promo-banner/PromoBanner.cases.tsx +87 -0
- package/templates/nova/tests/cases/sections/marketing/slideshow/Slideshow.cases.tsx +113 -0
- package/templates/nova/tests/cases/sections/marketing/slideshow/blocks/Slide.cases.tsx +26 -0
- package/templates/nova/tests/cases/sections/marketing/video-hero/VideoHero.cases.tsx +72 -0
- package/templates/nova/tests/cases/sections/trust/comparison-table/ComparisonTableSection.cases.tsx +42 -0
- package/templates/nova/tests/cases/sections/trust/comparison-table/blocks/CompareItem.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/logo-list/LogoList.cases.tsx +29 -0
- package/templates/nova/tests/cases/sections/trust/logo-list/blocks/Logo.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/product-reviews/ProductReviews.cases.tsx +51 -0
- package/templates/nova/tests/cases/sections/trust/shop-the-look/ShopTheLook.cases.tsx +51 -0
- package/templates/nova/tests/cases/sections/trust/shop-the-look/blocks/Hotspot.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/testimonials/Testimonials.cases.tsx +61 -0
- package/templates/nova/tests/cases/sections/trust/testimonials/blocks/Testimonial.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/trust/trust-badges/TrustBadges.cases.tsx +30 -0
- package/templates/nova/tests/cases/sections/trust/ugc-gallery/UgcGallery.cases.tsx +32 -0
- package/templates/nova/tests/cases/sections/trust/ugc-gallery/blocks/UgcImage.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/utility/account/Account.cases.tsx +44 -0
- package/templates/nova/tests/cases/sections/utility/cart-items/CartItems.cases.tsx +43 -0
- package/templates/nova/tests/cases/sections/utility/cart-items/blocks/CartBadge.cases.tsx +16 -0
- package/templates/nova/tests/cases/sections/utility/contact-form/ContactFormSection.cases.tsx +52 -0
- package/templates/nova/tests/cases/sections/utility/contact-form/blocks/ContactDetail.cases.tsx +17 -0
- package/templates/nova/tests/cases/sections/utility/newsletter/NewsletterSection.cases.tsx +109 -0
- package/templates/nova/tests/cases/sections/utility/not-found/NotFound.cases.tsx +28 -0
- package/templates/nova/tests/cases/sections/utility/policy-page/PolicyPage.cases.tsx +29 -0
- package/templates/nova/tests/cases/sections/utility/search-results/SearchResultsSection.cases.tsx +39 -0
- package/templates/nova/tests/cases/sections/utility/store-locator/StoreLocator.cases.tsx +40 -0
- package/templates/nova/tests/cases/styles/Borders.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Breakpoints.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Colors.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Elevation.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Icon.cases.tsx +23 -0
- package/templates/nova/tests/cases/styles/Layout.cases.tsx +8 -0
- package/templates/nova/tests/cases/styles/Motion.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Overview.cases.tsx +8 -0
- package/templates/nova/tests/cases/styles/Radius.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/SharedThemeSettings.cases.tsx +19 -0
- package/templates/nova/tests/cases/styles/Spacing.cases.tsx +10 -0
- package/templates/nova/tests/cases/styles/Typography.cases.tsx +10 -0
- package/templates/nova/tests/cases.test.tsx +38 -0
- package/templates/nova/tests/components/PromoPopup.test.ts +21 -0
- package/templates/nova/tests/components/RichText.test.tsx +65 -0
- package/templates/nova/tests/components/formatDate.test.ts +10 -0
- package/templates/nova/tests/contract-locks.test.ts +23 -0
- package/templates/nova/tests/contracts.test.ts +153 -0
- package/templates/nova/tests/cookie-consent-privacy.test.tsx +128 -0
- package/templates/nova/tests/empty-store.test.tsx +81 -0
- package/templates/nova/tests/fixtures/commerce.ts +128 -0
- package/templates/nova/tests/fixtures/content.ts +58 -0
- package/templates/nova/tests/fixtures/index.ts +8 -0
- package/templates/nova/tests/fixtures/merch.ts +161 -0
- package/templates/nova/tests/fixtures/navigation.ts +125 -0
- package/templates/nova/tests/fixtures/promotion.ts +43 -0
- package/templates/nova/tests/fixtures/sample-store.json +1674 -0
- package/templates/nova/tests/fixtures/shop.ts +88 -0
- package/templates/nova/tests/fixtures/stress.ts +21 -0
- package/templates/nova/tests/inert.test.tsx +285 -0
- package/templates/nova/tests/line-add-friend.test.tsx +108 -0
- package/templates/nova/tests/localized-copy.test.ts +330 -0
- package/templates/nova/tests/product-template-blocks.test.ts +28 -0
- package/templates/nova/tests/rewards-launcher.test.tsx +401 -0
- package/templates/nova/tests/schema.test.ts +65 -0
- package/templates/nova/tests/schema.typetest.ts +7 -0
- package/templates/nova/tests/section-groups.test.ts +189 -0
- package/templates/nova/tests/sections/Group.test.tsx +37 -0
- package/templates/nova/tests/setup.ts +30 -0
- package/templates/nova/tests/starter.test.ts +56 -0
- package/templates/nova/tests/storefront-click-path.test.tsx +157 -0
- package/templates/nova/tests/styles/button-brand.test.ts +24 -0
- package/templates/nova/tests/styles/theme.test.ts +43 -0
- package/templates/nova/tests/styles/tokens.test.ts +35 -0
- package/templates/nova/tests/support/abi-ctx.ts +136 -0
- package/templates/nova/tests/support/block-stories.tsx +13 -0
- package/templates/nova/tests/support/case.tsx +102 -0
- package/templates/nova/tests/support/contracts.ts +30 -0
- package/templates/nova/tests/support/foundation-pages.tsx +260 -0
- package/templates/nova/tests/support/ia-pages.tsx +154 -0
- package/templates/nova/tests/support/listing-demo.tsx +29 -0
- package/templates/nova/tests/support/presets.ts +14 -0
- package/templates/nova/tests/support/sections.ts +36 -0
- package/templates/nova/tests/support/story-content.ts +321 -0
- package/templates/nova/tests/support/story-helpers.tsx +37 -0
- package/templates/nova/tests/support/with-nova.tsx +26 -0
- package/templates/nova/tests/theme-config.test.ts +82 -0
- package/templates/nova/tests/theme-integrity.test.ts +315 -0
- package/templates/nova/theme.config.ts +134 -0
- package/templates/nova/theme.manifest.json +17495 -0
- package/templates/nova/tsconfig.json +19 -0
- package/templates/nova/vite.abi-ssr.config.ts +37 -0
- package/templates/nova/vite.abi.config.ts +26 -0
- package/templates/nova/vitest.config.ts +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tanqory
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
|
-
#
|
|
1
|
+
# create-tanqory-theme
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
```bash
|
|
4
|
+
npm create tanqory-theme@latest my-theme
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Creates a Tanqory storefront theme (Theme ABI v2) that builds and passes the platform's checks with nothing but
|
|
8
|
+
the public npm registry: no token, no private registry, no git clone. Everything the project needs ships inside
|
|
9
|
+
this package.
|
|
10
|
+
|
|
11
|
+
## Templates
|
|
12
|
+
|
|
13
|
+
| Template | What you get |
|
|
14
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
15
|
+
| `blank` (default) | Unstyled. Every storefront function wired through `@tanqory/theme-kit/headless` (variants and `?variant=`, cart drawer and cart page, checkout hand-off, sort / filter / pagination, predictive search, markets and languages, forms, consent, SEO and JSON-LD, th/en, live edit, the AI-compat profile) with minimal neutral CSS. Start here for a theme of your own design. |
|
|
16
|
+
| `nova` | A standalone fork of Nova V3, the Tanqory reference theme: sections, components, styles, starter content, contracts tooling and its test suite. Needs Node ≥ 22.6. |
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm create tanqory-theme@latest my-theme -- --template nova
|
|
20
|
+
pnpm create tanqory-theme my-theme --template blank --yes
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Options: `--template <blank|nova>`, `--yes` (defaults: `my-theme`, `blank`), `--no-install`,
|
|
24
|
+
`--package-manager <npm|pnpm|yarn|bun>` (default: the one running the command).
|
|
25
|
+
|
|
26
|
+
## What is in the project
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
my-theme/
|
|
30
|
+
├── AGENTS.md, CLAUDE.md the rules for coding agents (one text, two names)
|
|
31
|
+
├── .mcp.json Claude Code ─┐
|
|
32
|
+
├── .codex/config.toml Codex │ the Tanqory MCP server:
|
|
33
|
+
├── .vscode/mcp.json VS Code │ npx -y @tanqory/cli mcp
|
|
34
|
+
├── .gemini/settings.json Gemini CLI ─┘
|
|
35
|
+
├── .github/workflows/theme-check.yml build + test + check on every push and PR
|
|
36
|
+
├── tanqory.config.json the store and output the CLI uses
|
|
37
|
+
├── tests/ vitest
|
|
38
|
+
└── package.json dev · build · check · test · typecheck
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Script | Does |
|
|
42
|
+
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| `npm run build` | the theme → `dist/abi` (manifest, browser bundle, single-file server entry, defaults, locales) |
|
|
44
|
+
| `npm run check` | `theme-conformance run dist/abi --tier all`: security (the 9 ABI suites), storefront, budgets; reports in `reports/` |
|
|
45
|
+
| `npm test` / `npm run typecheck` | vitest / tsc |
|
|
46
|
+
| `npm run dev` | `tanqory theme dev`: localhost:9292 with real store data (after `npx tanqory login`), editor at `/__editor`; `-- --mock` offline |
|
|
47
|
+
|
|
48
|
+
## Maintainers
|
|
49
|
+
|
|
50
|
+
- `templates/blank` derives from the kit's Aurora example with its styling removed; `templates/common` is copied
|
|
51
|
+
into every project; `lib/agents.mjs` is the single source of `AGENTS.md` / `CLAUDE.md`.
|
|
52
|
+
- `templates/nova` is generated, never edited by hand:
|
|
53
|
+
`node scripts/sync-nova-template.mjs <nova-v3 source dir> <commit>` (see the script header for what it changes).
|
|
54
|
+
- Both templates pin the same exact `@tanqory/*` versions (`test/create.test.mjs`).
|
|
55
|
+
- The package is `"private": true` until the owner's licence decision: remove `private` to let the next
|
|
56
|
+
changesets release publish it to npmjs (its first publish needs npm 2FA, so the owner publishes it by hand).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* npm create tanqory-theme@latest my-theme
|
|
4
|
+
*
|
|
5
|
+
* Scaffolds a Tanqory storefront theme (Theme ABI v2) from a template that ships inside this package.
|
|
6
|
+
*/
|
|
7
|
+
import { main } from '../lib/create.mjs'
|
|
8
|
+
|
|
9
|
+
if (Number(process.versions.node.split('.')[0]) < 20) {
|
|
10
|
+
console.error(`\n create-tanqory-theme needs Node.js 20 or newer (this is ${process.version}).\n`)
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
process.exitCode = await main()
|
package/lib/agents.mjs
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent instructions every scaffolded theme ships:
|
|
3
|
+
* - AGENTS.md (Codex, Copilot, Gemini CLI, Cursor …) and CLAUDE.md (Claude Code), identical bytes;
|
|
4
|
+
* - .claude/skills/tanqory-theme/SKILL.md, the same workflow as a Claude Code project skill.
|
|
5
|
+
* One source, here, so they can never drift; `test/create.test.mjs` asserts it.
|
|
6
|
+
*
|
|
7
|
+
* The workflow block is first and short on purpose: coding agents skim long instructions, and Claude Code shows
|
|
8
|
+
* MCP tools as deferred (behind ToolSearch), so an agent that is not handed the exact tool names rarely loads them.
|
|
9
|
+
* The rules are the platform's acceptance bar, not style advice: each one is something `tanqory theme check`
|
|
10
|
+
* fails on.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** The Tanqory MCP tools the workflow names, as Claude Code exposes them (server `tanqory`). */
|
|
14
|
+
export const MCP_TOOLS = ['scaffold_section', 'screenshot', 'get_page', 'check_theme', 'dev_server_status', 'search_docs', 'get_kit_example']
|
|
15
|
+
export const claudeName = (tool) => `mcp__tanqory__${tool}`
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The workflow, imperative and numbered. Shared by AGENTS.md / CLAUDE.md and the skill.
|
|
19
|
+
* @param {{ id: string }} template
|
|
20
|
+
*/
|
|
21
|
+
export function workflow(template) {
|
|
22
|
+
const select = MCP_TOOLS.map(claudeName).join(',')
|
|
23
|
+
const scaffold =
|
|
24
|
+
template.id === 'blank'
|
|
25
|
+
? `**New section → \`scaffold_section\`** (\`${claudeName('scaffold_section')}\`). Call it with \`name\`, \`purpose\` and \`template: "index"\`; it returns a plan. Call it again with the same arguments plus \`confirm: true\` and the \`planDigest\`. It writes the section, its settings, en + th keys, CSS and a test, wired to the kit. Then restyle it. For any kit API use \`search_docs\` / \`get_kit_example\` instead of reading node_modules.`
|
|
26
|
+
: `**New section → copy the closest section in \`src/sections/\`** and keep its kit wiring (\`scaffold_section\` writes the Blank layout only). For any kit API use \`search_docs\` / \`get_kit_example\` (\`${claudeName('get_kit_example')}\`) instead of reading node_modules.`
|
|
27
|
+
return `## Workflow: do this for every change
|
|
28
|
+
|
|
29
|
+
The **Tanqory MCP server** (\`tanqory\`) is configured in this folder. Use its tools for the steps below; the shell commands are only the fallback. In Claude Code the tools are deferred: load them first with ToolSearch \`select:${select}\`. Other hosts list the same tool names under the \`tanqory\` server.
|
|
30
|
+
|
|
31
|
+
1. **Start the dev server in the background** and keep it running: \`npm run dev -- --mock\` (offline fixture store; plain \`npm run dev\` once \`npx tanqory login\` is done). It rebuilds on every save. \`dev_server_status\` says when it is up; if the server exits instead, read its output and start it again.
|
|
32
|
+
2. ${scaffold}
|
|
33
|
+
3. **Look at your work → \`screenshot\`** (\`${claudeName('screenshot')}\`) of the page you changed, \`viewport: "desktop"\` and \`"mobile"\`, \`locale: "th"\` and \`"en"\`; **\`get_page\`** (\`${claudeName('get_page')}\`) for the HTML and console errors. Fix what looks wrong and look again.
|
|
34
|
+
4. **Verify → \`check_theme\`** (\`${claudeName('check_theme')}\`), not \`npm run check\`: the same checks as \`tanqory theme check\`, returned as JSON failures with the check id, route, fix hint and file:line when known. Fix **every** failure, including ones you did not cause, and call it again until \`passed: true\`.
|
|
35
|
+
5. **Stop the dev server** with \`npm run dev -- --stop\` (it stops the pid in \`.tanqory/dev-server.json\`). Never \`pkill\`, \`killall\` or a pid found by name (\`pgrep\`, \`ps | grep\`): other servers on this machine are not yours.
|
|
36
|
+
6. Only then say done, and say what the screenshots showed.
|
|
37
|
+
`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {{ title: string, template: { id: string, title: string, summary: string, api: string,
|
|
42
|
+
* layout: Array<[string, string]>, docs: Array<[string, string]>, extraRules?: string[] },
|
|
43
|
+
* versions: Record<string, string>, generator: string }} input
|
|
44
|
+
*/
|
|
45
|
+
export function agentInstructions({ title, template, versions, generator }) {
|
|
46
|
+
const pins = Object.entries(versions)
|
|
47
|
+
.map(([name, v]) => `\`${name}@${v}\``)
|
|
48
|
+
.join(', ')
|
|
49
|
+
const rows = (pairs) => pairs.map(([a, b]) => `| \`${a}\` | ${b} |`).join('\n')
|
|
50
|
+
const extra = (template.extraRules ?? []).map((r, i) => `${9 + i}. ${r}`).join('\n')
|
|
51
|
+
|
|
52
|
+
return `<!-- Generated by ${generator} (template: ${template.id}) for ${pins}. AGENTS.md and CLAUDE.md are the same file. -->
|
|
53
|
+
# ${title}: instructions for coding agents
|
|
54
|
+
|
|
55
|
+
This is a **Tanqory storefront theme** (Theme ABI v2), started from the **${template.title}** template. The theme owns its markup and CSS; **every storefront function comes from the kit** (\`${template.api}\`).
|
|
56
|
+
|
|
57
|
+
${workflow(template)}
|
|
58
|
+
## Commands (shell fallback)
|
|
59
|
+
|
|
60
|
+
| Command | What it does |
|
|
61
|
+
|---|---|
|
|
62
|
+
| \`npm run dev\` | \`tanqory theme dev\`: the theme on http://localhost:9292 (workerd, the platform's production shim, the signed-in store's real data, cart and checkout), rebuilt on every change. \`-- --mock\`: offline fixture store. \`-- --stop\`: stop the running one |
|
|
63
|
+
| \`http://localhost:9292/__editor\` | the Tanqory Editor on your local theme while the dev server runs; edits are saved to \`.tanqory/dev/content.json\` |
|
|
64
|
+
| \`npm run build\` | builds \`dist/abi\`; fails on any contract problem or hard size limit |
|
|
65
|
+
| \`npm test\` / \`npm run typecheck\` | vitest / \`tsc --noEmit\` (after a build) |
|
|
66
|
+
| \`npm run check\` | \`tanqory theme check\` on \`dist/abi\`: **security** (9 ABI suites), **storefront**, **budgets**. Reports in \`reports/\`. \`-- --tier <name>\` for one tier |
|
|
67
|
+
| \`npx tanqory login\` | sign in once (browser, OAuth); the grant is for one store |
|
|
68
|
+
|
|
69
|
+
## Rules
|
|
70
|
+
|
|
71
|
+
${template.summary}
|
|
72
|
+
|
|
73
|
+
1. **Function from the kit, never re-implemented.** Cart, variant selection and \`?variant=\`, search, collection sort/filter/pagination, markets and languages, forms, consent, SEO and JSON-LD, money, i18n and live edit all come from the kit. Style them; do not rewrite them. If the kit lacks something, say so instead of building a parallel version.
|
|
74
|
+
2. **Never fetch raw APIs.** No \`fetch\`, \`XMLHttpRequest\`, \`WebSocket\`, \`EventSource\` or \`sendBeacon\`, and no third-party script or font origin. Data reaches the theme only through the kit (server: \`ctx.data\`; browser: \`/_tq/data\` and \`/_tq/actions\`, called by the kit).
|
|
75
|
+
3. **\`data-tq-node\` on every section.** \`defineSection\` adds it; never remove it, never render a section outside the kit's section tree, keep it on any wrapper you add.
|
|
76
|
+
4. **i18n every visible string.** No hard-coded text in components: add the key to \`locales/en.json\` **and** \`locales/th.json\` and render it with \`t()\` / \`useTranslate()\`. Text the merchant edits belongs in section settings.
|
|
77
|
+
5. **Accessibility.** Semantic HTML (one \`h1\` per page, landmarks, lists), a label for every control, \`alt\` on informative images, contrast 4.5:1, a visible \`:focus-visible\` outline, every link and button at least **44 × 44 px**, cart and menu reachable by keyboard. Never use \`text-transform\` (use \`font-variant-caps\`).
|
|
78
|
+
6. **Deterministic, self-contained render.** No \`Date.now()\`, \`new Date()\`, \`Math.random()\` or timers while rendering; no Node built-ins; no browser globals at module scope or during the server render.
|
|
79
|
+
7. **Settings and content are validated.** Every setting has a default; \`templates/\`, \`regions/\` and \`config/settings.json\` use only declared section types and setting keys. Keep the kit's \`data:shop\` capability.
|
|
80
|
+
8. **Do not edit generated output**: \`dist/\`, \`reports/\`, \`src/generated/\`, \`lib/abi/generated/\`.
|
|
81
|
+
${extra ? `${extra}\n` : ''}
|
|
82
|
+
## Before you say done
|
|
83
|
+
|
|
84
|
+
\`check_theme\` (or, without the MCP server, \`npm run build && npm run typecheck && npm test && npm run check\`, i.e. \`tanqory theme check\`) is **green on every tier**, and you have looked at the result with \`screenshot\`. A theme that builds but fails a tier is not done.
|
|
85
|
+
|
|
86
|
+
## Layout
|
|
87
|
+
|
|
88
|
+
| Path | What it is |
|
|
89
|
+
|---|---|
|
|
90
|
+
${rows(template.layout)}
|
|
91
|
+
|
|
92
|
+
## Reference (installed, matches your versions)
|
|
93
|
+
|
|
94
|
+
| File | What |
|
|
95
|
+
|---|---|
|
|
96
|
+
${rows(template.docs)}
|
|
97
|
+
|
|
98
|
+
All Tanqory MCP tools: \`search_docs\`, \`get_doc\`, \`get_schema\`, \`list_kit_components\`, \`get_kit_example\`, \`scaffold_section\`, \`validate_manifest\`, \`check_theme\`, \`run_storefront_checks\`, \`dev_server_status\`, \`get_page\`, \`screenshot\`, \`list_dev_stores\`, \`get_store_data_summary\`. The server (\`npx -y @tanqory/cli mcp\`) is pre-configured for Claude Code (\`.mcp.json\`), Codex (\`.codex/config.toml\`), VS Code (\`.vscode/mcp.json\`) and Gemini CLI (\`.gemini/settings.json\`). It never publishes anything.
|
|
99
|
+
`
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The Claude Code project skill (`.claude/skills/tanqory-theme/SKILL.md`): Claude Code lists project skills to the
|
|
104
|
+
* model by name + description, so theme work pulls the workflow in even when CLAUDE.md was skimmed.
|
|
105
|
+
* @param {{ title: string, template: { id: string }, generator: string }} input
|
|
106
|
+
*/
|
|
107
|
+
export function skillFile({ title, template, generator }) {
|
|
108
|
+
return `---
|
|
109
|
+
name: tanqory-theme
|
|
110
|
+
description: Use for ANY change to this Tanqory storefront theme (${title}) - new or changed sections, styles, locales, templates, or making \`tanqory theme check\` green. Gives the required workflow with the Tanqory MCP tools (scaffold_section, screenshot, get_page, check_theme) and how to stop the dev server safely.
|
|
111
|
+
---
|
|
112
|
+
<!-- Generated by ${generator} (template: ${template.id}). Same workflow as AGENTS.md / CLAUDE.md. -->
|
|
113
|
+
# Tanqory theme workflow
|
|
114
|
+
|
|
115
|
+
${workflow(template)}
|
|
116
|
+
The rules (kit for every storefront function, no raw fetch, \`data-tq-node\`, en + th for every string, 44 px targets) are in \`CLAUDE.md\`.
|
|
117
|
+
`
|
|
118
|
+
}
|
package/lib/create.mjs
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* create-tanqory-theme: copy a starter theme, name it, install it.
|
|
3
|
+
*
|
|
4
|
+
* Everything the project needs ships inside this package (templates/), so creating a theme needs the npm
|
|
5
|
+
* registry and nothing else: no git clone, no GitHub, no token.
|
|
6
|
+
*/
|
|
7
|
+
import { spawnSync } from 'node:child_process'
|
|
8
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
9
|
+
import { cp, mkdir, readFile, readdir, rename, stat, writeFile } from 'node:fs/promises'
|
|
10
|
+
import { basename, dirname, join, relative, resolve } from 'node:path'
|
|
11
|
+
import { fileURLToPath } from 'node:url'
|
|
12
|
+
import { createInterface } from 'node:readline/promises'
|
|
13
|
+
import { agentInstructions, skillFile } from './agents.mjs'
|
|
14
|
+
|
|
15
|
+
export const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
16
|
+
export const TEMPLATES_DIR = join(ROOT, 'templates')
|
|
17
|
+
export const TEMPLATE_IDS = ['blank', 'nova']
|
|
18
|
+
const SELF = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'))
|
|
19
|
+
|
|
20
|
+
/** npm's own package-name rule (validate-npm-package-name, new packages): lowercase, URL-safe, ≤ 214. */
|
|
21
|
+
const NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/
|
|
22
|
+
const PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun']
|
|
23
|
+
/** Files whose bytes are copied untouched (no placeholder substitution). */
|
|
24
|
+
const BINARY = /\.(png|jpe?g|gif|webp|avif|ico|woff2?|ttf|otf|wav|mp3|mp4|webm|wasm|gz|tgz)$/i
|
|
25
|
+
|
|
26
|
+
export class CreateError extends Error {}
|
|
27
|
+
|
|
28
|
+
export function usage() {
|
|
29
|
+
return `
|
|
30
|
+
npm create tanqory-theme@latest [directory] [-- options]
|
|
31
|
+
|
|
32
|
+
Creates a Tanqory storefront theme (Theme ABI v2) ready for Claude Code, Codex and other coding agents.
|
|
33
|
+
|
|
34
|
+
Templates
|
|
35
|
+
blank Unstyled. Every storefront function wired through @tanqory/theme-kit/headless,
|
|
36
|
+
minimal neutral CSS. Start here for a theme of your own design.
|
|
37
|
+
nova A standalone fork of Nova, the Tanqory reference theme, with its full build
|
|
38
|
+
tooling, tests and contracts.
|
|
39
|
+
|
|
40
|
+
Options
|
|
41
|
+
--template, -t <blank|nova> skip the template question
|
|
42
|
+
--yes, -y accept the defaults (directory my-theme, template blank)
|
|
43
|
+
--no-install do not install dependencies
|
|
44
|
+
--package-manager <npm|pnpm|yarn|bun>
|
|
45
|
+
install with this one (default: the one running this command)
|
|
46
|
+
--help, -h
|
|
47
|
+
|
|
48
|
+
Examples
|
|
49
|
+
npm create tanqory-theme@latest my-theme
|
|
50
|
+
npm create tanqory-theme@latest my-theme -- --template nova
|
|
51
|
+
pnpm create tanqory-theme my-theme --template blank --yes
|
|
52
|
+
`
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** @returns {{ dir?: string, template?: string, yes: boolean, install: boolean, pm?: string, help: boolean }} */
|
|
56
|
+
export function parseArgs(argv) {
|
|
57
|
+
const out = { yes: false, install: true, help: false }
|
|
58
|
+
for (let i = 0; i < argv.length; i++) {
|
|
59
|
+
const a = argv[i]
|
|
60
|
+
const value = () => {
|
|
61
|
+
const v = a.includes('=') ? a.slice(a.indexOf('=') + 1) : argv[++i]
|
|
62
|
+
if (!v || v.startsWith('-')) throw new CreateError(`${a.split('=')[0]} needs a value`)
|
|
63
|
+
return v
|
|
64
|
+
}
|
|
65
|
+
if (a === '--help' || a === '-h') out.help = true
|
|
66
|
+
else if (a === '--yes' || a === '-y') out.yes = true
|
|
67
|
+
else if (a === '--no-install') out.install = false
|
|
68
|
+
else if (a === '--template' || a === '-t' || a.startsWith('--template=')) out.template = value()
|
|
69
|
+
else if (a === '--package-manager' || a.startsWith('--package-manager=')) out.pm = value()
|
|
70
|
+
else if (a.startsWith('-')) throw new CreateError(`unknown option ${a} (see --help)`)
|
|
71
|
+
else if (out.dir === undefined) out.dir = a
|
|
72
|
+
else throw new CreateError(`unexpected argument ${a}: give one directory`)
|
|
73
|
+
}
|
|
74
|
+
if (out.template !== undefined && !TEMPLATE_IDS.includes(out.template))
|
|
75
|
+
throw new CreateError(`--template must be one of ${TEMPLATE_IDS.join(', ')} (got "${out.template}")`)
|
|
76
|
+
if (out.pm !== undefined && !PACKAGE_MANAGERS.includes(out.pm))
|
|
77
|
+
throw new CreateError(`--package-manager must be one of ${PACKAGE_MANAGERS.join(', ')} (got "${out.pm}")`)
|
|
78
|
+
return out
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The package manager that is running `create` (npm/pnpm/yarn/bun set npm_config_user_agent). */
|
|
82
|
+
export function detectPackageManager(userAgent = process.env.npm_config_user_agent ?? '') {
|
|
83
|
+
const name = userAgent.split('/')[0]
|
|
84
|
+
return PACKAGE_MANAGERS.includes(name) ? name : 'npm'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function titleCase(name) {
|
|
88
|
+
return basename(name)
|
|
89
|
+
.split(/[-_.\s]+/)
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
92
|
+
.join(' ')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function validatePackageName(name) {
|
|
96
|
+
if (!name) return 'the directory name is empty'
|
|
97
|
+
if (name.length > 214) return 'it is longer than 214 characters'
|
|
98
|
+
if (!NAME.test(name)) return 'npm package names use lowercase letters, digits, "-", "." and "_" (e.g. my-theme)'
|
|
99
|
+
if (/^[._]/.test(name)) return 'it must not start with "." or "_"'
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function readTemplate(id) {
|
|
104
|
+
const dir = join(TEMPLATES_DIR, id)
|
|
105
|
+
const meta = JSON.parse(readFileSync(join(dir, 'template.json'), 'utf8'))
|
|
106
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'))
|
|
107
|
+
const versions = Object.fromEntries(
|
|
108
|
+
Object.entries({ ...pkg.dependencies, ...pkg.devDependencies }).filter(([n]) => n.startsWith('@tanqory/')).sort(),
|
|
109
|
+
)
|
|
110
|
+
return { dir, meta, versions }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function ask({ dir, template }) {
|
|
114
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout })
|
|
115
|
+
try {
|
|
116
|
+
if (dir === undefined) dir = (await rl.question(' Project directory (my-theme): ')).trim() || 'my-theme'
|
|
117
|
+
if (template === undefined) {
|
|
118
|
+
process.stdout.write(`
|
|
119
|
+
Which template?
|
|
120
|
+
1) Blank unstyled, every storefront function wired through the kit
|
|
121
|
+
2) Nova a standalone fork of the Nova reference theme
|
|
122
|
+
`)
|
|
123
|
+
for (;;) {
|
|
124
|
+
const a = (await rl.question(' Template (1): ')).trim().toLowerCase() || '1'
|
|
125
|
+
if (a === '1' || a === 'blank') { template = 'blank'; break }
|
|
126
|
+
if (a === '2' || a === 'nova') { template = 'nova'; break }
|
|
127
|
+
process.stdout.write(' Type 1 or 2.\n')
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} finally {
|
|
131
|
+
rl.close()
|
|
132
|
+
}
|
|
133
|
+
return { dir, template }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function substitute(dir, replacements) {
|
|
137
|
+
for (const entry of await readdir(dir)) {
|
|
138
|
+
const path = join(dir, entry)
|
|
139
|
+
if ((await stat(path)).isDirectory()) {
|
|
140
|
+
await substitute(path, replacements)
|
|
141
|
+
continue
|
|
142
|
+
}
|
|
143
|
+
if (BINARY.test(entry)) continue
|
|
144
|
+
const text = await readFile(path, 'utf8')
|
|
145
|
+
let next = text
|
|
146
|
+
for (const [token, value] of Object.entries(replacements)) next = next.split(token).join(value)
|
|
147
|
+
if (next !== text) await writeFile(path, next)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** npm drops `.gitignore` from a published tarball, so templates ship it as `_gitignore`. */
|
|
152
|
+
async function restoreDotfiles(dir) {
|
|
153
|
+
for (const entry of await readdir(dir)) {
|
|
154
|
+
const path = join(dir, entry)
|
|
155
|
+
if ((await stat(path)).isDirectory()) {
|
|
156
|
+
if (entry !== 'node_modules') await restoreDotfiles(path)
|
|
157
|
+
} else if (entry === '_gitignore') await rename(path, join(dir, '.gitignore'))
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Write the project. Pure file work (no prompt, no install), so tests drive it directly.
|
|
163
|
+
* @returns {Promise<{ target: string, name: string, template: string }>}
|
|
164
|
+
*/
|
|
165
|
+
export async function scaffold({ dir, template, cwd = process.cwd() }) {
|
|
166
|
+
const target = resolve(cwd, dir)
|
|
167
|
+
const name = basename(target)
|
|
168
|
+
const problem = validatePackageName(name)
|
|
169
|
+
if (problem) throw new CreateError(`"${name}" cannot be the theme's package name: ${problem}.`)
|
|
170
|
+
if (existsSync(target) && readdirSync(target).length > 0)
|
|
171
|
+
throw new CreateError(`${relative(cwd, target) || '.'}/ already exists and is not empty. Choose another directory.`)
|
|
172
|
+
|
|
173
|
+
const { dir: from, meta, versions } = readTemplate(template)
|
|
174
|
+
const title = titleCase(name)
|
|
175
|
+
await mkdir(target, { recursive: true })
|
|
176
|
+
await cp(join(TEMPLATES_DIR, 'common'), target, { recursive: true })
|
|
177
|
+
await cp(from, target, { recursive: true, filter: (src) => src !== join(from, 'template.json') })
|
|
178
|
+
await restoreDotfiles(target)
|
|
179
|
+
await substitute(target, { __PACKAGE_NAME__: name, __THEME_TITLE__: title })
|
|
180
|
+
|
|
181
|
+
const instructions = agentInstructions({ title, template: meta, versions, generator: `${SELF.name}@${SELF.version}` })
|
|
182
|
+
await writeFile(join(target, 'AGENTS.md'), instructions)
|
|
183
|
+
await writeFile(join(target, 'CLAUDE.md'), instructions)
|
|
184
|
+
await mkdir(join(target, '.claude', 'skills', 'tanqory-theme'), { recursive: true })
|
|
185
|
+
await writeFile(join(target, '.claude', 'skills', 'tanqory-theme', 'SKILL.md'), skillFile({ title, template: meta, generator: `${SELF.name}@${SELF.version}` }))
|
|
186
|
+
return { target, name, template }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function install(target, pm) {
|
|
190
|
+
const r = spawnSync(pm, ['install'], { cwd: target, stdio: 'inherit', shell: process.platform === 'win32' })
|
|
191
|
+
return r.status === 0
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export async function main(argv = process.argv.slice(2), { interactive = process.stdin.isTTY && process.stdout.isTTY } = {}) {
|
|
195
|
+
let opts
|
|
196
|
+
try {
|
|
197
|
+
opts = parseArgs(argv)
|
|
198
|
+
} catch (e) {
|
|
199
|
+
if (e instanceof CreateError) {
|
|
200
|
+
console.error(`\n ${e.message}\n`)
|
|
201
|
+
return 1
|
|
202
|
+
}
|
|
203
|
+
throw e
|
|
204
|
+
}
|
|
205
|
+
if (opts.help) {
|
|
206
|
+
console.log(usage())
|
|
207
|
+
return 0
|
|
208
|
+
}
|
|
209
|
+
let { dir, template } = opts
|
|
210
|
+
if ((dir === undefined || template === undefined) && interactive && !opts.yes) ({ dir, template } = await ask({ dir, template }))
|
|
211
|
+
dir ??= 'my-theme'
|
|
212
|
+
template ??= 'blank'
|
|
213
|
+
|
|
214
|
+
let result
|
|
215
|
+
try {
|
|
216
|
+
result = await scaffold({ dir, template })
|
|
217
|
+
} catch (e) {
|
|
218
|
+
if (e instanceof CreateError) {
|
|
219
|
+
console.error(`\n ${e.message}\n`)
|
|
220
|
+
return 1
|
|
221
|
+
}
|
|
222
|
+
throw e
|
|
223
|
+
}
|
|
224
|
+
const pm = opts.pm ?? detectPackageManager()
|
|
225
|
+
const rel = relative(process.cwd(), result.target) || '.'
|
|
226
|
+
console.log(`\n Created ${rel}/ from the ${template === 'nova' ? 'Nova fork' : 'Blank'} template.\n`)
|
|
227
|
+
|
|
228
|
+
let installed = false
|
|
229
|
+
if (opts.install) {
|
|
230
|
+
console.log(` Installing dependencies with ${pm} …\n`)
|
|
231
|
+
installed = install(result.target, pm)
|
|
232
|
+
if (!installed) console.error(`\n ${pm} install failed (see above). Run it again inside ${rel}/.\n`)
|
|
233
|
+
}
|
|
234
|
+
const runCmd = pm === 'npm' ? 'npm run' : pm
|
|
235
|
+
console.log(` Next:
|
|
236
|
+
|
|
237
|
+
cd ${rel}${installed ? '' : `\n ${pm} install`}
|
|
238
|
+
${runCmd} build build the theme into dist/abi
|
|
239
|
+
${runCmd} check the platform's checks: security, storefront, budgets
|
|
240
|
+
|
|
241
|
+
Open the folder in VS Code with Claude Code or Codex: AGENTS.md / CLAUDE.md tell the agent the rules,
|
|
242
|
+
and the Tanqory MCP server is pre-configured (.mcp.json, .codex/config.toml, .vscode/mcp.json).
|
|
243
|
+
`)
|
|
244
|
+
return opts.install && !installed ? 1 : 0
|
|
245
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-tanqory-theme",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "Create a Tanqory storefront theme (Theme ABI v2): Blank or a Nova fork, ready for Claude Code, Codex and other coding agents.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"tanqory",
|
|
7
|
+
"theme",
|
|
8
|
+
"storefront",
|
|
9
|
+
"ecommerce",
|
|
10
|
+
"scaffold",
|
|
11
|
+
"create"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Tanqory",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/tanqory/tanqory-platform-packages.git",
|
|
18
|
+
"directory": "packages/tools/create-tanqory-theme"
|
|
19
|
+
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"bin": {
|
|
22
|
+
"create-tanqory-theme": "./bin/create-tanqory-theme.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"bin",
|
|
26
|
+
"lib",
|
|
27
|
+
"templates",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public",
|
|
36
|
+
"registry": "https://registry.npmjs.org"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "node --test test/*.test.mjs"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# __THEME_TITLE__
|
|
2
|
+
|
|
3
|
+
A Tanqory storefront theme (Theme ABI v2) on `@tanqory/theme-kit/headless`, started from the **Blank** template:
|
|
4
|
+
every storefront function is wired, the markup is minimal and the CSS is neutral. Make it yours.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install
|
|
8
|
+
npm run build # dist/abi: manifest, browser bundle, single-file server entry, defaults, locales
|
|
9
|
+
npm test # vitest
|
|
10
|
+
npm run check # the platform's checks: security, storefront, budgets (reports/)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Node ≥ 20. Coding agents: read `AGENTS.md` (the same text as `CLAUDE.md`).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"theme.nav.main": "Main menu",
|
|
3
|
+
"theme.footer.menu": "More",
|
|
4
|
+
"theme.footer.rights": "© {name}. All rights reserved.",
|
|
5
|
+
"theme.price.from": "From {price}",
|
|
6
|
+
"theme.shelf.viewAll": "View all",
|
|
7
|
+
"theme.shelf.empty": "No products in this collection yet.",
|
|
8
|
+
"theme.product.missing": "This product is not available.",
|
|
9
|
+
"theme.collection.kicker": "Collection",
|
|
10
|
+
"theme.collection.none": "This collection is empty for now.",
|
|
11
|
+
"theme.cart.continue": "Continue shopping",
|
|
12
|
+
"theme.cart.view": "View cart",
|
|
13
|
+
"theme.cart.taxes": "Taxes and shipping are calculated at checkout.",
|
|
14
|
+
"theme.drawer.qty": "Qty {count}",
|
|
15
|
+
"theme.journal.read": "Read more",
|
|
16
|
+
"theme.journal.back": "Back to {blog}",
|
|
17
|
+
"theme.journal.by": "By {author}",
|
|
18
|
+
"theme.notFound.title": "Page not found",
|
|
19
|
+
"theme.notFound.body": "The link may be old, or the page has moved.",
|
|
20
|
+
"theme.notFound.home": "Back to the home page",
|
|
21
|
+
"seo.homeDescription": "{name}: shop online."
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"theme.nav.main": "เมนูหลัก",
|
|
3
|
+
"theme.footer.menu": "เพิ่มเติม",
|
|
4
|
+
"theme.footer.rights": "© {name} สงวนลิขสิทธิ์",
|
|
5
|
+
"theme.price.from": "เริ่มต้น {price}",
|
|
6
|
+
"theme.shelf.viewAll": "ดูทั้งหมด",
|
|
7
|
+
"theme.shelf.empty": "ยังไม่มีสินค้าในคอลเลกชันนี้",
|
|
8
|
+
"theme.product.missing": "สินค้านี้ไม่มีจำหน่าย",
|
|
9
|
+
"theme.collection.kicker": "คอลเลกชัน",
|
|
10
|
+
"theme.collection.none": "คอลเลกชันนี้ยังไม่มีสินค้า",
|
|
11
|
+
"theme.cart.continue": "เลือกซื้อสินค้าต่อ",
|
|
12
|
+
"theme.cart.view": "ดูตะกร้า",
|
|
13
|
+
"theme.cart.taxes": "ภาษีและค่าจัดส่งคำนวณตอนชำระเงิน",
|
|
14
|
+
"theme.drawer.qty": "จำนวน {count}",
|
|
15
|
+
"theme.journal.read": "อ่านต่อ",
|
|
16
|
+
"theme.journal.back": "กลับไปที่ {blog}",
|
|
17
|
+
"theme.journal.by": "โดย {author}",
|
|
18
|
+
"theme.notFound.title": "ไม่พบหน้าที่คุณกำลังหา",
|
|
19
|
+
"theme.notFound.body": "ลิงก์อาจเก่าแล้ว หรือหน้านี้ถูกย้ายไป",
|
|
20
|
+
"theme.notFound.home": "กลับหน้าแรก",
|
|
21
|
+
"seo.homeDescription": "{name}: ช้อปออนไลน์"
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PACKAGE_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "A Tanqory storefront theme (Theme ABI v2) on @tanqory/theme-kit.",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.0.0"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "node scripts/dev.mjs",
|
|
12
|
+
"build": "node scripts/build.mjs",
|
|
13
|
+
"check": "node scripts/check.mjs",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"typecheck": "tsc --noEmit"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@tanqory/theme-kit": "2.0.0-alpha.3",
|
|
19
|
+
"react": "18.3.1",
|
|
20
|
+
"react-dom": "18.3.1"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@tanqory/cli": "2.0.0-alpha.3",
|
|
24
|
+
"@tanqory/theme-abi": "2.0.0-alpha.14",
|
|
25
|
+
"@tanqory/theme-conformance": "0.1.0-alpha.15",
|
|
26
|
+
"@types/node": "^22.10.0",
|
|
27
|
+
"@types/react": "^18.3.12",
|
|
28
|
+
"@types/react-dom": "^18.3.1",
|
|
29
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
30
|
+
"typescript": "~5.9.3",
|
|
31
|
+
"vite": "^5.4.10",
|
|
32
|
+
"vitest": "^3.2.4"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contentVersion": 1,
|
|
3
|
+
"region": "footer",
|
|
4
|
+
"sections": [
|
|
5
|
+
{
|
|
6
|
+
"id": "footer",
|
|
7
|
+
"type": "footer",
|
|
8
|
+
"blocks": [
|
|
9
|
+
{
|
|
10
|
+
"id": "footer-brand",
|
|
11
|
+
"type": "footer-brand",
|
|
12
|
+
"settings": {
|
|
13
|
+
"tagline": "Made in small batches."
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "footer-menu",
|
|
18
|
+
"type": "footer-menu",
|
|
19
|
+
"settings": {
|
|
20
|
+
"heading": "Explore",
|
|
21
|
+
"menu": "main-menu"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "footer-menu-2",
|
|
26
|
+
"type": "footer-menu",
|
|
27
|
+
"settings": {
|
|
28
|
+
"heading": "Help",
|
|
29
|
+
"menu": "footer"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|