@akinon/projectzero 2.0.0-beta.9 → 2.0.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 (290) hide show
  1. package/CHANGELOG.md +191 -17
  2. package/app-template/.env.example +3 -0
  3. package/app-template/.github/instructions/account.instructions.md +749 -0
  4. package/app-template/.github/instructions/checkout.instructions.md +678 -0
  5. package/app-template/.github/instructions/default.instructions.md +279 -0
  6. package/app-template/.github/instructions/edge-cases.instructions.md +73 -0
  7. package/app-template/.github/instructions/routing.instructions.md +603 -0
  8. package/app-template/.github/instructions/settings.instructions.md +338 -0
  9. package/app-template/.gitignore +3 -0
  10. package/app-template/AGENTS.md +7 -0
  11. package/app-template/CHANGELOG.md +2065 -232
  12. package/app-template/Procfile +1 -1
  13. package/app-template/akinon.json +1 -4
  14. package/app-template/build.sh +10 -0
  15. package/app-template/docs/advanced-usage.md +111 -0
  16. package/app-template/docs/plugins.md +60 -25
  17. package/app-template/docs/sentry-usage.md +35 -0
  18. package/app-template/jest.config.ts +2 -2
  19. package/app-template/next-env.d.ts +1 -0
  20. package/app-template/{next.config.ts → next.config.mjs} +6 -7
  21. package/app-template/package.json +58 -50
  22. package/app-template/postcss.config.mjs +1 -4
  23. package/app-template/public/amex.svg +12 -0
  24. package/app-template/public/apple-pay.svg +16 -0
  25. package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
  26. package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
  27. package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
  28. package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
  29. package/app-template/public/google-pay.svg +16 -0
  30. package/app-template/public/locales/en/account.json +9 -4
  31. package/app-template/public/locales/en/auth.json +6 -7
  32. package/app-template/public/locales/en/basket.json +6 -6
  33. package/app-template/public/locales/en/blog.json +7 -0
  34. package/app-template/public/locales/en/category.json +3 -1
  35. package/app-template/public/locales/en/checkout.json +17 -4
  36. package/app-template/public/locales/en/common.json +61 -3
  37. package/app-template/public/locales/en/forgot_password.json +6 -7
  38. package/app-template/public/locales/en/product.json +84 -4
  39. package/app-template/public/locales/tr/account.json +9 -4
  40. package/app-template/public/locales/tr/auth.json +16 -17
  41. package/app-template/public/locales/tr/basket.json +4 -4
  42. package/app-template/public/locales/tr/blog.json +7 -0
  43. package/app-template/public/locales/tr/category.json +3 -1
  44. package/app-template/public/locales/tr/checkout.json +48 -36
  45. package/app-template/public/locales/tr/common.json +60 -2
  46. package/app-template/public/locales/tr/forgot_password.json +12 -13
  47. package/app-template/public/locales/tr/product.json +82 -0
  48. package/app-template/public/logo.svg +3 -27
  49. package/app-template/public/mastercard.svg +14 -0
  50. package/app-template/public/masterpass-javascript-sdk-web.min.js +1 -0
  51. package/app-template/public/promotion-banner.jpg +0 -0
  52. package/app-template/public/shop-pay.svg +12 -0
  53. package/app-template/public/visa.svg +12 -0
  54. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/[...prettyurl]/page.tsx +11 -11
  55. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/layout.tsx +4 -3
  56. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/cancellation/page.tsx +13 -10
  57. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/page.tsx +73 -51
  58. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/page.tsx +1 -1
  59. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/profile/page.tsx +2 -2
  60. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/address/stores/page.tsx +2 -2
  61. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/page.tsx +1 -1
  62. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket/page.tsx +2 -2
  63. package/app-template/src/app/[pz]/blog/[slug]/page.tsx +120 -0
  64. package/app-template/src/app/[pz]/category/[pk]/page.tsx +37 -0
  65. package/app-template/src/app/[pz]/flat-page/[pk]/page.tsx +23 -0
  66. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/forms/[pk]/generate/page.tsx +2 -3
  67. package/app-template/src/app/[pz]/group-product/[pk]/page.tsx +93 -0
  68. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/page.tsx +2 -4
  69. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/layout.tsx +6 -11
  70. package/app-template/src/app/[pz]/list/page.tsx +26 -0
  71. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/not-found.tsx +5 -7
  72. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/page.tsx +6 -4
  73. package/app-template/src/app/[pz]/page.tsx +28 -0
  74. package/app-template/src/app/[pz]/pages/[slug]/page.tsx +19 -0
  75. package/app-template/src/app/[pz]/product/[pk]/page.tsx +102 -0
  76. package/app-template/src/app/[pz]/special-page/[pk]/page.tsx +35 -0
  77. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/email-set-primary/[[...id]]/page.tsx +3 -4
  78. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/registration/account-confirm-email/[[...id]]/page.tsx +3 -3
  79. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/reset/[[...id]]/page.tsx +41 -5
  80. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/[node]/route.ts +8 -6
  81. package/app-template/src/app/api/auth/[...nextauth]/route.ts +3 -0
  82. package/app-template/src/app/api/barcode-search/route.ts +1 -0
  83. package/app-template/src/app/api/cache/route.ts +1 -1
  84. package/app-template/src/app/api/form/[...id]/route.ts +1 -7
  85. package/app-template/src/app/api/image-proxy/route.ts +1 -0
  86. package/app-template/src/app/api/logout/route.ts +1 -1
  87. package/app-template/src/app/api/product-categories/route.ts +1 -0
  88. package/app-template/src/app/api/similar-product-list/route.ts +1 -0
  89. package/app-template/src/app/api/similar-products/route.ts +1 -0
  90. package/app-template/src/app/api/theme-settings/route.ts +12 -0
  91. package/app-template/src/app/api/virtual-try-on/limited-categories/route.ts +1 -0
  92. package/app-template/src/app/api/virtual-try-on/route.ts +1 -0
  93. package/app-template/src/app/api/web-vitals/route.ts +1 -1
  94. package/app-template/src/assets/fonts/pz-icon.css +211 -49
  95. package/app-template/src/assets/fonts/pz-icon.eot +0 -0
  96. package/app-template/src/assets/fonts/pz-icon.html +486 -0
  97. package/app-template/src/assets/fonts/pz-icon.scss +373 -49
  98. package/app-template/src/assets/fonts/pz-icon.svg +215 -53
  99. package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
  100. package/app-template/src/assets/fonts/pz-icon.woff +0 -0
  101. package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
  102. package/app-template/src/assets/globals.scss +8 -133
  103. package/app-template/src/assets/icons/arrow-right.svg +3 -0
  104. package/app-template/src/assets/icons/cart.svg +4 -12
  105. package/app-template/src/assets/icons/check.svg +2 -18
  106. package/app-template/src/assets/icons/chevron-down.svg +2 -7
  107. package/app-template/src/assets/icons/delete.svg +3 -0
  108. package/app-template/src/assets/icons/facebook.svg +2 -8
  109. package/app-template/src/assets/icons/fav-off.svg +5 -0
  110. package/app-template/src/assets/icons/fav-on.svg +5 -0
  111. package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
  112. package/app-template/src/assets/icons/heart.svg +3 -0
  113. package/app-template/src/assets/icons/instagram.svg +2 -13
  114. package/app-template/src/assets/icons/materials.svg +3 -0
  115. package/app-template/src/assets/icons/person.svg +4 -0
  116. package/app-template/src/assets/icons/pinterest.svg +5 -11
  117. package/app-template/src/assets/icons/ruler.svg +3 -0
  118. package/app-template/src/assets/icons/search.svg +8 -11
  119. package/app-template/src/assets/icons/share.svg +2 -9
  120. package/app-template/src/assets/icons/snapchat.svg +3 -0
  121. package/app-template/src/assets/icons/tiktok.svg +3 -0
  122. package/app-template/src/assets/icons/tumblr.svg +6 -0
  123. package/app-template/src/assets/icons/twitter.svg +2 -10
  124. package/app-template/src/assets/icons/vimeo.svg +3 -0
  125. package/app-template/src/assets/icons/youtube.svg +3 -0
  126. package/app-template/src/assets/icons/zoom.svg +8 -0
  127. package/app-template/src/auth.ts +3 -0
  128. package/app-template/src/components/__tests__/badge.test.tsx +2 -2
  129. package/app-template/src/components/__tests__/link.test.tsx +2 -0
  130. package/app-template/src/components/accordion.tsx +48 -23
  131. package/app-template/src/components/action-tooltip.tsx +160 -0
  132. package/app-template/src/components/button.tsx +1 -1
  133. package/app-template/src/components/carousel-core.tsx +4 -11
  134. package/app-template/src/components/checkbox.tsx +2 -1
  135. package/app-template/src/components/currency-select.tsx +150 -4
  136. package/app-template/src/components/file-input.tsx +27 -7
  137. package/app-template/src/components/generate-form-fields.tsx +49 -10
  138. package/app-template/src/components/icon.tsx +5 -6
  139. package/app-template/src/components/index.ts +4 -1
  140. package/app-template/src/components/input.tsx +11 -5
  141. package/app-template/src/components/language-select.tsx +88 -2
  142. package/app-template/src/components/modal.tsx +34 -16
  143. package/app-template/src/components/pagination.tsx +133 -20
  144. package/app-template/src/components/price.tsx +1 -1
  145. package/app-template/src/components/pwa-tags.tsx +1 -0
  146. package/app-template/src/components/quantity-input.tsx +63 -0
  147. package/app-template/src/components/quantity-selector.tsx +215 -0
  148. package/app-template/src/components/route-handler.tsx +50 -0
  149. package/app-template/src/components/select.tsx +86 -54
  150. package/app-template/src/components/shimmer.tsx +1 -1
  151. package/app-template/src/components/types/index.ts +51 -1
  152. package/app-template/src/components/widget-content.tsx +323 -0
  153. package/app-template/src/data/server/theme.ts +70 -0
  154. package/app-template/src/hooks/use-fav-button.tsx +9 -10
  155. package/app-template/src/hooks/use-product-cart.ts +80 -0
  156. package/app-template/src/hooks/use-stock-alert.ts +74 -0
  157. package/app-template/src/hooks/use-theme-settings.ts +42 -0
  158. package/app-template/src/lib/fonts.ts +149 -0
  159. package/app-template/src/plugins.js +12 -2
  160. package/app-template/src/{middleware.ts → proxy.ts} +3 -3
  161. package/app-template/src/redux/middlewares/category.ts +5 -4
  162. package/app-template/src/redux/store.ts +21 -1
  163. package/app-template/src/routes/index.ts +8 -7
  164. package/app-template/src/settings.js +6 -3
  165. package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
  166. package/app-template/src/types/index.ts +74 -3
  167. package/app-template/src/types/next-auth.d.ts +2 -2
  168. package/app-template/src/types/widget.ts +169 -0
  169. package/app-template/src/utils/__tests__/theme-page-context.test.ts +145 -0
  170. package/app-template/src/utils/formatDate.ts +48 -0
  171. package/app-template/src/utils/styles.ts +71 -0
  172. package/app-template/src/utils/theme-page-context.ts +309 -0
  173. package/app-template/src/utils/variant-validation.ts +41 -0
  174. package/app-template/src/views/account/address-form.tsx +8 -4
  175. package/app-template/src/views/account/contact-form.tsx +148 -131
  176. package/app-template/src/views/account/content-header.tsx +4 -3
  177. package/app-template/src/views/account/faq/faq-tabs.tsx +8 -2
  178. package/app-template/src/views/account/favorite-item.tsx +1 -1
  179. package/app-template/src/views/account/order.tsx +11 -9
  180. package/app-template/src/views/account/orders/order-cancellation-item.tsx +1 -1
  181. package/app-template/src/views/account/orders/order-detail-header.tsx +1 -1
  182. package/app-template/src/views/anonymous-tracking/order-detail/index.tsx +45 -38
  183. package/app-template/src/views/basket/basket-item.tsx +6 -1
  184. package/app-template/src/views/basket/summary.tsx +16 -0
  185. package/app-template/src/views/breadcrumb.tsx +2 -2
  186. package/app-template/src/views/category/category-banner.tsx +4 -23
  187. package/app-template/src/views/category/category-info.tsx +2 -1
  188. package/app-template/src/views/category/filters/filter-item.tsx +138 -42
  189. package/app-template/src/views/category/filters/index.tsx +1 -1
  190. package/app-template/src/views/category/layout.tsx +1 -0
  191. package/app-template/src/views/checkout/auth.tsx +64 -40
  192. package/app-template/src/views/checkout/layout/header.tsx +10 -6
  193. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +22 -6
  194. package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +25 -5
  195. package/app-template/src/views/checkout/steps/payment/options/loyalty.tsx +21 -2
  196. package/app-template/src/views/checkout/steps/payment/options/redirection.tsx +27 -5
  197. package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +464 -0
  198. package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +4 -4
  199. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +33 -20
  200. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +2 -2
  201. package/app-template/src/views/checkout/summary.tsx +12 -2
  202. package/app-template/src/views/find-in-store/index.tsx +2 -2
  203. package/app-template/src/views/guest-login/index.tsx +62 -58
  204. package/app-template/src/views/header/action-menu.tsx +1 -1
  205. package/app-template/src/views/header/band.tsx +2 -2
  206. package/app-template/src/views/header/index.tsx +1 -1
  207. package/app-template/src/views/header/mini-basket.tsx +3 -3
  208. package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
  209. package/app-template/src/views/header/mobile-menu.tsx +18 -6
  210. package/app-template/src/views/header/navbar.tsx +1 -1
  211. package/app-template/src/views/header/pwa-back-button.tsx +1 -1
  212. package/app-template/src/views/header/search/index.tsx +13 -3
  213. package/app-template/src/views/header/search/results.tsx +1 -1
  214. package/app-template/src/views/header/user-menu.tsx +1 -3
  215. package/app-template/src/views/login/index.tsx +66 -57
  216. package/app-template/src/views/otp-login/index.tsx +11 -6
  217. package/app-template/src/views/product/index.ts +1 -0
  218. package/app-template/src/views/product/layout.tsx +26 -6
  219. package/app-template/src/views/product/price-wrapper.tsx +3 -24
  220. package/app-template/src/views/product/product-actions.tsx +165 -0
  221. package/app-template/src/views/product/product-info.tsx +76 -238
  222. package/app-template/src/views/product/product-share.tsx +58 -0
  223. package/app-template/src/views/product/product-variants.tsx +26 -0
  224. package/app-template/src/views/product/slider.tsx +22 -1
  225. package/app-template/src/views/product/variant.tsx +69 -41
  226. package/app-template/src/views/product-pointer-banner-item.tsx +1 -1
  227. package/app-template/src/views/register/index.tsx +31 -46
  228. package/app-template/src/views/sales-contract-modal/index.tsx +17 -17
  229. package/app-template/src/views/share/index.tsx +9 -6
  230. package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
  231. package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
  232. package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
  233. package/app-template/src/widgets/footer-info.tsx +1 -1
  234. package/app-template/src/widgets/footer-menu.tsx +7 -3
  235. package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
  236. package/app-template/src/widgets/footer-subscription/index.tsx +1 -1
  237. package/app-template/src/widgets/home-stories-eng.tsx +43 -35
  238. package/app-template/src/widgets/index.ts +7 -0
  239. package/app-template/src/widgets/schemas/about-us.json +46 -0
  240. package/app-template/src/widgets/schemas/blog-list.json +37 -0
  241. package/app-template/src/widgets/schemas/blog.json +29 -0
  242. package/app-template/tailwind.config.js +155 -7
  243. package/app-template/tsconfig.json +29 -11
  244. package/codemods/migrate-auth-v5/index.js +339 -0
  245. package/codemods/migrate-auth-v5/transform.js +86 -0
  246. package/codemods/migrate-segments/index.js +591 -0
  247. package/codemods/update-tailwind-config/index.js +30 -0
  248. package/codemods/update-tailwind-config/transform.js +102 -0
  249. package/codemods/upgrade-to-2/index.js +549 -0
  250. package/commands/codemod.ts +0 -1
  251. package/commands/plugins.ts +111 -46
  252. package/dist/commands/codemod.js +0 -1
  253. package/dist/commands/plugins.js +104 -36
  254. package/package.json +3 -2
  255. package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +0 -22
  256. package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +0 -20
  257. package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +0 -74
  258. package/app-template/src/app/[commerce]/[locale]/[currency]/list/page.tsx +0 -18
  259. package/app-template/src/app/[commerce]/[locale]/[currency]/page.tsx +0 -50
  260. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +0 -84
  261. package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +0 -27
  262. package/app-template/src/pages/api/auth/[...nextauth].ts +0 -3
  263. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/address/page.tsx +0 -0
  264. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-email/page.tsx +0 -0
  265. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-password/page.tsx +0 -0
  266. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/contact/page.tsx +0 -0
  267. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/coupons/page.tsx +0 -0
  268. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/email-verification/page.tsx +0 -0
  269. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/faq/page.tsx +0 -0
  270. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/favourite-products/page.tsx +0 -0
  271. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/my-quotations/page.tsx +0 -0
  272. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/layout.tsx +0 -0
  273. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/page.tsx +0 -0
  274. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/anonymous-tracking/page.tsx +0 -0
  275. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/oauth-login/page.tsx +0 -0
  276. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket-b2b/page.tsx +0 -0
  277. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/category/[pk]/loading.tsx +0 -0
  278. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/client-root.tsx +0 -0
  279. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/contact-us/page.tsx +0 -0
  280. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/error.tsx +0 -0
  281. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/flat-page/[pk]/loading.tsx +0 -0
  282. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/group-product/[pk]/loading.tsx +0 -0
  283. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/loading.tsx +0 -0
  284. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/loading.tsx +0 -0
  285. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/checkout/page.tsx +0 -0
  286. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/layout.tsx +0 -0
  287. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/special-page/[pk]/loading.tsx +0 -0
  288. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/template.tsx +0 -0
  289. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/password/reset/page.tsx +0 -0
  290. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/route.ts +0 -0
@@ -39,8 +39,8 @@ export const Input = forwardRef<
39
39
  const hasFloatingLabel = label && labelStyle === 'floating';
40
40
  const inputClass = twMerge(
41
41
  clsx(
42
- 'text-xs border px-2.5 h-10 placeholder:text-gray-600 peer disabled:bg-gray-50',
43
- 'focus-visible:outline-hidden', // disable outline on focus
42
+ 'text-xs border px-2.5 h-10 placeholder:text-gray-600 peer',
43
+ 'focus-visible:outline-none', // disable outline on focus
44
44
  error
45
45
  ? 'border-error focus:border-error'
46
46
  : 'border-gray-500 hover:border-black focus:border-black'
@@ -48,7 +48,13 @@ export const Input = forwardRef<
48
48
  props.className
49
49
  );
50
50
 
51
- const inputProps: any = {
51
+ const inputProps: {
52
+ id?: string;
53
+ ref?: Ref<HTMLInputElement>;
54
+ className?: string;
55
+ onFocus?: () => void;
56
+ onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
57
+ } = {
52
58
  id,
53
59
  ref,
54
60
  className: inputClass,
@@ -68,7 +74,7 @@ export const Input = forwardRef<
68
74
  className={twMerge(
69
75
  'text-xs text-gray-800 transition-all',
70
76
  clsx({
71
- 'absolute left-2.5 pointer-events-none transform flex items-center h-full top-0! peer-placeholder-shown:-translate-y-2 peer-placeholder-shown:bg-white peer-placeholder-shown:inline-flex peer-placeholder-shown:h-auto':
77
+ 'absolute left-2.5 pointer-events-none transform flex items-center h-full !top-0 peer-placeholder-shown:-translate-y-2 peer-placeholder-shown:bg-white peer-placeholder-shown:inline-flex peer-placeholder-shown:h-auto':
72
78
  hasFloatingLabel,
73
79
  'mb-2': !hasFloatingLabel,
74
80
  '-translate-y-2 bg-white inline-flex h-auto':
@@ -112,7 +118,7 @@ export const Input = forwardRef<
112
118
  )}
113
119
  </div>
114
120
  {error && (
115
- <span className="mt-1 text-sm text-error">{error.message}</span>
121
+ <span className="mt-1 text-sm text-error">{String(error.message)}</span>
116
122
  )}
117
123
  </div>
118
124
  );
@@ -1,30 +1,116 @@
1
1
  'use client';
2
2
 
3
3
  import { useLocalization } from '@akinon/next/hooks';
4
+ import { useEffect, useRef } from 'react';
4
5
  import { Select } from './select';
5
6
 
6
7
  interface LanguageSelectProps {
7
8
  className?: string;
9
+ showIcon?: boolean;
10
+ iconClassName?: string;
11
+ /** Custom SVG icon content */
12
+ customIcon?: string;
13
+ /** Label format: 'full' (English), 'short' (EN), 'code' (en) */
14
+ labelFormat?: 'full' | 'short' | 'code';
8
15
  }
9
16
 
10
17
  export const LanguageSelect = (props: LanguageSelectProps) => {
11
18
  const { locale, locales, setLocale } = useLocalization();
19
+ const isUpdatingFromParent = useRef(false);
20
+
21
+ useEffect(() => {
22
+ if (window.parent !== window && !isUpdatingFromParent.current) {
23
+ window.parent.postMessage(
24
+ {
25
+ type: 'LOCALE_UPDATE',
26
+ data: {
27
+ locale,
28
+ locales: locales.map((lang) => ({
29
+ value: lang.value,
30
+ label: lang.label
31
+ }))
32
+ }
33
+ },
34
+ '*'
35
+ );
36
+ }
37
+ }, [locale, locales]);
38
+
39
+ useEffect(() => {
40
+ const handleMessage = (event: MessageEvent) => {
41
+ if (event.data?.type === 'LOCALE_UPDATE') {
42
+ const { locale: newLocale } = event.data.data;
43
+
44
+ if (newLocale && newLocale !== locale) {
45
+ isUpdatingFromParent.current = true;
46
+ setLocale(newLocale);
47
+ setTimeout(() => {
48
+ isUpdatingFromParent.current = false;
49
+ }, 100);
50
+ }
51
+ }
52
+ };
53
+
54
+ window.addEventListener('message', handleMessage);
55
+ return () => window.removeEventListener('message', handleMessage);
56
+ }, [locale, setLocale]);
12
57
 
13
58
  const handleChange = async (e) => {
14
59
  const selectedLanguage = e.currentTarget.value;
15
60
 
16
61
  setLocale(selectedLanguage);
62
+
63
+ if (window.parent !== window) {
64
+ window.parent.postMessage(
65
+ {
66
+ type: 'LOCALE_UPDATE',
67
+ data: {
68
+ locale: selectedLanguage,
69
+ locales: locales.map((lang) => ({
70
+ value: lang.value,
71
+ label: lang.label
72
+ }))
73
+ }
74
+ },
75
+ '*'
76
+ );
77
+ }
78
+ };
79
+
80
+ // Format label based on labelFormat prop
81
+ const formatLabel = (lang: { value: string; label: string }) => {
82
+ switch (props.labelFormat) {
83
+ case 'short':
84
+ // Get first 2 characters uppercase (EN, TR, etc.)
85
+ return lang.value.slice(0, 2).toUpperCase();
86
+ case 'code':
87
+ // Return locale code as-is (en, tr, etc.)
88
+ return lang.value;
89
+ case 'full':
90
+ default:
91
+ // Return full label (English, Türkçe, etc.)
92
+ return lang.label;
93
+ }
17
94
  };
18
95
 
96
+ // Check if customIcon has actual SVG content
97
+ const hasValidCustomIcon =
98
+ props.customIcon &&
99
+ typeof props.customIcon === 'string' &&
100
+ props.customIcon.includes('<svg');
101
+
19
102
  return (
20
103
  <Select
21
104
  onChange={handleChange}
22
105
  options={locales.map((lang) => ({
23
106
  value: lang.value,
24
- label: lang.label
107
+ label: formatLabel(lang)
25
108
  }))}
26
109
  value={locale}
27
- icon="globe"
110
+ icon={
111
+ props.showIcon !== false && !hasValidCustomIcon ? 'globe' : undefined
112
+ }
113
+ customIcon={props.showIcon !== false ? props.customIcon : undefined}
28
114
  data-testid="language"
29
115
  borderless
30
116
  className={props.className}
@@ -4,16 +4,7 @@ import ReactPortal from './react-portal';
4
4
  import { Icon } from './icon';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { useEffect } from 'react';
7
-
8
- export interface ModalProps {
9
- portalId: string;
10
- children?: React.ReactNode;
11
- open?: boolean;
12
- setOpen?: (open: boolean) => void;
13
- title?: React.ReactNode;
14
- showCloseButton?: React.ReactNode;
15
- className?: string;
16
- }
7
+ import { ModalProps } from '@theme/types';
17
8
 
18
9
  export const Modal = (props: ModalProps) => {
19
10
  const {
@@ -23,7 +14,14 @@ export const Modal = (props: ModalProps) => {
23
14
  setOpen,
24
15
  title = '',
25
16
  showCloseButton = true,
26
- className
17
+ className,
18
+ overlayClassName,
19
+ headerWrapperClassName,
20
+ titleClassName,
21
+ closeButtonClassName,
22
+ iconName = 'close',
23
+ iconSize = 16,
24
+ iconClassName
27
25
  } = props;
28
26
 
29
27
  useEffect(() => {
@@ -38,23 +36,43 @@ export const Modal = (props: ModalProps) => {
38
36
 
39
37
  return (
40
38
  <ReactPortal wrapperId={portalId}>
41
- <div className="fixed top-0 left-0 w-screen h-screen bg-primary/60 z-50" />
39
+ <div
40
+ className={twMerge(
41
+ 'fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50',
42
+ overlayClassName
43
+ )}
44
+ onClick={(e) => e.stopPropagation()}
45
+ />
42
46
  <section
43
47
  className={twMerge(
44
48
  'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 bg-white',
45
49
  className
46
50
  )}
51
+ onClick={(e) => e.stopPropagation()}
47
52
  >
48
53
  {(showCloseButton || title) && (
49
- <div className="flex px-6 py-4 border-b border-gray-400">
50
- {title && <h3 className="text-lg font-light">{title}</h3>}
54
+ <div
55
+ className={twMerge(
56
+ 'flex px-6 py-4 border-b border-gray-400',
57
+ headerWrapperClassName
58
+ )}
59
+ >
60
+ {title && (
61
+ <h3 className={twMerge('text-lg font-light', titleClassName)}>
62
+ {title}
63
+ </h3>
64
+ )}
51
65
  {showCloseButton && (
52
66
  <button
53
67
  type="button"
54
68
  onClick={() => setOpen(false)}
55
- className="ml-auto"
69
+ className={twMerge('ml-auto', closeButtonClassName)}
56
70
  >
57
- <Icon name="close" size={16} />
71
+ <Icon
72
+ name={iconName}
73
+ size={iconSize}
74
+ className={iconClassName}
75
+ />
58
76
  </button>
59
77
  )}
60
78
  </div>
@@ -8,6 +8,14 @@ import { useLocalization } from '@akinon/next/hooks';
8
8
  import { useRouter } from '@akinon/next/hooks';
9
9
  import { useInView } from 'react-intersection-observer';
10
10
 
11
+ const parseSafeUrl = (url: string) => {
12
+ try {
13
+ return new URL(url, window.location.origin);
14
+ } catch {
15
+ return null;
16
+ }
17
+ };
18
+
11
19
  export const Pagination = (props: PaginationProps) => {
12
20
  const { t } = useLocalization();
13
21
  const router = useRouter();
@@ -26,7 +34,8 @@ export const Pagination = (props: PaginationProps) => {
26
34
  onPageChange,
27
35
  direction,
28
36
  render,
29
- isLoading
37
+ isLoading,
38
+ customStyles
30
39
  } = props;
31
40
 
32
41
  const pagination = usePagination(total, limit, currentPage, numberOfPages);
@@ -96,7 +105,11 @@ export const Pagination = (props: PaginationProps) => {
96
105
  const handleClick = (e: MouseEvent<HTMLAnchorElement>, url: string) => {
97
106
  e.preventDefault();
98
107
 
99
- const newUrl = new URL(url, window.location.origin);
108
+ const newUrl = parseSafeUrl(url);
109
+ if (!newUrl) {
110
+ return;
111
+ }
112
+
100
113
  const page = newUrl.searchParams.get('page');
101
114
 
102
115
  if (page === '1') {
@@ -117,7 +130,21 @@ export const Pagination = (props: PaginationProps) => {
117
130
  setNextPage(changingPage);
118
131
  }
119
132
 
120
- onPageChange(changingPage);
133
+ // Navigate to new page using router if onPageChange is not provided
134
+ if (onPageChange) {
135
+ onPageChange(changingPage);
136
+ } else {
137
+ const currentUrl = parseSafeUrl(window.location.href);
138
+ if (!currentUrl) {
139
+ return;
140
+ }
141
+
142
+ currentUrl.searchParams.set('page', String(changingPage));
143
+ if (changingPage === 1) {
144
+ currentUrl.searchParams.delete('page');
145
+ }
146
+ router.push(currentUrl.pathname + currentUrl.search, undefined);
147
+ }
121
148
  };
122
149
 
123
150
  useEffect(() => {
@@ -125,6 +152,7 @@ export const Pagination = (props: PaginationProps) => {
125
152
  setPrevPage(1);
126
153
  setNextPage(1);
127
154
  }
155
+ // eslint-disable-next-line react-hooks/exhaustive-deps
128
156
  }, [page]);
129
157
 
130
158
  useEffect(() => {
@@ -155,11 +183,77 @@ export const Pagination = (props: PaginationProps) => {
155
183
  return <>{render(pagination)}</>;
156
184
  }
157
185
 
186
+ // Custom styles for pagination container
187
+ const containerStyles: React.CSSProperties = {
188
+ marginTop: customStyles?.marginTop || '32px',
189
+ marginBottom: customStyles?.marginBottom || '16px',
190
+ gap: customStyles?.pageGap || '8px'
191
+ };
192
+
193
+ // Custom styles for page links (button-like)
194
+ const pageStyles: React.CSSProperties = {
195
+ fontSize: customStyles?.pageFontSize || '14px',
196
+ color: customStyles?.pageColor || '#9ca3af',
197
+ backgroundColor: customStyles?.pageBgColor || 'transparent',
198
+ paddingLeft: customStyles?.pagePaddingX || '8px',
199
+ paddingRight: customStyles?.pagePaddingX || '8px',
200
+ paddingTop: customStyles?.pagePaddingY || '4px',
201
+ paddingBottom: customStyles?.pagePaddingY || '4px',
202
+ borderRadius: customStyles?.pageBorderRadius || '0px',
203
+ borderWidth: customStyles?.pageBorderWidth || '0px',
204
+ borderStyle: 'solid',
205
+ borderColor: customStyles?.pageBorderColor || '#e5e7eb',
206
+ display: 'flex',
207
+ alignItems: 'center',
208
+ justifyContent: 'center'
209
+ };
210
+
211
+ const activePageStyles: React.CSSProperties = {
212
+ fontSize: customStyles?.pageFontSize || '14px',
213
+ color: customStyles?.pageActiveColor || '#1a1a1a',
214
+ fontWeight: customStyles?.pageActiveFontWeight || '600',
215
+ backgroundColor: customStyles?.pageActiveBgColor || 'transparent',
216
+ paddingLeft: customStyles?.pagePaddingX || '8px',
217
+ paddingRight: customStyles?.pagePaddingX || '8px',
218
+ paddingTop: customStyles?.pagePaddingY || '4px',
219
+ paddingBottom: customStyles?.pagePaddingY || '4px',
220
+ borderRadius: customStyles?.pageBorderRadius || '0px',
221
+ borderWidth: customStyles?.pageBorderWidth || '0px',
222
+ borderStyle: 'solid',
223
+ borderColor: customStyles?.pageActiveBorderColor || '#1a1a1a',
224
+ display: 'flex',
225
+ alignItems: 'center',
226
+ justifyContent: 'center'
227
+ };
228
+
229
+ const arrowStyles: React.CSSProperties = {
230
+ color: customStyles?.arrowColor || '#1a1a1a'
231
+ };
232
+
233
+ // Custom styles for more button
234
+ const buttonStyles: React.CSSProperties = {
235
+ backgroundColor: customStyles?.buttonBgColor || '#000000',
236
+ color: customStyles?.buttonTextColor || '#ffffff',
237
+ borderRadius: customStyles?.buttonBorderRadius || '4px',
238
+ paddingLeft: customStyles?.buttonPaddingX || '20px',
239
+ paddingRight: customStyles?.buttonPaddingX || '20px',
240
+ paddingTop: customStyles?.buttonPaddingY || '12px',
241
+ paddingBottom: customStyles?.buttonPaddingY || '12px'
242
+ };
243
+
158
244
  return direction === 'prev' && type !== 'list' ? (
159
245
  <>
160
- <div className="flex items-center justify-center">
246
+ <div
247
+ className="flex items-center justify-center"
248
+ style={{
249
+ marginTop: customStyles?.marginTop,
250
+ marginBottom: customStyles?.marginBottom
251
+ }}
252
+ data-section-id="pagination-section"
253
+ >
161
254
  <Button
162
255
  className={twMerge('px-5', moreButtonClassName)}
256
+ style={buttonStyles}
163
257
  onClick={() => handlePageChange()}
164
258
  >
165
259
  {isLoading ? (
@@ -173,15 +267,26 @@ export const Pagination = (props: PaginationProps) => {
173
267
  ) : (
174
268
  <>
175
269
  {type === 'more' && (
176
- <div className="flex items-center justify-center">
270
+ <div
271
+ className="flex items-center justify-center"
272
+ style={{
273
+ marginTop: customStyles?.marginTop,
274
+ marginBottom: customStyles?.marginBottom
275
+ }}
276
+ data-section-id="pagination-section"
277
+ >
177
278
  <Button
178
279
  className={twMerge(
179
- 'px-5',
180
- Number(nextPage) === Number(last)
181
- ? 'bg-gray-600 border-gray-600 pointer-events-none'
182
- : 'bg-black',
280
+ Number(nextPage) === Number(last) ? 'pointer-events-none' : '',
183
281
  moreButtonClassName
184
282
  )}
283
+ style={{
284
+ ...buttonStyles,
285
+ backgroundColor:
286
+ Number(nextPage) === Number(last)
287
+ ? '#6b7280'
288
+ : customStyles?.buttonBgColor || '#000000'
289
+ }}
185
290
  onClick={() => handlePageChange()}
186
291
  disabled={Number(nextPage) === Number(last)}
187
292
  >
@@ -209,9 +314,11 @@ export const Pagination = (props: PaginationProps) => {
209
314
  {type === 'list' && (
210
315
  <ul
211
316
  className={twMerge(
212
- 'mb-4 mt-8 flex items-center justify-center',
317
+ 'flex items-center justify-center',
213
318
  containerClassName
214
319
  )}
320
+ style={containerStyles}
321
+ data-section-id="pagination-section"
215
322
  >
216
323
  {prev && currentPage !== 1 && (
217
324
  <li>
@@ -219,9 +326,10 @@ export const Pagination = (props: PaginationProps) => {
219
326
  onClick={(e) => handleClick(e, prev)}
220
327
  href={prev}
221
328
  className={twMerge(
222
- 'flex cursor-pointer px-2 text-sm items-center',
329
+ 'flex cursor-pointer px-2 items-center',
223
330
  prevClassName
224
331
  )}
332
+ style={arrowStyles}
225
333
  >
226
334
  <span>&lt;</span>
227
335
  <span className="ms-4 hidden lg:inline-block">
@@ -238,20 +346,24 @@ export const Pagination = (props: PaginationProps) => {
238
346
  onClick={(e) => handleClick(e, item.url)}
239
347
  href={item.url}
240
348
  className={twMerge(
241
- clsx(
242
- 'cursor-pointer px-2 text-xs items-center',
243
- { 'pointer-events-none': item.url === null },
244
- Number(page) === Number(item?.page)
245
- ? 'font-semibold text-black-800'
246
- : 'text-gray-400'
247
- ),
349
+ clsx('cursor-pointer px-2 items-center', {
350
+ 'pointer-events-none': item.url === null
351
+ }),
248
352
  pageClassName
249
353
  )}
354
+ style={
355
+ Number(page) === Number(item?.page)
356
+ ? activePageStyles
357
+ : pageStyles
358
+ }
250
359
  >
251
360
  {item?.page}
252
361
  </Link>
253
362
  ) : (
254
- <span className="flex cursor-default items-center justify-center text-xs">
363
+ <span
364
+ className="flex cursor-default items-center justify-center"
365
+ style={pageStyles}
366
+ >
255
367
  {item?.page}
256
368
  </span>
257
369
  )}
@@ -264,9 +376,10 @@ export const Pagination = (props: PaginationProps) => {
264
376
  onClick={(e) => handleClick(e, next)}
265
377
  href={next}
266
378
  className={twMerge(
267
- 'flex cursor-pointer px-2 text-xs items-center',
379
+ 'flex cursor-pointer px-2 items-center',
268
380
  nextClassName
269
381
  )}
382
+ style={arrowStyles}
270
383
  >
271
384
  <span className="me-4 hidden lg:inline-block">
272
385
  {t('category.pagination.next')}
@@ -56,7 +56,7 @@ export const Price = (props: NumericFormatProps & PriceProps) => {
56
56
 
57
57
  const currentCurrencyDecimalScale = Settings.localization.currencies.find(
58
58
  (currency) => currency.code === currencyCode_
59
- ).decimalScale;
59
+ )?.decimalScale;
60
60
 
61
61
  return (
62
62
  <NumericFormat
@@ -2,6 +2,7 @@ import { Metadata } from '@akinon/next/types';
2
2
 
3
3
  const pwaTags: Metadata = {
4
4
  manifest: '/manifest.json',
5
+ themeColor: '#FFFFFF',
5
6
  formatDetection: {
6
7
  telephone: false
7
8
  },
@@ -0,0 +1,63 @@
1
+ import { Button, Icon, LoaderSpinner } from '@theme/components';
2
+
3
+ interface QuantityInputProps {
4
+ quantity: number;
5
+ onChange?: (newQuantity: number) => void;
6
+ min?: number;
7
+ max?: number;
8
+ isLoading?: boolean;
9
+ disabled?: boolean;
10
+ className?: string;
11
+ }
12
+
13
+ export const QuantityInput = ({
14
+ quantity,
15
+ onChange,
16
+ min = 1,
17
+ max = 999,
18
+ isLoading = false,
19
+ disabled = false,
20
+ className = ''
21
+ }: QuantityInputProps) => {
22
+ const handleDecrease = () => {
23
+ if (quantity > min && onChange) {
24
+ onChange(quantity - 1);
25
+ }
26
+ };
27
+
28
+ const handleIncrease = () => {
29
+ if (quantity < max && onChange) {
30
+ onChange(quantity + 1);
31
+ }
32
+ };
33
+
34
+ return (
35
+ <div
36
+ className={`w-[138px] h-11 flex items-center justify-between border p-4 ${className}`}
37
+ >
38
+ <Button
39
+ className="h-auto p-0 hover:bg-transparent hover:text-black"
40
+ appearance="ghost"
41
+ onClick={handleDecrease}
42
+ disabled={disabled || isLoading || quantity <= min}
43
+ >
44
+ <Icon name="minus" size={12} />
45
+ </Button>
46
+ <div>
47
+ {isLoading ? (
48
+ <LoaderSpinner className="w-4 h-4" />
49
+ ) : (
50
+ <span>{quantity}</span>
51
+ )}
52
+ </div>
53
+ <Button
54
+ className="h-auto p-0 hover:bg-transparent hover:text-black"
55
+ appearance="ghost"
56
+ onClick={handleIncrease}
57
+ disabled={disabled || isLoading || quantity >= max}
58
+ >
59
+ <Icon name="plus" size={12} />
60
+ </Button>
61
+ </div>
62
+ );
63
+ };