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

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 (390) hide show
  1. package/README.md +4 -3
  2. package/bin/twilight-check-manifest.mjs +16 -0
  3. package/dist/{AddToCartForm-B5C2M4OZ.js → AddToCartForm-P644O2QL.js} +4 -4
  4. package/dist/{AddToCartForm-B5C2M4OZ.js.map → AddToCartForm-P644O2QL.js.map} +1 -1
  5. package/dist/{BlogAuthorPage-GTF4UGSS.js → BlogAuthorPage-VWSO6MPY.js} +13 -11
  6. package/dist/BlogAuthorPage-VWSO6MPY.js.map +1 -0
  7. package/dist/{BlogCategoryPage-TN7Y4NBP.js → BlogCategoryPage-K2KSQ6T6.js} +13 -11
  8. package/dist/BlogCategoryPage-K2KSQ6T6.js.map +1 -0
  9. package/dist/{BlogPage-TDB3M3PI.js → BlogPage-XRM7VWOZ.js} +12 -10
  10. package/dist/BlogPage-XRM7VWOZ.js.map +1 -0
  11. package/dist/{BlogSinglePage-4A52Q5QW.js → BlogSinglePage-XIAXT54H.js} +12 -10
  12. package/dist/BlogSinglePage-XIAXT54H.js.map +1 -0
  13. package/dist/{BlogTagPage-TOVPBETA.js → BlogTagPage-IHOA267V.js} +13 -11
  14. package/dist/BlogTagPage-IHOA267V.js.map +1 -0
  15. package/dist/{BrandsPage-VUDGYSQI.js → BrandsPage-ZFEILRT3.js} +12 -10
  16. package/dist/BrandsPage-ZFEILRT3.js.map +1 -0
  17. package/dist/{Breadcrumb-CI3SN5YR.js → Breadcrumb-CVSISL2K.js} +12 -10
  18. package/dist/Breadcrumb-CVSISL2K.js.map +1 -0
  19. package/dist/{CartItem-BHLEURAB.js → CartItem-EOI7P3JA.js} +12 -10
  20. package/dist/CartItem-EOI7P3JA.js.map +1 -0
  21. package/dist/{CartSummary-QERVESYN.js → CartSummary-RZGUBDKJ.js} +12 -10
  22. package/dist/CartSummary-RZGUBDKJ.js.map +1 -0
  23. package/dist/{Copyright-RL6ALKRC.js → Copyright-5BLYSP24.js} +4 -4
  24. package/dist/{Copyright-RL6ALKRC.js.map → Copyright-5BLYSP24.js.map} +1 -1
  25. package/dist/{CustomerLayout-VRZUWGQK.js → CustomerLayout-6F4BJAMU.js} +12 -10
  26. package/dist/CustomerLayout-6F4BJAMU.js.map +1 -0
  27. package/dist/{Footer-ZWBZCMDL.js → Footer-NF2NLDLR.js} +6 -6
  28. package/dist/{Footer-ZWBZCMDL.js.map → Footer-NF2NLDLR.js.map} +1 -1
  29. package/dist/{Header-WNK4O66B.js → Header-6DQJ5X7J.js} +9 -7
  30. package/dist/{Header-WNK4O66B.js.map → Header-6DQJ5X7J.js.map} +1 -1
  31. package/dist/{LoyaltyPage-CGTHWJ76.js → LoyaltyPage-YHWHIWCS.js} +12 -10
  32. package/dist/LoyaltyPage-YHWHIWCS.js.map +1 -0
  33. package/dist/{LoyaltyPointsPage-QSU6K3PW.js → LoyaltyPointsPage-T6K3H5A5.js} +10 -3
  34. package/dist/LoyaltyPointsPage-T6K3H5A5.js.map +1 -0
  35. package/dist/{MainMenu-V3T7F32R.js → MainMenu-Y2TAM7DK.js} +4 -4
  36. package/dist/{MainMenu-V3T7F32R.js.map → MainMenu-Y2TAM7DK.js.map} +1 -1
  37. package/dist/{MasterLayout-XQF644LD.js → MasterLayout-GBEEFFPG.js} +12 -10
  38. package/dist/{MasterLayout-XQF644LD.js.map → MasterLayout-GBEEFFPG.js.map} +1 -1
  39. package/dist/{MobileMenu-U4BVQYKH.js → MobileMenu-RE5XVGZL.js} +12 -10
  40. package/dist/MobileMenu-RE5XVGZL.js.map +1 -0
  41. package/dist/{NotificationsPage-ZRRQY7TF.js → NotificationsPage-QAFWZAS3.js} +12 -10
  42. package/dist/NotificationsPage-QAFWZAS3.js.map +1 -0
  43. package/dist/{OrderSinglePage-O3XYVMG5.js → OrderSinglePage-T4PRXTKG.js} +12 -10
  44. package/dist/OrderSinglePage-T4PRXTKG.js.map +1 -0
  45. package/dist/{OrdersPage-CMXZF5MI.js → OrdersPage-3S6ZS56E.js} +12 -10
  46. package/dist/OrdersPage-3S6ZS56E.js.map +1 -0
  47. package/dist/{PageSingle-IIG2US43.js → PageSingle-W3UTXDOW.js} +4 -4
  48. package/dist/{PageSingle-IIG2US43.js.map → PageSingle-W3UTXDOW.js.map} +1 -1
  49. package/dist/{ProductDetails-65GDABI7.js → ProductDetails-X5A7TG3F.js} +14 -7
  50. package/dist/ProductDetails-X5A7TG3F.js.map +1 -0
  51. package/dist/{ProfilePage-SNJ4WXU4.js → ProfilePage-DUH3AILJ.js} +12 -10
  52. package/dist/ProfilePage-DUH3AILJ.js.map +1 -0
  53. package/dist/{ReviewsPage-UT7UT55J.js → ReviewsPage-2C2P7VS3.js} +4 -4
  54. package/dist/{ReviewsPage-UT7UT55J.js.map → ReviewsPage-2C2P7VS3.js.map} +1 -1
  55. package/dist/{SeoCartWidget-DBJAXJKT.js → SeoCartWidget-VYLGEW2I.js} +12 -10
  56. package/dist/SeoCartWidget-VYLGEW2I.js.map +1 -0
  57. package/dist/{SettingsPage-FLTIOPU5.js → SettingsPage-OZJEW6CW.js} +12 -10
  58. package/dist/SettingsPage-OZJEW6CW.js.map +1 -0
  59. package/dist/{StoreClosedNotification-ZT3QKDKS.js → StoreClosedNotification-QHIZBNXO.js} +13 -11
  60. package/dist/{StoreClosedNotification-ZT3QKDKS.js.map → StoreClosedNotification-QHIZBNXO.js.map} +1 -1
  61. package/dist/{TestimonialsPage-CU7HKU4O.js → TestimonialsPage-K6WJKKME.js} +4 -4
  62. package/dist/{TestimonialsPage-CU7HKU4O.js.map → TestimonialsPage-K6WJKKME.js.map} +1 -1
  63. package/dist/{ThankYouPage-5X6B4X3T.js → ThankYouPage-H6QQEI5R.js} +12 -10
  64. package/dist/ThankYouPage-H6QQEI5R.js.map +1 -0
  65. package/dist/{WalletPage-H2BKIDPA.js → WalletPage-G5IBGN6B.js} +12 -10
  66. package/dist/WalletPage-G5IBGN6B.js.map +1 -0
  67. package/dist/{WishlistPage-RS5UCIQ3.js → WishlistPage-AIOTAB6L.js} +12 -10
  68. package/dist/WishlistPage-AIOTAB6L.js.map +1 -0
  69. package/dist/api/advertisement.d.ts +33 -0
  70. package/dist/api/advertisement.d.ts.map +1 -0
  71. package/dist/api/advertisement.js +8 -0
  72. package/dist/api/advertisement.js.map +1 -0
  73. package/dist/boot/critical-style.d.ts +3 -0
  74. package/dist/boot/critical-style.d.ts.map +1 -0
  75. package/dist/boot/index.d.ts +15 -0
  76. package/dist/boot/index.d.ts.map +1 -0
  77. package/dist/boot.d.ts +1 -0
  78. package/dist/boot.js +69 -0
  79. package/dist/boot.js.map +1 -0
  80. package/dist/chunk-4FJGZQD3.js +6 -0
  81. package/dist/chunk-4FJGZQD3.js.map +1 -0
  82. package/dist/{chunk-SDFDS4Q3.js → chunk-BCJTF3V7.js} +20 -4
  83. package/dist/chunk-BCJTF3V7.js.map +1 -0
  84. package/dist/chunk-DBW7XXNE.js +103 -0
  85. package/dist/chunk-DBW7XXNE.js.map +1 -0
  86. package/dist/{chunk-22SH7OVF.js → chunk-E7WWO3V3.js} +3 -3
  87. package/dist/{chunk-22SH7OVF.js.map → chunk-E7WWO3V3.js.map} +1 -1
  88. package/dist/{chunk-SE5JYWOK.js → chunk-EZHXVHXY.js} +4 -4
  89. package/dist/{chunk-SE5JYWOK.js.map → chunk-EZHXVHXY.js.map} +1 -1
  90. package/dist/{chunk-JO7JWV34.js → chunk-FWYKOQV5.js} +5 -5
  91. package/dist/chunk-FWYKOQV5.js.map +1 -0
  92. package/dist/{chunk-JRNH3FUF.js → chunk-FYHF62KI.js} +4 -4
  93. package/dist/{chunk-JRNH3FUF.js.map → chunk-FYHF62KI.js.map} +1 -1
  94. package/dist/{chunk-UJKFBZFJ.js → chunk-GJ5IMPNY.js} +7 -7
  95. package/dist/{chunk-UJKFBZFJ.js.map → chunk-GJ5IMPNY.js.map} +1 -1
  96. package/dist/chunk-IVBOLREE.js +29 -0
  97. package/dist/chunk-IVBOLREE.js.map +1 -0
  98. package/dist/chunk-LWPKBVIE.js +14 -0
  99. package/dist/{chunk-7WAXN2PP.js.map → chunk-LWPKBVIE.js.map} +1 -1
  100. package/dist/{chunk-SX5MF2YA.js → chunk-N3BCZIGS.js} +4 -4
  101. package/dist/{chunk-SX5MF2YA.js.map → chunk-N3BCZIGS.js.map} +1 -1
  102. package/dist/{chunk-NZVR4OF7.js → chunk-NXQZ4RLM.js} +8 -8
  103. package/dist/chunk-NXQZ4RLM.js.map +1 -0
  104. package/dist/{chunk-NXQJA7D3.js → chunk-PCURRKIH.js} +3 -3
  105. package/dist/{chunk-NXQJA7D3.js.map → chunk-PCURRKIH.js.map} +1 -1
  106. package/dist/{chunk-4CZRUAZB.js → chunk-PU2LHFDQ.js} +10 -11
  107. package/dist/chunk-PU2LHFDQ.js.map +1 -0
  108. package/dist/{chunk-OWX2CPNQ.js → chunk-UQIVX4YA.js} +3 -3
  109. package/dist/{chunk-OWX2CPNQ.js.map → chunk-UQIVX4YA.js.map} +1 -1
  110. package/dist/chunk-X5NK4TZH.js +228 -0
  111. package/dist/chunk-X5NK4TZH.js.map +1 -0
  112. package/dist/{chunk-6SWDSRIL.js → chunk-XKNXYQ2K.js} +6 -6
  113. package/dist/{chunk-6SWDSRIL.js.map → chunk-XKNXYQ2K.js.map} +1 -1
  114. package/dist/{chunk-KHBSGD2D.js → chunk-XO7B3VWS.js} +3 -3
  115. package/dist/{chunk-KHBSGD2D.js.map → chunk-XO7B3VWS.js.map} +1 -1
  116. package/dist/cli/check-manifest.d.ts +10 -0
  117. package/dist/cli/check-manifest.d.ts.map +1 -0
  118. package/dist/cli/check-manifest.js +44 -0
  119. package/dist/cli/check-manifest.js.map +1 -0
  120. package/dist/components/cart/index.js +1 -1
  121. package/dist/components/common/index.js +2 -2
  122. package/dist/components/drawer/index.js +10 -8
  123. package/dist/components/home/index.js +12 -10
  124. package/dist/components/layout/Footer.d.ts.map +1 -1
  125. package/dist/components/layout/MasterLayout.d.ts.map +1 -1
  126. package/dist/components/layout/PageAdvertisements.d.ts +7 -0
  127. package/dist/components/layout/PageAdvertisements.d.ts.map +1 -0
  128. package/dist/components/layout/index.d.ts +1 -0
  129. package/dist/components/layout/index.d.ts.map +1 -1
  130. package/dist/components/layout/index.js +8 -1
  131. package/dist/components/product/index.js +11 -9
  132. package/dist/components/store/index.js +12 -10
  133. package/dist/components/store/index.js.map +1 -1
  134. package/dist/{document-class-67HTP45G.js → document-class-FRL7JHWD.js} +6 -5
  135. package/dist/{document-class-67HTP45G.js.map → document-class-FRL7JHWD.js.map} +1 -1
  136. package/dist/hooks/index.js +10 -8
  137. package/dist/hooks/useGtm.js +10 -8
  138. package/dist/hooks/useMoney.js +10 -8
  139. package/dist/hooks/useStore.js +10 -8
  140. package/dist/index.js +10 -8
  141. package/dist/index.js.map +1 -1
  142. package/dist/{not-found-QTHBFPNT.js → not-found-E6AR4CZ4.js} +12 -10
  143. package/dist/not-found-E6AR4CZ4.js.map +1 -0
  144. package/dist/providers/index.js +10 -8
  145. package/dist/routes/account/orders.js +1 -1
  146. package/dist/routes/account.js +6 -6
  147. package/dist/routes/blog.js +5 -5
  148. package/dist/routes/brands.js +1 -1
  149. package/dist/routes/cart.js +14 -12
  150. package/dist/routes/cart.js.map +1 -1
  151. package/dist/routes/home.js +13 -11
  152. package/dist/routes/loyalty.js +2 -2
  153. package/dist/routes/page.js +1 -1
  154. package/dist/routes/product-listing.js +12 -10
  155. package/dist/routes/product-listing.js.map +1 -1
  156. package/dist/routes/product.js +12 -10
  157. package/dist/routes/product.js.map +1 -1
  158. package/dist/routes/root/beforeLoad.d.ts +2 -2
  159. package/dist/routes/root/beforeLoad.d.ts.map +1 -1
  160. package/dist/routes/root/head.d.ts.map +1 -1
  161. package/dist/routes/testimonials.js +2 -2
  162. package/dist/routes/thank-you.js +1 -1
  163. package/dist/skeleton.js +13 -11
  164. package/dist/tanstack/document-class.d.ts.map +1 -1
  165. package/dist/tanstack/index.d.ts +1 -0
  166. package/dist/tanstack/index.d.ts.map +1 -1
  167. package/dist/tanstack/stylesheet.d.ts +15 -0
  168. package/dist/tanstack/stylesheet.d.ts.map +1 -0
  169. package/dist/tanstack.js +33 -4
  170. package/dist/tanstack.js.map +1 -1
  171. package/dist/utils/index.js +2 -2
  172. package/dist/vite/index.d.ts +1 -1
  173. package/dist/vite/index.d.ts.map +1 -1
  174. package/dist/vite/index.js +14 -25
  175. package/dist/vite/index.js.map +1 -1
  176. package/dist/vite/plugins/twilight-manifest.d.ts +23 -0
  177. package/dist/vite/plugins/twilight-manifest.d.ts.map +1 -1
  178. package/dist/vite/plugins/twilight-schema.plugin.d.ts.map +1 -1
  179. package/package.json +16 -3
  180. package/tailwind/components/Component.tsx.txt +21 -0
  181. package/tailwind/components/ComponentRegistry.ts.txt +66 -0
  182. package/tailwind/components/cart/CartItem.tsx.txt +211 -0
  183. package/tailwind/components/cart/CartSummary.tsx.txt +269 -0
  184. package/tailwind/components/cart/PreOrderNotification.tsx.txt +16 -0
  185. package/tailwind/components/cart/PriceQuoteButton.tsx.txt +21 -0
  186. package/tailwind/components/cart/SeoCartWidget.tsx.txt +99 -0
  187. package/tailwind/components/cart/index.ts.txt +11 -0
  188. package/tailwind/components/cart/lazy.ts.txt +15 -0
  189. package/tailwind/components/collapse/Collapse.tsx.txt +95 -0
  190. package/tailwind/components/collapse/index.ts.txt +41 -0
  191. package/tailwind/components/common/Breadcrumb.tsx.txt +27 -0
  192. package/tailwind/components/common/BreadcrumbJsonLd.tsx.txt +40 -0
  193. package/tailwind/components/common/BreadcrumbTrail.tsx.txt +97 -0
  194. package/tailwind/components/common/CurrencySymbol.tsx.txt +8 -0
  195. package/tailwind/components/common/DeferredData.tsx.txt +122 -0
  196. package/tailwind/components/common/ErrorPage.tsx.txt +69 -0
  197. package/tailwind/components/common/Image.tsx.txt +119 -0
  198. package/tailwind/components/common/Link.tsx.txt +36 -0
  199. package/tailwind/components/common/Link.types.ts.txt +85 -0
  200. package/tailwind/components/common/NoContent.tsx.txt +27 -0
  201. package/tailwind/components/common/RenderWhenVisible.tsx.txt +92 -0
  202. package/tailwind/components/common/index.ts.txt +42 -0
  203. package/tailwind/components/common/lazy.ts.txt +28 -0
  204. package/tailwind/components/defineComponent.ts.txt +32 -0
  205. package/tailwind/components/drawer/Drawer.tsx.txt +219 -0
  206. package/tailwind/components/drawer/index.ts.txt +38 -0
  207. package/tailwind/components/dropdown/Dropdown.tsx.txt +166 -0
  208. package/tailwind/components/dropdown/index.ts.txt +40 -0
  209. package/tailwind/components/home/BundleComponent.tsx.txt +35 -0
  210. package/tailwind/components/home/ComponentErrorBoundary.tsx.txt +98 -0
  211. package/tailwind/components/home/FeaturedProductsStyle1.tsx.txt +125 -0
  212. package/tailwind/components/home/FeaturedProductsStyle2.tsx.txt +127 -0
  213. package/tailwind/components/home/FeaturedProductsStyle3.tsx.txt +71 -0
  214. package/tailwind/components/home/FixedBanner.tsx.txt +68 -0
  215. package/tailwind/components/home/FixedProducts.tsx.txt +72 -0
  216. package/tailwind/components/home/HomePageRenderer.tsx.txt +284 -0
  217. package/tailwind/components/home/PageBlocks.tsx.txt +24 -0
  218. package/tailwind/components/home/ParallaxBackground.tsx.txt +50 -0
  219. package/tailwind/components/home/PhotosSlider.tsx.txt +61 -0
  220. package/tailwind/components/home/ProductsSlider.tsx.txt +87 -0
  221. package/tailwind/components/home/ReorderProducts.tsx.txt +38 -0
  222. package/tailwind/components/home/SquarePhotos.tsx.txt +68 -0
  223. package/tailwind/components/home/StoreFeatures.tsx.txt +34 -0
  224. package/tailwind/components/home/Testimonials.tsx.txt +36 -0
  225. package/tailwind/components/home/Youtube.tsx.txt +48 -0
  226. package/tailwind/components/home/index.ts.txt +50 -0
  227. package/tailwind/components/home/lazy.ts.txt +17 -0
  228. package/tailwind/components/home/register.ts.txt +44 -0
  229. package/tailwind/components/home/reorder-hooks.ts.txt +52 -0
  230. package/tailwind/components/home/types.ts.txt +4 -0
  231. package/tailwind/components/layout/Copyright.tsx.txt +23 -0
  232. package/tailwind/components/layout/CustomerLayout.tsx.txt +91 -0
  233. package/tailwind/components/layout/Footer.tsx.txt +341 -0
  234. package/tailwind/components/layout/Header.tsx.txt +154 -0
  235. package/tailwind/components/layout/MasterLayout.tsx.txt +62 -0
  236. package/tailwind/components/layout/PageAdvertisements.tsx.txt +131 -0
  237. package/tailwind/components/layout/WidgetHead.tsx.txt +53 -0
  238. package/tailwind/components/layout/index.ts.txt +27 -0
  239. package/tailwind/components/layout/lazy.ts.txt +25 -0
  240. package/tailwind/components/layout/types.ts.txt +11 -0
  241. package/tailwind/components/modal/ImageModal.tsx.txt +70 -0
  242. package/tailwind/components/modal/Modal.tsx.txt +245 -0
  243. package/tailwind/components/modal/index.ts.txt +39 -0
  244. package/tailwind/components/modal/lazy.ts.txt +10 -0
  245. package/tailwind/components/navigation/MainMenu.tsx.txt +94 -0
  246. package/tailwind/components/navigation/MobileMenu.tsx.txt +160 -0
  247. package/tailwind/components/navigation/index.ts.txt +4 -0
  248. package/tailwind/components/navigation/lazy.ts.txt +11 -0
  249. package/tailwind/components/product/AddToCartForm.tsx.txt +365 -0
  250. package/tailwind/components/product/ProductCard.tsx.txt +305 -0
  251. package/tailwind/components/product/ProductDetails.tsx.txt +267 -0
  252. package/tailwind/components/product/ProductGallery.tsx.txt +234 -0
  253. package/tailwind/components/product/index.ts.txt +15 -0
  254. package/tailwind/components/product/lazy.ts.txt +9 -0
  255. package/tailwind/components/snippets/AppsSnippets.tsx.txt +225 -0
  256. package/tailwind/components/snippets/SallaSdkScripts.tsx.txt +14 -0
  257. package/tailwind/components/snippets/index.ts.txt +4 -0
  258. package/tailwind/components/store/StoreClosedNotification.tsx.txt +73 -0
  259. package/tailwind/components/store/index.ts.txt +8 -0
  260. package/tailwind/components/store/lazy.ts.txt +8 -0
  261. package/tailwind/components/toast/Toaster.tsx.txt +177 -0
  262. package/tailwind/components/toast/index.ts.txt +10 -0
  263. package/tailwind/components/toast/types.ts.txt +38 -0
  264. package/tailwind/components/toast/useToast.ts.txt +61 -0
  265. package/tailwind/components/tracking/GoogleTag.tsx.txt +77 -0
  266. package/tailwind/components/tracking/SiftSnippet.tsx.txt +49 -0
  267. package/tailwind/components/tracking/TwilightBundles.tsx.txt +67 -0
  268. package/tailwind/components/tracking/index.ts.txt +11 -0
  269. package/tailwind/components/tracking/lazy.ts.txt +11 -0
  270. package/tailwind/components/useComponent.ts.txt +12 -0
  271. package/tailwind/routes/account/index.tsx.txt +16 -0
  272. package/tailwind/routes/account/notifications/NotificationsPage.tsx.txt +54 -0
  273. package/tailwind/routes/account/notifications/index.tsx.txt +39 -0
  274. package/tailwind/routes/account/notifications/loader.ts.txt +22 -0
  275. package/tailwind/routes/account/notifications/types.ts.txt +18 -0
  276. package/tailwind/routes/account/orders/OrderSinglePage.tsx.txt +181 -0
  277. package/tailwind/routes/account/orders/OrdersPage.tsx.txt +28 -0
  278. package/tailwind/routes/account/orders/index.tsx.txt +86 -0
  279. package/tailwind/routes/account/orders/loader.ts.txt +66 -0
  280. package/tailwind/routes/account/orders/single/OrderActions.tsx.txt +197 -0
  281. package/tailwind/routes/account/orders/single/OrderHeader.tsx.txt +143 -0
  282. package/tailwind/routes/account/orders/single/OrderItemRow.tsx.txt +209 -0
  283. package/tailwind/routes/account/orders/single/OrderSections.tsx.txt +215 -0
  284. package/tailwind/routes/account/orders/single/types.ts.txt +38 -0
  285. package/tailwind/routes/account/orders/types.ts.txt +29 -0
  286. package/tailwind/routes/account/profile/ProfilePage.tsx.txt +30 -0
  287. package/tailwind/routes/account/profile/index.tsx.txt +39 -0
  288. package/tailwind/routes/account/profile/loader.ts.txt +16 -0
  289. package/tailwind/routes/account/profile/types.ts.txt +5 -0
  290. package/tailwind/routes/account/settings/SettingsPage.tsx.txt +13 -0
  291. package/tailwind/routes/account/settings/index.tsx.txt +39 -0
  292. package/tailwind/routes/account/settings/loader.ts.txt +13 -0
  293. package/tailwind/routes/account/settings/types.ts.txt +5 -0
  294. package/tailwind/routes/account/types.ts.txt +320 -0
  295. package/tailwind/routes/account/wallet/WalletPage.tsx.txt +195 -0
  296. package/tailwind/routes/account/wallet/index.tsx.txt +38 -0
  297. package/tailwind/routes/account/wallet/loader.ts.txt +27 -0
  298. package/tailwind/routes/account/wallet/types.ts.txt +11 -0
  299. package/tailwind/routes/account/wishlist/WishlistPage.tsx.txt +314 -0
  300. package/tailwind/routes/account/wishlist/WishlistShare.tsx.txt +248 -0
  301. package/tailwind/routes/account/wishlist/index.tsx.txt +40 -0
  302. package/tailwind/routes/account/wishlist/loader.ts.txt +26 -0
  303. package/tailwind/routes/account/wishlist/types.ts.txt +9 -0
  304. package/tailwind/routes/blog/BlogAuthorPage.tsx.txt +82 -0
  305. package/tailwind/routes/blog/BlogCategoryPage.tsx.txt +84 -0
  306. package/tailwind/routes/blog/BlogPage.tsx.txt +191 -0
  307. package/tailwind/routes/blog/BlogSinglePage.tsx.txt +168 -0
  308. package/tailwind/routes/blog/BlogTagPage.tsx.txt +84 -0
  309. package/tailwind/routes/blog/BlogTags.tsx.txt +54 -0
  310. package/tailwind/routes/blog/components.tsx.txt +87 -0
  311. package/tailwind/routes/blog/index.tsx.txt +238 -0
  312. package/tailwind/routes/blog/loader.ts.txt +173 -0
  313. package/tailwind/routes/blog/types.ts.txt +106 -0
  314. package/tailwind/routes/brands/BrandsPage.tsx.txt +179 -0
  315. package/tailwind/routes/brands/index.tsx.txt +47 -0
  316. package/tailwind/routes/brands/loader.ts.txt +14 -0
  317. package/tailwind/routes/brands/types.ts.txt +53 -0
  318. package/tailwind/routes/cart/CartPage.tsx.txt +112 -0
  319. package/tailwind/routes/cart/index.tsx.txt +39 -0
  320. package/tailwind/routes/cart/loader.ts.txt +15 -0
  321. package/tailwind/routes/cart/types.ts.txt +6 -0
  322. package/tailwind/routes/home/HomePage.tsx.txt +53 -0
  323. package/tailwind/routes/home/index.tsx.txt +56 -0
  324. package/tailwind/routes/home/loader.ts.txt +24 -0
  325. package/tailwind/routes/home/types.ts.txt +11 -0
  326. package/tailwind/routes/index.ts.txt +94 -0
  327. package/tailwind/routes/lazy.ts.txt +105 -0
  328. package/tailwind/routes/loyalty/LoyaltyPage.tsx.txt +17 -0
  329. package/tailwind/routes/loyalty/LoyaltyPointsPage.tsx.txt +11 -0
  330. package/tailwind/routes/loyalty/index.tsx.txt +81 -0
  331. package/tailwind/routes/loyalty/loader.ts.txt +53 -0
  332. package/tailwind/routes/loyalty/types.ts.txt +109 -0
  333. package/tailwind/routes/not-found.tsx.txt +50 -0
  334. package/tailwind/routes/page/PageSingle.tsx.txt +34 -0
  335. package/tailwind/routes/page/index.tsx.txt +60 -0
  336. package/tailwind/routes/page/loader.ts.txt +19 -0
  337. package/tailwind/routes/page/types.ts.txt +34 -0
  338. package/tailwind/routes/product/ProductPage.tsx.txt +77 -0
  339. package/tailwind/routes/product/index.tsx.txt +157 -0
  340. package/tailwind/routes/product/loader.ts.txt +35 -0
  341. package/tailwind/routes/product/types.ts.txt +6 -0
  342. package/tailwind/routes/product-listing/ProductListPage.tsx.txt +321 -0
  343. package/tailwind/routes/product-listing/index.tsx.txt +95 -0
  344. package/tailwind/routes/product-listing/loader.ts.txt +323 -0
  345. package/tailwind/routes/product-listing/types.ts.txt +96 -0
  346. package/tailwind/routes/product-listing/useAppliedFilters.ts.txt +130 -0
  347. package/tailwind/routes/product-short-link.ts.txt +104 -0
  348. package/tailwind/routes/root/beforeLoad.ts.txt +354 -0
  349. package/tailwind/routes/root/head.ts.txt +424 -0
  350. package/tailwind/routes/root/index.ts.txt +2 -0
  351. package/tailwind/routes/seo-redirects.ts.txt +82 -0
  352. package/tailwind/routes/testimonials/ReviewsPage.tsx.txt +12 -0
  353. package/tailwind/routes/testimonials/TestimonialsPage.tsx.txt +80 -0
  354. package/tailwind/routes/testimonials/index.tsx.txt +80 -0
  355. package/tailwind/routes/testimonials/loader.ts.txt +29 -0
  356. package/tailwind/routes/testimonials/types.ts.txt +9 -0
  357. package/tailwind/routes/thank-you/ThankYouPage.tsx.txt +241 -0
  358. package/tailwind/routes/thank-you/index.tsx.txt +49 -0
  359. package/tailwind/routes/thank-you/loader.ts.txt +40 -0
  360. package/tailwind/routes/thank-you/types.ts.txt +16 -0
  361. package/tailwind/routes/types.ts.txt +41 -0
  362. package/dist/BlogAuthorPage-GTF4UGSS.js.map +0 -1
  363. package/dist/BlogCategoryPage-TN7Y4NBP.js.map +0 -1
  364. package/dist/BlogPage-TDB3M3PI.js.map +0 -1
  365. package/dist/BlogSinglePage-4A52Q5QW.js.map +0 -1
  366. package/dist/BlogTagPage-TOVPBETA.js.map +0 -1
  367. package/dist/BrandsPage-VUDGYSQI.js.map +0 -1
  368. package/dist/Breadcrumb-CI3SN5YR.js.map +0 -1
  369. package/dist/CartItem-BHLEURAB.js.map +0 -1
  370. package/dist/CartSummary-QERVESYN.js.map +0 -1
  371. package/dist/CustomerLayout-VRZUWGQK.js.map +0 -1
  372. package/dist/LoyaltyPage-CGTHWJ76.js.map +0 -1
  373. package/dist/LoyaltyPointsPage-QSU6K3PW.js.map +0 -1
  374. package/dist/MobileMenu-U4BVQYKH.js.map +0 -1
  375. package/dist/NotificationsPage-ZRRQY7TF.js.map +0 -1
  376. package/dist/OrderSinglePage-O3XYVMG5.js.map +0 -1
  377. package/dist/OrdersPage-CMXZF5MI.js.map +0 -1
  378. package/dist/ProductDetails-65GDABI7.js.map +0 -1
  379. package/dist/ProfilePage-SNJ4WXU4.js.map +0 -1
  380. package/dist/SeoCartWidget-DBJAXJKT.js.map +0 -1
  381. package/dist/SettingsPage-FLTIOPU5.js.map +0 -1
  382. package/dist/ThankYouPage-5X6B4X3T.js.map +0 -1
  383. package/dist/WalletPage-H2BKIDPA.js.map +0 -1
  384. package/dist/WishlistPage-RS5UCIQ3.js.map +0 -1
  385. package/dist/chunk-4CZRUAZB.js.map +0 -1
  386. package/dist/chunk-7WAXN2PP.js +0 -14
  387. package/dist/chunk-JO7JWV34.js.map +0 -1
  388. package/dist/chunk-NZVR4OF7.js.map +0 -1
  389. package/dist/chunk-SDFDS4Q3.js.map +0 -1
  390. package/dist/not-found-QTHBFPNT.js.map +0 -1
@@ -0,0 +1,177 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { Toaster as SonnerToaster, toast } from 'sonner';
3
+ import { useTwilight } from '../../providers/twilight-context';
4
+ import { isNativeApp } from '../../native-app';
5
+ import type { ToastPosition } from './types';
6
+
7
+ const toastClassNames = {
8
+ toast: 'group bg-white border-2 rounded-xl shadow-2xl p-4 font-primary',
9
+ title: 'text-base font-bold',
10
+ description: 'text-sm mt-1 text-gray-600',
11
+ actionButton: 'bg-primary text-white px-3 py-1 rounded',
12
+ cancelButton: 'bg-gray-100 px-3 py-1 rounded',
13
+ success: 'border-green-500 [&_svg]:text-green-500 [&_aside]:text-green-700',
14
+ error: 'border-red-500 [&_svg]:text-red-500 [&_aside]:text-red-700',
15
+ warning: 'border-yellow-500 [&_svg]:text-yellow-500 [&_aside]:text-yellow-700',
16
+ info: 'border-blue-500 [&_svg]:text-blue-500 [&_aside]:text-blue-700',
17
+ loading: 'border-gray-400',
18
+ };
19
+
20
+ type RawMessage = string | { title?: string; text?: string; icon?: string };
21
+ type ToastVariant = 'success' | 'error' | 'warning' | 'info';
22
+
23
+ const MOBILE_BREAKPOINT = 768;
24
+ const NATIVE_ALERT_EVENT = 'ui::alert';
25
+
26
+ function dispatchNativeAlert(type: ToastVariant, message: string, title?: string) {
27
+ const salla = window.salla;
28
+ if (!isNativeApp() || !salla?.event?.dispatch) return false;
29
+
30
+ salla.event.dispatch(NATIVE_ALERT_EVENT, {
31
+ type,
32
+ message,
33
+ ...(title ? { title } : {}),
34
+ });
35
+ return true;
36
+ }
37
+
38
+ export function Toaster({
39
+ mobilePosition = 'bottom-center',
40
+ addToCartToast = true,
41
+ }: {
42
+ mobilePosition?: ToastPosition;
43
+ /** Show the default add-to-cart toast. Themes whose cart badge is the feedback can turn it off. */
44
+ addToCartToast?: boolean;
45
+ }) {
46
+ const { theme } = useTwilight();
47
+ const themeRef = useRef(theme);
48
+ themeRef.current = theme;
49
+ const flashShownRef = useRef(false);
50
+
51
+ const isRtl = theme.is_rtl;
52
+ const desktopPosition: ToastPosition = isRtl ? 'top-left' : 'top-right';
53
+
54
+ const [position, setPosition] = useState<ToastPosition>(() => {
55
+ if (typeof window === 'undefined') return desktopPosition;
56
+ return window.innerWidth < MOBILE_BREAKPOINT ? mobilePosition : desktopPosition;
57
+ });
58
+
59
+ useEffect(() => {
60
+ const handleResize = () => {
61
+ setPosition(window.innerWidth < MOBILE_BREAKPOINT ? mobilePosition : desktopPosition);
62
+ };
63
+ window.addEventListener('resize', handleResize);
64
+ return () => window.removeEventListener('resize', handleResize);
65
+ }, [desktopPosition, mobilePosition]);
66
+
67
+ useEffect(() => {
68
+ const salla = window.salla;
69
+ if (!salla) return;
70
+ let active = true;
71
+
72
+ const handleNotify = (message: RawMessage, type: string, data?: unknown) => {
73
+ const eventData = data as { data?: { googleTags?: { event?: string } } } | undefined;
74
+ const shouldSuppressAddToCartToast =
75
+ (!addToCartToast || themeRef.current.settings?.enable_add_product_toast) &&
76
+ eventData?.data?.googleTags?.event === 'addToCart';
77
+ let title: string;
78
+ let toastType: ToastVariant;
79
+
80
+ if (typeof message === 'object' && message !== null) {
81
+ title = message.title || message.text || '';
82
+ toastType = (message.icon || type || 'info') as ToastVariant;
83
+ } else {
84
+ title = message;
85
+ toastType = (type || 'info') as ToastVariant;
86
+ }
87
+
88
+ // Suppress the default addToCart toast when the theme opted out (addToCartToast=false)
89
+ // or renders its own rich toast (enable_add_product_toast) so they don't double up.
90
+ if (shouldSuppressAddToCartToast) {
91
+ return;
92
+ }
93
+
94
+ if (dispatchNativeAlert(toastType, title)) {
95
+ return;
96
+ }
97
+
98
+ if (toastType === 'success') {
99
+ toast.success(title, { duration: 3000 });
100
+ } else if (toastType === 'error') {
101
+ toast.error(title, { duration: 3000 });
102
+ } else if (toastType === 'warning') {
103
+ toast.warning(title, { duration: 3000 });
104
+ } else {
105
+ toast.info(title, { duration: 3000 });
106
+ }
107
+ };
108
+
109
+ // Before the SDK loads `salla` is the head stub, and the SDK's default notifier is alert().
110
+ void (async () => {
111
+ try {
112
+ await salla.onReady?.();
113
+ } catch {
114
+ // onReady() may fail during partial initialization; the toast still beats alert().
115
+ }
116
+ if (active) salla.notify?.setNotifier?.(handleNotify);
117
+ })();
118
+ return () => {
119
+ active = false;
120
+ salla.notify?.setNotifier?.(() => {});
121
+ };
122
+ }, [addToCartToast]);
123
+
124
+ useEffect(() => {
125
+ if (flashShownRef.current || typeof window === 'undefined') return;
126
+
127
+ const params = new URLSearchParams(window.location.search);
128
+ const successMsg = params.get('success');
129
+ const dangerMsg = params.get('danger');
130
+
131
+ if (!successMsg && !dangerMsg) return;
132
+
133
+ flashShownRef.current = true;
134
+
135
+ const message = successMsg || dangerMsg || '';
136
+ const toastType = dangerMsg ? 'error' : 'success';
137
+
138
+ const url = new URL(window.location.href);
139
+ url.searchParams.delete('success');
140
+ url.searchParams.delete('danger');
141
+ window.history.replaceState({}, '', url.toString());
142
+
143
+ const timer = setTimeout(() => {
144
+ if (dispatchNativeAlert(toastType, message)) return;
145
+
146
+ if (toastType === 'success') {
147
+ toast.success(message, { duration: 3000 });
148
+ } else {
149
+ toast.error(message, { duration: 3000 });
150
+ }
151
+ }, 100);
152
+
153
+ return () => clearTimeout(timer);
154
+ }, []);
155
+
156
+ return (
157
+ <SonnerToaster
158
+ position={position}
159
+ // Keep sonner's default gaps (24px desktop / 16px mobile) but clear the
160
+ // native status bar inset (--app-safe-area-top, set by useSafeAreaInset)
161
+ // so top-positioned toasts aren't covered in the app webview.
162
+ offset={{ top: 'calc(var(--app-safe-area-top, 0px) + 24px)' }}
163
+ mobileOffset={{ top: 'calc(var(--app-safe-area-top, 0px) + 16px)' }}
164
+ toastOptions={{
165
+ classNames: toastClassNames,
166
+ style: {
167
+ fontFamily: 'var(--font-main, inherit)',
168
+ },
169
+ }}
170
+ style={{
171
+ fontFamily: 'var(--font-main, inherit)',
172
+ }}
173
+ />
174
+ );
175
+ }
176
+
177
+ export type { ToasterProps } from 'sonner';
@@ -0,0 +1,10 @@
1
+ export { Toaster } from './Toaster';
2
+ export { useToast, toast } from './useToast';
3
+ export type {
4
+ ToastOptions,
5
+ ToastType,
6
+ ToastPosition,
7
+ ToastUpdateOptions,
8
+ ToastPromiseOptions,
9
+ ToastFn,
10
+ } from './types';
@@ -0,0 +1,38 @@
1
+ import type { ExternalToast } from 'sonner';
2
+
3
+ export type ToastType = 'success' | 'error' | 'warning' | 'info' | 'loading';
4
+
5
+ export type ToastPosition =
6
+ | 'top-left'
7
+ | 'top-right'
8
+ | 'bottom-left'
9
+ | 'bottom-right'
10
+ | 'top-center'
11
+ | 'bottom-center';
12
+
13
+ export interface ToastOptions extends ExternalToast {
14
+ description?: string;
15
+ }
16
+
17
+ export interface ToastUpdateOptions extends ToastOptions {
18
+ title?: string;
19
+ type?: ToastType;
20
+ }
21
+
22
+ export interface ToastPromiseOptions<T = unknown> {
23
+ loading: string;
24
+ success: string | ((data: T) => string);
25
+ error: string | ((error: Error) => string);
26
+ }
27
+
28
+ export interface ToastFn {
29
+ (title: string, options?: ToastOptions): string | number;
30
+ success: (title: string, options?: ToastOptions) => string | number;
31
+ error: (title: string, options?: ToastOptions) => string | number;
32
+ warning: (title: string, options?: ToastOptions) => string | number;
33
+ info: (title: string, options?: ToastOptions) => string | number;
34
+ loading: (title: string, options?: ToastOptions) => string | number;
35
+ update: (id: string | number, options: ToastUpdateOptions) => void;
36
+ dismiss: (id?: string | number) => void;
37
+ promise: <T>(promise: Promise<T>, options: ToastPromiseOptions<T>) => Promise<T>;
38
+ }
@@ -0,0 +1,61 @@
1
+ import { toast as sonnerToast } from 'sonner';
2
+ import type { ToastT } from 'sonner';
3
+ import type { ToastFn, ToastOptions, ToastUpdateOptions, ToastPromiseOptions } from './types';
4
+
5
+ export const useToast: ToastFn = Object.assign(
6
+ (title: string, options?: ToastOptions) => sonnerToast(title, options),
7
+ {
8
+ success: (title: string, options?: ToastOptions) => sonnerToast.success(title, options),
9
+ error: (title: string, options?: ToastOptions) => sonnerToast.error(title, options),
10
+ warning: (title: string, options?: ToastOptions) => sonnerToast.warning(title, options),
11
+ info: (title: string, options?: ToastOptions) => sonnerToast.info(title, options),
12
+ loading: (title: string, options?: ToastOptions) => sonnerToast.loading(title, options),
13
+ update: (id: string | number, options: ToastUpdateOptions) => {
14
+ // sonner updates an existing toast when `id` is passed in the options;
15
+ // the first argument is the message (title), not the id.
16
+ const { title, type, ...rest } = options;
17
+ const opts = { ...rest, id };
18
+ // sonner overwrites the title with the message, so reuse the current one when none is given.
19
+ const message =
20
+ title ??
21
+ sonnerToast.getToasts().find((t): t is ToastT => t.id === id && 'title' in t)?.title;
22
+ if (type === 'success') {
23
+ sonnerToast.success(message, opts);
24
+ } else if (type === 'error') {
25
+ sonnerToast.error(message, opts);
26
+ } else if (type === 'warning') {
27
+ sonnerToast.warning(message, opts);
28
+ } else if (type === 'info') {
29
+ sonnerToast.info(message, opts);
30
+ } else if (type === 'loading') {
31
+ sonnerToast.loading(message, opts);
32
+ } else {
33
+ sonnerToast(message, opts);
34
+ }
35
+ },
36
+ dismiss: (id?: string | number) => {
37
+ if (id !== undefined) {
38
+ sonnerToast.dismiss(id);
39
+ } else {
40
+ sonnerToast.dismiss();
41
+ }
42
+ },
43
+ promise: <T>(promise: Promise<T>, options: ToastPromiseOptions<T>): Promise<T> => {
44
+ sonnerToast.promise(promise, {
45
+ loading: options.loading,
46
+ success: options.success,
47
+ error: options.error,
48
+ });
49
+ return promise;
50
+ },
51
+ }
52
+ ) as ToastFn;
53
+
54
+ export { useToast as toast };
55
+ export type {
56
+ ToastOptions,
57
+ ToastType,
58
+ ToastPosition,
59
+ ToastUpdateOptions,
60
+ ToastPromiseOptions,
61
+ } from './types';
@@ -0,0 +1,77 @@
1
+ import { useEffect } from 'react';
2
+
3
+ export interface GoogleTagBodyProps {
4
+ /** GTM container IDs - if empty, renders nothing */
5
+ gtmIds?: string[];
6
+ }
7
+
8
+ /**
9
+ * Generates the GTM head script content.
10
+ */
11
+ function gtmScript(gtmId: string): string {
12
+ return `
13
+ window.dataLayer = window.dataLayer || [];
14
+ (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
15
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
16
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
17
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
18
+ })(window,document,'script','dataLayer','${gtmId}');
19
+
20
+ window.dataLayer = new Proxy(window.dataLayer, {
21
+ set(target, property, value) {
22
+ target[property] = value;
23
+ if (typeof value === 'object') {
24
+ ['form_data', 'data', 'gateway', 'config', 'request', 'headers']
25
+ .forEach(function(key) { value && value.hasOwnProperty(key) && delete value[key]; });
26
+ }
27
+ return true;
28
+ }
29
+ });
30
+ `.trim();
31
+ }
32
+
33
+ const INTERACTION_EVENTS = ['pointerdown', 'keydown', 'touchstart', 'scroll', 'wheel'] as const;
34
+
35
+ /** How long after `load` GTM waits for a visitor who never interacts. */
36
+ export const GTM_LOAD_DELAY_MS = 4000;
37
+
38
+ /** Injects GTM on the first interaction or GTM_LOAD_DELAY_MS after `load`, off the page's load path. */
39
+ export function GoogleTagBody({ gtmIds }: GoogleTagBodyProps): null {
40
+ const gtmId = gtmIds?.[0];
41
+
42
+ useEffect(() => {
43
+ if (!gtmId) return;
44
+ const id = gtmId;
45
+
46
+ let timer: number | undefined;
47
+ const stopWaiting = () => {
48
+ window.clearTimeout(timer);
49
+ window.removeEventListener('load', onLoad);
50
+ INTERACTION_EVENTS.forEach((type) => window.removeEventListener(type, inject));
51
+ };
52
+ function inject() {
53
+ stopWaiting();
54
+ if (document.getElementById('gtm-script')) return;
55
+ const script = document.createElement('script');
56
+ script.id = 'gtm-script';
57
+ script.textContent = gtmScript(id);
58
+ document.head.appendChild(script);
59
+ }
60
+ function onLoad() {
61
+ timer = window.setTimeout(inject, GTM_LOAD_DELAY_MS);
62
+ }
63
+
64
+ INTERACTION_EVENTS.forEach((type) =>
65
+ window.addEventListener(type, inject, { once: true, passive: true })
66
+ );
67
+ if (document.readyState === 'complete') onLoad();
68
+ else window.addEventListener('load', onLoad, { once: true });
69
+
70
+ return () => {
71
+ stopWaiting();
72
+ document.getElementById('gtm-script')?.remove();
73
+ };
74
+ }, [gtmId]);
75
+
76
+ return null;
77
+ }
@@ -0,0 +1,49 @@
1
+ import { useEffect } from 'react';
2
+
3
+ export interface SiftSnippetProps {
4
+ /** Sift Science beacon key - if empty, renders nothing */
5
+ beaconKey?: string;
6
+ /** Logged-in customer ID, or empty for guests */
7
+ customerId?: string;
8
+ }
9
+
10
+ /**
11
+ * SiftSnippet - Injects Sift Science fraud detection script.
12
+ *
13
+ * Mirrors PHP SiftSnippetJsWidget:
14
+ * - Injects Sift Science beacon script via useEffect
15
+ * - Tracks user ID, session ID, and page views
16
+ * - Used for fraud detection and risk scoring
17
+ */
18
+ export function SiftSnippet({ beaconKey, customerId }: SiftSnippetProps): null {
19
+ useEffect(() => {
20
+ if (!beaconKey) return;
21
+
22
+ // Get session ID from Salla analytics
23
+ const salla = window.salla;
24
+ const sessionId = salla?.analytics?._anonymousId || '';
25
+
26
+ window._sift = window._sift ?? [];
27
+ const _sift = window._sift;
28
+
29
+ // Push configuration
30
+ _sift.push(['_setAccount', beaconKey]);
31
+ _sift.push(['_setUserId', customerId || '']);
32
+ _sift.push(['_setSessionId', sessionId]);
33
+ _sift.push(['_trackPageview']);
34
+
35
+ // Load the Sift script
36
+ const script = document.createElement('script');
37
+ script.src = 'https://cdn.sift.com/s.js';
38
+ script.async = true;
39
+ document.body.appendChild(script);
40
+
41
+ return () => {
42
+ script.remove();
43
+ // Clear sift queue on unmount
44
+ window._sift = undefined;
45
+ };
46
+ }, [beaconKey, customerId]);
47
+
48
+ return null;
49
+ }
@@ -0,0 +1,67 @@
1
+ import { useEffect } from 'react';
2
+
3
+ /**
4
+ * TwilightBundles - Injects twilight bundles script when custom components are detected.
5
+ *
6
+ * Mirrors PHP TwilightThemesAdditionsWidget:
7
+ * - Sets up MutationObserver to watch for `salla-custom-component` tags
8
+ * - Injects bundles script when a custom component is detected
9
+ * - Uses importmap for lit dependencies
10
+ * - Runs only once
11
+ */
12
+ export function TwilightBundles(): null {
13
+ useEffect(() => {
14
+ // Check if already injected
15
+ if (document.getElementById('twilight-bundles-assets')) {
16
+ return;
17
+ }
18
+
19
+ const bundlesUrl =
20
+ 'https://cdn.assets.salla.network/prod/@salla.sa/twilight-bundles/latest/twilight-bundles.js';
21
+
22
+ const injectBundles = () => {
23
+ // Disconnect observer since we only need to inject once
24
+ window.twilightBundlesObserver?.disconnect?.();
25
+
26
+ if (document.getElementById('twilight-bundles-assets')) {
27
+ return;
28
+ }
29
+
30
+ const script = document.createElement('script');
31
+ script.type = 'module';
32
+ script.src = bundlesUrl;
33
+ script.defer = true;
34
+ script.id = 'twilight-bundles-assets';
35
+ document.head.appendChild(script);
36
+ };
37
+
38
+ // Set up MutationObserver to watch for salla-custom-component
39
+ const observer = new MutationObserver((mutations) => {
40
+ for (const mutation of mutations) {
41
+ for (const node of mutation.addedNodes) {
42
+ if (
43
+ node.nodeType === 1 &&
44
+ (node as Element).tagName?.toLowerCase() === 'salla-custom-component'
45
+ ) {
46
+ injectBundles();
47
+ return;
48
+ }
49
+ }
50
+ }
51
+ });
52
+
53
+ observer.observe(document.body, { childList: true, subtree: true });
54
+ window.twilightBundlesObserver = observer;
55
+
56
+ // Check if component already exists on mount
57
+ if (document.querySelector('salla-custom-component')) {
58
+ injectBundles();
59
+ }
60
+
61
+ return () => {
62
+ observer.disconnect();
63
+ };
64
+ }, []);
65
+
66
+ return null;
67
+ }
@@ -0,0 +1,11 @@
1
+ // Component - injects GTM script + noscript via useEffect
2
+ export { GoogleTagBody, type GoogleTagBodyProps } from './GoogleTag';
3
+
4
+ // Component - injects Sift Science fraud detection script
5
+ export { SiftSnippet, type SiftSnippetProps } from './SiftSnippet';
6
+
7
+ // Component - injects twilight bundles when custom components detected
8
+ export { TwilightBundles } from './TwilightBundles';
9
+
10
+ // Lazy components
11
+ export { LazyGoogleTagBody, LazySiftSnippet } from './lazy';
@@ -0,0 +1,11 @@
1
+ import { lazy } from 'react';
2
+
3
+ /** Lazy-loaded GoogleTagBody component. */
4
+ export const LazyGoogleTagBody = lazy(() =>
5
+ import('./GoogleTag').then((m) => ({ default: m.GoogleTagBody }))
6
+ );
7
+
8
+ /** Lazy-loaded SiftSnippet component. */
9
+ export const LazySiftSnippet = lazy(() =>
10
+ import('./SiftSnippet').then((m) => ({ default: m.SiftSnippet }))
11
+ );
@@ -0,0 +1,12 @@
1
+ import { registry } from './ComponentRegistry';
2
+ import type { ComponentType } from '../types';
3
+
4
+ export function useComponent<P = Record<string, unknown>>(name: string): ComponentType<P> | null {
5
+ return registry.resolve<P>(name);
6
+ }
7
+
8
+ export function useOriginalComponent<P = Record<string, unknown>>(
9
+ name: string
10
+ ): ComponentType<P> | null {
11
+ return registry.getOriginal<P>(name);
12
+ }
@@ -0,0 +1,16 @@
1
+ // Re-export from organized route folders
2
+ export * from './profile';
3
+ export * from './wishlist';
4
+ export * from './wallet';
5
+ export * from './notifications';
6
+ export * from './settings';
7
+ export * from './orders';
8
+
9
+ // Re-export shared types for backward compatibility
10
+ export type {
11
+ Order,
12
+ OrderItem,
13
+ OrderListItem,
14
+ OrdersPageProps,
15
+ OrderSinglePageProps,
16
+ } from './types';
@@ -0,0 +1,54 @@
1
+ import { HookSlot } from '../../../hooks';
2
+ import { NoContent } from '../../../components/common';
3
+ import { useTranslation } from '../../../providers/I18nProvider';
4
+ import type { NotificationsPageProps, Notification } from './types';
5
+
6
+ function NotificationItem({ notification }: { notification: Notification }) {
7
+ return (
8
+ <a
9
+ href={notification.url}
10
+ className={`s-notifications-item s-notifications-item-shadow${notification.is_read ? ' s-notifications-item-read' : ''}`}
11
+ >
12
+ <span className="s-notifications-item-icon">
13
+ <i
14
+ className={`s-notifications-item-icon sicon-bell-ring${!notification.is_read ? ' s-notifications-item-icon-new' : ''}`}
15
+ ></i>
16
+ </span>
17
+ <div className="s-notifications-item-content">
18
+ <div className="s-notifications-item-content-leading">
19
+ <h4>{notification.title}</h4>
20
+ <p>{notification.body}</p>
21
+ </div>
22
+ <span className="s-notifications-item-content-trailing">
23
+ <i className="sicon-time s-notifications-item-content-trailing-icon"></i>
24
+ <span>{notification.time_ago}</span>
25
+ </span>
26
+ </div>
27
+ </a>
28
+ );
29
+ }
30
+
31
+ export function NotificationsPage({ notifications }: NotificationsPageProps) {
32
+ const { t } = useTranslation();
33
+
34
+ return (
35
+ <>
36
+ <HookSlot name="customer:notifications.items.start" />
37
+ <div className="s-notifications-wrapper">
38
+ {notifications.length > 0 ? (
39
+ <div className="s-notifications-container space-y-2">
40
+ {notifications.map((item: Notification) => (
41
+ <NotificationItem key={item.id} notification={item} />
42
+ ))}
43
+ </div>
44
+ ) : (
45
+ <NoContent
46
+ icon="sicon-bell-ring"
47
+ message={t('blocks.header.no_notifications', 'No notifications')}
48
+ />
49
+ )}
50
+ </div>
51
+ <HookSlot name="customer:notifications.items.end" />
52
+ </>
53
+ );
54
+ }
@@ -0,0 +1,39 @@
1
+ import type { HeadDescriptor } from '../../../utils/head';
2
+ import { buildHreflangAlternates } from '../../../utils/baseHead';
3
+ import { lazy } from 'react';
4
+ import { notificationsLoader } from './loader';
5
+ import type { NotificationsPageProps } from './types';
6
+ import type { TwilightContext } from '../../../twilight/context';
7
+ import { RouteId } from '../../../router/route-ids';
8
+
9
+ const LazyNotificationsPage = lazy(() =>
10
+ import('./NotificationsPage').then((m) => ({ default: m.NotificationsPage }))
11
+ );
12
+
13
+ export const NotificationsPage = LazyNotificationsPage;
14
+ export { notificationsLoader } from './loader';
15
+ export type { NotificationsPageProps, Notification } from './types';
16
+
17
+ export const Notifications = {
18
+ id: RouteId.CUSTOMER_NOTIFICATIONS,
19
+ loader: async (
20
+ _ctx: { locale?: string },
21
+ extend?: (
22
+ data: NotificationsPageProps,
23
+ ctx: { params: Record<string, never> }
24
+ ) => Promise<Record<string, unknown>> | Record<string, unknown>
25
+ ): Promise<NotificationsPageProps> => {
26
+ const data = await notificationsLoader({ locale: _ctx.locale ?? 'ar' });
27
+ if (extend) {
28
+ const extra = await extend(data, { params: {} });
29
+ return { ...data, ...extra } as NotificationsPageProps;
30
+ }
31
+ return data;
32
+ },
33
+ head: (ctx: TwilightContext, data: NotificationsPageProps): HeadDescriptor => ({
34
+ title: data.page.title,
35
+ description: data.page.description,
36
+ alternateLanguages: buildHreflangAlternates(ctx.settings, ctx.location.pathname),
37
+ }),
38
+ Component: LazyNotificationsPage,
39
+ } as const;
@@ -0,0 +1,22 @@
1
+ import { notification } from '../../../api/notification';
2
+ import { getTwilightContext } from '../../../twilight/context';
3
+ import { orUnauthorized, unauthorized } from '../../../providers/NavigationProvider';
4
+ import { getAuthToken } from '../../../api/client';
5
+ import type { NotificationsPageProps } from './types';
6
+ import { RouteId } from '../../../router/route-ids';
7
+
8
+ export async function notificationsLoader(_ctx: {
9
+ locale: string;
10
+ }): Promise<NotificationsPageProps> {
11
+ if (!getAuthToken()) throw unauthorized();
12
+ const i18n = getTwilightContext().i18n;
13
+ const response = await orUnauthorized(notification.list());
14
+
15
+ return {
16
+ page: {
17
+ title: i18n.t('common.titles.notifications') || 'Notifications',
18
+ slug: RouteId.CUSTOMER_NOTIFICATIONS,
19
+ },
20
+ notifications: response.data,
21
+ };
22
+ }
@@ -0,0 +1,18 @@
1
+ import type { Page } from '../../../types';
2
+
3
+ export interface Notification {
4
+ id: number;
5
+ title: string;
6
+ color: string;
7
+ icon: string;
8
+ url: string;
9
+ body: string;
10
+ is_read: boolean;
11
+ time_ago: string;
12
+ created_at: number;
13
+ }
14
+
15
+ export interface NotificationsPageProps {
16
+ page: Page;
17
+ notifications: Notification[];
18
+ }