@salla.sa/twilight-theme-engine 1.0.65 → 1.0.67

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 (202) hide show
  1. package/dist/{AddToCartForm-NKXOZ6TW.js → AddToCartForm-UVQG3BI5.js} +3 -3
  2. package/dist/{AddToCartForm-NKXOZ6TW.js.map → AddToCartForm-UVQG3BI5.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-GQPWTGT2.js → BlogAuthorPage-7HVGT3CS.js} +8 -8
  4. package/dist/{BlogAuthorPage-GQPWTGT2.js.map → BlogAuthorPage-7HVGT3CS.js.map} +1 -1
  5. package/dist/{BlogCategoryPage-LTSZDBIZ.js → BlogCategoryPage-MSITS6B3.js} +8 -8
  6. package/dist/{BlogCategoryPage-LTSZDBIZ.js.map → BlogCategoryPage-MSITS6B3.js.map} +1 -1
  7. package/dist/{BlogPage-QN7QL562.js → BlogPage-6FLWZBK3.js} +6 -6
  8. package/dist/{BlogPage-QN7QL562.js.map → BlogPage-6FLWZBK3.js.map} +1 -1
  9. package/dist/{BlogSinglePage-7GVVVVBL.js → BlogSinglePage-LSF5P4GA.js} +6 -6
  10. package/dist/{BlogSinglePage-7GVVVVBL.js.map → BlogSinglePage-LSF5P4GA.js.map} +1 -1
  11. package/dist/{BlogTagPage-QKYXFRET.js → BlogTagPage-JPOF3OC4.js} +8 -8
  12. package/dist/{BlogTagPage-QKYXFRET.js.map → BlogTagPage-JPOF3OC4.js.map} +1 -1
  13. package/dist/{BrandsPage-LF5NVBUE.js → BrandsPage-7G5VWJ2S.js} +7 -7
  14. package/dist/{BrandsPage-LF5NVBUE.js.map → BrandsPage-7G5VWJ2S.js.map} +1 -1
  15. package/dist/{Breadcrumb-E7KDHZX4.js → Breadcrumb-MNYKDV27.js} +6 -6
  16. package/dist/{Breadcrumb-E7KDHZX4.js.map → Breadcrumb-MNYKDV27.js.map} +1 -1
  17. package/dist/{CartItem-RB5CTJT6.js → CartItem-DNA2TJ6B.js} +6 -6
  18. package/dist/{CartItem-RB5CTJT6.js.map → CartItem-DNA2TJ6B.js.map} +1 -1
  19. package/dist/{CartSummary-JCYQ2SQD.js → CartSummary-RTDKJUV7.js} +6 -6
  20. package/dist/{CartSummary-JCYQ2SQD.js.map → CartSummary-RTDKJUV7.js.map} +1 -1
  21. package/dist/{Copyright-XXSKQ3TB.js → Copyright-IR4VD3I6.js} +3 -3
  22. package/dist/{Copyright-XXSKQ3TB.js.map → Copyright-IR4VD3I6.js.map} +1 -1
  23. package/dist/{CustomerLayout-CBFF4QEB.js → CustomerLayout-6YWOUFEN.js} +6 -6
  24. package/dist/{CustomerLayout-CBFF4QEB.js.map → CustomerLayout-6YWOUFEN.js.map} +1 -1
  25. package/dist/{Footer-NFN2EMI2.js → Footer-YQHS47HV.js} +6 -6
  26. package/dist/{Footer-NFN2EMI2.js.map → Footer-YQHS47HV.js.map} +1 -1
  27. package/dist/{Header-THQIZ2IR.js → Header-VEI2M3XJ.js} +5 -5
  28. package/dist/{Header-THQIZ2IR.js.map → Header-VEI2M3XJ.js.map} +1 -1
  29. package/dist/{LoyaltyPage-5SLR7TJX.js → LoyaltyPage-L7LABJWG.js} +6 -6
  30. package/dist/{LoyaltyPage-5SLR7TJX.js.map → LoyaltyPage-L7LABJWG.js.map} +1 -1
  31. package/dist/{LoyaltyPointsPage-HSXFTJUH.js → LoyaltyPointsPage-Z2GAMWCG.js} +3 -3
  32. package/dist/{LoyaltyPointsPage-HSXFTJUH.js.map → LoyaltyPointsPage-Z2GAMWCG.js.map} +1 -1
  33. package/dist/{MainMenu-7SVMOZ6P.js → MainMenu-76GBUVNZ.js} +3 -3
  34. package/dist/{MainMenu-7SVMOZ6P.js.map → MainMenu-76GBUVNZ.js.map} +1 -1
  35. package/dist/{MasterLayout-7IHDLNPZ.js → MasterLayout-GEQBU2MH.js} +6 -6
  36. package/dist/{MasterLayout-7IHDLNPZ.js.map → MasterLayout-GEQBU2MH.js.map} +1 -1
  37. package/dist/{MobileMenu-7HKRWQBQ.js → MobileMenu-DS5OJRCO.js} +6 -6
  38. package/dist/{MobileMenu-7HKRWQBQ.js.map → MobileMenu-DS5OJRCO.js.map} +1 -1
  39. package/dist/{NotificationsPage-4JX7GFXF.js → NotificationsPage-OT2WY2EF.js} +6 -6
  40. package/dist/{NotificationsPage-4JX7GFXF.js.map → NotificationsPage-OT2WY2EF.js.map} +1 -1
  41. package/dist/{OrderSinglePage-B7TBZ7TX.js → OrderSinglePage-XGPSBIA3.js} +7 -7
  42. package/dist/{OrderSinglePage-B7TBZ7TX.js.map → OrderSinglePage-XGPSBIA3.js.map} +1 -1
  43. package/dist/{OrdersPage-XZ2DAJYB.js → OrdersPage-A5TARKJ7.js} +6 -6
  44. package/dist/{OrdersPage-XZ2DAJYB.js.map → OrdersPage-A5TARKJ7.js.map} +1 -1
  45. package/dist/{PageSingle-QWT77P4S.js → PageSingle-VUNU2BG4.js} +3 -3
  46. package/dist/{PageSingle-QWT77P4S.js.map → PageSingle-VUNU2BG4.js.map} +1 -1
  47. package/dist/{ProductDetails-5IQHNQPS.js → ProductDetails-2JWKUXLI.js} +3 -3
  48. package/dist/{ProductDetails-5IQHNQPS.js.map → ProductDetails-2JWKUXLI.js.map} +1 -1
  49. package/dist/{ProfilePage-R2JDY6BF.js → ProfilePage-AVUCRBHQ.js} +6 -6
  50. package/dist/{ProfilePage-R2JDY6BF.js.map → ProfilePage-AVUCRBHQ.js.map} +1 -1
  51. package/dist/{SeoCartWidget-I2FBWKI4.js → SeoCartWidget-X5HTL62D.js} +6 -6
  52. package/dist/{SeoCartWidget-I2FBWKI4.js.map → SeoCartWidget-X5HTL62D.js.map} +1 -1
  53. package/dist/{SettingsPage-7X5YPAXL.js → SettingsPage-WGGKT3I4.js} +6 -6
  54. package/dist/{SettingsPage-7X5YPAXL.js.map → SettingsPage-WGGKT3I4.js.map} +1 -1
  55. package/dist/{StoreClosedNotification-5F4I3N27.js → StoreClosedNotification-XDYQO7JF.js} +7 -7
  56. package/dist/{StoreClosedNotification-5F4I3N27.js.map → StoreClosedNotification-XDYQO7JF.js.map} +1 -1
  57. package/dist/{TestimonialsPage-7YXSU33Z.js → TestimonialsPage-CKAYXFER.js} +3 -3
  58. package/dist/{TestimonialsPage-7YXSU33Z.js.map → TestimonialsPage-CKAYXFER.js.map} +1 -1
  59. package/dist/{ThankYouPage-7BN53JTK.js → ThankYouPage-ZTCFTEI7.js} +6 -6
  60. package/dist/{ThankYouPage-7BN53JTK.js.map → ThankYouPage-ZTCFTEI7.js.map} +1 -1
  61. package/dist/{WalletPage-JKXQSYPX.js → WalletPage-XKAOZIO2.js} +6 -6
  62. package/dist/{WalletPage-JKXQSYPX.js.map → WalletPage-XKAOZIO2.js.map} +1 -1
  63. package/dist/{WishlistPage-CSFHKERP.js → WishlistPage-LHIUUR4U.js} +8 -8
  64. package/dist/{WishlistPage-CSFHKERP.js.map → WishlistPage-LHIUUR4U.js.map} +1 -1
  65. package/dist/api/brands.js +2 -2
  66. package/dist/api/cart.js +2 -2
  67. package/dist/api/category.js +2 -2
  68. package/dist/api/home.d.ts +13 -0
  69. package/dist/api/home.d.ts.map +1 -1
  70. package/dist/api/home.js +1 -1
  71. package/dist/api/loyalty.js +2 -2
  72. package/dist/api/order.js +2 -2
  73. package/dist/api/page.js +2 -2
  74. package/dist/api/product.js +2 -2
  75. package/dist/api/wishlist.js +3 -3
  76. package/dist/{chunk-D5UIBY3V.js → chunk-3L5VG2X4.js} +3 -3
  77. package/dist/{chunk-D5UIBY3V.js.map → chunk-3L5VG2X4.js.map} +1 -1
  78. package/dist/{chunk-UEKIAED3.js → chunk-3Q22KK7C.js} +6 -6
  79. package/dist/{chunk-UEKIAED3.js.map → chunk-3Q22KK7C.js.map} +1 -1
  80. package/dist/{chunk-24QOBDMC.js → chunk-4YWBXQV5.js} +8 -4
  81. package/dist/chunk-4YWBXQV5.js.map +1 -0
  82. package/dist/{chunk-2QNDO2OY.js → chunk-6IRWFBGU.js} +3 -3
  83. package/dist/{chunk-2QNDO2OY.js.map → chunk-6IRWFBGU.js.map} +1 -1
  84. package/dist/{chunk-2BRCE7MK.js → chunk-A4UQKSOU.js} +4 -4
  85. package/dist/{chunk-2BRCE7MK.js.map → chunk-A4UQKSOU.js.map} +1 -1
  86. package/dist/{chunk-ZBARSETM.js → chunk-EFMAB636.js} +3 -3
  87. package/dist/{chunk-ZBARSETM.js.map → chunk-EFMAB636.js.map} +1 -1
  88. package/dist/{chunk-43XFO6KF.js → chunk-EYFMLMMF.js} +3 -3
  89. package/dist/{chunk-43XFO6KF.js.map → chunk-EYFMLMMF.js.map} +1 -1
  90. package/dist/{chunk-FY573DJA.js → chunk-FAVZMJRY.js} +6 -6
  91. package/dist/{chunk-FY573DJA.js.map → chunk-FAVZMJRY.js.map} +1 -1
  92. package/dist/{chunk-RWTZH6G3.js → chunk-FRFTO2HP.js} +6 -6
  93. package/dist/{chunk-RWTZH6G3.js.map → chunk-FRFTO2HP.js.map} +1 -1
  94. package/dist/{chunk-65JM62NV.js → chunk-FTM3RIVB.js} +4 -4
  95. package/dist/{chunk-65JM62NV.js.map → chunk-FTM3RIVB.js.map} +1 -1
  96. package/dist/{chunk-OJPJP7ML.js → chunk-GNH3W6T4.js} +4 -4
  97. package/dist/chunk-GNH3W6T4.js.map +1 -0
  98. package/dist/{chunk-GXDBY4WB.js → chunk-GYXT7T2Z.js} +3 -3
  99. package/dist/{chunk-GXDBY4WB.js.map → chunk-GYXT7T2Z.js.map} +1 -1
  100. package/dist/{chunk-QYUYQPXN.js → chunk-HDO37URJ.js} +3 -3
  101. package/dist/{chunk-QYUYQPXN.js.map → chunk-HDO37URJ.js.map} +1 -1
  102. package/dist/{chunk-P6DV6EHM.js → chunk-RH5VLLTG.js} +3 -3
  103. package/dist/{chunk-P6DV6EHM.js.map → chunk-RH5VLLTG.js.map} +1 -1
  104. package/dist/{chunk-WF7DYPR6.js → chunk-SOPZ72BU.js} +3 -3
  105. package/dist/{chunk-WF7DYPR6.js.map → chunk-SOPZ72BU.js.map} +1 -1
  106. package/dist/{chunk-KBQXQKPZ.js → chunk-SSPAMQRV.js} +2 -2
  107. package/dist/chunk-SSPAMQRV.js.map +1 -0
  108. package/dist/chunk-TFROBJP5.js +14 -0
  109. package/dist/{chunk-XMZPFHE7.js.map → chunk-TFROBJP5.js.map} +1 -1
  110. package/dist/{chunk-A6SKDX5E.js → chunk-TOPFB6FL.js} +3 -3
  111. package/dist/{chunk-A6SKDX5E.js.map → chunk-TOPFB6FL.js.map} +1 -1
  112. package/dist/{chunk-55VTMG2H.js → chunk-UEQFXSTX.js} +21 -11
  113. package/dist/chunk-UEQFXSTX.js.map +1 -0
  114. package/dist/{chunk-6AV7RQ6H.js → chunk-VAW73MFZ.js} +23 -8
  115. package/dist/chunk-VAW73MFZ.js.map +1 -0
  116. package/dist/{chunk-347K33DP.js → chunk-VGIK4BW6.js} +4 -4
  117. package/dist/{chunk-347K33DP.js.map → chunk-VGIK4BW6.js.map} +1 -1
  118. package/dist/{chunk-EBMMJWX6.js → chunk-VI5R46KX.js} +7 -7
  119. package/dist/{chunk-EBMMJWX6.js.map → chunk-VI5R46KX.js.map} +1 -1
  120. package/dist/{chunk-PDMVQCEV.js → chunk-VKB5AQUS.js} +3 -3
  121. package/dist/{chunk-PDMVQCEV.js.map → chunk-VKB5AQUS.js.map} +1 -1
  122. package/dist/{chunk-GRV7ELSP.js → chunk-W5K6YUA2.js} +19 -10
  123. package/dist/chunk-W5K6YUA2.js.map +1 -0
  124. package/dist/chunk-Y43T7PJV.js +48 -0
  125. package/dist/chunk-Y43T7PJV.js.map +1 -0
  126. package/dist/components/cart/index.js +1 -1
  127. package/dist/components/common/index.js +1 -1
  128. package/dist/components/drawer/index.js +4 -4
  129. package/dist/components/home/HomePageRenderer.d.ts +5 -1
  130. package/dist/components/home/HomePageRenderer.d.ts.map +1 -1
  131. package/dist/components/home/PageBlocks.d.ts +10 -0
  132. package/dist/components/home/PageBlocks.d.ts.map +1 -0
  133. package/dist/components/home/index.d.ts +2 -0
  134. package/dist/components/home/index.d.ts.map +1 -1
  135. package/dist/components/home/index.js +8 -7
  136. package/dist/components/layout/index.js +1 -1
  137. package/dist/components/product/index.js +5 -5
  138. package/dist/components/store/index.js +6 -6
  139. package/dist/{document-class-ZLPAWZEX.js → document-class-SPTMBRWL.js} +5 -5
  140. package/dist/{document-class-ZLPAWZEX.js.map → document-class-SPTMBRWL.js.map} +1 -1
  141. package/dist/dom/edge.d.ts +3 -0
  142. package/dist/dom/edge.d.ts.map +1 -0
  143. package/dist/dom/index.d.ts +1 -0
  144. package/dist/dom/index.d.ts.map +1 -1
  145. package/dist/dom.js +8 -1
  146. package/dist/dom.js.map +1 -1
  147. package/dist/hooks/index.js +4 -4
  148. package/dist/hooks/useGtm.js +4 -4
  149. package/dist/hooks/useMoney.js +4 -4
  150. package/dist/hooks/useStore.js +4 -4
  151. package/dist/index.js +4 -4
  152. package/dist/{navigation-DU3BF72V.js → navigation-CJHPA74M.js} +3 -3
  153. package/dist/{navigation-DU3BF72V.js.map → navigation-CJHPA74M.js.map} +1 -1
  154. package/dist/{navigation-WB75NC6Y.js → navigation-F2TD5X2P.js} +4 -4
  155. package/dist/{navigation-WB75NC6Y.js.map → navigation-F2TD5X2P.js.map} +1 -1
  156. package/dist/{not-found-MA54AXJB.js → not-found-T2WYF64G.js} +7 -7
  157. package/dist/{not-found-MA54AXJB.js.map → not-found-T2WYF64G.js.map} +1 -1
  158. package/dist/providers/NavigationProvider.d.ts +8 -9
  159. package/dist/providers/NavigationProvider.d.ts.map +1 -1
  160. package/dist/providers/index.js +4 -4
  161. package/dist/providers/twilight-init.d.ts.map +1 -1
  162. package/dist/routes/account/orders.js +3 -3
  163. package/dist/routes/account.js +10 -10
  164. package/dist/routes/blog.js +7 -7
  165. package/dist/routes/brands.js +3 -3
  166. package/dist/routes/cart.js +12 -12
  167. package/dist/routes/home.js +9 -9
  168. package/dist/routes/index.js +2 -2
  169. package/dist/routes/loyalty.js +4 -4
  170. package/dist/routes/page.js +3 -3
  171. package/dist/routes/product-listing.js +10 -9
  172. package/dist/routes/product-listing.js.map +1 -1
  173. package/dist/routes/product.js +8 -7
  174. package/dist/routes/product.js.map +1 -1
  175. package/dist/routes/seo-redirects.d.ts +7 -0
  176. package/dist/routes/seo-redirects.d.ts.map +1 -1
  177. package/dist/routes/seo-redirects.js +2 -2
  178. package/dist/routes/testimonials.js +1 -1
  179. package/dist/routes/thank-you.js +3 -3
  180. package/dist/skeleton.js +9 -9
  181. package/dist/tanstack/middleware/earlyHints.d.ts.map +1 -1
  182. package/dist/tanstack/router.d.ts.map +1 -1
  183. package/dist/tanstack/search.d.ts +3 -0
  184. package/dist/tanstack/search.d.ts.map +1 -0
  185. package/dist/tanstack/templates/locale-wrapper.d.ts.map +1 -1
  186. package/dist/tanstack.js +6 -7
  187. package/dist/tanstack.js.map +1 -1
  188. package/dist/types/index.d.ts +2 -0
  189. package/dist/types/index.d.ts.map +1 -1
  190. package/dist/vite/adapters/tanstack.adapter.d.ts.map +1 -1
  191. package/dist/vite/index.js +62 -3
  192. package/dist/vite/index.js.map +1 -1
  193. package/package.json +1 -1
  194. package/dist/chunk-24QOBDMC.js.map +0 -1
  195. package/dist/chunk-55VTMG2H.js.map +0 -1
  196. package/dist/chunk-6AV7RQ6H.js.map +0 -1
  197. package/dist/chunk-GRV7ELSP.js.map +0 -1
  198. package/dist/chunk-KBQXQKPZ.js.map +0 -1
  199. package/dist/chunk-NQVJ7NJ6.js +0 -19
  200. package/dist/chunk-NQVJ7NJ6.js.map +0 -1
  201. package/dist/chunk-OJPJP7ML.js.map +0 -1
  202. package/dist/chunk-XMZPFHE7.js +0 -14
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/product-listing/loader.ts","../../src/routes/product-listing/useAppliedFilters.ts","../../src/routes/product-listing/ProductListPage.tsx","../../src/routes/product-listing/index.tsx"],"names":["i18n","useState","brand","useEffect","useCallback","category"],"mappings":"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","file":"product-listing.js","sourcesContent":["import type { ProductListLoaderData, ProductListLoaderContext, ProductListSource } from './types';\nimport type { ProductsListSource } from '../../api/product';\nimport { category } from '../../api/category';\nimport { product } from '../../api/product';\nimport { brand } from '../../api/brands';\nimport { notFound } from '../../providers/NavigationProvider';\nimport { getTwilightContext } from '../../twilight/context';\nimport { RouteId } from '../../router/route-ids';\n\nconst DEFAULT_SORT = 'ourSuggest';\n\nconst SOURCE_TO_API: Record<ProductListSource, ProductsListSource> = {\n categories: 'categories',\n latest: 'latest',\n sales: 'sales',\n offers: 'offers',\n search: 'search',\n tags: 'tags',\n brands: 'brands',\n};\n\nconst SOURCE_TITLE_KEY: Record<'latest' | 'sales' | 'offers', string> = {\n latest: 'blocks.home.latest_products',\n sales: 'common.titles.most_sales',\n offers: 'common.titles.discounts',\n};\n\nconst SOURCE_SLUG: Record<'latest' | 'sales' | 'offers', string> = {\n latest: 'latest-products',\n sales: 'most-sales-products',\n offers: 'offers',\n};\n\nexport async function productListLoader(\n ctx: ProductListLoaderContext\n): Promise<ProductListLoaderData> {\n const { params, search } = ctx;\n const cursor = search?.page ? String(search.page) : undefined;\n const sort = search?.sort ?? DEFAULT_SORT;\n\n const sourceType = params.source ?? (params.id ? 'categories' : undefined);\n\n if (!sourceType) {\n throw new Error('ProductList loader requires source type');\n }\n\n if (sourceType === 'categories' && params.id) {\n return loadCategoryProducts(params.id, cursor, sort);\n }\n\n if (sourceType === 'search') {\n const keyword = (search?.q ?? params.keyword ?? '').trim();\n return loadSearchProducts(keyword, cursor, sort);\n }\n\n if (sourceType === 'tags' && params.id) {\n return loadTagProducts(params.id, cursor, sort);\n }\n\n if (sourceType === 'brands' && params.id) {\n return loadBrandProducts(params.id, cursor, sort);\n }\n\n if (sourceType === 'latest' || sourceType === 'sales' || sourceType === 'offers') {\n return loadStaticProducts(\n sourceType as 'latest' | 'sales' | 'offers',\n params.title ?? '',\n params.slug ?? '',\n cursor,\n sort\n );\n }\n\n throw new Error(`Unknown source type: ${sourceType}`);\n}\n\n// ============================================================================\n// Source-Specific Loaders\n// ============================================================================\n\nasync function loadCategoryProducts(\n id: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n let categoryData, productsResult;\n try {\n [categoryData, productsResult] = await Promise.all([\n queryClient.fetchQuery(category.queries.detail(id)),\n queryClient.fetchQuery(\n product.queries.list({\n source: 'categories',\n sourceValue: id,\n cursor,\n sort,\n filterable: true,\n })\n ),\n ]);\n } catch {\n throw notFound();\n }\n\n if (!categoryData) throw notFound();\n\n return {\n page: {\n slug: RouteId.PRODUCT_INDEX,\n id,\n title: categoryData.name,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: categoryData.name, url: categoryData.url },\n ],\n },\n source: { type: 'categories', value: id, entity: categoryData },\n query: { sort, filters: true },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n filters: productsResult.filters,\n };\n}\n\nasync function loadSearchProducts(\n keyword: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n if (!keyword) {\n const { i18n } = getTwilightContext();\n return {\n page: {\n slug: RouteId.SEARCH,\n title: i18n.t('pages.products.search_result'),\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: i18n.t('pages.products.search_result'), url: '/search' },\n ],\n },\n source: { type: 'search', value: '' },\n query: { sort, filters: true },\n products: [],\n pagination: { next: null },\n };\n }\n\n const { queryClient, i18n } = getTwilightContext();\n const productsResult = await queryClient.fetchQuery(\n product.queries.list({\n source: 'search',\n sourceValue: keyword,\n cursor,\n sort,\n filterable: true,\n })\n );\n\n return {\n page: {\n slug: RouteId.SEARCH,\n title: i18n.t('common.elements.search_about').replace(':word', keyword),\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: keyword, url: '/search' },\n ],\n },\n source: { type: 'search', value: keyword },\n query: { sort, filters: true },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n filters: productsResult.filters,\n };\n}\n\nasync function loadTagProducts(\n id: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n const productsResult = await queryClient.fetchQuery(\n product.queries.list({\n source: 'tags',\n sourceValue: id,\n cursor,\n sort,\n })\n );\n\n const tagFromProduct = productsResult.items[0]?.tags?.find((t) => String(t.id) === id);\n if (!tagFromProduct) throw notFound();\n\n const tag = { id: Number(tagFromProduct.id), name: tagFromProduct.name, url: tagFromProduct.url };\n\n return {\n page: {\n slug: RouteId.PRODUCT_INDEX_TAG,\n id,\n title: tag.name,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: tag.name, url: tag.url },\n ],\n },\n source: { type: 'tags', value: id, entity: tag },\n query: { sort, filters: false },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n };\n}\n\nasync function loadBrandProducts(\n id: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n let brandData, productsResult;\n try {\n [brandData, productsResult] = await Promise.all([\n queryClient.fetchQuery(brand.queries.detail(id)),\n queryClient.fetchQuery(\n product.queries.list({\n source: 'brands',\n sourceValue: id,\n cursor,\n sort,\n })\n ),\n ]);\n } catch {\n throw notFound();\n }\n\n if (!brandData) throw notFound();\n\n return {\n page: {\n slug: RouteId.BRANDS_INDEX,\n id,\n title: brandData.name,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n // The brand API sends no url.\n { name: brandData.name, url: `/brands/${id}` },\n ],\n },\n source: { type: 'brands', value: id, entity: brandData },\n query: { sort, filters: false },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n };\n}\n\nconst SOURCE_ROUTE_ID: Record<'latest' | 'sales' | 'offers', string> = {\n latest: RouteId.PRODUCT_INDEX_LATEST,\n sales: RouteId.PRODUCT_INDEX_SALES,\n offers: RouteId.PRODUCT_INDEX_OFFERS,\n};\n\nasync function loadStaticProducts(\n source: 'latest' | 'sales' | 'offers',\n title: string,\n slug: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n const resolvedTitle = title || i18n.t(SOURCE_TITLE_KEY[source]);\n const resolvedSlug = slug || SOURCE_SLUG[source];\n const productsResult = await queryClient.fetchQuery(\n product.queries.list({\n source: SOURCE_TO_API[source],\n cursor,\n sort,\n })\n );\n\n return {\n page: {\n slug: SOURCE_ROUTE_ID[source],\n title: resolvedTitle,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: resolvedTitle, url: `/${resolvedSlug}` },\n ],\n },\n source: { type: source },\n query: { sort, filters: false },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { product } from '../../api/product';\nimport type { ProductListFilters } from '../../api/product';\nimport type { Product } from '../../types';\nimport type { ProductListLoaderData } from './types';\n\ntype Source = ProductListLoaderData['source'];\ntype Node = Record<string, unknown>;\n\n/** Path segments that would reach the shared prototype chain if used as object keys. */\nconst UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/**\n * Reads the `filters[...]` selection `<salla-filters>` writes to the address bar\n * (`filters[k]=v`, `filters[k][]=v`, `filters[k][sub]=v`) back into an object, so a\n * filtered link can be opened directly.\n *\n * The keys come straight from the URL, so nodes are null-prototype objects and any\n * `__proto__` / `constructor` / `prototype` segment drops the whole entry — a crafted\n * `?filters[__proto__][x]=1` must never reach `Object.prototype`.\n */\nexport function parseFiltersFromSearch(search: string): ProductListFilters | null {\n const out: Node = Object.create(null);\n new URLSearchParams(search).forEach((value, rawKey) => {\n if (!rawKey.startsWith('filters[')) return;\n const path = [...rawKey.matchAll(/\\[([^\\]]*)\\]/g)].map((m) => m[1]);\n const isList = path[path.length - 1] === '';\n const keys = isList ? path.slice(0, -1) : path;\n if (!keys.length || keys.includes('') || keys.some((key) => UNSAFE_KEYS.has(key))) return;\n\n let node = out;\n keys.slice(0, -1).forEach((key) => {\n const existing = node[key];\n if (typeof existing !== 'object' || existing === null || Array.isArray(existing)) {\n node[key] = Object.create(null);\n }\n node = node[key] as Node;\n });\n const leaf = keys[keys.length - 1];\n if (isList) {\n node[leaf] = [...(Array.isArray(node[leaf]) ? (node[leaf] as string[]) : []), value];\n } else {\n node[leaf] = value;\n }\n });\n return Object.keys(out).length ? (out as ProductListFilters) : null;\n}\n\ninterface FilteredPage {\n items: Product[];\n next: string | null;\n}\n\nexport type AppliedFiltersStatus = 'idle' | 'loading' | 'ready' | 'error';\n\n/**\n * Applies the `<salla-filters>` selection to the product list.\n *\n * The filters component only rewrites the address bar (`history.pushState`, invisible\n * to the router) and emits `salla-filters::changed`; nothing re-queries the list, so\n * the route's loader output — fetched without filters — kept showing. This listens\n * for that event (and for a filtered URL on first load) and fetches the first page\n * with the selection.\n *\n * Each fetched page is stored with the selection that produced it, so `page` is only\n * ever the page for the *current* selection. Until it arrives `status` is `loading`\n * (and `lastPage` is the previous selection's page, for a dimmed placeholder); if the\n * request fails `status` is `error` and `retry` re-runs it — the old products never\n * pass for the new selection.\n */\nexport function useAppliedFilters(\n source: Source,\n sort: string,\n enabled: boolean\n): {\n filters: ProductListFilters | null;\n page: FilteredPage | null;\n lastPage: FilteredPage | null;\n status: AppliedFiltersStatus;\n retry: () => void;\n} {\n const [filters, setFilters] = useState<ProductListFilters | null>(null);\n const [result, setResult] = useState<{ key: string; page: FilteredPage } | null>(null);\n const [failedKey, setFailedKey] = useState<string | null>(null);\n const [attempt, setAttempt] = useState(0);\n\n useEffect(() => {\n if (!enabled) return;\n setFilters(parseFiltersFromSearch(window.location.search));\n const sdk = window.salla;\n if (!sdk?.event) return;\n const onChanged = (...args: unknown[]) => {\n const next = args[0] as ProductListFilters | undefined;\n setFilters(next && Object.keys(next).length ? { ...next } : null);\n };\n sdk.event.on('salla-filters::changed', onChanged);\n return () => sdk.event.off('salla-filters::changed', onChanged);\n }, [enabled, source.type, source.value]);\n\n const key = filters ? JSON.stringify([source.type, source.value, sort, filters]) : '';\n\n useEffect(() => {\n if (!filters) return;\n const controller = new AbortController();\n setFailedKey(null);\n product\n .list({\n source: source.type,\n sourceValue: source.value,\n sort,\n filterable: true,\n filters,\n signal: controller.signal,\n })\n .then((res) => setResult({ key, page: { items: res.items, next: res.next } }))\n .catch(() => {\n // Aborted by a newer selection (its own effect run owns the state now), or failed.\n if (!controller.signal.aborted) setFailedKey(key);\n });\n return () => controller.abort();\n // `key` already encodes filters + source + sort.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, attempt]);\n\n const retry = useCallback(() => setAttempt((n) => n + 1), []);\n\n if (!filters) return { filters: null, page: null, lastPage: null, status: 'idle', retry };\n\n const page = result?.key === key ? result.page : null;\n const status: AppliedFiltersStatus = page ? 'ready' : failedKey === key ? 'error' : 'loading';\n return { filters, page, lastPage: result?.page ?? null, status, retry };\n}\n","import { useState, useRef, useEffect, useMemo, useCallback } from 'react';\nimport { HookSlot, useStore } from '../../hooks';\nimport { useTranslation } from '../../providers/I18nProvider';\nimport { useNavigate, useLocation } from '../../providers/NavigationProvider';\nimport { useTwilight } from '../../providers/TwilightProvider';\nimport { sortOptions } from '../../utils/sort-options';\nimport { Drawer } from '../../components/drawer';\nimport { Breadcrumb } from '../../components/common';\nimport { SallaFilters } from '@salla.sa/twilight-components-react/filters';\nimport { ItemsList, ReviewItemSkeleton } from '@salla.sa/twilight-components-react';\nimport { Testimonials } from '../../components/home';\nimport { ProductCard } from '../../components/product';\nimport { NoContent, ProductCardSkeleton, Image, RenderWhenVisible } from '../../components/common';\nimport { product } from '../../api/product';\nimport { useAppliedFilters } from './useAppliedFilters';\nimport type { ProductListLoaderData } from './types';\nimport type { Brand } from '../brands/types';\nimport type { Product } from '../../types';\n\n/** 3-col + 288px sidebar from md; 3-col of the full container below md. */\nconst FILTERED_PRODUCT_IMAGE_SIZES = '(min-width: 768px) 25vw, 33vw';\n\n/**\n * Product List Page - Unified component for all product listing pages\n *\n * Handles:\n * - Category pages (with filters, category entity, testimonials)\n * - Search pages (keyword display, product count)\n * - Tag pages (tag entity)\n * - Brand pages (brand entity with banner/logo)\n * - Static listings (latest, sales, offers)\n */\nexport function ProductListPage({\n page,\n source,\n query,\n products,\n pagination,\n filters,\n}: ProductListLoaderData) {\n const { t } = useTranslation();\n const store = useStore();\n const { theme } = useTwilight();\n const navigate = useNavigate();\n // Sort is now SSR-driven, no local state needed\n const selectedSort = query.sort;\n const [filtersOpen, setFiltersOpen] = useState(false);\n\n // Determine filters visibility\n const showFilters = query.filters && store?.settings?.product?.filters;\n // const isSearch = source.type === 'search';\n const isBrand = source.type === 'brands';\n const brand = isBrand ? (source.entity as Brand | undefined) : null;\n\n // Generate sort options with translations\n const sortOptionsWithTrans = useMemo(() => sortOptions(selectedSort, t), [selectedSort, t]);\n\n // Get location from hook for consistent URL handling\n const location = useLocation();\n\n // Re-query the list with the selection made in `<salla-filters>`: the component only\n // rewrites the address bar and emits `salla-filters::changed`, and the route's loader\n // output was fetched without it.\n const {\n filters: appliedFilters,\n page: filteredPage,\n lastPage,\n status: filterStatus,\n retry: retryFilters,\n } = useAppliedFilters(source, selectedSort, !!showFilters);\n // While the new selection loads, the previous page stays up (dimmed, `aria-busy`); if\n // the request fails nothing stale passes for the new selection. Infinite scroll is only\n // live for the loader's own page or a fully loaded filtered one.\n const shownPage = filterStatus === 'ready' ? filteredPage : lastPage;\n const shownProducts =\n filterStatus === 'error'\n ? []\n : filterStatus === 'idle'\n ? products\n : (shownPage?.items ?? products);\n const shownNext =\n filterStatus === 'idle'\n ? pagination?.next\n : filterStatus === 'ready'\n ? filteredPage?.next\n : null;\n const filteredKey =\n filterStatus === 'idle'\n ? ''\n : `-${filterStatus}${filterStatus === 'ready' ? JSON.stringify(appliedFilters) : ''}`;\n\n // Listen for filters changed event to close drawer\n useEffect(() => {\n const handleFiltersChanged = () => setFiltersOpen(false);\n const sdk = window.salla;\n if (typeof sdk === 'undefined') return;\n\n sdk.event.on('salla-filters::changed', handleFiltersChanged);\n\n return () => {\n sdk.event.off('salla-filters::changed', handleFiltersChanged);\n };\n }, []);\n\n // Handle sort change - use client-side navigation to trigger route loader re-run\n const handleSortChange = useCallback(\n (event: React.ChangeEvent<HTMLSelectElement>) => {\n const newSort = event.target.value;\n\n const params = new URLSearchParams(location.searchStr);\n params.set('sort', newSort);\n params.delete('page'); // clear any cursor token from URL on sort change\n\n // Use client-side navigation to trigger route loader re-execution (SSR-like).\n // Built from the router's location rather than `window.location`: on a host\n // where the store is the root, the address bar carries the store segment and\n // `navigate` would add it a second time.\n navigate(`${location.pathname}?${params.toString()}`);\n },\n [navigate, location.pathname, location.searchStr]\n );\n\n // Key for remounting products list\n const listKey = source.value ?? source.type;\n\n // Track cursor for the next page — initialized from SSR pagination response.\n // On sort change the key prop remounts ItemsList and this effect resets the cursor.\n const nextCursorRef = useRef<string | null>(shownNext ?? null);\n useEffect(() => {\n nextCursorRef.current = shownNext ?? null;\n }, [shownNext]);\n\n const loader = useCallback(async () => {\n const nextUrl = nextCursorRef.current;\n // Extract the cursor token from the next URL provided by the previous response\n const cursorMatch = nextUrl?.match(/[?&]cursor=([^&]+)/);\n const cursor = cursorMatch ? decodeURIComponent(cursorMatch[1]) : (nextUrl ?? undefined);\n\n const result = await product.list({\n source: source.type,\n sourceValue: source.value,\n ...(cursor && { cursor }),\n sort: selectedSort,\n ...(appliedFilters && { filterable: true, filters: appliedFilters }),\n });\n\n nextCursorRef.current = result.next;\n\n return result;\n }, [source.type, source.value, selectedSort, appliedFilters]);\n\n return (\n <div key={listKey} className=\"container px-2.5 ms:px-5 mb-10\">\n {theme?.settings?.product_index_show_breadcrumbs !== false && <Breadcrumb page={page} />}\n\n {isBrand && brand && (\n <>\n <Image\n width={1200}\n height={300}\n className=\"w-full max-h-[300px] object-cover rounded-md bg-gray-100\"\n src={brand.banner || undefined}\n alt={brand.name}\n priority\n />\n <header className=\"flex flex-col md:flex-row items-center md:items-start text-center rtl:md:text-right ltr:md:text-left mt-2 mb-8\">\n <Image\n className=\"rounded-md w-40 h-24 object-contain shadow-md p-4 bg-white shrink-0\"\n src={brand.logo || undefined}\n alt={brand.name}\n aspectRatio=\"5/3\"\n />\n <div className=\"px-5 pt-3 rtl:text-right\">\n <h1 className=\"text-2xl font-bold mb-1\">{brand.name}</h1>\n {brand.description && (\n <p\n className=\"text-base text-gray-500 font-medium\"\n dangerouslySetInnerHTML={{ __html: brand.description }}\n />\n )}\n </div>\n </header>\n </>\n )}\n\n <HookSlot name=\"product:list.start\" />\n\n <div className={showFilters ? 'md:grid md:grid-cols-[288px_1fr] gap-8' : ''}>\n {/* <FiltersSkeleton></FiltersSkeleton> */}\n {showFilters && (\n <SallaFilters\n id=\"filters-menu\"\n className=\"hidden md:block lg:sticky lg:top-20\"\n filters={filters as any}\n />\n )}\n\n <div className=\"min-w-0\">\n <div className=\"mb-4 sm:mb-6 flex justify-between items-center\">\n <h1 className=\"font-bold text-xl rtl:pl-3 ltr:pr-3\" id=\"page-main-title\">\n {isBrand ? t('common.titles.products') : page.title}\n </h1>\n\n <div className=\"flex items-center space-x-2 rtl:space-x-reverse\">\n {showFilters && (\n <button\n type=\"button\"\n onClick={() => setFiltersOpen(true)}\n className=\"filters-trigger bg-border-color text-primary lg:hidden p-2 rounded\"\n >\n <i className=\"sicon-filter text-gray-text text-2xl\" />\n </button>\n )}\n\n {sortOptionsWithTrans.length > 0 && (\n <div className=\"flex items-center\">\n <label\n className=\"hidden sm:block rtl:ml-3 ltr:mr-3 whitespace-nowrap\"\n htmlFor=\"product-sort\"\n >\n {t('pages.categories.sorting', 'Sort By')}\n </label>\n <select\n id=\"product-sort\"\n className=\"form-input pt-0 pb-1 rtl:md:pl-10 ltr:md:pr-10\"\n value={selectedSort}\n onChange={handleSortChange}\n >\n {sortOptionsWithTrans.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n </div>\n )}\n </div>\n </div>\n\n <HookSlot name=\"product:list.items.start\" />\n\n <div\n className={`flex min-h-screen${filterStatus === 'loading' ? ' opacity-60' : ''}`}\n aria-busy={filterStatus === 'loading'}\n >\n {filterStatus === 'error' ? (\n <div className=\"flex-1 min-w-0 flex flex-col items-center\">\n <NoContent\n icon=\"sicon-shopping-bag\"\n message={t('common.errors.error_occurred', 'Something went wrong')}\n />\n <button type=\"button\" className=\"link--primary mt-4\" onClick={retryFilters}>\n {t('common.elements.try_again', 'Try again')}\n </button>\n </div>\n ) : (\n <ItemsList<Product>\n key={`${listKey}-${selectedSort}${filteredKey}`}\n resetKey={`${listKey}-${selectedSort}${filteredKey}`}\n items={shownProducts}\n loader={loader}\n mode={shownNext ? 'infinite' : 'static'}\n pageUrl={location.pathname + location.searchStr}\n className=\"s-products-list flex-1 min-w-0\"\n itemsClassName={`s-products-list-wrapper s-products-list-vertical-cards${showFilters ? ' s-products-list-with-filters' : ''}`}\n skeleton={<ProductCardSkeleton />}\n skeletonType=\"item\"\n skeletonCount={12}\n empty={\n <NoContent\n icon=\"sicon-shopping-bag\"\n message={t(\n 'pages.categories.no_products',\n 'No products found in this category'\n )}\n />\n }\n t={(key, fallback) => t(key, fallback || key)}\n >\n {(items) =>\n items.map((prod, idx) => (\n <ProductCard\n key={prod.id}\n product={prod}\n index={idx}\n sizes={showFilters ? FILTERED_PRODUCT_IMAGE_SIZES : undefined}\n />\n ))\n }\n </ItemsList>\n )}\n </div>\n\n <HookSlot name=\"product:list.items.end\" />\n </div>\n </div>\n\n {showFilters && (\n <Drawer isOpen={filtersOpen} onClose={() => setFiltersOpen(false)} size=\"md\">\n <div className=\"p-4\">\n <div className=\"flex justify-between items-center mb-4\">\n <h3 className=\"font-bold text-lg\">{t('pages.categories.filters', 'Filters')}</h3>\n <button\n type=\"button\"\n onClick={() => setFiltersOpen(false)}\n className=\"btn--close-sm sicon-cancel text-gray-500\"\n />\n </div>\n <SallaFilters id=\"filters-menu-mobile\" filters={filters as any} />\n </div>\n </Drawer>\n )}\n\n {source.type === 'categories' && store?.settings?.category?.testimonial_enabled && (\n <RenderWhenVisible placeholder={<ReviewItemSkeleton />}>\n <Testimonials data={{}} />\n </RenderWhenVisible>\n )}\n\n <HookSlot name=\"product:list.end\" />\n </div>\n );\n}\n","import type { HeadDescriptor } from '../../utils/head';\nimport { buildHreflangAlternates } from '../../utils/baseHead';\nimport { productListLoader } from './loader';\nimport type { ProductListLoaderData, ProductListTag, Category } from './types';\nimport type { TwilightContext } from '../../twilight/context';\nimport { RouteId } from '../../router/route-ids';\nimport { ProductListPage } from './ProductListPage';\n\nexport function head(ctx: TwilightContext, data: ProductListLoaderData): HeadDescriptor {\n const entity = data.source.entity;\n const category = data.source.type === 'categories' ? (entity as Category | undefined) : undefined;\n const tag = data.source.type === 'tags' ? (entity as ProductListTag | undefined) : undefined;\n\n const canonical = category?.url ?? tag?.url;\n const title = category?.name ?? tag?.name ?? data.page.title;\n const image = category?.image ?? undefined;\n const storeName = ctx.settings?.store?.name;\n // Twig: categories read \"<category> | <store name>\", other listings get the default suffix.\n const pageTitle = category && storeName ? `${title} | ${storeName}` : title;\n\n const base: HeadDescriptor = {\n title: pageTitle,\n appendStoreTitle: !category,\n description: `Browse ${title}`,\n canonical,\n openGraph: {\n type: 'website',\n title: pageTitle,\n description: `Browse ${title}`,\n images: image,\n url: canonical,\n },\n twitter: {\n card: 'summary_large_image',\n title: pageTitle,\n description: `Browse ${title}`,\n images: image,\n },\n alternateLanguages: buildHreflangAlternates(ctx.settings, canonical ?? ctx.location.pathname),\n };\n\n return base;\n}\n\nexport const ProductListing = {\n id: RouteId.PRODUCT_INDEX,\n loader: productListLoader,\n head,\n Component: ProductListPage,\n} as const;\n\nexport { ProductListPage };\nexport { productListLoader };\nexport { useAppliedFilters, parseFiltersFromSearch } from './useAppliedFilters';\nexport type { AppliedFiltersStatus } from './useAppliedFilters';\n\nexport type {\n ProductListLoaderData,\n ProductListLoaderParams,\n ProductListLoaderContext,\n ProductListSource,\n ProductListTag,\n ProductListEntity,\n ProductListPageMeta,\n ProductListSourceConfig,\n ProductListQuery,\n CategoryPageProps,\n} from './types';\n"]}
1
+ {"version":3,"sources":["../../src/routes/product-listing/loader.ts","../../src/routes/product-listing/useAppliedFilters.ts","../../src/routes/product-listing/ProductListPage.tsx","../../src/routes/product-listing/index.tsx"],"names":["i18n","useState","brand","useEffect","useCallback","category"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,IAAM,YAAA,GAAe,YAAA;AAErB,IAAM,aAAA,GAA+D;AAAA,EACnE,UAAA,EAAY,YAAA;AAAA,EACZ,MAAA,EAAQ,QAAA;AAAA,EACR,KAAA,EAAO,OAAA;AAAA,EACP,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ,QAAA;AAAA,EACR,IAAA,EAAM,MAAA;AAAA,EACN,MAAA,EAAQ;AACV,CAAA;AAEA,IAAM,gBAAA,GAAkE;AAAA,EACtE,MAAA,EAAQ,6BAAA;AAAA,EACR,KAAA,EAAO,0BAAA;AAAA,EACP,MAAA,EAAQ;AACV,CAAA;AAEA,IAAM,WAAA,GAA6D;AAAA,EACjE,MAAA,EAAQ,iBAAA;AAAA,EACR,KAAA,EAAO,qBAAA;AAAA,EACP,MAAA,EAAQ;AACV,CAAA;AAEA,eAAsB,kBACpB,GAAA,EACgC;AAChC,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,GAAA;AAC3B,EAAA,MAAM,SAAS,MAAA,EAAQ,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA,GAAI,MAAA;AACpD,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,IAAQ,YAAA;AAE7B,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,MAAA,KAAW,MAAA,CAAO,KAAK,YAAA,GAAe,MAAA,CAAA;AAEhE,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,EAC3D;AAEA,EAAA,IAAI,UAAA,KAAe,YAAA,IAAgB,MAAA,CAAO,EAAA,EAAI;AAC5C,IAAA,OAAO,oBAAA,CAAqB,MAAA,CAAO,EAAA,EAAI,MAAA,EAAQ,IAAI,CAAA;AAAA,EACrD;AAEA,EAAA,IAAI,eAAe,QAAA,EAAU;AAC3B,IAAA,MAAM,WAAW,MAAA,EAAQ,CAAA,IAAK,MAAA,CAAO,OAAA,IAAW,IAAI,IAAA,EAAK;AACzD,IAAA,OAAO,kBAAA,CAAmB,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAAA,EACjD;AAEA,EAAA,IAAI,UAAA,KAAe,MAAA,IAAU,MAAA,CAAO,EAAA,EAAI;AACtC,IAAA,OAAO,eAAA,CAAgB,MAAA,CAAO,EAAA,EAAI,MAAA,EAAQ,IAAI,CAAA;AAAA,EAChD;AAEA,EAAA,IAAI,UAAA,KAAe,QAAA,IAAY,MAAA,CAAO,EAAA,EAAI;AACxC,IAAA,OAAO,iBAAA,CAAkB,MAAA,CAAO,EAAA,EAAI,MAAA,EAAQ,IAAI,CAAA;AAAA,EAClD;AAEA,EAAA,IAAI,UAAA,KAAe,QAAA,IAAY,UAAA,KAAe,OAAA,IAAW,eAAe,QAAA,EAAU;AAChF,IAAA,OAAO,kBAAA;AAAA,MACL,UAAA;AAAA,MACA,OAAO,KAAA,IAAS,EAAA;AAAA,MAChB,OAAO,IAAA,IAAQ,EAAA;AAAA,MACf,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,UAAU,CAAA,CAAE,CAAA;AACtD;AAMA,eAAe,oBAAA,CACb,EAAA,EACA,MAAA,EACA,IAAA,EACgC;AAChC,EAAA,MAAM,EAAE,WAAA,EAAa,IAAA,EAAK,GAAI,kBAAA,EAAmB;AACjD,EAAA,IAAI,YAAA,EAAc,cAAA;AAClB,EAAA,IAAI;AACF,IAAA,CAAC,YAAA,EAAc,cAAc,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MACjD,YAAY,UAAA,CAAW,QAAA,CAAS,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAC,CAAA;AAAA,MAClD,WAAA,CAAY,UAAA;AAAA,QACV,OAAA,CAAQ,QAAQ,IAAA,CAAK;AAAA,UACnB,MAAA,EAAQ,YAAA;AAAA,UACR,WAAA,EAAa,EAAA;AAAA,UACb,MAAA;AAAA,UACA,IAAA;AAAA,UACA,UAAA,EAAY;AAAA,SACb;AAAA;AACH,KACD,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,QAAA,EAAS;AAAA,EACjB;AAEA,EAAA,IAAI,CAAC,YAAA,EAAc,MAAM,QAAA,EAAS;AAElC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,MAAM,OAAA,CAAQ,aAAA;AAAA,MACd,EAAA;AAAA,MACA,OAAO,YAAA,CAAa,IAAA;AAAA,MACpB,WAAA,EAAa;AAAA,QACX,EAAE,IAAA,EAAM,IAAA,CAAK,EAAE,oBAAoB,CAAA,EAAG,KAAK,GAAA,EAAI;AAAA,QAC/C,EAAE,IAAA,EAAM,YAAA,CAAa,IAAA,EAAM,GAAA,EAAK,aAAa,GAAA;AAAI;AACnD,KACF;AAAA,IACA,QAAQ,EAAE,IAAA,EAAM,cAAc,KAAA,EAAO,EAAA,EAAI,QAAQ,YAAA,EAAa;AAAA,IAC9D,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAK;AAAA,IAC7B,UAAU,cAAA,CAAe,KAAA;AAAA,IACzB,UAAA,EAAY;AAAA,MACV,MAAM,cAAA,CAAe;AAAA,KACvB;AAAA,IACA,SAAS,cAAA,CAAe;AAAA,GAC1B;AACF;AAEA,eAAe,kBAAA,CACb,OAAA,EACA,MAAA,EACA,IAAA,EACgC;AAChC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,EAAE,IAAA,EAAAA,KAAAA,EAAK,GAAI,kBAAA,EAAmB;AACpC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM;AAAA,QACJ,MAAM,OAAA,CAAQ,MAAA;AAAA,QACd,KAAA,EAAOA,KAAAA,CAAK,CAAA,CAAE,8BAA8B,CAAA;AAAA,QAC5C,WAAA,EAAa;AAAA,UACX,EAAE,IAAA,EAAMA,KAAAA,CAAK,EAAE,oBAAoB,CAAA,EAAG,KAAK,GAAA,EAAI;AAAA,UAC/C,EAAE,IAAA,EAAMA,KAAAA,CAAK,EAAE,8BAA8B,CAAA,EAAG,KAAK,SAAA;AAAU;AACjE,OACF;AAAA,MACA,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,EAAA,EAAG;AAAA,MACpC,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAK;AAAA,MAC7B,UAAU,EAAC;AAAA,MACX,UAAA,EAAY,EAAE,IAAA,EAAM,IAAA;AAAK,KAC3B;AAAA,EACF;AAEA,EAAA,MAAM,EAAE,WAAA,EAAa,IAAA,EAAK,GAAI,kBAAA,EAAmB;AACjD,EAAA,MAAM,cAAA,GAAiB,MAAM,WAAA,CAAY,UAAA;AAAA,IACvC,OAAA,CAAQ,QAAQ,IAAA,CAAK;AAAA,MACnB,MAAA,EAAQ,QAAA;AAAA,MACR,WAAA,EAAa,OAAA;AAAA,MACb,MAAA;AAAA,MACA,IAAA;AAAA,MACA,UAAA,EAAY;AAAA,KACb;AAAA,GACH;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,MAAM,OAAA,CAAQ,MAAA;AAAA,MACd,OAAO,IAAA,CAAK,CAAA,CAAE,8BAA8B,CAAA,CAAE,OAAA,CAAQ,SAAS,OAAO,CAAA;AAAA,MACtE,WAAA,EAAa;AAAA,QACX,EAAE,IAAA,EAAM,IAAA,CAAK,EAAE,oBAAoB,CAAA,EAAG,KAAK,GAAA,EAAI;AAAA,QAC/C,EAAE,IAAA,EAAM,OAAA,EAAS,GAAA,EAAK,SAAA;AAAU;AAClC,KACF;AAAA,IACA,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,OAAA,EAAQ;AAAA,IACzC,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,IAAA,EAAK;AAAA,IAC7B,UAAU,cAAA,CAAe,KAAA;AAAA,IACzB,UAAA,EAAY;AAAA,MACV,MAAM,cAAA,CAAe;AAAA,KACvB;AAAA,IACA,SAAS,cAAA,CAAe;AAAA,GAC1B;AACF;AAEA,eAAe,eAAA,CACb,EAAA,EACA,MAAA,EACA,IAAA,EACgC;AAChC,EAAA,MAAM,EAAE,WAAA,EAAa,IAAA,EAAK,GAAI,kBAAA,EAAmB;AACjD,EAAA,MAAM,cAAA,GAAiB,MAAM,WAAA,CAAY,UAAA;AAAA,IACvC,OAAA,CAAQ,QAAQ,IAAA,CAAK;AAAA,MACnB,MAAA,EAAQ,MAAA;AAAA,MACR,WAAA,EAAa,EAAA;AAAA,MACb,MAAA;AAAA,MACA;AAAA,KACD;AAAA,GACH;AAEA,EAAA,MAAM,cAAA,GAAiB,cAAA,CAAe,KAAA,CAAM,CAAC,CAAA,EAAG,IAAA,EAAM,IAAA,CAAK,CAAC,CAAA,KAAM,MAAA,CAAO,CAAA,CAAE,EAAE,MAAM,EAAE,CAAA;AACrF,EAAA,IAAI,CAAC,cAAA,EAAgB,MAAM,QAAA,EAAS;AAEpC,EAAA,MAAM,GAAA,GAAM,EAAE,EAAA,EAAI,MAAA,CAAO,cAAA,CAAe,EAAE,CAAA,EAAG,IAAA,EAAM,cAAA,CAAe,IAAA,EAAM,GAAA,EAAK,cAAA,CAAe,GAAA,EAAI;AAEhG,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,MAAM,OAAA,CAAQ,iBAAA;AAAA,MACd,EAAA;AAAA,MACA,OAAO,GAAA,CAAI,IAAA;AAAA,MACX,WAAA,EAAa;AAAA,QACX,EAAE,IAAA,EAAM,IAAA,CAAK,EAAE,oBAAoB,CAAA,EAAG,KAAK,GAAA,EAAI;AAAA,QAC/C,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,GAAA,EAAK,IAAI,GAAA;AAAI;AACjC,KACF;AAAA,IACA,QAAQ,EAAE,IAAA,EAAM,QAAQ,KAAA,EAAO,EAAA,EAAI,QAAQ,GAAA,EAAI;AAAA,IAC/C,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAM;AAAA,IAC9B,UAAU,cAAA,CAAe,KAAA;AAAA,IACzB,UAAA,EAAY;AAAA,MACV,MAAM,cAAA,CAAe;AAAA;AACvB,GACF;AACF;AAEA,eAAe,iBAAA,CACb,EAAA,EACA,MAAA,EACA,IAAA,EACgC;AAChC,EAAA,MAAM,EAAE,WAAA,EAAa,IAAA,EAAK,GAAI,kBAAA,EAAmB;AACjD,EAAA,IAAI,SAAA,EAAW,cAAA;AACf,EAAA,IAAI;AACF,IAAA,CAAC,SAAA,EAAW,cAAc,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MAC9C,YAAY,UAAA,CAAW,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAC,CAAA;AAAA,MAC/C,WAAA,CAAY,UAAA;AAAA,QACV,OAAA,CAAQ,QAAQ,IAAA,CAAK;AAAA,UACnB,MAAA,EAAQ,QAAA;AAAA,UACR,WAAA,EAAa,EAAA;AAAA,UACb,MAAA;AAAA,UACA;AAAA,SACD;AAAA;AACH,KACD,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,QAAA,EAAS;AAAA,EACjB;AAEA,EAAA,IAAI,CAAC,SAAA,EAAW,MAAM,QAAA,EAAS;AAE/B,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,MAAM,OAAA,CAAQ,YAAA;AAAA,MACd,EAAA;AAAA,MACA,OAAO,SAAA,CAAU,IAAA;AAAA,MACjB,WAAA,EAAa;AAAA,QACX,EAAE,IAAA,EAAM,IAAA,CAAK,EAAE,oBAAoB,CAAA,EAAG,KAAK,GAAA,EAAI;AAAA;AAAA,QAE/C,EAAE,IAAA,EAAM,SAAA,CAAU,MAAM,GAAA,EAAK,CAAA,QAAA,EAAW,EAAE,CAAA,CAAA;AAAG;AAC/C,KACF;AAAA,IACA,QAAQ,EAAE,IAAA,EAAM,UAAU,KAAA,EAAO,EAAA,EAAI,QAAQ,SAAA,EAAU;AAAA,IACvD,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAM;AAAA,IAC9B,UAAU,cAAA,CAAe,KAAA;AAAA,IACzB,UAAA,EAAY;AAAA,MACV,MAAM,cAAA,CAAe;AAAA;AACvB,GACF;AACF;AAEA,IAAM,eAAA,GAAiE;AAAA,EACrE,QAAQ,OAAA,CAAQ,oBAAA;AAAA,EAChB,OAAO,OAAA,CAAQ,mBAAA;AAAA,EACf,QAAQ,OAAA,CAAQ;AAClB,CAAA;AAEA,eAAe,kBAAA,CACb,MAAA,EACA,KAAA,EACA,IAAA,EACA,QACA,IAAA,EACgC;AAChC,EAAA,MAAM,EAAE,WAAA,EAAa,IAAA,EAAK,GAAI,kBAAA,EAAmB;AACjD,EAAA,MAAM,gBAAgB,KAAA,IAAS,IAAA,CAAK,CAAA,CAAE,gBAAA,CAAiB,MAAM,CAAC,CAAA;AAC9D,EAAA,MAAM,YAAA,GAAe,IAAA,IAAQ,WAAA,CAAY,MAAM,CAAA;AAC/C,EAAA,MAAM,cAAA,GAAiB,MAAM,WAAA,CAAY,UAAA;AAAA,IACvC,OAAA,CAAQ,QAAQ,IAAA,CAAK;AAAA,MACnB,MAAA,EAAQ,cAAc,MAAM,CAAA;AAAA,MAC5B,MAAA;AAAA,MACA;AAAA,KACD;AAAA,GACH;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,MACJ,IAAA,EAAM,gBAAgB,MAAM,CAAA;AAAA,MAC5B,KAAA,EAAO,aAAA;AAAA,MACP,WAAA,EAAa;AAAA,QACX,EAAE,IAAA,EAAM,IAAA,CAAK,EAAE,oBAAoB,CAAA,EAAG,KAAK,GAAA,EAAI;AAAA,QAC/C,EAAE,IAAA,EAAM,aAAA,EAAe,GAAA,EAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AAAG;AACjD,KACF;AAAA,IACA,MAAA,EAAQ,EAAE,IAAA,EAAM,MAAA,EAAO;AAAA,IACvB,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAM;AAAA,IAC9B,UAAU,cAAA,CAAe,KAAA;AAAA,IACzB,UAAA,EAAY;AAAA,MACV,MAAM,cAAA,CAAe;AAAA;AACvB,GACF;AACF;ACrSA,IAAM,8BAAc,IAAI,GAAA,CAAI,CAAC,WAAA,EAAa,aAAA,EAAe,WAAW,CAAC,CAAA;AAW9D,SAAS,uBAAuB,MAAA,EAA2C;AAChF,EAAA,MAAM,GAAA,mBAAY,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AACpC,EAAA,IAAI,gBAAgB,MAAM,CAAA,CAAE,OAAA,CAAQ,CAAC,OAAO,MAAA,KAAW;AACrD,IAAA,IAAI,CAAC,MAAA,CAAO,UAAA,CAAW,UAAU,CAAA,EAAG;AACpC,IAAA,MAAM,IAAA,GAAO,CAAC,GAAG,MAAA,CAAO,QAAA,CAAS,eAAe,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAC,CAAA;AAClE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,KAAM,EAAA;AACzC,IAAA,MAAM,OAAO,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GAAI,IAAA;AAC1C,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,SAAS,EAAE,CAAA,IAAK,IAAA,CAAK,IAAA,CAAK,CAAC,GAAA,KAAQ,WAAA,CAAY,GAAA,CAAI,GAAG,CAAC,CAAA,EAAG;AAEnF,IAAA,IAAI,IAAA,GAAO,GAAA;AACX,IAAA,IAAA,CAAK,MAAM,CAAA,EAAG,EAAE,CAAA,CAAE,OAAA,CAAQ,CAAC,GAAA,KAAQ;AACjC,MAAA,MAAM,QAAA,GAAW,KAAK,GAAG,CAAA;AACzB,MAAA,IAAI,OAAO,aAAa,QAAA,IAAY,QAAA,KAAa,QAAQ,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAChF,QAAA,IAAA,CAAK,GAAG,CAAA,mBAAI,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAAA,MAChC;AACA,MAAA,IAAA,GAAO,KAAK,GAAG,CAAA;AAAA,IACjB,CAAC,CAAA;AACD,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AACjC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAA,CAAK,IAAI,CAAA,GAAI,CAAC,GAAI,MAAM,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,IAAK,IAAA,CAAK,IAAI,CAAA,GAAiB,IAAK,KAAK,CAAA;AAAA,IACrF,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,IAAI,CAAA,GAAI,KAAA;AAAA,IACf;AAAA,EACF,CAAC,CAAA;AACD,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAAE,SAAU,GAAA,GAA6B,IAAA;AACjE;AAwBO,SAAS,iBAAA,CACd,MAAA,EACA,IAAA,EACA,OAAA,EAOA;AACA,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAoC,IAAI,CAAA;AACtE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAqD,IAAI,CAAA;AACrF,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAwB,IAAI,CAAA;AAC9D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,CAAC,CAAA;AAExC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,UAAA,CAAW,sBAAA,CAAuB,MAAA,CAAO,QAAA,CAAS,MAAM,CAAC,CAAA;AACzD,IAAA,MAAM,MAAM,MAAA,CAAO,KAAA;AACnB,IAAA,IAAI,CAAC,KAAK,KAAA,EAAO;AACjB,IAAA,MAAM,SAAA,GAAY,IAAI,IAAA,KAAoB;AACxC,MAAA,MAAM,IAAA,GAAO,KAAK,CAAC,CAAA;AACnB,MAAA,UAAA,CAAW,IAAA,IAAQ,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS,EAAE,GAAG,IAAA,EAAK,GAAI,IAAI,CAAA;AAAA,IAClE,CAAA;AACA,IAAA,GAAA,CAAI,KAAA,CAAM,EAAA,CAAG,wBAAA,EAA0B,SAAS,CAAA;AAChD,IAAA,OAAO,MAAM,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,0BAA0B,SAAS,CAAA;AAAA,EAChE,GAAG,CAAC,OAAA,EAAS,OAAO,IAAA,EAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAEvC,EAAA,MAAM,GAAA,GAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,CAAC,MAAA,CAAO,IAAA,EAAM,MAAA,CAAO,KAAA,EAAO,IAAA,EAAM,OAAO,CAAC,CAAA,GAAI,EAAA;AAEnF,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,YAAA,CAAa,IAAI,CAAA;AACjB,IAAA,OAAA,CACG,IAAA,CAAK;AAAA,MACJ,QAAQ,MAAA,CAAO,IAAA;AAAA,MACf,aAAa,MAAA,CAAO,KAAA;AAAA,MACpB,IAAA;AAAA,MACA,UAAA,EAAY,IAAA;AAAA,MACZ,OAAA;AAAA,MACA,QAAQ,UAAA,CAAW;AAAA,KACpB,EACA,IAAA,CAAK,CAAC,QAAQ,SAAA,CAAU,EAAE,KAAK,IAAA,EAAM,EAAE,OAAO,GAAA,CAAI,KAAA,EAAO,MAAM,GAAA,CAAI,IAAA,IAAQ,CAAC,CAAA,CAC5E,KAAA,CAAM,MAAM;AAEX,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,eAAsB,GAAG,CAAA;AAAA,IAClD,CAAC,CAAA;AACH,IAAA,OAAO,MAAM,WAAW,KAAA,EAAM;AAAA,EAGhC,CAAA,EAAG,CAAC,GAAA,EAAK,OAAO,CAAC,CAAA;AAEjB,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,MAAM,UAAA,CAAW,CAAC,MAAM,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA;AAE5D,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,QAAA,EAAU,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM;AAExF,EAAA,MAAM,IAAA,GAAO,MAAA,EAAQ,GAAA,KAAQ,GAAA,GAAM,OAAO,IAAA,GAAO,IAAA;AACjD,EAAA,MAAM,MAAA,GAA+B,IAAA,GAAO,OAAA,GAAU,SAAA,KAAc,MAAM,OAAA,GAAU,SAAA;AACpF,EAAA,OAAO,EAAE,SAAS,IAAA,EAAM,QAAA,EAAU,QAAQ,IAAA,IAAQ,IAAA,EAAM,QAAQ,KAAA,EAAM;AACxE;AC/GA,IAAM,4BAAA,GAA+B,+BAAA;AAY9B,SAAS,eAAA,CAAgB;AAAA,EAC9B,IAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,cAAA,EAAe;AAC7B,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,MAAM,EAAE,KAAA,EAAM,GAAI,WAAA,EAAY;AAC9B,EAAA,MAAM,WAAW,WAAA,EAAY;AAE7B,EAAA,MAAM,eAAe,KAAA,CAAM,IAAA;AAC3B,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIC,SAAS,KAAK,CAAA;AAGpD,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,OAAA,IAAW,KAAA,EAAO,UAAU,OAAA,EAAS,OAAA;AAE/D,EAAA,MAAM,OAAA,GAAU,OAAO,IAAA,KAAS,QAAA;AAChC,EAAA,MAAMC,MAAAA,GAAQ,OAAA,GAAW,MAAA,CAAO,MAAA,GAA+B,IAAA;AAG/D,EAAA,MAAM,oBAAA,GAAuB,OAAA,CAAQ,MAAM,WAAA,CAAY,YAAA,EAAc,CAAC,CAAA,EAAG,CAAC,YAAA,EAAc,CAAC,CAAC,CAAA;AAG1F,EAAA,MAAM,WAAW,WAAA,EAAY;AAK7B,EAAA,MAAM;AAAA,IACJ,OAAA,EAAS,cAAA;AAAA,IACT,IAAA,EAAM,YAAA;AAAA,IACN,QAAA;AAAA,IACA,MAAA,EAAQ,YAAA;AAAA,IACR,KAAA,EAAO;AAAA,MACL,iBAAA,CAAkB,MAAA,EAAQ,YAAA,EAAc,CAAC,CAAC,WAAW,CAAA;AAIzD,EAAA,MAAM,SAAA,GAAY,YAAA,KAAiB,OAAA,GAAU,YAAA,GAAe,QAAA;AAC5D,EAAA,MAAM,aAAA,GACJ,iBAAiB,OAAA,GACb,KACA,YAAA,KAAiB,MAAA,GACf,QAAA,GACC,SAAA,EAAW,KAAA,IAAS,QAAA;AAC7B,EAAA,MAAM,SAAA,GACJ,iBAAiB,MAAA,GACb,UAAA,EAAY,OACZ,YAAA,KAAiB,OAAA,GACf,cAAc,IAAA,GACd,IAAA;AACR,EAAA,MAAM,WAAA,GACJ,YAAA,KAAiB,MAAA,GACb,EAAA,GACA,CAAA,CAAA,EAAI,YAAY,CAAA,EAAG,YAAA,KAAiB,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,cAAc,IAAI,EAAE,CAAA,CAAA;AAGvF,EAAAC,UAAU,MAAM;AACd,IAAA,MAAM,oBAAA,GAAuB,MAAM,cAAA,CAAe,KAAK,CAAA;AACvD,IAAA,MAAM,MAAM,MAAA,CAAO,KAAA;AACnB,IAAA,IAAI,OAAO,QAAQ,WAAA,EAAa;AAEhC,IAAA,GAAA,CAAI,KAAA,CAAM,EAAA,CAAG,wBAAA,EAA0B,oBAAoB,CAAA;AAE3D,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,wBAAA,EAA0B,oBAAoB,CAAA;AAAA,IAC9D,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,gBAAA,GAAmBC,WAAAA;AAAA,IACvB,CAAC,KAAA,KAAgD;AAC/C,MAAA,MAAM,OAAA,GAAU,MAAM,MAAA,CAAO,KAAA;AAE7B,MAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB,QAAA,CAAS,SAAS,CAAA;AACrD,MAAA,MAAA,CAAO,GAAA,CAAI,QAAQ,OAAO,CAAA;AAC1B,MAAA,MAAA,CAAO,OAAO,MAAM,CAAA;AAMpB,MAAA,QAAA,CAAS,GAAG,QAAA,CAAS,QAAQ,IAAI,MAAA,CAAO,QAAA,EAAU,CAAA,CAAE,CAAA;AAAA,IACtD,CAAA;AAAA,IACA,CAAC,QAAA,EAAU,QAAA,CAAS,QAAA,EAAU,SAAS,SAAS;AAAA,GAClD;AAGA,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAA,IAAS,MAAA,CAAO,IAAA;AAIvC,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAsB,SAAA,IAAa,IAAI,CAAA;AAC7D,EAAAD,UAAU,MAAM;AACd,IAAA,aAAA,CAAc,UAAU,SAAA,IAAa,IAAA;AAAA,EACvC,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,MAAA,GAASC,YAAY,YAAY;AACrC,IAAA,MAAM,UAAU,aAAA,CAAc,OAAA;AAE9B,IAAA,MAAM,WAAA,GAAc,OAAA,EAAS,KAAA,CAAM,oBAAoB,CAAA;AACvD,IAAA,MAAM,SAAS,WAAA,GAAc,kBAAA,CAAmB,YAAY,CAAC,CAAC,IAAK,OAAA,IAAW,MAAA;AAE9E,IAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,IAAA,CAAK;AAAA,MAChC,QAAQ,MAAA,CAAO,IAAA;AAAA,MACf,aAAa,MAAA,CAAO,KAAA;AAAA,MACpB,GAAI,MAAA,IAAU,EAAE,MAAA,EAAO;AAAA,MACvB,IAAA,EAAM,YAAA;AAAA,MACN,GAAI,cAAA,IAAkB,EAAE,UAAA,EAAY,IAAA,EAAM,SAAS,cAAA;AAAe,KACnE,CAAA;AAED,IAAA,aAAA,CAAc,UAAU,MAAA,CAAO,IAAA;AAE/B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,EAAG,CAAC,MAAA,CAAO,IAAA,EAAM,OAAO,KAAA,EAAO,YAAA,EAAc,cAAc,CAAC,CAAA;AAE5D,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAkB,SAAA,EAAU,gCAAA,EAC1B,QAAA,EAAA;AAAA,IAAA,KAAA,EAAO,QAAA,EAAU,8BAAA,KAAmC,KAAA,oBAAS,GAAA,CAAC,kBAAW,IAAA,EAAY,CAAA;AAAA,IAErF,OAAA,IAAWF,0BACV,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,IAAA;AAAA,UACP,MAAA,EAAQ,GAAA;AAAA,UACR,SAAA,EAAU,0DAAA;AAAA,UACV,GAAA,EAAKA,OAAM,MAAA,IAAU,MAAA;AAAA,UACrB,KAAKA,MAAAA,CAAM,IAAA;AAAA,UACX,QAAA,EAAQ;AAAA;AAAA,OACV;AAAA,sBACA,IAAA,CAAC,QAAA,EAAA,EAAO,SAAA,EAAU,gHAAA,EAChB,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,qEAAA;AAAA,YACV,GAAA,EAAKA,OAAM,IAAA,IAAQ,MAAA;AAAA,YACnB,KAAKA,MAAAA,CAAM,IAAA;AAAA,YACX,WAAA,EAAY;AAAA;AAAA,SACd;AAAA,wBACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0BAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,yBAAA,EAA2B,QAAA,EAAAA,OAAM,IAAA,EAAK,CAAA;AAAA,UACnDA,OAAM,WAAA,oBACL,GAAA;AAAA,YAAC,GAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,qCAAA;AAAA,cACV,uBAAA,EAAyB,EAAE,MAAA,EAAQA,MAAAA,CAAM,WAAA;AAAY;AAAA;AACvD,SAAA,EAEJ;AAAA,OAAA,EACF;AAAA,KAAA,EACF,CAAA;AAAA,oBAGF,GAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EAAK,oBAAA,EAAqB,CAAA;AAAA,oBAEpC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,WAAA,GAAc,2CAA2C,EAAA,EAEtE,QAAA,EAAA;AAAA,MAAA,WAAA,oBACC,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,EAAA,EAAG,cAAA;AAAA,UACH,SAAA,EAAU,qCAAA;AAAA,UACV;AAAA;AAAA,OACF;AAAA,sBAGF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,SAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gDAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,qCAAA,EAAsC,EAAA,EAAG,iBAAA,EACpD,oBAAU,CAAA,CAAE,wBAAwB,CAAA,GAAI,IAAA,CAAK,KAAA,EAChD,CAAA;AAAA,0BAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iDAAA,EACZ,QAAA,EAAA;AAAA,YAAA,WAAA,oBACC,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,MAAM,cAAA,CAAe,IAAI,CAAA;AAAA,gBAClC,SAAA,EAAU,oEAAA;AAAA,gBAEV,QAAA,kBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,sCAAA,EAAuC;AAAA;AAAA,aACtD;AAAA,YAGD,qBAAqB,MAAA,GAAS,CAAA,oBAC7B,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,mBAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,qDAAA;AAAA,kBACV,OAAA,EAAQ,cAAA;AAAA,kBAEP,QAAA,EAAA,CAAA,CAAE,4BAA4B,SAAS;AAAA;AAAA,eAC1C;AAAA,8BACA,GAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,EAAA,EAAG,cAAA;AAAA,kBACH,SAAA,EAAU,gDAAA;AAAA,kBACV,KAAA,EAAO,YAAA;AAAA,kBACP,QAAA,EAAU,gBAAA;AAAA,kBAET,QAAA,EAAA,oBAAA,CAAqB,GAAA,CAAI,CAAC,MAAA,qBACzB,GAAA,CAAC,QAAA,EAAA,EAAuB,KAAA,EAAO,MAAA,CAAO,EAAA,EACnC,QAAA,EAAA,MAAA,CAAO,IAAA,EAAA,EADG,MAAA,CAAO,EAEpB,CACD;AAAA;AAAA;AACH,aAAA,EACF;AAAA,WAAA,EAEJ;AAAA,SAAA,EACF,CAAA;AAAA,wBAEA,GAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EAAK,0BAAA,EAA2B,CAAA;AAAA,wBAE1C,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,CAAA,iBAAA,EAAoB,YAAA,KAAiB,SAAA,GAAY,gBAAgB,EAAE,CAAA,CAAA;AAAA,YAC9E,aAAW,YAAA,KAAiB,SAAA;AAAA,YAE3B,QAAA,EAAA,YAAA,KAAiB,OAAA,mBAChB,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,2CAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,aAAA;AAAA,gBAAA;AAAA,kBACC,IAAA,EAAK,oBAAA;AAAA,kBACL,OAAA,EAAS,CAAA,CAAE,8BAAA,EAAgC,sBAAsB;AAAA;AAAA,eACnE;AAAA,8BACA,GAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,SAAA,EAAU,oBAAA,EAAqB,OAAA,EAAS,YAAA,EAC3D,QAAA,EAAA,CAAA,CAAE,2BAAA,EAA6B,WAAW,CAAA,EAC7C;AAAA,aAAA,EACF,CAAA,mBAEA,GAAA;AAAA,cAAC,SAAA;AAAA,cAAA;AAAA,gBAEC,UAAU,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,YAAY,GAAG,WAAW,CAAA,CAAA;AAAA,gBAClD,KAAA,EAAO,aAAA;AAAA,gBACP,MAAA;AAAA,gBACA,IAAA,EAAM,YAAY,UAAA,GAAa,QAAA;AAAA,gBAC/B,OAAA,EAAS,QAAA,CAAS,QAAA,GAAW,QAAA,CAAS,SAAA;AAAA,gBACtC,SAAA,EAAU,gCAAA;AAAA,gBACV,cAAA,EAAgB,CAAA,sDAAA,EAAyD,WAAA,GAAc,+BAAA,GAAkC,EAAE,CAAA,CAAA;AAAA,gBAC3H,QAAA,sBAAW,mBAAA,EAAA,EAAoB,CAAA;AAAA,gBAC/B,YAAA,EAAa,MAAA;AAAA,gBACb,aAAA,EAAe,EAAA;AAAA,gBACf,KAAA,kBACE,GAAA;AAAA,kBAAC,aAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,oBAAA;AAAA,oBACL,OAAA,EAAS,CAAA;AAAA,sBACP,8BAAA;AAAA,sBACA;AAAA;AACF;AAAA,iBACF;AAAA,gBAEF,GAAG,CAAC,GAAA,EAAK,aAAa,CAAA,CAAE,GAAA,EAAK,YAAY,GAAG,CAAA;AAAA,gBAE3C,WAAC,KAAA,KACA,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,GAAA,qBACf,GAAA;AAAA,kBAAC,WAAA;AAAA,kBAAA;AAAA,oBAEC,OAAA,EAAS,IAAA;AAAA,oBACT,KAAA,EAAO,GAAA;AAAA,oBACP,KAAA,EAAO,cAAc,4BAAA,GAA+B;AAAA,mBAAA;AAAA,kBAH/C,IAAA,CAAK;AAAA,iBAKb;AAAA,eAAA;AAAA,cA9BE,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,YAAY,GAAG,WAAW,CAAA;AAAA;AAgC/C;AAAA,SAEJ;AAAA,wBAEA,GAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EAAK,wBAAA,EAAyB;AAAA,OAAA,EAC1C;AAAA,KAAA,EACF,CAAA;AAAA,IAEC,WAAA,oBACC,GAAA,CAAC,MAAA,EAAA,EAAO,MAAA,EAAQ,aAAa,OAAA,EAAS,MAAM,cAAA,CAAe,KAAK,GAAG,IAAA,EAAK,IAAA,EACtE,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,KAAA,EACb,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,QAAG,SAAA,EAAU,mBAAA,EAAqB,QAAA,EAAA,CAAA,CAAE,0BAAA,EAA4B,SAAS,CAAA,EAAE,CAAA;AAAA,wBAC5E,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAS,MAAM,cAAA,CAAe,KAAK,CAAA;AAAA,YACnC,SAAA,EAAU;AAAA;AAAA;AACZ,OAAA,EACF,CAAA;AAAA,sBACA,GAAA,CAAC,YAAA,EAAA,EAAa,EAAA,EAAG,qBAAA,EAAsB,OAAA,EAAyB;AAAA,KAAA,EAClE,CAAA,EACF,CAAA;AAAA,IAGD,OAAO,IAAA,KAAS,YAAA,IAAgB,OAAO,QAAA,EAAU,QAAA,EAAU,uCAC1D,GAAA,CAAC,qBAAA,EAAA,EAAkB,WAAA,kBAAa,GAAA,CAAC,sBAAmB,CAAA,EAClD,QAAA,kBAAA,GAAA,CAAC,oBAAa,IAAA,EAAM,IAAI,CAAA,EAC1B,CAAA;AAAA,oBAGF,GAAA,CAAC,QAAA,EAAA,EAAS,IAAA,EAAK,kBAAA,EAAmB;AAAA,GAAA,EAAA,EAvK1B,OAwKV,CAAA;AAEJ;;;AC1TO,SAAS,IAAA,CAAK,KAAsB,IAAA,EAA6C;AACtF,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,CAAO,MAAA;AAC3B,EAAA,MAAMG,SAAAA,GAAW,IAAA,CAAK,MAAA,CAAO,IAAA,KAAS,eAAgB,MAAA,GAAkC,MAAA;AACxF,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,IAAA,KAAS,SAAU,MAAA,GAAwC,MAAA;AAEnF,EAAA,MAAM,SAAA,GAAYA,SAAAA,EAAU,GAAA,IAAO,GAAA,EAAK,GAAA;AACxC,EAAA,MAAM,QAAQA,SAAAA,EAAU,IAAA,IAAQ,GAAA,EAAK,IAAA,IAAQ,KAAK,IAAA,CAAK,KAAA;AACvD,EAAA,MAAM,KAAA,GAAQA,WAAU,KAAA,IAAS,MAAA;AACjC,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,QAAA,EAAU,KAAA,EAAO,IAAA;AAEvC,EAAA,MAAM,YAAYA,SAAAA,IAAY,SAAA,GAAY,GAAG,KAAK,CAAA,GAAA,EAAM,SAAS,CAAA,CAAA,GAAK,KAAA;AAEtE,EAAA,MAAM,IAAA,GAAuB;AAAA,IAC3B,KAAA,EAAO,SAAA;AAAA,IACP,kBAAkB,CAACA,SAAAA;AAAA,IACnB,WAAA,EAAa,UAAU,KAAK,CAAA,CAAA;AAAA,IAC5B,SAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,IAAA,EAAM,SAAA;AAAA,MACN,KAAA,EAAO,SAAA;AAAA,MACP,WAAA,EAAa,UAAU,KAAK,CAAA,CAAA;AAAA,MAC5B,MAAA,EAAQ,KAAA;AAAA,MACR,GAAA,EAAK;AAAA,KACP;AAAA,IACA,OAAA,EAAS;AAAA,MACP,IAAA,EAAM,qBAAA;AAAA,MACN,KAAA,EAAO,SAAA;AAAA,MACP,WAAA,EAAa,UAAU,KAAK,CAAA,CAAA;AAAA,MAC5B,MAAA,EAAQ;AAAA,KACV;AAAA,IACA,oBAAoB,uBAAA,CAAwB,GAAA,CAAI,UAAU,SAAA,IAAa,GAAA,CAAI,SAAS,QAAQ;AAAA,GAC9F;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,IAAM,cAAA,GAAiB;AAAA,EAC5B,IAAI,OAAA,CAAQ,aAAA;AAAA,EACZ,MAAA,EAAQ,iBAAA;AAAA,EACR,IAAA;AAAA,EACA,SAAA,EAAW;AACb","file":"product-listing.js","sourcesContent":["import type { ProductListLoaderData, ProductListLoaderContext, ProductListSource } from './types';\nimport type { ProductsListSource } from '../../api/product';\nimport { category } from '../../api/category';\nimport { product } from '../../api/product';\nimport { brand } from '../../api/brands';\nimport { notFound } from '../../providers/NavigationProvider';\nimport { getTwilightContext } from '../../twilight/context';\nimport { RouteId } from '../../router/route-ids';\n\nconst DEFAULT_SORT = 'ourSuggest';\n\nconst SOURCE_TO_API: Record<ProductListSource, ProductsListSource> = {\n categories: 'categories',\n latest: 'latest',\n sales: 'sales',\n offers: 'offers',\n search: 'search',\n tags: 'tags',\n brands: 'brands',\n};\n\nconst SOURCE_TITLE_KEY: Record<'latest' | 'sales' | 'offers', string> = {\n latest: 'blocks.home.latest_products',\n sales: 'common.titles.most_sales',\n offers: 'common.titles.discounts',\n};\n\nconst SOURCE_SLUG: Record<'latest' | 'sales' | 'offers', string> = {\n latest: 'latest-products',\n sales: 'most-sales-products',\n offers: 'offers',\n};\n\nexport async function productListLoader(\n ctx: ProductListLoaderContext\n): Promise<ProductListLoaderData> {\n const { params, search } = ctx;\n const cursor = search?.page ? String(search.page) : undefined;\n const sort = search?.sort ?? DEFAULT_SORT;\n\n const sourceType = params.source ?? (params.id ? 'categories' : undefined);\n\n if (!sourceType) {\n throw new Error('ProductList loader requires source type');\n }\n\n if (sourceType === 'categories' && params.id) {\n return loadCategoryProducts(params.id, cursor, sort);\n }\n\n if (sourceType === 'search') {\n const keyword = (search?.q ?? params.keyword ?? '').trim();\n return loadSearchProducts(keyword, cursor, sort);\n }\n\n if (sourceType === 'tags' && params.id) {\n return loadTagProducts(params.id, cursor, sort);\n }\n\n if (sourceType === 'brands' && params.id) {\n return loadBrandProducts(params.id, cursor, sort);\n }\n\n if (sourceType === 'latest' || sourceType === 'sales' || sourceType === 'offers') {\n return loadStaticProducts(\n sourceType as 'latest' | 'sales' | 'offers',\n params.title ?? '',\n params.slug ?? '',\n cursor,\n sort\n );\n }\n\n throw new Error(`Unknown source type: ${sourceType}`);\n}\n\n// ============================================================================\n// Source-Specific Loaders\n// ============================================================================\n\nasync function loadCategoryProducts(\n id: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n let categoryData, productsResult;\n try {\n [categoryData, productsResult] = await Promise.all([\n queryClient.fetchQuery(category.queries.detail(id)),\n queryClient.fetchQuery(\n product.queries.list({\n source: 'categories',\n sourceValue: id,\n cursor,\n sort,\n filterable: true,\n })\n ),\n ]);\n } catch {\n throw notFound();\n }\n\n if (!categoryData) throw notFound();\n\n return {\n page: {\n slug: RouteId.PRODUCT_INDEX,\n id,\n title: categoryData.name,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: categoryData.name, url: categoryData.url },\n ],\n },\n source: { type: 'categories', value: id, entity: categoryData },\n query: { sort, filters: true },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n filters: productsResult.filters,\n };\n}\n\nasync function loadSearchProducts(\n keyword: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n if (!keyword) {\n const { i18n } = getTwilightContext();\n return {\n page: {\n slug: RouteId.SEARCH,\n title: i18n.t('pages.products.search_result'),\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: i18n.t('pages.products.search_result'), url: '/search' },\n ],\n },\n source: { type: 'search', value: '' },\n query: { sort, filters: true },\n products: [],\n pagination: { next: null },\n };\n }\n\n const { queryClient, i18n } = getTwilightContext();\n const productsResult = await queryClient.fetchQuery(\n product.queries.list({\n source: 'search',\n sourceValue: keyword,\n cursor,\n sort,\n filterable: true,\n })\n );\n\n return {\n page: {\n slug: RouteId.SEARCH,\n title: i18n.t('common.elements.search_about').replace(':word', keyword),\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: keyword, url: '/search' },\n ],\n },\n source: { type: 'search', value: keyword },\n query: { sort, filters: true },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n filters: productsResult.filters,\n };\n}\n\nasync function loadTagProducts(\n id: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n const productsResult = await queryClient.fetchQuery(\n product.queries.list({\n source: 'tags',\n sourceValue: id,\n cursor,\n sort,\n })\n );\n\n const tagFromProduct = productsResult.items[0]?.tags?.find((t) => String(t.id) === id);\n if (!tagFromProduct) throw notFound();\n\n const tag = { id: Number(tagFromProduct.id), name: tagFromProduct.name, url: tagFromProduct.url };\n\n return {\n page: {\n slug: RouteId.PRODUCT_INDEX_TAG,\n id,\n title: tag.name,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: tag.name, url: tag.url },\n ],\n },\n source: { type: 'tags', value: id, entity: tag },\n query: { sort, filters: false },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n };\n}\n\nasync function loadBrandProducts(\n id: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n let brandData, productsResult;\n try {\n [brandData, productsResult] = await Promise.all([\n queryClient.fetchQuery(brand.queries.detail(id)),\n queryClient.fetchQuery(\n product.queries.list({\n source: 'brands',\n sourceValue: id,\n cursor,\n sort,\n })\n ),\n ]);\n } catch {\n throw notFound();\n }\n\n if (!brandData) throw notFound();\n\n return {\n page: {\n slug: RouteId.BRANDS_INDEX,\n id,\n title: brandData.name,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n // The brand API sends no url.\n { name: brandData.name, url: `/brands/${id}` },\n ],\n },\n source: { type: 'brands', value: id, entity: brandData },\n query: { sort, filters: false },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n };\n}\n\nconst SOURCE_ROUTE_ID: Record<'latest' | 'sales' | 'offers', string> = {\n latest: RouteId.PRODUCT_INDEX_LATEST,\n sales: RouteId.PRODUCT_INDEX_SALES,\n offers: RouteId.PRODUCT_INDEX_OFFERS,\n};\n\nasync function loadStaticProducts(\n source: 'latest' | 'sales' | 'offers',\n title: string,\n slug: string,\n cursor: string | undefined,\n sort: string\n): Promise<ProductListLoaderData> {\n const { queryClient, i18n } = getTwilightContext();\n const resolvedTitle = title || i18n.t(SOURCE_TITLE_KEY[source]);\n const resolvedSlug = slug || SOURCE_SLUG[source];\n const productsResult = await queryClient.fetchQuery(\n product.queries.list({\n source: SOURCE_TO_API[source],\n cursor,\n sort,\n })\n );\n\n return {\n page: {\n slug: SOURCE_ROUTE_ID[source],\n title: resolvedTitle,\n breadcrumbs: [\n { name: i18n.t('common.titles.home'), url: '/' },\n { name: resolvedTitle, url: `/${resolvedSlug}` },\n ],\n },\n source: { type: source },\n query: { sort, filters: false },\n products: productsResult.items,\n pagination: {\n next: productsResult.next,\n },\n };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { product } from '../../api/product';\nimport type { ProductListFilters } from '../../api/product';\nimport type { Product } from '../../types';\nimport type { ProductListLoaderData } from './types';\n\ntype Source = ProductListLoaderData['source'];\ntype Node = Record<string, unknown>;\n\n/** Path segments that would reach the shared prototype chain if used as object keys. */\nconst UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\n/**\n * Reads the `filters[...]` selection `<salla-filters>` writes to the address bar\n * (`filters[k]=v`, `filters[k][]=v`, `filters[k][sub]=v`) back into an object, so a\n * filtered link can be opened directly.\n *\n * The keys come straight from the URL, so nodes are null-prototype objects and any\n * `__proto__` / `constructor` / `prototype` segment drops the whole entry — a crafted\n * `?filters[__proto__][x]=1` must never reach `Object.prototype`.\n */\nexport function parseFiltersFromSearch(search: string): ProductListFilters | null {\n const out: Node = Object.create(null);\n new URLSearchParams(search).forEach((value, rawKey) => {\n if (!rawKey.startsWith('filters[')) return;\n const path = [...rawKey.matchAll(/\\[([^\\]]*)\\]/g)].map((m) => m[1]);\n const isList = path[path.length - 1] === '';\n const keys = isList ? path.slice(0, -1) : path;\n if (!keys.length || keys.includes('') || keys.some((key) => UNSAFE_KEYS.has(key))) return;\n\n let node = out;\n keys.slice(0, -1).forEach((key) => {\n const existing = node[key];\n if (typeof existing !== 'object' || existing === null || Array.isArray(existing)) {\n node[key] = Object.create(null);\n }\n node = node[key] as Node;\n });\n const leaf = keys[keys.length - 1];\n if (isList) {\n node[leaf] = [...(Array.isArray(node[leaf]) ? (node[leaf] as string[]) : []), value];\n } else {\n node[leaf] = value;\n }\n });\n return Object.keys(out).length ? (out as ProductListFilters) : null;\n}\n\ninterface FilteredPage {\n items: Product[];\n next: string | null;\n}\n\nexport type AppliedFiltersStatus = 'idle' | 'loading' | 'ready' | 'error';\n\n/**\n * Applies the `<salla-filters>` selection to the product list.\n *\n * The filters component only rewrites the address bar (`history.pushState`, invisible\n * to the router) and emits `salla-filters::changed`; nothing re-queries the list, so\n * the route's loader output — fetched without filters — kept showing. This listens\n * for that event (and for a filtered URL on first load) and fetches the first page\n * with the selection.\n *\n * Each fetched page is stored with the selection that produced it, so `page` is only\n * ever the page for the *current* selection. Until it arrives `status` is `loading`\n * (and `lastPage` is the previous selection's page, for a dimmed placeholder); if the\n * request fails `status` is `error` and `retry` re-runs it — the old products never\n * pass for the new selection.\n */\nexport function useAppliedFilters(\n source: Source,\n sort: string,\n enabled: boolean\n): {\n filters: ProductListFilters | null;\n page: FilteredPage | null;\n lastPage: FilteredPage | null;\n status: AppliedFiltersStatus;\n retry: () => void;\n} {\n const [filters, setFilters] = useState<ProductListFilters | null>(null);\n const [result, setResult] = useState<{ key: string; page: FilteredPage } | null>(null);\n const [failedKey, setFailedKey] = useState<string | null>(null);\n const [attempt, setAttempt] = useState(0);\n\n useEffect(() => {\n if (!enabled) return;\n setFilters(parseFiltersFromSearch(window.location.search));\n const sdk = window.salla;\n if (!sdk?.event) return;\n const onChanged = (...args: unknown[]) => {\n const next = args[0] as ProductListFilters | undefined;\n setFilters(next && Object.keys(next).length ? { ...next } : null);\n };\n sdk.event.on('salla-filters::changed', onChanged);\n return () => sdk.event.off('salla-filters::changed', onChanged);\n }, [enabled, source.type, source.value]);\n\n const key = filters ? JSON.stringify([source.type, source.value, sort, filters]) : '';\n\n useEffect(() => {\n if (!filters) return;\n const controller = new AbortController();\n setFailedKey(null);\n product\n .list({\n source: source.type,\n sourceValue: source.value,\n sort,\n filterable: true,\n filters,\n signal: controller.signal,\n })\n .then((res) => setResult({ key, page: { items: res.items, next: res.next } }))\n .catch(() => {\n // Aborted by a newer selection (its own effect run owns the state now), or failed.\n if (!controller.signal.aborted) setFailedKey(key);\n });\n return () => controller.abort();\n // `key` already encodes filters + source + sort.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, attempt]);\n\n const retry = useCallback(() => setAttempt((n) => n + 1), []);\n\n if (!filters) return { filters: null, page: null, lastPage: null, status: 'idle', retry };\n\n const page = result?.key === key ? result.page : null;\n const status: AppliedFiltersStatus = page ? 'ready' : failedKey === key ? 'error' : 'loading';\n return { filters, page, lastPage: result?.page ?? null, status, retry };\n}\n","import { useState, useRef, useEffect, useMemo, useCallback } from 'react';\nimport { HookSlot, useStore } from '../../hooks';\nimport { useTranslation } from '../../providers/I18nProvider';\nimport { useNavigate, useLocation } from '../../providers/NavigationProvider';\nimport { useTwilight } from '../../providers/TwilightProvider';\nimport { sortOptions } from '../../utils/sort-options';\nimport { Drawer } from '../../components/drawer';\nimport { Breadcrumb } from '../../components/common';\nimport { SallaFilters } from '@salla.sa/twilight-components-react/filters';\nimport { ItemsList, ReviewItemSkeleton } from '@salla.sa/twilight-components-react';\nimport { Testimonials } from '../../components/home';\nimport { ProductCard } from '../../components/product';\nimport { NoContent, ProductCardSkeleton, Image, RenderWhenVisible } from '../../components/common';\nimport { product } from '../../api/product';\nimport { useAppliedFilters } from './useAppliedFilters';\nimport type { ProductListLoaderData } from './types';\nimport type { Brand } from '../brands/types';\nimport type { Product } from '../../types';\n\n/** 3-col + 288px sidebar from md; 3-col of the full container below md. */\nconst FILTERED_PRODUCT_IMAGE_SIZES = '(min-width: 768px) 25vw, 33vw';\n\n/**\n * Product List Page - Unified component for all product listing pages\n *\n * Handles:\n * - Category pages (with filters, category entity, testimonials)\n * - Search pages (keyword display, product count)\n * - Tag pages (tag entity)\n * - Brand pages (brand entity with banner/logo)\n * - Static listings (latest, sales, offers)\n */\nexport function ProductListPage({\n page,\n source,\n query,\n products,\n pagination,\n filters,\n}: ProductListLoaderData) {\n const { t } = useTranslation();\n const store = useStore();\n const { theme } = useTwilight();\n const navigate = useNavigate();\n // Sort is now SSR-driven, no local state needed\n const selectedSort = query.sort;\n const [filtersOpen, setFiltersOpen] = useState(false);\n\n // Determine filters visibility\n const showFilters = query.filters && store?.settings?.product?.filters;\n // const isSearch = source.type === 'search';\n const isBrand = source.type === 'brands';\n const brand = isBrand ? (source.entity as Brand | undefined) : null;\n\n // Generate sort options with translations\n const sortOptionsWithTrans = useMemo(() => sortOptions(selectedSort, t), [selectedSort, t]);\n\n // Get location from hook for consistent URL handling\n const location = useLocation();\n\n // Re-query the list with the selection made in `<salla-filters>`: the component only\n // rewrites the address bar and emits `salla-filters::changed`, and the route's loader\n // output was fetched without it.\n const {\n filters: appliedFilters,\n page: filteredPage,\n lastPage,\n status: filterStatus,\n retry: retryFilters,\n } = useAppliedFilters(source, selectedSort, !!showFilters);\n // While the new selection loads, the previous page stays up (dimmed, `aria-busy`); if\n // the request fails nothing stale passes for the new selection. Infinite scroll is only\n // live for the loader's own page or a fully loaded filtered one.\n const shownPage = filterStatus === 'ready' ? filteredPage : lastPage;\n const shownProducts =\n filterStatus === 'error'\n ? []\n : filterStatus === 'idle'\n ? products\n : (shownPage?.items ?? products);\n const shownNext =\n filterStatus === 'idle'\n ? pagination?.next\n : filterStatus === 'ready'\n ? filteredPage?.next\n : null;\n const filteredKey =\n filterStatus === 'idle'\n ? ''\n : `-${filterStatus}${filterStatus === 'ready' ? JSON.stringify(appliedFilters) : ''}`;\n\n // Listen for filters changed event to close drawer\n useEffect(() => {\n const handleFiltersChanged = () => setFiltersOpen(false);\n const sdk = window.salla;\n if (typeof sdk === 'undefined') return;\n\n sdk.event.on('salla-filters::changed', handleFiltersChanged);\n\n return () => {\n sdk.event.off('salla-filters::changed', handleFiltersChanged);\n };\n }, []);\n\n // Handle sort change - use client-side navigation to trigger route loader re-run\n const handleSortChange = useCallback(\n (event: React.ChangeEvent<HTMLSelectElement>) => {\n const newSort = event.target.value;\n\n const params = new URLSearchParams(location.searchStr);\n params.set('sort', newSort);\n params.delete('page'); // clear any cursor token from URL on sort change\n\n // Use client-side navigation to trigger route loader re-execution (SSR-like).\n // Built from the router's location rather than `window.location`: on a host\n // where the store is the root, the address bar carries the store segment and\n // `navigate` would add it a second time.\n navigate(`${location.pathname}?${params.toString()}`);\n },\n [navigate, location.pathname, location.searchStr]\n );\n\n // Key for remounting products list\n const listKey = source.value ?? source.type;\n\n // Track cursor for the next page — initialized from SSR pagination response.\n // On sort change the key prop remounts ItemsList and this effect resets the cursor.\n const nextCursorRef = useRef<string | null>(shownNext ?? null);\n useEffect(() => {\n nextCursorRef.current = shownNext ?? null;\n }, [shownNext]);\n\n const loader = useCallback(async () => {\n const nextUrl = nextCursorRef.current;\n // Extract the cursor token from the next URL provided by the previous response\n const cursorMatch = nextUrl?.match(/[?&]cursor=([^&]+)/);\n const cursor = cursorMatch ? decodeURIComponent(cursorMatch[1]) : (nextUrl ?? undefined);\n\n const result = await product.list({\n source: source.type,\n sourceValue: source.value,\n ...(cursor && { cursor }),\n sort: selectedSort,\n ...(appliedFilters && { filterable: true, filters: appliedFilters }),\n });\n\n nextCursorRef.current = result.next;\n\n return result;\n }, [source.type, source.value, selectedSort, appliedFilters]);\n\n return (\n <div key={listKey} className=\"container px-2.5 ms:px-5 mb-10\">\n {theme?.settings?.product_index_show_breadcrumbs !== false && <Breadcrumb page={page} />}\n\n {isBrand && brand && (\n <>\n <Image\n width={1200}\n height={300}\n className=\"w-full max-h-[300px] object-cover rounded-md bg-gray-100\"\n src={brand.banner || undefined}\n alt={brand.name}\n priority\n />\n <header className=\"flex flex-col md:flex-row items-center md:items-start text-center rtl:md:text-right ltr:md:text-left mt-2 mb-8\">\n <Image\n className=\"rounded-md w-40 h-24 object-contain shadow-md p-4 bg-white shrink-0\"\n src={brand.logo || undefined}\n alt={brand.name}\n aspectRatio=\"5/3\"\n />\n <div className=\"px-5 pt-3 rtl:text-right\">\n <h1 className=\"text-2xl font-bold mb-1\">{brand.name}</h1>\n {brand.description && (\n <p\n className=\"text-base text-gray-500 font-medium\"\n dangerouslySetInnerHTML={{ __html: brand.description }}\n />\n )}\n </div>\n </header>\n </>\n )}\n\n <HookSlot name=\"product:list.start\" />\n\n <div className={showFilters ? 'md:grid md:grid-cols-[288px_1fr] gap-8' : ''}>\n {/* <FiltersSkeleton></FiltersSkeleton> */}\n {showFilters && (\n <SallaFilters\n id=\"filters-menu\"\n className=\"hidden md:block lg:sticky lg:top-20\"\n filters={filters as any}\n />\n )}\n\n <div className=\"min-w-0\">\n <div className=\"mb-4 sm:mb-6 flex justify-between items-center\">\n <h1 className=\"font-bold text-xl rtl:pl-3 ltr:pr-3\" id=\"page-main-title\">\n {isBrand ? t('common.titles.products') : page.title}\n </h1>\n\n <div className=\"flex items-center space-x-2 rtl:space-x-reverse\">\n {showFilters && (\n <button\n type=\"button\"\n onClick={() => setFiltersOpen(true)}\n className=\"filters-trigger bg-border-color text-primary lg:hidden p-2 rounded\"\n >\n <i className=\"sicon-filter text-gray-text text-2xl\" />\n </button>\n )}\n\n {sortOptionsWithTrans.length > 0 && (\n <div className=\"flex items-center\">\n <label\n className=\"hidden sm:block rtl:ml-3 ltr:mr-3 whitespace-nowrap\"\n htmlFor=\"product-sort\"\n >\n {t('pages.categories.sorting', 'Sort By')}\n </label>\n <select\n id=\"product-sort\"\n className=\"form-input pt-0 pb-1 rtl:md:pl-10 ltr:md:pr-10\"\n value={selectedSort}\n onChange={handleSortChange}\n >\n {sortOptionsWithTrans.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n </div>\n )}\n </div>\n </div>\n\n <HookSlot name=\"product:list.items.start\" />\n\n <div\n className={`flex min-h-screen${filterStatus === 'loading' ? ' opacity-60' : ''}`}\n aria-busy={filterStatus === 'loading'}\n >\n {filterStatus === 'error' ? (\n <div className=\"flex-1 min-w-0 flex flex-col items-center\">\n <NoContent\n icon=\"sicon-shopping-bag\"\n message={t('common.errors.error_occurred', 'Something went wrong')}\n />\n <button type=\"button\" className=\"link--primary mt-4\" onClick={retryFilters}>\n {t('common.elements.try_again', 'Try again')}\n </button>\n </div>\n ) : (\n <ItemsList<Product>\n key={`${listKey}-${selectedSort}${filteredKey}`}\n resetKey={`${listKey}-${selectedSort}${filteredKey}`}\n items={shownProducts}\n loader={loader}\n mode={shownNext ? 'infinite' : 'static'}\n pageUrl={location.pathname + location.searchStr}\n className=\"s-products-list flex-1 min-w-0\"\n itemsClassName={`s-products-list-wrapper s-products-list-vertical-cards${showFilters ? ' s-products-list-with-filters' : ''}`}\n skeleton={<ProductCardSkeleton />}\n skeletonType=\"item\"\n skeletonCount={12}\n empty={\n <NoContent\n icon=\"sicon-shopping-bag\"\n message={t(\n 'pages.categories.no_products',\n 'No products found in this category'\n )}\n />\n }\n t={(key, fallback) => t(key, fallback || key)}\n >\n {(items) =>\n items.map((prod, idx) => (\n <ProductCard\n key={prod.id}\n product={prod}\n index={idx}\n sizes={showFilters ? FILTERED_PRODUCT_IMAGE_SIZES : undefined}\n />\n ))\n }\n </ItemsList>\n )}\n </div>\n\n <HookSlot name=\"product:list.items.end\" />\n </div>\n </div>\n\n {showFilters && (\n <Drawer isOpen={filtersOpen} onClose={() => setFiltersOpen(false)} size=\"md\">\n <div className=\"p-4\">\n <div className=\"flex justify-between items-center mb-4\">\n <h3 className=\"font-bold text-lg\">{t('pages.categories.filters', 'Filters')}</h3>\n <button\n type=\"button\"\n onClick={() => setFiltersOpen(false)}\n className=\"btn--close-sm sicon-cancel text-gray-500\"\n />\n </div>\n <SallaFilters id=\"filters-menu-mobile\" filters={filters as any} />\n </div>\n </Drawer>\n )}\n\n {source.type === 'categories' && store?.settings?.category?.testimonial_enabled && (\n <RenderWhenVisible placeholder={<ReviewItemSkeleton />}>\n <Testimonials data={{}} />\n </RenderWhenVisible>\n )}\n\n <HookSlot name=\"product:list.end\" />\n </div>\n );\n}\n","import type { HeadDescriptor } from '../../utils/head';\nimport { buildHreflangAlternates } from '../../utils/baseHead';\nimport { productListLoader } from './loader';\nimport type { ProductListLoaderData, ProductListTag, Category } from './types';\nimport type { TwilightContext } from '../../twilight/context';\nimport { RouteId } from '../../router/route-ids';\nimport { ProductListPage } from './ProductListPage';\n\nexport function head(ctx: TwilightContext, data: ProductListLoaderData): HeadDescriptor {\n const entity = data.source.entity;\n const category = data.source.type === 'categories' ? (entity as Category | undefined) : undefined;\n const tag = data.source.type === 'tags' ? (entity as ProductListTag | undefined) : undefined;\n\n const canonical = category?.url ?? tag?.url;\n const title = category?.name ?? tag?.name ?? data.page.title;\n const image = category?.image ?? undefined;\n const storeName = ctx.settings?.store?.name;\n // Twig: categories read \"<category> | <store name>\", other listings get the default suffix.\n const pageTitle = category && storeName ? `${title} | ${storeName}` : title;\n\n const base: HeadDescriptor = {\n title: pageTitle,\n appendStoreTitle: !category,\n description: `Browse ${title}`,\n canonical,\n openGraph: {\n type: 'website',\n title: pageTitle,\n description: `Browse ${title}`,\n images: image,\n url: canonical,\n },\n twitter: {\n card: 'summary_large_image',\n title: pageTitle,\n description: `Browse ${title}`,\n images: image,\n },\n alternateLanguages: buildHreflangAlternates(ctx.settings, canonical ?? ctx.location.pathname),\n };\n\n return base;\n}\n\nexport const ProductListing = {\n id: RouteId.PRODUCT_INDEX,\n loader: productListLoader,\n head,\n Component: ProductListPage,\n} as const;\n\nexport { ProductListPage };\nexport { productListLoader };\nexport { useAppliedFilters, parseFiltersFromSearch } from './useAppliedFilters';\nexport type { AppliedFiltersStatus } from './useAppliedFilters';\n\nexport type {\n ProductListLoaderData,\n ProductListLoaderParams,\n ProductListLoaderContext,\n ProductListSource,\n ProductListTag,\n ProductListEntity,\n ProductListPageMeta,\n ProductListSourceConfig,\n ProductListQuery,\n CategoryPageProps,\n} from './types';\n"]}
@@ -1,16 +1,17 @@
1
1
  import { buildHreflangAlternates } from '../chunk-TZ3E5BN4.js';
2
- import { ProductsSlider, LazyTestimonials } from '../chunk-GRV7ELSP.js';
3
- import { product } from '../chunk-QYUYQPXN.js';
4
- import { ProductGallery, LazyProductDetails, LazyAddToCartForm } from '../chunk-FY573DJA.js';
2
+ import { ProductsSlider, LazyTestimonials } from '../chunk-W5K6YUA2.js';
3
+ import '../chunk-Y43T7PJV.js';
4
+ import { product } from '../chunk-HDO37URJ.js';
5
+ import { ProductGallery, LazyProductDetails, LazyAddToCartForm } from '../chunk-FAVZMJRY.js';
5
6
  import '../chunk-342EPVXN.js';
6
- import { fastCheckoutScript } from '../chunk-55VTMG2H.js';
7
- import '../chunk-UEKIAED3.js';
7
+ import { fastCheckoutScript } from '../chunk-UEQFXSTX.js';
8
+ import '../chunk-3Q22KK7C.js';
8
9
  import '../chunk-JKIRRMBU.js';
9
10
  import '../chunk-2JV6WZ6O.js';
10
11
  import '../chunk-UIOLSYKV.js';
11
12
  import '../chunk-VVZNW5CB.js';
12
13
  import '../chunk-2XGQSJKH.js';
13
- import '../chunk-KBQXQKPZ.js';
14
+ import '../chunk-SSPAMQRV.js';
14
15
  import { RouteId } from '../chunk-ZGHRSRDO.js';
15
16
  import { useComments } from '../chunk-GOPUP26T.js';
16
17
  import '../chunk-C5X6CVXC.js';
@@ -36,7 +37,7 @@ import '../chunk-T72DAX7R.js';
36
37
  import '../chunk-RJPPO3ET.js';
37
38
  import { HookSlot } from '../chunk-Q7VWURUR.js';
38
39
  import '../chunk-GU2KUQVD.js';
39
- import { LazyBreadcrumb, LazyRenderWhenVisible } from '../chunk-WF7DYPR6.js';
40
+ import { LazyBreadcrumb, LazyRenderWhenVisible } from '../chunk-SOPZ72BU.js';
40
41
  import '../chunk-AXW67SY7.js';
41
42
  import '../chunk-BYMOPN2S.js';
42
43
  import '../chunk-SKLEJJ6M.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/product/loader.ts","../../src/routes/product/ProductPage.tsx","../../src/routes/product/index.tsx"],"names":["product"],"mappings":"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","file":"product.js","sourcesContent":["import type { ProductPageProps } from './types';\nimport type { IdParams } from '../types';\nimport { product } from '../../api/product';\nimport { getTwilightContext } from '../../twilight/context';\nimport { RouteId } from '../../router/route-ids';\nimport type { Breadcrumb } from '../../types';\n\nexport async function productLoader({ params }: { params: IdParams }): Promise<ProductPageProps> {\n const data = await product.findOrThrow(params.id);\n const i18n = getTwilightContext().i18n;\n const home: Breadcrumb = { name: i18n.t('common.titles.home'), url: '/' };\n\n const breadcrumbs: Breadcrumb[] = [home];\n if (data.category) {\n breadcrumbs.push({ name: data.category.name, url: data.category.url });\n }\n breadcrumbs.push({ name: data.name, url: data.url });\n\n const page = {\n slug: RouteId.PRODUCT_SINGLE,\n id: data.id,\n title: data.name,\n url: data.url,\n parent:\n data.category && data.category.id\n ? { id: data.category.id, name: data.category.name, url: data.category.url }\n : null,\n breadcrumbs,\n };\n\n return {\n page,\n product: data,\n };\n}\n","import { SallaQuickOrder } from '@salla.sa/twilight-components-react/quick-order';\nimport { SallaOffer } from '@salla.sa/twilight-components-react/offer';\nimport { SallaComments } from '@salla.sa/twilight-components-react/comments';\nimport { HookSlot } from '../../hooks';\nimport { useTranslation } from '../../providers/I18nProvider';\nimport { useProduct } from '../../hooks/useProduct';\nimport { useComments } from '../../hooks/useComments';\nimport type { ProductPageProps } from './types';\nimport { Breadcrumb, RenderWhenVisible } from '../../components/common';\nimport { ProductDetails, AddToCartForm, ProductGallery } from '../../components/product';\nimport { ProductsSlider, Testimonials } from '../../components/home';\nimport { useTwilight } from '../../providers/twilight-context';\n\nexport function ProductPage({ product: initialProduct, page }: ProductPageProps) {\n const { theme, store } = useTwilight();\n const { t } = useTranslation();\n const { product } = useProduct(initialProduct);\n const { commentsKey } = useComments();\n\n return (\n <div key={product.id}>\n <div className=\"container\">\n {theme?.settings?.product_show_breadcrumbs !== false && <Breadcrumb page={page} />}\n\n <HookSlot name=\"product:start\" />\n\n <div className=\"flex flex-col items-start md:flex-row\" id={`product-${product.id}`}>\n <ProductGallery product={product} />\n\n <div className=\"main-content md:sticky md:overflow-hidden top-24 w-full md:w-2/4 md:pb-16\">\n <HookSlot name=\"product:details.start\" />\n <HookSlot name=\"product:single.description.start\" />\n <ProductDetails product={product} showTags={theme.settings.show_tags} />\n <HookSlot name=\"product:single.description\" />\n <HookSlot name=\"product:single.description.end\" />\n <HookSlot name=\"product:details.end\" />\n\n <HookSlot name=\"product:single.form.start\" />\n <AddToCartForm product={product} stickyAddToCart={theme.settings.sticky_add_to_cart} />\n <HookSlot name=\"product:single.form.end\" />\n\n <SallaQuickOrder className=\"mt-5 md:-mb-2 block\" />\n </div>\n </div>\n\n <SallaOffer />\n </div>\n\n {store.settings?.rating?.show_on_product && (\n <RenderWhenVisible>\n <SallaComments key={commentsKey} itemId={product.id} type={'product' as any} />\n </RenderWhenVisible>\n )}\n\n <HookSlot name=\"product:related.start\" />\n <RenderWhenVisible>\n <div className=\"container\">\n <ProductsSlider\n data={{\n products: { source: 'related', source_value: product.id },\n title: t('pages.products.similar_products'),\n display_all_url: '',\n }}\n />\n </div>\n </RenderWhenVisible>\n <HookSlot name=\"product:related.end\" />\n\n <RenderWhenVisible>\n <div className=\"container\">\n <Testimonials data={{}} />\n </div>\n </RenderWhenVisible>\n\n <HookSlot name=\"product:end\" />\n </div>\n );\n}\n","import type { HeadDescriptor } from '../../utils/head';\nimport { buildHreflangAlternates } from '../../utils/baseHead';\nimport type { ProductPageProps } from './types';\nimport type { IdParams } from '../types';\nimport type { TwilightContext } from '../../twilight/context';\nimport { productLoader } from './loader';\nimport { RouteId } from '../../router/route-ids';\nimport { ProductPage } from './ProductPage';\nimport { fastCheckoutScript } from '../../utils/fast-checkout';\nexport { productLoader } from './loader';\nexport type { ProductPageProps } from './types';\n\nasync function loader(\n ctx: { params: IdParams; locale?: string },\n extend?: (\n data: ProductPageProps,\n ctx: { params: IdParams }\n ) => Promise<Record<string, unknown>> | Record<string, unknown>\n): Promise<ProductPageProps> {\n const data = await productLoader({ params: ctx.params });\n\n if (extend) {\n const extra = await extend(data, ctx);\n return { ...data, ...extra } as ProductPageProps;\n }\n return data;\n}\n\nfunction head(ctx: TwilightContext, data: ProductPageProps): HeadDescriptor {\n if (!data?.product) {\n return {\n title: 'Products',\n description: 'Browse our products',\n };\n }\n const product = data.product;\n const storeName = ctx.settings?.store?.name ?? '';\n\n // Strip HTML and limit description to 160 chars\n const description = product.description?.replace(/<[^>]*>/g, '').slice(0, 160) ?? '';\n\n // Price valid until: 1 month from now\n const priceValidUntil = new Date();\n priceValidUntil.setMonth(priceValidUntil.getMonth() + 1);\n\n // Collect all product images\n const images = product.images?.map((img) => img.url).filter(Boolean) ?? [];\n if (product.image?.url && !images.includes(product.image.url)) {\n images.unshift(product.image.url);\n }\n\n // Build JSON-LD schema matching SchemaProductWidget.php\n const jsonLd: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': 'Product',\n name: product.name,\n description,\n sku: product.sku,\n image: images.length > 0 ? images : undefined,\n offers: {\n '@type': 'Offer',\n url: product.url,\n availability: product.is_available\n ? 'https://schema.org/InStock'\n : 'https://schema.org/OutOfStock',\n price: product.sale_price,\n priceCurrency: product.currency,\n priceValidUntil: priceValidUntil.toISOString().split('T')[0],\n seller: storeName\n ? {\n '@type': 'Organization',\n name: storeName,\n }\n : undefined,\n },\n };\n\n // Add brand if exists\n if (product.brand) {\n jsonLd.brand = {\n '@type': 'Brand',\n name: product.brand.name,\n description: product.brand.description,\n logo: product.brand.logo,\n };\n }\n\n // Add aggregateRating and review if rating exists\n if (product.rating && product.rating.count > 0) {\n const ratingValue = product.rating.stars;\n jsonLd.aggregateRating = {\n '@type': 'AggregateRating',\n ratingCount: product.rating.count,\n ratingValue,\n };\n jsonLd.review = {\n '@type': 'Review',\n author: storeName\n ? {\n '@type': 'Organization',\n name: storeName,\n }\n : undefined,\n reviewRating: {\n '@type': 'Rating',\n bestRating: 5,\n ratingValue,\n },\n };\n }\n\n if (product.gtin && product.gtin.length === 8) {\n jsonLd.gtin8 = product.gtin;\n }\n\n if (product.mpn) {\n jsonLd.mpn = product.mpn;\n }\n\n // Twig: \"<product> | <store name>\", without the store meta title.\n const title = storeName ? `${product.name} | ${storeName}` : product.name;\n const base: HeadDescriptor = {\n title,\n appendStoreTitle: false,\n description,\n canonical: product.url,\n openGraph: {\n type: 'product',\n title,\n description,\n images: product.image?.url,\n url: product.url,\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: product.image?.url,\n },\n jsonLd,\n alternateLanguages: buildHreflangAlternates(ctx.settings, ctx.location.pathname),\n // Quick-buy widget code, eager only here: the Buy Now button is above the fold on this page.\n // Other routes load it on idle from the body:end default hook, which also owns the\n // `#fast-checkout-js` marker `salla-add-product-button` checks for.\n scripts: ctx.settings?.store?.settings?.buy_now ? [fastCheckoutScript()] : [],\n };\n\n return base;\n}\n\nexport const Product = {\n id: RouteId.PRODUCT_SINGLE,\n loader,\n head,\n Component: ProductPage,\n} as const;\n"]}
1
+ {"version":3,"sources":["../../src/routes/product/loader.ts","../../src/routes/product/ProductPage.tsx","../../src/routes/product/index.tsx"],"names":["product"],"mappings":"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","file":"product.js","sourcesContent":["import type { ProductPageProps } from './types';\nimport type { IdParams } from '../types';\nimport { product } from '../../api/product';\nimport { getTwilightContext } from '../../twilight/context';\nimport { RouteId } from '../../router/route-ids';\nimport type { Breadcrumb } from '../../types';\n\nexport async function productLoader({ params }: { params: IdParams }): Promise<ProductPageProps> {\n const data = await product.findOrThrow(params.id);\n const i18n = getTwilightContext().i18n;\n const home: Breadcrumb = { name: i18n.t('common.titles.home'), url: '/' };\n\n const breadcrumbs: Breadcrumb[] = [home];\n if (data.category) {\n breadcrumbs.push({ name: data.category.name, url: data.category.url });\n }\n breadcrumbs.push({ name: data.name, url: data.url });\n\n const page = {\n slug: RouteId.PRODUCT_SINGLE,\n id: data.id,\n title: data.name,\n url: data.url,\n parent:\n data.category && data.category.id\n ? { id: data.category.id, name: data.category.name, url: data.category.url }\n : null,\n breadcrumbs,\n };\n\n return {\n page,\n product: data,\n };\n}\n","import { SallaQuickOrder } from '@salla.sa/twilight-components-react/quick-order';\nimport { SallaOffer } from '@salla.sa/twilight-components-react/offer';\nimport { SallaComments } from '@salla.sa/twilight-components-react/comments';\nimport { HookSlot } from '../../hooks';\nimport { useTranslation } from '../../providers/I18nProvider';\nimport { useProduct } from '../../hooks/useProduct';\nimport { useComments } from '../../hooks/useComments';\nimport type { ProductPageProps } from './types';\nimport { Breadcrumb, RenderWhenVisible } from '../../components/common';\nimport { ProductDetails, AddToCartForm, ProductGallery } from '../../components/product';\nimport { ProductsSlider, Testimonials } from '../../components/home';\nimport { useTwilight } from '../../providers/twilight-context';\n\nexport function ProductPage({ product: initialProduct, page }: ProductPageProps) {\n const { theme, store } = useTwilight();\n const { t } = useTranslation();\n const { product } = useProduct(initialProduct);\n const { commentsKey } = useComments();\n\n return (\n <div key={product.id}>\n <div className=\"container\">\n {theme?.settings?.product_show_breadcrumbs !== false && <Breadcrumb page={page} />}\n\n <HookSlot name=\"product:start\" />\n\n <div className=\"flex flex-col items-start md:flex-row\" id={`product-${product.id}`}>\n <ProductGallery product={product} />\n\n <div className=\"main-content md:sticky md:overflow-hidden top-24 w-full md:w-2/4 md:pb-16\">\n <HookSlot name=\"product:details.start\" />\n <HookSlot name=\"product:single.description.start\" />\n <ProductDetails product={product} showTags={theme.settings.show_tags} />\n <HookSlot name=\"product:single.description\" />\n <HookSlot name=\"product:single.description.end\" />\n <HookSlot name=\"product:details.end\" />\n\n <HookSlot name=\"product:single.form.start\" />\n <AddToCartForm product={product} stickyAddToCart={theme.settings.sticky_add_to_cart} />\n <HookSlot name=\"product:single.form.end\" />\n\n <SallaQuickOrder className=\"mt-5 md:-mb-2 block\" />\n </div>\n </div>\n\n <SallaOffer />\n </div>\n\n {store.settings?.rating?.show_on_product && (\n <RenderWhenVisible>\n <SallaComments key={commentsKey} itemId={product.id} type={'product' as any} />\n </RenderWhenVisible>\n )}\n\n <HookSlot name=\"product:related.start\" />\n <RenderWhenVisible>\n <div className=\"container\">\n <ProductsSlider\n data={{\n products: { source: 'related', source_value: product.id },\n title: t('pages.products.similar_products'),\n display_all_url: '',\n }}\n />\n </div>\n </RenderWhenVisible>\n <HookSlot name=\"product:related.end\" />\n\n <RenderWhenVisible>\n <div className=\"container\">\n <Testimonials data={{}} />\n </div>\n </RenderWhenVisible>\n\n <HookSlot name=\"product:end\" />\n </div>\n );\n}\n","import type { HeadDescriptor } from '../../utils/head';\nimport { buildHreflangAlternates } from '../../utils/baseHead';\nimport type { ProductPageProps } from './types';\nimport type { IdParams } from '../types';\nimport type { TwilightContext } from '../../twilight/context';\nimport { productLoader } from './loader';\nimport { RouteId } from '../../router/route-ids';\nimport { ProductPage } from './ProductPage';\nimport { fastCheckoutScript } from '../../utils/fast-checkout';\nexport { productLoader } from './loader';\nexport type { ProductPageProps } from './types';\n\nasync function loader(\n ctx: { params: IdParams; locale?: string },\n extend?: (\n data: ProductPageProps,\n ctx: { params: IdParams }\n ) => Promise<Record<string, unknown>> | Record<string, unknown>\n): Promise<ProductPageProps> {\n const data = await productLoader({ params: ctx.params });\n\n if (extend) {\n const extra = await extend(data, ctx);\n return { ...data, ...extra } as ProductPageProps;\n }\n return data;\n}\n\nfunction head(ctx: TwilightContext, data: ProductPageProps): HeadDescriptor {\n if (!data?.product) {\n return {\n title: 'Products',\n description: 'Browse our products',\n };\n }\n const product = data.product;\n const storeName = ctx.settings?.store?.name ?? '';\n\n // Strip HTML and limit description to 160 chars\n const description = product.description?.replace(/<[^>]*>/g, '').slice(0, 160) ?? '';\n\n // Price valid until: 1 month from now\n const priceValidUntil = new Date();\n priceValidUntil.setMonth(priceValidUntil.getMonth() + 1);\n\n // Collect all product images\n const images = product.images?.map((img) => img.url).filter(Boolean) ?? [];\n if (product.image?.url && !images.includes(product.image.url)) {\n images.unshift(product.image.url);\n }\n\n // Build JSON-LD schema matching SchemaProductWidget.php\n const jsonLd: Record<string, unknown> = {\n '@context': 'https://schema.org',\n '@type': 'Product',\n name: product.name,\n description,\n sku: product.sku,\n image: images.length > 0 ? images : undefined,\n offers: {\n '@type': 'Offer',\n url: product.url,\n availability: product.is_available\n ? 'https://schema.org/InStock'\n : 'https://schema.org/OutOfStock',\n price: product.sale_price,\n priceCurrency: product.currency,\n priceValidUntil: priceValidUntil.toISOString().split('T')[0],\n seller: storeName\n ? {\n '@type': 'Organization',\n name: storeName,\n }\n : undefined,\n },\n };\n\n // Add brand if exists\n if (product.brand) {\n jsonLd.brand = {\n '@type': 'Brand',\n name: product.brand.name,\n description: product.brand.description,\n logo: product.brand.logo,\n };\n }\n\n // Add aggregateRating and review if rating exists\n if (product.rating && product.rating.count > 0) {\n const ratingValue = product.rating.stars;\n jsonLd.aggregateRating = {\n '@type': 'AggregateRating',\n ratingCount: product.rating.count,\n ratingValue,\n };\n jsonLd.review = {\n '@type': 'Review',\n author: storeName\n ? {\n '@type': 'Organization',\n name: storeName,\n }\n : undefined,\n reviewRating: {\n '@type': 'Rating',\n bestRating: 5,\n ratingValue,\n },\n };\n }\n\n if (product.gtin && product.gtin.length === 8) {\n jsonLd.gtin8 = product.gtin;\n }\n\n if (product.mpn) {\n jsonLd.mpn = product.mpn;\n }\n\n // Twig: \"<product> | <store name>\", without the store meta title.\n const title = storeName ? `${product.name} | ${storeName}` : product.name;\n const base: HeadDescriptor = {\n title,\n appendStoreTitle: false,\n description,\n canonical: product.url,\n openGraph: {\n type: 'product',\n title,\n description,\n images: product.image?.url,\n url: product.url,\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: product.image?.url,\n },\n jsonLd,\n alternateLanguages: buildHreflangAlternates(ctx.settings, ctx.location.pathname),\n // Quick-buy widget code, eager only here: the Buy Now button is above the fold on this page.\n // Other routes load it on idle from the body:end default hook, which also owns the\n // `#fast-checkout-js` marker `salla-add-product-button` checks for.\n scripts: ctx.settings?.store?.settings?.buy_now ? [fastCheckoutScript()] : [],\n };\n\n return base;\n}\n\nexport const Product = {\n id: RouteId.PRODUCT_SINGLE,\n loader,\n head,\n Component: ProductPage,\n} as const;\n"]}
@@ -20,6 +20,13 @@ export declare function pendingOrdersRedirectLoader(ctx?: {
20
20
  export declare function ratingRedirectLoader(ctx?: {
21
21
  params: PendingOrdersRedirectParams;
22
22
  }): Promise<never>;
23
+ /** A Twig customer URL (`/profile`, `/orders`, …) kept working as its `/account/…` page. */
24
+ export declare function accountRedirectLoader(ctx: {
25
+ params: PendingOrdersRedirectParams;
26
+ page: string;
27
+ /** The incoming query string (`?status=pending`), kept on the account page. */
28
+ search?: string;
29
+ }): Promise<never>;
23
30
  /**
24
31
  * `/logout` — where the SDK sends the browser once `salla.auth.logout()` has run
25
32
  * (`salla.url.get('logout?from=…')`). The Twig storefront serves that URL server-side. Here
@@ -1 +1 @@
1
- {"version":3,"file":"seo-redirects.d.ts","sourceRoot":"","sources":["../../src/routes/seo-redirects.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,uBAAuB,CAAC,GAAG,EAAE;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAG9F;AAED,MAAM,WAAW,2BAA2B;IAC1C,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,2BAA2B,CAC/C,GAAG,GAAE;IAAE,MAAM,EAAE,2BAA2B,CAAA;CAAmB,GAC5D,OAAO,CAAC,KAAK,CAAC,CAGhB;AAED,4HAA4H;AAC5H,wBAAsB,oBAAoB,CACxC,GAAG,GAAE;IAAE,MAAM,EAAE,2BAA2B,CAAA;CAAmB,GAC5D,OAAO,CAAC,KAAK,CAAC,CAGhB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAOrC"}
1
+ {"version":3,"file":"seo-redirects.d.ts","sourceRoot":"","sources":["../../src/routes/seo-redirects.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,uBAAuB,CAAC,GAAG,EAAE;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAG9F;AAED,MAAM,WAAW,2BAA2B;IAC1C,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,2BAA2B,CAC/C,GAAG,GAAE;IAAE,MAAM,EAAE,2BAA2B,CAAA;CAAmB,GAC5D,OAAO,CAAC,KAAK,CAAC,CAGhB;AAED,4HAA4H;AAC5H,wBAAsB,oBAAoB,CACxC,GAAG,GAAE;IAAE,MAAM,EAAE,2BAA2B,CAAA;CAAmB,GAC5D,OAAO,CAAC,KAAK,CAAC,CAGhB;AAED,4FAA4F;AAC5F,wBAAsB,qBAAqB,CAAC,GAAG,EAAE;IAC/C,MAAM,EAAE,2BAA2B,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,KAAK,CAAC,CAIjB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAOrC"}
@@ -1,5 +1,5 @@
1
- export { LogoutRedirect, pendingOrdersRedirectLoader, ratingRedirectLoader, slugBrandRedirectLoader } from '../chunk-24QOBDMC.js';
2
- import '../chunk-KBQXQKPZ.js';
1
+ export { LogoutRedirect, accountRedirectLoader, pendingOrdersRedirectLoader, ratingRedirectLoader, slugBrandRedirectLoader } from '../chunk-4YWBXQV5.js';
2
+ import '../chunk-SSPAMQRV.js';
3
3
  import '../chunk-ZGHRSRDO.js';
4
4
  import '../chunk-SR4OTLTJ.js';
5
5
  import '../chunk-N2S25NXP.js';
@@ -18,7 +18,7 @@ async function testimonialsLoader(_ctx) {
18
18
 
19
19
  // src/routes/testimonials/index.tsx
20
20
  var LazyTestimonialsPage = lazy(
21
- () => import('../TestimonialsPage-7YXSU33Z.js').then((m) => ({ default: m.TestimonialsPage }))
21
+ () => import('../TestimonialsPage-CKAYXFER.js').then((m) => ({ default: m.TestimonialsPage }))
22
22
  );
23
23
  var TestimonialsPage = LazyTestimonialsPage;
24
24
  async function loader(ctx, extend) {
@@ -1,6 +1,6 @@
1
- import { order } from '../chunk-2QNDO2OY.js';
1
+ import { order } from '../chunk-6IRWFBGU.js';
2
2
  import { buildHreflangAlternates } from '../chunk-TZ3E5BN4.js';
3
- import '../chunk-KBQXQKPZ.js';
3
+ import '../chunk-SSPAMQRV.js';
4
4
  import { RouteId } from '../chunk-ZGHRSRDO.js';
5
5
  import '../chunk-P3OPJL6I.js';
6
6
  import '../chunk-WY4IYO3G.js';
@@ -40,7 +40,7 @@ async function thankYouLoader({
40
40
 
41
41
  // src/routes/thank-you/index.tsx
42
42
  var LazyThankYouPage = lazy(
43
- () => import('../ThankYouPage-7BN53JTK.js').then((m) => ({ default: m.ThankYouPage }))
43
+ () => import('../ThankYouPage-ZTCFTEI7.js').then((m) => ({ default: m.ThankYouPage }))
44
44
  );
45
45
  var ThankYouPage = LazyThankYouPage;
46
46
  async function loader(ctx, extend) {
package/dist/skeleton.js CHANGED
@@ -1,19 +1,19 @@
1
1
  export { BlogSkeleton, BreadcrumbSkeleton, CartSkeleton, CustomerLayoutSkeleton, CustomerPageSkeleton, PageSkeleton, ProductCardSkeleton, ProductDetailSkeleton, ProductGridSkeleton, SkeletonPulse } from './chunk-N7CCSGZF.js';
2
- export { HomeSkeleton } from './chunk-347K33DP.js';
3
- import './chunk-NQVJ7NJ6.js';
2
+ export { HomeSkeleton } from './chunk-VGIK4BW6.js';
4
3
  import './chunk-TZ3E5BN4.js';
5
- import './chunk-GRV7ELSP.js';
6
- import './chunk-QYUYQPXN.js';
7
- import './chunk-FY573DJA.js';
4
+ import './chunk-W5K6YUA2.js';
5
+ import './chunk-Y43T7PJV.js';
6
+ import './chunk-HDO37URJ.js';
7
+ import './chunk-FAVZMJRY.js';
8
8
  import './chunk-342EPVXN.js';
9
- import './chunk-55VTMG2H.js';
10
- import './chunk-UEKIAED3.js';
9
+ import './chunk-UEQFXSTX.js';
10
+ import './chunk-3Q22KK7C.js';
11
11
  import './chunk-JKIRRMBU.js';
12
12
  import './chunk-2JV6WZ6O.js';
13
13
  import './chunk-UIOLSYKV.js';
14
14
  import './chunk-VVZNW5CB.js';
15
15
  import './chunk-2XGQSJKH.js';
16
- import './chunk-KBQXQKPZ.js';
16
+ import './chunk-SSPAMQRV.js';
17
17
  import './chunk-ZGHRSRDO.js';
18
18
  import './chunk-GOPUP26T.js';
19
19
  import './chunk-C5X6CVXC.js';
@@ -39,7 +39,7 @@ import './chunk-T72DAX7R.js';
39
39
  import './chunk-RJPPO3ET.js';
40
40
  import './chunk-Q7VWURUR.js';
41
41
  import './chunk-GU2KUQVD.js';
42
- import './chunk-WF7DYPR6.js';
42
+ import './chunk-SOPZ72BU.js';
43
43
  import './chunk-AXW67SY7.js';
44
44
  import './chunk-BYMOPN2S.js';
45
45
  import './chunk-SKLEJJ6M.js';
@@ -1 +1 @@
1
- {"version":3,"file":"earlyHints.d.ts","sourceRoot":"","sources":["../../../src/tanstack/middleware/earlyHints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAkDlE,eAAO,MAAM,oBAAoB,QAAO,oBA6EvC,CAAC"}
1
+ {"version":3,"file":"earlyHints.d.ts","sourceRoot":"","sources":["../../../src/tanstack/middleware/earlyHints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAiDlE,eAAO,MAAM,oBAAoB,QAAO,oBA6EvC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/tanstack/router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAKpD,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAMnF,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUhE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CAC7D;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAyC7D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzD;AAoED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,KAG7B,SAAS,GAAG,kRAOrB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,sCA4BlE;AAyID;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB,CAAC,EAAE,CAAC,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,mBAAmB,uGAyHzE;AAED,OAAO,QAAQ,wBAAwB,CAAC;IACtC,UAAU,QAAQ;QAChB,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;KACzC;IAED,UAAU,aAAc,SAAQ,oBAAoB;KAAG;CACxD"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/tanstack/router.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAMpD,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAMnF,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUhE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CAC7D;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAyC7D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzD;AAoED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,KAG7B,SAAS,GAAG,kRAOrB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,sCA4BlE;AAyID;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB,CAAC,EAAE,CAAC,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,mBAAmB,uGA0HzE;AAED,OAAO,QAAQ,wBAAwB,CAAC;IACtC,UAAU,QAAQ;QAChB,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;KACzC;IAED,UAAU,aAAc,SAAQ,oBAAoB;KAAG;CACxD"}
@@ -0,0 +1,3 @@
1
+ /** The router's query serialiser, writing `[]` keys back as repeated keys, as `<salla-filters>` does. */
2
+ export declare function stringifySearch(search: Record<string, unknown>): string;
3
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tanstack/search.ts"],"names":[],"mappings":"AAIA,yGAAyG;AACzG,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAevE"}
@@ -1 +1 @@
1
- {"version":3,"file":"locale-wrapper.d.ts","sourceRoot":"","sources":["../../../src/tanstack/templates/locale-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAmCzE"}
1
+ {"version":3,"file":"locale-wrapper.d.ts","sourceRoot":"","sources":["../../../src/tanstack/templates/locale-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CA4CzE"}
package/dist/tanstack.js CHANGED
@@ -1,7 +1,7 @@
1
- import { rootHead } from './chunk-6AV7RQ6H.js';
2
- export { tanstackDocumentAdapter as attrs, createRouter, createTwilightRootRoute, useTanstackDocumentAttrs as useAttrs } from './chunk-6AV7RQ6H.js';
3
- import { requestHostOf } from './chunk-OJPJP7ML.js';
4
- export { TanStackLinkAdapter, TanStackNavigationProvider, createTanStackLinkAdapter } from './chunk-OJPJP7ML.js';
1
+ import { rootHead } from './chunk-VAW73MFZ.js';
2
+ export { tanstackDocumentAdapter as attrs, createRouter, createTwilightRootRoute, useTanstackDocumentAttrs as useAttrs } from './chunk-VAW73MFZ.js';
3
+ import { requestHostOf } from './chunk-GNH3W6T4.js';
4
+ export { TanStackLinkAdapter, TanStackNavigationProvider, createTanStackLinkAdapter } from './chunk-GNH3W6T4.js';
5
5
  import './chunk-Z4Y55HWX.js';
6
6
  export { tanstackHeadAdapter as head, withHead } from './chunk-BE3JDKE2.js';
7
7
  import './chunk-5ZR2HKZ7.js';
@@ -9,10 +9,10 @@ import './chunk-GD26FI4J.js';
9
9
  import './chunk-EQ32CL4D.js';
10
10
  import './chunk-Q3COPV5Z.js';
11
11
  import './chunk-TZ3E5BN4.js';
12
- import './chunk-QYUYQPXN.js';
12
+ import './chunk-HDO37URJ.js';
13
13
  import './chunk-UIOLSYKV.js';
14
14
  import './chunk-2XGQSJKH.js';
15
- import './chunk-KBQXQKPZ.js';
15
+ import './chunk-SSPAMQRV.js';
16
16
  import './chunk-ZGHRSRDO.js';
17
17
  import './chunk-P3OPJL6I.js';
18
18
  import './chunk-WY4IYO3G.js';
@@ -46,7 +46,6 @@ var twilightMiddleware = (options) => {
46
46
  });
47
47
  };
48
48
  var CRITICAL_ASSETS = [
49
- { rel: "modulepreload", href: "https://cdn.assets.salla.network/static/lit/3.3.3/lit.js" },
50
49
  { rel: "preconnect", href: "https://api.salla.dev" },
51
50
  { rel: "preconnect", href: "https://cdn.salla.sa" },
52
51
  { rel: "preconnect", href: "https://cdn.assets.salla.network", crossOrigin: "anonymous" },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tanstack/middleware/twilight.ts","../src/tanstack/middleware/earlyHints.ts"],"names":["createMiddleware"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBO,IAAM,kBAAA,GAAqB,CAAC,OAAA,KAA8D;AAC/F,EAAA,MAAM,UAAA,GAAa,SAAS,UAAA,IAAc,sBAAA;AAE1C,EAAA,OAAO,kBAAiB,CAAE,MAAA,CAAO,CAAC,EAAE,OAAA,EAAS,MAAK,KAAM;AACtD,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACjD,IAAA,MAAM,SAAA,GAAY,uBAAA,CAAwB,YAAA,EAAc,UAAU,CAAA;AAClE,IAAA,MAAM,KAAA,GAAQ,wBAAwB,YAAY,CAAA;AAClD,IAAA,MAAM,WAAA,GAAc,cAAc,OAAO,CAAA;AAczC,IAAA,MAAM,EAAE,SAAS,SAAA,EAAU,GAAI,oBAAoB,OAAA,CAAQ,GAAA,EAAK,cAAc,WAAW,CAAA;AAKzF,IAAA,MAAM,SAAA,GAAY,uBAAA,CAAwB,OAAA,CAAQ,GAAA,EAAK,cAAc,WAAW,CAAA;AAEhF,IAAA,OAAO,sBAAA;AAAA,MACL,EAAE,SAAA,EAAW,KAAA,EAAO,OAAA,EAAS,SAAA,EAAW,WAAW,WAAA,EAAY;AAAA,MAC/D,MAAM,IAAA,CAAK,EAAE,SAAS,EAAE,SAAA,IAAa;AAAA,KACvC;AAAA,EACF,CAAC,CAAA;AACH;AC3CA,IAAM,eAAA,GAAkB;AAAA,EACtB,EAAE,GAAA,EAAK,eAAA,EAAiB,IAAA,EAAM,0DAAA,EAA2D;AAAA,EACzF,EAAE,GAAA,EAAK,YAAA,EAAc,IAAA,EAAM,uBAAA,EAAwB;AAAA,EACnD,EAAE,GAAA,EAAK,YAAA,EAAc,IAAA,EAAM,sBAAA,EAAuB;AAAA,EAClD,EAAE,GAAA,EAAK,YAAA,EAAc,IAAA,EAAM,kCAAA,EAAoC,aAAa,WAAA,EAAY;AAAA,EACxF,EAAE,GAAA,EAAK,YAAA,EAAc,IAAA,EAAM,2BAAA,EAA6B,aAAa,WAAA;AACvE,CAAA;AAGA,SAAS,cAAc,GAAA,EAAiC;AACtD,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,qBAAqB,CAAA;AAC7C,EAAA,OAAO,QAAQ,CAAC,CAAA;AAClB;AAGA,SAAS,gBAAgB,IAAA,EAA8C;AACrE,EAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA;AACjB,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,GAAA,EAAK,OAAO,IAAA;AAG1B,EAAA,IAAI,QAAQ,YAAA,EAAc;AACxB,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,IAAA,IAAI,KAAA,KAAU,SAAS,OAAO,IAAA;AAC9B,IAAA,OAAO,IAAI,IAAI,CAAA,wBAAA,CAAA;AAAA,EACjB;AAEA,EAAA,IAAI,QAAQ,SAAA,EAAW;AACrB,IAAA,MAAM,SAAS,IAAA,CAAK,EAAA;AACpB,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,IAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,CAAA,EAAI,IAAI,KAAK,aAAA,EAAe,CAAA,GAAA,EAAM,MAAM,CAAA,CAAE,CAAA;AACzD,IAAA,IAAI,MAAA,KAAW,MAAA,IAAU,IAAA,CAAK,WAAA,EAAa;AACzC,MAAA,KAAA,CAAM,KAAK,aAAa,CAAA;AAAA,IAC1B;AACA,IAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,EACxB;AAEA,EAAA,IAAI,QAAQ,eAAA,EAAiB;AAC3B,IAAA,OAAO,IAAI,IAAI,CAAA,oBAAA,CAAA;AAAA,EACjB;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,IAAM,uBAAuB,MAA4B;AAC9D,EAAA,IAAI,mBAAA,GAAuC,IAAA;AAE3C,EAAA,OAAOA,kBAAiB,CAAE,MAAA,CAAO,OAAO,EAAE,OAAA,EAAS,MAAK,KAAM;AAC5D,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,EAAK;AAE5B,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA,IAAK,EAAA;AAChD,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,WAAW,CAAA,IAAK,MAAA,KAAW,OAAO,OAAO,QAAA;AAC9D,IAAA,IAAI,EAAE,QAAA,YAAoB,QAAA,CAAA,EAAW,OAAO,QAAA;AAE5C,IAAA,MAAM,cAAwB,EAAC;AAG/B,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,MAAA,MAAM,MAAA,GAAS,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA;AACzC,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,MAAM,aAAa,QAAA,CAAS,EAAE,QAAQ,EAAE,MAAA,IAAU,CAAA;AAClD,QAAA,MAAM,KAAA,GAAS,UAAA,CAAW,KAAA,IAAuC,EAAC;AAClE,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,UAAA,MAAM,MAAA,GAAS,gBAAgB,IAAI,CAAA;AACnC,UAAA,IAAI,MAAA,EAAQ,WAAA,CAAY,IAAA,CAAK,MAAM,CAAA;AAAA,QACrC;AAAA,MACF;AAAA,IACF,SAAS,CAAA,EAAG;AAEV,MAAA,OAAA,CAAQ,KAAK,+BAAA,EAAiC,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,UAAU,CAAC,CAAA;AAChF,MAAA,KAAA,MAAW,SAAS,eAAA,EAAiB;AACnC,QAAA,MAAM,EAAA,GAAK,aAAA,IAAiB,KAAA,GAAQ,KAAA,CAAM,WAAA,GAAc,MAAA;AACxD,QAAA,WAAA,CAAY,IAAA,CAAK,CAAA,CAAA,EAAI,KAAA,CAAM,IAAI,CAAA,OAAA,EAAU,KAAA,CAAM,GAAG,CAAA,EAAG,EAAA,GAAK,eAAA,GAAkB,EAAE,CAAA,CAAE,CAAA;AAAA,MAClF;AAAA,IACF;AAGA,IAAA,IAAI,CAAC,mBAAA,EAAqB;AACxB,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,gBAAA,EAAiB;AAClC,QAAA,MAAM,aAAa,QAAA,CAAS,MAAA,CAAO,UAAU,CAAA,EAAG,UAAU,EAAC;AAC3D,QAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,QAAA,mBAAA,GAAsB,EAAC;AACvB,QAAA,KAAA,MAAW,SAAS,UAAA,EAAY;AAC9B,UAAA,IAAI,KAAA,CAAM,QAAQ,MAAA,IAAU,KAAA,CAAM,OAAO,IAAA,EAAM,QAAA,CAAS,MAAM,CAAA,EAAG;AAC/D,YAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA,EAAG;AAC/B,cAAA,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA;AACzB,cAAA,mBAAA,CAAoB,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA;AAAA,YAC3C;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,CAAA,EAAG;AAEV,QAAA,OAAA,CAAQ,KAAK,uCAAA,EAAyC,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,UAAU,CAAC,CAAA;AAAA,MAC1F;AAAA,IACF;AAEA,IAAA,IAAI,mBAAA,EAAqB;AACvB,MAAA,KAAA,MAAW,QAAQ,mBAAA,EAAqB;AACtC,QAAA,WAAA,CAAY,IAAA,CAAK,CAAA,CAAA,EAAI,IAAI,CAAA,wBAAA,CAA0B,CAAA;AAAA,MACrD;AAAA,IACF;AAGA,IAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC5B,MAAA,OAAA,CAAQ,KAAK,oEAA+D,CAAA;AAC5E,MAAA,OAAO,QAAA;AAAA,IACT;AAEA,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,QAAA,CAAS,OAAO,CAAA;AAC5C,IAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,MAAA,OAAA,CAAQ,MAAA,CAAO,QAAQ,UAAU,CAAA;AAAA,IACnC;AAEA,IAAA,OAAO,IAAI,QAAA,CAAS,QAAA,CAAS,IAAA,EAAM;AAAA,MACjC,QAAQ,QAAA,CAAS,MAAA;AAAA,MACjB,YAAY,QAAA,CAAS,UAAA;AAAA,MACrB;AAAA,KACD,CAAA;AAAA,EACH,CAAC,CAAA;AACH","file":"tanstack.js","sourcesContent":["import type { AnyRequestMiddleware } from '@tanstack/react-start';\nimport { createMiddleware } from '@tanstack/react-start';\nimport {\n extractTokenFromCookies,\n extractScopeFromCookies,\n resolveRequestStore,\n resolveRequestVersionId,\n AUTH_TOKEN_COOKIE_NAME,\n} from '../../utils/cookies';\nimport { runWithTwilightContext } from '../../twilight/context';\nimport { requestHostOf } from '../../utils/request-host';\n\ninterface TwilightMiddlewareOptions {\n cookieName?: string;\n}\n\nexport const twilightMiddleware = (options?: TwilightMiddlewareOptions): AnyRequestMiddleware => {\n const cookieName = options?.cookieName ?? AUTH_TOKEN_COOKIE_NAME;\n\n return createMiddleware().server(({ request, next }) => {\n const cookieHeader = request.headers.get('Cookie');\n const authToken = extractTokenFromCookies(cookieHeader, cookieName);\n const scope = extractScopeFromCookies(cookieHeader);\n const requestHost = requestHostOf(request);\n // Read here and nowhere else: a deployed theme worker has no vars and no\n // bindings, so the request is the only thing that knows which store it is\n // serving. Everything downstream reads it off the context rather than\n // reaching for a build-time constant that is not there in production.\n //\n // The host goes in because it decides whether the request is allowed to name\n // a store at all. On a merchant's own domain it is not: the hostname is the\n // store, and `?storeId=` there would serve a stranger's shop from a domain\n // its owner controls.\n //\n // On those same hosts the store is also the first segment of the path, the\n // root of every URL there, and a store named that way takes the cookie's\n // place: the path is the address the visitor can see.\n const { storeId, storeBase } = resolveRequestStore(request.url, cookieHeader, requestHost);\n // The version is read here for the same reason and behind the same gate. A\n // theme editor previews a draft version of a merchant's settings before it is\n // published, and a partner running the theme locally renders against one —\n // both open the storefront in an iframe and say which version in the URL.\n const versionId = resolveRequestVersionId(request.url, cookieHeader, requestHost);\n\n return runWithTwilightContext(\n { authToken, scope, storeId, storeBase, versionId, requestHost },\n () => next({ context: { authToken } })\n );\n });\n};\n","import type { AnyRequestMiddleware } from '@tanstack/react-start';\nimport { createMiddleware } from '@tanstack/react-start';\nimport { tsrStartManifest } from 'tanstack-start-manifest:v';\nimport { rootHead } from '../../routes/root/head';\n\n/** Known critical assets that should always be preloaded */\nconst CRITICAL_ASSETS = [\n { rel: 'modulepreload', href: 'https://cdn.assets.salla.network/static/lit/3.3.3/lit.js' },\n { rel: 'preconnect', href: 'https://api.salla.dev' },\n { rel: 'preconnect', href: 'https://cdn.salla.sa' },\n { rel: 'preconnect', href: 'https://cdn.assets.salla.network', crossOrigin: 'anonymous' },\n { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossOrigin: 'anonymous' },\n] as const;\n\n/** Extract locale from URL path (e.g., /ar/products → 'ar') */\nfunction extractLocale(url: string): string | undefined {\n const match = url.match(/^\\/([a-z]{2})(\\/|$)/);\n return match?.[1];\n}\n\n/** Build Link header value from a link descriptor */\nfunction buildLinkHeader(link: Record<string, unknown>): string | null {\n const href = link.href as string | undefined;\n const rel = link.rel as string | undefined;\n if (!href || !rel) return null;\n\n // Skip print-media stylesheets (already non-blocking)\n if (rel === 'stylesheet') {\n const media = link.media as string | undefined;\n if (media === 'print') return null;\n return `<${href}>; rel=preload; as=style`;\n }\n\n if (rel === 'preload') {\n const asType = link.as as string | undefined;\n if (!asType) return null;\n const parts = [`<${href}>`, 'rel=preload', `as=${asType}`];\n if (asType === 'font' || link.crossOrigin) {\n parts.push('crossorigin');\n }\n return parts.join('; ');\n }\n\n if (rel === 'modulepreload') {\n return `<${href}>; rel=modulepreload`;\n }\n\n return null;\n}\n\nexport const earlyHintsMiddleware = (): AnyRequestMiddleware => {\n let cachedManifestPaths: string[] | null = null;\n\n return createMiddleware().server(async ({ request, next }) => {\n const response = await next();\n\n const accept = request.headers.get('Accept') ?? '';\n if (!accept.includes('text/html') && accept !== '*/*') return response;\n if (!(response instanceof Response)) return response;\n\n const linkHeaders: string[] = [];\n\n // 1. Add critical assets from rootHead (fonts, icons, SDK, etc.)\n try {\n const url = new URL(request.url);\n const locale = extractLocale(url.pathname);\n if (locale) {\n const headResult = rootHead({ params: { locale } });\n const links = (headResult.links as Record<string, unknown>[]) ?? [];\n for (const link of links) {\n const header = buildLinkHeader(link);\n if (header) linkHeaders.push(header);\n }\n }\n } catch (e) {\n // rootHead failed — log why, then fall back to known critical assets\n console.warn('[earlyHints] rootHead failed:', e instanceof Error ? e.message : e);\n for (const asset of CRITICAL_ASSETS) {\n const co = 'crossOrigin' in asset ? asset.crossOrigin : undefined;\n linkHeaders.push(`<${asset.href}>; rel=${asset.rel}${co ? '; crossorigin' : ''}`);\n }\n }\n\n // 2. Add CSS from TanStack Start manifest (bundled theme CSS)\n if (!cachedManifestPaths) {\n try {\n const manifest = tsrStartManifest();\n const rootAssets = manifest.routes['__root__']?.assets ?? [];\n const seen = new Set<string>();\n cachedManifestPaths = [];\n for (const asset of rootAssets) {\n if (asset.tag === 'link' && asset.attrs?.href?.endsWith('.css')) {\n if (!seen.has(asset.attrs.href)) {\n seen.add(asset.attrs.href);\n cachedManifestPaths.push(asset.attrs.href);\n }\n }\n }\n } catch (e) {\n // manifest not available — skip\n console.warn('[earlyHints] tsrStartManifest failed:', e instanceof Error ? e.message : e);\n }\n }\n\n if (cachedManifestPaths) {\n for (const href of cachedManifestPaths) {\n linkHeaders.push(`<${href}>; rel=preload; as=style`);\n }\n }\n\n // Apply Link headers if we have any\n if (linkHeaders.length === 0) {\n console.warn('[earlyHints] no critical assets found — no Link headers added');\n return response;\n }\n\n const headers = new Headers(response.headers);\n for (const linkHeader of linkHeaders) {\n headers.append('Link', linkHeader);\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n });\n};\n"]}
1
+ {"version":3,"sources":["../src/tanstack/middleware/twilight.ts","../src/tanstack/middleware/earlyHints.ts"],"names":["createMiddleware"],"mappings":"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","file":"tanstack.js","sourcesContent":["import type { AnyRequestMiddleware } from '@tanstack/react-start';\nimport { createMiddleware } from '@tanstack/react-start';\nimport {\n extractTokenFromCookies,\n extractScopeFromCookies,\n resolveRequestStore,\n resolveRequestVersionId,\n AUTH_TOKEN_COOKIE_NAME,\n} from '../../utils/cookies';\nimport { runWithTwilightContext } from '../../twilight/context';\nimport { requestHostOf } from '../../utils/request-host';\n\ninterface TwilightMiddlewareOptions {\n cookieName?: string;\n}\n\nexport const twilightMiddleware = (options?: TwilightMiddlewareOptions): AnyRequestMiddleware => {\n const cookieName = options?.cookieName ?? AUTH_TOKEN_COOKIE_NAME;\n\n return createMiddleware().server(({ request, next }) => {\n const cookieHeader = request.headers.get('Cookie');\n const authToken = extractTokenFromCookies(cookieHeader, cookieName);\n const scope = extractScopeFromCookies(cookieHeader);\n const requestHost = requestHostOf(request);\n // Read here and nowhere else: a deployed theme worker has no vars and no\n // bindings, so the request is the only thing that knows which store it is\n // serving. Everything downstream reads it off the context rather than\n // reaching for a build-time constant that is not there in production.\n //\n // The host goes in because it decides whether the request is allowed to name\n // a store at all. On a merchant's own domain it is not: the hostname is the\n // store, and `?storeId=` there would serve a stranger's shop from a domain\n // its owner controls.\n //\n // On those same hosts the store is also the first segment of the path, the\n // root of every URL there, and a store named that way takes the cookie's\n // place: the path is the address the visitor can see.\n const { storeId, storeBase } = resolveRequestStore(request.url, cookieHeader, requestHost);\n // The version is read here for the same reason and behind the same gate. A\n // theme editor previews a draft version of a merchant's settings before it is\n // published, and a partner running the theme locally renders against one —\n // both open the storefront in an iframe and say which version in the URL.\n const versionId = resolveRequestVersionId(request.url, cookieHeader, requestHost);\n\n return runWithTwilightContext(\n { authToken, scope, storeId, storeBase, versionId, requestHost },\n () => next({ context: { authToken } })\n );\n });\n};\n","import type { AnyRequestMiddleware } from '@tanstack/react-start';\nimport { createMiddleware } from '@tanstack/react-start';\nimport { tsrStartManifest } from 'tanstack-start-manifest:v';\nimport { rootHead } from '../../routes/root/head';\n\n/** Known critical assets that should always be preloaded */\nconst CRITICAL_ASSETS = [\n { rel: 'preconnect', href: 'https://api.salla.dev' },\n { rel: 'preconnect', href: 'https://cdn.salla.sa' },\n { rel: 'preconnect', href: 'https://cdn.assets.salla.network', crossOrigin: 'anonymous' },\n { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossOrigin: 'anonymous' },\n] as const;\n\n/** Extract locale from URL path (e.g., /ar/products → 'ar') */\nfunction extractLocale(url: string): string | undefined {\n const match = url.match(/^\\/([a-z]{2})(\\/|$)/);\n return match?.[1];\n}\n\n/** Build Link header value from a link descriptor */\nfunction buildLinkHeader(link: Record<string, unknown>): string | null {\n const href = link.href as string | undefined;\n const rel = link.rel as string | undefined;\n if (!href || !rel) return null;\n\n // Skip print-media stylesheets (already non-blocking)\n if (rel === 'stylesheet') {\n const media = link.media as string | undefined;\n if (media === 'print') return null;\n return `<${href}>; rel=preload; as=style`;\n }\n\n if (rel === 'preload') {\n const asType = link.as as string | undefined;\n if (!asType) return null;\n const parts = [`<${href}>`, 'rel=preload', `as=${asType}`];\n if (asType === 'font' || link.crossOrigin) {\n parts.push('crossorigin');\n }\n return parts.join('; ');\n }\n\n if (rel === 'modulepreload') {\n return `<${href}>; rel=modulepreload`;\n }\n\n return null;\n}\n\nexport const earlyHintsMiddleware = (): AnyRequestMiddleware => {\n let cachedManifestPaths: string[] | null = null;\n\n return createMiddleware().server(async ({ request, next }) => {\n const response = await next();\n\n const accept = request.headers.get('Accept') ?? '';\n if (!accept.includes('text/html') && accept !== '*/*') return response;\n if (!(response instanceof Response)) return response;\n\n const linkHeaders: string[] = [];\n\n // 1. Add critical assets from rootHead (fonts, icons, SDK, etc.)\n try {\n const url = new URL(request.url);\n const locale = extractLocale(url.pathname);\n if (locale) {\n const headResult = rootHead({ params: { locale } });\n const links = (headResult.links as Record<string, unknown>[]) ?? [];\n for (const link of links) {\n const header = buildLinkHeader(link);\n if (header) linkHeaders.push(header);\n }\n }\n } catch (e) {\n // rootHead failed — log why, then fall back to known critical assets\n console.warn('[earlyHints] rootHead failed:', e instanceof Error ? e.message : e);\n for (const asset of CRITICAL_ASSETS) {\n const co = 'crossOrigin' in asset ? asset.crossOrigin : undefined;\n linkHeaders.push(`<${asset.href}>; rel=${asset.rel}${co ? '; crossorigin' : ''}`);\n }\n }\n\n // 2. Add CSS from TanStack Start manifest (bundled theme CSS)\n if (!cachedManifestPaths) {\n try {\n const manifest = tsrStartManifest();\n const rootAssets = manifest.routes['__root__']?.assets ?? [];\n const seen = new Set<string>();\n cachedManifestPaths = [];\n for (const asset of rootAssets) {\n if (asset.tag === 'link' && asset.attrs?.href?.endsWith('.css')) {\n if (!seen.has(asset.attrs.href)) {\n seen.add(asset.attrs.href);\n cachedManifestPaths.push(asset.attrs.href);\n }\n }\n }\n } catch (e) {\n // manifest not available — skip\n console.warn('[earlyHints] tsrStartManifest failed:', e instanceof Error ? e.message : e);\n }\n }\n\n if (cachedManifestPaths) {\n for (const href of cachedManifestPaths) {\n linkHeaders.push(`<${href}>; rel=preload; as=style`);\n }\n }\n\n // Apply Link headers if we have any\n if (linkHeaders.length === 0) {\n console.warn('[earlyHints] no critical assets found — no Link headers added');\n return response;\n }\n\n const headers = new Headers(response.headers);\n for (const linkHeader of linkHeaders) {\n headers.append('Link', linkHeader);\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n });\n};\n"]}