@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,179 @@
1
+ import { memo, useState, useRef, useCallback, useEffect, useMemo } from 'react';
2
+ import { useInfiniteQuery } from '@tanstack/react-query';
3
+ import { useWindowScroll } from '@uidotdev/usehooks';
4
+ import { Link, Breadcrumb, NoContent, Image } from '../../components/common';
5
+ import { HookSlot } from '../../hooks';
6
+ import { useTranslation } from '../../providers/I18nProvider';
7
+ import { brand } from '../../api/brands';
8
+ import type { Brand, BrandsGroup, BrandsPageProps } from './types';
9
+
10
+ function byLetter(brands: Brand[], locale: string): [string, Brand[]][] {
11
+ const groups: BrandsGroup = {};
12
+ for (const item of brands) {
13
+ (groups[(locale === 'ar' ? item.ar_char : item.en_char) || '#'] ??= []).push(item);
14
+ }
15
+ // Code point order is alphabetical for Arabic and Latin, and the same on server and browser.
16
+ return Object.entries(groups).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
17
+ }
18
+
19
+ interface BrandSectionProps {
20
+ char: string;
21
+ brands: Brand[];
22
+ sectionRef: (el: HTMLElement | null) => void;
23
+ }
24
+
25
+ function BrandSection({ char, brands, sectionRef }: BrandSectionProps) {
26
+ return (
27
+ <section
28
+ id={`brand-section-${char}`}
29
+ ref={sectionRef}
30
+ className="pt-24 first:pt-16 md:first:pt-24"
31
+ >
32
+ <div className="flex items-center mb-10">
33
+ <span data-id={char} className="brand-char">
34
+ <span className="fix-align">{char}</span>
35
+ </span>
36
+ <div className="bg-border-color h-px flex-1"></div>
37
+ </div>
38
+ <div className="grid grid-cols-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 grid-flow-row gap-4 md:gap-8">
39
+ {brands.map((item) => (
40
+ // A grid of logos would preload a brand for every logo the mouse crosses.
41
+ <Link key={item.id} to={`/brands/${item.id}`} className="brand-item" preload={false}>
42
+ <Image
43
+ className="max-h-full"
44
+ width={400}
45
+ height={300}
46
+ src={item.logo}
47
+ alt={item.name}
48
+ />
49
+ </Link>
50
+ ))}
51
+ </div>
52
+ </section>
53
+ );
54
+ }
55
+
56
+ const PAGES_PER_WAVE = 6;
57
+
58
+ // One retry per page, so a network blip does not drop it.
59
+ const fetchPage = (page: number) => brand.list(page).catch(() => brand.list(page));
60
+
61
+ async function fetchWave(from: number): Promise<{ items: Brand[]; done: boolean }> {
62
+ const settled = await Promise.allSettled(
63
+ Array.from({ length: PAGES_PER_WAVE }, (_, i) => fetchPage(from + i))
64
+ );
65
+ const pages = settled.flatMap((result) => (result.status === 'fulfilled' ? [result.value] : []));
66
+ return {
67
+ items: pages.flatMap((result) => result.items),
68
+ // Stop at the last page, or when a whole wave fails.
69
+ done: pages.length === 0 || pages.some((result) => !result.next),
70
+ };
71
+ }
72
+
73
+ /**
74
+ * The first page plus every page after `next`, fetched in the background so the letter menu is
75
+ * complete without scrolling. The API has no page count, so pages load in parallel waves.
76
+ */
77
+ function useAllBrands(first: Brand[], next: string | null | undefined, locale: string): Brand[] {
78
+ const startPage = Number(next?.match(/[?&]page=(\d+)/)?.[1]) || 0;
79
+ const { data, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteQuery({
80
+ queryKey: ['brands', 'after-first-page', locale, startPage],
81
+ queryFn: ({ pageParam }) => fetchWave(pageParam),
82
+ initialPageParam: startPage,
83
+ getNextPageParam: (wave, _waves, from) => (wave.done ? undefined : from + PAGES_PER_WAVE),
84
+ enabled: startPage > 0,
85
+ // Not reused across visits: it must match the first page the loader just fetched.
86
+ gcTime: 0,
87
+ });
88
+
89
+ useEffect(() => {
90
+ if (hasNextPage && !isFetchingNextPage) void fetchNextPage();
91
+ }, [hasNextPage, isFetchingNextPage, fetchNextPage]);
92
+
93
+ return useMemo(() => {
94
+ const extra = data?.pages.flatMap((wave) => wave.items) ?? [];
95
+ return extra.length ? [...first, ...extra] : first;
96
+ }, [first, data]);
97
+ }
98
+
99
+ function BrandsPageComponent({ page, brands, pagination }: BrandsPageProps) {
100
+ const { t, locale } = useTranslation();
101
+ const allBrands = useAllBrands(brands, pagination?.next, locale);
102
+ const brandEntries = useMemo(() => byLetter(allBrands, locale), [allBrands, locale]);
103
+ const [selectedChar, setSelectedChar] = useState<string | null>(null);
104
+ const sectionRefs = useRef<Record<string, HTMLElement | null>>({});
105
+
106
+ // Use useWindowScroll hook instead of manual listener
107
+ const [{ y }] = useWindowScroll();
108
+ const isSticky = (y ?? 0) > 200;
109
+
110
+ // Handle brand nav item click - matches brands.js toggle class logic
111
+ const handleBrandClick = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => {
112
+ e.preventDefault();
113
+ const char = e.currentTarget.dataset.id;
114
+ if (char) {
115
+ setSelectedChar(char);
116
+ sectionRefs.current[char]?.scrollIntoView({ behavior: 'smooth' });
117
+ }
118
+ }, []);
119
+
120
+ return (
121
+ <div className="container mb-20">
122
+ <Breadcrumb page={page} />
123
+
124
+ <div className="flex justify-between pt-2 pb-6">
125
+ <h1 className="font-bold mb-6 md:mb-0">{page.title}</h1>
126
+ </div>
127
+
128
+ {brandEntries.length > 0 ? (
129
+ <>
130
+ <div className="brands-nav-wrap">
131
+ <ul
132
+ id="brands-nav"
133
+ className={`brands-nav ${isSticky ? 'is-sticky' : 'is-not-sticky'}`}
134
+ >
135
+ <li></li>
136
+ {brandEntries.map(([char]) => (
137
+ <li key={char}>
138
+ <a
139
+ className={`brands-nav__item ${selectedChar === char ? 'is-selected' : 'unselected'}`}
140
+ href={`#brand-section-${char}`}
141
+ onClick={handleBrandClick}
142
+ data-id={char}
143
+ >
144
+ <span className="fix-align">{char}</span>
145
+ </a>
146
+ </li>
147
+ ))}
148
+ </ul>
149
+ </div>
150
+
151
+ <div className="px-8 xl:px-0">
152
+ <HookSlot name="brands:index.items.start" />
153
+
154
+ {brandEntries.map(([char, brandGroup]) => (
155
+ <BrandSection
156
+ key={char}
157
+ char={char}
158
+ brands={brandGroup}
159
+ sectionRef={(el) => {
160
+ sectionRefs.current[char] = el;
161
+ }}
162
+ />
163
+ ))}
164
+
165
+ <HookSlot name="brands:index.items.end" />
166
+ </div>
167
+ </>
168
+ ) : (
169
+ <NoContent
170
+ icon="sicon-award-ribbon"
171
+ message={t('pages.brands.non_brands')}
172
+ actionLabel={t('common.elements.back_home')}
173
+ />
174
+ )}
175
+ </div>
176
+ );
177
+ }
178
+
179
+ export const BrandsPage = memo(BrandsPageComponent);
@@ -0,0 +1,47 @@
1
+ import type { HeadDescriptor } from '../../utils/head';
2
+ import { buildHreflangAlternates } from '../../utils/baseHead';
3
+ import { lazy } from 'react';
4
+ import { brandsLoader } from './loader';
5
+ import type { BrandsPageProps } from './types';
6
+ import type { TwilightContext } from '../../twilight/context';
7
+ import { RouteId } from '../../router/route-ids';
8
+
9
+ // Lazy-load components for code-splitting
10
+ const LazyBrandsPage = lazy(() => import('./BrandsPage').then((m) => ({ default: m.BrandsPage })));
11
+
12
+ export const BrandsPage = LazyBrandsPage;
13
+ export { brandsLoader };
14
+ export type { BrandsPageProps, Brand, BrandsGroup } from './types';
15
+
16
+ async function brandsLoaderWithExtend(
17
+ _ctx?: { locale?: string },
18
+ extend?: (
19
+ data: BrandsPageProps,
20
+ ctx: { params: Record<string, never> }
21
+ ) => Promise<Record<string, unknown>> | Record<string, unknown>
22
+ ): Promise<BrandsPageProps> {
23
+ const data = await brandsLoader();
24
+
25
+ if (extend) {
26
+ const extra = await extend(data, { params: {} });
27
+ return { ...data, ...extra } as BrandsPageProps;
28
+ }
29
+ return data;
30
+ }
31
+
32
+ function brandsHead(ctx: TwilightContext, data: BrandsPageProps): HeadDescriptor {
33
+ const base: HeadDescriptor = {
34
+ title: data.page.title,
35
+ description: data.page.description,
36
+ alternateLanguages: buildHreflangAlternates(ctx.settings, ctx.location.pathname),
37
+ };
38
+
39
+ return base;
40
+ }
41
+
42
+ export const Brands = {
43
+ id: RouteId.BRANDS_INDEX,
44
+ loader: brandsLoaderWithExtend,
45
+ head: brandsHead,
46
+ Component: LazyBrandsPage,
47
+ } as const;
@@ -0,0 +1,14 @@
1
+ import type { BrandsPageProps } from './types';
2
+ import { brand } from '../../api/brands';
3
+ import { getTwilightContext } from '../../twilight/context';
4
+ import { RouteId } from '../../router/route-ids';
5
+
6
+ export async function brandsLoader(): Promise<BrandsPageProps> {
7
+ const { items, next } = await brand.list();
8
+ const i18n = getTwilightContext().i18n;
9
+ return {
10
+ page: { slug: RouteId.BRANDS_INDEX, title: i18n.t('common.titles.brands') || 'Brands' },
11
+ brands: items,
12
+ pagination: { next },
13
+ };
14
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Brands Route Types
3
+ * Only types that need to be exported.
4
+ */
5
+
6
+ import type { Page } from '../../types';
7
+ import type { RoutePagination } from '../types';
8
+
9
+ export interface Brand {
10
+ /** Brand id. Numeric on the Store API (`brands` and `brands/{id}`); string in older fixtures. */
11
+ id: string | number;
12
+ /** Brand page URL. */
13
+ url: string;
14
+ /** Brand name. */
15
+ name: string;
16
+ /** Display label. */
17
+ label: string;
18
+ /** Brand description. */
19
+ description: string;
20
+ /** Banner image URL, or null. */
21
+ banner?: string | null;
22
+ /** Logo image URL. Always present; required to match Twig template usage. */
23
+ logo: string;
24
+ /** Whether the brand is active. */
25
+ status: boolean;
26
+ /** First Arabic letter, used to group the brands directory. */
27
+ ar_char: string;
28
+ /** First Latin letter, used to group the brands directory. */
29
+ en_char: string;
30
+ /** Sales channels the brand is available on. */
31
+ channels?: string[];
32
+ /** SEO data. */
33
+ metadata?: {
34
+ /** SEO title. */
35
+ title: string;
36
+ /** SEO description. */
37
+ description: string;
38
+ /** SEO URL. */
39
+ url: string;
40
+ };
41
+ }
42
+
43
+ export interface BrandsGroup {
44
+ [char: string]: Brand[];
45
+ }
46
+
47
+ // Page props
48
+ export interface BrandsPageProps {
49
+ page: Page;
50
+ /** The first page of brands; the page groups them by letter and loads the rest on scroll. */
51
+ brands: Brand[];
52
+ pagination?: RoutePagination;
53
+ }
@@ -0,0 +1,112 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { SallaConditionalOffer } from '@salla.sa/twilight-components-react/conditional-offer';
3
+ import { SallaOffer } from '@salla.sa/twilight-components-react/offer';
4
+ import { SallaProductOptions } from '@salla.sa/twilight-components-react/product-options';
5
+ import { HookSlot } from '../../hooks';
6
+ import { useTranslation } from '../../providers/I18nProvider';
7
+ import type { CartPageProps } from './types';
8
+ import { Breadcrumb, NoContent } from '../../components/common';
9
+ import { CartItem, CartSummary, SeoCartWidget } from '../../components/cart';
10
+ import { useTwilight } from '../../providers/twilight-context';
11
+ import { CartSkeleton } from '../../skeleton';
12
+ import { loyalty } from '../../api/loyalty';
13
+ import { cart } from '../../api/cart';
14
+
15
+ function CartPageContent({ page }: CartPageProps) {
16
+ const { store } = useTwilight();
17
+ const { t } = useTranslation();
18
+ const { data: loyaltyPoints } = useQuery(loyalty.queries.points());
19
+
20
+ const { data: cartId } = useQuery(cart.queries.currentId());
21
+
22
+ const { data: cartData } = useQuery({
23
+ ...cart.queries.detail(cartId!),
24
+ enabled: !!cartId,
25
+ });
26
+
27
+ const isLoading = cartId == null || cartData === undefined;
28
+
29
+ if (isLoading) {
30
+ return <CartSkeleton />;
31
+ }
32
+
33
+ // No cart: it was already turned into an order, shown empty like Twig.
34
+ if (!cartData || cartData.items.length === 0) {
35
+ return (
36
+ <div className="container">
37
+ <Breadcrumb page={page} />
38
+ <NoContent
39
+ icon="sicon-shopping-bag"
40
+ message={t('pages.cart.empty_cart', 'Your cart is empty')}
41
+ actionLabel={t('common.elements.back_home', 'Back to Home')}
42
+ actionUrl="/"
43
+ />
44
+ </div>
45
+ );
46
+ }
47
+
48
+ return (
49
+ <div className="container">
50
+ {/* Analytics — no visible UI, fires GTM checkout events */}
51
+ <SeoCartWidget cart={cartData} />
52
+
53
+ <Breadcrumb page={page} />
54
+ <h1 className="sr-only">{t('common.titles.cart', 'Cart')}</h1>
55
+ <SallaConditionalOffer />
56
+
57
+ <HookSlot name="cart:start" />
58
+
59
+ <div className="pt-5 flex flex-col items-start lg:flex-row pb-6 lg:pb-20">
60
+ <div className="main-content w-full lg:w-[calc(100%-384px)]">
61
+ <HookSlot name="cart:items.start" context={{ cartItems: cartData.items }} />
62
+
63
+ {cartData.items.map((item, index) => (
64
+ <CartItem key={item.id} item={item} isFirst={index === 0} />
65
+ ))}
66
+
67
+ {cartData.options?.length > 0 && (
68
+ <div className="cart-options">
69
+ {cartData.options.map((option) => (
70
+ <form
71
+ key={option.id}
72
+ className="first:pt-5 relative"
73
+ onChange={(e) => window.salla?.form.onChange('cart.updateItem', e)}
74
+ id={`item-${option.id}`}
75
+ >
76
+ <input type="hidden" name="id" value={option.id} />
77
+ <input type="hidden" name="quantity" value={option.quantity} />
78
+ {/* Twig: {% include 'pages.partials.product.options' with {product:product_option} %} */}
79
+ {option.options && option.options.length > 0 && (
80
+ <SallaProductOptions
81
+ options={JSON.stringify(option.options)}
82
+ productId={option.id}
83
+ />
84
+ )}
85
+ </form>
86
+ ))}
87
+ </div>
88
+ )}
89
+
90
+ <SallaOffer />
91
+ <HookSlot name="cart:items.end" />
92
+ </div>
93
+
94
+ <CartSummary
95
+ cart={cartData}
96
+ applyCouponEnabled={store.settings?.cart?.apply_coupon_enabled}
97
+ taxAmount={cartData.tax_amount}
98
+ key={cartData.id}
99
+ loyalty={cartData.loyalty}
100
+ gift={cartData.gift}
101
+ loyaltyPoints={loyaltyPoints ?? undefined}
102
+ />
103
+ </div>
104
+
105
+ <HookSlot name="cart:end" />
106
+ </div>
107
+ );
108
+ }
109
+
110
+ export function CartPage(props: CartPageProps) {
111
+ return <CartPageContent {...props} />;
112
+ }
@@ -0,0 +1,39 @@
1
+ import type { HeadDescriptor } from '../../utils/head';
2
+ import { buildHreflangAlternates } from '../../utils/baseHead';
3
+ import { CartPage } from './CartPage';
4
+ import { cartLoader } from './loader';
5
+ import type { CartPageProps } from './types';
6
+ import type { TwilightContext } from '../../twilight/context';
7
+ import { RouteId } from '../../router/route-ids';
8
+
9
+ export { CartPage } from './CartPage';
10
+ export { cartLoader } from './loader';
11
+ export type { CartPageProps } from './types';
12
+
13
+ async function loader(
14
+ _ctx?: { locale?: string },
15
+ extend?: (
16
+ data: CartPageProps,
17
+ ctx: { params: Record<string, never> }
18
+ ) => Promise<Record<string, unknown>> | Record<string, unknown>
19
+ ): Promise<CartPageProps> {
20
+ const data = cartLoader();
21
+
22
+ if (extend) {
23
+ const extra = extend(data, { params: {} });
24
+ return { ...data, ...(extra instanceof Promise ? {} : extra) } as CartPageProps;
25
+ }
26
+ return data;
27
+ }
28
+
29
+ function head(ctx: TwilightContext, data: CartPageProps): HeadDescriptor {
30
+ const base: HeadDescriptor = {
31
+ title: data.page.title,
32
+ description: data.page.description,
33
+ alternateLanguages: buildHreflangAlternates(ctx.settings, ctx.location.pathname),
34
+ };
35
+
36
+ return base;
37
+ }
38
+
39
+ export const Cart = { id: RouteId.CART, loader, head, Component: CartPage } as const;
@@ -0,0 +1,15 @@
1
+ import type { CartPageProps } from './types';
2
+ import { getTwilightContext } from '../../twilight/context';
3
+ import { RouteId } from '../../router/route-ids';
4
+
5
+ /**
6
+ * SSR-safe loader that returns only page metadata.
7
+ * Cart data is fetched client-side via React Query since the cart ID
8
+ * lives in localStorage (unavailable during SSR).
9
+ */
10
+ export function cartLoader(): CartPageProps {
11
+ const i18n = getTwilightContext().i18n;
12
+ return {
13
+ page: { slug: RouteId.CART, title: i18n.t('common.titles.cart') || 'Cart' },
14
+ } as CartPageProps;
15
+ }
@@ -0,0 +1,6 @@
1
+ import type { Page, Cart } from '../../types';
2
+
3
+ export interface CartPageProps {
4
+ page: Page;
5
+ cart?: Cart;
6
+ }
@@ -0,0 +1,53 @@
1
+ import { memo } from 'react';
2
+ import { useDevHomeComponentOverrides } from '../../dev/dev-settings-store';
3
+ import { HookSlot } from '../../hooks';
4
+ import { HomeComponentRenderer, ReorderProducts } from '../../components/home';
5
+ import type { HomePageProps } from './types';
6
+ import { Pulse } from '@salla.sa/twilight-components-react';
7
+
8
+ export const HomeSkeleton = memo(function HomeSkeleton() {
9
+ return (
10
+ <>
11
+ <div className="s-block container skeleton-block-hero">
12
+ <Pulse className="h-64 sm:h-80 rounded-md" />
13
+ </div>
14
+ <div className="s-block container skeleton-block-products">
15
+ <Pulse className="h-10 w-48 mb-4" />
16
+ <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
17
+ {[1, 2, 3, 4].map((i) => (
18
+ <Pulse key={i} className="h-56" />
19
+ ))}
20
+ </div>
21
+ </div>
22
+ <div className="s-block container skeleton-block-products">
23
+ <Pulse className="h-10 w-48 mb-4" />
24
+ <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
25
+ {[1, 2, 3, 4].map((i) => (
26
+ <Pulse key={i} className="h-56" />
27
+ ))}
28
+ </div>
29
+ </div>
30
+ </>
31
+ );
32
+ });
33
+
34
+ export const HomePage = memo(function HomePage({ components = [] }: HomePageProps) {
35
+ // Dev-mode only: overlay DevSettingsWidget component-field overrides onto the
36
+ // blocks so edits render live. No-op passthrough in production builds.
37
+ const renderedComponents = useDevHomeComponentOverrides(components);
38
+ return (
39
+ <>
40
+ <HookSlot name="home:start" />
41
+ <HookSlot name="home:content" />
42
+ {renderedComponents.map((data, index) => (
43
+ // `data.key` is the twilight.json catalog id, shared by every placement
44
+ // of that block. Platform blocks send null. Position is unique.
45
+ <HomeComponentRenderer key={index} data={data} index={index} />
46
+ ))}
47
+ <HookSlot name="home:end" />
48
+ <ReorderProducts />
49
+ </>
50
+ );
51
+ });
52
+
53
+ export { HomePage as default };
@@ -0,0 +1,56 @@
1
+ import type { HeadDescriptor } from '../../utils/head';
2
+ import { buildHreflangAlternates } from '../../utils/baseHead';
3
+ import type { HomeLoaderData } from './loader';
4
+ import { homeLoader } from './loader';
5
+ import type { TwilightContext } from '../../twilight/context';
6
+ import { HomePage } from './HomePage';
7
+ import { RouteId } from '../../router/route-ids';
8
+
9
+ export { HomeSkeleton } from './HomePage';
10
+ export { registerHomeComponents, DefaultHomeComponents } from '../../components/home/register';
11
+ export { registerHomeComponentConfig } from '../../components/home';
12
+ export type { HomePageProps } from './types';
13
+ export type { HomeLoaderData } from './loader';
14
+ export type {
15
+ HomeComponentsProps,
16
+ AnyHomeComponent,
17
+ HomeComponentConfig,
18
+ } from '../../components/home';
19
+
20
+ function loader(_ctx?: { locale?: string }): Promise<HomeLoaderData> {
21
+ return homeLoader({ locale: _ctx?.locale });
22
+ }
23
+
24
+ function head(ctx: TwilightContext): HeadDescriptor {
25
+ const store = ctx.settings?.store;
26
+ if (!store) return {};
27
+
28
+ const title = store.meta?.title ?? store.name;
29
+ const description = store.meta?.description ?? store.description;
30
+ const keywords = store.meta?.keywords;
31
+
32
+ return {
33
+ title,
34
+ description,
35
+ keywords,
36
+ canonical: store.url,
37
+ openGraph: {
38
+ type: 'website',
39
+ title,
40
+ description,
41
+ images: store.logo,
42
+ url: store.url,
43
+ },
44
+ twitter: {
45
+ card: 'summary_large_image',
46
+ title,
47
+ description,
48
+ images: store.logo,
49
+ },
50
+ alternateLanguages: buildHreflangAlternates(ctx.settings, ctx.location.pathname),
51
+ };
52
+ }
53
+
54
+ export const Home = { id: RouteId.INDEX, loader, head, Component: HomePage } as const;
55
+
56
+ export { homeLoader };
@@ -0,0 +1,24 @@
1
+ import { getTwilightContext } from '../../twilight/context';
2
+ import { home } from '../../api/home';
3
+ import type { HomeComponentData } from '../../types';
4
+ import { RouteId } from '../../router/route-ids';
5
+
6
+ export interface HomeLoaderData {
7
+ locale: string;
8
+ components: HomeComponentData[];
9
+ page: { slug: string };
10
+ }
11
+
12
+ export async function homeLoader(ctx?: { locale?: string }): Promise<HomeLoaderData> {
13
+ const { queryClient } = getTwilightContext();
14
+ const components = await queryClient.ensureQueryData(home.queries.components());
15
+ const result = {
16
+ locale: ctx?.locale || 'ar',
17
+ components: components.map((comp) => ({
18
+ ...comp,
19
+ path: comp.path?.replace('home.', '') || comp.path,
20
+ })),
21
+ page: { slug: RouteId.INDEX },
22
+ };
23
+ return result;
24
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Home Route Types
3
+ */
4
+
5
+ import type { HomeComponentData } from '../../types';
6
+
7
+ /** Props for HomePage component */
8
+ export interface HomePageProps {
9
+ locale?: string;
10
+ components?: HomeComponentData[];
11
+ }