create-tanqory-theme 0.0.0-stage → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (879) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -2
  3. package/bin/create-tanqory-theme.mjs +13 -0
  4. package/lib/agents.mjs +118 -0
  5. package/lib/create.mjs +245 -0
  6. package/package.json +39 -4
  7. package/templates/blank/README.md +13 -0
  8. package/templates/blank/config/settings.json +3 -0
  9. package/templates/blank/locales/en.json +22 -0
  10. package/templates/blank/locales/th.json +22 -0
  11. package/templates/blank/package.json +34 -0
  12. package/templates/blank/regions/footer.json +35 -0
  13. package/templates/blank/regions/header.json +13 -0
  14. package/templates/blank/scripts/build.mjs +193 -0
  15. package/templates/blank/scripts/probe.ts +4 -0
  16. package/templates/blank/src/bundle.ts +15 -0
  17. package/templates/blank/src/components/parts.tsx +32 -0
  18. package/templates/blank/src/entry.client.tsx +6 -0
  19. package/templates/blank/src/entry.server.tsx +13 -0
  20. package/templates/blank/src/sections/chrome.tsx +132 -0
  21. package/templates/blank/src/sections/commerce.tsx +242 -0
  22. package/templates/blank/src/sections/content.tsx +111 -0
  23. package/templates/blank/src/sections/editorial.tsx +107 -0
  24. package/templates/blank/src/settings.ts +15 -0
  25. package/templates/blank/src/styles/theme.css +195 -0
  26. package/templates/blank/src/templates.ts +14 -0
  27. package/templates/blank/src/theme.tsx +76 -0
  28. package/templates/blank/template.json +24 -0
  29. package/templates/blank/templates/404.json +14 -0
  30. package/templates/blank/templates/account.json +14 -0
  31. package/templates/blank/templates/article.json +14 -0
  32. package/templates/blank/templates/blog.json +14 -0
  33. package/templates/blank/templates/cart.json +14 -0
  34. package/templates/blank/templates/collection.json +14 -0
  35. package/templates/blank/templates/index.json +36 -0
  36. package/templates/blank/templates/page.contact.json +18 -0
  37. package/templates/blank/templates/page.json +14 -0
  38. package/templates/blank/templates/product.json +18 -0
  39. package/templates/blank/templates/search.json +14 -0
  40. package/templates/blank/tests/theme.test.ts +49 -0
  41. package/templates/blank/tsconfig.json +17 -0
  42. package/templates/blank/vite.client.config.ts +17 -0
  43. package/templates/blank/vite.probe.config.ts +16 -0
  44. package/templates/blank/vite.server.config.ts +32 -0
  45. package/templates/blank/vitest.config.ts +9 -0
  46. package/templates/common/.claude/settings.json +8 -0
  47. package/templates/common/.codex/config.toml +4 -0
  48. package/templates/common/.gemini/settings.json +12 -0
  49. package/templates/common/.github/workflows/theme-check.yml +44 -0
  50. package/templates/common/.mcp.json +12 -0
  51. package/templates/common/.vscode/mcp.json +9 -0
  52. package/templates/common/_gitignore +9 -0
  53. package/templates/common/scripts/check.mjs +44 -0
  54. package/templates/common/scripts/dev.mjs +30 -0
  55. package/templates/common/tanqory.config.json +6 -0
  56. package/templates/nova/.gitattributes +3 -0
  57. package/templates/nova/.tanqory/contracts/LOCK.json +66 -0
  58. package/templates/nova/.tanqory/contracts/nova-01.json +1092 -0
  59. package/templates/nova/.tanqory/contracts/nova-12A.json +2674 -0
  60. package/templates/nova/.tanqory/contracts/nova-12B.json +2285 -0
  61. package/templates/nova/.tanqory/contracts/nova-12C.json +2848 -0
  62. package/templates/nova/.tanqory/contracts/nova-12D.json +3039 -0
  63. package/templates/nova/.tanqory/contracts/nova-12E.json +1473 -0
  64. package/templates/nova/.tanqory/contracts/nova-12F.json +1670 -0
  65. package/templates/nova/.tanqory/contracts/nova-12G.json +1661 -0
  66. package/templates/nova/.tanqory/contracts/nova-13.json +301 -0
  67. package/templates/nova/.tanqory/contracts/nova-14.json +172 -0
  68. package/templates/nova/.tanqory/legacy-settings.json +1121 -0
  69. package/templates/nova/README.md +150 -0
  70. package/templates/nova/_gitignore +28 -0
  71. package/templates/nova/assets/ai-tokens.css +6 -0
  72. package/templates/nova/assets/starter/starter-art-1200x800-0b773ac4.svg +1 -0
  73. package/templates/nova/assets/starter/starter-art-1200x900-59600290.svg +1 -0
  74. package/templates/nova/assets/starter/starter-art-1200x900-c549d496.svg +1 -0
  75. package/templates/nova/assets/starter/starter-art-1600x900-8f979fcb.svg +1 -0
  76. package/templates/nova/assets/starter/starter-art-2100x900-cbb71bfd.svg +1 -0
  77. package/templates/nova/config/legacy-settings.json +438 -0
  78. package/templates/nova/config/promotion-popup.schema.ts +29 -0
  79. package/templates/nova/config/settings.json +23 -0
  80. package/templates/nova/config/settings.schema.ts +231 -0
  81. package/templates/nova/entry.abi.tsx +27 -0
  82. package/templates/nova/groups/footer.json +39 -0
  83. package/templates/nova/groups/header.json +11 -0
  84. package/templates/nova/lib/abi/abi.css +41 -0
  85. package/templates/nova/lib/bundle-core.ts +35 -0
  86. package/templates/nova/lib/bundle.client.ts +15 -0
  87. package/templates/nova/lib/bundle.ts +15 -0
  88. package/templates/nova/lib/legacy-settings.ts +104 -0
  89. package/templates/nova/locales/ar.json +590 -0
  90. package/templates/nova/locales/en.json +590 -0
  91. package/templates/nova/locales/th.json +590 -0
  92. package/templates/nova/main.abi.tsx +12 -0
  93. package/templates/nova/package.json +44 -0
  94. package/templates/nova/scripts/abi/build.mjs +145 -0
  95. package/templates/nova/scripts/abi/check-content.mjs +99 -0
  96. package/templates/nova/scripts/abi/jcs.mjs +27 -0
  97. package/templates/nova/scripts/abi/local-host.mjs +294 -0
  98. package/templates/nova/scripts/abi/manifest.mjs +392 -0
  99. package/templates/nova/scripts/abi/starter-assets.mjs +32 -0
  100. package/templates/nova/scripts/compiler/checks/check-a11y.mjs +88 -0
  101. package/templates/nova/scripts/compiler/checks/check-layout-sanity.mjs +169 -0
  102. package/templates/nova/scripts/compiler/checks/check-page-headings.mjs +67 -0
  103. package/templates/nova/scripts/compiler/checks/check-product-jsonld.mjs +80 -0
  104. package/templates/nova/scripts/compiler/checks/theme-spec/check.mjs +88 -0
  105. package/templates/nova/scripts/compiler/contracts/extract.mjs +188 -0
  106. package/templates/nova/scripts/compiler/contracts/index.ts +125 -0
  107. package/templates/nova/scripts/compiler/contracts/validate.ts +347 -0
  108. package/templates/nova/scripts/compiler/manifest/gen-manifest.mjs +156 -0
  109. package/templates/nova/scripts/compiler/manifest/manifest-entry.ts +386 -0
  110. package/templates/nova/scripts/compiler/manifest/manifest-sections.ts +247 -0
  111. package/templates/nova/scripts/compiler/migrate/migrate-content.mjs +171 -0
  112. package/templates/nova/scripts/compiler/migrate/migrate-groups.mjs +159 -0
  113. package/templates/nova/scripts/parity/case-shim.ts +14 -0
  114. package/templates/nova/scripts/parity/emit.ts +206 -0
  115. package/templates/nova/scripts/parity/index.html +12 -0
  116. package/templates/nova/scripts/parity/main.tsx +23 -0
  117. package/templates/nova/scripts/parity/pages.tsx +123 -0
  118. package/templates/nova/scripts/parity/vite.config.ts +29 -0
  119. package/templates/nova/src/components/base/Accordion.css +20 -0
  120. package/templates/nova/src/components/base/Accordion.tsx +50 -0
  121. package/templates/nova/src/components/base/Badge.css +17 -0
  122. package/templates/nova/src/components/base/Badge.tsx +26 -0
  123. package/templates/nova/src/components/base/Button.css +73 -0
  124. package/templates/nova/src/components/base/Button.tsx +64 -0
  125. package/templates/nova/src/components/base/Checkbox.tsx +18 -0
  126. package/templates/nova/src/components/base/Chip.css +20 -0
  127. package/templates/nova/src/components/base/Chip.tsx +33 -0
  128. package/templates/nova/src/components/base/Divider.css +6 -0
  129. package/templates/nova/src/components/base/Divider.tsx +28 -0
  130. package/templates/nova/src/components/base/IconButton.css +34 -0
  131. package/templates/nova/src/components/base/IconButton.tsx +41 -0
  132. package/templates/nova/src/components/base/Input.css +21 -0
  133. package/templates/nova/src/components/base/Input.tsx +24 -0
  134. package/templates/nova/src/components/base/Link.css +15 -0
  135. package/templates/nova/src/components/base/Link.tsx +23 -0
  136. package/templates/nova/src/components/base/Radio.tsx +13 -0
  137. package/templates/nova/src/components/base/Select.css +18 -0
  138. package/templates/nova/src/components/base/Select.tsx +34 -0
  139. package/templates/nova/src/components/base/Skeleton.css +17 -0
  140. package/templates/nova/src/components/base/Skeleton.tsx +23 -0
  141. package/templates/nova/src/components/base/Spinner.css +13 -0
  142. package/templates/nova/src/components/base/Spinner.tsx +8 -0
  143. package/templates/nova/src/components/base/Switch.tsx +16 -0
  144. package/templates/nova/src/components/base/Tabs.css +24 -0
  145. package/templates/nova/src/components/base/Tabs.tsx +61 -0
  146. package/templates/nova/src/components/base/Textarea.css +1 -0
  147. package/templates/nova/src/components/base/Textarea.tsx +8 -0
  148. package/templates/nova/src/components/base/choice-props.ts +9 -0
  149. package/templates/nova/src/components/base/choice.css +69 -0
  150. package/templates/nova/src/components/commerce/AddToCart.css +4 -0
  151. package/templates/nova/src/components/commerce/AddToCart.tsx +77 -0
  152. package/templates/nova/src/components/commerce/CartLine.css +26 -0
  153. package/templates/nova/src/components/commerce/CartLine.tsx +82 -0
  154. package/templates/nova/src/components/commerce/CartSummary.css +23 -0
  155. package/templates/nova/src/components/commerce/CartSummary.tsx +120 -0
  156. package/templates/nova/src/components/commerce/CollectionCard.css +66 -0
  157. package/templates/nova/src/components/commerce/CollectionCard.tsx +57 -0
  158. package/templates/nova/src/components/commerce/ComparisonTable.css +33 -0
  159. package/templates/nova/src/components/commerce/ComparisonTable.tsx +113 -0
  160. package/templates/nova/src/components/commerce/EarnHint.css +3 -0
  161. package/templates/nova/src/components/commerce/EarnHint.tsx +31 -0
  162. package/templates/nova/src/components/commerce/Hotspot.css +16 -0
  163. package/templates/nova/src/components/commerce/Hotspot.tsx +64 -0
  164. package/templates/nova/src/components/commerce/ListingParts.css +79 -0
  165. package/templates/nova/src/components/commerce/ListingParts.tsx +211 -0
  166. package/templates/nova/src/components/commerce/LookItem.css +19 -0
  167. package/templates/nova/src/components/commerce/LookItem.tsx +41 -0
  168. package/templates/nova/src/components/commerce/MiniCartLine.css +20 -0
  169. package/templates/nova/src/components/commerce/MiniCartLine.tsx +93 -0
  170. package/templates/nova/src/components/commerce/PaymentMark.css +2 -0
  171. package/templates/nova/src/components/commerce/PaymentMark.tsx +55 -0
  172. package/templates/nova/src/components/commerce/Price.css +27 -0
  173. package/templates/nova/src/components/commerce/Price.tsx +55 -0
  174. package/templates/nova/src/components/commerce/ProductCard.css +66 -0
  175. package/templates/nova/src/components/commerce/ProductCard.tsx +117 -0
  176. package/templates/nova/src/components/commerce/ProductGallery.css +72 -0
  177. package/templates/nova/src/components/commerce/ProductGallery.tsx +98 -0
  178. package/templates/nova/src/components/commerce/QuantitySelector.css +23 -0
  179. package/templates/nova/src/components/commerce/QuantitySelector.tsx +45 -0
  180. package/templates/nova/src/components/commerce/Reviews.css +34 -0
  181. package/templates/nova/src/components/commerce/Reviews.tsx +112 -0
  182. package/templates/nova/src/components/commerce/Stars.css +7 -0
  183. package/templates/nova/src/components/commerce/Stars.tsx +38 -0
  184. package/templates/nova/src/components/commerce/VariantPicker.css +31 -0
  185. package/templates/nova/src/components/commerce/VariantPicker.tsx +122 -0
  186. package/templates/nova/src/components/commerce/blocks/Badge.css +6 -0
  187. package/templates/nova/src/components/commerce/blocks/Badge.tsx +33 -0
  188. package/templates/nova/src/components/commerce/blocks/PaymentIcons.tsx +43 -0
  189. package/templates/nova/src/components/commerce/blocks/Swatches.tsx +17 -0
  190. package/templates/nova/src/components/commerce/blocks/payment.css +2 -0
  191. package/templates/nova/src/components/commerce/cart-limit.ts +11 -0
  192. package/templates/nova/src/components/commerce/money.ts +34 -0
  193. package/templates/nova/src/components/commerce/swatch.ts +54 -0
  194. package/templates/nova/src/components/content/ArticleCard.css +22 -0
  195. package/templates/nova/src/components/content/ArticleCard.tsx +53 -0
  196. package/templates/nova/src/components/content/BeforeAfterSlider.css +38 -0
  197. package/templates/nova/src/components/content/BeforeAfterSlider.tsx +87 -0
  198. package/templates/nova/src/components/content/CardRow.css +80 -0
  199. package/templates/nova/src/components/content/CardRow.tsx +140 -0
  200. package/templates/nova/src/components/content/CarouselControls.css +61 -0
  201. package/templates/nova/src/components/content/CarouselControls.tsx +90 -0
  202. package/templates/nova/src/components/content/ContentsNav.css +16 -0
  203. package/templates/nova/src/components/content/ContentsNav.tsx +55 -0
  204. package/templates/nova/src/components/content/Countdown.css +24 -0
  205. package/templates/nova/src/components/content/Countdown.tsx +115 -0
  206. package/templates/nova/src/components/content/HeroCopy.css +92 -0
  207. package/templates/nova/src/components/content/HeroCopy.tsx +148 -0
  208. package/templates/nova/src/components/content/HeroFrame.css +75 -0
  209. package/templates/nova/src/components/content/HeroFrame.tsx +49 -0
  210. package/templates/nova/src/components/content/HeroMedia.css +40 -0
  211. package/templates/nova/src/components/content/HeroMedia.tsx +170 -0
  212. package/templates/nova/src/components/content/LongForm.css +40 -0
  213. package/templates/nova/src/components/content/LongForm.tsx +56 -0
  214. package/templates/nova/src/components/content/MediaFrame.css +5 -0
  215. package/templates/nova/src/components/content/MediaFrame.tsx +52 -0
  216. package/templates/nova/src/components/content/RichText.tsx +30 -0
  217. package/templates/nova/src/components/content/SectionHead.css +8 -0
  218. package/templates/nova/src/components/content/SectionHead.tsx +34 -0
  219. package/templates/nova/src/components/content/ShareButtons.css +2 -0
  220. package/templates/nova/src/components/content/ShareButtons.tsx +40 -0
  221. package/templates/nova/src/components/content/StoreCard.css +14 -0
  222. package/templates/nova/src/components/content/StoreCard.tsx +60 -0
  223. package/templates/nova/src/components/content/TestimonialCard.css +36 -0
  224. package/templates/nova/src/components/content/TestimonialCard.tsx +102 -0
  225. package/templates/nova/src/components/content/UgcTile.css +8 -0
  226. package/templates/nova/src/components/content/UgcTile.tsx +33 -0
  227. package/templates/nova/src/components/content/blocks/Button.tsx +36 -0
  228. package/templates/nova/src/components/content/blocks/Column.tsx +30 -0
  229. package/templates/nova/src/components/content/blocks/Heading.tsx +31 -0
  230. package/templates/nova/src/components/content/blocks/Icon.tsx +25 -0
  231. package/templates/nova/src/components/content/blocks/Image.tsx +42 -0
  232. package/templates/nova/src/components/content/blocks/Text.tsx +26 -0
  233. package/templates/nova/src/components/content/blocks/Video.tsx +44 -0
  234. package/templates/nova/src/components/content/blocks/content.css +25 -0
  235. package/templates/nova/src/components/content/blocks/shared.ts +5 -0
  236. package/templates/nova/src/components/forms/ContactForm.css +19 -0
  237. package/templates/nova/src/components/forms/ContactForm.tsx +139 -0
  238. package/templates/nova/src/components/forms/FormField.css +15 -0
  239. package/templates/nova/src/components/forms/FormField.tsx +77 -0
  240. package/templates/nova/src/components/forms/GatewayFields.tsx +79 -0
  241. package/templates/nova/src/components/forms/NewsletterForm.css +9 -0
  242. package/templates/nova/src/components/forms/NewsletterForm.tsx +141 -0
  243. package/templates/nova/src/components/forms/SearchField.css +7 -0
  244. package/templates/nova/src/components/forms/SearchField.tsx +68 -0
  245. package/templates/nova/src/components/forms/blocks/Newsletter.css +5 -0
  246. package/templates/nova/src/components/forms/blocks/Newsletter.tsx +71 -0
  247. package/templates/nova/src/components/forms/validate.ts +4 -0
  248. package/templates/nova/src/components/listing/ProductListing.tsx +200 -0
  249. package/templates/nova/src/components/navigation/BrandLogo.tsx +35 -0
  250. package/templates/nova/src/components/navigation/Breadcrumb.css +16 -0
  251. package/templates/nova/src/components/navigation/Breadcrumb.tsx +59 -0
  252. package/templates/nova/src/components/navigation/LineAddFriend.css +5 -0
  253. package/templates/nova/src/components/navigation/LineAddFriend.tsx +42 -0
  254. package/templates/nova/src/components/navigation/LocaleSelector.css +33 -0
  255. package/templates/nova/src/components/navigation/LocaleSelector.tsx +64 -0
  256. package/templates/nova/src/components/navigation/Menu.tsx +26 -0
  257. package/templates/nova/src/components/navigation/Pagination.css +24 -0
  258. package/templates/nova/src/components/navigation/Pagination.tsx +74 -0
  259. package/templates/nova/src/components/navigation/RecoveryLinks.css +8 -0
  260. package/templates/nova/src/components/navigation/RecoveryLinks.tsx +23 -0
  261. package/templates/nova/src/components/navigation/SocialLinks.css +5 -0
  262. package/templates/nova/src/components/navigation/SocialLinks.tsx +51 -0
  263. package/templates/nova/src/components/navigation/blocks/SocialLinks.tsx +23 -0
  264. package/templates/nova/src/components/overlays/AccountMenu.css +11 -0
  265. package/templates/nova/src/components/overlays/AccountMenu.tsx +91 -0
  266. package/templates/nova/src/components/overlays/CartDrawer.css +17 -0
  267. package/templates/nova/src/components/overlays/CartDrawer.tsx +118 -0
  268. package/templates/nova/src/components/overlays/ConfirmationDialog.tsx +49 -0
  269. package/templates/nova/src/components/overlays/CookieConsent.css +56 -0
  270. package/templates/nova/src/components/overlays/CookieConsent.tsx +170 -0
  271. package/templates/nova/src/components/overlays/Drawer.css +38 -0
  272. package/templates/nova/src/components/overlays/Drawer.tsx +66 -0
  273. package/templates/nova/src/components/overlays/FriendOfferPanel.tsx +79 -0
  274. package/templates/nova/src/components/overlays/MarketSelector.css +111 -0
  275. package/templates/nova/src/components/overlays/MarketSelector.tsx +450 -0
  276. package/templates/nova/src/components/overlays/Menu.css +9 -0
  277. package/templates/nova/src/components/overlays/Menu.tsx +124 -0
  278. package/templates/nova/src/components/overlays/MobileNavDrawer.css +28 -0
  279. package/templates/nova/src/components/overlays/MobileNavDrawer.tsx +166 -0
  280. package/templates/nova/src/components/overlays/Modal.css +52 -0
  281. package/templates/nova/src/components/overlays/Modal.tsx +88 -0
  282. package/templates/nova/src/components/overlays/Popover.css +4 -0
  283. package/templates/nova/src/components/overlays/Popover.tsx +115 -0
  284. package/templates/nova/src/components/overlays/ProductLightbox.css +20 -0
  285. package/templates/nova/src/components/overlays/ProductLightbox.tsx +70 -0
  286. package/templates/nova/src/components/overlays/PromoPopup.css +32 -0
  287. package/templates/nova/src/components/overlays/PromoPopup.tsx +198 -0
  288. package/templates/nova/src/components/overlays/QuickView.css +31 -0
  289. package/templates/nova/src/components/overlays/QuickView.tsx +127 -0
  290. package/templates/nova/src/components/overlays/ReferralPanel.css +16 -0
  291. package/templates/nova/src/components/overlays/ReferralPanel.tsx +138 -0
  292. package/templates/nova/src/components/overlays/RewardsLauncher.css +22 -0
  293. package/templates/nova/src/components/overlays/RewardsLauncher.tsx +270 -0
  294. package/templates/nova/src/components/overlays/SearchModal.css +48 -0
  295. package/templates/nova/src/components/overlays/SearchModal.tsx +302 -0
  296. package/templates/nova/src/components/overlays/Sheet.css +16 -0
  297. package/templates/nova/src/components/overlays/Sheet.tsx +48 -0
  298. package/templates/nova/src/components/overlays/SizeGuide.css +8 -0
  299. package/templates/nova/src/components/overlays/SizeGuide.tsx +74 -0
  300. package/templates/nova/src/components/overlays/Toast.css +20 -0
  301. package/templates/nova/src/components/overlays/Toast.tsx +164 -0
  302. package/templates/nova/src/components/overlays/Tooltip.css +6 -0
  303. package/templates/nova/src/components/overlays/Tooltip.tsx +59 -0
  304. package/templates/nova/src/components/overlays/use-dialog.ts +74 -0
  305. package/templates/nova/src/components/section/shared.css +42 -0
  306. package/templates/nova/src/components/section/shared.ts +120 -0
  307. package/templates/nova/src/components/section/shell.tsx +29 -0
  308. package/templates/nova/src/components/states/Alert.css +10 -0
  309. package/templates/nova/src/components/states/Alert.tsx +50 -0
  310. package/templates/nova/src/components/states/EditorFrame.css +31 -0
  311. package/templates/nova/src/components/states/EditorFrame.tsx +43 -0
  312. package/templates/nova/src/components/states/MediaState.css +1 -0
  313. package/templates/nova/src/components/states/MediaState.tsx +49 -0
  314. package/templates/nova/src/components/states/OfflineNotice.css +4 -0
  315. package/templates/nova/src/components/states/OfflineNotice.tsx +24 -0
  316. package/templates/nova/src/components/states/SkeletonLayout.css +22 -0
  317. package/templates/nova/src/components/states/SkeletonLayout.tsx +104 -0
  318. package/templates/nova/src/components/states/StateBlock.css +22 -0
  319. package/templates/nova/src/components/states/StateBlock.tsx +39 -0
  320. package/templates/nova/src/components/states/media/MediaError.css +6 -0
  321. package/templates/nova/src/components/states/media/MediaError.tsx +49 -0
  322. package/templates/nova/src/components/states/media/MediaPlaceholder.css +24 -0
  323. package/templates/nova/src/components/states/media/MediaPlaceholder.tsx +101 -0
  324. package/templates/nova/src/components/states/media/placeholder-art.ts +142 -0
  325. package/templates/nova/src/layouts/Main.tsx +80 -0
  326. package/templates/nova/src/sections/Account/Account.tsx +109 -0
  327. package/templates/nova/src/sections/Account/index.ts +22 -0
  328. package/templates/nova/src/sections/Account/presets.ts +6 -0
  329. package/templates/nova/src/sections/Account/schema.ts +29 -0
  330. package/templates/nova/src/sections/AnnouncementBar/AnnouncementBar.css +37 -0
  331. package/templates/nova/src/sections/AnnouncementBar/AnnouncementBar.tsx +151 -0
  332. package/templates/nova/src/sections/AnnouncementBar/index.ts +20 -0
  333. package/templates/nova/src/sections/AnnouncementBar/presets.ts +10 -0
  334. package/templates/nova/src/sections/AnnouncementBar/schema.ts +26 -0
  335. package/templates/nova/src/sections/ArticleBody/ArticleBody.tsx +129 -0
  336. package/templates/nova/src/sections/ArticleBody/index.ts +21 -0
  337. package/templates/nova/src/sections/ArticleBody/presets.ts +10 -0
  338. package/templates/nova/src/sections/ArticleBody/schema.ts +40 -0
  339. package/templates/nova/src/sections/BeforeAfter/BeforeAfter.tsx +47 -0
  340. package/templates/nova/src/sections/BeforeAfter/blocks/Comparison.tsx +20 -0
  341. package/templates/nova/src/sections/BeforeAfter/index.ts +28 -0
  342. package/templates/nova/src/sections/BeforeAfter/presets.ts +10 -0
  343. package/templates/nova/src/sections/BeforeAfter/schema.ts +34 -0
  344. package/templates/nova/src/sections/BlogPosts/BlogPosts.tsx +106 -0
  345. package/templates/nova/src/sections/BlogPosts/index.ts +30 -0
  346. package/templates/nova/src/sections/BlogPosts/presets.ts +10 -0
  347. package/templates/nova/src/sections/BlogPosts/schema.ts +42 -0
  348. package/templates/nova/src/sections/Breadcrumbs/Breadcrumbs.css +10 -0
  349. package/templates/nova/src/sections/Breadcrumbs/Breadcrumbs.tsx +41 -0
  350. package/templates/nova/src/sections/Breadcrumbs/index.ts +20 -0
  351. package/templates/nova/src/sections/Breadcrumbs/presets.ts +6 -0
  352. package/templates/nova/src/sections/Breadcrumbs/schema.ts +24 -0
  353. package/templates/nova/src/sections/CartItems/CartItems.tsx +170 -0
  354. package/templates/nova/src/sections/CartItems/blocks/CartBadge.tsx +14 -0
  355. package/templates/nova/src/sections/CartItems/index.ts +37 -0
  356. package/templates/nova/src/sections/CartItems/presets.ts +8 -0
  357. package/templates/nova/src/sections/CartItems/schema.ts +34 -0
  358. package/templates/nova/src/sections/CollectionBanner/CollectionBanner.tsx +120 -0
  359. package/templates/nova/src/sections/CollectionBanner/index.ts +25 -0
  360. package/templates/nova/src/sections/CollectionBanner/presets.ts +10 -0
  361. package/templates/nova/src/sections/CollectionBanner/schema.ts +37 -0
  362. package/templates/nova/src/sections/CollectionLinks/CollectionLinks.tsx +47 -0
  363. package/templates/nova/src/sections/CollectionLinks/index.ts +20 -0
  364. package/templates/nova/src/sections/CollectionLinks/presets.ts +8 -0
  365. package/templates/nova/src/sections/CollectionLinks/schema.ts +33 -0
  366. package/templates/nova/src/sections/CollectionList/CollectionList.tsx +89 -0
  367. package/templates/nova/src/sections/CollectionList/blocks/CollectionItem.tsx +25 -0
  368. package/templates/nova/src/sections/CollectionList/index.ts +33 -0
  369. package/templates/nova/src/sections/CollectionList/presets.ts +10 -0
  370. package/templates/nova/src/sections/CollectionList/schema.ts +41 -0
  371. package/templates/nova/src/sections/ComparisonTable/ComparisonTable.tsx +52 -0
  372. package/templates/nova/src/sections/ComparisonTable/blocks/CompareItem.tsx +26 -0
  373. package/templates/nova/src/sections/ComparisonTable/index.ts +31 -0
  374. package/templates/nova/src/sections/ComparisonTable/presets.ts +8 -0
  375. package/templates/nova/src/sections/ComparisonTable/schema.ts +31 -0
  376. package/templates/nova/src/sections/ContactForm/ContactForm.tsx +83 -0
  377. package/templates/nova/src/sections/ContactForm/blocks/ContactDetail.tsx +13 -0
  378. package/templates/nova/src/sections/ContactForm/index.ts +29 -0
  379. package/templates/nova/src/sections/ContactForm/presets.ts +8 -0
  380. package/templates/nova/src/sections/ContactForm/schema.ts +34 -0
  381. package/templates/nova/src/sections/Divider/Divider.css +17 -0
  382. package/templates/nova/src/sections/Divider/Divider.tsx +21 -0
  383. package/templates/nova/src/sections/Divider/index.ts +20 -0
  384. package/templates/nova/src/sections/Divider/presets.ts +10 -0
  385. package/templates/nova/src/sections/Divider/schema.ts +24 -0
  386. package/templates/nova/src/sections/Faq/Faq.tsx +51 -0
  387. package/templates/nova/src/sections/Faq/blocks/FaqItem.tsx +13 -0
  388. package/templates/nova/src/sections/Faq/index.ts +28 -0
  389. package/templates/nova/src/sections/Faq/presets.ts +8 -0
  390. package/templates/nova/src/sections/Faq/schema.ts +32 -0
  391. package/templates/nova/src/sections/FeatureGridBlocks/FeatureGridBlocks.tsx +90 -0
  392. package/templates/nova/src/sections/FeatureGridBlocks/index.ts +35 -0
  393. package/templates/nova/src/sections/FeatureGridBlocks/presets.ts +8 -0
  394. package/templates/nova/src/sections/FeatureGridBlocks/schema.ts +35 -0
  395. package/templates/nova/src/sections/FeatureHighlights/FeatureHighlights.tsx +56 -0
  396. package/templates/nova/src/sections/FeatureHighlights/index.ts +20 -0
  397. package/templates/nova/src/sections/FeatureHighlights/presets.ts +6 -0
  398. package/templates/nova/src/sections/FeatureHighlights/schema.ts +27 -0
  399. package/templates/nova/src/sections/FeaturedCollection/FeaturedCollection.tsx +67 -0
  400. package/templates/nova/src/sections/FeaturedCollection/index.ts +21 -0
  401. package/templates/nova/src/sections/FeaturedCollection/presets.ts +10 -0
  402. package/templates/nova/src/sections/FeaturedCollection/schema.ts +39 -0
  403. package/templates/nova/src/sections/FeaturedProduct/FeaturedProduct.tsx +107 -0
  404. package/templates/nova/src/sections/FeaturedProduct/index.ts +23 -0
  405. package/templates/nova/src/sections/FeaturedProduct/presets.ts +8 -0
  406. package/templates/nova/src/sections/FeaturedProduct/schema.ts +35 -0
  407. package/templates/nova/src/sections/Footer/Footer.css +81 -0
  408. package/templates/nova/src/sections/Footer/Footer.tsx +256 -0
  409. package/templates/nova/src/sections/Footer/blocks/FooterBrand.tsx +40 -0
  410. package/templates/nova/src/sections/Footer/blocks/FooterLine.tsx +11 -0
  411. package/templates/nova/src/sections/Footer/blocks/FooterMenu.tsx +14 -0
  412. package/templates/nova/src/sections/Footer/blocks/FooterText.tsx +8 -0
  413. package/templates/nova/src/sections/Footer/blocks/footer.css +7 -0
  414. package/templates/nova/src/sections/Footer/index.ts +38 -0
  415. package/templates/nova/src/sections/Footer/presets.ts +10 -0
  416. package/templates/nova/src/sections/Footer/schema.ts +27 -0
  417. package/templates/nova/src/sections/Group/Group.css +59 -0
  418. package/templates/nova/src/sections/Group/Group.tsx +167 -0
  419. package/templates/nova/src/sections/Group/blocks/Accordion.tsx +26 -0
  420. package/templates/nova/src/sections/Group/blocks/JumboText.tsx +20 -0
  421. package/templates/nova/src/sections/Group/blocks/Spacer.tsx +16 -0
  422. package/templates/nova/src/sections/Group/index.ts +36 -0
  423. package/templates/nova/src/sections/Group/presets.ts +12 -0
  424. package/templates/nova/src/sections/Group/schema.ts +35 -0
  425. package/templates/nova/src/sections/Header/Header.css +185 -0
  426. package/templates/nova/src/sections/Header/Header.tsx +478 -0
  427. package/templates/nova/src/sections/Header/index.ts +32 -0
  428. package/templates/nova/src/sections/Header/presets.ts +10 -0
  429. package/templates/nova/src/sections/Header/schema.ts +32 -0
  430. package/templates/nova/src/sections/Hero/Hero.tsx +128 -0
  431. package/templates/nova/src/sections/Hero/index.ts +24 -0
  432. package/templates/nova/src/sections/Hero/presets.ts +16 -0
  433. package/templates/nova/src/sections/Hero/schema.ts +56 -0
  434. package/templates/nova/src/sections/ImageGallery/ImageGallery.tsx +86 -0
  435. package/templates/nova/src/sections/ImageGallery/index.ts +28 -0
  436. package/templates/nova/src/sections/ImageGallery/presets.ts +10 -0
  437. package/templates/nova/src/sections/ImageGallery/schema.ts +34 -0
  438. package/templates/nova/src/sections/ImageWithText/ImageWithText.tsx +62 -0
  439. package/templates/nova/src/sections/ImageWithText/index.ts +23 -0
  440. package/templates/nova/src/sections/ImageWithText/presets.ts +12 -0
  441. package/templates/nova/src/sections/ImageWithText/schema.ts +45 -0
  442. package/templates/nova/src/sections/LineAddFriend/LineAddFriend.tsx +25 -0
  443. package/templates/nova/src/sections/LineAddFriend/index.ts +20 -0
  444. package/templates/nova/src/sections/LineAddFriend/presets.ts +3 -0
  445. package/templates/nova/src/sections/LineAddFriend/schema.ts +25 -0
  446. package/templates/nova/src/sections/LogoList/LogoList.tsx +40 -0
  447. package/templates/nova/src/sections/LogoList/blocks/Logo.tsx +18 -0
  448. package/templates/nova/src/sections/LogoList/index.ts +29 -0
  449. package/templates/nova/src/sections/LogoList/presets.ts +8 -0
  450. package/templates/nova/src/sections/LogoList/schema.ts +29 -0
  451. package/templates/nova/src/sections/MainCollection/MainCollection.tsx +51 -0
  452. package/templates/nova/src/sections/MainCollection/index.ts +26 -0
  453. package/templates/nova/src/sections/MainCollection/presets.ts +10 -0
  454. package/templates/nova/src/sections/MainCollection/schema.ts +29 -0
  455. package/templates/nova/src/sections/Marquee/Marquee.tsx +114 -0
  456. package/templates/nova/src/sections/Marquee/index.ts +20 -0
  457. package/templates/nova/src/sections/Marquee/presets.ts +10 -0
  458. package/templates/nova/src/sections/Marquee/schema.ts +23 -0
  459. package/templates/nova/src/sections/Multicolumn/Multicolumn.tsx +56 -0
  460. package/templates/nova/src/sections/Multicolumn/index.ts +25 -0
  461. package/templates/nova/src/sections/Multicolumn/presets.ts +8 -0
  462. package/templates/nova/src/sections/Multicolumn/schema.ts +34 -0
  463. package/templates/nova/src/sections/Newsletter/Newsletter.tsx +64 -0
  464. package/templates/nova/src/sections/Newsletter/index.ts +20 -0
  465. package/templates/nova/src/sections/Newsletter/presets.ts +10 -0
  466. package/templates/nova/src/sections/Newsletter/schema.ts +36 -0
  467. package/templates/nova/src/sections/NotFound/NotFound.tsx +41 -0
  468. package/templates/nova/src/sections/NotFound/index.ts +20 -0
  469. package/templates/nova/src/sections/NotFound/presets.ts +6 -0
  470. package/templates/nova/src/sections/NotFound/schema.ts +30 -0
  471. package/templates/nova/src/sections/PageBody/PageBody.tsx +35 -0
  472. package/templates/nova/src/sections/PageBody/index.ts +21 -0
  473. package/templates/nova/src/sections/PageBody/presets.ts +6 -0
  474. package/templates/nova/src/sections/PageBody/schema.ts +29 -0
  475. package/templates/nova/src/sections/PolicyPage/PolicyPage.tsx +62 -0
  476. package/templates/nova/src/sections/PolicyPage/index.ts +23 -0
  477. package/templates/nova/src/sections/PolicyPage/presets.ts +6 -0
  478. package/templates/nova/src/sections/PolicyPage/schema.ts +27 -0
  479. package/templates/nova/src/sections/ProductDetails/ProductDetails.tsx +269 -0
  480. package/templates/nova/src/sections/ProductDetails/blocks/AddToCartBlock.tsx +15 -0
  481. package/templates/nova/src/sections/ProductDetails/blocks/ProductDescription.tsx +15 -0
  482. package/templates/nova/src/sections/ProductDetails/blocks/ProductInventory.tsx +38 -0
  483. package/templates/nova/src/sections/ProductDetails/blocks/ProductPrice.tsx +19 -0
  484. package/templates/nova/src/sections/ProductDetails/blocks/ProductSku.tsx +15 -0
  485. package/templates/nova/src/sections/ProductDetails/blocks/ProductTitle.tsx +17 -0
  486. package/templates/nova/src/sections/ProductDetails/blocks/Quantity.tsx +14 -0
  487. package/templates/nova/src/sections/ProductDetails/blocks/Tab.tsx +23 -0
  488. package/templates/nova/src/sections/ProductDetails/blocks/VariantPickerBlock.tsx +44 -0
  489. package/templates/nova/src/sections/ProductDetails/blocks/commerce-blocks.css +13 -0
  490. package/templates/nova/src/sections/ProductDetails/index.ts +44 -0
  491. package/templates/nova/src/sections/ProductDetails/presets.ts +10 -0
  492. package/templates/nova/src/sections/ProductDetails/schema.ts +44 -0
  493. package/templates/nova/src/sections/ProductGrid/ProductGrid.tsx +38 -0
  494. package/templates/nova/src/sections/ProductGrid/index.ts +25 -0
  495. package/templates/nova/src/sections/ProductGrid/presets.ts +6 -0
  496. package/templates/nova/src/sections/ProductGrid/schema.ts +37 -0
  497. package/templates/nova/src/sections/ProductRecommendations/ProductRecommendations.tsx +45 -0
  498. package/templates/nova/src/sections/ProductRecommendations/index.ts +20 -0
  499. package/templates/nova/src/sections/ProductRecommendations/presets.ts +8 -0
  500. package/templates/nova/src/sections/ProductRecommendations/schema.ts +28 -0
  501. package/templates/nova/src/sections/ProductReviews/ProductReviews.tsx +136 -0
  502. package/templates/nova/src/sections/ProductReviews/index.ts +22 -0
  503. package/templates/nova/src/sections/ProductReviews/presets.ts +6 -0
  504. package/templates/nova/src/sections/ProductReviews/schema.ts +31 -0
  505. package/templates/nova/src/sections/PromoBanner/PromoBanner.tsx +78 -0
  506. package/templates/nova/src/sections/PromoBanner/index.ts +20 -0
  507. package/templates/nova/src/sections/PromoBanner/presets.ts +10 -0
  508. package/templates/nova/src/sections/PromoBanner/schema.ts +38 -0
  509. package/templates/nova/src/sections/RecentlyViewed/RecentlyViewed.tsx +53 -0
  510. package/templates/nova/src/sections/RecentlyViewed/index.ts +20 -0
  511. package/templates/nova/src/sections/RecentlyViewed/presets.ts +6 -0
  512. package/templates/nova/src/sections/RecentlyViewed/schema.ts +26 -0
  513. package/templates/nova/src/sections/RichText/RichText.tsx +38 -0
  514. package/templates/nova/src/sections/RichText/index.ts +20 -0
  515. package/templates/nova/src/sections/RichText/presets.ts +10 -0
  516. package/templates/nova/src/sections/RichText/schema.ts +37 -0
  517. package/templates/nova/src/sections/SearchResults/SearchResults.tsx +112 -0
  518. package/templates/nova/src/sections/SearchResults/index.ts +26 -0
  519. package/templates/nova/src/sections/SearchResults/presets.ts +8 -0
  520. package/templates/nova/src/sections/SearchResults/schema.ts +30 -0
  521. package/templates/nova/src/sections/ShopTheLook/ShopTheLook.tsx +112 -0
  522. package/templates/nova/src/sections/ShopTheLook/blocks/Hotspot.tsx +22 -0
  523. package/templates/nova/src/sections/ShopTheLook/index.ts +33 -0
  524. package/templates/nova/src/sections/ShopTheLook/presets.ts +8 -0
  525. package/templates/nova/src/sections/ShopTheLook/schema.ts +31 -0
  526. package/templates/nova/src/sections/Slideshow/Slideshow.tsx +199 -0
  527. package/templates/nova/src/sections/Slideshow/blocks/Slide.tsx +93 -0
  528. package/templates/nova/src/sections/Slideshow/index.ts +30 -0
  529. package/templates/nova/src/sections/Slideshow/presets.ts +10 -0
  530. package/templates/nova/src/sections/Slideshow/schema.ts +36 -0
  531. package/templates/nova/src/sections/StoreLocator/StoreLocator.tsx +66 -0
  532. package/templates/nova/src/sections/StoreLocator/index.ts +20 -0
  533. package/templates/nova/src/sections/StoreLocator/presets.ts +6 -0
  534. package/templates/nova/src/sections/StoreLocator/schema.ts +34 -0
  535. package/templates/nova/src/sections/TeamFounders/TeamFounders.tsx +74 -0
  536. package/templates/nova/src/sections/TeamFounders/blocks/Person.tsx +28 -0
  537. package/templates/nova/src/sections/TeamFounders/index.ts +28 -0
  538. package/templates/nova/src/sections/TeamFounders/presets.ts +10 -0
  539. package/templates/nova/src/sections/TeamFounders/schema.ts +36 -0
  540. package/templates/nova/src/sections/Testimonials/Testimonials.tsx +83 -0
  541. package/templates/nova/src/sections/Testimonials/blocks/Testimonial.tsx +30 -0
  542. package/templates/nova/src/sections/Testimonials/index.ts +29 -0
  543. package/templates/nova/src/sections/Testimonials/presets.ts +10 -0
  544. package/templates/nova/src/sections/Testimonials/schema.ts +35 -0
  545. package/templates/nova/src/sections/Timeline/Timeline.tsx +43 -0
  546. package/templates/nova/src/sections/Timeline/blocks/Step.tsx +19 -0
  547. package/templates/nova/src/sections/Timeline/index.ts +28 -0
  548. package/templates/nova/src/sections/Timeline/presets.ts +8 -0
  549. package/templates/nova/src/sections/Timeline/schema.ts +31 -0
  550. package/templates/nova/src/sections/TrustBadges/TrustBadges.tsx +42 -0
  551. package/templates/nova/src/sections/TrustBadges/index.ts +29 -0
  552. package/templates/nova/src/sections/TrustBadges/presets.ts +8 -0
  553. package/templates/nova/src/sections/TrustBadges/schema.ts +29 -0
  554. package/templates/nova/src/sections/UgcGallery/UgcGallery.tsx +58 -0
  555. package/templates/nova/src/sections/UgcGallery/blocks/UgcImage.tsx +27 -0
  556. package/templates/nova/src/sections/UgcGallery/index.ts +31 -0
  557. package/templates/nova/src/sections/UgcGallery/presets.ts +8 -0
  558. package/templates/nova/src/sections/UgcGallery/schema.ts +35 -0
  559. package/templates/nova/src/sections/VideoHero/VideoHero.tsx +75 -0
  560. package/templates/nova/src/sections/VideoHero/index.ts +22 -0
  561. package/templates/nova/src/sections/VideoHero/presets.ts +8 -0
  562. package/templates/nova/src/sections/VideoHero/schema.ts +43 -0
  563. package/templates/nova/src/sections/data.ts +115 -0
  564. package/templates/nova/src/sections/shipped-copy.ts +25 -0
  565. package/templates/nova/src/sections/starter.ts +49 -0
  566. package/templates/nova/src/styles/Container.css +6 -0
  567. package/templates/nova/src/styles/Container.tsx +13 -0
  568. package/templates/nova/src/styles/Icon.css +2 -0
  569. package/templates/nova/src/styles/Icon.tsx +101 -0
  570. package/templates/nova/src/styles/NovaProvider.tsx +91 -0
  571. package/templates/nova/src/styles/base.css +142 -0
  572. package/templates/nova/src/styles/blocks.css +6 -0
  573. package/templates/nova/src/styles/fonts/OFL.txt +93 -0
  574. package/templates/nova/src/styles/fonts/geist-cyrillic-ext.woff2 +0 -0
  575. package/templates/nova/src/styles/fonts/geist-cyrillic.woff2 +0 -0
  576. package/templates/nova/src/styles/fonts/geist-latin-ext.woff2 +0 -0
  577. package/templates/nova/src/styles/fonts/geist-latin.woff2 +0 -0
  578. package/templates/nova/src/styles/fonts/geist-mono-cyrillic-ext.woff2 +0 -0
  579. package/templates/nova/src/styles/fonts/geist-mono-cyrillic.woff2 +0 -0
  580. package/templates/nova/src/styles/fonts/geist-mono-latin-ext.woff2 +0 -0
  581. package/templates/nova/src/styles/fonts/geist-mono-latin.woff2 +0 -0
  582. package/templates/nova/src/styles/fonts/geist-mono-vietnamese.woff2 +0 -0
  583. package/templates/nova/src/styles/fonts/geist-vietnamese.woff2 +0 -0
  584. package/templates/nova/src/styles/fonts.css +95 -0
  585. package/templates/nova/src/styles/global-settings.css +88 -0
  586. package/templates/nova/src/styles/index.css +6 -0
  587. package/templates/nova/src/styles/motion.ts +53 -0
  588. package/templates/nova/src/styles/scroll.ts +24 -0
  589. package/templates/nova/src/styles/sections/commerce.css +147 -0
  590. package/templates/nova/src/styles/sections/content.css +304 -0
  591. package/templates/nova/src/styles/sections/editorial.css +131 -0
  592. package/templates/nova/src/styles/sections/promotion.css +336 -0
  593. package/templates/nova/src/styles/sections/trust.css +117 -0
  594. package/templates/nova/src/styles/sections/utility.css +190 -0
  595. package/templates/nova/src/styles/strings.ts +492 -0
  596. package/templates/nova/src/styles/text.ts +4 -0
  597. package/templates/nova/src/styles/theme.ts +171 -0
  598. package/templates/nova/src/styles/tokens.css +600 -0
  599. package/templates/nova/src/styles/viewport.ts +23 -0
  600. package/templates/nova/template.json +94 -0
  601. package/templates/nova/templates/404.json +30 -0
  602. package/templates/nova/templates/account.json +15 -0
  603. package/templates/nova/templates/article.json +41 -0
  604. package/templates/nova/templates/article.longform.json +17 -0
  605. package/templates/nova/templates/blog.featured.json +22 -0
  606. package/templates/nova/templates/blog.json +29 -0
  607. package/templates/nova/templates/cart.json +67 -0
  608. package/templates/nova/templates/collection.featured.json +43 -0
  609. package/templates/nova/templates/collection.json +30 -0
  610. package/templates/nova/templates/contact.json +65 -0
  611. package/templates/nova/templates/index.json +167 -0
  612. package/templates/nova/templates/list-collections.json +19 -0
  613. package/templates/nova/templates/page.about.json +134 -0
  614. package/templates/nova/templates/page.contact.json +27 -0
  615. package/templates/nova/templates/page.json +27 -0
  616. package/templates/nova/templates/policy.json +23 -0
  617. package/templates/nova/templates/product.bundle.json +145 -0
  618. package/templates/nova/templates/product.json +119 -0
  619. package/templates/nova/templates/search.json +17 -0
  620. package/templates/nova/tests/abi-ai-contract.test.ts +99 -0
  621. package/templates/nova/tests/abi-forms.test.tsx +269 -0
  622. package/templates/nova/tests/abi-inventory.test.tsx +197 -0
  623. package/templates/nova/tests/abi-legacy-settings.test.tsx +105 -0
  624. package/templates/nova/tests/abi-opt-in.test.tsx +100 -0
  625. package/templates/nova/tests/abi-parity.test.tsx +95 -0
  626. package/templates/nova/tests/abi-r5-store-settings.test.tsx +337 -0
  627. package/templates/nova/tests/abi-render.test.tsx +178 -0
  628. package/templates/nova/tests/abi-shop-links.test.tsx +141 -0
  629. package/templates/nova/tests/abi-storefront-basics.test.tsx +233 -0
  630. package/templates/nova/tests/abi-variant-url.test.tsx +73 -0
  631. package/templates/nova/tests/add-refused-no-success.test.tsx +193 -0
  632. package/templates/nova/tests/architecture.test.ts +63 -0
  633. package/templates/nova/tests/architecture.ts +160 -0
  634. package/templates/nova/tests/audit-guards.test.ts +31 -0
  635. package/templates/nova/tests/bundle-split.test.ts +29 -0
  636. package/templates/nova/tests/cart-limit-message.test.tsx +212 -0
  637. package/templates/nova/tests/cart-link-message.test.tsx +98 -0
  638. package/templates/nova/tests/cases/components/Overview.cases.tsx +8 -0
  639. package/templates/nova/tests/cases/components/base/Accordion.cases.tsx +40 -0
  640. package/templates/nova/tests/cases/components/base/Badge.cases.tsx +30 -0
  641. package/templates/nova/tests/cases/components/base/Button.cases.tsx +73 -0
  642. package/templates/nova/tests/cases/components/base/Checkbox.cases.tsx +27 -0
  643. package/templates/nova/tests/cases/components/base/Chip.cases.tsx +37 -0
  644. package/templates/nova/tests/cases/components/base/Divider.cases.tsx +26 -0
  645. package/templates/nova/tests/cases/components/base/IconButton.cases.tsx +28 -0
  646. package/templates/nova/tests/cases/components/base/Input.cases.tsx +28 -0
  647. package/templates/nova/tests/cases/components/base/Link.cases.tsx +27 -0
  648. package/templates/nova/tests/cases/components/base/Radio.cases.tsx +27 -0
  649. package/templates/nova/tests/cases/components/base/Select.cases.tsx +26 -0
  650. package/templates/nova/tests/cases/components/base/Skeleton.cases.tsx +29 -0
  651. package/templates/nova/tests/cases/components/base/Spinner.cases.tsx +16 -0
  652. package/templates/nova/tests/cases/components/base/Switch.cases.tsx +26 -0
  653. package/templates/nova/tests/cases/components/base/Tabs.cases.tsx +39 -0
  654. package/templates/nova/tests/cases/components/base/Textarea.cases.tsx +17 -0
  655. package/templates/nova/tests/cases/components/commerce/AddToCart.cases.tsx +36 -0
  656. package/templates/nova/tests/cases/components/commerce/CartLine.cases.tsx +20 -0
  657. package/templates/nova/tests/cases/components/commerce/CartSummary.cases.tsx +16 -0
  658. package/templates/nova/tests/cases/components/commerce/CollectionCard.cases.tsx +19 -0
  659. package/templates/nova/tests/cases/components/commerce/ComparisonTable.cases.tsx +19 -0
  660. package/templates/nova/tests/cases/components/commerce/Hotspot.cases.tsx +25 -0
  661. package/templates/nova/tests/cases/components/commerce/LookItem.cases.tsx +19 -0
  662. package/templates/nova/tests/cases/components/commerce/PaymentMark.cases.tsx +16 -0
  663. package/templates/nova/tests/cases/components/commerce/Price.cases.tsx +27 -0
  664. package/templates/nova/tests/cases/components/commerce/ProductCard.cases.tsx +67 -0
  665. package/templates/nova/tests/cases/components/commerce/ProductGallery.cases.tsx +39 -0
  666. package/templates/nova/tests/cases/components/commerce/QuantitySelector.cases.tsx +31 -0
  667. package/templates/nova/tests/cases/components/commerce/Reviews.cases.tsx +35 -0
  668. package/templates/nova/tests/cases/components/commerce/Stars.cases.tsx +16 -0
  669. package/templates/nova/tests/cases/components/commerce/VariantPicker.cases.tsx +38 -0
  670. package/templates/nova/tests/cases/components/commerce/blocks/Badge.cases.tsx +17 -0
  671. package/templates/nova/tests/cases/components/commerce/blocks/PaymentIcons.cases.tsx +17 -0
  672. package/templates/nova/tests/cases/components/commerce/blocks/Swatches.cases.tsx +22 -0
  673. package/templates/nova/tests/cases/components/content/ArticleCard.cases.tsx +17 -0
  674. package/templates/nova/tests/cases/components/content/BeforeAfterSlider.cases.tsx +18 -0
  675. package/templates/nova/tests/cases/components/content/CardRow.cases.tsx +23 -0
  676. package/templates/nova/tests/cases/components/content/CarouselControls.cases.tsx +48 -0
  677. package/templates/nova/tests/cases/components/content/ContentsNav.cases.tsx +17 -0
  678. package/templates/nova/tests/cases/components/content/Countdown.cases.tsx +28 -0
  679. package/templates/nova/tests/cases/components/content/HeroCopy.cases.tsx +42 -0
  680. package/templates/nova/tests/cases/components/content/HeroFrame.cases.tsx +22 -0
  681. package/templates/nova/tests/cases/components/content/HeroMedia.cases.tsx +18 -0
  682. package/templates/nova/tests/cases/components/content/LongForm.cases.tsx +17 -0
  683. package/templates/nova/tests/cases/components/content/MediaFrame.cases.tsx +32 -0
  684. package/templates/nova/tests/cases/components/content/RichText.cases.tsx +19 -0
  685. package/templates/nova/tests/cases/components/content/SectionHead.cases.tsx +19 -0
  686. package/templates/nova/tests/cases/components/content/ShareButtons.cases.tsx +24 -0
  687. package/templates/nova/tests/cases/components/content/StoreCard.cases.tsx +17 -0
  688. package/templates/nova/tests/cases/components/content/TestimonialCard.cases.tsx +19 -0
  689. package/templates/nova/tests/cases/components/content/UgcTile.cases.tsx +18 -0
  690. package/templates/nova/tests/cases/components/content/blocks/Button.cases.tsx +20 -0
  691. package/templates/nova/tests/cases/components/content/blocks/Column.cases.tsx +17 -0
  692. package/templates/nova/tests/cases/components/content/blocks/Heading.cases.tsx +18 -0
  693. package/templates/nova/tests/cases/components/content/blocks/Icon.cases.tsx +17 -0
  694. package/templates/nova/tests/cases/components/content/blocks/Image.cases.tsx +22 -0
  695. package/templates/nova/tests/cases/components/content/blocks/Text.cases.tsx +18 -0
  696. package/templates/nova/tests/cases/components/content/blocks/Video.cases.tsx +18 -0
  697. package/templates/nova/tests/cases/components/forms/ContactForm.cases.tsx +29 -0
  698. package/templates/nova/tests/cases/components/forms/FormField.cases.tsx +61 -0
  699. package/templates/nova/tests/cases/components/forms/NewsletterForm.cases.tsx +17 -0
  700. package/templates/nova/tests/cases/components/forms/SearchField.cases.tsx +25 -0
  701. package/templates/nova/tests/cases/components/forms/blocks/Newsletter.cases.tsx +19 -0
  702. package/templates/nova/tests/cases/components/navigation/BrandLogo.cases.tsx +29 -0
  703. package/templates/nova/tests/cases/components/navigation/Breadcrumb.cases.tsx +19 -0
  704. package/templates/nova/tests/cases/components/navigation/LocaleSelector.cases.tsx +32 -0
  705. package/templates/nova/tests/cases/components/navigation/Menu.cases.tsx +27 -0
  706. package/templates/nova/tests/cases/components/navigation/Pagination.cases.tsx +25 -0
  707. package/templates/nova/tests/cases/components/navigation/RecoveryLinks.cases.tsx +16 -0
  708. package/templates/nova/tests/cases/components/navigation/SocialLinks.cases.tsx +18 -0
  709. package/templates/nova/tests/cases/components/navigation/blocks/SocialLinks.cases.tsx +17 -0
  710. package/templates/nova/tests/cases/components/overlays/AccountMenu.cases.tsx +28 -0
  711. package/templates/nova/tests/cases/components/overlays/CartDrawer.cases.tsx +30 -0
  712. package/templates/nova/tests/cases/components/overlays/ConfirmationDialog.cases.tsx +16 -0
  713. package/templates/nova/tests/cases/components/overlays/CookieConsent.cases.tsx +23 -0
  714. package/templates/nova/tests/cases/components/overlays/CookiePreferences.cases.tsx +16 -0
  715. package/templates/nova/tests/cases/components/overlays/Drawer.cases.tsx +52 -0
  716. package/templates/nova/tests/cases/components/overlays/MarketSelector.cases.tsx +82 -0
  717. package/templates/nova/tests/cases/components/overlays/Menu.cases.tsx +27 -0
  718. package/templates/nova/tests/cases/components/overlays/MobileNavDrawer.cases.tsx +32 -0
  719. package/templates/nova/tests/cases/components/overlays/Modal.cases.tsx +71 -0
  720. package/templates/nova/tests/cases/components/overlays/Popover.cases.tsx +50 -0
  721. package/templates/nova/tests/cases/components/overlays/PromoPopup.cases.tsx +19 -0
  722. package/templates/nova/tests/cases/components/overlays/QuickView.cases.tsx +18 -0
  723. package/templates/nova/tests/cases/components/overlays/SearchModal.cases.tsx +60 -0
  724. package/templates/nova/tests/cases/components/overlays/Sheet.cases.tsx +32 -0
  725. package/templates/nova/tests/cases/components/overlays/SizeGuide.cases.tsx +27 -0
  726. package/templates/nova/tests/cases/components/overlays/Toast.cases.tsx +48 -0
  727. package/templates/nova/tests/cases/components/overlays/Tooltip.cases.tsx +33 -0
  728. package/templates/nova/tests/cases/components/states/Alert.cases.tsx +27 -0
  729. package/templates/nova/tests/cases/components/states/EditorFrame.cases.tsx +36 -0
  730. package/templates/nova/tests/cases/components/states/Empty.cases.tsx +30 -0
  731. package/templates/nova/tests/cases/components/states/Error.cases.tsx +38 -0
  732. package/templates/nova/tests/cases/components/states/Loading.cases.tsx +15 -0
  733. package/templates/nova/tests/cases/components/states/MediaState.cases.tsx +29 -0
  734. package/templates/nova/tests/cases/components/states/SkeletonLayout.cases.tsx +20 -0
  735. package/templates/nova/tests/cases/components/states/Unavailable.cases.tsx +16 -0
  736. package/templates/nova/tests/cases/components/states/media/MediaError.cases.tsx +18 -0
  737. package/templates/nova/tests/cases/components/states/media/MediaPlaceholder.cases.tsx +87 -0
  738. package/templates/nova/tests/cases/sections/Overview.cases.tsx +8 -0
  739. package/templates/nova/tests/cases/sections/commerce/collection-list/CollectionList.cases.tsx +46 -0
  740. package/templates/nova/tests/cases/sections/commerce/collection-list/blocks/CollectionItem.cases.tsx +18 -0
  741. package/templates/nova/tests/cases/sections/commerce/featured-collection/FeaturedCollection.cases.tsx +46 -0
  742. package/templates/nova/tests/cases/sections/commerce/featured-product/FeaturedProduct.cases.tsx +40 -0
  743. package/templates/nova/tests/cases/sections/commerce/main-collection/MainCollection.cases.tsx +81 -0
  744. package/templates/nova/tests/cases/sections/commerce/product-details/ProductDetails.cases.tsx +110 -0
  745. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/AddToCartBlock.cases.tsx +21 -0
  746. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductDescription.cases.tsx +17 -0
  747. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductInventory.cases.tsx +17 -0
  748. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductPrice.cases.tsx +17 -0
  749. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductSku.cases.tsx +17 -0
  750. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/ProductTitle.cases.tsx +17 -0
  751. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/Quantity.cases.tsx +20 -0
  752. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/Tab.cases.tsx +29 -0
  753. package/templates/nova/tests/cases/sections/commerce/product-details/blocks/VariantPickerBlock.cases.tsx +32 -0
  754. package/templates/nova/tests/cases/sections/commerce/product-grid/ProductGrid.cases.tsx +48 -0
  755. package/templates/nova/tests/cases/sections/commerce/product-recommendations/ProductRecommendations.cases.tsx +27 -0
  756. package/templates/nova/tests/cases/sections/commerce/recently-viewed/RecentlyViewed.cases.tsx +36 -0
  757. package/templates/nova/tests/cases/sections/content/article-body/ArticleBody.cases.tsx +32 -0
  758. package/templates/nova/tests/cases/sections/content/before-after/BeforeAfter.cases.tsx +40 -0
  759. package/templates/nova/tests/cases/sections/content/before-after/blocks/Comparison.cases.tsx +17 -0
  760. package/templates/nova/tests/cases/sections/content/blog-posts/BlogPosts.cases.tsx +47 -0
  761. package/templates/nova/tests/cases/sections/content/collection-links/CollectionLinks.cases.tsx +36 -0
  762. package/templates/nova/tests/cases/sections/content/faq/Faq.cases.tsx +38 -0
  763. package/templates/nova/tests/cases/sections/content/faq/blocks/FaqItem.cases.tsx +17 -0
  764. package/templates/nova/tests/cases/sections/content/feature-grid-blocks/FeatureGridBlocks.cases.tsx +31 -0
  765. package/templates/nova/tests/cases/sections/content/feature-highlights/FeatureHighlights.cases.tsx +26 -0
  766. package/templates/nova/tests/cases/sections/content/image-gallery/ImageGallery.cases.tsx +31 -0
  767. package/templates/nova/tests/cases/sections/content/image-with-text/ImageWithText.cases.tsx +35 -0
  768. package/templates/nova/tests/cases/sections/content/multicolumn/Multicolumn.cases.tsx +32 -0
  769. package/templates/nova/tests/cases/sections/content/page-body/PageBody.cases.tsx +31 -0
  770. package/templates/nova/tests/cases/sections/content/rich-text/RichTextSection.cases.tsx +33 -0
  771. package/templates/nova/tests/cases/sections/content/team-founders/TeamFounders.cases.tsx +31 -0
  772. package/templates/nova/tests/cases/sections/content/team-founders/blocks/Person.cases.tsx +18 -0
  773. package/templates/nova/tests/cases/sections/content/timeline/Timeline.cases.tsx +27 -0
  774. package/templates/nova/tests/cases/sections/content/timeline/blocks/Step.cases.tsx +17 -0
  775. package/templates/nova/tests/cases/sections/layout/announcement-bar/AnnouncementBar.cases.tsx +119 -0
  776. package/templates/nova/tests/cases/sections/layout/breadcrumbs/Breadcrumbs.cases.tsx +73 -0
  777. package/templates/nova/tests/cases/sections/layout/divider/Divider.cases.tsx +81 -0
  778. package/templates/nova/tests/cases/sections/layout/footer/Footer.cases.tsx +116 -0
  779. package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterBrand.cases.tsx +27 -0
  780. package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterMenu.cases.tsx +22 -0
  781. package/templates/nova/tests/cases/sections/layout/footer/blocks/FooterText.cases.tsx +20 -0
  782. package/templates/nova/tests/cases/sections/layout/group/Group.cases.tsx +185 -0
  783. package/templates/nova/tests/cases/sections/layout/group/blocks/Accordion.cases.tsx +17 -0
  784. package/templates/nova/tests/cases/sections/layout/group/blocks/JumboText.cases.tsx +17 -0
  785. package/templates/nova/tests/cases/sections/layout/group/blocks/Spacer.cases.tsx +33 -0
  786. package/templates/nova/tests/cases/sections/layout/header/Header.cases.tsx +277 -0
  787. package/templates/nova/tests/cases/sections/marketing/collection-banner/CollectionBanner.cases.tsx +62 -0
  788. package/templates/nova/tests/cases/sections/marketing/hero/Hero.cases.tsx +138 -0
  789. package/templates/nova/tests/cases/sections/marketing/marquee/Marquee.cases.tsx +63 -0
  790. package/templates/nova/tests/cases/sections/marketing/promo-banner/PromoBanner.cases.tsx +87 -0
  791. package/templates/nova/tests/cases/sections/marketing/slideshow/Slideshow.cases.tsx +113 -0
  792. package/templates/nova/tests/cases/sections/marketing/slideshow/blocks/Slide.cases.tsx +26 -0
  793. package/templates/nova/tests/cases/sections/marketing/video-hero/VideoHero.cases.tsx +72 -0
  794. package/templates/nova/tests/cases/sections/trust/comparison-table/ComparisonTableSection.cases.tsx +42 -0
  795. package/templates/nova/tests/cases/sections/trust/comparison-table/blocks/CompareItem.cases.tsx +17 -0
  796. package/templates/nova/tests/cases/sections/trust/logo-list/LogoList.cases.tsx +29 -0
  797. package/templates/nova/tests/cases/sections/trust/logo-list/blocks/Logo.cases.tsx +17 -0
  798. package/templates/nova/tests/cases/sections/trust/product-reviews/ProductReviews.cases.tsx +51 -0
  799. package/templates/nova/tests/cases/sections/trust/shop-the-look/ShopTheLook.cases.tsx +51 -0
  800. package/templates/nova/tests/cases/sections/trust/shop-the-look/blocks/Hotspot.cases.tsx +17 -0
  801. package/templates/nova/tests/cases/sections/trust/testimonials/Testimonials.cases.tsx +61 -0
  802. package/templates/nova/tests/cases/sections/trust/testimonials/blocks/Testimonial.cases.tsx +17 -0
  803. package/templates/nova/tests/cases/sections/trust/trust-badges/TrustBadges.cases.tsx +30 -0
  804. package/templates/nova/tests/cases/sections/trust/ugc-gallery/UgcGallery.cases.tsx +32 -0
  805. package/templates/nova/tests/cases/sections/trust/ugc-gallery/blocks/UgcImage.cases.tsx +17 -0
  806. package/templates/nova/tests/cases/sections/utility/account/Account.cases.tsx +44 -0
  807. package/templates/nova/tests/cases/sections/utility/cart-items/CartItems.cases.tsx +43 -0
  808. package/templates/nova/tests/cases/sections/utility/cart-items/blocks/CartBadge.cases.tsx +16 -0
  809. package/templates/nova/tests/cases/sections/utility/contact-form/ContactFormSection.cases.tsx +52 -0
  810. package/templates/nova/tests/cases/sections/utility/contact-form/blocks/ContactDetail.cases.tsx +17 -0
  811. package/templates/nova/tests/cases/sections/utility/newsletter/NewsletterSection.cases.tsx +109 -0
  812. package/templates/nova/tests/cases/sections/utility/not-found/NotFound.cases.tsx +28 -0
  813. package/templates/nova/tests/cases/sections/utility/policy-page/PolicyPage.cases.tsx +29 -0
  814. package/templates/nova/tests/cases/sections/utility/search-results/SearchResultsSection.cases.tsx +39 -0
  815. package/templates/nova/tests/cases/sections/utility/store-locator/StoreLocator.cases.tsx +40 -0
  816. package/templates/nova/tests/cases/styles/Borders.cases.tsx +10 -0
  817. package/templates/nova/tests/cases/styles/Breakpoints.cases.tsx +10 -0
  818. package/templates/nova/tests/cases/styles/Colors.cases.tsx +10 -0
  819. package/templates/nova/tests/cases/styles/Elevation.cases.tsx +10 -0
  820. package/templates/nova/tests/cases/styles/Icon.cases.tsx +23 -0
  821. package/templates/nova/tests/cases/styles/Layout.cases.tsx +8 -0
  822. package/templates/nova/tests/cases/styles/Motion.cases.tsx +10 -0
  823. package/templates/nova/tests/cases/styles/Overview.cases.tsx +8 -0
  824. package/templates/nova/tests/cases/styles/Radius.cases.tsx +10 -0
  825. package/templates/nova/tests/cases/styles/SharedThemeSettings.cases.tsx +19 -0
  826. package/templates/nova/tests/cases/styles/Spacing.cases.tsx +10 -0
  827. package/templates/nova/tests/cases/styles/Typography.cases.tsx +10 -0
  828. package/templates/nova/tests/cases.test.tsx +38 -0
  829. package/templates/nova/tests/components/PromoPopup.test.ts +21 -0
  830. package/templates/nova/tests/components/RichText.test.tsx +65 -0
  831. package/templates/nova/tests/components/formatDate.test.ts +10 -0
  832. package/templates/nova/tests/contract-locks.test.ts +23 -0
  833. package/templates/nova/tests/contracts.test.ts +153 -0
  834. package/templates/nova/tests/cookie-consent-privacy.test.tsx +128 -0
  835. package/templates/nova/tests/empty-store.test.tsx +81 -0
  836. package/templates/nova/tests/fixtures/commerce.ts +128 -0
  837. package/templates/nova/tests/fixtures/content.ts +58 -0
  838. package/templates/nova/tests/fixtures/index.ts +8 -0
  839. package/templates/nova/tests/fixtures/merch.ts +161 -0
  840. package/templates/nova/tests/fixtures/navigation.ts +125 -0
  841. package/templates/nova/tests/fixtures/promotion.ts +43 -0
  842. package/templates/nova/tests/fixtures/sample-store.json +1674 -0
  843. package/templates/nova/tests/fixtures/shop.ts +88 -0
  844. package/templates/nova/tests/fixtures/stress.ts +21 -0
  845. package/templates/nova/tests/inert.test.tsx +285 -0
  846. package/templates/nova/tests/line-add-friend.test.tsx +108 -0
  847. package/templates/nova/tests/localized-copy.test.ts +330 -0
  848. package/templates/nova/tests/product-template-blocks.test.ts +28 -0
  849. package/templates/nova/tests/rewards-launcher.test.tsx +401 -0
  850. package/templates/nova/tests/schema.test.ts +65 -0
  851. package/templates/nova/tests/schema.typetest.ts +7 -0
  852. package/templates/nova/tests/section-groups.test.ts +189 -0
  853. package/templates/nova/tests/sections/Group.test.tsx +37 -0
  854. package/templates/nova/tests/setup.ts +30 -0
  855. package/templates/nova/tests/starter.test.ts +56 -0
  856. package/templates/nova/tests/storefront-click-path.test.tsx +157 -0
  857. package/templates/nova/tests/styles/button-brand.test.ts +24 -0
  858. package/templates/nova/tests/styles/theme.test.ts +43 -0
  859. package/templates/nova/tests/styles/tokens.test.ts +35 -0
  860. package/templates/nova/tests/support/abi-ctx.ts +136 -0
  861. package/templates/nova/tests/support/block-stories.tsx +13 -0
  862. package/templates/nova/tests/support/case.tsx +102 -0
  863. package/templates/nova/tests/support/contracts.ts +30 -0
  864. package/templates/nova/tests/support/foundation-pages.tsx +260 -0
  865. package/templates/nova/tests/support/ia-pages.tsx +154 -0
  866. package/templates/nova/tests/support/listing-demo.tsx +29 -0
  867. package/templates/nova/tests/support/presets.ts +14 -0
  868. package/templates/nova/tests/support/sections.ts +36 -0
  869. package/templates/nova/tests/support/story-content.ts +321 -0
  870. package/templates/nova/tests/support/story-helpers.tsx +37 -0
  871. package/templates/nova/tests/support/with-nova.tsx +26 -0
  872. package/templates/nova/tests/theme-config.test.ts +82 -0
  873. package/templates/nova/tests/theme-integrity.test.ts +315 -0
  874. package/templates/nova/theme.config.ts +134 -0
  875. package/templates/nova/theme.manifest.json +17495 -0
  876. package/templates/nova/tsconfig.json +19 -0
  877. package/templates/nova/vite.abi-ssr.config.ts +37 -0
  878. package/templates/nova/vite.abi.config.ts +26 -0
  879. package/templates/nova/vitest.config.ts +20 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Nova's presentation mapping, shared by the sections' data bindings: which
3
+ * saved blocks a section shows and in what shape, whether the header sits over
4
+ * a media hero, what "add" means for a product card. WHERE the data comes from
5
+ * is the runtime's (it fills the store context; `@tanqory/theme-sdk`'s
6
+ * imageFor / menuFor / collectionFor / productFor … read it); HOW it is
7
+ * presented is decided here.
8
+ */
9
+ import { NovaImage, NovaMenu, NovaVideo, Product, SavedBlock, SavedSection, SettingIssue, SettingsOf, StoreContext, ThemeActions, imageFor, menuFor, resolveSettings, videoFor } from '@tanqory/theme-kit'
10
+ import { ColumnInstance, columnSchema } from '../components/content/blocks/Column'
11
+ import { imageSchema } from '../components/content/blocks/Image'
12
+ import { footerMenuSchema } from './Footer/blocks/FooterMenu'
13
+ import { heroSchema } from './Hero/schema'
14
+ import { slideSchema } from './Slideshow/blocks/Slide'
15
+ import { videoHeroSchema } from './VideoHero/schema'
16
+ import type { accordionSchema } from './Group/blocks/Accordion'
17
+ import type { buttonSchema } from '../components/content/blocks/Button'
18
+ import type { footerBrandSchema } from './Footer/blocks/FooterBrand'
19
+ import type { footerTextSchema } from './Footer/blocks/FooterText'
20
+ import type { footerLineSchema } from './Footer/blocks/FooterLine'
21
+ import type { headingSchema } from '../components/content/blocks/Heading'
22
+ import type { iconSchema } from '../components/content/blocks/Icon'
23
+ import type { jumboTextSchema } from './Group/blocks/JumboText'
24
+ import { NEWSLETTER_BLOCK, newsletterBlockSchema } from '../components/forms/blocks/Newsletter'
25
+ import type { paymentIconsSchema } from '../components/commerce/blocks/PaymentIcons'
26
+ import type { socialLinksSchema } from '../components/navigation/blocks/SocialLinks'
27
+ import type { spacerSchema } from './Group/blocks/Spacer'
28
+ import type { textSchema } from '../components/content/blocks/Text'
29
+ import type { videoSchema } from '../components/content/blocks/Video'
30
+
31
+ export const blocksOf = (node: SavedSection, type: string) => (node.blocks ?? []).filter((b) => b.type === type)
32
+
33
+ /**
34
+ * 12A header transparentOnHero needs to know whether the page opens with a
35
+ * hero-type section that has media (hero image layouts, slideshow, video-hero).
36
+ */
37
+ export function isHeroWithMedia(node: SavedSection | undefined, ctx: StoreContext): boolean {
38
+ if (!node) return false
39
+ if (node.type === 'hero') {
40
+ const r = resolveSettings(heroSchema, node.settings)
41
+ return (r.settings.layout === 'image-background' || r.settings.layout === 'contained') && Boolean(imageFor(ctx, r.handles.backgroundImage) || videoFor(ctx, r.handles.video))
42
+ }
43
+ if (node.type === 'slideshow') return (node.blocks ?? []).some((b) => b.type === 'slide' && Boolean(imageFor(ctx, resolveSettings(slideSchema, b.settings).handles.image)))
44
+ if (node.type === 'video-hero') {
45
+ const r = resolveSettings(videoHeroSchema, node.settings)
46
+ return Boolean(r.settings.videoUrl || imageFor(ctx, r.handles.poster))
47
+ }
48
+ return false
49
+ }
50
+
51
+ export function columnsOf(ctx: StoreContext, saved: SavedBlock[] | undefined, issues: SettingIssue[]): ColumnInstance[] {
52
+ return (saved ?? []).filter((b) => b.type === 'column').map((b) => {
53
+ const r = resolveSettings(columnSchema, b.settings)
54
+ issues.push(...r.issues)
55
+ return { settings: r.settings, image: imageFor(ctx, r.handles.image), video: videoFor(ctx, r.handles.video) }
56
+ })
57
+ }
58
+
59
+ /**
60
+ * A placed block, as a section receives it: the block type, its (partial,
61
+ * saved) settings and any resolved data the adapter attached.
62
+ */
63
+ export type BlockInstance =
64
+ | { type: 'heading'; settings?: Partial<SettingsOf<typeof headingSchema>> }
65
+ | { type: 'text'; settings?: Partial<SettingsOf<typeof textSchema>> }
66
+ | { type: 'button'; settings?: Partial<SettingsOf<typeof buttonSchema>> }
67
+ | { type: 'image'; settings?: Partial<SettingsOf<typeof imageSchema>>; image?: NovaImage | null }
68
+ | { type: 'icon'; settings?: Partial<SettingsOf<typeof iconSchema>> }
69
+ | { type: 'spacer'; settings?: Partial<SettingsOf<typeof spacerSchema>> }
70
+ | { type: 'video'; settings?: Partial<SettingsOf<typeof videoSchema>>; video?: NovaVideo | null }
71
+ | { type: 'jumbo-text'; settings?: Partial<SettingsOf<typeof jumboTextSchema>> }
72
+ | { type: 'accordion'; settings?: Partial<SettingsOf<typeof accordionSchema>> }
73
+ | { type: 'footer-brand'; settings?: Partial<SettingsOf<typeof footerBrandSchema>> }
74
+ | { type: 'footer-menu'; settings?: Partial<Pick<SettingsOf<typeof footerMenuSchema>, 'heading'>>; menu?: NovaMenu | null }
75
+ | { type: 'footer-text'; settings?: Partial<SettingsOf<typeof footerTextSchema>> }
76
+ | { type: 'social-links'; settings?: Partial<SettingsOf<typeof socialLinksSchema>> }
77
+ | { type: 'payment-icons'; settings?: Partial<SettingsOf<typeof paymentIconsSchema>> }
78
+ | { type: 'newsletter-signup'; settings?: Partial<SettingsOf<typeof newsletterBlockSchema>>; endpoint?: string; formResult?: StoreContext['formResult'] }
79
+ | { type: 'footer-line'; settings?: Partial<SettingsOf<typeof footerLineSchema>> }
80
+
81
+ export function adaptBlocks(ctx: StoreContext, saved: SavedBlock[] | undefined, issues: SettingIssue[]): BlockInstance[] {
82
+ return (saved ?? []).map((b) => {
83
+ if (b.type === 'image') {
84
+ const r = resolveSettings(imageSchema, b.settings)
85
+ issues.push(...r.issues)
86
+ return { type: 'image', settings: r.settings, image: ctx.images?.[r.handles.image] ?? null }
87
+ }
88
+ if (b.type === 'footer-menu') {
89
+ const r = resolveSettings(footerMenuSchema, b.settings)
90
+ issues.push(...r.issues)
91
+ const m = menuFor(ctx, r.handles.menu)
92
+ // No saved heading → the menu's own name (what stores saved against), then the default.
93
+ const saved = typeof b.settings?.heading === 'string' ? b.settings.heading.trim() : ''
94
+ return { type: 'footer-menu', settings: { heading: saved || m?.title || r.settings.heading }, menu: m }
95
+ }
96
+ if (b.type === 'video') {
97
+ const video = typeof b.settings?.url === 'string' ? ctx.videos?.[b.settings.url] : undefined
98
+ return { type: 'video', settings: b.settings as never, video: video ?? null }
99
+ }
100
+ if (b.type === NEWSLETTER_BLOCK || newsletterBlockSchema.legacyNames?.includes(b.type)) {
101
+ // The platform's native form endpoint, as the Newsletter section gets it: zero setup in a footer or group.
102
+ // A block saved under its old name (`newsletter`) is the same block (alias on read).
103
+ return { type: NEWSLETTER_BLOCK, settings: b.settings as never, ...(ctx.newsletterEndpoint ? { endpoint: ctx.newsletterEndpoint } : {}), ...(ctx.formResult ? { formResult: ctx.formResult } : {}) }
104
+ }
105
+ // Other blocks carry only settings; the section resolves their defaults.
106
+ return { type: b.type, settings: b.settings } as BlockInstance
107
+ })
108
+ }
109
+
110
+
111
+ /** Add a product to the cart: its first available variant, else its first. */
112
+ export function addProduct(actions: ThemeActions, product: Product): Promise<boolean> | undefined {
113
+ const v = product.variants?.find((x) => x.available) ?? product.variants?.[0]
114
+ return v ? actions.cart.add(v.id, 1) : undefined
115
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shipped copy the runtime must NOT localize or fill in (theme `shippedCopy`,
3
+ * @tanqory/theme-kit runtime/render/localized-copy.ts). Each entry names the renderer
4
+ * that depends on it; `tests/localized-copy.test.ts` scans the theme for new
5
+ * cases and fails when one is not listed here.
6
+ */
7
+
8
+ /**
9
+ * The renderer compares the value with the shipped English, so a translated
10
+ * value would read as the merchant's own:
11
+ * - footer-brand.title: `title !== 'Your store'` — the default title is not an
12
+ * override; the brand logo / store name shows instead (FooterBrand.tsx).
13
+ * - footer-brand.tagline: `=== TAGLINE_STARTER` — an editor-only placeholder,
14
+ * never shown to shoppers (FooterBrand.tsx).
15
+ * - testimonial.quote: `=== TESTIMONIAL_STARTER` — the editor's starter state
16
+ * (Testimonials.tsx); the live store drops it as starter text.
17
+ */
18
+ export const KEEP_SHIPPED_COPY = ['block:footer-brand.title', 'block:footer-brand.tagline', 'block:testimonial.quote'] as const
19
+
20
+ /**
21
+ * An unset value is derived from data, so the default must not be filled in:
22
+ * - footer-menu.heading: no saved heading → the menu's own name
23
+ * (sections/data.ts adaptBlocks). A saved heading is still localized.
24
+ */
25
+ export const DERIVED_WHEN_UNSET = ['block:footer-menu.heading'] as const
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Starter text: what the starter templates, presets and setting defaults say
3
+ * in place of content, to tell a merchant what to write.
4
+ *
5
+ * The editor shows it as it is. On the live storefront the runtime renders no
6
+ * section whose own settings still hold one of these, and leaves out any block
7
+ * that does (theme `starterText`) — so a store that opens before it is set up
8
+ * shows less, never an instruction or a review nobody wrote.
9
+ *
10
+ * Exact strings, compared trimmed. `tests/starter.test.ts` fails when a
11
+ * template or default carries instruction-like text that is not listed here,
12
+ * so the list and the templates cannot drift apart.
13
+ */
14
+ import { TESTIMONIAL_STARTER } from './Testimonials/blocks/Testimonial'
15
+
16
+ export const STARTER_TEXT: readonly string[] = [
17
+ // Home
18
+ 'Introduce your store in a sentence or two — what you make, and who it is for.',
19
+ 'Tell customers how your products are made, and by whom.',
20
+ TESTIMONIAL_STARTER,
21
+ 'Customer name',
22
+ 'City',
23
+ 'Delivery | Describe how and when you ship.\nReturns | Describe your returns window.\nCare | Describe how to look after a piece.\nPayment | List the ways customers can pay.',
24
+ // About
25
+ 'Tell the story of your store',
26
+ 'Describe the place and the process.',
27
+ 'Introduce the people who make or choose what you sell.',
28
+ '<p>A paragraph or two on what you make, where, and why it matters to you.</p>',
29
+ 'Milestone 1',
30
+ 'Milestone 2',
31
+ 'Milestone 3',
32
+ 'Milestone 4',
33
+ 'A line about this moment in your story.',
34
+ // Contact
35
+ 'Add a question customers often ask',
36
+ 'Add another question',
37
+ '<p>Answer it here, in your own words.</p>',
38
+ // Bundle product
39
+ 'Item 1',
40
+ 'Item 2',
41
+ 'Item 3',
42
+ 'Describe this piece of the set.',
43
+ // Featured collection, blog
44
+ '<p>Say why these pieces belong together.</p>',
45
+ 'Tell readers what you will send them, and how often.',
46
+ // Setting defaults
47
+ 'Tell your story here…',
48
+ 'Describe this step.',
49
+ ]
@@ -0,0 +1,6 @@
1
+ .nv-container { width: 100%; margin-inline: auto; padding-inline: var(--page-gutter); }
2
+ .nv-container[data-width='narrow'] { max-width: calc(var(--container-narrow) + 2 * var(--page-gutter)); }
3
+ .nv-container[data-width='content'] { max-width: calc(var(--container-content) + 2 * var(--page-gutter)); }
4
+ .nv-container[data-width='standard'] { max-width: calc(var(--container-standard) + 2 * var(--page-gutter)); }
5
+ .nv-container[data-width='wide'] { max-width: calc(var(--container-wide) + 2 * var(--page-gutter)); }
6
+ .nv-container[data-width='full'] { max-width: none; }
@@ -0,0 +1,13 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react'
2
+ import './Container.css'
3
+
4
+ /** Nova 02 · Container — narrow 640 · content 960 · standard 1280 · wide 1536 · full; page gutter 16 / 24 / 40. */
5
+ export type ContainerWidth = 'narrow' | 'content' | 'standard' | 'wide' | 'full'
6
+
7
+ export function Container({ width = 'standard', children, className, ...rest }: { width?: ContainerWidth; children: ReactNode } & HTMLAttributes<HTMLDivElement>): JSX.Element {
8
+ return (
9
+ <div className={['nv-container', className].filter(Boolean).join(' ')} data-width={width} {...rest}>
10
+ {children}
11
+ </div>
12
+ )
13
+ }
@@ -0,0 +1,2 @@
1
+ .nv-icon { flex: none; stroke-width: var(--icon-stroke); }
2
+ .nv-icon[data-icon='play'] { fill: currentColor; }
@@ -0,0 +1,101 @@
1
+ import type { ReactNode } from 'react'
2
+ import './Icon.css'
3
+
4
+ /**
5
+ * Nova 02 · Icon — 24px grid, 1.6 stroke (2.0 under iconStyle filled), round
6
+ * caps. Sizes sm 16 · md 20 · lg 24. Decorative by default (aria-hidden);
7
+ * pass `label` for a meaningful standalone icon. Directional icons mirror in RTL.
8
+ */
9
+ const PATHS: Record<string, ReactNode> = {
10
+ // Nova 02 set
11
+ search: <path d="M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-4-4" />,
12
+ bag: <path d="M5 8h14l-1 12H6L5 8zM9 8V6a3 3 0 0 1 6 0v2" />,
13
+ user: <path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM4 21c1-4 4-6 8-6s7 2 8 6" />,
14
+ menu: <path d="M4 8h16M4 16h16" />,
15
+ close: <path d="M6 6l12 12M18 6L6 18" />,
16
+ 'chevron-right': <path d="M9 6l6 6-6 6" />,
17
+ 'chevron-left': <path d="M15 6l-6 6 6 6" />,
18
+ 'chevron-down': <path d="M6 9l6 6 6-6" />,
19
+ 'chevron-up': <path d="M6 15l6-6 6 6" />,
20
+ plus: <path d="M12 5v14M5 12h14" />,
21
+ minus: <path d="M5 12h14" />,
22
+ check: <path d="M5 12l5 5 9-10" />,
23
+ heart: <path d="M12 21s-7-4.5-7-10a4 4 0 0 1 7-2.5A4 4 0 0 1 19 11c0 5.5-7 10-7 10z" />,
24
+ truck: <path d="M3 7h11v9H3zM14 10h4l3 3v3h-7" />,
25
+ return: <path d="M4 12a8 8 0 1 0 3-6.2M4 4v4h4" />,
26
+ shield: <path d="M12 3l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V6l7-3z" />,
27
+ mail: <path d="M4 6h16v12H4zM4 7l8 6 8-6" />,
28
+ globe: <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zM2 12h20M12 2c3 3 3 17 0 20M12 2c-3 3-3 17 0 20" />,
29
+ // icon block options (12D)
30
+ chat: <path d="M21 11.5a7.5 7.5 0 0 1-11 6.6L4 19.5l1.4-4.3A7.5 7.5 0 1 1 21 11.5z" />,
31
+ star: <path d="M12 3.5 14.6 9l6 .6-4.5 4 1.4 5.9L12 16.4 6.5 19.5 7.9 13.6 3.4 9.6l6-.6z" />,
32
+ gift: <path d="M4 9h16v11H4zM4 13h16M12 9v11M8.5 9a2.2 2.2 0 1 1 3.5-1.8M15.5 9a2.2 2.2 0 1 0-3.5-1.8" />,
33
+ leaf: <path d="M5 19c0-8 6-13 14-13 0 9-5 14-13 14a8 8 0 0 1 5-7" />,
34
+ clock: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM12 7v5l3.5 2" />,
35
+ card: <path d="M3 6.5h18v11H3zM3 10h18M6.5 14.5h4" />,
36
+ filter: <path d="M4 7h10M18 7h2M4 17h4M12 17h8M16 5v4M10 15v4" />,
37
+ zoom: <path d="M10.5 4a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13zM15.2 15.2 20 20M10.5 8v5M8 10.5h5" />,
38
+ link: <path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1" />,
39
+ share: <path d="M12 3.5v12M7.5 8 12 3.5 16.5 8M5 12.5v7h14v-7" />,
40
+ drop: <path d="M12 3s6 6.5 6 11a6 6 0 0 1-12 0c0-4.5 6-11 6-11z" />,
41
+ // utility
42
+ 'arrow-right': <path d="M5 12h14M13 6l6 6-6 6" />,
43
+ 'arrow-up-right': <path d="M7 17 17 7M8 7h9v9" />,
44
+ pause: <path d="M9 6v12M15 6v12" />,
45
+ play: <path d="M8 5v14l11-7z" />,
46
+ image: <path d="M4 5h16v14H4zM4 16l5-5 4 4 3-3 4 4M15 9.5a1.5 1.5 0 1 0 0-.01" />,
47
+ alert: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM12 8v5M12 16v.01" />,
48
+ info: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM12 11v5M12 8v.01" />,
49
+ // social (simplified marks)
50
+ instagram: <path d="M8.5 4h7A4.5 4.5 0 0 1 20 8.5v7a4.5 4.5 0 0 1-4.5 4.5h-7A4.5 4.5 0 0 1 4 15.5v-7A4.5 4.5 0 0 1 8.5 4zM12 8.4a3.6 3.6 0 1 0 0 7.2 3.6 3.6 0 0 0 0-7.2zM17 7v.01" />,
51
+ facebook: <path d="M14.5 8.5H16V5.6h-1.9c-1.9 0-3.1 1.2-3.1 3.1v1.8H9v2.9h2v6.1h3v-6.1h2.1l.5-2.9H14v-1.4c0-.4.2-.6.5-.6z" />,
52
+ x: <path d="M5 5l14 14M19 5 5 19" />,
53
+ tiktok: <path d="M13.5 5v9.2a3.3 3.3 0 1 1-2.4-3.18M13.5 5c.4 1.9 1.9 3.2 3.9 3.4" />,
54
+ youtube: <path d="M6.2 6.5h11.6A3.2 3.2 0 0 1 21 9.7v4.6a3.2 3.2 0 0 1-3.2 3.2H6.2A3.2 3.2 0 0 1 3 14.3V9.7a3.2 3.2 0 0 1 3.2-3.2zM11 9.8l4 2.2-4 2.2z" />,
55
+ // Nova 13 · feedback: every status carries an icon and a word (colour is a third signal).
56
+ warning: <path d="M12 4 21.5 20h-19L12 4zM12 10v4.5M12 17.2v.01" />,
57
+ error: <path d="M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17zM9.2 9.2l5.6 5.6M14.8 9.2l-5.6 5.6" />,
58
+ trash: <path d="M5 7h14M10 7V5h4v2M7 7l1 12h8l1-12M10.5 10.5v5M13.5 10.5v5" />,
59
+ wifi: <path d="M3.5 9.5a12 12 0 0 1 17 0M6.5 12.8a7.5 7.5 0 0 1 11 0M9.5 16a3.2 3.2 0 0 1 5 0M12 19v.01" />,
60
+ }
61
+
62
+ /** Icons that point somewhere and so mirror under RTL. */
63
+ const DIRECTIONAL = new Set(['chevron-right', 'chevron-left', 'arrow-right', 'arrow-up-right', 'return'])
64
+
65
+ export const ICON_NAMES = Object.keys(PATHS) as IconName[]
66
+ export type IconName = keyof typeof PATHS & string
67
+
68
+ export type IconSize = 'sm' | 'md' | 'lg' | number
69
+
70
+ export interface IconProps {
71
+ name: IconName
72
+ size?: IconSize
73
+ /** Accessible name. Omit for decorative icons (the default). */
74
+ label?: string
75
+ className?: string
76
+ }
77
+
78
+ const PX: Record<string, number> = { sm: 16, md: 20, lg: 24 }
79
+
80
+ export function Icon({ name, size = 'md', label, className }: IconProps): JSX.Element {
81
+ const px = typeof size === 'number' ? size : PX[size]
82
+ return (
83
+ <svg
84
+ className={['nv-icon', DIRECTIONAL.has(name) ? 'nv-dir' : '', className].filter(Boolean).join(' ')}
85
+ width={px}
86
+ height={px}
87
+ viewBox="0 0 24 24"
88
+ fill="none"
89
+ stroke="currentColor"
90
+ strokeLinecap="round"
91
+ strokeLinejoin="round"
92
+ data-icon={name}
93
+ role={label ? 'img' : undefined}
94
+ aria-label={label}
95
+ aria-hidden={label ? undefined : true}
96
+ focusable="false"
97
+ >
98
+ {PATHS[name]}
99
+ </svg>
100
+ )
101
+ }
@@ -0,0 +1,91 @@
1
+ import { sx, sxJoin } from '@tanqory/theme-kit'
2
+ import { createContext, useContext, useMemo, type CSSProperties, type ReactNode } from 'react'
3
+ import { resolveTheme, type NovaThemeSettings } from './theme'
4
+ import { BUILTIN_STRINGS, STRINGS_EN, type NovaStrings } from './strings'
5
+ import './index.css'
6
+
7
+ /**
8
+ * Where a component is rendering:
9
+ * storefront — a shopper's page: an empty section renders nothing.
10
+ * editor — the Studio canvas: an empty section renders its setup frame
11
+ * (Nova 14 · Editor states) so the merchant can fill it.
12
+ */
13
+ export type NovaMode = 'storefront' | 'editor'
14
+
15
+ export interface NovaContextValue {
16
+ readonly mode: NovaMode
17
+ readonly locale: string
18
+ readonly dir: 'ltr' | 'rtl'
19
+ readonly strings: NovaStrings
20
+ /** Current year, injectable so a copyright line is deterministic in tests. */
21
+ readonly year: number
22
+ }
23
+
24
+ const NovaContext = createContext<NovaContextValue>({
25
+ mode: 'storefront',
26
+ locale: 'en',
27
+ dir: 'ltr',
28
+ strings: STRINGS_EN,
29
+ year: 2026,
30
+ })
31
+
32
+ export function useNova(): NovaContextValue {
33
+ return useContext(NovaContext)
34
+ }
35
+
36
+ export interface NovaProviderProps {
37
+ mode?: NovaMode
38
+ /** BCP 47 language tag; drives `lang` and the built-in string set. */
39
+ locale?: string
40
+ /**
41
+ * The language the page's CONTENT is in (the store's, `ctx.locale.language`), when it differs from
42
+ * the interface strings' `locale` — a store language Nova ships no strings for falls back to
43
+ * English strings, but its merchant copy is still in its own language. Drives `lang` only.
44
+ */
45
+ lang?: string
46
+ dir?: 'ltr' | 'rtl'
47
+ /** Overrides for the system strings (a storefront passes its locale file). */
48
+ strings?: Partial<NovaStrings>
49
+ /** Global theme settings (Level 1). Defaults write nothing. */
50
+ theme?: NovaThemeSettings
51
+ year?: number
52
+ className?: string
53
+ children: ReactNode
54
+ }
55
+
56
+ /**
57
+ * The scope every Nova tree renders inside: tokens + base styles, theme
58
+ * settings as CSS variables on this element, `lang` / `dir`, and the context
59
+ * components read their mode and strings from. Presentational: no data.
60
+ */
61
+ export function NovaProvider({ mode = 'storefront', locale = 'en', lang, dir, strings, theme, year = 2026, className, children }: NovaProviderProps): JSX.Element {
62
+ const base = BUILTIN_STRINGS[locale.split('-')[0]] ?? STRINGS_EN
63
+ const resolvedDir = dir ?? (/^(ar|he|fa|ur)\b/.test(locale) ? 'rtl' : 'ltr')
64
+ const value = useMemo<NovaContextValue>(
65
+ () => ({ mode, locale, dir: resolvedDir, strings: { ...base, ...strings }, year }),
66
+ [mode, locale, resolvedDir, base, strings, year],
67
+ )
68
+ const { vars, attrs } = useMemo(() => resolveTheme(theme), [theme])
69
+ return (
70
+ <NovaContext.Provider value={value}>
71
+ <div
72
+ className={sxJoin(['nv-root', className].filter(Boolean).join(' '), sx(vars as CSSProperties))}
73
+ lang={lang || locale}
74
+ dir={resolvedDir}
75
+ data-mode={mode}
76
+ {...attrs}
77
+ >
78
+ {children}
79
+ </div>
80
+ </NovaContext.Provider>
81
+ )
82
+ }
83
+
84
+ /** The theme's root for the platform (ThemeDefinition.Provider): Nova's provider, fed the store's settings. */
85
+ export function ThemeRoot({ mode, locale, contentLanguage, settings, children }: { mode: NovaMode; locale: string; contentLanguage?: string; settings: Readonly<Record<string, unknown>>; children: ReactNode }): JSX.Element {
86
+ return (
87
+ <NovaProvider mode={mode} locale={locale} lang={contentLanguage} theme={settings as NovaThemeSettings}>
88
+ {children}
89
+ </NovaProvider>
90
+ )
91
+ }
@@ -0,0 +1,142 @@
1
+ /* ============================================================================
2
+ * Nova base — reset, type roles, focus, long scripts, RTL.
3
+ *
4
+ * Scoped to `.nv-root` (the NovaProvider element) plus the document
5
+ * defaults every storefront needs, so the lab can host Nova inside any page
6
+ * without leaking a reset into it. Values are tokens only.
7
+ * ============================================================================ */
8
+
9
+ /* The storefront document: the page runs edge to edge (the browser's default
10
+ 8px body margin framed every page in white). */
11
+ html,
12
+ body { margin: 0; padding: 0; }
13
+
14
+ .nv-root,
15
+ .nv-root *,
16
+ .nv-root *::before,
17
+ .nv-root *::after {
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ .nv-root {
22
+ font-family: var(--font-body);
23
+ font-size: var(--type-body);
24
+ line-height: var(--leading-base);
25
+ color: var(--color-fg);
26
+ background: var(--color-bg);
27
+ -webkit-font-smoothing: antialiased;
28
+ -moz-osx-font-smoothing: grayscale;
29
+ text-rendering: optimizeLegibility;
30
+ font-feature-settings: 'kern' 1, 'liga' 1, 'calt' 1;
31
+ }
32
+
33
+ .nv-root :where(h1, h2, h3, h4, h5, h6, p, ul, ol, figure, blockquote, dl, dd) {
34
+ margin: 0;
35
+ padding: 0;
36
+ }
37
+ .nv-root :where(ul, ol) { list-style: none; }
38
+ .nv-root :where(img, picture, video, canvas, svg) { display: block; max-width: 100%; }
39
+ .nv-root :where(input, button, textarea, select) { font: inherit; color: inherit; }
40
+ .nv-root :where(button) { background: none; border: 0; padding: 0; cursor: pointer; }
41
+ .nv-root :where(a) { color: inherit; text-decoration: none; }
42
+
43
+ /* Inline links are ALWAYS underlined (02 · Link): inside running copy the
44
+ underline is the only thing that says "link". */
45
+ .nv-root :where(p a, .nv-prose a) {
46
+ text-decoration: underline;
47
+ text-underline-offset: var(--underline-offset);
48
+ text-decoration-thickness: var(--border-width);
49
+ transition: text-decoration-thickness var(--duration-fast) var(--ease-standard);
50
+ }
51
+ .nv-root :where(p a, .nv-prose a):hover { text-decoration-thickness: 2px; }
52
+
53
+ /* Heading roles — the ladder is in tokens.css; weight is the global
54
+ headingWeight setting; h6 is always one step heavier (01 typeRules). */
55
+ .nv-root :where(h1, h2, h3, h4, h5, h6, .nv-h1, .nv-h2, .nv-h3, .nv-h4, .nv-display) {
56
+ font-family: var(--font-display);
57
+ font-weight: var(--weight-heading);
58
+ color: inherit;
59
+ text-wrap: balance;
60
+ }
61
+ .nv-root :where(.nv-display) { font-size: var(--type-display); line-height: var(--leading-display); letter-spacing: var(--tracking-display); }
62
+ .nv-root :where(.nv-h1) { font-size: var(--type-h1); line-height: var(--leading-h1); letter-spacing: var(--tracking-h1); }
63
+ .nv-root :where(.nv-h2) { font-size: var(--type-h2); line-height: var(--leading-h2); letter-spacing: var(--tracking-h2); }
64
+ .nv-root :where(.nv-h3) { font-size: var(--type-h3); line-height: var(--leading-h3); letter-spacing: var(--tracking-h3); }
65
+ .nv-root :where(.nv-h4) { font-size: var(--type-h4); line-height: var(--leading-h4); }
66
+ .nv-root :where(p) { text-wrap: pretty; }
67
+
68
+ .nv-root :where(.nv-eyebrow) {
69
+ font-size: var(--type-label);
70
+ font-weight: var(--weight-medium);
71
+ line-height: var(--leading-tight);
72
+ color: var(--color-fg-muted);
73
+ }
74
+
75
+ /* Prices, quantities and counts are tabular everywhere. */
76
+ .nv-root :where(.nv-tabular) { font-variant-numeric: tabular-nums; }
77
+
78
+ /* Focus is ALWAYS a 2px ring at 2px offset in the fixed focus blue — never
79
+ the brand, so it cannot vanish into a brand fill. */
80
+ .nv-root :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
81
+ outline: var(--focus-ring-width) solid var(--color-focus);
82
+ outline-offset: var(--focus-ring-offset);
83
+ }
84
+
85
+ .nv-visually-hidden {
86
+ position: absolute !important;
87
+ width: 1px !important;
88
+ height: 1px !important;
89
+ padding: 0 !important;
90
+ margin: -1px !important;
91
+ overflow: hidden !important;
92
+ clip: rect(0 0 0 0) !important;
93
+ white-space: nowrap !important;
94
+ border: 0 !important;
95
+ }
96
+
97
+ /* Directional glyphs mirror in RTL. */
98
+ [dir='rtl'] .nv-dir { transform: scaleX(-1); }
99
+
100
+ /* ── Long scripts (01 typeRules · Round 2 · D17) ───────────────────────────
101
+ Thai: taller line boxes, tracking 0, no uppercase, never split a cluster. */
102
+ .nv-root:lang(th),
103
+ .nv-root :lang(th) { letter-spacing: 0; }
104
+ .nv-root:lang(th) :where(p, li, dd, .nv-prose),
105
+ .nv-root :lang(th) :where(p, li, dd, .nv-prose) { line-height: var(--leading-body-script); }
106
+ .nv-root:lang(th) :where(h1, h2, h3, .nv-display, .nv-h1, .nv-h2, .nv-h3),
107
+ .nv-root :lang(th) :where(h1, h2, h3, .nv-display, .nv-h1, .nv-h2, .nv-h3) { line-height: var(--leading-h4); letter-spacing: 0; }
108
+ .nv-root:lang(th) :where(p, li, h1, h2, h3, h4, h5, h6, .nv-btn),
109
+ .nv-root :lang(th) :where(p, li, h1, h2, h3, h4, h5, h6, .nv-btn) {
110
+ word-break: keep-all;
111
+ overflow-wrap: anywhere;
112
+ line-break: strict;
113
+ text-transform: none;
114
+ }
115
+
116
+ /* RTL: layout mirrors through logical properties; leading 1.7+, tracking 0. */
117
+ .nv-root[dir='rtl'],
118
+ .nv-root [dir='rtl'] { letter-spacing: 0; }
119
+ .nv-root[dir='rtl'] :where(p, li, dd, .nv-prose) { line-height: var(--leading-body-script); }
120
+ .nv-root[dir='rtl'] :where(h1, h2, h3, .nv-display, .nv-h1, .nv-h2, .nv-h3) { line-height: var(--leading-h4); letter-spacing: 0; }
121
+ /* Merchant text keeps its own direction through <bdi> in the markup (the text
122
+ elements that render merchant or store text, and each RichText paragraph),
123
+ so "Halden & Co." keeps its period on an Arabic storefront while the element
124
+ keeps the page direction and alignment. Deliberately not a page-wide
125
+ unicode-bidi rule: that flipped the theme's own strings, prices and counts
126
+ (a bare "١٢", "English غير متاحة…") to LTR. */
127
+
128
+ /* The skip link — first focusable thing on every page (12A header guardrail). */
129
+ .nv-skip-link {
130
+ position: absolute;
131
+ inset-inline-start: var(--space-4);
132
+ top: var(--space-2);
133
+ z-index: var(--z-skip-link);
134
+ padding: var(--space-2) var(--space-4);
135
+ background: var(--color-bg);
136
+ color: var(--color-fg);
137
+ border-radius: var(--radius-md);
138
+ box-shadow: var(--shadow-popover);
139
+ transform: translateY(-200%);
140
+ }
141
+ .nv-skip-link:focus-visible { transform: none; }
142
+ .nv-scroll-lock, .nv-scroll-lock body { overflow: hidden; }
@@ -0,0 +1,6 @@
1
+ /* Blocks carry no outer margins; the parent owns spacing by pair (04C). */
2
+ .nv-block { min-width: 0; margin: 0; }
3
+ .nv-block[data-align='left'] { text-align: start; }
4
+ .nv-block[data-align='center'] { text-align: center; }
5
+ .nv-block[data-align='right'] { text-align: end; }
6
+ .nv-block__eyebrow { margin-bottom: var(--space-2); }
@@ -0,0 +1,93 @@
1
+ Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ https://openfontlicense.org
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.