@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,154 @@
1
+ import { useState } from 'react';
2
+ import { useIsHome } from '../../providers/NavigationProvider';
3
+ import { SallaCartSummary } from '@salla.sa/twilight-components-react/cart-summary';
4
+ import { SallaContacts } from '@salla.sa/twilight-components-react/contacts';
5
+ import { SallaLocalizationModal } from '@salla.sa/twilight-components-react/localization-modal';
6
+ import { SallaMenu } from '@salla.sa/twilight-components-react/menu';
7
+ import { SallaSearch } from '@salla.sa/twilight-components-react/search';
8
+ import { SallaUserMenu } from '@salla.sa/twilight-components-react/user-menu';
9
+ import { useTwilight } from '../../providers/twilight-context';
10
+ import { useTranslation } from '../../providers/I18nProvider';
11
+ import { HookSlot } from '../../hooks/HookSlot';
12
+ import { MainMenu, MobileMenu } from '../navigation';
13
+ import { Image } from '../common';
14
+ import { PageAdvertisements } from './PageAdvertisements';
15
+ import type { Cart } from '../../types';
16
+
17
+ interface HeaderProps {
18
+ cart?: Cart;
19
+ }
20
+
21
+ export function Header(_props: HeaderProps) {
22
+ const { currency, theme, store } = useTwilight();
23
+ const { locale, languageName } = useTranslation();
24
+ const settings = theme?.settings || {};
25
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
26
+
27
+ // Check if we're on homepage
28
+ const isHomepage = useIsHome();
29
+
30
+ const StoreTitle = isHomepage ? 'h1' : 'span';
31
+
32
+ return (
33
+ <header className="store-header" suppressHydrationWarning>
34
+ <HookSlot name="header:start" />
35
+ <div className="advertisement-slot">
36
+ <PageAdvertisements />
37
+ </div>
38
+ {/* Top Nav */}
39
+ <div className={`top-navbar${settings.topnav_is_dark ? ' top-navbar--dark' : ''}`}>
40
+ <div className="container flex justify-between">
41
+ <div className="flex-1 flex items-center gap-2">
42
+ {/* Footer Menu */}
43
+ {settings.important_links && <SallaMenu source="footer" topnav />}
44
+
45
+ {/* Language & Currency */}
46
+ <div className="header-buttons">
47
+ {(store?.settings?.is_multilingual || store?.settings?.currencies_enabled) && (
48
+ <>
49
+ <button
50
+ type="button"
51
+ onClick={() => window.salla?.event.dispatch('localization::open')}
52
+ className="btn--rounded-gray basis-0"
53
+ >
54
+ <span>{languageName}</span>
55
+ <span className="mx-1.5">|</span>
56
+ <span className={`flag iti__flag iti__${store?.country.toLowerCase()}`}></span>
57
+
58
+ <span>
59
+ {store?.settings?.use_sar_symbol && currency?.code === 'SAR' ? (
60
+ <i className="sicon-sar"></i>
61
+ ) : (
62
+ <>{currency?.symbol}</>
63
+ )}
64
+ </span>
65
+ </button>
66
+ {/* TODO:: support switch the lang without hit the web API, by set it in the sdk and local storage */}
67
+ {/* TODO:: Support switch the curency without hit the web API, by set it in the sdk and local storage */}
68
+ <SallaLocalizationModal
69
+ language={locale}
70
+ currency={currency?.code || 'SAR'}
71
+ suppressHydrationWarning
72
+ />
73
+ </>
74
+ )}
75
+ </div>
76
+
77
+ {/* Scopes / Branches */}
78
+ {store?.scope && (
79
+ <button
80
+ type="button"
81
+ className="btn--rounded-gray"
82
+ onClick={() =>
83
+ window.salla?.event.dispatch('scopes::open', {
84
+ mode: 'default',
85
+ })
86
+ }
87
+ >
88
+ <i className="sicon-location rtl:ml-1 ltr:mr-1"></i>
89
+ {store.scope.name}
90
+ </button>
91
+ )}
92
+
93
+ {/* Search bar */}
94
+ <div className="header-search flex-1">
95
+ {/* todo:: use a search icon insted with open the search popup */}
96
+ <SallaSearch inline oval height={36} />
97
+ </div>
98
+ </div>
99
+
100
+ <SallaContacts contacts={store?.contacts} contactsTitle="N/A" isHeader />
101
+ </div>
102
+ </div>
103
+
104
+ {/* Main Nav */}
105
+ <div
106
+ id="mainnav"
107
+ className={`main-nav-container shadow-default bg-white flex items-center relative z-50${settings.header_is_sticky ? ' sticky top-0' : ''}`}
108
+ >
109
+ <div className="inner bg-inherit w-full">
110
+ <div className="container">
111
+ <div className="flex items-stretch justify-between relative">
112
+ <div className="flex items-center">
113
+ <a
114
+ className="lg:hidden mburger mburger--collapse leading-none rtl:ml-4 ltr:mr-4"
115
+ href="#mobile-menu"
116
+ aria-label="Open-menu"
117
+ onClick={(e) => {
118
+ e.preventDefault();
119
+ setIsMobileMenuOpen(true);
120
+ }}
121
+ >
122
+ <i className="sicon-menu text-primary text-2xl"></i>
123
+ </a>
124
+ <a className="navbar-brand" href={store?.url || '/'}>
125
+ <div className="logo-wrapper">
126
+ <Image
127
+ src={store?.logo}
128
+ alt={`${store?.name || 'Store'} logo`}
129
+ priority
130
+ width={120}
131
+ height={48}
132
+ />
133
+ </div>
134
+ <StoreTitle className="sr-only">{store?.name || 'Store'}</StoreTitle>
135
+ </a>
136
+ <MainMenu />
137
+ </div>
138
+ <div className="flex items-center justify-end my-2.5">
139
+ <SallaUserMenu avatarOnly showHeader className="header-btn" />
140
+ <SallaCartSummary className="ml-4 rtl:ml-[unset] rtl:mr-4">
141
+ <i slot="icon" className="header-btn__icon icon sicon-shopping-bag"></i>
142
+ </SallaCartSummary>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+
149
+ {/* Mobile Menu */}
150
+ <MobileMenu isOpen={isMobileMenuOpen} onClose={() => setIsMobileMenuOpen(false)} />
151
+ <HookSlot name="header:end" />
152
+ </header>
153
+ );
154
+ }
@@ -0,0 +1,63 @@
1
+ import { lazy, Suspense } from 'react';
2
+ import { Header } from './Header';
3
+ import { Footer } from './Footer';
4
+ import type { LayoutProps } from '../../types';
5
+ import { useTwilight } from '../../providers/twilight-context';
6
+ import { useUser } from '../../hooks';
7
+
8
+ const SallaLoginModal = lazy(() =>
9
+ import('@salla.sa/twilight-components-react/login-modal').then((m) => ({
10
+ default: m.SallaLoginModal,
11
+ }))
12
+ );
13
+ const SallaScopes = lazy(() =>
14
+ import('@salla.sa/twilight-components-react/scopes').then((m) => ({
15
+ default: m.SallaScopes,
16
+ }))
17
+ );
18
+ const SallaOfferModal = lazy(() =>
19
+ import('@salla.sa/twilight-components-react/offer-modal').then((m) => ({
20
+ default: m.SallaOfferModal,
21
+ }))
22
+ );
23
+
24
+ export function MasterLayout({ children }: LayoutProps) {
25
+ const { store } = useTwilight();
26
+ const { isLoggedIn } = useUser();
27
+
28
+ return (
29
+ <>
30
+ <div className="app-inner flex flex-col min-h-full">
31
+ <Header />
32
+ <main id="main-content" role="main" className="flex-1">
33
+ {children}
34
+ </main>
35
+ <Footer />
36
+ </div>
37
+
38
+ <Suspense>
39
+ <SallaOfferModal />
40
+ </Suspense>
41
+
42
+ {!isLoggedIn && (
43
+ <Suspense>
44
+ <SallaLoginModal
45
+ isEmailAllowed={store?.settings?.auth?.email_allowed}
46
+ isMobileAllowed={store?.settings?.auth?.mobile_allowed}
47
+ isEmailRequired={store?.settings?.auth?.is_email_required}
48
+ suppressHydrationWarning
49
+ />
50
+ </Suspense>
51
+ )}
52
+
53
+ {store?.scope && (
54
+ <Suspense>
55
+ <SallaScopes
56
+ selection={store?.scope?.display_as === 'popup' ? 'mandatory' : 'optional'}
57
+ suppressHydrationWarning
58
+ />
59
+ </Suspense>
60
+ )}
61
+ </>
62
+ );
63
+ }
@@ -0,0 +1,131 @@
1
+ import { useEffect, useState, useSyncExternalStore } from 'react';
2
+ import { useQuery } from '@tanstack/react-query';
3
+ import { advertisement, advertisementsFor, type Advertisement } from '../../api/advertisement';
4
+ import { whenSallaReady } from '../../utils/sdk-helpers';
5
+ import { useTranslation } from '../../providers/I18nProvider';
6
+ import { getTwilightContext, subscribeTwilight } from '../../twilight/context';
7
+
8
+ const currentPageSlug = () => getTwilightContext().page?.slug;
9
+
10
+ /** The key `<salla-advertisement>` marks a closed ad with, through `salla.storage` (store.js, JSON). */
11
+ const dismissedKey = (id: number) => `statusAd-${id}`;
12
+
13
+ /** Stable while the query has no data, so the effect below doesn't rerun on every render. */
14
+ const NO_ADS: Advertisement[] = [];
15
+
16
+ /** Hides the ads this visitor closed before the first paint; the effect then drops them. */
17
+ const HIDE_DISMISSED_SCRIPT =
18
+ "(function(){try{if(window.self!==window.top)return;document.currentScript.parentNode.querySelectorAll('.s-advertisement[data-id]').forEach(function(e){if(localStorage.getItem('statusAd-'+e.getAttribute('data-id')))e.hidden=true})}catch(e){}})();";
19
+
20
+ function isDismissed(id: number): boolean {
21
+ try {
22
+ return Boolean(window.localStorage.getItem(dismissedKey(id)));
23
+ } catch {
24
+ return false;
25
+ }
26
+ }
27
+
28
+ function dismiss(id: number): void {
29
+ const storage = window.salla?.storage;
30
+ if (typeof storage?.set === 'function') storage.set(dismissedKey(id), 'dismissed');
31
+ else {
32
+ try {
33
+ window.localStorage.setItem(dismissedKey(id), JSON.stringify('dismissed'));
34
+ } catch {
35
+ // Storage disabled: the ad hides for this page view only.
36
+ }
37
+ }
38
+ }
39
+
40
+ interface ClientView {
41
+ /** The theme editor's iframe, or the SDK's debug flag: every ad shows, closed or not. */
42
+ preview: boolean;
43
+ /** Inside the Salla mobile app, which shows no ads. */
44
+ inApp: boolean;
45
+ dismissed: Set<number>;
46
+ }
47
+
48
+ /**
49
+ * The merchant's announcement bars, in place of `<salla-advertisement>`. Same data, rules and
50
+ * markup, but rendered on the server (the ads are prefetched in the root `beforeLoad`), so the
51
+ * bar is in the first paint instead of pushing the page down when the web component fetches it.
52
+ */
53
+ export function PageAdvertisements() {
54
+ const { t } = useTranslation();
55
+ // The deepest route loader's `page`, the page `salla.config` reports.
56
+ const pageSlug = useSyncExternalStore(subscribeTwilight, currentPageSlug, currentPageSlug);
57
+ // The query's `retry: 0` only bounds the server wait; the browser may retry.
58
+ const { data: ads = NO_ADS } = useQuery({ ...advertisement.queries.list(), retry: 2 });
59
+ const [view, setView] = useState<ClientView | null>(null);
60
+
61
+ useEffect(() => {
62
+ const dismissed = new Set(ads.filter((ad) => isDismissed(ad.id)).map((ad) => ad.id));
63
+ setView({ preview: window.self !== window.top, inApp: false, dismissed });
64
+ return whenSallaReady((sdk) => {
65
+ const config = sdk.config as { isMobileApp?: () => boolean; isDebug?: () => boolean };
66
+ const inApp = Boolean(config?.isMobileApp?.());
67
+ const debug = Boolean(config?.isDebug?.());
68
+ if (inApp || debug) {
69
+ setView((current) =>
70
+ current ? { ...current, inApp, preview: current.preview || debug } : current
71
+ );
72
+ }
73
+ });
74
+ }, [ads]);
75
+
76
+ if (view?.inApp) return null;
77
+ const shown = view?.preview
78
+ ? ads
79
+ : advertisementsFor(ads, pageSlug).filter((ad) => !view?.dismissed.has(ad.id));
80
+ if (!shown.length) return null;
81
+
82
+ const close = (id: number) => {
83
+ dismiss(id);
84
+ setView((current) =>
85
+ current ? { ...current, dismissed: new Set(current.dismissed).add(id) } : current
86
+ );
87
+ };
88
+
89
+ return (
90
+ <>
91
+ {shown.map((ad) => (
92
+ <div
93
+ key={ad.id}
94
+ className="s-advertisement"
95
+ data-id={ad.id}
96
+ style={{ backgroundColor: ad.colors?.bg, color: ad.colors?.text }}
97
+ >
98
+ <div className="s-advertisement-content container flex justify-between items-center py-2.5">
99
+ <span className="s-advertisement-content-main flex-1 font-bold text-center text-sm">
100
+ {/* Rendered without an icon too, as the SDK does: its margin is part of the layout. */}
101
+ <i
102
+ className={`s-advertisement-content-icon inline-block align-middle me-2 text-base ${ad.icon ?? ''}`}
103
+ />
104
+ {ad.url ? (
105
+ <a
106
+ href={ad.url}
107
+ target={ad.target ?? undefined}
108
+ rel={ad.target === '_blank' ? 'noopener' : undefined}
109
+ >
110
+ {ad.description}
111
+ </a>
112
+ ) : (
113
+ ad.description
114
+ )}
115
+ </span>
116
+ <button
117
+ type="button"
118
+ className="s-advertisement-action px-1"
119
+ aria-label={t('common.buttons.close', 'Close')}
120
+ onClick={() => close(ad.id)}
121
+ >
122
+ {/* `inline-block`: before the icon CSS loads, an empty inline `<i>` leaves the button 0px tall. */}
123
+ <i className="sicon-cancel inline-block" />
124
+ </button>
125
+ </div>
126
+ </div>
127
+ ))}
128
+ <script suppressHydrationWarning>{HIDE_DISMISSED_SCRIPT}</script>
129
+ </>
130
+ );
131
+ }
@@ -0,0 +1,53 @@
1
+ import { useEffect } from 'react';
2
+ import { useTwilight } from '../../providers/twilight-context';
3
+ import { HookSlot } from '../../hooks/HookSlot';
4
+
5
+ /**
6
+ * Pushes the equal-height product card configuration to the GTM dataLayer.
7
+ * Mirrors PHP `HeadWidget::run()` -> `GoogleTagManager::set('equalHeight', ...)`.
8
+ *
9
+ * @param settings - Flat settings map from the store (keyed by dot-path strings).
10
+ */
11
+ export function pushEqualHeightConfig(settings: Record<string, unknown>): void {
12
+ const isEnabled = settings['products::card.equal-height.enabled'];
13
+ if (isEnabled === undefined || isEnabled === null) return;
14
+
15
+ window.dataLayer = window.dataLayer ?? [];
16
+ window.dataLayer.push({
17
+ equalHeight: {
18
+ isEnabled: Boolean(isEnabled),
19
+ max: Number(settings['products::card.equal-height.max-pixel'] ?? 300),
20
+ classType: String(settings['products::card.equal-height.type'] ?? 'min'),
21
+ },
22
+ });
23
+ }
24
+
25
+ /**
26
+ * WidgetHead - Client-side head infrastructure widget.
27
+ *
28
+ * Handles runtime-only head operations that cannot be done in SSR head():
29
+ * - Pushes `equalHeight` config to GTM dataLayer (requires window).
30
+ * - Exposes `head:start`, `head`, and `head:end` HookSlots for theme customisation.
31
+ *
32
+ * Static head elements (favicon, msapplication tiles, theme colors, hreflang, custom CSS/JS)
33
+ * are handled in __root.tsx head() function.
34
+ *
35
+ * Renders no visible UI.
36
+ */
37
+ export function WidgetHead() {
38
+ const { store } = useTwilight();
39
+
40
+ // ── equalHeight → GTM dataLayer ───────────────────────────────────────────
41
+ useEffect(() => {
42
+ const settings = (store.settings as unknown as Record<string, unknown>) ?? {};
43
+ pushEqualHeightConfig(settings);
44
+ }, [store.id, store.settings]);
45
+
46
+ return (
47
+ <>
48
+ <HookSlot name="head:start" ssr />
49
+ <HookSlot name="head" ssr />
50
+ <HookSlot name="head:end" ssr />
51
+ </>
52
+ );
53
+ }
@@ -0,0 +1,27 @@
1
+ import {
2
+ LazyHeader,
3
+ LazyFooter,
4
+ LazyCopyright,
5
+ LazyMasterLayout,
6
+ LazyWidgetHead,
7
+ LazyCustomerLayout,
8
+ } from './lazy';
9
+
10
+ // Lazy-loaded layout components (code-split)
11
+ export {
12
+ LazyHeader as Header,
13
+ LazyFooter as Footer,
14
+ LazyCopyright as Copyright,
15
+ LazyMasterLayout as MasterLayout,
16
+ LazyWidgetHead as WidgetHead,
17
+ LazyCustomerLayout as CustomerLayout,
18
+ };
19
+
20
+ // Eager: the header renders it on the server, so it can't suspend.
21
+ export { PageAdvertisements } from './PageAdvertisements';
22
+
23
+ // Export utilities directly (not components)
24
+ export { pushEqualHeightConfig } from './WidgetHead';
25
+
26
+ // Shared types
27
+ export type { LayoutProps } from './types';
@@ -0,0 +1,25 @@
1
+ import { lazy } from 'react';
2
+
3
+ /**
4
+ * Lazy-loaded layout components
5
+ * Use these for code-splitting layout sections
6
+ */
7
+ export const LazyHeader = lazy(() => import('./Header').then((m) => ({ default: m.Header })));
8
+
9
+ export const LazyFooter = lazy(() => import('./Footer').then((m) => ({ default: m.Footer })));
10
+
11
+ export const LazyCopyright = lazy(() =>
12
+ import('./Copyright').then((m) => ({ default: m.Copyright }))
13
+ );
14
+
15
+ export const LazyMasterLayout = lazy(() =>
16
+ import('./MasterLayout').then((m) => ({ default: m.MasterLayout }))
17
+ );
18
+
19
+ export const LazyWidgetHead = lazy(() =>
20
+ import('./WidgetHead').then((m) => ({ default: m.WidgetHead }))
21
+ );
22
+
23
+ export const LazyCustomerLayout = lazy(() =>
24
+ import('./CustomerLayout').then((m) => ({ default: m.CustomerLayout }))
25
+ );
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Layout Component Types
3
+ * Only types shared across multiple components.
4
+ */
5
+
6
+ import type { ReactNode } from 'react';
7
+
8
+ /** Base props for layout components with children */
9
+ export interface LayoutProps {
10
+ children: ReactNode;
11
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * ImageModal - Modal for displaying images in full scale
3
+ *
4
+ * Used for previewing images like tax certificates, etc.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * const [isOpen, setIsOpen] = useState(false);
9
+ * const [imageSrc, setImageSrc] = useState('');
10
+ *
11
+ * <a onClick={() => { setImageSrc('/images/tax-certificate.jpg'); setIsOpen(true); }}>
12
+ * <img src="/images/tax-thumb.png" />
13
+ * </a>
14
+ *
15
+ * <ImageModal
16
+ * isOpen={isOpen}
17
+ * onClose={() => setIsOpen(false)}
18
+ * src={imageSrc}
19
+ * alt="Tax Certificate"
20
+ * />
21
+ * ```
22
+ */
23
+
24
+ import { useState, type ImgHTMLAttributes } from 'react';
25
+ import { Modal } from './Modal';
26
+
27
+ export interface ImageModalProps {
28
+ isOpen: boolean;
29
+ onClose: () => void;
30
+ /** Image source URL */
31
+ src: string;
32
+ /** Alt text for the image */
33
+ alt?: string;
34
+ /** Title shown in modal header */
35
+ title?: string;
36
+ /** Additional props for the img element */
37
+ imgProps?: Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'alt'>;
38
+ }
39
+
40
+ function ModalImage({ src, alt, imgProps }: Pick<ImageModalProps, 'src' | 'alt' | 'imgProps'>) {
41
+ const [isLoaded, setIsLoaded] = useState(false);
42
+
43
+ return (
44
+ <>
45
+ {!isLoaded && <div className="animate-pulse bg-gray-200 w-full h-64 rounded" />}
46
+ <img
47
+ src={src}
48
+ alt={alt}
49
+ className={`max-w-full max-h-[70vh] object-contain ${isLoaded ? 'block' : 'hidden'}`}
50
+ onLoad={() => setIsLoaded(true)}
51
+ {...imgProps}
52
+ />
53
+ </>
54
+ );
55
+ }
56
+
57
+ export function ImageModal({ isOpen, onClose, src, alt = '', title, imgProps }: ImageModalProps) {
58
+ if (!src) return null;
59
+
60
+ return (
61
+ <Modal isOpen={isOpen} onClose={onClose} size="lg" position="center">
62
+ <Modal.Header onClose={onClose} showCloseButton>
63
+ {title || ''}
64
+ </Modal.Header>
65
+ <Modal.Body className="flex items-center justify-center min-h-64">
66
+ <ModalImage key={src} src={src} alt={alt} imgProps={imgProps} />
67
+ </Modal.Body>
68
+ </Modal>
69
+ );
70
+ }