@salla.sa/twilight-theme-engine 1.0.94 → 1.0.96

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 (353) hide show
  1. package/dist/{AddToCartForm-MASXVJOI.js → AddToCartForm-DASRXMY7.js} +3 -3
  2. package/dist/{AddToCartForm-MASXVJOI.js.map → AddToCartForm-DASRXMY7.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-KRT7MRTC.js → BlogAuthorPage-WFZGYSUB.js} +26 -24
  4. package/dist/BlogAuthorPage-WFZGYSUB.js.map +1 -0
  5. package/dist/{BlogCategoryPage-OP3ETAMT.js → BlogCategoryPage-23PFOVVP.js} +26 -24
  6. package/dist/BlogCategoryPage-23PFOVVP.js.map +1 -0
  7. package/dist/{BlogPage-RGAQVUDI.js → BlogPage-4RFI56TW.js} +24 -22
  8. package/dist/BlogPage-4RFI56TW.js.map +1 -0
  9. package/dist/{BlogSinglePage-VG4UXBTL.js → BlogSinglePage-KMGBQUG5.js} +24 -22
  10. package/dist/BlogSinglePage-KMGBQUG5.js.map +1 -0
  11. package/dist/{BlogTagPage-G4IVHJD5.js → BlogTagPage-ZPQJKPBO.js} +26 -24
  12. package/dist/BlogTagPage-ZPQJKPBO.js.map +1 -0
  13. package/dist/{BrandsPage-2JMPPOOU.js → BrandsPage-FIHOZYMB.js} +25 -23
  14. package/dist/BrandsPage-FIHOZYMB.js.map +1 -0
  15. package/dist/{Breadcrumb-I3ZOGG2Y.js → Breadcrumb-2IXFQL6L.js} +24 -22
  16. package/dist/Breadcrumb-2IXFQL6L.js.map +1 -0
  17. package/dist/{CartItem-YTPYETW6.js → CartItem-GRFH5BED.js} +24 -22
  18. package/dist/CartItem-GRFH5BED.js.map +1 -0
  19. package/dist/{CartSummary-DND7BO26.js → CartSummary-IOCZJL26.js} +24 -22
  20. package/dist/CartSummary-IOCZJL26.js.map +1 -0
  21. package/dist/{Copyright-RWML3BQV.js → Copyright-MDKYCKML.js} +3 -3
  22. package/dist/{Copyright-RWML3BQV.js.map → Copyright-MDKYCKML.js.map} +1 -1
  23. package/dist/{CustomerLayout-HCYVBODI.js → CustomerLayout-4737YCAK.js} +24 -22
  24. package/dist/CustomerLayout-4737YCAK.js.map +1 -0
  25. package/dist/{Footer-3GEKWEQD.js → Footer-2F652QDB.js} +4 -4
  26. package/dist/{Footer-3GEKWEQD.js.map → Footer-2F652QDB.js.map} +1 -1
  27. package/dist/Header-4OATF4LX.js +22 -0
  28. package/dist/{Header-QG4UO3MF.js.map → Header-4OATF4LX.js.map} +1 -1
  29. package/dist/{LoyaltyPage-ZMFYQMQY.js → LoyaltyPage-POFUTIPB.js} +24 -22
  30. package/dist/LoyaltyPage-POFUTIPB.js.map +1 -0
  31. package/dist/{LoyaltyPointsPage-5PB6IFLY.js → LoyaltyPointsPage-L4S4NZA2.js} +8 -7
  32. package/dist/LoyaltyPointsPage-L4S4NZA2.js.map +1 -0
  33. package/dist/{MainMenu-SAUMNMBF.js → MainMenu-ROGX37TG.js} +7 -6
  34. package/dist/MainMenu-ROGX37TG.js.map +1 -0
  35. package/dist/{MasterLayout-TY223YR7.js → MasterLayout-PGL5YU2B.js} +24 -22
  36. package/dist/{MasterLayout-TY223YR7.js.map → MasterLayout-PGL5YU2B.js.map} +1 -1
  37. package/dist/{MobileMenu-2WOWOFQB.js → MobileMenu-VGXWJHEF.js} +25 -23
  38. package/dist/MobileMenu-VGXWJHEF.js.map +1 -0
  39. package/dist/{NotificationsPage-6FX4SOZU.js → NotificationsPage-PZAEKKJO.js} +24 -22
  40. package/dist/NotificationsPage-PZAEKKJO.js.map +1 -0
  41. package/dist/{OrderSinglePage-RUMSJIFD.js → OrderSinglePage-KTKLXTUX.js} +25 -23
  42. package/dist/OrderSinglePage-KTKLXTUX.js.map +1 -0
  43. package/dist/{OrdersPage-B4Q4QIEM.js → OrdersPage-BY6LYV5M.js} +24 -22
  44. package/dist/OrdersPage-BY6LYV5M.js.map +1 -0
  45. package/dist/{PageSingle-F4TDNKUM.js → PageSingle-CJRT3HJZ.js} +6 -5
  46. package/dist/PageSingle-CJRT3HJZ.js.map +1 -0
  47. package/dist/{ProductDetails-BNVVUDBH.js → ProductDetails-O2VJVIZC.js} +7 -6
  48. package/dist/ProductDetails-O2VJVIZC.js.map +1 -0
  49. package/dist/{ProfilePage-OJSAXSC2.js → ProfilePage-TB7PBODI.js} +24 -22
  50. package/dist/ProfilePage-TB7PBODI.js.map +1 -0
  51. package/dist/{RenderWhenVisible-F44J5MMG.js → RenderWhenVisible-KWAXEJOJ.js} +8 -5
  52. package/dist/RenderWhenVisible-KWAXEJOJ.js.map +1 -0
  53. package/dist/{ReviewsPage-3IJKJKTY.js → ReviewsPage-5KGCKLFR.js} +3 -3
  54. package/dist/{ReviewsPage-3IJKJKTY.js.map → ReviewsPage-5KGCKLFR.js.map} +1 -1
  55. package/dist/{SeoCartWidget-4PN2DW54.js → SeoCartWidget-6BU7WCTP.js} +24 -22
  56. package/dist/SeoCartWidget-6BU7WCTP.js.map +1 -0
  57. package/dist/{SettingsPage-BCRNV4GU.js → SettingsPage-G55AM2KS.js} +24 -22
  58. package/dist/SettingsPage-G55AM2KS.js.map +1 -0
  59. package/dist/{StoreClosedNotification-IRUTRLIH.js → StoreClosedNotification-C3BBFGAA.js} +25 -23
  60. package/dist/{StoreClosedNotification-IRUTRLIH.js.map → StoreClosedNotification-C3BBFGAA.js.map} +1 -1
  61. package/dist/{TestimonialsPage-YU4PLOLR.js → TestimonialsPage-EA4PSO7E.js} +6 -5
  62. package/dist/TestimonialsPage-EA4PSO7E.js.map +1 -0
  63. package/dist/{ThankYouPage-MUDELEIQ.js → ThankYouPage-R2OEK7ZZ.js} +24 -22
  64. package/dist/ThankYouPage-R2OEK7ZZ.js.map +1 -0
  65. package/dist/{WalletPage-2I4KTR5E.js → WalletPage-MEWHIHUE.js} +25 -23
  66. package/dist/WalletPage-MEWHIHUE.js.map +1 -0
  67. package/dist/{WishlistPage-7AYL3RUD.js → WishlistPage-YFKG7CXU.js} +26 -24
  68. package/dist/WishlistPage-YFKG7CXU.js.map +1 -0
  69. package/dist/ambient/virtual-modules.d.ts +43 -1
  70. package/dist/api/advertisement.js +4 -3
  71. package/dist/api/apps.js +4 -3
  72. package/dist/api/blog.js +6 -5
  73. package/dist/api/brands.js +6 -5
  74. package/dist/api/cart.js +6 -5
  75. package/dist/api/category.js +6 -5
  76. package/dist/api/client.js +3 -2
  77. package/dist/api/home.js +4 -3
  78. package/dist/api/loyalty.js +6 -5
  79. package/dist/api/menu.js +4 -3
  80. package/dist/api/notification.js +4 -3
  81. package/dist/api/order.js +6 -5
  82. package/dist/api/page.js +6 -5
  83. package/dist/api/product.js +6 -5
  84. package/dist/api/profile.js +3 -2
  85. package/dist/api/profile.js.map +1 -1
  86. package/dist/api/store.js +4 -3
  87. package/dist/api/translations.js +4 -3
  88. package/dist/api/user.js +4 -3
  89. package/dist/api/wallet.js +4 -3
  90. package/dist/api/wishlist.js +7 -6
  91. package/dist/{chunk-LA7KZ2XY.js → chunk-2D5TFSVG.js} +8 -8
  92. package/dist/{chunk-LA7KZ2XY.js.map → chunk-2D5TFSVG.js.map} +1 -1
  93. package/dist/{chunk-HQAFPDJK.js → chunk-2FDLEB5J.js} +3 -3
  94. package/dist/{chunk-HQAFPDJK.js.map → chunk-2FDLEB5J.js.map} +1 -1
  95. package/dist/chunk-2FKZAAV7.js +90 -0
  96. package/dist/chunk-2FKZAAV7.js.map +1 -0
  97. package/dist/{chunk-YDFOJBEY.js → chunk-3GW3VFR6.js} +3 -3
  98. package/dist/{chunk-YDFOJBEY.js.map → chunk-3GW3VFR6.js.map} +1 -1
  99. package/dist/{chunk-CEYT3JER.js → chunk-56T47K7P.js} +4 -4
  100. package/dist/{chunk-CEYT3JER.js.map → chunk-56T47K7P.js.map} +1 -1
  101. package/dist/{chunk-LPQ5FUMJ.js → chunk-5SDCUGYR.js} +4 -4
  102. package/dist/{chunk-LPQ5FUMJ.js.map → chunk-5SDCUGYR.js.map} +1 -1
  103. package/dist/{chunk-QGOPTVV5.js → chunk-6EQ7G3SZ.js} +4 -3
  104. package/dist/chunk-6EQ7G3SZ.js.map +1 -0
  105. package/dist/{chunk-H7CVJFTK.js → chunk-6RHU4TEF.js} +7 -7
  106. package/dist/{chunk-H7CVJFTK.js.map → chunk-6RHU4TEF.js.map} +1 -1
  107. package/dist/{chunk-FZYR4BA2.js → chunk-7WTUA4WY.js} +3 -3
  108. package/dist/{chunk-FZYR4BA2.js.map → chunk-7WTUA4WY.js.map} +1 -1
  109. package/dist/{chunk-3PXONLUK.js → chunk-BH7YNCYB.js} +3 -3
  110. package/dist/{chunk-3PXONLUK.js.map → chunk-BH7YNCYB.js.map} +1 -1
  111. package/dist/{chunk-DBW7XXNE.js → chunk-BPL5H33B.js} +4 -4
  112. package/dist/{chunk-DBW7XXNE.js.map → chunk-BPL5H33B.js.map} +1 -1
  113. package/dist/{chunk-66K5P5ZX.js → chunk-CNUBL24W.js} +3 -3
  114. package/dist/{chunk-66K5P5ZX.js.map → chunk-CNUBL24W.js.map} +1 -1
  115. package/dist/chunk-COJH52VR.js +443 -0
  116. package/dist/chunk-COJH52VR.js.map +1 -0
  117. package/dist/{chunk-6OOTDFC7.js → chunk-D56TVNOG.js} +3 -3
  118. package/dist/{chunk-6OOTDFC7.js.map → chunk-D56TVNOG.js.map} +1 -1
  119. package/dist/{chunk-Y7XVWQXG.js → chunk-DNPQ2JBM.js} +4 -4
  120. package/dist/{chunk-Y7XVWQXG.js.map → chunk-DNPQ2JBM.js.map} +1 -1
  121. package/dist/{chunk-JJARU7YP.js → chunk-EWLVLDRP.js} +3 -3
  122. package/dist/{chunk-JJARU7YP.js.map → chunk-EWLVLDRP.js.map} +1 -1
  123. package/dist/{chunk-Y357MBJI.js → chunk-FNHZEBA5.js} +9 -8
  124. package/dist/chunk-FNHZEBA5.js.map +1 -0
  125. package/dist/{chunk-HSWRYXC7.js → chunk-FO4WVGUQ.js} +3 -88
  126. package/dist/chunk-FO4WVGUQ.js.map +1 -0
  127. package/dist/{chunk-BNI6SKFL.js → chunk-G3UTLICK.js} +4 -4
  128. package/dist/{chunk-BNI6SKFL.js.map → chunk-G3UTLICK.js.map} +1 -1
  129. package/dist/{chunk-C4RXPVDF.js → chunk-GMXI6V2D.js} +6 -5
  130. package/dist/chunk-GMXI6V2D.js.map +1 -0
  131. package/dist/{chunk-RKQH63G2.js → chunk-GXHJXZBG.js} +4 -4
  132. package/dist/{chunk-RKQH63G2.js.map → chunk-GXHJXZBG.js.map} +1 -1
  133. package/dist/{chunk-43D2CG4F.js → chunk-IBSQO6LW.js} +4 -4
  134. package/dist/{chunk-43D2CG4F.js.map → chunk-IBSQO6LW.js.map} +1 -1
  135. package/dist/{chunk-ZVZGLEZ6.js → chunk-IU4KTCS3.js} +3 -3
  136. package/dist/{chunk-ZVZGLEZ6.js.map → chunk-IU4KTCS3.js.map} +1 -1
  137. package/dist/{chunk-ZFNLX3F7.js → chunk-J3G4ZD76.js} +13 -12
  138. package/dist/chunk-J3G4ZD76.js.map +1 -0
  139. package/dist/{chunk-ENJ3CM5M.js → chunk-J5X4LXNM.js} +3 -3
  140. package/dist/{chunk-ENJ3CM5M.js.map → chunk-J5X4LXNM.js.map} +1 -1
  141. package/dist/{chunk-TJF6YZ5I.js → chunk-JKBLG344.js} +8 -7
  142. package/dist/chunk-JKBLG344.js.map +1 -0
  143. package/dist/{chunk-RPDMNNRW.js → chunk-JVIPOD6M.js} +20 -19
  144. package/dist/chunk-JVIPOD6M.js.map +1 -0
  145. package/dist/{chunk-4WAUITU2.js → chunk-KNIGLCRV.js} +3 -3
  146. package/dist/{chunk-4WAUITU2.js.map → chunk-KNIGLCRV.js.map} +1 -1
  147. package/dist/{chunk-OMKLPCBA.js → chunk-KQW6I5CD.js} +4 -4
  148. package/dist/{chunk-OMKLPCBA.js.map → chunk-KQW6I5CD.js.map} +1 -1
  149. package/dist/{chunk-HR3QJ3LW.js → chunk-LXNS6CMT.js} +4 -4
  150. package/dist/{chunk-HR3QJ3LW.js.map → chunk-LXNS6CMT.js.map} +1 -1
  151. package/dist/chunk-MGDCJQ5P.js +14 -0
  152. package/dist/{chunk-KZM7HXJ3.js.map → chunk-MGDCJQ5P.js.map} +1 -1
  153. package/dist/chunk-N45X7D55.js +63 -0
  154. package/dist/chunk-N45X7D55.js.map +1 -0
  155. package/dist/{chunk-OH2L4U2C.js → chunk-NZRJOAA7.js} +3 -3
  156. package/dist/{chunk-OH2L4U2C.js.map → chunk-NZRJOAA7.js.map} +1 -1
  157. package/dist/{chunk-TEOVJ6WU.js → chunk-O7B5JL6H.js} +4 -4
  158. package/dist/{chunk-TEOVJ6WU.js.map → chunk-O7B5JL6H.js.map} +1 -1
  159. package/dist/{chunk-UURVAJ42.js → chunk-OZP2FID7.js} +4 -4
  160. package/dist/{chunk-UURVAJ42.js.map → chunk-OZP2FID7.js.map} +1 -1
  161. package/dist/{chunk-HCA2TE4G.js → chunk-PGUKRWOY.js} +5 -5
  162. package/dist/{chunk-HCA2TE4G.js.map → chunk-PGUKRWOY.js.map} +1 -1
  163. package/dist/{chunk-3MIFT4VQ.js → chunk-Q62YEBIA.js} +4 -4
  164. package/dist/{chunk-3MIFT4VQ.js.map → chunk-Q62YEBIA.js.map} +1 -1
  165. package/dist/{chunk-6DMNJPLW.js → chunk-QS4EDTEX.js} +3 -3
  166. package/dist/{chunk-6DMNJPLW.js.map → chunk-QS4EDTEX.js.map} +1 -1
  167. package/dist/{chunk-SAGXF3MU.js → chunk-QZEQOVA5.js} +3 -3
  168. package/dist/{chunk-SAGXF3MU.js.map → chunk-QZEQOVA5.js.map} +1 -1
  169. package/dist/{chunk-JTOVO3ZU.js → chunk-RWBTMHLR.js} +5 -5
  170. package/dist/{chunk-JTOVO3ZU.js.map → chunk-RWBTMHLR.js.map} +1 -1
  171. package/dist/{chunk-DV6SJHL5.js → chunk-S34G5DL4.js} +4 -4
  172. package/dist/{chunk-DV6SJHL5.js.map → chunk-S34G5DL4.js.map} +1 -1
  173. package/dist/{chunk-MKVCFBVF.js → chunk-TIPR4JUO.js} +4 -4
  174. package/dist/{chunk-MKVCFBVF.js.map → chunk-TIPR4JUO.js.map} +1 -1
  175. package/dist/{chunk-WHJZP3QJ.js → chunk-ULMSO2XZ.js} +7 -7
  176. package/dist/{chunk-WHJZP3QJ.js.map → chunk-ULMSO2XZ.js.map} +1 -1
  177. package/dist/{chunk-IVBOLREE.js → chunk-VWVCSD3N.js} +3 -3
  178. package/dist/{chunk-IVBOLREE.js.map → chunk-VWVCSD3N.js.map} +1 -1
  179. package/dist/{chunk-5G7NYNX6.js → chunk-W2LNKEBF.js} +3 -3
  180. package/dist/{chunk-5G7NYNX6.js.map → chunk-W2LNKEBF.js.map} +1 -1
  181. package/dist/{chunk-AV6AAVNU.js → chunk-XGNML7XM.js} +7 -7
  182. package/dist/{chunk-AV6AAVNU.js.map → chunk-XGNML7XM.js.map} +1 -1
  183. package/dist/{chunk-46NBPXAI.js → chunk-XT6CLGF5.js} +3 -3
  184. package/dist/{chunk-46NBPXAI.js.map → chunk-XT6CLGF5.js.map} +1 -1
  185. package/dist/{chunk-SFZ7IIWL.js → chunk-ZEGNYJOR.js} +4 -4
  186. package/dist/{chunk-SFZ7IIWL.js.map → chunk-ZEGNYJOR.js.map} +1 -1
  187. package/dist/{chunk-OM26SAHA.js → chunk-ZPVLBXDY.js} +4 -4
  188. package/dist/{chunk-OM26SAHA.js.map → chunk-ZPVLBXDY.js.map} +1 -1
  189. package/dist/components/cart/index.js +1 -1
  190. package/dist/components/common/RenderWhenVisible.d.ts +3 -1
  191. package/dist/components/common/RenderWhenVisible.d.ts.map +1 -1
  192. package/dist/components/common/index.js +1 -1
  193. package/dist/components/common/lazy.d.ts +1 -1
  194. package/dist/components/common/lazy.d.ts.map +1 -1
  195. package/dist/components/drawer/index.js +22 -20
  196. package/dist/components/home/HomePageRenderer.d.ts.map +1 -1
  197. package/dist/components/home/index.js +26 -24
  198. package/dist/components/layout/index.js +6 -5
  199. package/dist/components/product/index.js +23 -21
  200. package/dist/components/store/index.js +24 -22
  201. package/dist/components/store/index.js.map +1 -1
  202. package/dist/components/toast/index.js +4 -3
  203. package/dist/components/toast/index.js.map +1 -1
  204. package/dist/components/tracking/index.js +1 -1
  205. package/dist/dev/DevSettingsWidget.d.ts +6 -7
  206. package/dist/dev/DevSettingsWidget.d.ts.map +1 -1
  207. package/dist/dev/dev-settings-store.d.ts +89 -46
  208. package/dist/dev/dev-settings-store.d.ts.map +1 -1
  209. package/dist/dev/editor/AddElementDrawer.d.ts +17 -0
  210. package/dist/dev/editor/AddElementDrawer.d.ts.map +1 -0
  211. package/dist/dev/editor/BuilderPanel.d.ts +23 -0
  212. package/dist/dev/editor/BuilderPanel.d.ts.map +1 -0
  213. package/dist/dev/editor/SettingsPanel.d.ts +9 -0
  214. package/dist/dev/editor/SettingsPanel.d.ts.map +1 -0
  215. package/dist/dev/editor/ThemeEditor.d.ts +20 -0
  216. package/dist/dev/editor/ThemeEditor.d.ts.map +1 -0
  217. package/dist/dev/editor/catalog.d.ts +10 -0
  218. package/dist/dev/editor/catalog.d.ts.map +1 -0
  219. package/dist/dev/editor/fields.d.ts +18 -0
  220. package/dist/dev/editor/fields.d.ts.map +1 -0
  221. package/dist/dev/editor/i18n.d.ts +72 -0
  222. package/dist/dev/editor/i18n.d.ts.map +1 -0
  223. package/dist/dev/editor/icons.d.ts +21 -0
  224. package/dist/dev/editor/icons.d.ts.map +1 -0
  225. package/dist/dev/editor/index.d.ts +8 -0
  226. package/dist/dev/editor/index.d.ts.map +1 -0
  227. package/dist/dev/editor/index.js +2059 -0
  228. package/dist/dev/editor/index.js.map +1 -0
  229. package/dist/dev/editor/lookup.d.ts +22 -0
  230. package/dist/dev/editor/lookup.d.ts.map +1 -0
  231. package/dist/dev/editor/mount.d.ts +4 -0
  232. package/dist/dev/editor/mount.d.ts.map +1 -0
  233. package/dist/dev/editor/paths.d.ts +44 -0
  234. package/dist/dev/editor/paths.d.ts.map +1 -0
  235. package/dist/dev/editor/pickers.d.ts +12 -0
  236. package/dist/dev/editor/pickers.d.ts.map +1 -0
  237. package/dist/dev/editor/styles.d.ts +8 -0
  238. package/dist/dev/editor/styles.d.ts.map +1 -0
  239. package/dist/dev/index.d.ts +1 -1
  240. package/dist/dev/index.d.ts.map +1 -1
  241. package/dist/dev/index.js +35 -309
  242. package/dist/dev/index.js.map +1 -1
  243. package/dist/dev/schema-types.d.ts +124 -4
  244. package/dist/dev/schema-types.d.ts.map +1 -1
  245. package/dist/dev/store-lookup.d.ts +13 -0
  246. package/dist/dev/store-lookup.d.ts.map +1 -0
  247. package/dist/document-class-2RROXH4K.js +29 -0
  248. package/dist/{document-class-AJGI7GKJ.js.map → document-class-2RROXH4K.js.map} +1 -1
  249. package/dist/hooks/index.js +22 -20
  250. package/dist/hooks/useComments.js +3 -2
  251. package/dist/hooks/useGtm.js +22 -20
  252. package/dist/hooks/useMoney.js +22 -20
  253. package/dist/hooks/useProduct.js +3 -2
  254. package/dist/hooks/useStore.js +22 -20
  255. package/dist/hooks/useUser.js +5 -4
  256. package/dist/hooks/useWishlist.js +3 -2
  257. package/dist/index.js +22 -20
  258. package/dist/index.js.map +1 -1
  259. package/dist/native-app/index.js +3 -2
  260. package/dist/{navigation-KTFJWOWI.js → navigation-JB2CJXBF.js} +7 -6
  261. package/dist/navigation-JB2CJXBF.js.map +1 -0
  262. package/dist/navigation-KTMLD4VB.js +14 -0
  263. package/dist/{navigation-BARZWXJZ.js.map → navigation-KTMLD4VB.js.map} +1 -1
  264. package/dist/{not-found-NK6ZFJ7H.js → not-found-ZM6VIELR.js} +25 -23
  265. package/dist/not-found-ZM6VIELR.js.map +1 -0
  266. package/dist/providers/index.js +22 -20
  267. package/dist/routes/account/orders.js +7 -6
  268. package/dist/routes/account.js +16 -15
  269. package/dist/routes/account.js.map +1 -1
  270. package/dist/routes/blog.js +11 -10
  271. package/dist/routes/blog.js.map +1 -1
  272. package/dist/routes/brands.js +7 -6
  273. package/dist/routes/brands.js.map +1 -1
  274. package/dist/routes/cart.js +30 -28
  275. package/dist/routes/cart.js.map +1 -1
  276. package/dist/routes/home/HomePage.d.ts.map +1 -1
  277. package/dist/routes/home.js +27 -25
  278. package/dist/routes/index.js +6 -5
  279. package/dist/routes/loyalty.js +8 -7
  280. package/dist/routes/loyalty.js.map +1 -1
  281. package/dist/routes/page.js +7 -6
  282. package/dist/routes/page.js.map +1 -1
  283. package/dist/routes/product-listing/index.d.ts +27 -0
  284. package/dist/routes/product-listing/index.d.ts.map +1 -1
  285. package/dist/routes/product-listing.js +52 -27
  286. package/dist/routes/product-listing.js.map +1 -1
  287. package/dist/routes/product.js +26 -24
  288. package/dist/routes/product.js.map +1 -1
  289. package/dist/routes/seo-redirects.js +6 -5
  290. package/dist/routes/testimonials.js +2 -2
  291. package/dist/routes/thank-you.js +7 -6
  292. package/dist/routes/thank-you.js.map +1 -1
  293. package/dist/skeleton.js +27 -25
  294. package/dist/store-lookup-T4TK7CKA.js +114 -0
  295. package/dist/store-lookup-T4TK7CKA.js.map +1 -0
  296. package/dist/tanstack.js +17 -16
  297. package/dist/tanstack.js.map +1 -1
  298. package/dist/utils/index.js +6 -5
  299. package/dist/utils/index.js.map +1 -1
  300. package/dist/vite/adapters/tanstack.adapter.d.ts.map +1 -1
  301. package/dist/vite/index.js +424 -47
  302. package/dist/vite/index.js.map +1 -1
  303. package/dist/vite/plugins/twilight-schema.d.ts +7 -2
  304. package/dist/vite/plugins/twilight-schema.d.ts.map +1 -1
  305. package/dist/vite/plugins/twilight-schema.plugin.d.ts +26 -0
  306. package/dist/vite/plugins/twilight-schema.plugin.d.ts.map +1 -1
  307. package/package.json +5 -1
  308. package/tailwind/components/common/RenderWhenVisible.tsx.txt +9 -2
  309. package/tailwind/components/home/HomePageRenderer.tsx.txt +2 -0
  310. package/tailwind/routes/home/HomePage.tsx.txt +7 -6
  311. package/tailwind/routes/product-listing/index.tsx.txt +42 -0
  312. package/dist/BlogAuthorPage-KRT7MRTC.js.map +0 -1
  313. package/dist/BlogCategoryPage-OP3ETAMT.js.map +0 -1
  314. package/dist/BlogPage-RGAQVUDI.js.map +0 -1
  315. package/dist/BlogSinglePage-VG4UXBTL.js.map +0 -1
  316. package/dist/BlogTagPage-G4IVHJD5.js.map +0 -1
  317. package/dist/BrandsPage-2JMPPOOU.js.map +0 -1
  318. package/dist/Breadcrumb-I3ZOGG2Y.js.map +0 -1
  319. package/dist/CartItem-YTPYETW6.js.map +0 -1
  320. package/dist/CartSummary-DND7BO26.js.map +0 -1
  321. package/dist/CustomerLayout-HCYVBODI.js.map +0 -1
  322. package/dist/Header-QG4UO3MF.js +0 -21
  323. package/dist/LoyaltyPage-ZMFYQMQY.js.map +0 -1
  324. package/dist/LoyaltyPointsPage-5PB6IFLY.js.map +0 -1
  325. package/dist/MainMenu-SAUMNMBF.js.map +0 -1
  326. package/dist/MobileMenu-2WOWOFQB.js.map +0 -1
  327. package/dist/NotificationsPage-6FX4SOZU.js.map +0 -1
  328. package/dist/OrderSinglePage-RUMSJIFD.js.map +0 -1
  329. package/dist/OrdersPage-B4Q4QIEM.js.map +0 -1
  330. package/dist/PageSingle-F4TDNKUM.js.map +0 -1
  331. package/dist/ProductDetails-BNVVUDBH.js.map +0 -1
  332. package/dist/ProfilePage-OJSAXSC2.js.map +0 -1
  333. package/dist/RenderWhenVisible-F44J5MMG.js.map +0 -1
  334. package/dist/SeoCartWidget-4PN2DW54.js.map +0 -1
  335. package/dist/SettingsPage-BCRNV4GU.js.map +0 -1
  336. package/dist/TestimonialsPage-YU4PLOLR.js.map +0 -1
  337. package/dist/ThankYouPage-MUDELEIQ.js.map +0 -1
  338. package/dist/WalletPage-2I4KTR5E.js.map +0 -1
  339. package/dist/WishlistPage-7AYL3RUD.js.map +0 -1
  340. package/dist/chunk-2JV6WZ6O.js +0 -136
  341. package/dist/chunk-2JV6WZ6O.js.map +0 -1
  342. package/dist/chunk-C4RXPVDF.js.map +0 -1
  343. package/dist/chunk-HSWRYXC7.js.map +0 -1
  344. package/dist/chunk-KZM7HXJ3.js +0 -14
  345. package/dist/chunk-QGOPTVV5.js.map +0 -1
  346. package/dist/chunk-RPDMNNRW.js.map +0 -1
  347. package/dist/chunk-TJF6YZ5I.js.map +0 -1
  348. package/dist/chunk-Y357MBJI.js.map +0 -1
  349. package/dist/chunk-ZFNLX3F7.js.map +0 -1
  350. package/dist/document-class-AJGI7GKJ.js +0 -28
  351. package/dist/navigation-BARZWXJZ.js +0 -13
  352. package/dist/navigation-KTFJWOWI.js.map +0 -1
  353. package/dist/not-found-NK6ZFJ7H.js.map +0 -1
@@ -0,0 +1,2059 @@
1
+ import { useDevEditorMeta, devSettingsStore, useDevSettingsState, blockPath } from '../../chunk-COJH52VR.js';
2
+ import { conditionsMet, DEV_EDITOR_FRAME_ATTR, DEV_PREVIEW_IMAGE_MAX_BYTES, DEV_PREVIEW_IMAGE_ENDPOINT } from '../../chunk-N45X7D55.js';
3
+ import '../../chunk-FO4WVGUQ.js';
4
+ import '../../chunk-N2S25NXP.js';
5
+ import '../../chunk-T72DAX7R.js';
6
+ import '../../chunk-DGUM43GV.js';
7
+ import { useState, useCallback, useEffect, StrictMode, useRef, useId, useMemo } from 'react';
8
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
9
+ import { createRoot } from 'react-dom/client';
10
+
11
+ // src/dev/editor/i18n.ts
12
+ var en = {
13
+ homePage: "Home page",
14
+ builder: "Page elements",
15
+ showPanel: "Show the side panel",
16
+ hidePanel: "Hide the side panel",
17
+ settings: "Theme settings",
18
+ addElement: "Add new element",
19
+ pickFromStore: "Choose from the store",
20
+ change: "Change",
21
+ done: "Done",
22
+ searchStore: "Search the store",
23
+ searching: "Searching\u2026",
24
+ noResults: "Nothing found.",
25
+ sampleNotice: "Sample data: the dev store has none of these, or could not be reached.",
26
+ sampleProducts: "Sample products only show how the field works: the block fetches products from the store, so it can't display them.",
27
+ linkTo: "Link to",
28
+ typeUrl: "URL",
29
+ searchElements: "Search elements",
30
+ noMatches: "No element matches that search.",
31
+ close: "Close",
32
+ cancel: "Cancel",
33
+ storeLayoutHint: "The home page shows the store's elements. Customize it to add, remove and reorder elements here.",
34
+ customize: "Customize page elements",
35
+ startEmpty: "Start from an empty page",
36
+ backToStore: "Back to the store's elements",
37
+ confirm: "Click again to confirm",
38
+ noBlocks: "No elements yet.",
39
+ noFields: "No editable fields.",
40
+ storeBlock: "store",
41
+ notDeclared: "Not declared in twilight.json, so it renders with the store's data as-is.",
42
+ back: "Back",
43
+ duplicate: "Duplicate",
44
+ remove: "Remove",
45
+ moveUp: "Move up",
46
+ moveDown: "Move down",
47
+ mobile: "Mobile",
48
+ desktop: "Desktop",
49
+ preview: "Preview",
50
+ saving: "Saving\u2026",
51
+ saved: "Saved",
52
+ saveError: "Could not save",
53
+ savedTo: "Changes save to",
54
+ openStorefront: "Open the storefront in a new tab",
55
+ reload: "Reload the preview",
56
+ notHome: "You are not on the home page.",
57
+ goHome: "Go to it",
58
+ previewOff: "Preview is off: turn it on to see your changes.",
59
+ resetSettings: "Reset settings to twilight.json defaults",
60
+ noSettings: "twilight.json declares no settings.",
61
+ waitingForStore: "Loading the home page\u2026",
62
+ items: (n) => `${n} item${n === 1 ? "" : "s"}`,
63
+ item: "Item",
64
+ language: "Language",
65
+ outOfRange: (min, max) => min !== void 0 && max !== void 0 ? `Between ${min} and ${max}.` : min !== void 0 ? `At least ${min}.` : `At most ${max}.`,
66
+ uploading: "Uploading\u2026",
67
+ uploadFailed: "Could not upload that image.",
68
+ addItem: (label) => `Add ${label}`,
69
+ minItems: (n) => `Needs at least ${n}.`,
70
+ chooseImage: "Choose an image from your computer",
71
+ imageTooLarge: "That image is over 5 MB. Use a smaller one, or paste its URL."
72
+ };
73
+ var ar = {
74
+ homePage: "\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629",
75
+ builder: "\u0639\u0646\u0627\u0635\u0631 \u0627\u0644\u0635\u0641\u062D\u0629",
76
+ showPanel: "\u0625\u0638\u0647\u0627\u0631 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u062C\u0627\u0646\u0628\u064A\u0629",
77
+ hidePanel: "\u0625\u062E\u0641\u0627\u0621 \u0627\u0644\u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u062C\u0627\u0646\u0628\u064A\u0629",
78
+ settings: "\u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0627\u0644\u062B\u064A\u0645",
79
+ addElement: "\u0625\u0636\u0627\u0641\u0629 \u0639\u0646\u0635\u0631 \u062C\u062F\u064A\u062F",
80
+ pickFromStore: "\u0627\u062E\u062A\u064A\u0627\u0631 \u0645\u0646 \u0627\u0644\u0645\u062A\u062C\u0631",
81
+ change: "\u062A\u063A\u064A\u064A\u0631",
82
+ done: "\u062A\u0645",
83
+ searchStore: "\u0627\u0628\u062D\u062B \u0641\u064A \u0627\u0644\u0645\u062A\u062C\u0631",
84
+ searching: "\u062C\u0627\u0631\u064D \u0627\u0644\u0628\u062D\u062B\u2026",
85
+ noResults: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0646\u062A\u0627\u0626\u062C.",
86
+ sampleNotice: "\u0628\u064A\u0627\u0646\u0627\u062A \u062A\u062C\u0631\u064A\u0628\u064A\u0629: \u0644\u0627 \u064A\u062D\u062A\u0648\u064A \u0645\u062A\u062C\u0631 \u0627\u0644\u062A\u0637\u0648\u064A\u0631 \u0639\u0644\u0649 \u0647\u0630\u0647 \u0627\u0644\u0639\u0646\u0627\u0635\u0631\u060C \u0623\u0648 \u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u0648\u0635\u0648\u0644 \u0625\u0644\u064A\u0647.",
87
+ sampleProducts: "\u0627\u0644\u0645\u0646\u062A\u062C\u0627\u062A \u0627\u0644\u062A\u062C\u0631\u064A\u0628\u064A\u0629 \u0644\u062A\u062C\u0631\u0628\u0629 \u0627\u0644\u062D\u0642\u0644 \u0641\u0642\u0637: \u0627\u0644\u0639\u0646\u0635\u0631 \u064A\u062C\u0644\u0628 \u0627\u0644\u0645\u0646\u062A\u062C\u0627\u062A \u0645\u0646 \u0627\u0644\u0645\u062A\u062C\u0631\u060C \u0641\u0644\u0646 \u064A\u0639\u0631\u0636\u0647\u0627.",
88
+ linkTo: "\u0627\u0644\u0631\u0627\u0628\u0637 \u0625\u0644\u0649",
89
+ typeUrl: "\u0631\u0627\u0628\u0637",
90
+ searchElements: "\u0627\u0628\u062D\u062B \u0641\u064A \u0627\u0644\u0639\u0646\u0627\u0635\u0631",
91
+ noMatches: "\u0644\u0627 \u064A\u0648\u062C\u062F \u0639\u0646\u0635\u0631 \u064A\u0637\u0627\u0628\u0642 \u0627\u0644\u0628\u062D\u062B.",
92
+ close: "\u0625\u063A\u0644\u0627\u0642",
93
+ cancel: "\u0625\u0644\u063A\u0627\u0621",
94
+ storeLayoutHint: "\u062A\u0639\u0631\u0636 \u0627\u0644\u0635\u0641\u062D\u0629 \u0639\u0646\u0627\u0635\u0631 \u0627\u0644\u0645\u062A\u062C\u0631. \u062E\u0635\u0651\u0635\u0647\u0627 \u0644\u062A\u0636\u064A\u0641 \u0627\u0644\u0639\u0646\u0627\u0635\u0631 \u0648\u062A\u062D\u0630\u0641\u0647\u0627 \u0648\u062A\u0631\u062A\u0651\u0628\u0647\u0627 \u0645\u0646 \u0647\u0646\u0627.",
95
+ customize: "\u062A\u062E\u0635\u064A\u0635 \u0639\u0646\u0627\u0635\u0631 \u0627\u0644\u0635\u0641\u062D\u0629",
96
+ startEmpty: "\u0627\u0644\u0628\u062F\u0621 \u0628\u0635\u0641\u062D\u0629 \u0641\u0627\u0631\u063A\u0629",
97
+ backToStore: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0625\u0644\u0649 \u0639\u0646\u0627\u0635\u0631 \u0627\u0644\u0645\u062A\u062C\u0631",
98
+ confirm: "\u0627\u0636\u063A\u0637 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u0644\u0644\u062A\u0623\u0643\u064A\u062F",
99
+ noBlocks: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0639\u0646\u0627\u0635\u0631 \u0628\u0639\u062F.",
100
+ noFields: "\u0644\u0627 \u062A\u0648\u062C\u062F \u062D\u0642\u0648\u0644 \u0642\u0627\u0628\u0644\u0629 \u0644\u0644\u062A\u0639\u062F\u064A\u0644.",
101
+ storeBlock: "\u0645\u0646 \u0627\u0644\u0645\u062A\u062C\u0631",
102
+ notDeclared: "\u063A\u064A\u0631 \u0645\u0639\u0631\u0651\u0641 \u0641\u064A twilight.json\u060C \u0644\u0630\u0627 \u064A\u064F\u0639\u0631\u0636 \u0628\u0628\u064A\u0627\u0646\u0627\u062A \u0627\u0644\u0645\u062A\u062C\u0631 \u0643\u0645\u0627 \u0647\u064A.",
103
+ back: "\u0631\u062C\u0648\u0639",
104
+ duplicate: "\u062A\u0643\u0631\u0627\u0631",
105
+ remove: "\u062D\u0630\u0641",
106
+ moveUp: "\u062A\u062D\u0631\u064A\u0643 \u0644\u0623\u0639\u0644\u0649",
107
+ moveDown: "\u062A\u062D\u0631\u064A\u0643 \u0644\u0623\u0633\u0641\u0644",
108
+ mobile: "\u0627\u0644\u062C\u0648\u0627\u0644",
109
+ desktop: "\u0633\u0637\u062D \u0627\u0644\u0645\u0643\u062A\u0628",
110
+ preview: "\u0627\u0644\u0645\u0639\u0627\u064A\u0646\u0629",
111
+ saving: "\u062C\u0627\u0631\u064D \u0627\u0644\u062D\u0641\u0638\u2026",
112
+ saved: "\u062A\u0645 \u0627\u0644\u062D\u0641\u0638",
113
+ saveError: "\u062A\u0639\u0630\u0651\u0631 \u0627\u0644\u062D\u0641\u0638",
114
+ savedTo: "\u062A\u064F\u062D\u0641\u0638 \u0627\u0644\u062A\u063A\u064A\u064A\u0631\u0627\u062A \u0641\u064A",
115
+ openStorefront: "\u0641\u062A\u062D \u0627\u0644\u0645\u062A\u062C\u0631 \u0641\u064A \u062A\u0628\u0648\u064A\u0628 \u062C\u062F\u064A\u062F",
116
+ reload: "\u0625\u0639\u0627\u062F\u0629 \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0645\u0639\u0627\u064A\u0646\u0629",
117
+ notHome: "\u0623\u0646\u062A \u0644\u0633\u062A \u0641\u064A \u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629.",
118
+ goHome: "\u0627\u0644\u0630\u0647\u0627\u0628 \u0625\u0644\u064A\u0647\u0627",
119
+ previewOff: "\u0627\u0644\u0645\u0639\u0627\u064A\u0646\u0629 \u0645\u062A\u0648\u0642\u0641\u0629: \u0641\u0639\u0651\u0644\u0647\u0627 \u0644\u062A\u0631\u0649 \u062A\u063A\u064A\u064A\u0631\u0627\u062A\u0643.",
120
+ resetSettings: "\u0627\u0633\u062A\u0639\u0627\u062F\u0629 \u0627\u0644\u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0627\u0644\u0627\u0641\u062A\u0631\u0627\u0636\u064A\u0629 \u0645\u0646 twilight.json",
121
+ noSettings: "\u0644\u0627 \u064A\u0639\u0631\u0651\u0641 twilight.json \u0623\u064A \u0625\u0639\u062F\u0627\u062F\u0627\u062A.",
122
+ waitingForStore: "\u062C\u0627\u0631\u064D \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0631\u0626\u064A\u0633\u064A\u0629\u2026",
123
+ items: (n) => `${n} \u0639\u0646\u0635\u0631`,
124
+ item: "\u0639\u0646\u0635\u0631",
125
+ language: "\u0627\u0644\u0644\u063A\u0629",
126
+ outOfRange: (min, max) => min !== void 0 && max !== void 0 ? `\u0628\u064A\u0646 ${min} \u0648 ${max}.` : min !== void 0 ? `${min} \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644.` : `${max} \u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631.`,
127
+ uploading: "\u062C\u0627\u0631\u064D \u0627\u0644\u0631\u0641\u0639\u2026",
128
+ uploadFailed: "\u062A\u0639\u0630\u0651\u0631 \u0631\u0641\u0639 \u0627\u0644\u0635\u0648\u0631\u0629.",
129
+ addItem: (label) => `\u0625\u0636\u0627\u0641\u0629 ${label}`,
130
+ minItems: (n) => `\u064A\u0644\u0632\u0645 ${n} \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644.`,
131
+ chooseImage: "\u0627\u062E\u062A\u064A\u0627\u0631 \u0635\u0648\u0631\u0629 \u0645\u0646 \u062C\u0647\u0627\u0632\u0643",
132
+ imageTooLarge: "\u062D\u062C\u0645 \u0627\u0644\u0635\u0648\u0631\u0629 \u0623\u0643\u0628\u0631 \u0645\u0646 5 \u0645\u064A\u062C\u0627\u0628\u0627\u064A\u062A. \u0627\u0633\u062A\u062E\u062F\u0645 \u0635\u0648\u0631\u0629 \u0623\u0635\u063A\u0631 \u0623\u0648 \u0627\u0644\u0635\u0642 \u0631\u0627\u0628\u0637\u0647\u0627."
133
+ };
134
+ var STRINGS = { ar, en };
135
+ function stringsFor(locale) {
136
+ return STRINGS[locale] ?? en;
137
+ }
138
+ function pick(values, locale) {
139
+ if (!values) return "";
140
+ return values[locale] ?? values.ar ?? values.en ?? Object.values(values)[0] ?? "";
141
+ }
142
+ function Icon({ children, size = 20 }) {
143
+ return /* @__PURE__ */ jsx(
144
+ "svg",
145
+ {
146
+ width: size,
147
+ height: size,
148
+ viewBox: "0 0 24 24",
149
+ fill: "none",
150
+ stroke: "currentColor",
151
+ strokeWidth: 1.7,
152
+ strokeLinecap: "round",
153
+ strokeLinejoin: "round",
154
+ "aria-hidden": true,
155
+ children
156
+ }
157
+ );
158
+ }
159
+ var HomeIcon = () => /* @__PURE__ */ jsxs(Icon, { children: [
160
+ /* @__PURE__ */ jsx("path", { d: "M3 10.5 12 3l9 7.5" }),
161
+ /* @__PURE__ */ jsx("path", { d: "M5 9v10a1 1 0 0 0 1 1h4v-6h4v6h4a1 1 0 0 0 1-1V9" })
162
+ ] });
163
+ var SidebarIcon = () => /* @__PURE__ */ jsx("span", { style: { display: "flex", transform: "scaleX(var(--te-back-flip, 1))" }, children: /* @__PURE__ */ jsxs(Icon, { children: [
164
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }),
165
+ /* @__PURE__ */ jsx("path", { d: "M9 4v16" })
166
+ ] }) });
167
+ var PaletteIcon = () => /* @__PURE__ */ jsxs(Icon, { children: [
168
+ /* @__PURE__ */ jsx("path", { d: "M12 3a9 9 0 1 0 0 18c1 0 1.5-.8 1.5-1.6 0-1.3-1-1.6-1-2.6 0-.9.7-1.3 1.6-1.3H16a5 5 0 0 0 5-5C21 6.5 17 3 12 3Z" }),
169
+ /* @__PURE__ */ jsx("circle", { cx: "7.5", cy: "11", r: "1" }),
170
+ /* @__PURE__ */ jsx("circle", { cx: "10", cy: "7", r: "1" }),
171
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "7.5", r: "1" })
172
+ ] });
173
+ var PhoneIcon = () => /* @__PURE__ */ jsxs(Icon, { children: [
174
+ /* @__PURE__ */ jsx("rect", { x: "7", y: "3", width: "10", height: "18", rx: "2" }),
175
+ /* @__PURE__ */ jsx("path", { d: "M11 17.5h2" })
176
+ ] });
177
+ var DesktopIcon = () => /* @__PURE__ */ jsxs(Icon, { children: [
178
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "12", rx: "2" }),
179
+ /* @__PURE__ */ jsx("path", { d: "M8 20h8M12 16v4" })
180
+ ] });
181
+ var PlusCircleIcon = () => /* @__PURE__ */ jsxs(Icon, { children: [
182
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
183
+ /* @__PURE__ */ jsx("path", { d: "M12 8v8M8 12h8" })
184
+ ] });
185
+ var GripIcon = () => /* @__PURE__ */ jsxs(Icon, { size: 16, children: [
186
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "6", r: "1" }),
187
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "6", r: "1" }),
188
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "12", r: "1" }),
189
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "12", r: "1" }),
190
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "18", r: "1" }),
191
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "18", r: "1" })
192
+ ] });
193
+ var BlockIcon = () => /* @__PURE__ */ jsxs(Icon, { children: [
194
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }),
195
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "10", r: "1.5" }),
196
+ /* @__PURE__ */ jsx("path", { d: "m21 16-5-5-8 8" })
197
+ ] });
198
+ var CopyIcon = () => /* @__PURE__ */ jsxs(Icon, { size: 16, children: [
199
+ /* @__PURE__ */ jsx("rect", { x: "8", y: "8", width: "12", height: "12", rx: "2" }),
200
+ /* @__PURE__ */ jsx("path", { d: "M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2" })
201
+ ] });
202
+ var TrashIcon = () => /* @__PURE__ */ jsx(Icon, { size: 16, children: /* @__PURE__ */ jsx("path", { d: "M4 7h16M10 11v6M14 11v6M6 7l1 12a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-12M9 7V4h6v3" }) });
203
+ var ArrowUpIcon = () => /* @__PURE__ */ jsx(Icon, { size: 16, children: /* @__PURE__ */ jsx("path", { d: "M12 19V5M6 11l6-6 6 6" }) });
204
+ var ArrowDownIcon = () => /* @__PURE__ */ jsx(Icon, { size: 16, children: /* @__PURE__ */ jsx("path", { d: "M12 5v14M6 13l6 6 6-6" }) });
205
+ var BackIcon = () => /* @__PURE__ */ jsx("span", { style: { display: "flex", transform: "scaleX(var(--te-back-flip, 1))" }, children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx("path", { d: "M15 6l-6 6 6 6" }) }) });
206
+ var ReloadIcon = () => /* @__PURE__ */ jsx(Icon, { size: 18, children: /* @__PURE__ */ jsx("path", { d: "M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7" }) });
207
+ var ExternalIcon = () => /* @__PURE__ */ jsx(Icon, { size: 18, children: /* @__PURE__ */ jsx("path", { d: "M14 4h6v6M20 4l-9 9M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5" }) });
208
+ var CloseIcon = () => /* @__PURE__ */ jsx(Icon, { size: 18, children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M18 6 6 18" }) });
209
+ var SearchIcon = () => /* @__PURE__ */ jsxs(Icon, { size: 18, children: [
210
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
211
+ /* @__PURE__ */ jsx("path", { d: "m20 20-3.5-3.5" })
212
+ ] });
213
+ function componentFor(schema, path) {
214
+ return path ? schema.components.find((c) => blockPath(c.path) === blockPath(path)) : void 0;
215
+ }
216
+ function titleOf(component, path, locale) {
217
+ if (!component) return path;
218
+ return pick(component.titles, locale) || component.title;
219
+ }
220
+ function ComponentIcon({
221
+ component
222
+ }) {
223
+ if (!component?.icon) return /* @__PURE__ */ jsx(BlockIcon, {});
224
+ return /* @__PURE__ */ jsx("i", { className: `te-sicon ${component.icon}`, "aria-hidden": true });
225
+ }
226
+ function haystack(component) {
227
+ return [component.title, ...Object.values(component.titles ?? {}), component.path].join(" ").toLowerCase();
228
+ }
229
+ function Card({
230
+ component,
231
+ locale,
232
+ onPick
233
+ }) {
234
+ const [broken, setBroken] = useState(false);
235
+ const title = titleOf(component, component.path, locale);
236
+ return /* @__PURE__ */ jsxs("button", { type: "button", className: "te-card", onClick: onPick, children: [
237
+ /* @__PURE__ */ jsxs("span", { className: "te-card__title", children: [
238
+ /* @__PURE__ */ jsx("span", { className: "te-card__icon", children: /* @__PURE__ */ jsx(ComponentIcon, { component }) }),
239
+ title
240
+ ] }),
241
+ /* @__PURE__ */ jsx("span", { className: "te-card__preview", children: component.image && !broken ? /* @__PURE__ */ jsx("img", { src: component.image, alt: "", loading: "lazy", onError: () => setBroken(true) }) : /* @__PURE__ */ jsx("span", { className: "te-card__placeholder", children: /* @__PURE__ */ jsx(ComponentIcon, { component }) }) })
242
+ ] });
243
+ }
244
+ function AddElementDrawer({
245
+ schema,
246
+ t,
247
+ locale,
248
+ onPick,
249
+ onClose
250
+ }) {
251
+ const searchId = useId();
252
+ const [query, setQuery] = useState("");
253
+ const search = useRef(null);
254
+ useEffect(() => {
255
+ search.current?.focus();
256
+ const onKey = (event) => {
257
+ if (event.key === "Escape") onClose();
258
+ };
259
+ window.addEventListener("keydown", onKey);
260
+ return () => window.removeEventListener("keydown", onKey);
261
+ }, [onClose]);
262
+ const indexed = useMemo(
263
+ () => schema.components.map((component) => ({ component, text: haystack(component) })),
264
+ [schema.components]
265
+ );
266
+ const shown = useMemo(() => {
267
+ const words = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
268
+ if (!words.length) return schema.components;
269
+ return indexed.filter(({ text }) => words.every((word) => text.includes(word))).map(({ component }) => component);
270
+ }, [schema.components, indexed, query]);
271
+ return (
272
+ // A non-modal <dialog>, open as rendered: the preview beside it stays usable.
273
+ /* @__PURE__ */ jsxs("dialog", { open: true, className: "te-drawer", "aria-label": t.addElement, children: [
274
+ /* @__PURE__ */ jsxs("header", { className: "te-drawer__head", children: [
275
+ /* @__PURE__ */ jsx("h2", { children: t.addElement }),
276
+ /* @__PURE__ */ jsx(
277
+ "button",
278
+ {
279
+ type: "button",
280
+ className: "te-icon-btn te-icon-btn--danger-outline",
281
+ "aria-label": t.close,
282
+ onClick: onClose,
283
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
284
+ }
285
+ )
286
+ ] }),
287
+ /* @__PURE__ */ jsxs("label", { className: "te-search", htmlFor: searchId, children: [
288
+ /* @__PURE__ */ jsx(SearchIcon, {}),
289
+ /* @__PURE__ */ jsx(
290
+ "input",
291
+ {
292
+ ref: search,
293
+ id: searchId,
294
+ type: "search",
295
+ placeholder: t.searchElements,
296
+ "aria-label": t.searchElements,
297
+ value: query,
298
+ onChange: (e) => setQuery(e.target.value)
299
+ }
300
+ )
301
+ ] }),
302
+ /* @__PURE__ */ jsx("div", { className: "te-drawer__body", children: shown.length === 0 ? /* @__PURE__ */ jsx("p", { className: "te-hint", children: t.noMatches }) : /* @__PURE__ */ jsx("div", { className: "te-cards", children: shown.map((component) => /* @__PURE__ */ jsx(
303
+ Card,
304
+ {
305
+ component,
306
+ locale,
307
+ onPick: () => onPick(component.path)
308
+ },
309
+ component.path
310
+ )) }) })
311
+ ] })
312
+ );
313
+ }
314
+
315
+ // src/dev/editor/lookup.ts
316
+ var COLORS = ["#0d9488", "#7c3aed", "#d97706", "#2563eb", "#db2777", "#059669"];
317
+ function placeholder(name, index) {
318
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="120" height="120"><rect width="120" height="120" fill="${COLORS[index % COLORS.length]}"/><text x="60" y="76" font-size="48" font-family="sans-serif" fill="#fff" text-anchor="middle">${name.slice(0, 1)}</text></svg>`;
319
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`;
320
+ }
321
+ var NAMES = {
322
+ products: [
323
+ "Sample shirt",
324
+ "Sample sneakers",
325
+ "Sample watch",
326
+ "Sample bag",
327
+ "Sample perfume",
328
+ "Sample lamp"
329
+ ],
330
+ categories: ["Clothing", "Shoes", "Accessories", "Home", "Beauty", "Electronics"],
331
+ brands: ["Northwind", "Contoso", "Fabrikam", "Tailspin", "Litware", "Adventure Works"],
332
+ blog_articles: ["How to choose a gift", "Spring collection notes", "Care guide"],
333
+ blog_categories: ["News", "Guides", "Stories"]
334
+ };
335
+ var PATHS = {
336
+ products: "/p",
337
+ categories: "/c",
338
+ brands: "/brands",
339
+ blog_articles: "/blog",
340
+ blog_categories: "/blog/category"
341
+ };
342
+ function sampleItem(source, name, index) {
343
+ const id = `sample-${source}-${index + 1}`;
344
+ const url = `${PATHS[source]}/${id}`;
345
+ const image = placeholder(name, index);
346
+ const data = { id, name, url, sample: true };
347
+ if (source === "brands") data.logo = image;
348
+ else if (source !== "blog_categories") data.image = image;
349
+ return { id, name, url, image, data };
350
+ }
351
+ function sampleItems(source, query = "") {
352
+ const q = query.trim().toLowerCase();
353
+ return (NAMES[source] ?? []).map((name, index) => sampleItem(source, name, index)).filter((item) => !q || item.name.toLowerCase().includes(q));
354
+ }
355
+ var emptyInStore = /* @__PURE__ */ new Set();
356
+ async function searchSource(source, query) {
357
+ try {
358
+ const items = await devSettingsStore.lookup(source, query);
359
+ if (items.length > 0) {
360
+ emptyInStore.delete(source);
361
+ return { items, sample: false };
362
+ }
363
+ if (!query.trim()) emptyInStore.add(source);
364
+ if (emptyInStore.has(source)) return { items: sampleItems(source, query), sample: true };
365
+ return { items: [], sample: false };
366
+ } catch {
367
+ return { items: sampleItems(source, query), sample: true };
368
+ }
369
+ }
370
+ var LINK_LOOKUPS = {
371
+ products: "products",
372
+ categories: "categories",
373
+ brands: "brands",
374
+ blog_articles: "blog_articles",
375
+ blog_categories: "blog_categories"
376
+ };
377
+ var FIXED_LINKS = {
378
+ offers_link: "/offers",
379
+ brands_link: "/brands",
380
+ blog_link: "/blog"
381
+ };
382
+ var SEARCH_DELAY_MS = 250;
383
+ function rowId(row) {
384
+ const id = row?.id;
385
+ return typeof id === "string" || typeof id === "number" ? id : void 0;
386
+ }
387
+ function idKey(id) {
388
+ return id === void 0 ? void 0 : String(id);
389
+ }
390
+ function chipKeys(rows) {
391
+ const seen = /* @__PURE__ */ new Map();
392
+ return rows.map((row) => {
393
+ const base = idKey(rowId(row)) ?? `name:${rowName(row)}`;
394
+ const n = (seen.get(base) ?? 0) + 1;
395
+ seen.set(base, n);
396
+ return n === 1 ? base : `${base}#${n}`;
397
+ });
398
+ }
399
+ function rowName(row) {
400
+ const name = row?.name;
401
+ return typeof name === "string" ? name : String(rowId(row) ?? "");
402
+ }
403
+ function rowImage(row) {
404
+ const r = row ?? {};
405
+ const image = r.image ?? r.logo;
406
+ return typeof image === "string" && image ? image : void 0;
407
+ }
408
+ function LookupSearch({
409
+ source,
410
+ t,
411
+ isPicked,
412
+ onPick
413
+ }) {
414
+ const id = useId();
415
+ const input = useRef(null);
416
+ const [query, setQuery] = useState("");
417
+ const [outcome, setOutcome] = useState(null);
418
+ const [searching, setSearching] = useState(true);
419
+ useEffect(() => {
420
+ input.current?.focus();
421
+ }, []);
422
+ useEffect(() => {
423
+ let current = true;
424
+ setSearching(true);
425
+ const timer = setTimeout(() => {
426
+ void searchSource(source, query).then((result) => {
427
+ if (!current) return;
428
+ setOutcome(result);
429
+ setSearching(false);
430
+ });
431
+ }, SEARCH_DELAY_MS);
432
+ return () => {
433
+ current = false;
434
+ clearTimeout(timer);
435
+ };
436
+ }, [source, query]);
437
+ return /* @__PURE__ */ jsxs("div", { className: "te-lookup", children: [
438
+ /* @__PURE__ */ jsxs("label", { className: "te-search te-search--small", htmlFor: id, children: [
439
+ /* @__PURE__ */ jsx(SearchIcon, {}),
440
+ /* @__PURE__ */ jsx(
441
+ "input",
442
+ {
443
+ ref: input,
444
+ id,
445
+ type: "search",
446
+ placeholder: t.searchStore,
447
+ "aria-label": t.searchStore,
448
+ value: query,
449
+ onChange: (e) => setQuery(e.target.value)
450
+ }
451
+ )
452
+ ] }),
453
+ outcome?.sample && /* @__PURE__ */ jsx("p", { className: "te-field__help te-field__help--warn", children: source === "products" ? t.sampleProducts : t.sampleNotice }),
454
+ searching && /* @__PURE__ */ jsx("p", { className: "te-field__help", children: t.searching }),
455
+ !searching && outcome?.items.length === 0 && /* @__PURE__ */ jsx("p", { className: "te-field__help", children: t.noResults }),
456
+ /* @__PURE__ */ jsx("ul", { className: "te-lookup__results", children: outcome?.items.map((item) => {
457
+ const picked = isPicked?.(item) ?? false;
458
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
459
+ "button",
460
+ {
461
+ type: "button",
462
+ className: "te-lookup__item",
463
+ disabled: picked,
464
+ "aria-pressed": picked,
465
+ onClick: () => onPick(item),
466
+ children: [
467
+ item.image ? /* @__PURE__ */ jsx("img", { src: item.image, alt: "", loading: "lazy" }) : /* @__PURE__ */ jsx("span", { className: "te-lookup__noimage" }),
468
+ /* @__PURE__ */ jsx("span", { children: item.name })
469
+ ]
470
+ }
471
+ ) }, String(item.id));
472
+ }) })
473
+ ] });
474
+ }
475
+ function EntitiesField({ field, value, onChange, t }) {
476
+ const rows = Array.isArray(value) ? value : [];
477
+ const [adding, setAdding] = useState(false);
478
+ const max = field.multiple ? field.max ?? Infinity : 1;
479
+ const min = field.min ?? 0;
480
+ const source = field.source ?? "products";
481
+ const pickedIds = new Set(rows.map((row) => idKey(rowId(row))));
482
+ const keys = chipKeys(rows);
483
+ const pick2 = (item) => {
484
+ if (!field.multiple) {
485
+ onChange([item.data]);
486
+ setAdding(false);
487
+ return;
488
+ }
489
+ if (rows.length >= max) {
490
+ setAdding(false);
491
+ return;
492
+ }
493
+ const next = [...rows, item.data];
494
+ onChange(next);
495
+ if (next.length >= max) setAdding(false);
496
+ };
497
+ return /* @__PURE__ */ jsxs("div", { className: "te-field", children: [
498
+ /* @__PURE__ */ jsxs("div", { className: "te-field__label", children: [
499
+ field.label,
500
+ " ",
501
+ field.multiple && /* @__PURE__ */ jsxs("span", { className: "te-field__count", children: [
502
+ "(",
503
+ rows.length,
504
+ ")"
505
+ ] })
506
+ ] }),
507
+ field.description && /* @__PURE__ */ jsx("p", { className: "te-field__help", children: field.description }),
508
+ rows.length > 0 && /* @__PURE__ */ jsx("ul", { className: "te-chips", children: rows.map((row, index) => {
509
+ const name = rowName(row);
510
+ const image = rowImage(row);
511
+ return /* @__PURE__ */ jsxs("li", { className: "te-chip", children: [
512
+ image ? /* @__PURE__ */ jsx("img", { src: image, alt: "" }) : /* @__PURE__ */ jsx("span", { className: "te-lookup__noimage" }),
513
+ /* @__PURE__ */ jsx("span", { className: "te-chip__name", children: name }),
514
+ /* @__PURE__ */ jsx(
515
+ "button",
516
+ {
517
+ type: "button",
518
+ className: "te-icon-btn te-icon-btn--bare te-icon-btn--danger",
519
+ "aria-label": `${t.remove}: ${name}`,
520
+ disabled: rows.length <= min,
521
+ onClick: () => onChange(rows.filter((_, i) => i !== index)),
522
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
523
+ }
524
+ )
525
+ ] }, keys[index]);
526
+ }) }),
527
+ adding ? /* @__PURE__ */ jsxs(Fragment, { children: [
528
+ /* @__PURE__ */ jsx(
529
+ LookupSearch,
530
+ {
531
+ source,
532
+ t,
533
+ isPicked: (item) => field.multiple === true && pickedIds.has(idKey(item.id)),
534
+ onPick: pick2
535
+ }
536
+ ),
537
+ /* @__PURE__ */ jsx("button", { type: "button", className: "te-btn te-btn--quiet", onClick: () => setAdding(false), children: t.done })
538
+ ] }) : /* @__PURE__ */ jsxs(
539
+ "button",
540
+ {
541
+ type: "button",
542
+ className: "te-add",
543
+ disabled: field.multiple === true && rows.length >= max,
544
+ onClick: () => setAdding(true),
545
+ children: [
546
+ /* @__PURE__ */ jsx(PlusCircleIcon, {}),
547
+ field.multiple || rows.length === 0 ? t.pickFromStore : t.change
548
+ ]
549
+ }
550
+ ),
551
+ rows.length < min && /* @__PURE__ */ jsx("p", { className: "te-field__help te-field__help--error", children: t.minItems(min) })
552
+ ] });
553
+ }
554
+ function kindOf(url, kinds) {
555
+ const fixed = Object.entries(FIXED_LINKS).find(([, path]) => path === url)?.[0];
556
+ if (fixed && kinds.includes(fixed)) return fixed;
557
+ return kinds.includes("custom") ? "custom" : kinds[0] ?? "custom";
558
+ }
559
+ function LinkNotes({ url, description }) {
560
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
561
+ url && /* @__PURE__ */ jsx("p", { className: "te-field__help", dir: "ltr", children: url }),
562
+ description && /* @__PURE__ */ jsx("p", { className: "te-field__help", children: description })
563
+ ] });
564
+ }
565
+ function LinkField({ field, value, onChange, t }) {
566
+ const typeId = useId();
567
+ const urlId = useId();
568
+ const url = typeof value === "string" ? value : "";
569
+ const kinds = field.linkSources?.map((o) => o.value) ?? ["custom"];
570
+ const [kind, setKind] = useState(() => kindOf(url, kinds));
571
+ const [searching, setSearching] = useState(false);
572
+ const lookup = LINK_LOOKUPS[kind];
573
+ const fixed = FIXED_LINKS[kind];
574
+ return /* @__PURE__ */ jsxs("div", { className: "te-field", children: [
575
+ /* @__PURE__ */ jsx("label", { className: "te-field__label", htmlFor: typeId, children: field.label }),
576
+ /* @__PURE__ */ jsx(
577
+ "select",
578
+ {
579
+ id: typeId,
580
+ className: "te-input",
581
+ "aria-label": `${field.label}: ${t.linkTo}`,
582
+ value: kind,
583
+ onChange: (e) => {
584
+ const next = e.target.value;
585
+ setKind(next);
586
+ setSearching(LINK_LOOKUPS[next] !== void 0);
587
+ if (FIXED_LINKS[next]) onChange(FIXED_LINKS[next]);
588
+ },
589
+ children: (field.linkSources ?? [{ label: t.typeUrl, value: "custom" }]).map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
590
+ }
591
+ ),
592
+ lookup && searching && /* @__PURE__ */ jsx(
593
+ LookupSearch,
594
+ {
595
+ source: lookup,
596
+ t,
597
+ onPick: (item) => {
598
+ onChange(item.url ?? "");
599
+ setSearching(false);
600
+ }
601
+ }
602
+ ),
603
+ lookup && !searching && /* @__PURE__ */ jsxs("button", { type: "button", className: "te-add", onClick: () => setSearching(true), children: [
604
+ /* @__PURE__ */ jsx(SearchIcon, {}),
605
+ url ? t.change : t.pickFromStore
606
+ ] }),
607
+ !lookup && !fixed && /* @__PURE__ */ jsx(
608
+ "input",
609
+ {
610
+ id: urlId,
611
+ type: "text",
612
+ dir: "ltr",
613
+ className: "te-input te-input--spaced",
614
+ "aria-label": `${field.label}: URL`,
615
+ placeholder: "https://",
616
+ value: url,
617
+ onChange: (e) => onChange(e.target.value)
618
+ }
619
+ ),
620
+ /* @__PURE__ */ jsx(LinkNotes, { url: lookup || fixed ? url : "", description: field.description })
621
+ ] });
622
+ }
623
+ var MAX_IMAGE_BYTES = DEV_PREVIEW_IMAGE_MAX_BYTES;
624
+ function blockValue(fields, data, id) {
625
+ return id in data ? data[id] : fields.find((f) => f.id === id)?.default;
626
+ }
627
+ function Labeled({
628
+ field,
629
+ htmlFor,
630
+ children
631
+ }) {
632
+ return /* @__PURE__ */ jsxs("div", { className: "te-field", children: [
633
+ /* @__PURE__ */ jsx("label", { className: "te-field__label", htmlFor, children: field.label }),
634
+ children,
635
+ field.description && /* @__PURE__ */ jsx("p", { className: "te-field__help", children: field.description })
636
+ ] });
637
+ }
638
+ function useOnScreen() {
639
+ const onScreen = useRef(false);
640
+ useEffect(() => {
641
+ onScreen.current = true;
642
+ return () => {
643
+ onScreen.current = false;
644
+ };
645
+ }, []);
646
+ return onScreen;
647
+ }
648
+ async function uploadImage(file) {
649
+ const res = await fetch(DEV_PREVIEW_IMAGE_ENDPOINT, {
650
+ method: "POST",
651
+ headers: { "content-type": file.type },
652
+ body: file
653
+ });
654
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
655
+ const { url } = await res.json();
656
+ if (typeof url !== "string") throw new Error("no url");
657
+ return url;
658
+ }
659
+ function ImageField({ field, value, onChange, t }) {
660
+ const id = useId();
661
+ const [upload, setUpload] = useState("idle");
662
+ const latestPick = useRef(0);
663
+ const onScreen = useOnScreen();
664
+ const url = typeof value === "string" ? value : "";
665
+ const pickImage = async (file) => {
666
+ const pick2 = ++latestPick.current;
667
+ setUpload("uploading");
668
+ try {
669
+ const uploaded = await uploadImage(file);
670
+ if (!onScreen.current || pick2 !== latestPick.current) return;
671
+ setUpload("idle");
672
+ onChange(uploaded);
673
+ } catch {
674
+ if (onScreen.current && pick2 === latestPick.current) setUpload("failed");
675
+ }
676
+ };
677
+ const message = {
678
+ idle: null,
679
+ uploading: t.uploading,
680
+ "too-large": t.imageTooLarge,
681
+ failed: t.uploadFailed
682
+ }[upload];
683
+ return /* @__PURE__ */ jsxs(Labeled, { field, htmlFor: id, children: [
684
+ url && /* @__PURE__ */ jsx("img", { className: "te-image__preview", src: url, alt: "" }),
685
+ /* @__PURE__ */ jsx(
686
+ "input",
687
+ {
688
+ id,
689
+ type: "text",
690
+ dir: "ltr",
691
+ className: "te-input",
692
+ placeholder: field.placeholder ?? "https://",
693
+ value: url,
694
+ onChange: (e) => {
695
+ latestPick.current += 1;
696
+ setUpload("idle");
697
+ onChange(e.target.value);
698
+ }
699
+ }
700
+ ),
701
+ /* @__PURE__ */ jsxs("label", { className: "te-image__pick", children: [
702
+ t.chooseImage,
703
+ /* @__PURE__ */ jsx(
704
+ "input",
705
+ {
706
+ type: "file",
707
+ accept: "image/png,image/jpeg,image/webp,image/gif,image/avif",
708
+ hidden: true,
709
+ onChange: (e) => {
710
+ const file = e.target.files?.[0];
711
+ e.target.value = "";
712
+ if (!file) return;
713
+ if (file.size > MAX_IMAGE_BYTES) {
714
+ setUpload("too-large");
715
+ return;
716
+ }
717
+ void pickImage(file);
718
+ }
719
+ }
720
+ )
721
+ ] }),
722
+ message && /* @__PURE__ */ jsx("p", { className: `te-field__help${upload === "uploading" ? "" : " te-field__help--error"}`, children: message })
723
+ ] });
724
+ }
725
+ function itemTitle(field, row, index, t) {
726
+ const name = `${field.itemLabel ?? t.item} ${index + 1}`;
727
+ const textField = field.fields?.find(
728
+ (f) => (f.kind === "text" || f.kind === "textarea") && typeof row[f.id] === "string" && row[f.id]
729
+ );
730
+ return textField ? `${name} \xB7 ${String(row[textField.id])}` : name;
731
+ }
732
+ function newRow(field) {
733
+ return Object.fromEntries(
734
+ (field.fields ?? []).filter((f) => f.kind !== "readonly").map((f) => [f.id, f.default])
735
+ );
736
+ }
737
+ var nextItemKey = 0;
738
+ var newItemKey = () => `item-${nextItemKey++}`;
739
+ function useRowKeys(count) {
740
+ const [keys, setKeys] = useState(() => Array.from({ length: count }, newItemKey));
741
+ if (keys.length !== count) {
742
+ const fresh = Array.from({ length: count }, newItemKey);
743
+ setKeys(fresh);
744
+ return [fresh, setKeys];
745
+ }
746
+ return [keys, setKeys];
747
+ }
748
+ function ItemCard({
749
+ field,
750
+ row,
751
+ index,
752
+ total,
753
+ open,
754
+ t,
755
+ onToggle,
756
+ onMove,
757
+ onRemove,
758
+ onEdit
759
+ }) {
760
+ const title = itemTitle(field, row, index, t);
761
+ return /* @__PURE__ */ jsxs("div", { className: `te-item${open ? " te-item--open" : ""}`, children: [
762
+ /* @__PURE__ */ jsxs("div", { className: "te-item__head", children: [
763
+ /* @__PURE__ */ jsx("button", { type: "button", className: "te-item__title", "aria-expanded": open, onClick: onToggle, children: title }),
764
+ /* @__PURE__ */ jsx(
765
+ "button",
766
+ {
767
+ type: "button",
768
+ className: "te-icon-btn te-icon-btn--bare",
769
+ "aria-label": `${t.moveUp}: ${title}`,
770
+ disabled: index === 0,
771
+ onClick: () => onMove(index - 1),
772
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, {})
773
+ }
774
+ ),
775
+ /* @__PURE__ */ jsx(
776
+ "button",
777
+ {
778
+ type: "button",
779
+ className: "te-icon-btn te-icon-btn--bare",
780
+ "aria-label": `${t.moveDown}: ${title}`,
781
+ disabled: index === total - 1,
782
+ onClick: () => onMove(index + 1),
783
+ children: /* @__PURE__ */ jsx(ArrowDownIcon, {})
784
+ }
785
+ ),
786
+ /* @__PURE__ */ jsx(
787
+ "button",
788
+ {
789
+ type: "button",
790
+ className: "te-icon-btn te-icon-btn--bare te-icon-btn--danger",
791
+ "aria-label": `${t.remove}: ${title}`,
792
+ disabled: !onRemove,
793
+ onClick: onRemove,
794
+ children: /* @__PURE__ */ jsx(TrashIcon, {})
795
+ }
796
+ )
797
+ ] }),
798
+ open && /* @__PURE__ */ jsx("div", { className: "te-item__body", children: field.fields?.filter((sub) => conditionsMet(sub, (id) => blockValue(field.fields ?? [], row, id))).map((sub) => /* @__PURE__ */ jsx(
799
+ Field,
800
+ {
801
+ field: sub,
802
+ t,
803
+ value: blockValue(field.fields ?? [], row, sub.id),
804
+ onChange: (v) => onEdit(sub.id, v)
805
+ },
806
+ sub.id
807
+ )) })
808
+ ] });
809
+ }
810
+ function CollectionField({ field, value, onChange, t }) {
811
+ const rows = Array.isArray(value) ? value : [];
812
+ const [keys, setKeys] = useRowKeys(rows.length);
813
+ const latest = useRef({ rows, keys, onChange });
814
+ const onScreen = useOnScreen();
815
+ useEffect(() => {
816
+ latest.current = { rows, keys, onChange };
817
+ });
818
+ const editItem = (key, fieldId, v) => {
819
+ if (!onScreen.current) return;
820
+ const { rows: now, keys: nowKeys, onChange: report } = latest.current;
821
+ const at = nowKeys.indexOf(key);
822
+ if (at === -1) return;
823
+ report(now.map((r, i) => i === at ? { ...r, [fieldId]: v } : r));
824
+ };
825
+ const [openKey, setOpenKey] = useState(null);
826
+ const min = field.min ?? 0;
827
+ const max = field.max ?? Infinity;
828
+ const update = (edit) => {
829
+ setKeys(edit(keys));
830
+ onChange(edit(rows));
831
+ };
832
+ const move = (from, to) => update((list) => {
833
+ const next = [...list];
834
+ const [item] = next.splice(from, 1);
835
+ next.splice(to, 0, item);
836
+ return next;
837
+ });
838
+ return /* @__PURE__ */ jsxs("div", { className: "te-field", children: [
839
+ /* @__PURE__ */ jsxs("div", { className: "te-field__label", children: [
840
+ field.label,
841
+ " ",
842
+ /* @__PURE__ */ jsxs("span", { className: "te-field__count", children: [
843
+ "(",
844
+ rows.length,
845
+ ")"
846
+ ] })
847
+ ] }),
848
+ field.description && /* @__PURE__ */ jsx("p", { className: "te-field__help", children: field.description }),
849
+ /* @__PURE__ */ jsx("div", { className: "te-items", children: rows.map((row, index) => {
850
+ const key = keys[index];
851
+ return /* @__PURE__ */ jsx(
852
+ ItemCard,
853
+ {
854
+ field,
855
+ row,
856
+ index,
857
+ total: rows.length,
858
+ open: openKey === key,
859
+ t,
860
+ onToggle: () => setOpenKey(openKey === key ? null : key),
861
+ onMove: (to) => move(index, to),
862
+ onRemove: rows.length > min ? () => update((list) => list.filter((_, i) => i !== index)) : void 0,
863
+ onEdit: (fieldId, v) => editItem(key, fieldId, v)
864
+ },
865
+ key
866
+ );
867
+ }) }),
868
+ /* @__PURE__ */ jsxs(
869
+ "button",
870
+ {
871
+ type: "button",
872
+ className: "te-add",
873
+ disabled: rows.length >= max,
874
+ onClick: () => {
875
+ const key = newItemKey();
876
+ setKeys([...keys, key]);
877
+ onChange([...rows, newRow(field)]);
878
+ setOpenKey(key);
879
+ },
880
+ children: [
881
+ /* @__PURE__ */ jsx(PlusCircleIcon, {}),
882
+ t.addItem(field.itemLabel ?? t.item)
883
+ ]
884
+ }
885
+ ),
886
+ rows.length < min && /* @__PURE__ */ jsx("p", { className: "te-field__help te-field__help--error", children: t.minItems(min) })
887
+ ] });
888
+ }
889
+ function ToggleField({ field, value, onChange }) {
890
+ const id = useId();
891
+ return /* @__PURE__ */ jsxs("div", { className: "te-field", children: [
892
+ /* @__PURE__ */ jsxs("label", { className: "te-field--row", htmlFor: id, children: [
893
+ /* @__PURE__ */ jsx("span", { className: "te-field__label", children: field.label }),
894
+ /* @__PURE__ */ jsx(
895
+ "input",
896
+ {
897
+ id,
898
+ type: "checkbox",
899
+ className: "te-checkbox",
900
+ checked: Boolean(value),
901
+ onChange: (e) => onChange(e.target.checked)
902
+ }
903
+ )
904
+ ] }),
905
+ field.description && /* @__PURE__ */ jsx("p", { className: "te-field__help", children: field.description })
906
+ ] });
907
+ }
908
+ function SelectField({ field, value, onChange }) {
909
+ const id = useId();
910
+ return /* @__PURE__ */ jsx(Labeled, { field, htmlFor: id, children: /* @__PURE__ */ jsx(
911
+ "select",
912
+ {
913
+ id,
914
+ className: "te-input",
915
+ value: value == null ? "" : String(value),
916
+ onChange: (e) => onChange(e.target.value),
917
+ children: field.options?.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
918
+ }
919
+ ) });
920
+ }
921
+ function TextField({ field, value, onChange }) {
922
+ const id = useId();
923
+ const common = {
924
+ id,
925
+ className: "te-input",
926
+ placeholder: field.placeholder,
927
+ value: value == null ? "" : String(value)
928
+ };
929
+ return /* @__PURE__ */ jsx(Labeled, { field, htmlFor: id, children: field.kind === "textarea" ? /* @__PURE__ */ jsx("textarea", { ...common, rows: 3, onChange: (e) => onChange(e.target.value) }) : /* @__PURE__ */ jsx("input", { ...common, type: "text", onChange: (e) => onChange(e.target.value) }) });
930
+ }
931
+ function checkNumber(field, raw) {
932
+ if (raw.trim() === "") return { value: null, ok: true };
933
+ const value = Number(raw);
934
+ const ok = Number.isFinite(value) && (field.min === void 0 || value >= field.min) && (field.max === void 0 || value <= field.max);
935
+ return { value, ok };
936
+ }
937
+ function NumberField({ field, value, onChange, t }) {
938
+ const id = useId();
939
+ const shown = typeof value === "number" ? String(value) : "";
940
+ const [draft, setDraft] = useState(shown);
941
+ const [seen, setSeen] = useState(shown);
942
+ if (shown !== seen) {
943
+ setSeen(shown);
944
+ setDraft(shown);
945
+ }
946
+ const { ok } = checkNumber(field, draft);
947
+ return /* @__PURE__ */ jsxs(Labeled, { field, htmlFor: id, children: [
948
+ /* @__PURE__ */ jsx(
949
+ "input",
950
+ {
951
+ id,
952
+ type: "number",
953
+ className: "te-input",
954
+ min: field.min,
955
+ max: field.max,
956
+ placeholder: field.placeholder,
957
+ "aria-invalid": !ok,
958
+ value: draft,
959
+ onChange: (e) => {
960
+ setDraft(e.target.value);
961
+ const checked = checkNumber(field, e.target.value);
962
+ if (checked.ok) onChange(checked.value);
963
+ }
964
+ }
965
+ ),
966
+ !ok && /* @__PURE__ */ jsx("p", { className: "te-field__help te-field__help--error", children: t.outOfRange(field.min, field.max) })
967
+ ] });
968
+ }
969
+ function ReadonlyField({ field, value, t }) {
970
+ const count = Array.isArray(value) ? `${t.items(value.length)} \xB7 ` : "";
971
+ return /* @__PURE__ */ jsxs("div", { className: "te-field te-field--row", children: [
972
+ /* @__PURE__ */ jsx("span", { className: "te-field__label", children: field.label }),
973
+ /* @__PURE__ */ jsxs("span", { className: "te-field__readonly", children: [
974
+ count,
975
+ field.note ?? "\u2014"
976
+ ] })
977
+ ] });
978
+ }
979
+ var FIELDS = {
980
+ toggle: ToggleField,
981
+ select: SelectField,
982
+ text: TextField,
983
+ textarea: TextField,
984
+ number: NumberField,
985
+ image: ImageField,
986
+ collection: CollectionField,
987
+ entities: EntitiesField,
988
+ link: LinkField,
989
+ readonly: ReadonlyField
990
+ };
991
+ function Field(props) {
992
+ const Control = FIELDS[props.field.kind] ?? ReadonlyField;
993
+ return /* @__PURE__ */ jsx(Control, { ...props });
994
+ }
995
+ function PanelHead({ title, onBack, t }) {
996
+ return /* @__PURE__ */ jsxs("div", { className: "te-panel__head", children: [
997
+ onBack && /* @__PURE__ */ jsx(
998
+ "button",
999
+ {
1000
+ type: "button",
1001
+ className: "te-icon-btn te-icon-btn--bare",
1002
+ onClick: onBack,
1003
+ "aria-label": t.back,
1004
+ children: /* @__PURE__ */ jsx(BackIcon, {})
1005
+ }
1006
+ ),
1007
+ /* @__PURE__ */ jsx("span", { children: title })
1008
+ ] });
1009
+ }
1010
+ function BlockRow({
1011
+ block,
1012
+ index,
1013
+ total,
1014
+ title,
1015
+ component,
1016
+ dragging,
1017
+ t,
1018
+ onOpen,
1019
+ onDragStart,
1020
+ onDragEnd,
1021
+ onDropAt
1022
+ }) {
1023
+ const [over, setOver] = useState(false);
1024
+ const className = ["te-block", over && "te-block--over", dragging && "te-block--dragging"].filter(Boolean).join(" ");
1025
+ return /* @__PURE__ */ jsxs(
1026
+ "div",
1027
+ {
1028
+ className,
1029
+ draggable: true,
1030
+ onDragStart: (e) => {
1031
+ e.dataTransfer.effectAllowed = "move";
1032
+ onDragStart();
1033
+ },
1034
+ onDragEnd,
1035
+ onDragOver: (e) => {
1036
+ e.preventDefault();
1037
+ setOver(true);
1038
+ },
1039
+ onDragLeave: () => setOver(false),
1040
+ onDrop: (e) => {
1041
+ e.preventDefault();
1042
+ setOver(false);
1043
+ onDropAt(index);
1044
+ },
1045
+ children: [
1046
+ /* @__PURE__ */ jsx("span", { className: "te-block__grip", children: /* @__PURE__ */ jsx(GripIcon, {}) }),
1047
+ /* @__PURE__ */ jsx("span", { className: "te-block__icon", children: /* @__PURE__ */ jsx(ComponentIcon, { component }) }),
1048
+ /* @__PURE__ */ jsxs("button", { type: "button", className: "te-block__title", onClick: onOpen, children: [
1049
+ title,
1050
+ !component && /* @__PURE__ */ jsxs("span", { className: "te-block__tag", children: [
1051
+ " \xB7 ",
1052
+ t.storeBlock
1053
+ ] })
1054
+ ] }),
1055
+ /* @__PURE__ */ jsxs("span", { className: "te-block__actions", children: [
1056
+ /* @__PURE__ */ jsx(
1057
+ "button",
1058
+ {
1059
+ type: "button",
1060
+ className: "te-icon-btn te-icon-btn--bare",
1061
+ "aria-label": `${t.moveUp}: ${title}`,
1062
+ disabled: index === 0,
1063
+ onClick: () => devSettingsStore.moveBlock(block.id, index - 1),
1064
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, {})
1065
+ }
1066
+ ),
1067
+ /* @__PURE__ */ jsx(
1068
+ "button",
1069
+ {
1070
+ type: "button",
1071
+ className: "te-icon-btn te-icon-btn--bare",
1072
+ "aria-label": `${t.moveDown}: ${title}`,
1073
+ disabled: index === total - 1,
1074
+ onClick: () => devSettingsStore.moveBlock(block.id, index + 1),
1075
+ children: /* @__PURE__ */ jsx(ArrowDownIcon, {})
1076
+ }
1077
+ ),
1078
+ /* @__PURE__ */ jsx(
1079
+ "button",
1080
+ {
1081
+ type: "button",
1082
+ className: "te-icon-btn te-icon-btn--bare",
1083
+ "aria-label": `${t.duplicate}: ${title}`,
1084
+ onClick: () => devSettingsStore.duplicateBlock(block.id),
1085
+ children: /* @__PURE__ */ jsx(CopyIcon, {})
1086
+ }
1087
+ ),
1088
+ /* @__PURE__ */ jsx(
1089
+ "button",
1090
+ {
1091
+ type: "button",
1092
+ className: "te-icon-btn te-icon-btn--bare te-icon-btn--danger",
1093
+ "aria-label": `${t.remove}: ${title}`,
1094
+ onClick: () => devSettingsStore.removeBlock(block.id),
1095
+ children: /* @__PURE__ */ jsx(TrashIcon, {})
1096
+ }
1097
+ )
1098
+ ] })
1099
+ ]
1100
+ }
1101
+ );
1102
+ }
1103
+ function storeRowKeys(blocks) {
1104
+ const seen = /* @__PURE__ */ new Map();
1105
+ return blocks.map((block, index) => {
1106
+ const path = block.path ?? "";
1107
+ const n = (seen.get(path) ?? 0) + 1;
1108
+ seen.set(path, n);
1109
+ return { key: n === 1 ? path : `${path}#${n}`, block, index };
1110
+ });
1111
+ }
1112
+ function StoreLayout({
1113
+ schema,
1114
+ t,
1115
+ locale,
1116
+ isHome
1117
+ }) {
1118
+ const { liveBlocks } = useDevEditorMeta();
1119
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1120
+ /* @__PURE__ */ jsx("div", { className: "te-section-title", children: t.builder }),
1121
+ liveBlocks && storeRowKeys(liveBlocks).map(({ key, block, index }) => /* @__PURE__ */ jsxs("div", { className: "te-block te-block--static", children: [
1122
+ /* @__PURE__ */ jsx("span", { className: "te-block__icon", children: /* @__PURE__ */ jsx(ComponentIcon, { component: componentFor(schema, block.path) }) }),
1123
+ /* @__PURE__ */ jsx(
1124
+ "button",
1125
+ {
1126
+ type: "button",
1127
+ className: "te-block__title",
1128
+ onClick: () => devSettingsStore.focusBlock(index),
1129
+ children: titleOf(componentFor(schema, block.path), block.path ?? "", locale)
1130
+ }
1131
+ )
1132
+ ] }, key)),
1133
+ !liveBlocks && isHome && /* @__PURE__ */ jsx("p", { className: "te-hint", children: t.waitingForStore }),
1134
+ /* @__PURE__ */ jsx("p", { className: "te-hint", children: t.storeLayoutHint }),
1135
+ /* @__PURE__ */ jsx(
1136
+ "button",
1137
+ {
1138
+ type: "button",
1139
+ className: "te-btn te-btn--primary",
1140
+ onClick: () => devSettingsStore.customizeLayout(schema),
1141
+ children: t.customize
1142
+ }
1143
+ ),
1144
+ /* @__PURE__ */ jsx("button", { type: "button", className: "te-btn", onClick: () => devSettingsStore.startEmptyLayout(), children: t.startEmpty })
1145
+ ] });
1146
+ }
1147
+ function BlockList({
1148
+ schema,
1149
+ t,
1150
+ locale,
1151
+ layout,
1152
+ onOpen,
1153
+ onAdd
1154
+ }) {
1155
+ const [dragId, setDragId] = useState(null);
1156
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1157
+ /* @__PURE__ */ jsx("div", { className: "te-section-title", children: t.builder }),
1158
+ layout.length === 0 && /* @__PURE__ */ jsx("p", { className: "te-hint", children: t.noBlocks }),
1159
+ layout.map((block, index) => {
1160
+ const component = componentFor(schema, block.path);
1161
+ return /* @__PURE__ */ jsx(
1162
+ BlockRow,
1163
+ {
1164
+ block,
1165
+ index,
1166
+ total: layout.length,
1167
+ title: titleOf(component, block.path, locale),
1168
+ component,
1169
+ dragging: dragId === block.id,
1170
+ t,
1171
+ onOpen: () => onOpen(block.id),
1172
+ onDragStart: () => setDragId(block.id),
1173
+ onDragEnd: () => setDragId(null),
1174
+ onDropAt: (to) => {
1175
+ if (dragId) devSettingsStore.moveBlock(dragId, to);
1176
+ setDragId(null);
1177
+ }
1178
+ },
1179
+ block.id
1180
+ );
1181
+ }),
1182
+ schema.components.length > 0 && /* @__PURE__ */ jsxs("button", { type: "button", className: "te-add", onClick: onAdd, children: [
1183
+ /* @__PURE__ */ jsx(PlusCircleIcon, {}),
1184
+ t.addElement
1185
+ ] })
1186
+ ] });
1187
+ }
1188
+ function BackToStore({ t }) {
1189
+ const [confirming, setConfirming] = useState(false);
1190
+ return /* @__PURE__ */ jsx("div", { className: "te-panel__actions", children: /* @__PURE__ */ jsx(
1191
+ "button",
1192
+ {
1193
+ type: "button",
1194
+ className: `te-btn te-btn--quiet${confirming ? " te-btn--danger" : ""}`,
1195
+ onClick: () => {
1196
+ if (!confirming) {
1197
+ setConfirming(true);
1198
+ return;
1199
+ }
1200
+ setConfirming(false);
1201
+ devSettingsStore.clearLayout();
1202
+ },
1203
+ onBlur: () => setConfirming(false),
1204
+ children: confirming ? t.confirm : t.backToStore
1205
+ }
1206
+ ) });
1207
+ }
1208
+ function BlockEditor({
1209
+ schema,
1210
+ t,
1211
+ locale,
1212
+ block,
1213
+ index,
1214
+ total,
1215
+ onBack
1216
+ }) {
1217
+ const component = componentFor(schema, block.path);
1218
+ const title = titleOf(component, block.path, locale);
1219
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1220
+ /* @__PURE__ */ jsx(PanelHead, { title, onBack, t }),
1221
+ /* @__PURE__ */ jsxs("div", { className: "te-panel__body", children: [
1222
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 4, margin: "0 4px 6px" }, children: [
1223
+ /* @__PURE__ */ jsx(
1224
+ "button",
1225
+ {
1226
+ type: "button",
1227
+ className: "te-icon-btn",
1228
+ "aria-label": `${t.moveUp}: ${title}`,
1229
+ disabled: index === 0,
1230
+ onClick: () => devSettingsStore.moveBlock(block.id, index - 1),
1231
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, {})
1232
+ }
1233
+ ),
1234
+ /* @__PURE__ */ jsx(
1235
+ "button",
1236
+ {
1237
+ type: "button",
1238
+ className: "te-icon-btn",
1239
+ "aria-label": `${t.moveDown}: ${title}`,
1240
+ disabled: index === total - 1,
1241
+ onClick: () => devSettingsStore.moveBlock(block.id, index + 1),
1242
+ children: /* @__PURE__ */ jsx(ArrowDownIcon, {})
1243
+ }
1244
+ ),
1245
+ /* @__PURE__ */ jsx(
1246
+ "button",
1247
+ {
1248
+ type: "button",
1249
+ className: "te-icon-btn",
1250
+ "aria-label": `${t.duplicate}: ${title}`,
1251
+ onClick: () => devSettingsStore.duplicateBlock(block.id),
1252
+ children: /* @__PURE__ */ jsx(CopyIcon, {})
1253
+ }
1254
+ ),
1255
+ /* @__PURE__ */ jsx(
1256
+ "button",
1257
+ {
1258
+ type: "button",
1259
+ className: "te-icon-btn te-icon-btn--danger",
1260
+ "aria-label": `${t.remove}: ${title}`,
1261
+ onClick: () => {
1262
+ devSettingsStore.removeBlock(block.id);
1263
+ onBack();
1264
+ },
1265
+ children: /* @__PURE__ */ jsx(TrashIcon, {})
1266
+ }
1267
+ )
1268
+ ] }),
1269
+ !component && /* @__PURE__ */ jsx("p", { className: "te-hint", children: t.notDeclared }),
1270
+ component && component.fields.length === 0 && /* @__PURE__ */ jsx("p", { className: "te-hint", children: t.noFields }),
1271
+ component?.fields.filter((f) => conditionsMet(f, (id) => blockValue(component.fields, block.fields, id))).map((f) => /* @__PURE__ */ jsx(
1272
+ Field,
1273
+ {
1274
+ field: f,
1275
+ t,
1276
+ value: blockValue(component.fields, block.fields, f.id),
1277
+ onChange: (v) => {
1278
+ if (!devSettingsStore.get().enabled) devSettingsStore.enable(schema);
1279
+ devSettingsStore.setBlockField(block.id, f.id, v);
1280
+ }
1281
+ },
1282
+ f.id
1283
+ ))
1284
+ ] })
1285
+ ] });
1286
+ }
1287
+ function BuilderPanel({
1288
+ schema,
1289
+ t,
1290
+ locale,
1291
+ isHome,
1292
+ onGoHome,
1293
+ openId,
1294
+ onOpenId,
1295
+ onAddElement
1296
+ }) {
1297
+ const store = useDevSettingsState();
1298
+ const layout = store.layout;
1299
+ const index = layout && openId ? layout.findIndex((block) => block.id === openId) : -1;
1300
+ if (layout && index !== -1) {
1301
+ return /* @__PURE__ */ jsx(
1302
+ BlockEditor,
1303
+ {
1304
+ schema,
1305
+ t,
1306
+ locale,
1307
+ block: layout[index],
1308
+ index,
1309
+ total: layout.length,
1310
+ onBack: () => onOpenId(null)
1311
+ }
1312
+ );
1313
+ }
1314
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1315
+ /* @__PURE__ */ jsx(PanelHead, { title: t.homePage, t }),
1316
+ /* @__PURE__ */ jsxs("div", { className: "te-panel__body", children: [
1317
+ !isHome && /* @__PURE__ */ jsxs("div", { className: "te-note", children: [
1318
+ t.notHome,
1319
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: onGoHome, children: t.goHome })
1320
+ ] }),
1321
+ layout && !store.enabled && /* @__PURE__ */ jsx("div", { className: "te-note", children: t.previewOff }),
1322
+ layout ? /* @__PURE__ */ jsx(
1323
+ BlockList,
1324
+ {
1325
+ schema,
1326
+ t,
1327
+ locale,
1328
+ layout,
1329
+ onOpen: (id) => {
1330
+ onOpenId(id);
1331
+ devSettingsStore.focusBlock(layout.findIndex((block) => block.id === id));
1332
+ },
1333
+ onAdd: onAddElement
1334
+ }
1335
+ ) : /* @__PURE__ */ jsx(StoreLayout, { schema, t, locale, isHome })
1336
+ ] }),
1337
+ layout && /* @__PURE__ */ jsx(BackToStore, { t })
1338
+ ] });
1339
+ }
1340
+ function SettingsPanel({
1341
+ schema,
1342
+ t
1343
+ }) {
1344
+ const store = useDevSettingsState();
1345
+ const valueOf = (f) => f.id in store.settings ? store.settings[f.id] : f.default;
1346
+ const byId = new Map(schema.settings.map((f) => [f.id, f]));
1347
+ const visible = schema.settings.filter(
1348
+ (f) => conditionsMet(f, (id) => {
1349
+ const other = byId.get(id);
1350
+ return other ? valueOf(other) : store.settings[id];
1351
+ })
1352
+ );
1353
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1354
+ /* @__PURE__ */ jsx("div", { className: "te-panel__head", children: /* @__PURE__ */ jsx("span", { children: t.settings }) }),
1355
+ /* @__PURE__ */ jsxs("div", { className: "te-panel__body", children: [
1356
+ !store.enabled && /* @__PURE__ */ jsx("div", { className: "te-note", children: t.previewOff }),
1357
+ schema.settings.length === 0 && /* @__PURE__ */ jsx("p", { className: "te-hint", children: t.noSettings }),
1358
+ visible.map((f) => /* @__PURE__ */ jsx(
1359
+ Field,
1360
+ {
1361
+ field: f,
1362
+ t,
1363
+ value: valueOf(f),
1364
+ onChange: (v) => {
1365
+ if (!store.enabled) devSettingsStore.enable(schema);
1366
+ devSettingsStore.setSetting(f.id, v);
1367
+ }
1368
+ },
1369
+ f.id
1370
+ )),
1371
+ schema.settings.length > 0 && /* @__PURE__ */ jsx(
1372
+ "button",
1373
+ {
1374
+ type: "button",
1375
+ className: "te-btn te-btn--quiet",
1376
+ onClick: () => devSettingsStore.resetSettings(schema),
1377
+ children: t.resetSettings
1378
+ }
1379
+ )
1380
+ ] })
1381
+ ] });
1382
+ }
1383
+
1384
+ // src/dev/editor/paths.ts
1385
+ var LOCALES = ["ar", "en"];
1386
+ function isLocale(segment) {
1387
+ return LOCALES.includes(segment ?? "");
1388
+ }
1389
+ function splitSuffix(path) {
1390
+ const at = path.search(/[?#]/);
1391
+ return at === -1 ? [path, ""] : [path.slice(0, at), path.slice(at)];
1392
+ }
1393
+ function parseStorePath(path, base) {
1394
+ const [pathname, suffix] = splitSuffix(path);
1395
+ let segments = pathname.split("/").filter(Boolean);
1396
+ let storeBase = null;
1397
+ if (base !== void 0) {
1398
+ if (base && segments[0] === base) {
1399
+ storeBase = base;
1400
+ segments = segments.slice(1);
1401
+ }
1402
+ } else if (!isLocale(segments[0]) && isLocale(segments[1])) {
1403
+ storeBase = segments[0];
1404
+ segments = segments.slice(1);
1405
+ }
1406
+ const locale = isLocale(segments[0]) ? segments[0] : null;
1407
+ return { base: storeBase, locale, rest: segments.slice(locale ? 1 : 0), suffix };
1408
+ }
1409
+ function join(base, segments, suffix = "") {
1410
+ return `/${[...base ? [base] : [], ...segments].join("/")}${suffix}`;
1411
+ }
1412
+ function safePath(raw, origin) {
1413
+ if (!raw) return "/ar";
1414
+ const here = (typeof window !== "undefined" ? window.location.origin : "http://localhost");
1415
+ try {
1416
+ const url = new URL(raw, here);
1417
+ if (url.origin !== new URL(here).origin) return "/ar";
1418
+ return `${url.pathname}${url.search}${url.hash}`;
1419
+ } catch {
1420
+ return "/ar";
1421
+ }
1422
+ }
1423
+ function localeOf(path, base) {
1424
+ return parseStorePath(path, base).locale ?? "ar";
1425
+ }
1426
+ function isHomePath(path, base) {
1427
+ return parseStorePath(path, base).rest.length === 0;
1428
+ }
1429
+ function withLocale(path, locale, base) {
1430
+ const parsed = parseStorePath(path, base);
1431
+ return join(parsed.base, [locale, ...parsed.rest], parsed.suffix);
1432
+ }
1433
+ function homeOf(path, base) {
1434
+ const parsed = parseStorePath(path, base);
1435
+ return join(parsed.base, [parsed.locale ?? "ar"]);
1436
+ }
1437
+ function standaloneHref(path) {
1438
+ const [pathname, suffix] = splitSuffix(path);
1439
+ if (pathname !== "/" && pathname !== "") return path;
1440
+ const hashAt = suffix.indexOf("#");
1441
+ const query = hashAt === -1 ? suffix : suffix.slice(0, hashAt);
1442
+ const hash = hashAt === -1 ? "" : suffix.slice(hashAt);
1443
+ const params = new URLSearchParams(query.replace(/^\?/, ""));
1444
+ params.set("editor", "off");
1445
+ return `/?${params.toString()}${hash}`;
1446
+ }
1447
+
1448
+ // src/dev/editor/styles.ts
1449
+ var EDITOR_CSS = `
1450
+ :root {
1451
+ --te-accent: #0d9488;
1452
+ --te-accent-soft: #e6f6f4;
1453
+ --te-text: #1f2937;
1454
+ --te-sub: #6b7280;
1455
+ --te-faint: #9ca3af;
1456
+ --te-border: #e5e7eb;
1457
+ --te-row: #f3f4f6;
1458
+ --te-bg: #ffffff;
1459
+ --te-canvas: #f6f7f9;
1460
+ --te-danger: #dc2626;
1461
+ --te-warn-bg: #fef3c7;
1462
+ --te-warn: #b45309;
1463
+ --te-rail: 56px;
1464
+ --te-panel: 385px;
1465
+ --te-top: 52px;
1466
+ }
1467
+ * { box-sizing: border-box; }
1468
+ [dir='rtl'] { --te-back-flip: -1; }
1469
+ html, body, #root { height: 100%; margin: 0; }
1470
+ body {
1471
+ font-family: 'PingARLT', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
1472
+ color: var(--te-text);
1473
+ background: var(--te-bg);
1474
+ font-size: 13px;
1475
+ }
1476
+ button { font: inherit; color: inherit; }
1477
+ code { font-size: 11.5px; background: var(--te-row); padding: 1px 4px; border-radius: 4px; }
1478
+
1479
+ .te-shell { display: grid; grid-template-rows: var(--te-top) 1fr; height: 100%; }
1480
+ .te-body { display: flex; min-height: 0; position: relative; }
1481
+
1482
+ /* Top bar */
1483
+ .te-top {
1484
+ display: flex; align-items: center; gap: 12px; padding: 0 14px;
1485
+ border-bottom: 1px solid var(--te-border); background: var(--te-bg);
1486
+ }
1487
+ .te-top__start, .te-top__end { flex: 1; display: flex; align-items: center; gap: 10px; min-width: 0; }
1488
+ .te-top__end { justify-content: flex-end; }
1489
+ .te-theme-name { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
1490
+ .te-badge {
1491
+ font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px;
1492
+ background: var(--te-warn-bg); color: var(--te-warn); white-space: nowrap;
1493
+ }
1494
+ .te-pill {
1495
+ display: flex; align-items: center; gap: 6px; padding: 5px 10px; border-radius: 8px;
1496
+ border: 1px solid var(--te-border); color: var(--te-sub); white-space: nowrap; max-width: 260px;
1497
+ overflow: hidden; text-overflow: ellipsis; direction: ltr;
1498
+ }
1499
+ .te-status { font-size: 12px; color: var(--te-faint); white-space: nowrap; display: flex; align-items: center; gap: 6px; }
1500
+ .te-status--error { color: var(--te-danger); }
1501
+ .te-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
1502
+
1503
+ .te-segment { display: flex; padding: 3px; gap: 2px; background: var(--te-row); border-radius: 10px; }
1504
+ .te-segment button {
1505
+ display: flex; align-items: center; justify-content: center; width: 36px; height: 30px;
1506
+ border: none; border-radius: 8px; background: transparent; color: var(--te-sub); cursor: pointer;
1507
+ }
1508
+ .te-segment button[aria-pressed='true'] { background: var(--te-bg); color: var(--te-text); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
1509
+ .te-segment--text button { width: auto; padding: 0 10px; font-size: 12px; font-weight: 600; }
1510
+
1511
+ .te-icon-btn {
1512
+ display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px;
1513
+ border: 1px solid var(--te-border); border-radius: 8px; background: var(--te-bg);
1514
+ color: var(--te-sub); cursor: pointer; text-decoration: none; flex: none;
1515
+ }
1516
+ .te-icon-btn:hover { color: var(--te-text); background: var(--te-row); }
1517
+ .te-icon-btn--bare { border-color: transparent; background: transparent; width: 28px; height: 28px; }
1518
+ .te-icon-btn--danger:hover { color: var(--te-danger); }
1519
+ .te-icon-btn:disabled { opacity: .35; cursor: default; }
1520
+
1521
+ .te-switch {
1522
+ display: inline-flex; align-items: center; gap: 8px; border: none; background: none;
1523
+ cursor: pointer; font-size: 12px; font-weight: 600; color: var(--te-sub); white-space: nowrap;
1524
+ }
1525
+ .te-switch__track {
1526
+ width: 34px; height: 20px; border-radius: 999px; background: #d1d5db; position: relative; transition: background .15s;
1527
+ }
1528
+ .te-switch__track::after {
1529
+ content: ''; position: absolute; top: 2px; inset-inline-start: 2px; width: 16px; height: 16px;
1530
+ border-radius: 50%; background: #fff; transition: inset-inline-start .15s; box-shadow: 0 1px 2px rgba(0,0,0,.2);
1531
+ }
1532
+ .te-switch[aria-checked='true'] { color: var(--te-accent); }
1533
+ .te-switch[aria-checked='true'] .te-switch__track { background: var(--te-accent); }
1534
+ .te-switch[aria-checked='true'] .te-switch__track::after { inset-inline-start: 16px; }
1535
+
1536
+ /* Icon rail + panel (start side: the right in Arabic, like the dashboard) */
1537
+ .te-rail {
1538
+ width: var(--te-rail); flex: none; display: flex; flex-direction: column; align-items: center;
1539
+ gap: 6px; padding: 12px 0; border-inline-end: 1px solid var(--te-border); background: var(--te-bg);
1540
+ }
1541
+ .te-rail button {
1542
+ width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
1543
+ border: none; border-radius: 10px; background: transparent; color: var(--te-sub); cursor: pointer;
1544
+ }
1545
+ .te-rail button:hover { background: var(--te-row); color: var(--te-text); }
1546
+ .te-rail button[aria-selected='true'] { background: var(--te-accent-soft); color: var(--te-accent); }
1547
+ .te-rail__tabs { display: flex; flex-direction: column; gap: 6px; padding-top: 6px; border-top: 1px solid var(--te-border); }
1548
+
1549
+ .te-panel {
1550
+ width: var(--te-panel); flex: none; display: flex; flex-direction: column; min-height: 0;
1551
+ border-inline-end: 1px solid var(--te-border); background: var(--te-bg);
1552
+ }
1553
+ .te-panel[hidden] { display: none; }
1554
+ .te-panel__head {
1555
+ display: flex; align-items: center; gap: 8px; padding: 14px 16px 10px; font-weight: 700; font-size: 14px;
1556
+ }
1557
+ .te-panel__head span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1558
+ .te-panel__body { flex: 1; overflow-y: auto; padding: 0 12px 16px; }
1559
+ .te-panel__actions { padding: 0 12px 4px; border-top: 1px solid var(--te-border); }
1560
+ .te-panel__actions .te-btn { margin-top: 8px; }
1561
+ .te-panel__foot { padding: 10px 16px; border-top: 1px solid var(--te-border); font-size: 11.5px; color: var(--te-faint); }
1562
+
1563
+ .te-section-title {
1564
+ font-size: 11px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
1565
+ color: var(--te-faint); margin: 14px 4px 6px;
1566
+ }
1567
+ .te-hint { font-size: 12px; color: var(--te-sub); line-height: 1.6; margin: 8px 4px; }
1568
+ .te-note {
1569
+ font-size: 12px; line-height: 1.6; margin: 4px 0 10px; padding: 8px 10px; border-radius: 8px;
1570
+ background: var(--te-warn-bg); color: var(--te-warn);
1571
+ }
1572
+ .te-note button { margin-inline-start: 6px; border: none; background: none; color: inherit; font-weight: 700; text-decoration: underline; cursor: pointer; padding: 0; }
1573
+
1574
+ /* Block list */
1575
+ .te-block {
1576
+ display: flex; align-items: center; gap: 8px; padding: 6px 6px; border-radius: 8px;
1577
+ border-top: 2px solid transparent; cursor: pointer;
1578
+ }
1579
+ .te-block:hover { background: var(--te-row); }
1580
+ .te-block--over { border-top-color: var(--te-accent); }
1581
+ .te-block--dragging { opacity: .4; }
1582
+ .te-block--static { cursor: default; }
1583
+ .te-block__grip { color: var(--te-faint); cursor: grab; display: flex; }
1584
+ .te-block__icon { color: var(--te-sub); display: flex; flex: none; }
1585
+ .te-block__title {
1586
+ flex: 1; min-width: 0; border: none; background: none; text-align: start; cursor: pointer;
1587
+ padding: 4px 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1588
+ }
1589
+ .te-block__tag { font-size: 11px; color: var(--te-faint); }
1590
+ .te-block__actions { display: flex; gap: 2px; opacity: 0; }
1591
+ .te-block:hover .te-block__actions, .te-block:focus-within .te-block__actions { opacity: 1; }
1592
+
1593
+ .te-add {
1594
+ display: flex; align-items: center; gap: 8px; width: 100%; margin-top: 6px; padding: 9px 8px;
1595
+ border: none; border-radius: 8px; background: none; color: var(--te-accent); font-weight: 600; cursor: pointer; text-align: start;
1596
+ }
1597
+ .te-add:hover { background: var(--te-accent-soft); }
1598
+
1599
+ .te-btn {
1600
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px; width: 100%;
1601
+ padding: 10px 12px; border-radius: 10px; border: 1px solid var(--te-border); background: var(--te-bg);
1602
+ color: var(--te-text); font-weight: 600; cursor: pointer; margin-top: 8px;
1603
+ }
1604
+ .te-btn:hover { background: var(--te-row); }
1605
+ .te-btn--primary { background: var(--te-accent); border-color: var(--te-accent); color: #fff; }
1606
+ .te-btn--primary:hover { background: #0f766e; }
1607
+ .te-btn--quiet { border-color: transparent; color: var(--te-sub); font-weight: 500; }
1608
+ .te-btn--danger { color: var(--te-danger); border-color: var(--te-danger); }
1609
+
1610
+ /* Fields */
1611
+ .te-field { padding: 10px 4px; border-bottom: 1px solid var(--te-row); }
1612
+ .te-field__label { display: block; font-size: 12.5px; color: var(--te-text); margin-bottom: 6px; line-height: 1.5; }
1613
+ .te-field--row { display: flex; align-items: center; justify-content: space-between; gap: 10px; cursor: pointer; }
1614
+ .te-field > .te-field--row .te-field__label { margin: 0; }
1615
+ .te-field--row .te-field__label { margin: 0; flex: 1; }
1616
+ .te-input {
1617
+ width: 100%; padding: 8px 10px; border: 1px solid var(--te-border); border-radius: 8px;
1618
+ background: var(--te-bg); color: var(--te-text); font: inherit;
1619
+ }
1620
+ .te-input:focus { outline: 2px solid var(--te-accent-soft); border-color: var(--te-accent); }
1621
+ .te-field__help { font-size: 11.5px; color: var(--te-faint); line-height: 1.6; margin: 6px 0 0; }
1622
+ .te-field__help--error { color: var(--te-danger); }
1623
+ .te-field__count { color: var(--te-faint); font-weight: 400; }
1624
+ textarea.te-input { resize: vertical; min-height: 64px; }
1625
+ .te-image__preview {
1626
+ display: block; width: 100%; max-height: 140px; object-fit: contain; margin-bottom: 8px;
1627
+ border-radius: 8px; background: var(--te-row);
1628
+ }
1629
+ .te-image__pick {
1630
+ display: inline-block; margin-top: 6px; font-size: 12px; color: var(--te-accent); font-weight: 600; cursor: pointer;
1631
+ }
1632
+ .te-items { display: flex; flex-direction: column; gap: 6px; }
1633
+ .te-item { border: 1px solid var(--te-border); border-radius: 10px; background: var(--te-bg); }
1634
+ .te-item--open { border-color: var(--te-accent); }
1635
+ .te-item__head { display: flex; align-items: center; gap: 2px; padding: 4px 6px 4px 4px; }
1636
+ .te-item__title {
1637
+ flex: 1; min-width: 0; border: none; background: none; cursor: pointer; text-align: start;
1638
+ padding: 6px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1639
+ }
1640
+ .te-item__body { padding: 0 10px 6px; border-top: 1px solid var(--te-row); }
1641
+ .te-field__help--warn { color: var(--te-warn); background: var(--te-warn-bg); padding: 6px 8px; border-radius: 6px; }
1642
+ .te-input--spaced { margin-top: 8px; }
1643
+ .te-search--small { margin: 8px 0; }
1644
+ .te-search--small input { padding: 8px 0; }
1645
+ .te-lookup { margin-top: 6px; }
1646
+ .te-lookup__results { list-style: none; margin: 4px 0 0; padding: 0; max-height: 260px; overflow-y: auto; }
1647
+ .te-lookup__item {
1648
+ display: flex; align-items: center; gap: 10px; width: 100%; padding: 6px; border: none; border-radius: 8px;
1649
+ background: none; cursor: pointer; text-align: start;
1650
+ }
1651
+ .te-lookup__item:hover { background: var(--te-row); }
1652
+ .te-lookup__item:disabled { opacity: .45; cursor: default; }
1653
+ .te-lookup__item img, .te-chip img, .te-lookup__noimage {
1654
+ width: 32px; height: 32px; border-radius: 6px; object-fit: cover; flex: none; background: var(--te-row);
1655
+ }
1656
+ .te-chips { list-style: none; margin: 0 0 4px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
1657
+ .te-chip { display: flex; align-items: center; gap: 8px; padding: 4px 4px 4px 6px; border: 1px solid var(--te-border); border-radius: 10px; }
1658
+ .te-chip__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1659
+ .te-add:disabled { opacity: .4; cursor: default; background: none; }
1660
+ .te-field__readonly { font-size: 11.5px; color: var(--te-faint); font-style: italic; }
1661
+ .te-checkbox { width: 16px; height: 16px; accent-color: var(--te-accent); cursor: pointer; flex: none; }
1662
+
1663
+ /* Salla icons (sallaicons.css) inside the editor's own chrome */
1664
+ .te-sicon { font-size: 20px; line-height: 1; display: inline-flex; width: 20px; justify-content: center; }
1665
+
1666
+ /* Add-element drawer: beside the panel, over the preview */
1667
+ .te-drawer {
1668
+ /* reset what browsers give a <dialog> */
1669
+ margin: 0; padding: 0; border: none; max-width: none; max-height: none; height: auto; color: inherit;
1670
+ position: absolute; top: 0; bottom: 0; z-index: 5;
1671
+ inset-inline-start: calc(var(--te-rail) + var(--te-panel));
1672
+ width: min(760px, calc(100% - var(--te-rail) - var(--te-panel)));
1673
+ display: flex; flex-direction: column; background: var(--te-bg);
1674
+ border-inline-end: 1px solid var(--te-border); box-shadow: 0 12px 40px rgba(0,0,0,.12);
1675
+ }
1676
+ .te-drawer__head { display: flex; align-items: center; gap: 10px; padding: 16px 20px 8px; }
1677
+ .te-drawer__head h2 { flex: 1; margin: 0; font-size: 18px; }
1678
+ .te-icon-btn--danger-outline { color: var(--te-danger); border-color: #fca5a5; }
1679
+ .te-icon-btn--danger-outline:hover { color: var(--te-danger); background: #fef2f2; }
1680
+ .te-search {
1681
+ display: flex; align-items: center; gap: 8px; margin: 8px 20px 14px; padding: 0 12px;
1682
+ border: 1px solid var(--te-border); border-radius: 10px; color: var(--te-faint);
1683
+ }
1684
+ .te-search:focus-within { border-color: var(--te-accent); }
1685
+ .te-search input { flex: 1; border: none; outline: none; padding: 11px 0; font: inherit; color: var(--te-text); background: none; }
1686
+ .te-drawer__body { flex: 1; overflow-y: auto; padding: 0 20px 20px; }
1687
+ .te-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 14px; }
1688
+ .te-card {
1689
+ display: flex; flex-direction: column; text-align: start; padding: 0; overflow: hidden; cursor: pointer;
1690
+ border: 1px solid var(--te-border); border-radius: 12px; background: var(--te-bg);
1691
+ }
1692
+ .te-card:hover, .te-card:focus-visible { border-color: var(--te-accent); box-shadow: 0 4px 14px rgba(13,148,136,.12); outline: none; }
1693
+ .te-card__title { display: flex; align-items: center; gap: 8px; padding: 12px 14px; font-weight: 600; }
1694
+ .te-card__icon { color: #d97706; display: flex; }
1695
+ .te-card__preview {
1696
+ display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3;
1697
+ background: var(--te-row); overflow: hidden;
1698
+ }
1699
+ .te-card__preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
1700
+ .te-card__placeholder { color: #cbd5e1; transform: scale(2); display: flex; }
1701
+
1702
+ /* Canvas */
1703
+ .te-canvas {
1704
+ flex: 1; min-width: 0; display: flex; justify-content: center; padding: 20px; overflow: auto;
1705
+ background-color: var(--te-canvas);
1706
+ background-image: radial-gradient(#d9dce1 1px, transparent 1px);
1707
+ background-size: 16px 16px;
1708
+ }
1709
+ .te-frame {
1710
+ border: none; background: #fff; height: 100%; display: block;
1711
+ border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,.08), 0 8px 24px rgba(0,0,0,.06);
1712
+ transition: width .2s ease;
1713
+ }
1714
+ .te-frame--desktop { width: 100%; }
1715
+ .te-canvas--mobile { align-items: center; }
1716
+ /* A typical phone screen (390\xD7844), never taller than the canvas. */
1717
+ .te-frame--mobile {
1718
+ width: 390px; height: min(844px, 100%); flex: none;
1719
+ border-radius: 36px; border: 10px solid #111827;
1720
+ }
1721
+ `;
1722
+ var DEVICE_KEY = "twilight:editor-device";
1723
+ var PANEL_KEY = "twilight:editor-panel";
1724
+ var PANEL_ID = "te-panel";
1725
+ var PATH_POLL_MS = 500;
1726
+ function readDevice() {
1727
+ if (typeof window === "undefined") return "mobile";
1728
+ try {
1729
+ return window.localStorage.getItem(DEVICE_KEY) === "desktop" ? "desktop" : "mobile";
1730
+ } catch {
1731
+ return "mobile";
1732
+ }
1733
+ }
1734
+ function readCollapsed() {
1735
+ if (typeof window === "undefined") return false;
1736
+ try {
1737
+ return window.localStorage.getItem(PANEL_KEY) === "collapsed";
1738
+ } catch {
1739
+ return false;
1740
+ }
1741
+ }
1742
+ function usePanelCollapsed() {
1743
+ const [collapsed, setCollapsed] = useState(readCollapsed);
1744
+ useEffect(() => {
1745
+ try {
1746
+ window.localStorage.setItem(PANEL_KEY, collapsed ? "collapsed" : "open");
1747
+ } catch {
1748
+ }
1749
+ }, [collapsed]);
1750
+ return [collapsed, setCollapsed];
1751
+ }
1752
+ function readInitialPath(initialPath) {
1753
+ if (initialPath !== void 0 || typeof window === "undefined") return safePath(initialPath);
1754
+ return safePath(new URLSearchParams(window.location.search).get("path"));
1755
+ }
1756
+ function useFramePath(initialPath) {
1757
+ const [src, setSrc] = useState(() => readInitialPath(initialPath));
1758
+ const [path, setPath] = useState(src);
1759
+ const [frameKey, setFrameKey] = useState(0);
1760
+ const frameRef = useRef(null);
1761
+ useEffect(() => {
1762
+ const timer = setInterval(() => {
1763
+ try {
1764
+ const location = frameRef.current?.contentWindow?.location;
1765
+ if (!location || location.href === "about:blank") return;
1766
+ const next = `${location.pathname}${location.search}${location.hash}`;
1767
+ setPath((current) => current === next ? current : next);
1768
+ } catch {
1769
+ }
1770
+ }, PATH_POLL_MS);
1771
+ return () => clearInterval(timer);
1772
+ }, []);
1773
+ useEffect(() => {
1774
+ const url = new URL(window.location.href);
1775
+ url.searchParams.set("path", path);
1776
+ window.history.replaceState(null, "", url);
1777
+ }, [path]);
1778
+ const navigate = useCallback((to) => {
1779
+ setSrc(to);
1780
+ setPath(to);
1781
+ setFrameKey((key) => key + 1);
1782
+ }, []);
1783
+ useEffect(() => devSettingsStore.connectFrame(() => frameRef.current?.contentWindow ?? null), []);
1784
+ return { src, path, frameKey, frameRef, navigate };
1785
+ }
1786
+ function Rail({
1787
+ panel,
1788
+ onPanel,
1789
+ collapsed,
1790
+ onCollapsed,
1791
+ t
1792
+ }) {
1793
+ const tabs = [
1794
+ ["builder", t.builder, /* @__PURE__ */ jsx(HomeIcon, {}, "builder")],
1795
+ ["settings", t.settings, /* @__PURE__ */ jsx(PaletteIcon, {}, "settings")]
1796
+ ];
1797
+ const toggle = collapsed ? t.showPanel : t.hidePanel;
1798
+ return /* @__PURE__ */ jsxs("nav", { className: "te-rail", children: [
1799
+ /* @__PURE__ */ jsx(
1800
+ "button",
1801
+ {
1802
+ type: "button",
1803
+ "aria-expanded": !collapsed,
1804
+ "aria-controls": PANEL_ID,
1805
+ "aria-label": toggle,
1806
+ title: toggle,
1807
+ onClick: () => onCollapsed(!collapsed),
1808
+ children: /* @__PURE__ */ jsx(SidebarIcon, {})
1809
+ }
1810
+ ),
1811
+ /* @__PURE__ */ jsx("div", { className: "te-rail__tabs", role: "tablist", "aria-orientation": "vertical", children: tabs.map(([id, label, icon]) => /* @__PURE__ */ jsx(
1812
+ "button",
1813
+ {
1814
+ type: "button",
1815
+ role: "tab",
1816
+ "aria-selected": !collapsed && panel === id,
1817
+ "aria-controls": PANEL_ID,
1818
+ "aria-label": label,
1819
+ title: label,
1820
+ onClick: () => onPanel(id),
1821
+ children: icon
1822
+ },
1823
+ id
1824
+ )) })
1825
+ ] });
1826
+ }
1827
+ function SaveStatus({ t }) {
1828
+ const { saveStatus } = useDevEditorMeta();
1829
+ if (saveStatus === "idle") return null;
1830
+ const label = { saving: t.saving, saved: t.saved, error: t.saveError }[saveStatus];
1831
+ return /* @__PURE__ */ jsxs("span", { className: `te-status${saveStatus === "error" ? " te-status--error" : ""}`, role: "status", children: [
1832
+ /* @__PURE__ */ jsx("span", { className: "te-dot" }),
1833
+ label
1834
+ ] });
1835
+ }
1836
+ function TopBar({
1837
+ schema,
1838
+ t,
1839
+ locale,
1840
+ path,
1841
+ device,
1842
+ onDevice,
1843
+ onLocale,
1844
+ onReload
1845
+ }) {
1846
+ const store = useDevSettingsState();
1847
+ const themeName = pick(schema.themeName, locale) || "Theme";
1848
+ return /* @__PURE__ */ jsxs("header", { className: "te-top", children: [
1849
+ /* @__PURE__ */ jsxs("div", { className: "te-top__start", children: [
1850
+ /* @__PURE__ */ jsx("span", { className: "te-theme-name", children: themeName }),
1851
+ /* @__PURE__ */ jsx("span", { className: "te-badge", children: "Local" })
1852
+ ] }),
1853
+ /* @__PURE__ */ jsxs("div", { className: "te-segment", role: "group", "aria-label": `${t.mobile} / ${t.desktop}`, children: [
1854
+ /* @__PURE__ */ jsx(
1855
+ "button",
1856
+ {
1857
+ type: "button",
1858
+ "aria-label": t.mobile,
1859
+ "aria-pressed": device === "mobile",
1860
+ onClick: () => onDevice("mobile"),
1861
+ children: /* @__PURE__ */ jsx(PhoneIcon, {})
1862
+ }
1863
+ ),
1864
+ /* @__PURE__ */ jsx(
1865
+ "button",
1866
+ {
1867
+ type: "button",
1868
+ "aria-label": t.desktop,
1869
+ "aria-pressed": device === "desktop",
1870
+ onClick: () => onDevice("desktop"),
1871
+ children: /* @__PURE__ */ jsx(DesktopIcon, {})
1872
+ }
1873
+ )
1874
+ ] }),
1875
+ /* @__PURE__ */ jsxs("div", { className: "te-top__end", children: [
1876
+ /* @__PURE__ */ jsx(SaveStatus, { t }),
1877
+ /* @__PURE__ */ jsxs(
1878
+ "button",
1879
+ {
1880
+ type: "button",
1881
+ role: "switch",
1882
+ className: "te-switch",
1883
+ "aria-checked": store.enabled,
1884
+ onClick: () => store.enabled ? devSettingsStore.disable() : devSettingsStore.enable(schema),
1885
+ children: [
1886
+ /* @__PURE__ */ jsx("span", { className: "te-switch__track" }),
1887
+ t.preview
1888
+ ]
1889
+ }
1890
+ ),
1891
+ /* @__PURE__ */ jsx("div", { className: "te-segment te-segment--text", role: "group", "aria-label": t.language, children: ["ar", "en"].map((code) => /* @__PURE__ */ jsx(
1892
+ "button",
1893
+ {
1894
+ type: "button",
1895
+ "aria-pressed": locale === code,
1896
+ onClick: () => onLocale(code),
1897
+ children: code.toUpperCase()
1898
+ },
1899
+ code
1900
+ )) }),
1901
+ /* @__PURE__ */ jsx(
1902
+ "button",
1903
+ {
1904
+ type: "button",
1905
+ className: "te-icon-btn",
1906
+ "aria-label": t.reload,
1907
+ title: t.reload,
1908
+ onClick: onReload,
1909
+ children: /* @__PURE__ */ jsx(ReloadIcon, {})
1910
+ }
1911
+ ),
1912
+ /* @__PURE__ */ jsx(
1913
+ "a",
1914
+ {
1915
+ className: "te-icon-btn",
1916
+ href: standaloneHref(path),
1917
+ target: "_blank",
1918
+ rel: "noreferrer",
1919
+ "aria-label": t.openStorefront,
1920
+ title: t.openStorefront,
1921
+ children: /* @__PURE__ */ jsx(ExternalIcon, {})
1922
+ }
1923
+ )
1924
+ ] })
1925
+ ] });
1926
+ }
1927
+ function PreviewCanvas({
1928
+ frameRef,
1929
+ frameKey,
1930
+ src,
1931
+ device,
1932
+ title
1933
+ }) {
1934
+ return /* @__PURE__ */ jsx("main", { className: `te-canvas te-canvas--${device}`, children: /* @__PURE__ */ jsx(
1935
+ "iframe",
1936
+ {
1937
+ ref: frameRef,
1938
+ src,
1939
+ title,
1940
+ className: `te-frame te-frame--${device}`,
1941
+ onLoad: () => devSettingsStore.requestLiveBlocks(),
1942
+ ...{ [DEV_EDITOR_FRAME_ATTR]: "" }
1943
+ },
1944
+ frameKey
1945
+ ) });
1946
+ }
1947
+ function ThemeEditor({ schema, initialPath }) {
1948
+ const [panel, setPanel] = useState("builder");
1949
+ const [openId, setOpenId] = useState(null);
1950
+ const [adding, setAdding] = useState(false);
1951
+ const closeAdding = useCallback(() => setAdding(false), []);
1952
+ const [device, setDevice] = useState(readDevice);
1953
+ const [collapsed, setCollapsed] = usePanelCollapsed();
1954
+ const { src, path, frameKey, frameRef, navigate } = useFramePath(initialPath);
1955
+ const { frameBase } = useDevEditorMeta();
1956
+ const locale = localeOf(path, frameBase);
1957
+ const t = stringsFor(locale);
1958
+ useEffect(() => {
1959
+ document.documentElement.lang = locale;
1960
+ document.documentElement.dir = locale === "ar" ? "rtl" : "ltr";
1961
+ }, [locale]);
1962
+ useEffect(() => {
1963
+ try {
1964
+ window.localStorage.setItem(DEVICE_KEY, device);
1965
+ } catch {
1966
+ }
1967
+ }, [device]);
1968
+ return /* @__PURE__ */ jsxs("div", { className: "te-shell", children: [
1969
+ /* @__PURE__ */ jsx("style", { children: EDITOR_CSS }),
1970
+ /* @__PURE__ */ jsx(
1971
+ TopBar,
1972
+ {
1973
+ schema,
1974
+ t,
1975
+ locale,
1976
+ path,
1977
+ device,
1978
+ onDevice: setDevice,
1979
+ onLocale: (code) => navigate(withLocale(path, code, frameBase)),
1980
+ onReload: () => navigate(path)
1981
+ }
1982
+ ),
1983
+ /* @__PURE__ */ jsxs("div", { className: "te-body", children: [
1984
+ /* @__PURE__ */ jsx(
1985
+ Rail,
1986
+ {
1987
+ panel,
1988
+ onPanel: (next) => {
1989
+ setPanel(next);
1990
+ setCollapsed(false);
1991
+ setAdding(false);
1992
+ },
1993
+ collapsed,
1994
+ onCollapsed: (next) => {
1995
+ setCollapsed(next);
1996
+ setAdding(false);
1997
+ },
1998
+ t
1999
+ }
2000
+ ),
2001
+ /* @__PURE__ */ jsxs("aside", { id: PANEL_ID, className: "te-panel", role: "tabpanel", hidden: collapsed, children: [
2002
+ panel === "builder" ? /* @__PURE__ */ jsx(
2003
+ BuilderPanel,
2004
+ {
2005
+ schema,
2006
+ t,
2007
+ locale,
2008
+ isHome: isHomePath(path, frameBase),
2009
+ onGoHome: () => navigate(homeOf(path, frameBase)),
2010
+ openId,
2011
+ onOpenId: setOpenId,
2012
+ onAddElement: () => setAdding(true)
2013
+ }
2014
+ ) : /* @__PURE__ */ jsx(SettingsPanel, { schema, t }),
2015
+ /* @__PURE__ */ jsxs("div", { className: "te-panel__foot", children: [
2016
+ t.savedTo,
2017
+ " ",
2018
+ /* @__PURE__ */ jsx("code", { children: "twilight.preview.json" })
2019
+ ] })
2020
+ ] }),
2021
+ /* @__PURE__ */ jsx(
2022
+ PreviewCanvas,
2023
+ {
2024
+ frameRef,
2025
+ frameKey,
2026
+ src,
2027
+ device,
2028
+ title: pick(schema.themeName, locale) || "Storefront"
2029
+ }
2030
+ ),
2031
+ adding && panel === "builder" && /* @__PURE__ */ jsx(
2032
+ AddElementDrawer,
2033
+ {
2034
+ schema,
2035
+ t,
2036
+ locale,
2037
+ onClose: closeAdding,
2038
+ onPick: (componentPath) => {
2039
+ const at = devSettingsStore.get().layout?.length ?? 0;
2040
+ setOpenId(devSettingsStore.addBlock(schema, componentPath));
2041
+ devSettingsStore.focusBlock(at);
2042
+ setAdding(false);
2043
+ }
2044
+ }
2045
+ )
2046
+ ] })
2047
+ ] });
2048
+ }
2049
+ function mountThemeEditor(container, schema) {
2050
+ const root = createRoot(container);
2051
+ root.render(
2052
+ /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(ThemeEditor, { schema }) })
2053
+ );
2054
+ return () => root.unmount();
2055
+ }
2056
+
2057
+ export { ThemeEditor, mountThemeEditor };
2058
+ //# sourceMappingURL=index.js.map
2059
+ //# sourceMappingURL=index.js.map