@doswiftly/cli 0.1.1

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 (453) hide show
  1. package/README.md +357 -0
  2. package/bin/doswiftly.js +2 -0
  3. package/dist/commands/auth-github.d.ts +6 -0
  4. package/dist/commands/auth-github.d.ts.map +1 -0
  5. package/dist/commands/auth-github.js +89 -0
  6. package/dist/commands/auth-github.js.map +1 -0
  7. package/dist/commands/auth-token.d.ts +12 -0
  8. package/dist/commands/auth-token.d.ts.map +1 -0
  9. package/dist/commands/auth-token.js +43 -0
  10. package/dist/commands/auth-token.js.map +1 -0
  11. package/dist/commands/auth.d.ts +22 -0
  12. package/dist/commands/auth.d.ts.map +1 -0
  13. package/dist/commands/auth.js +348 -0
  14. package/dist/commands/auth.js.map +1 -0
  15. package/dist/commands/check.d.ts +5 -0
  16. package/dist/commands/check.d.ts.map +1 -0
  17. package/dist/commands/check.js +234 -0
  18. package/dist/commands/check.js.map +1 -0
  19. package/dist/commands/config.d.ts +3 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +104 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/deploy.d.ts +37 -0
  24. package/dist/commands/deploy.d.ts.map +1 -0
  25. package/dist/commands/deploy.js +580 -0
  26. package/dist/commands/deploy.js.map +1 -0
  27. package/dist/commands/dev.d.ts +8 -0
  28. package/dist/commands/dev.d.ts.map +1 -0
  29. package/dist/commands/dev.js +83 -0
  30. package/dist/commands/dev.js.map +1 -0
  31. package/dist/commands/doctor.d.ts +5 -0
  32. package/dist/commands/doctor.d.ts.map +1 -0
  33. package/dist/commands/doctor.js +363 -0
  34. package/dist/commands/doctor.js.map +1 -0
  35. package/dist/commands/domain.d.ts +13 -0
  36. package/dist/commands/domain.d.ts.map +1 -0
  37. package/dist/commands/domain.js +128 -0
  38. package/dist/commands/domain.js.map +1 -0
  39. package/dist/commands/env.d.ts +25 -0
  40. package/dist/commands/env.d.ts.map +1 -0
  41. package/dist/commands/env.js +228 -0
  42. package/dist/commands/env.js.map +1 -0
  43. package/dist/commands/init.d.ts +11 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +1028 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/inspect.d.ts +12 -0
  48. package/dist/commands/inspect.d.ts.map +1 -0
  49. package/dist/commands/inspect.js +162 -0
  50. package/dist/commands/inspect.js.map +1 -0
  51. package/dist/commands/migrate.d.ts +18 -0
  52. package/dist/commands/migrate.d.ts.map +1 -0
  53. package/dist/commands/migrate.js +355 -0
  54. package/dist/commands/migrate.js.map +1 -0
  55. package/dist/commands/preview.d.ts +29 -0
  56. package/dist/commands/preview.d.ts.map +1 -0
  57. package/dist/commands/preview.js +199 -0
  58. package/dist/commands/preview.js.map +1 -0
  59. package/dist/commands/proxy.d.ts +9 -0
  60. package/dist/commands/proxy.d.ts.map +1 -0
  61. package/dist/commands/proxy.js +37 -0
  62. package/dist/commands/proxy.js.map +1 -0
  63. package/dist/commands/sdk.d.ts +5 -0
  64. package/dist/commands/sdk.d.ts.map +1 -0
  65. package/dist/commands/sdk.js +82 -0
  66. package/dist/commands/sdk.js.map +1 -0
  67. package/dist/commands/template.d.ts +107 -0
  68. package/dist/commands/template.d.ts.map +1 -0
  69. package/dist/commands/template.js +1309 -0
  70. package/dist/commands/template.js.map +1 -0
  71. package/dist/commands/types.d.ts +5 -0
  72. package/dist/commands/types.d.ts.map +1 -0
  73. package/dist/commands/types.js +82 -0
  74. package/dist/commands/types.js.map +1 -0
  75. package/dist/commands/update.d.ts +2 -0
  76. package/dist/commands/update.d.ts.map +1 -0
  77. package/dist/commands/update.js +103 -0
  78. package/dist/commands/update.js.map +1 -0
  79. package/dist/commands/upgrade.d.ts +18 -0
  80. package/dist/commands/upgrade.d.ts.map +1 -0
  81. package/dist/commands/upgrade.js +55 -0
  82. package/dist/commands/upgrade.js.map +1 -0
  83. package/dist/commands/verify.d.ts +5 -0
  84. package/dist/commands/verify.d.ts.map +1 -0
  85. package/dist/commands/verify.js +232 -0
  86. package/dist/commands/verify.js.map +1 -0
  87. package/dist/commands/whoami.d.ts +5 -0
  88. package/dist/commands/whoami.d.ts.map +1 -0
  89. package/dist/commands/whoami.js +60 -0
  90. package/dist/commands/whoami.js.map +1 -0
  91. package/dist/config/types.d.ts +173 -0
  92. package/dist/config/types.d.ts.map +1 -0
  93. package/dist/config/types.js +48 -0
  94. package/dist/config/types.js.map +1 -0
  95. package/dist/index.d.ts +3 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +416 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/lib/api-url.d.ts +14 -0
  100. package/dist/lib/api-url.d.ts.map +1 -0
  101. package/dist/lib/api-url.js +24 -0
  102. package/dist/lib/api-url.js.map +1 -0
  103. package/dist/lib/api.d.ts +67 -0
  104. package/dist/lib/api.d.ts.map +1 -0
  105. package/dist/lib/api.js +36 -0
  106. package/dist/lib/api.js.map +1 -0
  107. package/dist/lib/config.d.ts +39 -0
  108. package/dist/lib/config.d.ts.map +1 -0
  109. package/dist/lib/config.js +195 -0
  110. package/dist/lib/config.js.map +1 -0
  111. package/dist/lib/env-storage.d.ts +140 -0
  112. package/dist/lib/env-storage.d.ts.map +1 -0
  113. package/dist/lib/env-storage.js +464 -0
  114. package/dist/lib/env-storage.js.map +1 -0
  115. package/dist/lib/errors.d.ts +61 -0
  116. package/dist/lib/errors.d.ts.map +1 -0
  117. package/dist/lib/errors.js +204 -0
  118. package/dist/lib/errors.js.map +1 -0
  119. package/dist/lib/i18n.d.ts +99 -0
  120. package/dist/lib/i18n.d.ts.map +1 -0
  121. package/dist/lib/i18n.js +184 -0
  122. package/dist/lib/i18n.js.map +1 -0
  123. package/dist/lib/logger.d.ts +95 -0
  124. package/dist/lib/logger.d.ts.map +1 -0
  125. package/dist/lib/logger.js +168 -0
  126. package/dist/lib/logger.js.map +1 -0
  127. package/dist/lib/package-manager.d.ts +91 -0
  128. package/dist/lib/package-manager.d.ts.map +1 -0
  129. package/dist/lib/package-manager.js +205 -0
  130. package/dist/lib/package-manager.js.map +1 -0
  131. package/dist/lib/proxy-server.d.ts +24 -0
  132. package/dist/lib/proxy-server.d.ts.map +1 -0
  133. package/dist/lib/proxy-server.js +173 -0
  134. package/dist/lib/proxy-server.js.map +1 -0
  135. package/dist/lib/select-with-back.d.ts +34 -0
  136. package/dist/lib/select-with-back.d.ts.map +1 -0
  137. package/dist/lib/select-with-back.js +94 -0
  138. package/dist/lib/select-with-back.js.map +1 -0
  139. package/dist/lib/shared-api-client.d.ts +40 -0
  140. package/dist/lib/shared-api-client.d.ts.map +1 -0
  141. package/dist/lib/shared-api-client.js +92 -0
  142. package/dist/lib/shared-api-client.js.map +1 -0
  143. package/dist/lib/wizard-engine.d.ts +128 -0
  144. package/dist/lib/wizard-engine.d.ts.map +1 -0
  145. package/dist/lib/wizard-engine.js +168 -0
  146. package/dist/lib/wizard-engine.js.map +1 -0
  147. package/package.json +85 -0
  148. package/templates/storefront-minimal/.env.example +10 -0
  149. package/templates/storefront-minimal/.github/workflows/build-template.yml +109 -0
  150. package/templates/storefront-minimal/app/globals.css +18 -0
  151. package/templates/storefront-minimal/app/layout.tsx +26 -0
  152. package/templates/storefront-minimal/app/page.tsx +93 -0
  153. package/templates/storefront-minimal/lib/graphql-client.ts +23 -0
  154. package/templates/storefront-minimal/next.config.ts +15 -0
  155. package/templates/storefront-minimal/open-next.config.ts +3 -0
  156. package/templates/storefront-minimal/package.json +30 -0
  157. package/templates/storefront-minimal/postcss.config.mjs +5 -0
  158. package/templates/storefront-minimal/tailwind.config.ts +14 -0
  159. package/templates/storefront-minimal/tsconfig.json +27 -0
  160. package/templates/storefront-minimal/wrangler.toml +9 -0
  161. package/templates/storefront-nextjs/.env.example +68 -0
  162. package/templates/storefront-nextjs/.github/workflows/build-template.yml +109 -0
  163. package/templates/storefront-nextjs/.github/workflows/deploy.yml +25 -0
  164. package/templates/storefront-nextjs/.github/workflows/preview.yml +22 -0
  165. package/templates/storefront-nextjs/README.md +520 -0
  166. package/templates/storefront-nextjs/app/account/orders/page.tsx +216 -0
  167. package/templates/storefront-nextjs/app/account/page.tsx +167 -0
  168. package/templates/storefront-nextjs/app/auth/login/page.tsx +135 -0
  169. package/templates/storefront-nextjs/app/auth/register/page.tsx +228 -0
  170. package/templates/storefront-nextjs/app/cart/page.tsx +263 -0
  171. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +200 -0
  172. package/templates/storefront-nextjs/app/categories/page.tsx +58 -0
  173. package/templates/storefront-nextjs/app/checkout/page.tsx +351 -0
  174. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +158 -0
  175. package/templates/storefront-nextjs/app/collections/page.tsx +61 -0
  176. package/templates/storefront-nextjs/app/globals.css +98 -0
  177. package/templates/storefront-nextjs/app/layout.tsx +39 -0
  178. package/templates/storefront-nextjs/app/page.tsx +136 -0
  179. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +119 -0
  180. package/templates/storefront-nextjs/app/products/page.tsx +107 -0
  181. package/templates/storefront-nextjs/app/search/page.tsx +127 -0
  182. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +94 -0
  183. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +77 -0
  184. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +29 -0
  185. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +217 -0
  186. package/templates/storefront-nextjs/components/commerce/pagination.tsx +62 -0
  187. package/templates/storefront-nextjs/components/commerce/product-actions.tsx +135 -0
  188. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +109 -0
  189. package/templates/storefront-nextjs/components/commerce/product-price.tsx +375 -0
  190. package/templates/storefront-nextjs/components/commerce/search-input.tsx +178 -0
  191. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +64 -0
  192. package/templates/storefront-nextjs/components/commerce/variant-selector.tsx +210 -0
  193. package/templates/storefront-nextjs/components/layout/footer.tsx +107 -0
  194. package/templates/storefront-nextjs/components/layout/header.tsx +104 -0
  195. package/templates/storefront-nextjs/components/providers.tsx +62 -0
  196. package/templates/storefront-nextjs/lib/auth/routes.ts +52 -0
  197. package/templates/storefront-nextjs/lib/currency.tsx +140 -0
  198. package/templates/storefront-nextjs/lib/format.ts +159 -0
  199. package/templates/storefront-nextjs/lib/graphql-queries.ts +629 -0
  200. package/templates/storefront-nextjs/lib/hooks.ts +30 -0
  201. package/templates/storefront-nextjs/middleware.ts +80 -0
  202. package/templates/storefront-nextjs/next.config.ts +37 -0
  203. package/templates/storefront-nextjs/open-next.config.ts +3 -0
  204. package/templates/storefront-nextjs/package.dev.json +30 -0
  205. package/templates/storefront-nextjs/package.json +32 -0
  206. package/templates/storefront-nextjs/package.json.template +32 -0
  207. package/templates/storefront-nextjs/postcss.config.mjs +8 -0
  208. package/templates/storefront-nextjs/tailwind.config.ts +111 -0
  209. package/templates/storefront-nextjs/tsconfig.json +27 -0
  210. package/templates/storefront-nextjs/wrangler.toml +9 -0
  211. package/templates/storefront-nextjs-shadcn/.env.example +68 -0
  212. package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +109 -0
  213. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +25 -0
  214. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +22 -0
  215. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +282 -0
  216. package/templates/storefront-nextjs-shadcn/CLAUDE.md +96 -0
  217. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +190 -0
  218. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +263 -0
  219. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +135 -0
  220. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +142 -0
  221. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +448 -0
  222. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +307 -0
  223. package/templates/storefront-nextjs-shadcn/README.md +195 -0
  224. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +245 -0
  225. package/templates/storefront-nextjs-shadcn/app/about/page.tsx +34 -0
  226. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +215 -0
  227. package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +484 -0
  228. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +128 -0
  229. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/tracking/page.tsx +206 -0
  230. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +80 -0
  231. package/templates/storefront-nextjs-shadcn/app/account/page.tsx +107 -0
  232. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +195 -0
  233. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +87 -0
  234. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +125 -0
  235. package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +131 -0
  236. package/templates/storefront-nextjs-shadcn/app/auth/login/page.tsx +24 -0
  237. package/templates/storefront-nextjs-shadcn/app/auth/register/page.tsx +20 -0
  238. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +323 -0
  239. package/templates/storefront-nextjs-shadcn/app/blog/page.tsx +159 -0
  240. package/templates/storefront-nextjs-shadcn/app/brands/[slug]/page.tsx +170 -0
  241. package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +73 -0
  242. package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +165 -0
  243. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +78 -0
  244. package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +75 -0
  245. package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +1752 -0
  246. package/templates/storefront-nextjs-shadcn/app/checkout/success/[orderId]/page.tsx +256 -0
  247. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +74 -0
  248. package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +75 -0
  249. package/templates/storefront-nextjs-shadcn/app/contact/page.tsx +114 -0
  250. package/templates/storefront-nextjs-shadcn/app/error.tsx +90 -0
  251. package/templates/storefront-nextjs-shadcn/app/globals.css +125 -0
  252. package/templates/storefront-nextjs-shadcn/app/layout.tsx +57 -0
  253. package/templates/storefront-nextjs-shadcn/app/not-found.tsx +68 -0
  254. package/templates/storefront-nextjs-shadcn/app/page.tsx +21 -0
  255. package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +246 -0
  256. package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +343 -0
  257. package/templates/storefront-nextjs-shadcn/app/products/page.tsx +25 -0
  258. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +192 -0
  259. package/templates/storefront-nextjs-shadcn/app/returns/page.tsx +77 -0
  260. package/templates/storefront-nextjs-shadcn/app/robots.ts +53 -0
  261. package/templates/storefront-nextjs-shadcn/app/search/page.tsx +16 -0
  262. package/templates/storefront-nextjs-shadcn/app/search/search-client.tsx +47 -0
  263. package/templates/storefront-nextjs-shadcn/app/shipping/page.tsx +62 -0
  264. package/templates/storefront-nextjs-shadcn/app/sitemap.ts +144 -0
  265. package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +179 -0
  266. package/templates/storefront-nextjs-shadcn/codegen.ts +51 -0
  267. package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +348 -0
  268. package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +144 -0
  269. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +258 -0
  270. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +107 -0
  271. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +132 -0
  272. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +188 -0
  273. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +305 -0
  274. package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +240 -0
  275. package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +177 -0
  276. package/templates/storefront-nextjs-shadcn/components/blog/index.ts +8 -0
  277. package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +119 -0
  278. package/templates/storefront-nextjs-shadcn/components/brand/brand-grid.tsx +64 -0
  279. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +140 -0
  280. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +48 -0
  281. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +112 -0
  282. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +84 -0
  283. package/templates/storefront-nextjs-shadcn/components/cart/index.ts +17 -0
  284. package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +121 -0
  285. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +162 -0
  286. package/templates/storefront-nextjs-shadcn/components/checkout/index.ts +25 -0
  287. package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +187 -0
  288. package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +160 -0
  289. package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +154 -0
  290. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +225 -0
  291. package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +62 -0
  292. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +158 -0
  293. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +174 -0
  294. package/templates/storefront-nextjs-shadcn/components/commerce/variant-selector.tsx +210 -0
  295. package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +97 -0
  296. package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +187 -0
  297. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +151 -0
  298. package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +166 -0
  299. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +245 -0
  300. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +246 -0
  301. package/templates/storefront-nextjs-shadcn/components/discount/index.ts +19 -0
  302. package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +113 -0
  303. package/templates/storefront-nextjs-shadcn/components/error/index.ts +7 -0
  304. package/templates/storefront-nextjs-shadcn/components/filters/attribute-filter.tsx +153 -0
  305. package/templates/storefront-nextjs-shadcn/components/filters/checkbox-group-filter.tsx +167 -0
  306. package/templates/storefront-nextjs-shadcn/components/filters/color-swatch-filter.tsx +176 -0
  307. package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +220 -0
  308. package/templates/storefront-nextjs-shadcn/components/filters/index.ts +36 -0
  309. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +193 -0
  310. package/templates/storefront-nextjs-shadcn/components/filters/toggle-filter.tsx +132 -0
  311. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +321 -0
  312. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +309 -0
  313. package/templates/storefront-nextjs-shadcn/components/gift-card/index.ts +24 -0
  314. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +72 -0
  315. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +107 -0
  316. package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +85 -0
  317. package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +34 -0
  318. package/templates/storefront-nextjs-shadcn/components/home/index.ts +8 -0
  319. package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +108 -0
  320. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +133 -0
  321. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +341 -0
  322. package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +128 -0
  323. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +147 -0
  324. package/templates/storefront-nextjs-shadcn/components/layout/index.ts +9 -0
  325. package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +211 -0
  326. package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +95 -0
  327. package/templates/storefront-nextjs-shadcn/components/layout/theme-switcher.tsx +192 -0
  328. package/templates/storefront-nextjs-shadcn/components/loyalty/index.ts +11 -0
  329. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +93 -0
  330. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +177 -0
  331. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +250 -0
  332. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +217 -0
  333. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-badge.tsx +106 -0
  334. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +131 -0
  335. package/templates/storefront-nextjs-shadcn/components/order/delivery-estimate.tsx +196 -0
  336. package/templates/storefront-nextjs-shadcn/components/order/index.ts +11 -0
  337. package/templates/storefront-nextjs-shadcn/components/order/order-tracking.tsx +200 -0
  338. package/templates/storefront-nextjs-shadcn/components/order/shipment-card.tsx +407 -0
  339. package/templates/storefront-nextjs-shadcn/components/order/tracking-status.tsx +222 -0
  340. package/templates/storefront-nextjs-shadcn/components/order/tracking-timeline.tsx +205 -0
  341. package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +161 -0
  342. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +250 -0
  343. package/templates/storefront-nextjs-shadcn/components/product/discount-badge.tsx +196 -0
  344. package/templates/storefront-nextjs-shadcn/components/product/index.ts +41 -0
  345. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +147 -0
  346. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +217 -0
  347. package/templates/storefront-nextjs-shadcn/components/product/product-gallery.tsx +143 -0
  348. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +83 -0
  349. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +155 -0
  350. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +158 -0
  351. package/templates/storefront-nextjs-shadcn/components/product/product-quantity-selector.tsx +111 -0
  352. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +238 -0
  353. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +58 -0
  354. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +169 -0
  355. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +220 -0
  356. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +338 -0
  357. package/templates/storefront-nextjs-shadcn/components/product/review-summary.tsx +143 -0
  358. package/templates/storefront-nextjs-shadcn/components/product/sale-countdown.tsx +166 -0
  359. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +213 -0
  360. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +57 -0
  361. package/templates/storefront-nextjs-shadcn/components/product/stock-indicator.tsx +91 -0
  362. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +103 -0
  363. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +8 -0
  364. package/templates/storefront-nextjs-shadcn/components/providers/query-provider.tsx +260 -0
  365. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +13 -0
  366. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +26 -0
  367. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +608 -0
  368. package/templates/storefront-nextjs-shadcn/components/returns/return-status-card.tsx +554 -0
  369. package/templates/storefront-nextjs-shadcn/components/search/index.ts +8 -0
  370. package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +140 -0
  371. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +58 -0
  372. package/templates/storefront-nextjs-shadcn/components/search/search-suggestions.tsx +43 -0
  373. package/templates/storefront-nextjs-shadcn/components/seo/index.ts +12 -0
  374. package/templates/storefront-nextjs-shadcn/components/seo/json-ld.tsx +56 -0
  375. package/templates/storefront-nextjs-shadcn/components/seo/product-json-ld.ts +167 -0
  376. package/templates/storefront-nextjs-shadcn/components/shipping/index.ts +16 -0
  377. package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +337 -0
  378. package/templates/storefront-nextjs-shadcn/components/ui/accordion.tsx +153 -0
  379. package/templates/storefront-nextjs-shadcn/components/ui/alert.tsx +59 -0
  380. package/templates/storefront-nextjs-shadcn/components/ui/badge.tsx +34 -0
  381. package/templates/storefront-nextjs-shadcn/components/ui/button.tsx +51 -0
  382. package/templates/storefront-nextjs-shadcn/components/ui/card.tsx +77 -0
  383. package/templates/storefront-nextjs-shadcn/components/ui/checkbox.tsx +30 -0
  384. package/templates/storefront-nextjs-shadcn/components/ui/dialog.tsx +137 -0
  385. package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +207 -0
  386. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +67 -0
  387. package/templates/storefront-nextjs-shadcn/components/ui/input.tsx +65 -0
  388. package/templates/storefront-nextjs-shadcn/components/ui/label.tsx +26 -0
  389. package/templates/storefront-nextjs-shadcn/components/ui/pagination.tsx +205 -0
  390. package/templates/storefront-nextjs-shadcn/components/ui/radio-group.tsx +44 -0
  391. package/templates/storefront-nextjs-shadcn/components/ui/select.tsx +160 -0
  392. package/templates/storefront-nextjs-shadcn/components/ui/separator.tsx +28 -0
  393. package/templates/storefront-nextjs-shadcn/components/ui/skeleton.tsx +20 -0
  394. package/templates/storefront-nextjs-shadcn/components/ui/spinner.tsx +82 -0
  395. package/templates/storefront-nextjs-shadcn/components/ui/tabs.tsx +119 -0
  396. package/templates/storefront-nextjs-shadcn/components/ui/toast.tsx +96 -0
  397. package/templates/storefront-nextjs-shadcn/components/wishlist/index.ts +9 -0
  398. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +148 -0
  399. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +47 -0
  400. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +165 -0
  401. package/templates/storefront-nextjs-shadcn/components.json +19 -0
  402. package/templates/storefront-nextjs-shadcn/generated/.gitkeep +2 -0
  403. package/templates/storefront-nextjs-shadcn/graphql/.gitkeep +31 -0
  404. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +168 -0
  405. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +160 -0
  406. package/templates/storefront-nextjs-shadcn/hooks/index.ts +9 -0
  407. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +310 -0
  408. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +286 -0
  409. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +110 -0
  410. package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.test.ts +173 -0
  411. package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.ts +298 -0
  412. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +220 -0
  413. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +57 -0
  414. package/templates/storefront-nextjs-shadcn/lib/config.ts +46 -0
  415. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +254 -0
  416. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +464 -0
  417. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +328 -0
  418. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +295 -0
  419. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +27 -0
  420. package/templates/storefront-nextjs-shadcn/lib/format.test.ts +397 -0
  421. package/templates/storefront-nextjs-shadcn/lib/format.ts +226 -0
  422. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +109 -0
  423. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +1183 -0
  424. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +267 -0
  425. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +30 -0
  426. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +89 -0
  427. package/templates/storefront-nextjs-shadcn/lib/utils.ts +6 -0
  428. package/templates/storefront-nextjs-shadcn/next.config.ts +47 -0
  429. package/templates/storefront-nextjs-shadcn/open-next.config.ts +3 -0
  430. package/templates/storefront-nextjs-shadcn/package.dev.json +30 -0
  431. package/templates/storefront-nextjs-shadcn/package.json +60 -0
  432. package/templates/storefront-nextjs-shadcn/package.json.template +46 -0
  433. package/templates/storefront-nextjs-shadcn/postcss.config.mjs +8 -0
  434. package/templates/storefront-nextjs-shadcn/proxy.ts +80 -0
  435. package/templates/storefront-nextjs-shadcn/public/icons/payment/apple-pay.svg +8 -0
  436. package/templates/storefront-nextjs-shadcn/public/icons/payment/bank-transfer.svg +10 -0
  437. package/templates/storefront-nextjs-shadcn/public/icons/payment/blik.svg +6 -0
  438. package/templates/storefront-nextjs-shadcn/public/icons/payment/cash-on-delivery.svg +11 -0
  439. package/templates/storefront-nextjs-shadcn/public/icons/payment/google-pay.svg +11 -0
  440. package/templates/storefront-nextjs-shadcn/public/icons/payment/mastercard.svg +7 -0
  441. package/templates/storefront-nextjs-shadcn/public/icons/payment/paypal.svg +7 -0
  442. package/templates/storefront-nextjs-shadcn/public/icons/payment/payu.svg +7 -0
  443. package/templates/storefront-nextjs-shadcn/public/icons/payment/przelewy24.svg +7 -0
  444. package/templates/storefront-nextjs-shadcn/public/icons/payment/stripe.svg +4 -0
  445. package/templates/storefront-nextjs-shadcn/public/icons/payment/visa.svg +5 -0
  446. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +66 -0
  447. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +56 -0
  448. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +184 -0
  449. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +103 -0
  450. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +291 -0
  451. package/templates/storefront-nextjs-shadcn/tailwind.config.ts +111 -0
  452. package/templates/storefront-nextjs-shadcn/tsconfig.json +27 -0
  453. package/templates/storefront-nextjs-shadcn/wrangler.toml +9 -0
@@ -0,0 +1,72 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { cn } from "@/lib/utils";
5
+ import { useCollections } from "@/lib/graphql/hooks";
6
+
7
+ export interface CategoryGridProps {
8
+ className?: string;
9
+ }
10
+
11
+ export function CategoryGrid({ className }: CategoryGridProps) {
12
+ // Use collections for homepage marketing (not categories)
13
+ // Collections are better for homepage because they're curated and flexible
14
+ const { data, isLoading, error } = useCollections({
15
+ first: 8,
16
+ });
17
+
18
+ const collections = data?.collections ?? [];
19
+
20
+ if (isLoading) {
21
+ return (
22
+ <section className={cn("container mx-auto px-4", className)}>
23
+ <div className="mb-8 text-center">
24
+ <h2 className="text-3xl font-bold text-foreground">Shop by Category</h2>
25
+ <p className="mt-2 text-muted-foreground">
26
+ Find exactly what you're looking for
27
+ </p>
28
+ </div>
29
+ <div className="grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-4">
30
+ {Array.from({ length: 8 }).map((_, i) => (
31
+ <div key={i} className="animate-pulse rounded-lg border border-border p-6">
32
+ <div className="mb-3 h-10 w-10 bg-muted rounded mx-auto"></div>
33
+ <div className="h-4 bg-muted rounded"></div>
34
+ </div>
35
+ ))}
36
+ </div>
37
+ </section>
38
+ );
39
+ }
40
+
41
+ if (error || collections.length === 0) {
42
+ return null; // Don't show section if no collections
43
+ }
44
+
45
+ return (
46
+ <section className={cn("container mx-auto px-4", className)}>
47
+ <div className="mb-8 text-center">
48
+ <h2 className="text-3xl font-bold text-foreground">Shop by Category</h2>
49
+ <p className="mt-2 text-muted-foreground">
50
+ Find exactly what you're looking for
51
+ </p>
52
+ </div>
53
+
54
+ <div className="grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-4">
55
+ {collections.map((collection: any) => (
56
+ <Link
57
+ key={collection.id}
58
+ href={`/collections/${collection.handle}`}
59
+ className="group flex flex-col items-center justify-center rounded-lg border border-border bg-background p-6 transition-all hover:border-primary hover:shadow-md"
60
+ >
61
+ <div className="mb-3 text-4xl transition-transform group-hover:scale-110">
62
+ 🛍️
63
+ </div>
64
+ <span className="text-center font-medium text-foreground group-hover:text-primary">
65
+ {collection.title}
66
+ </span>
67
+ </Link>
68
+ ))}
69
+ </div>
70
+ </section>
71
+ );
72
+ }
@@ -0,0 +1,107 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Button } from "@/components/ui/button";
5
+ import { Card, CardContent } from "@/components/ui/card";
6
+ import { useCollections } from "@/lib/graphql/hooks";
7
+
8
+ export interface Collection {
9
+ id: string;
10
+ handle: string;
11
+ title: string;
12
+ description?: string;
13
+ image?: {
14
+ url: string;
15
+ altText?: string | null;
16
+ } | null;
17
+ }
18
+
19
+ export function FeaturedCollections() {
20
+ // Fetch collections using GraphQL
21
+ const { data, isLoading, error } = useCollections({
22
+ first: 3,
23
+ });
24
+
25
+ const collections = data?.collections ?? [];
26
+
27
+ if (isLoading) {
28
+ return (
29
+ <section className="container mx-auto px-4">
30
+ <div className="mb-8 text-center">
31
+ <h2 className="text-3xl font-bold text-foreground">Featured Collections</h2>
32
+ <p className="mt-2 text-muted-foreground">
33
+ Explore our curated collections
34
+ </p>
35
+ </div>
36
+ <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
37
+ {Array.from({ length: 3 }).map((_, i) => (
38
+ <div key={i} className="animate-pulse">
39
+ <div className="aspect-[4/3] bg-muted rounded-lg mb-4"></div>
40
+ <div className="h-6 bg-muted rounded mb-2"></div>
41
+ <div className="h-4 bg-muted rounded w-3/4"></div>
42
+ </div>
43
+ ))}
44
+ </div>
45
+ </section>
46
+ );
47
+ }
48
+
49
+ if (error || collections.length === 0) {
50
+ return null; // Don't show section if no collections
51
+ }
52
+
53
+ return (
54
+ <section className="container mx-auto px-4">
55
+ <div className="mb-8 text-center">
56
+ <h2 className="text-3xl font-bold text-foreground">Featured Collections</h2>
57
+ <p className="mt-2 text-muted-foreground">
58
+ Explore our curated collections
59
+ </p>
60
+ </div>
61
+
62
+ {collections.length > 0 ? (
63
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
64
+ {collections.map((collection: Collection) => (
65
+ <Link
66
+ key={collection.id}
67
+ href={`/collections/${collection.handle}`}
68
+ className="group"
69
+ >
70
+ <Card className="overflow-hidden transition-shadow hover:shadow-lg">
71
+ <div className="relative aspect-[16/9] overflow-hidden bg-muted">
72
+ {collection.image?.url ? (
73
+ <img
74
+ src={collection.image.url}
75
+ alt={collection.image.altText || collection.title}
76
+ className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105"
77
+ />
78
+ ) : (
79
+ <div className="flex h-full items-center justify-center text-muted-foreground">
80
+ <span className="text-4xl">🛍️</span>
81
+ </div>
82
+ )}
83
+ </div>
84
+ <CardContent className="p-6">
85
+ <h3 className="text-xl font-semibold text-foreground group-hover:text-primary">
86
+ {collection.title}
87
+ </h3>
88
+ {collection.description && (
89
+ <p className="mt-2 line-clamp-2 text-sm text-muted-foreground">
90
+ {collection.description}
91
+ </p>
92
+ )}
93
+ </CardContent>
94
+ </Card>
95
+ </Link>
96
+ ))}
97
+ </div>
98
+ ) : (
99
+ <div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
100
+ <p className="text-muted-foreground">
101
+ No collections available at the moment.
102
+ </p>
103
+ </div>
104
+ )}
105
+ </section>
106
+ );
107
+ }
@@ -0,0 +1,85 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { ProductGrid } from "@/components/product/product-grid";
5
+ import { Button } from "@/components/ui/button";
6
+ import { useProducts } from "@/lib/graphql/hooks";
7
+
8
+ export function FeaturedProducts() {
9
+ // Fetch featured products using GraphQL
10
+ const { data, isLoading, error } = useProducts({
11
+ first: 8,
12
+ // TODO: Add featured filter when backend supports it
13
+ });
14
+
15
+ const products = data?.products ?? [];
16
+
17
+ if (isLoading) {
18
+ return (
19
+ <section className="container mx-auto px-4">
20
+ <div className="mb-8 flex items-center justify-between">
21
+ <div>
22
+ <h2 className="text-3xl font-bold text-foreground">Featured Products</h2>
23
+ <p className="mt-2 text-muted-foreground">
24
+ Handpicked favorites just for you
25
+ </p>
26
+ </div>
27
+ </div>
28
+ <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
29
+ {Array.from({ length: 4 }).map((_, i) => (
30
+ <div key={i} className="animate-pulse">
31
+ <div className="aspect-square bg-muted rounded-lg mb-4"></div>
32
+ <div className="h-4 bg-muted rounded mb-2"></div>
33
+ <div className="h-4 bg-muted rounded w-1/2"></div>
34
+ </div>
35
+ ))}
36
+ </div>
37
+ </section>
38
+ );
39
+ }
40
+
41
+ // Handle error state explicitly
42
+ if (error) {
43
+ console.error('[FeaturedProducts] Failed to load products:', error);
44
+ return null; // Gracefully hide section on error
45
+ }
46
+
47
+ // Hide section if no products
48
+ if (products.length === 0) {
49
+ return null;
50
+ }
51
+
52
+ return (
53
+ <section className="container mx-auto px-4">
54
+ <div className="mb-8 flex items-center justify-between">
55
+ <div>
56
+ <h2 className="text-3xl font-bold text-foreground">Featured Products</h2>
57
+ <p className="mt-2 text-muted-foreground">
58
+ Handpicked favorites just for you
59
+ </p>
60
+ </div>
61
+ <Button variant="outline" asChild>
62
+ <Link href="/products">View All</Link>
63
+ </Button>
64
+ </div>
65
+
66
+ {products.length > 0 ? (
67
+ <ProductGrid
68
+ products={products}
69
+ columns={4}
70
+ priorityCount={4}
71
+ showBadges
72
+ />
73
+ ) : (
74
+ <div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
75
+ <p className="text-muted-foreground">
76
+ No featured products available at the moment.
77
+ </p>
78
+ <Button className="mt-4" asChild>
79
+ <Link href="/products">Browse All Products</Link>
80
+ </Button>
81
+ </div>
82
+ )}
83
+ </section>
84
+ );
85
+ }
@@ -0,0 +1,34 @@
1
+ import Link from "next/link";
2
+ import { Button } from "@/components/ui/button";
3
+
4
+ export function HeroSection() {
5
+ return (
6
+ <section className="container mx-auto px-4">
7
+ <div className="relative overflow-hidden rounded-2xl bg-gradient-to-r from-primary/10 via-primary/5 to-background p-8 md:p-16">
8
+ <div className="relative z-10 mx-auto max-w-3xl text-center">
9
+ <h1 className="mb-4 text-4xl font-bold tracking-tight text-foreground sm:text-5xl md:text-6xl">
10
+ Welcome to{" "}
11
+ <span className="text-primary">
12
+ {process.env.NEXT_PUBLIC_SITE_NAME || "My Store"}
13
+ </span>
14
+ </h1>
15
+ <p className="mx-auto mb-8 max-w-2xl text-lg text-muted-foreground">
16
+ Discover our curated collection of quality products. Shop with confidence and enjoy exceptional service.
17
+ </p>
18
+ <div className="flex flex-col justify-center gap-4 sm:flex-row">
19
+ <Button size="lg" asChild>
20
+ <Link href="/products">Shop Now</Link>
21
+ </Button>
22
+ <Button size="lg" variant="outline" asChild>
23
+ <Link href="/products">Browse Products</Link>
24
+ </Button>
25
+ </div>
26
+ </div>
27
+
28
+ {/* Decorative elements */}
29
+ <div className="absolute -right-20 -top-20 h-64 w-64 rounded-full bg-primary/10 blur-3xl" />
30
+ <div className="absolute -bottom-20 -left-20 h-64 w-64 rounded-full bg-primary/10 blur-3xl" />
31
+ </div>
32
+ </section>
33
+ );
34
+ }
@@ -0,0 +1,8 @@
1
+ export { HeroSection } from './hero-section';
2
+ export { FeaturedProducts } from './featured-products';
3
+ export { FeaturedCollections } from './featured-collections';
4
+ export type { Collection } from './featured-collections';
5
+ export { CategoryGrid } from './category-grid';
6
+ export type { CategoryGridProps } from './category-grid';
7
+ export { NewsletterSignup } from './newsletter-signup';
8
+ export type { NewsletterSignupProps } from './newsletter-signup';
@@ -0,0 +1,108 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { Mail, Check } from "lucide-react";
5
+ import { Input } from "@/components/ui/input";
6
+ import { Button } from "@/components/ui/button";
7
+ import { cn } from "@/lib/utils";
8
+
9
+ export interface NewsletterSignupProps {
10
+ className?: string;
11
+ }
12
+
13
+ export function NewsletterSignup({ className }: NewsletterSignupProps) {
14
+ const [email, setEmail] = useState("");
15
+ const [isLoading, setIsLoading] = useState(false);
16
+ const [isSuccess, setIsSuccess] = useState(false);
17
+ const [error, setError] = useState<string | null>(null);
18
+
19
+ const handleSubmit = async (e: React.FormEvent) => {
20
+ e.preventDefault();
21
+
22
+ if (!email || !email.includes("@")) {
23
+ setError("Please enter a valid email address");
24
+ return;
25
+ }
26
+
27
+ setIsLoading(true);
28
+ setError(null);
29
+
30
+ try {
31
+ // TODO: Implement newsletter subscription API call
32
+ // await subscribeToNewsletter(email);
33
+
34
+ // Simulate API call
35
+ await new Promise((resolve) => setTimeout(resolve, 1000));
36
+
37
+ setIsSuccess(true);
38
+ setEmail("");
39
+
40
+ // Reset success state after 3 seconds
41
+ setTimeout(() => {
42
+ setIsSuccess(false);
43
+ }, 3000);
44
+ } catch (err) {
45
+ setError("Failed to subscribe. Please try again.");
46
+ } finally {
47
+ setIsLoading(false);
48
+ }
49
+ };
50
+
51
+ return (
52
+ <section className={cn("container mx-auto px-4", className)}>
53
+ <div className="rounded-2xl bg-gradient-to-r from-primary/10 via-primary/5 to-background p-8 md:p-12">
54
+ <div className="mx-auto max-w-2xl text-center">
55
+ <div className="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-full bg-primary/10">
56
+ <Mail className="h-6 w-6 text-primary" />
57
+ </div>
58
+
59
+ <h2 className="mb-2 text-3xl font-bold text-foreground">
60
+ Stay in the Loop
61
+ </h2>
62
+ <p className="mb-6 text-muted-foreground">
63
+ Subscribe to our newsletter for exclusive offers, new arrivals, and insider news.
64
+ </p>
65
+
66
+ {isSuccess ? (
67
+ <div className="flex items-center justify-center gap-2 rounded-lg bg-green-50 p-4 text-green-700 dark:bg-green-950 dark:text-green-400">
68
+ <Check className="h-5 w-5" />
69
+ <span className="font-medium">
70
+ Thanks for subscribing! Check your email for confirmation.
71
+ </span>
72
+ </div>
73
+ ) : (
74
+ <form onSubmit={handleSubmit} className="mx-auto max-w-md">
75
+ <div className="flex flex-col gap-3 sm:flex-row">
76
+ <Input
77
+ type="email"
78
+ placeholder="Enter your email"
79
+ value={email}
80
+ onChange={(e) => setEmail(e.target.value)}
81
+ disabled={isLoading}
82
+ className="flex-1"
83
+ required
84
+ />
85
+ <Button
86
+ type="submit"
87
+ disabled={isLoading || !email}
88
+ size="lg"
89
+ className="sm:w-auto"
90
+ >
91
+ {isLoading ? "Subscribing..." : "Subscribe"}
92
+ </Button>
93
+ </div>
94
+
95
+ {error && (
96
+ <p className="mt-2 text-sm text-destructive">{error}</p>
97
+ )}
98
+
99
+ <p className="mt-3 text-xs text-muted-foreground">
100
+ By subscribing, you agree to our Privacy Policy and consent to receive updates.
101
+ </p>
102
+ </form>
103
+ )}
104
+ </div>
105
+ </div>
106
+ </section>
107
+ );
108
+ }
@@ -0,0 +1,133 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { usePathname } from "next/navigation";
5
+ import { ChevronRight, Home } from "lucide-react";
6
+ import { cn } from "@/lib/utils";
7
+
8
+ export interface BreadcrumbItem {
9
+ label: string;
10
+ href: string;
11
+ }
12
+
13
+ export interface BreadcrumbsProps {
14
+ items?: BreadcrumbItem[];
15
+ className?: string;
16
+ showHome?: boolean;
17
+ }
18
+
19
+ /**
20
+ * Breadcrumbs component for navigation hierarchy
21
+ *
22
+ * @example
23
+ * // Auto-generate from pathname
24
+ * <Breadcrumbs />
25
+ *
26
+ * @example
27
+ * // Custom breadcrumb items
28
+ * <Breadcrumbs items={[
29
+ * { label: "Products", href: "/products" },
30
+ * { label: "Electronics", href: "/products/electronics" },
31
+ * { label: "Laptops", href: "/products/electronics/laptops" }
32
+ * ]} />
33
+ */
34
+ export function Breadcrumbs({
35
+ items,
36
+ className,
37
+ showHome = true,
38
+ }: BreadcrumbsProps) {
39
+ const pathname = usePathname();
40
+
41
+ // Auto-generate breadcrumbs from pathname if items not provided
42
+ const breadcrumbItems = items || generateBreadcrumbs(pathname);
43
+
44
+ // Don't show breadcrumbs on homepage
45
+ if (pathname === "/" || breadcrumbItems.length === 0) {
46
+ return null;
47
+ }
48
+
49
+ return (
50
+ <nav
51
+ aria-label="Breadcrumb"
52
+ className={cn("flex items-center gap-2 text-sm", className)}
53
+ >
54
+ <ol className="flex items-center gap-2">
55
+ {showHome && (
56
+ <li>
57
+ <Link
58
+ href="/"
59
+ className="flex items-center text-muted-foreground hover:text-foreground transition-colors"
60
+ aria-label="Home"
61
+ >
62
+ <Home className="h-4 w-4" />
63
+ </Link>
64
+ </li>
65
+ )}
66
+
67
+ {breadcrumbItems.map((item, index) => {
68
+ const isLast = index === breadcrumbItems.length - 1;
69
+
70
+ return (
71
+ <li key={item.href} className="flex items-center gap-2">
72
+ {(showHome || index > 0) && (
73
+ <ChevronRight
74
+ className="h-4 w-4 text-muted-foreground"
75
+ aria-hidden="true"
76
+ />
77
+ )}
78
+
79
+ {isLast ? (
80
+ <span
81
+ className="font-medium text-foreground"
82
+ aria-current="page"
83
+ >
84
+ {item.label}
85
+ </span>
86
+ ) : (
87
+ <Link
88
+ href={item.href}
89
+ className="text-muted-foreground hover:text-foreground transition-colors"
90
+ >
91
+ {item.label}
92
+ </Link>
93
+ )}
94
+ </li>
95
+ );
96
+ })}
97
+ </ol>
98
+ </nav>
99
+ );
100
+ }
101
+
102
+ /**
103
+ * Generate breadcrumb items from pathname
104
+ */
105
+ function generateBreadcrumbs(pathname: string): BreadcrumbItem[] {
106
+ const segments = pathname.split("/").filter(Boolean);
107
+ const breadcrumbs: BreadcrumbItem[] = [];
108
+
109
+ let currentPath = "";
110
+ for (const segment of segments) {
111
+ currentPath += `/${segment}`;
112
+
113
+ // Format label: remove hyphens, capitalize words
114
+ const label = segment
115
+ .split("-")
116
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
117
+ .join(" ");
118
+
119
+ breadcrumbs.push({
120
+ label,
121
+ href: currentPath,
122
+ });
123
+ }
124
+
125
+ return breadcrumbs;
126
+ }
127
+
128
+ /**
129
+ * Helper function to create custom breadcrumb items
130
+ */
131
+ export function createBreadcrumbs(...items: BreadcrumbItem[]): BreadcrumbItem[] {
132
+ return items;
133
+ }