@salla.sa/twilight-theme-engine 1.0.85 → 1.0.86

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 (372) hide show
  1. package/dist/{AddToCartForm-B5C2M4OZ.js → AddToCartForm-5X2WZDWR.js} +3 -3
  2. package/dist/{AddToCartForm-B5C2M4OZ.js.map → AddToCartForm-5X2WZDWR.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-GTF4UGSS.js → BlogAuthorPage-LO7FSSJR.js} +12 -10
  4. package/dist/BlogAuthorPage-LO7FSSJR.js.map +1 -0
  5. package/dist/{BlogCategoryPage-TN7Y4NBP.js → BlogCategoryPage-KKFQ3PGR.js} +12 -10
  6. package/dist/BlogCategoryPage-KKFQ3PGR.js.map +1 -0
  7. package/dist/{BlogPage-TDB3M3PI.js → BlogPage-VLF3NSGE.js} +11 -9
  8. package/dist/BlogPage-VLF3NSGE.js.map +1 -0
  9. package/dist/{BlogSinglePage-4A52Q5QW.js → BlogSinglePage-AVK535IW.js} +11 -9
  10. package/dist/BlogSinglePage-AVK535IW.js.map +1 -0
  11. package/dist/{BlogTagPage-TOVPBETA.js → BlogTagPage-F3T4D7RH.js} +12 -10
  12. package/dist/BlogTagPage-F3T4D7RH.js.map +1 -0
  13. package/dist/{BrandsPage-VUDGYSQI.js → BrandsPage-LVSBZSVC.js} +11 -9
  14. package/dist/BrandsPage-LVSBZSVC.js.map +1 -0
  15. package/dist/{Breadcrumb-CI3SN5YR.js → Breadcrumb-VLFTXRFC.js} +11 -9
  16. package/dist/Breadcrumb-VLFTXRFC.js.map +1 -0
  17. package/dist/{CartItem-BHLEURAB.js → CartItem-G3H34GW6.js} +11 -9
  18. package/dist/CartItem-G3H34GW6.js.map +1 -0
  19. package/dist/{CartSummary-QERVESYN.js → CartSummary-VH37RPUI.js} +11 -9
  20. package/dist/CartSummary-VH37RPUI.js.map +1 -0
  21. package/dist/{Copyright-RL6ALKRC.js → Copyright-HE5ZWINZ.js} +3 -3
  22. package/dist/{Copyright-RL6ALKRC.js.map → Copyright-HE5ZWINZ.js.map} +1 -1
  23. package/dist/{CustomerLayout-VRZUWGQK.js → CustomerLayout-LKBLOAVW.js} +11 -9
  24. package/dist/CustomerLayout-LKBLOAVW.js.map +1 -0
  25. package/dist/{Footer-ZWBZCMDL.js → Footer-HHXAST72.js} +5 -5
  26. package/dist/{Footer-ZWBZCMDL.js.map → Footer-HHXAST72.js.map} +1 -1
  27. package/dist/{Header-WNK4O66B.js → Header-GEVZM2YG.js} +8 -6
  28. package/dist/{Header-WNK4O66B.js.map → Header-GEVZM2YG.js.map} +1 -1
  29. package/dist/{LoyaltyPage-CGTHWJ76.js → LoyaltyPage-M5CT3CFD.js} +11 -9
  30. package/dist/LoyaltyPage-M5CT3CFD.js.map +1 -0
  31. package/dist/{LoyaltyPointsPage-QSU6K3PW.js → LoyaltyPointsPage-SDJB52U6.js} +10 -3
  32. package/dist/LoyaltyPointsPage-SDJB52U6.js.map +1 -0
  33. package/dist/{MainMenu-V3T7F32R.js → MainMenu-I7EYS752.js} +3 -3
  34. package/dist/{MainMenu-V3T7F32R.js.map → MainMenu-I7EYS752.js.map} +1 -1
  35. package/dist/{MasterLayout-XQF644LD.js → MasterLayout-QDK4T3NE.js} +11 -9
  36. package/dist/{MasterLayout-XQF644LD.js.map → MasterLayout-QDK4T3NE.js.map} +1 -1
  37. package/dist/{MobileMenu-U4BVQYKH.js → MobileMenu-7VTCWAVJ.js} +11 -9
  38. package/dist/MobileMenu-7VTCWAVJ.js.map +1 -0
  39. package/dist/{NotificationsPage-ZRRQY7TF.js → NotificationsPage-QCABE6QD.js} +11 -9
  40. package/dist/NotificationsPage-QCABE6QD.js.map +1 -0
  41. package/dist/{OrderSinglePage-O3XYVMG5.js → OrderSinglePage-2HVBKBG4.js} +11 -9
  42. package/dist/OrderSinglePage-2HVBKBG4.js.map +1 -0
  43. package/dist/{OrdersPage-CMXZF5MI.js → OrdersPage-5MNCPCM3.js} +11 -9
  44. package/dist/OrdersPage-5MNCPCM3.js.map +1 -0
  45. package/dist/{PageSingle-IIG2US43.js → PageSingle-EN5XIM2B.js} +3 -3
  46. package/dist/{PageSingle-IIG2US43.js.map → PageSingle-EN5XIM2B.js.map} +1 -1
  47. package/dist/{ProductDetails-65GDABI7.js → ProductDetails-UEWQPPDZ.js} +13 -6
  48. package/dist/ProductDetails-UEWQPPDZ.js.map +1 -0
  49. package/dist/{ProfilePage-SNJ4WXU4.js → ProfilePage-TZSU3GHZ.js} +11 -9
  50. package/dist/ProfilePage-TZSU3GHZ.js.map +1 -0
  51. package/dist/{ReviewsPage-UT7UT55J.js → ReviewsPage-WYZ6CHF2.js} +3 -3
  52. package/dist/{ReviewsPage-UT7UT55J.js.map → ReviewsPage-WYZ6CHF2.js.map} +1 -1
  53. package/dist/{SeoCartWidget-DBJAXJKT.js → SeoCartWidget-5JR5RXQM.js} +11 -9
  54. package/dist/SeoCartWidget-5JR5RXQM.js.map +1 -0
  55. package/dist/{SettingsPage-FLTIOPU5.js → SettingsPage-DIDRQXMM.js} +11 -9
  56. package/dist/SettingsPage-DIDRQXMM.js.map +1 -0
  57. package/dist/{StoreClosedNotification-ZT3QKDKS.js → StoreClosedNotification-C2G32E34.js} +12 -10
  58. package/dist/{StoreClosedNotification-ZT3QKDKS.js.map → StoreClosedNotification-C2G32E34.js.map} +1 -1
  59. package/dist/{TestimonialsPage-CU7HKU4O.js → TestimonialsPage-XPHFRBZ7.js} +3 -3
  60. package/dist/{TestimonialsPage-CU7HKU4O.js.map → TestimonialsPage-XPHFRBZ7.js.map} +1 -1
  61. package/dist/{ThankYouPage-5X6B4X3T.js → ThankYouPage-UA6YYFB2.js} +11 -9
  62. package/dist/ThankYouPage-UA6YYFB2.js.map +1 -0
  63. package/dist/{WalletPage-H2BKIDPA.js → WalletPage-AJVV7LVL.js} +11 -9
  64. package/dist/WalletPage-AJVV7LVL.js.map +1 -0
  65. package/dist/{WishlistPage-RS5UCIQ3.js → WishlistPage-UW6LJLSW.js} +11 -9
  66. package/dist/WishlistPage-UW6LJLSW.js.map +1 -0
  67. package/dist/api/advertisement.d.ts +33 -0
  68. package/dist/api/advertisement.d.ts.map +1 -0
  69. package/dist/api/advertisement.js +8 -0
  70. package/dist/api/advertisement.js.map +1 -0
  71. package/dist/boot/critical-style.d.ts +3 -0
  72. package/dist/boot/critical-style.d.ts.map +1 -0
  73. package/dist/boot/index.d.ts +15 -0
  74. package/dist/boot/index.d.ts.map +1 -0
  75. package/dist/boot.d.ts +1 -0
  76. package/dist/boot.js +69 -0
  77. package/dist/boot.js.map +1 -0
  78. package/dist/{chunk-SE5JYWOK.js → chunk-2HCCIHU7.js} +4 -4
  79. package/dist/{chunk-SE5JYWOK.js.map → chunk-2HCCIHU7.js.map} +1 -1
  80. package/dist/chunk-4FJGZQD3.js +6 -0
  81. package/dist/chunk-4FJGZQD3.js.map +1 -0
  82. package/dist/{chunk-SDFDS4Q3.js → chunk-4WVJJ7SN.js} +20 -4
  83. package/dist/chunk-4WVJJ7SN.js.map +1 -0
  84. package/dist/{chunk-NXQJA7D3.js → chunk-BAYGWTNM.js} +3 -3
  85. package/dist/{chunk-NXQJA7D3.js.map → chunk-BAYGWTNM.js.map} +1 -1
  86. package/dist/{chunk-OWX2CPNQ.js → chunk-CLBFF2CY.js} +3 -3
  87. package/dist/{chunk-OWX2CPNQ.js.map → chunk-CLBFF2CY.js.map} +1 -1
  88. package/dist/chunk-DBW7XXNE.js +103 -0
  89. package/dist/chunk-DBW7XXNE.js.map +1 -0
  90. package/dist/{chunk-KHBSGD2D.js → chunk-DBXH3EMJ.js} +3 -3
  91. package/dist/{chunk-KHBSGD2D.js.map → chunk-DBXH3EMJ.js.map} +1 -1
  92. package/dist/{chunk-JRNH3FUF.js → chunk-E26YG3AO.js} +4 -4
  93. package/dist/{chunk-JRNH3FUF.js.map → chunk-E26YG3AO.js.map} +1 -1
  94. package/dist/{chunk-22SH7OVF.js → chunk-E7WWO3V3.js} +3 -3
  95. package/dist/{chunk-22SH7OVF.js.map → chunk-E7WWO3V3.js.map} +1 -1
  96. package/dist/{chunk-UJKFBZFJ.js → chunk-HQ7WA37L.js} +7 -7
  97. package/dist/{chunk-UJKFBZFJ.js.map → chunk-HQ7WA37L.js.map} +1 -1
  98. package/dist/chunk-IVBOLREE.js +29 -0
  99. package/dist/chunk-IVBOLREE.js.map +1 -0
  100. package/dist/{chunk-6SWDSRIL.js → chunk-KP3VYG4F.js} +6 -6
  101. package/dist/{chunk-6SWDSRIL.js.map → chunk-KP3VYG4F.js.map} +1 -1
  102. package/dist/{chunk-4CZRUAZB.js → chunk-PWTXR4RR.js} +10 -10
  103. package/dist/{chunk-4CZRUAZB.js.map → chunk-PWTXR4RR.js.map} +1 -1
  104. package/dist/chunk-QJYUTRAQ.js +14 -0
  105. package/dist/{chunk-7WAXN2PP.js.map → chunk-QJYUTRAQ.js.map} +1 -1
  106. package/dist/{chunk-JO7JWV34.js → chunk-U55ZJC2X.js} +4 -4
  107. package/dist/{chunk-JO7JWV34.js.map → chunk-U55ZJC2X.js.map} +1 -1
  108. package/dist/{chunk-SX5MF2YA.js → chunk-WSDG4ZRI.js} +4 -4
  109. package/dist/{chunk-SX5MF2YA.js.map → chunk-WSDG4ZRI.js.map} +1 -1
  110. package/dist/{chunk-NZVR4OF7.js → chunk-X54QP332.js} +8 -8
  111. package/dist/chunk-X54QP332.js.map +1 -0
  112. package/dist/components/cart/index.js +1 -1
  113. package/dist/components/common/index.js +1 -1
  114. package/dist/components/drawer/index.js +9 -7
  115. package/dist/components/home/index.js +11 -9
  116. package/dist/components/layout/PageAdvertisements.d.ts +7 -0
  117. package/dist/components/layout/PageAdvertisements.d.ts.map +1 -0
  118. package/dist/components/layout/index.d.ts +1 -0
  119. package/dist/components/layout/index.d.ts.map +1 -1
  120. package/dist/components/layout/index.js +8 -1
  121. package/dist/components/product/index.js +10 -8
  122. package/dist/components/store/index.js +11 -9
  123. package/dist/components/store/index.js.map +1 -1
  124. package/dist/{document-class-67HTP45G.js → document-class-7AXAAWGZ.js} +6 -5
  125. package/dist/{document-class-67HTP45G.js.map → document-class-7AXAAWGZ.js.map} +1 -1
  126. package/dist/hooks/index.js +9 -7
  127. package/dist/hooks/useGtm.js +9 -7
  128. package/dist/hooks/useMoney.js +9 -7
  129. package/dist/hooks/useStore.js +9 -7
  130. package/dist/index.js +9 -7
  131. package/dist/index.js.map +1 -1
  132. package/dist/{not-found-QTHBFPNT.js → not-found-3EEMQZMU.js} +11 -9
  133. package/dist/not-found-3EEMQZMU.js.map +1 -0
  134. package/dist/providers/index.js +9 -7
  135. package/dist/routes/account/orders.js +1 -1
  136. package/dist/routes/account.js +6 -6
  137. package/dist/routes/blog.js +5 -5
  138. package/dist/routes/brands.js +1 -1
  139. package/dist/routes/cart.js +13 -11
  140. package/dist/routes/cart.js.map +1 -1
  141. package/dist/routes/home.js +12 -10
  142. package/dist/routes/loyalty.js +2 -2
  143. package/dist/routes/page.js +1 -1
  144. package/dist/routes/product-listing.js +11 -9
  145. package/dist/routes/product-listing.js.map +1 -1
  146. package/dist/routes/product.js +11 -9
  147. package/dist/routes/product.js.map +1 -1
  148. package/dist/routes/root/beforeLoad.d.ts +2 -2
  149. package/dist/routes/root/beforeLoad.d.ts.map +1 -1
  150. package/dist/routes/root/head.d.ts.map +1 -1
  151. package/dist/routes/testimonials.js +2 -2
  152. package/dist/routes/thank-you.js +1 -1
  153. package/dist/skeleton.js +12 -10
  154. package/dist/tanstack/document-class.d.ts.map +1 -1
  155. package/dist/tanstack/index.d.ts +1 -0
  156. package/dist/tanstack/index.d.ts.map +1 -1
  157. package/dist/tanstack/stylesheet.d.ts +15 -0
  158. package/dist/tanstack/stylesheet.d.ts.map +1 -0
  159. package/dist/tanstack.js +34 -5
  160. package/dist/tanstack.js.map +1 -1
  161. package/dist/utils/index.js +1 -1
  162. package/dist/vite/index.js +1 -1
  163. package/package.json +12 -3
  164. package/tailwind/components/Component.tsx.txt +21 -0
  165. package/tailwind/components/ComponentRegistry.ts.txt +66 -0
  166. package/tailwind/components/cart/CartItem.tsx.txt +211 -0
  167. package/tailwind/components/cart/CartSummary.tsx.txt +269 -0
  168. package/tailwind/components/cart/PreOrderNotification.tsx.txt +16 -0
  169. package/tailwind/components/cart/PriceQuoteButton.tsx.txt +21 -0
  170. package/tailwind/components/cart/SeoCartWidget.tsx.txt +99 -0
  171. package/tailwind/components/cart/index.ts.txt +11 -0
  172. package/tailwind/components/cart/lazy.ts.txt +15 -0
  173. package/tailwind/components/collapse/Collapse.tsx.txt +95 -0
  174. package/tailwind/components/collapse/index.ts.txt +41 -0
  175. package/tailwind/components/common/Breadcrumb.tsx.txt +27 -0
  176. package/tailwind/components/common/BreadcrumbJsonLd.tsx.txt +40 -0
  177. package/tailwind/components/common/BreadcrumbTrail.tsx.txt +97 -0
  178. package/tailwind/components/common/CurrencySymbol.tsx.txt +8 -0
  179. package/tailwind/components/common/DeferredData.tsx.txt +122 -0
  180. package/tailwind/components/common/ErrorPage.tsx.txt +69 -0
  181. package/tailwind/components/common/Image.tsx.txt +119 -0
  182. package/tailwind/components/common/Link.tsx.txt +36 -0
  183. package/tailwind/components/common/Link.types.ts.txt +85 -0
  184. package/tailwind/components/common/NoContent.tsx.txt +27 -0
  185. package/tailwind/components/common/RenderWhenVisible.tsx.txt +92 -0
  186. package/tailwind/components/common/index.ts.txt +42 -0
  187. package/tailwind/components/common/lazy.ts.txt +28 -0
  188. package/tailwind/components/defineComponent.ts.txt +32 -0
  189. package/tailwind/components/drawer/Drawer.tsx.txt +219 -0
  190. package/tailwind/components/drawer/index.ts.txt +38 -0
  191. package/tailwind/components/dropdown/Dropdown.tsx.txt +166 -0
  192. package/tailwind/components/dropdown/index.ts.txt +40 -0
  193. package/tailwind/components/home/BundleComponent.tsx.txt +35 -0
  194. package/tailwind/components/home/ComponentErrorBoundary.tsx.txt +98 -0
  195. package/tailwind/components/home/FeaturedProductsStyle1.tsx.txt +125 -0
  196. package/tailwind/components/home/FeaturedProductsStyle2.tsx.txt +127 -0
  197. package/tailwind/components/home/FeaturedProductsStyle3.tsx.txt +71 -0
  198. package/tailwind/components/home/FixedBanner.tsx.txt +68 -0
  199. package/tailwind/components/home/FixedProducts.tsx.txt +72 -0
  200. package/tailwind/components/home/HomePageRenderer.tsx.txt +284 -0
  201. package/tailwind/components/home/PageBlocks.tsx.txt +24 -0
  202. package/tailwind/components/home/ParallaxBackground.tsx.txt +50 -0
  203. package/tailwind/components/home/PhotosSlider.tsx.txt +61 -0
  204. package/tailwind/components/home/ProductsSlider.tsx.txt +87 -0
  205. package/tailwind/components/home/ReorderProducts.tsx.txt +38 -0
  206. package/tailwind/components/home/SquarePhotos.tsx.txt +68 -0
  207. package/tailwind/components/home/StoreFeatures.tsx.txt +34 -0
  208. package/tailwind/components/home/Testimonials.tsx.txt +36 -0
  209. package/tailwind/components/home/Youtube.tsx.txt +48 -0
  210. package/tailwind/components/home/index.ts.txt +50 -0
  211. package/tailwind/components/home/lazy.ts.txt +17 -0
  212. package/tailwind/components/home/register.ts.txt +44 -0
  213. package/tailwind/components/home/reorder-hooks.ts.txt +52 -0
  214. package/tailwind/components/home/types.ts.txt +4 -0
  215. package/tailwind/components/layout/Copyright.tsx.txt +23 -0
  216. package/tailwind/components/layout/CustomerLayout.tsx.txt +91 -0
  217. package/tailwind/components/layout/Footer.tsx.txt +343 -0
  218. package/tailwind/components/layout/Header.tsx.txt +154 -0
  219. package/tailwind/components/layout/MasterLayout.tsx.txt +63 -0
  220. package/tailwind/components/layout/PageAdvertisements.tsx.txt +131 -0
  221. package/tailwind/components/layout/WidgetHead.tsx.txt +53 -0
  222. package/tailwind/components/layout/index.ts.txt +27 -0
  223. package/tailwind/components/layout/lazy.ts.txt +25 -0
  224. package/tailwind/components/layout/types.ts.txt +11 -0
  225. package/tailwind/components/modal/ImageModal.tsx.txt +70 -0
  226. package/tailwind/components/modal/Modal.tsx.txt +245 -0
  227. package/tailwind/components/modal/index.ts.txt +39 -0
  228. package/tailwind/components/modal/lazy.ts.txt +10 -0
  229. package/tailwind/components/navigation/MainMenu.tsx.txt +94 -0
  230. package/tailwind/components/navigation/MobileMenu.tsx.txt +160 -0
  231. package/tailwind/components/navigation/index.ts.txt +4 -0
  232. package/tailwind/components/navigation/lazy.ts.txt +11 -0
  233. package/tailwind/components/product/AddToCartForm.tsx.txt +365 -0
  234. package/tailwind/components/product/ProductCard.tsx.txt +305 -0
  235. package/tailwind/components/product/ProductDetails.tsx.txt +267 -0
  236. package/tailwind/components/product/ProductGallery.tsx.txt +234 -0
  237. package/tailwind/components/product/index.ts.txt +15 -0
  238. package/tailwind/components/product/lazy.ts.txt +9 -0
  239. package/tailwind/components/snippets/AppsSnippets.tsx.txt +225 -0
  240. package/tailwind/components/snippets/SallaSdkScripts.tsx.txt +14 -0
  241. package/tailwind/components/snippets/index.ts.txt +4 -0
  242. package/tailwind/components/store/StoreClosedNotification.tsx.txt +73 -0
  243. package/tailwind/components/store/index.ts.txt +8 -0
  244. package/tailwind/components/store/lazy.ts.txt +8 -0
  245. package/tailwind/components/toast/Toaster.tsx.txt +177 -0
  246. package/tailwind/components/toast/index.ts.txt +10 -0
  247. package/tailwind/components/toast/types.ts.txt +38 -0
  248. package/tailwind/components/toast/useToast.ts.txt +61 -0
  249. package/tailwind/components/tracking/GoogleTag.tsx.txt +77 -0
  250. package/tailwind/components/tracking/SiftSnippet.tsx.txt +49 -0
  251. package/tailwind/components/tracking/TwilightBundles.tsx.txt +67 -0
  252. package/tailwind/components/tracking/index.ts.txt +11 -0
  253. package/tailwind/components/tracking/lazy.ts.txt +11 -0
  254. package/tailwind/components/useComponent.ts.txt +12 -0
  255. package/tailwind/routes/account/index.tsx.txt +16 -0
  256. package/tailwind/routes/account/notifications/NotificationsPage.tsx.txt +54 -0
  257. package/tailwind/routes/account/notifications/index.tsx.txt +39 -0
  258. package/tailwind/routes/account/notifications/loader.ts.txt +22 -0
  259. package/tailwind/routes/account/notifications/types.ts.txt +18 -0
  260. package/tailwind/routes/account/orders/OrderSinglePage.tsx.txt +181 -0
  261. package/tailwind/routes/account/orders/OrdersPage.tsx.txt +28 -0
  262. package/tailwind/routes/account/orders/index.tsx.txt +86 -0
  263. package/tailwind/routes/account/orders/loader.ts.txt +66 -0
  264. package/tailwind/routes/account/orders/single/OrderActions.tsx.txt +197 -0
  265. package/tailwind/routes/account/orders/single/OrderHeader.tsx.txt +143 -0
  266. package/tailwind/routes/account/orders/single/OrderItemRow.tsx.txt +209 -0
  267. package/tailwind/routes/account/orders/single/OrderSections.tsx.txt +215 -0
  268. package/tailwind/routes/account/orders/single/types.ts.txt +38 -0
  269. package/tailwind/routes/account/orders/types.ts.txt +29 -0
  270. package/tailwind/routes/account/profile/ProfilePage.tsx.txt +30 -0
  271. package/tailwind/routes/account/profile/index.tsx.txt +39 -0
  272. package/tailwind/routes/account/profile/loader.ts.txt +16 -0
  273. package/tailwind/routes/account/profile/types.ts.txt +5 -0
  274. package/tailwind/routes/account/settings/SettingsPage.tsx.txt +13 -0
  275. package/tailwind/routes/account/settings/index.tsx.txt +39 -0
  276. package/tailwind/routes/account/settings/loader.ts.txt +13 -0
  277. package/tailwind/routes/account/settings/types.ts.txt +5 -0
  278. package/tailwind/routes/account/types.ts.txt +320 -0
  279. package/tailwind/routes/account/wallet/WalletPage.tsx.txt +195 -0
  280. package/tailwind/routes/account/wallet/index.tsx.txt +38 -0
  281. package/tailwind/routes/account/wallet/loader.ts.txt +27 -0
  282. package/tailwind/routes/account/wallet/types.ts.txt +11 -0
  283. package/tailwind/routes/account/wishlist/WishlistPage.tsx.txt +314 -0
  284. package/tailwind/routes/account/wishlist/WishlistShare.tsx.txt +248 -0
  285. package/tailwind/routes/account/wishlist/index.tsx.txt +40 -0
  286. package/tailwind/routes/account/wishlist/loader.ts.txt +26 -0
  287. package/tailwind/routes/account/wishlist/types.ts.txt +9 -0
  288. package/tailwind/routes/blog/BlogAuthorPage.tsx.txt +82 -0
  289. package/tailwind/routes/blog/BlogCategoryPage.tsx.txt +84 -0
  290. package/tailwind/routes/blog/BlogPage.tsx.txt +191 -0
  291. package/tailwind/routes/blog/BlogSinglePage.tsx.txt +168 -0
  292. package/tailwind/routes/blog/BlogTagPage.tsx.txt +84 -0
  293. package/tailwind/routes/blog/BlogTags.tsx.txt +54 -0
  294. package/tailwind/routes/blog/components.tsx.txt +87 -0
  295. package/tailwind/routes/blog/index.tsx.txt +238 -0
  296. package/tailwind/routes/blog/loader.ts.txt +173 -0
  297. package/tailwind/routes/blog/types.ts.txt +106 -0
  298. package/tailwind/routes/brands/BrandsPage.tsx.txt +179 -0
  299. package/tailwind/routes/brands/index.tsx.txt +47 -0
  300. package/tailwind/routes/brands/loader.ts.txt +14 -0
  301. package/tailwind/routes/brands/types.ts.txt +53 -0
  302. package/tailwind/routes/cart/CartPage.tsx.txt +112 -0
  303. package/tailwind/routes/cart/index.tsx.txt +39 -0
  304. package/tailwind/routes/cart/loader.ts.txt +15 -0
  305. package/tailwind/routes/cart/types.ts.txt +6 -0
  306. package/tailwind/routes/home/HomePage.tsx.txt +53 -0
  307. package/tailwind/routes/home/index.tsx.txt +56 -0
  308. package/tailwind/routes/home/loader.ts.txt +24 -0
  309. package/tailwind/routes/home/types.ts.txt +11 -0
  310. package/tailwind/routes/index.ts.txt +94 -0
  311. package/tailwind/routes/lazy.ts.txt +105 -0
  312. package/tailwind/routes/loyalty/LoyaltyPage.tsx.txt +17 -0
  313. package/tailwind/routes/loyalty/LoyaltyPointsPage.tsx.txt +11 -0
  314. package/tailwind/routes/loyalty/index.tsx.txt +81 -0
  315. package/tailwind/routes/loyalty/loader.ts.txt +53 -0
  316. package/tailwind/routes/loyalty/types.ts.txt +109 -0
  317. package/tailwind/routes/not-found.tsx.txt +50 -0
  318. package/tailwind/routes/page/PageSingle.tsx.txt +34 -0
  319. package/tailwind/routes/page/index.tsx.txt +60 -0
  320. package/tailwind/routes/page/loader.ts.txt +19 -0
  321. package/tailwind/routes/page/types.ts.txt +34 -0
  322. package/tailwind/routes/product/ProductPage.tsx.txt +77 -0
  323. package/tailwind/routes/product/index.tsx.txt +157 -0
  324. package/tailwind/routes/product/loader.ts.txt +35 -0
  325. package/tailwind/routes/product/types.ts.txt +6 -0
  326. package/tailwind/routes/product-listing/ProductListPage.tsx.txt +321 -0
  327. package/tailwind/routes/product-listing/index.tsx.txt +95 -0
  328. package/tailwind/routes/product-listing/loader.ts.txt +323 -0
  329. package/tailwind/routes/product-listing/types.ts.txt +96 -0
  330. package/tailwind/routes/product-listing/useAppliedFilters.ts.txt +130 -0
  331. package/tailwind/routes/product-short-link.ts.txt +104 -0
  332. package/tailwind/routes/root/beforeLoad.ts.txt +354 -0
  333. package/tailwind/routes/root/head.ts.txt +424 -0
  334. package/tailwind/routes/root/index.ts.txt +2 -0
  335. package/tailwind/routes/seo-redirects.ts.txt +82 -0
  336. package/tailwind/routes/testimonials/ReviewsPage.tsx.txt +12 -0
  337. package/tailwind/routes/testimonials/TestimonialsPage.tsx.txt +80 -0
  338. package/tailwind/routes/testimonials/index.tsx.txt +80 -0
  339. package/tailwind/routes/testimonials/loader.ts.txt +29 -0
  340. package/tailwind/routes/testimonials/types.ts.txt +9 -0
  341. package/tailwind/routes/thank-you/ThankYouPage.tsx.txt +241 -0
  342. package/tailwind/routes/thank-you/index.tsx.txt +49 -0
  343. package/tailwind/routes/thank-you/loader.ts.txt +40 -0
  344. package/tailwind/routes/thank-you/types.ts.txt +16 -0
  345. package/tailwind/routes/types.ts.txt +41 -0
  346. package/dist/BlogAuthorPage-GTF4UGSS.js.map +0 -1
  347. package/dist/BlogCategoryPage-TN7Y4NBP.js.map +0 -1
  348. package/dist/BlogPage-TDB3M3PI.js.map +0 -1
  349. package/dist/BlogSinglePage-4A52Q5QW.js.map +0 -1
  350. package/dist/BlogTagPage-TOVPBETA.js.map +0 -1
  351. package/dist/BrandsPage-VUDGYSQI.js.map +0 -1
  352. package/dist/Breadcrumb-CI3SN5YR.js.map +0 -1
  353. package/dist/CartItem-BHLEURAB.js.map +0 -1
  354. package/dist/CartSummary-QERVESYN.js.map +0 -1
  355. package/dist/CustomerLayout-VRZUWGQK.js.map +0 -1
  356. package/dist/LoyaltyPage-CGTHWJ76.js.map +0 -1
  357. package/dist/LoyaltyPointsPage-QSU6K3PW.js.map +0 -1
  358. package/dist/MobileMenu-U4BVQYKH.js.map +0 -1
  359. package/dist/NotificationsPage-ZRRQY7TF.js.map +0 -1
  360. package/dist/OrderSinglePage-O3XYVMG5.js.map +0 -1
  361. package/dist/OrdersPage-CMXZF5MI.js.map +0 -1
  362. package/dist/ProductDetails-65GDABI7.js.map +0 -1
  363. package/dist/ProfilePage-SNJ4WXU4.js.map +0 -1
  364. package/dist/SeoCartWidget-DBJAXJKT.js.map +0 -1
  365. package/dist/SettingsPage-FLTIOPU5.js.map +0 -1
  366. package/dist/ThankYouPage-5X6B4X3T.js.map +0 -1
  367. package/dist/WalletPage-H2BKIDPA.js.map +0 -1
  368. package/dist/WishlistPage-RS5UCIQ3.js.map +0 -1
  369. package/dist/chunk-7WAXN2PP.js +0 -14
  370. package/dist/chunk-NZVR4OF7.js.map +0 -1
  371. package/dist/chunk-SDFDS4Q3.js.map +0 -1
  372. package/dist/not-found-QTHBFPNT.js.map +0 -1
@@ -0,0 +1,269 @@
1
+ import { useCallback } from 'react';
2
+ import { HookSlot } from '../../hooks/HookSlot';
3
+ import { useTranslation } from '../../providers/I18nProvider';
4
+ import { useCoupon } from '../../hooks/useCoupon';
5
+ import { useMoney } from '../../hooks/useMoney';
6
+ import { stripUnsafeHtml } from '../../utils/sanitize';
7
+ import { SallaLoyalty } from '@salla.sa/twilight-components-react/loyalty';
8
+ import { SallaGifting } from '@salla.sa/twilight-components-react/gifting';
9
+ import { SallaButton } from '@salla.sa/twilight-components-react/button';
10
+ import { SallaTieredOffer } from '@salla.sa/twilight-components-react/tiered-offer';
11
+ import type { Cart } from '../../types';
12
+
13
+ interface CartSummaryProps {
14
+ cart: Cart;
15
+ applyCouponEnabled?: boolean;
16
+ taxAmount?: number;
17
+ loyalty?: Cart['loyalty'];
18
+ gift?: Cart['gift'];
19
+ loyaltyPoints?: number;
20
+ }
21
+
22
+ export function CartSummary({
23
+ cart,
24
+ applyCouponEnabled = true,
25
+ taxAmount,
26
+ loyalty,
27
+ gift,
28
+ loyaltyPoints,
29
+ }: CartSummaryProps) {
30
+ const { t } = useTranslation();
31
+ const { format } = useMoney();
32
+
33
+ const handleCartSubmit = useCallback(async () => {
34
+ // Twig's cart.js: a submit with an empty required option fails and the SDK resets the cart.
35
+ const forms = document.querySelectorAll<HTMLFormElement>('form[id^="item-"]');
36
+ if (![...forms].every((form) => form.reportValidity())) {
37
+ window.salla?.notify.error(window.salla.lang.get('common.messages.required_fields'));
38
+ return;
39
+ }
40
+ try {
41
+ await window.salla?.cart.submit();
42
+ } catch {
43
+ // Error handling
44
+ }
45
+ }, []);
46
+
47
+ return (
48
+ <div className="sticky top-24 w-full lg:w-96 rtl:lg:mr-8 ltr:lg:ml-8">
49
+ <HookSlot name="cart:summary.start" />
50
+ {cart.free_shipping_bar && <FreeShippingBar freeShippingBar={cart.free_shipping_bar} />}
51
+
52
+ {/* Twig: {% if loyalty and user.loyalty_points %} — top-level page vars rendered inside sidebar */}
53
+ {loyalty && loyaltyPoints && (
54
+ <div className="shadow-default mb-5 rounded-md p-3 xs:p-7 bg-white">
55
+ <SallaLoyalty
56
+ customerPoints={loyaltyPoints}
57
+ prizePoints={loyalty.prize.points}
58
+ prizeTitle={loyalty.prize.title}
59
+ />
60
+ </div>
61
+ )}
62
+
63
+ {/* Twig: {{gift.enabled ? '' : 'hidden'}} — top-level page var rendered inside sidebar */}
64
+ {gift?.enabled && (
65
+ <div id="cart-gifting" className="shadow-default bg-white xs:p-2 rounded-md mb-5 relative">
66
+ <SallaGifting
67
+ id="salla-gifting"
68
+ className="mt-5"
69
+ widgetTitle={t('pages.cart.gift_widget_title', 'Send as a gift')}
70
+ widgetSubtitle={gift.text}
71
+ {...(gift.type ? { [gift.type + 'Products']: true } : {})}
72
+ vertical
73
+ />
74
+ </div>
75
+ )}
76
+
77
+ <div className="shadow-default bg-white p-5 xs:p-7 rounded-md mb-5 relative transition-height duration-1000">
78
+ <h2 className="font-bold text-sm mb-5">{t('pages.cart.summary', 'Order Summary')}</h2>
79
+
80
+ <div className="flex justify-between text-sm mb-5">
81
+ <span className="text-gray-500">
82
+ {taxAmount
83
+ ? t('pages.cart.items_total_without_tax', 'Items total (excl. tax)')
84
+ : t('pages.cart.items_total', 'Items total')}
85
+ </span>
86
+ <b id="sub-total">{format(cart.sub_total)}</b>
87
+ </div>
88
+
89
+ {cart.options?.length > 0 && (
90
+ <div className="flex justify-between text-sm mb-5">
91
+ <span className="text-gray-500">
92
+ {t('pages.cart.order_options_total', 'Options total')}
93
+ </span>
94
+ <b id="cart-options-total">{format(cart.options_total ?? undefined)}</b>
95
+ </div>
96
+ )}
97
+
98
+ {cart.has_shipping && (
99
+ <div id="shipping-cost" className="flex justify-between text-sm mb-5">
100
+ <span className="text-gray-500">{t('pages.cart.shipping_cost', 'Shipping cost')}</span>
101
+ <b>{format(cart.real_shipping_cost)}</b>
102
+ </div>
103
+ )}
104
+
105
+ {applyCouponEnabled && <CouponInput initialCoupon={cart.coupon ?? undefined} />}
106
+
107
+ {!!cart.total_discount && (
108
+ <div id="total-discount" className="flex justify-between text-sm">
109
+ <span className="text-gray-500 block h-10">{t('pages.cart.discount', 'Discount')}</span>
110
+ <b>- {format(cart.total_discount)}</b>
111
+ </div>
112
+ )}
113
+
114
+ {!!taxAmount && (
115
+ <div className="flex justify-between text-sm mb-5">
116
+ <span className="text-gray-500">
117
+ {t('pages.cart.VAT_tax_amount', 'VAT Tax Amount')}
118
+ </span>
119
+ <b id="tax-amount">{format(taxAmount)}</b>
120
+ </div>
121
+ )}
122
+
123
+ <div className="flex justify-between text-lg mb-5">
124
+ <span className="text-gray-500">{t('pages.cart.final_total', 'Total')}</span>
125
+ <b data-cart-total>{format(cart.total)}</b>
126
+ </div>
127
+
128
+ <div className="cart-submit-wrap">
129
+ <HookSlot name="cart:submit.start" />
130
+ <SallaButton
131
+ id="cart-submit"
132
+ loaderPosition="center"
133
+ width="wide"
134
+ onClick={handleCartSubmit}
135
+ >
136
+ {t('pages.cart.complete_order', 'Complete Order')}
137
+ </SallaButton>
138
+ <HookSlot name="cart:submit.end" />
139
+ </div>
140
+
141
+ <HookSlot name="cart:summary.end" />
142
+ </div>
143
+
144
+ <SallaTieredOffer />
145
+ </div>
146
+ );
147
+ }
148
+
149
+ function FreeShippingBar({
150
+ freeShippingBar,
151
+ }: {
152
+ freeShippingBar: NonNullable<Cart['free_shipping_bar']>;
153
+ }) {
154
+ const isFree = freeShippingBar.has_free_shipping;
155
+ const { t } = useTranslation();
156
+
157
+ return (
158
+ <div className="shadow-default bg-white p-5 xs:p-7 rounded-md mb-5 relative" id="free-shipping">
159
+ <div className="flex rtl:space-x-reverse space-x-3 items-center">
160
+ <i className="bg-primary text-white rounded-icon sicon-shipping-fast"></i>
161
+ <div className="flex-1">
162
+ <h4 className="shipping-item font-bold text-sm mb-1.5">
163
+ {t('pages.cart.free_shipping', 'Free Shipping')}
164
+ </h4>
165
+ <p className="shipping-item text-sm text-gray-500">
166
+ {isFree ? (
167
+ <>
168
+ <span
169
+ id="free-shipping-msg"
170
+ dangerouslySetInnerHTML={{
171
+ __html: stripUnsafeHtml(
172
+ t('pages.cart.has_free_shipping', 'You have free shipping!')
173
+ ),
174
+ }}
175
+ />
176
+ <span className="emoji" id="free-shipping-applied">
177
+ 🎉
178
+ </span>
179
+ </>
180
+ ) : (
181
+ <span
182
+ id="free-shipping-msg"
183
+ dangerouslySetInnerHTML={{
184
+ __html: stripUnsafeHtml(
185
+ t(
186
+ 'pages.cart.free_shipping_alert',
187
+ 'Get free shipping when you add :amount more'
188
+ ).replace(':amount', String(freeShippingBar.remaining))
189
+ ),
190
+ }}
191
+ />
192
+ )}
193
+ </p>
194
+ </div>
195
+ </div>
196
+ {!isFree && (
197
+ <div className="mt-8 bg-border-color rounded-full" id="free-shipping-bar">
198
+ <div
199
+ className="progress-bg transition-all duration-500 h-2.5 bg-primary relative rounded-full flex justify-end"
200
+ style={{ width: `${freeShippingBar.percent}%` }}
201
+ >
202
+ <i className="inline-block sicon-shipping-fast absolute -top-5 rtl:left-0 ltr:right-0"></i>
203
+ </div>
204
+ </div>
205
+ )}
206
+ </div>
207
+ );
208
+ }
209
+
210
+ function CouponInput({ initialCoupon }: { initialCoupon?: string }) {
211
+ const { t } = useTranslation();
212
+ const { value, error, apply, remove } = useCoupon();
213
+
214
+ // Use initial coupon from cart if available
215
+ const appliedCoupon = value ?? initialCoupon;
216
+
217
+ const handleApplyCoupon = useCallback(
218
+ async (event: React.FormEvent<HTMLFormElement>) => {
219
+ event.preventDefault();
220
+ const formData = new FormData(event.currentTarget);
221
+ const code = formData.get('coupon') as string;
222
+ if (code?.trim()) {
223
+ await apply(code.trim());
224
+ }
225
+ },
226
+ [apply]
227
+ );
228
+
229
+ const handleRemoveCoupon = useCallback(async () => {
230
+ await remove();
231
+ }, [remove]);
232
+
233
+ return (
234
+ <form className="border-t border-gray-200 border-b py-5 mb-5" onSubmit={handleApplyCoupon}>
235
+ <label htmlFor="coupon-input" className="block text-sm">
236
+ {t('pages.cart.have_coupon', 'Have a coupon?')}
237
+ </label>
238
+ <div className="mt-2.5 relative">
239
+ <input
240
+ placeholder={t('pages.cart.coupon_placeholder', 'Enter coupon code')}
241
+ disabled={!!appliedCoupon}
242
+ className="rtl:pl-24 ltr:pr-24 form-input"
243
+ defaultValue={appliedCoupon}
244
+ id="coupon-input"
245
+ name="coupon"
246
+ aria-label={t('pages.cart.apply_coupon', 'Apply coupon')}
247
+ type="text"
248
+ />
249
+
250
+ <SallaButton
251
+ type="submit"
252
+ className={`btn--coupon ${appliedCoupon ? 'has-coupon btn--danger' : 'has-not-coupon btn--default'}`}
253
+ loaderPosition="center"
254
+ onClick={appliedCoupon ? handleRemoveCoupon : undefined}
255
+ >
256
+ <span className="coupon-text">
257
+ {appliedCoupon ? '' : t('pages.cart.apply_coupon_btn', 'Apply')}
258
+ </span>
259
+ {appliedCoupon && <i className="sicon-cancel icon text-xl w-8"></i>}
260
+ </SallaButton>
261
+ </div>
262
+ {error && (
263
+ <span className="text-xs text-red-700" id="coupon-error">
264
+ {error}
265
+ </span>
266
+ )}
267
+ </form>
268
+ );
269
+ }
@@ -0,0 +1,16 @@
1
+ import { useTranslation } from '../../providers/I18nProvider';
2
+
3
+ export function PreOrderNotification() {
4
+ const { t } = useTranslation();
5
+
6
+ return (
7
+ <salla-alert
8
+ className="mb-5"
9
+ message={t(
10
+ 'pages.cart.pre_order_shipping',
11
+ 'Your order will be shipped when the pre-order product becomes available in the store.'
12
+ )}
13
+ variant="info"
14
+ />
15
+ );
16
+ }
@@ -0,0 +1,21 @@
1
+ import { SallaButton } from '@salla.sa/twilight-components-react/button';
2
+ import { useTranslation } from '../../providers/I18nProvider';
3
+
4
+ const handlePriceQuote = async () => {
5
+ await window.salla?.cart.api.priceQuote?.();
6
+ };
7
+
8
+ export function PriceQuoteButton() {
9
+ const { t } = useTranslation();
10
+
11
+ return (
12
+ <SallaButton
13
+ id="request-price-quote-btn"
14
+ className="btn--oval btn--md"
15
+ fill="outline"
16
+ onClick={handlePriceQuote}
17
+ >
18
+ {t('pages.cart.request_price_quote', 'Request for Quotation')}
19
+ </SallaButton>
20
+ );
21
+ }
@@ -0,0 +1,99 @@
1
+ import { useEffect } from 'react';
2
+ import { useTwilight } from '../../providers/TwilightProvider';
3
+ import { useTranslation } from '../../providers/I18nProvider';
4
+ import type { Cart } from '../../types';
5
+ import { pushCheckoutEvent } from '../../lib/analytics/gtm';
6
+ import { onSallaEvent } from '../../utils/sdk-helpers';
7
+
8
+ // ─── Types ────────────────────────────────────────────────────────────────────
9
+
10
+ export interface SeoCartWidgetProps {
11
+ /**
12
+ * Cart data from the TanStack Router loader — no extra fetch needed.
13
+ */
14
+ cart: Cart;
15
+ /**
16
+ * Current checkout funnel step.
17
+ * Defaults to `1` (cart view) — CartPage always passes this default.
18
+ * The widget internally listens to Salla SDK events to promote to 2 / 3.
19
+ */
20
+ step?: 1 | 2 | 3;
21
+ }
22
+
23
+ // ─── Page title translation keys (mirrors PHP SeoCartWidget::$pageTitle) ─────
24
+
25
+ /**
26
+ * Matches the PHP backend exactly:
27
+ * ```php
28
+ * protected $pageTitle = [
29
+ * self::STEP_CART => 'common.titles.cart',
30
+ * self::STEP_SHIPPING => 'common.titles.shipping',
31
+ * self::STEP_PAYMENT => 'common.titles.checkout',
32
+ * ];
33
+ * ```
34
+ */
35
+ const PAGE_TITLE_KEYS: Record<1 | 2 | 3, string> = {
36
+ 1: 'common.titles.cart',
37
+ 2: 'common.titles.shipping',
38
+ 3: 'common.titles.checkout',
39
+ };
40
+
41
+ // ─── Component ────────────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * SeoCartWidget — Null-rendering analytics side-effect component.
45
+ *
46
+ * Responsibilities:
47
+ * 1. Fires a GTM `checkout` event (step 1) on cart page load.
48
+ * 2. Listens to Salla SDK checkout overlay events to fire steps 2 & 3.
49
+ * 3. Updates `document.title` to reflect the cart context.
50
+ *
51
+ * Architecture:
52
+ * - Lives in `theme-engine` so all themes using the engine get GTM tracking.
53
+ * - Mounted directly inside `CartPage`, which already has loader data.
54
+ * - `window.dataLayer` must be initialised by the store's GTM embed snippet;
55
+ * the widget initialises it as a safe-guard but does NOT inject GTM itself.
56
+ * - Must be mounted inside `<TwilightProvider>` (reads `currency` from context).
57
+ *
58
+ * @example
59
+ * // In CartPage:
60
+ * <SeoCartWidget cart={cart} />
61
+ */
62
+ export function SeoCartWidget({ cart, step = 1 }: SeoCartWidgetProps) {
63
+ const { store, currency } = useTwilight();
64
+ const { t } = useTranslation();
65
+ const currencyCode = currency?.code ?? 'SAR';
66
+
67
+ // ── Fire GTM checkout event for step 1 (or whichever step is passed) ────────
68
+ useEffect(() => {
69
+ pushCheckoutEvent(step, cart, currencyCode);
70
+ // Re-fire if the cart id, contents, or currency changes
71
+ }, [step, cart, currencyCode]);
72
+
73
+ // ── Subscribe to Salla SDK checkout step events (steps 2 & 3) ──────────────
74
+ // Fires GTM events when the user advances through the checkout overlay.
75
+ useEffect(() => {
76
+ const onShipping = () => pushCheckoutEvent(2, cart, currencyCode);
77
+ const onPayment = () => pushCheckoutEvent(3, cart, currencyCode);
78
+
79
+ const offShipping = onSallaEvent('checkout::step.shipping', onShipping);
80
+ const offPayment = onSallaEvent('checkout::step.payment', onPayment);
81
+
82
+ return () => {
83
+ offShipping();
84
+ offPayment();
85
+ };
86
+ }, [cart, currencyCode]);
87
+
88
+ // ── Update document title — mirrors PHP SeoCartWidget::$pageTitle ───────────
89
+ // Step 1 → 'common.titles.cart' (e.g. "Cart")
90
+ // Step 2 → 'common.titles.shipping' (e.g. "Shipping")
91
+ // Step 3 → 'common.titles.checkout' (e.g. "Checkout")
92
+ useEffect(() => {
93
+ const storeTitle = store.meta?.title || store.name;
94
+ const stepTitle = t(PAGE_TITLE_KEYS[step], PAGE_TITLE_KEYS[step]);
95
+ document.title = storeTitle ? `${stepTitle} - ${storeTitle}` : stepTitle;
96
+ }, [step, store.meta?.title, store.name, t]);
97
+
98
+ return null;
99
+ }
@@ -0,0 +1,11 @@
1
+ import { LazyCartItem, LazyCartSummary, LazySeoCartWidget } from './lazy';
2
+
3
+ // Lazy-loaded cart components (code-split)
4
+ export {
5
+ LazyCartItem as CartItem,
6
+ LazyCartSummary as CartSummary,
7
+ LazySeoCartWidget as SeoCartWidget,
8
+ };
9
+
10
+ // Types are co-located with components (not in types.ts)
11
+ export type { SeoCartWidgetProps } from './SeoCartWidget';
@@ -0,0 +1,15 @@
1
+ import { lazy } from 'react';
2
+
3
+ /**
4
+ * Lazy-loaded cart components
5
+ * Use these for code-splitting cart sections
6
+ */
7
+ export const LazyCartItem = lazy(() => import('./CartItem').then((m) => ({ default: m.CartItem })));
8
+
9
+ export const LazyCartSummary = lazy(() =>
10
+ import('./CartSummary').then((m) => ({ default: m.CartSummary }))
11
+ );
12
+
13
+ export const LazySeoCartWidget = lazy(() =>
14
+ import('./SeoCartWidget').then((m) => ({ default: m.SeoCartWidget }))
15
+ );
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Collapse Component
3
+ *
4
+ * A controlled collapsible content area with smooth animation.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * function FAQItem({ question, answer }) {
9
+ * const [isOpen, setIsOpen] = useState(false);
10
+ *
11
+ * return (
12
+ * <Collapse isOpen={isOpen} onToggle={() => setIsOpen(!isOpen)}>
13
+ * <Collapse.Trigger>
14
+ * <div className="flex justify-between">
15
+ * <span>{question}</span>
16
+ * <span>{isOpen ? '−' : '+'}</span>
17
+ * </div>
18
+ * </Collapse.Trigger>
19
+ * <Collapse.Content>
20
+ * <p>{answer}</p>
21
+ * </Collapse.Content>
22
+ * </Collapse>
23
+ * );
24
+ * }
25
+ * ```
26
+ */
27
+
28
+ import { type ReactNode, type HTMLAttributes, type ButtonHTMLAttributes } from 'react';
29
+
30
+ export interface CollapseProps {
31
+ isOpen: boolean;
32
+ onToggle: () => void;
33
+ children: ReactNode;
34
+ /**
35
+ * Additional className for the collapse container
36
+ */
37
+ className?: string;
38
+ }
39
+
40
+ export function Collapse({ children, className }: CollapseProps) {
41
+ return <div className={`overflow-hidden ${className || ''}`}>{children}</div>;
42
+ }
43
+
44
+ // Trigger Component
45
+ export interface CollapseTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
46
+ children: ReactNode;
47
+ isOpen?: boolean;
48
+ onToggle?: () => void;
49
+ }
50
+
51
+ Collapse.Trigger = function CollapseTrigger({
52
+ children,
53
+ isOpen = false,
54
+ onToggle,
55
+ className,
56
+ ...props
57
+ }: CollapseTriggerProps) {
58
+ return (
59
+ <button
60
+ type="button"
61
+ onClick={onToggle}
62
+ className={`block cursor-pointer border-0 bg-transparent p-0 text-start ${className || ''}`}
63
+ aria-expanded={isOpen}
64
+ {...props}
65
+ >
66
+ {children}
67
+ </button>
68
+ );
69
+ };
70
+
71
+ // Content Component
72
+ export interface CollapseContentProps extends HTMLAttributes<HTMLDivElement> {
73
+ children: ReactNode;
74
+ isOpen?: boolean;
75
+ }
76
+
77
+ Collapse.Content = function CollapseContent({
78
+ children,
79
+ isOpen = false,
80
+ className,
81
+ ...props
82
+ }: CollapseContentProps) {
83
+ return (
84
+ <div
85
+ className={`transition-all duration-200 ease-out ${
86
+ isOpen ? 'grid grid-rows-[1fr] opacity-100' : 'grid grid-rows-[0fr] opacity-0'
87
+ } ${className || ''}`}
88
+ {...props}
89
+ >
90
+ <div className="overflow-hidden">
91
+ <div className="pb-2">{children}</div>
92
+ </div>
93
+ </div>
94
+ );
95
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Collapse Component System
3
+ *
4
+ * A controlled collapsible panel for FAQs, accordions, and expandable sections.
5
+ * Eager-loaded because it uses compound component pattern (Collapse.Trigger, Collapse.Content).
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { Collapse } from '@salla.sa/twilight-theme-engine/components/collapse';
10
+ *
11
+ * function Accordion() {
12
+ * const [openId, setOpenId] = useState(null);
13
+ *
14
+ * return (
15
+ * <div className="space-y-2">
16
+ * {items.map((item) => (
17
+ * <Collapse
18
+ * key={item.id}
19
+ * isOpen={openId === item.id}
20
+ * onToggle={() => setOpenId(openId === item.id ? null : item.id)}
21
+ * >
22
+ * <Collapse.Trigger isOpen={openId === item.id} onToggle={() => setOpenId(item.id)}>
23
+ * <h3>{item.title}</h3>
24
+ * </Collapse.Trigger>
25
+ * <Collapse.Content isOpen={openId === item.id}>
26
+ * <p>{item.content}</p>
27
+ * </Collapse.Content>
28
+ * </Collapse>
29
+ * ))}
30
+ * </div>
31
+ * );
32
+ * }
33
+ * ```
34
+ */
35
+
36
+ export {
37
+ Collapse,
38
+ type CollapseProps,
39
+ type CollapseTriggerProps,
40
+ type CollapseContentProps,
41
+ } from './Collapse';
@@ -0,0 +1,27 @@
1
+ import type { Page } from '../../types';
2
+ import { useBreadcrumbs } from '../../hooks/useBreadcrumbs';
3
+ import { useTwilight } from '../../providers/TwilightProvider';
4
+ import { BreadcrumbTrail } from './BreadcrumbTrail';
5
+ import { BreadcrumbJsonLd } from './BreadcrumbJsonLd';
6
+
7
+ export interface BreadcrumbProps {
8
+ page?: Page | null;
9
+ className?: string;
10
+ }
11
+
12
+ export function Breadcrumb({ page, className }: BreadcrumbProps) {
13
+ const { theme, store } = useTwilight();
14
+ const breadcrumbsEnabled = theme.settings.is_breadcrumbs_enabled ?? true;
15
+ const origin = store.url;
16
+
17
+ const items = useBreadcrumbs(page);
18
+
19
+ if (!breadcrumbsEnabled) return null;
20
+
21
+ return (
22
+ <>
23
+ <BreadcrumbTrail items={items} className={className} />
24
+ <BreadcrumbJsonLd items={items} origin={origin} />
25
+ </>
26
+ );
27
+ }
@@ -0,0 +1,40 @@
1
+ import type { Breadcrumb } from '../../types';
2
+
3
+ interface BreadcrumbJsonLdProps {
4
+ items: Breadcrumb[];
5
+ origin: string;
6
+ }
7
+
8
+ function toAbsoluteUrl(origin: string, path: string): string {
9
+ if (path.startsWith('http')) return path;
10
+ return origin + path;
11
+ }
12
+
13
+ export function BreadcrumbJsonLd({ items, origin }: BreadcrumbJsonLdProps) {
14
+ if (items.length === 0) return null;
15
+
16
+ const schema = {
17
+ '@context': 'https://schema.org',
18
+ '@type': 'BreadcrumbList',
19
+ itemListElement: items.map((item, index) => {
20
+ const isLast = index === items.length - 1;
21
+ const url = toAbsoluteUrl(origin, item.url);
22
+ return {
23
+ '@type': 'ListItem',
24
+ position: index + 1,
25
+ name: item.name,
26
+ ...(isLast ? { '@id': url } : { item: url }),
27
+ };
28
+ }),
29
+ };
30
+
31
+ const html = JSON.stringify(schema);
32
+
33
+ return (
34
+ <script
35
+ type="application/ld+json"
36
+ suppressHydrationWarning
37
+ dangerouslySetInnerHTML={{ __html: html }}
38
+ />
39
+ );
40
+ }