@mohasinac/appkit 2.7.27 → 2.7.31

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 (397) hide show
  1. package/dist/_internal/client/features/filters/filter-load-options.d.ts +29 -0
  2. package/dist/_internal/client/features/filters/filter-load-options.js +98 -0
  3. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
  4. package/dist/_internal/server/features/checkout/actions.js +42 -35
  5. package/dist/_internal/server/features/classified/adapters.d.ts +21 -0
  6. package/dist/_internal/server/features/classified/adapters.js +24 -0
  7. package/dist/_internal/server/features/classified/index.d.ts +3 -0
  8. package/dist/_internal/server/features/classified/index.js +3 -0
  9. package/dist/_internal/server/features/classified/metadata.d.ts +8 -0
  10. package/dist/_internal/server/features/classified/metadata.js +43 -0
  11. package/dist/_internal/server/features/classified/og.d.ts +30 -0
  12. package/dist/_internal/server/features/classified/og.js +76 -0
  13. package/dist/_internal/server/features/digital-code/adapters.d.ts +21 -0
  14. package/dist/_internal/server/features/digital-code/adapters.js +29 -0
  15. package/dist/_internal/server/features/digital-code/index.d.ts +3 -0
  16. package/dist/_internal/server/features/digital-code/index.js +3 -0
  17. package/dist/_internal/server/features/digital-code/metadata.d.ts +8 -0
  18. package/dist/_internal/server/features/digital-code/metadata.js +36 -0
  19. package/dist/_internal/server/features/digital-code/og.d.ts +27 -0
  20. package/dist/_internal/server/features/digital-code/og.js +77 -0
  21. package/dist/_internal/server/features/live/adapters.d.ts +21 -0
  22. package/dist/_internal/server/features/live/adapters.js +34 -0
  23. package/dist/_internal/server/features/live/index.d.ts +3 -0
  24. package/dist/_internal/server/features/live/index.js +3 -0
  25. package/dist/_internal/server/features/live/metadata.d.ts +8 -0
  26. package/dist/_internal/server/features/live/metadata.js +39 -0
  27. package/dist/_internal/server/features/live/og.d.ts +27 -0
  28. package/dist/_internal/server/features/live/og.js +72 -0
  29. package/dist/_internal/server/features/promotions/actions.js +4 -3
  30. package/dist/_internal/server/jobs/core/onOrderCreate.js +19 -16
  31. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +25 -22
  32. package/dist/_internal/server/jobs/core/onProductWrite.js +48 -58
  33. package/dist/_internal/shared/actions/action-registry.js +504 -9
  34. package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
  35. package/dist/_internal/shared/features/brands/schema.d.ts +5 -5
  36. package/dist/_internal/shared/features/cart/schema.d.ts +18 -18
  37. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  38. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +38 -38
  39. package/dist/_internal/shared/features/events/schema.d.ts +8 -8
  40. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  41. package/dist/_internal/shared/features/products/schema.d.ts +42 -42
  42. package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
  43. package/dist/_internal/shared/features/reviews/schema.d.ts +1 -1
  44. package/dist/_internal/shared/media/limits.js +4 -3
  45. package/dist/client.d.ts +4 -0
  46. package/dist/client.js +2 -0
  47. package/dist/configs/next.js +4 -0
  48. package/dist/constants/api-endpoints.d.ts +6 -0
  49. package/dist/constants/api-endpoints.js +2 -0
  50. package/dist/constants/field-names.d.ts +1 -0
  51. package/dist/constants/field-names.js +1 -0
  52. package/dist/constants/table-keys.d.ts +6 -0
  53. package/dist/constants/table-keys.js +9 -0
  54. package/dist/core/hooks/useSyncManager.js +9 -8
  55. package/dist/features/about/components/FeesView.js +10 -7
  56. package/dist/features/about/components/HelpPageView.js +10 -1
  57. package/dist/features/about/components/HowAuctionsWorkView.js +10 -1
  58. package/dist/features/about/components/HowCheckoutWorksView.js +10 -1
  59. package/dist/features/about/components/HowOffersWorkView.js +10 -1
  60. package/dist/features/about/components/HowOrdersWorkView.js +10 -1
  61. package/dist/features/about/components/HowPayoutsWorkView.js +10 -1
  62. package/dist/features/about/components/HowPreOrdersWorkView.js +10 -1
  63. package/dist/features/about/components/HowReviewsWorkView.js +10 -1
  64. package/dist/features/about/components/PublicProfileView.js +46 -16
  65. package/dist/features/about/components/SecurityPrivacyView.js +7 -1
  66. package/dist/features/account/components/AddressesIndexListing.js +2 -2
  67. package/dist/features/account/components/NotificationBell.js +27 -16
  68. package/dist/features/account/components/NotificationPreferencesPanel.d.ts +9 -0
  69. package/dist/features/account/components/NotificationPreferencesPanel.js +91 -0
  70. package/dist/features/account/components/UserSidebar.js +4 -4
  71. package/dist/features/account/components/UserSupportView.js +16 -6
  72. package/dist/features/account/components/index.d.ts +2 -0
  73. package/dist/features/account/components/index.js +1 -0
  74. package/dist/features/account/schemas/index.d.ts +4 -4
  75. package/dist/features/account/types/index.d.ts +34 -0
  76. package/dist/features/admin/actions/admin-actions.js +4 -3
  77. package/dist/features/admin/actions/notification-actions.d.ts +24 -22
  78. package/dist/features/admin/actions/notification-actions.js +122 -22
  79. package/dist/features/admin/components/AdminAdEditorView.js +29 -15
  80. package/dist/features/admin/components/AdminAddressEditorView.d.ts +7 -0
  81. package/dist/features/admin/components/AdminAddressEditorView.js +117 -0
  82. package/dist/features/admin/components/AdminAdsView.js +22 -28
  83. package/dist/features/admin/components/AdminAllEventEntriesView.js +6 -1
  84. package/dist/features/admin/components/AdminBidsView.js +10 -3
  85. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  86. package/dist/features/admin/components/AdminBlogView.js +8 -3
  87. package/dist/features/admin/components/AdminBrandsView.js +7 -2
  88. package/dist/features/admin/components/AdminBundleEditorView.js +5 -2
  89. package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
  90. package/dist/features/admin/components/AdminCarouselView.js +13 -7
  91. package/dist/features/admin/components/AdminCategoriesView.js +8 -3
  92. package/dist/features/admin/components/AdminCategoryEditorView.js +12 -9
  93. package/dist/features/admin/components/AdminContactView.js +6 -1
  94. package/dist/features/admin/components/AdminCouponEditorView.js +8 -2
  95. package/dist/features/admin/components/AdminCouponsView.js +6 -1
  96. package/dist/features/admin/components/AdminEmployeeEditorView.js +12 -9
  97. package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
  98. package/dist/features/admin/components/AdminFaqsView.js +7 -2
  99. package/dist/features/admin/components/AdminFeatureFlagsView.js +58 -13
  100. package/dist/features/admin/components/AdminFeaturesView.js +4 -3
  101. package/dist/features/admin/components/AdminMediaView.js +9 -8
  102. package/dist/features/admin/components/AdminNavigationView.js +10 -17
  103. package/dist/features/admin/components/AdminNewsletterView.js +6 -1
  104. package/dist/features/admin/components/AdminNotificationsView.js +11 -3
  105. package/dist/features/admin/components/AdminOrdersView.js +6 -1
  106. package/dist/features/admin/components/AdminPayoutsView.js +10 -3
  107. package/dist/features/admin/components/AdminPrizeDrawsView.js +10 -3
  108. package/dist/features/admin/components/AdminProductEditorView.d.ts +3 -1
  109. package/dist/features/admin/components/AdminProductEditorView.js +12 -9
  110. package/dist/features/admin/components/AdminProductsView.js +18 -12
  111. package/dist/features/admin/components/AdminReturnRequestsView.js +5 -4
  112. package/dist/features/admin/components/AdminReviewsView.js +36 -26
  113. package/dist/features/admin/components/AdminScammerEditorView.js +3 -2
  114. package/dist/features/admin/components/AdminScammersView.js +28 -26
  115. package/dist/features/admin/components/AdminSectionsView.js +112 -99
  116. package/dist/features/admin/components/AdminSessionsView.js +10 -3
  117. package/dist/features/admin/components/AdminSidebar.js +4 -4
  118. package/dist/features/admin/components/AdminSiteSettingsView.js +45 -4
  119. package/dist/features/admin/components/AdminStoresView.js +6 -1
  120. package/dist/features/admin/components/AdminSublistingCategoriesView.js +0 -1
  121. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  122. package/dist/features/admin/components/AdminSupportTicketsView.js +32 -34
  123. package/dist/features/admin/components/AdminTeamView.js +6 -1
  124. package/dist/features/admin/components/AdminUserEditorView.js +8 -15
  125. package/dist/features/admin/components/AdminUsersView.js +6 -1
  126. package/dist/features/admin/components/AdminViewCards.js +4 -3
  127. package/dist/features/admin/components/DashboardStats.js +2 -2
  128. package/dist/features/admin/components/DataTable.js +2 -2
  129. package/dist/features/admin/components/index.d.ts +2 -0
  130. package/dist/features/admin/components/index.js +1 -0
  131. package/dist/features/admin/components/sections/adminSectionsTypes.js +4 -3
  132. package/dist/features/admin/repository/chat.repository.js +8 -8
  133. package/dist/features/admin/repository/site-settings.repository.d.ts +1 -0
  134. package/dist/features/admin/repository/site-settings.repository.js +11 -9
  135. package/dist/features/admin/schemas/firestore.d.ts +38 -0
  136. package/dist/features/admin/schemas/firestore.js +15 -0
  137. package/dist/features/auctions/components/AuctionBidsTable.d.ts +13 -0
  138. package/dist/features/auctions/components/AuctionBidsTable.js +62 -0
  139. package/dist/features/auctions/components/AuctionDetailPageView.js +15 -21
  140. package/dist/features/auctions/components/AuctionFilters.d.ts +7 -1
  141. package/dist/features/auctions/components/AuctionFilters.js +3 -2
  142. package/dist/features/auctions/components/MarketplaceAuctionCard.js +18 -9
  143. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +3 -2
  144. package/dist/features/auctions/components/index.d.ts +2 -1
  145. package/dist/features/auctions/components/index.js +1 -1
  146. package/dist/features/auctions/schemas/index.d.ts +14 -14
  147. package/dist/features/auth/actions/realtime-token-actions.js +19 -4
  148. package/dist/features/auth/components/RegisterForm.js +8 -4
  149. package/dist/features/auth/consent-otp.d.ts +2 -0
  150. package/dist/features/auth/consent-otp.js +8 -0
  151. package/dist/features/auth/schemas/firestore.d.ts +2 -0
  152. package/dist/features/auth/schemas/firestore.js +18 -25
  153. package/dist/features/auth/schemas/index.d.ts +2 -2
  154. package/dist/features/before-after/api/[id]/route.js +8 -6
  155. package/dist/features/before-after/schemas/index.d.ts +2 -2
  156. package/dist/features/blog/actions/blog-actions.d.ts +3 -3
  157. package/dist/features/blog/components/BlogIndexListing.js +21 -2
  158. package/dist/features/blog/components/BlogPostForm.js +11 -5
  159. package/dist/features/blog/components/BlogPostView.js +10 -2
  160. package/dist/features/blog/schemas/index.d.ts +18 -18
  161. package/dist/features/cart/components/CartDrawer.js +3 -2
  162. package/dist/features/cart/components/CartView.js +2 -1
  163. package/dist/features/cart/components/CheckoutView.js +2 -1
  164. package/dist/features/cart/repository/cart.repository.js +4 -3
  165. package/dist/features/cart/utils/pending-ops.d.ts +1 -1
  166. package/dist/features/categories/api/[id]/route.js +4 -3
  167. package/dist/features/categories/api/route.js +4 -3
  168. package/dist/features/categories/components/BrandDetailPageView.js +2 -2
  169. package/dist/features/categories/components/BrandDetailTabs.d.ts +5 -1
  170. package/dist/features/categories/components/BrandDetailTabs.js +30 -16
  171. package/dist/features/categories/components/BundleCollage.d.ts +8 -0
  172. package/dist/features/categories/components/BundleCollage.js +50 -0
  173. package/dist/features/categories/components/BundleDetailView.js +2 -10
  174. package/dist/features/categories/components/BundleItemsPicker.js +20 -13
  175. package/dist/features/categories/components/CategoriesIndexListing.js +28 -9
  176. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  177. package/dist/features/categories/components/CategoryDetailTabs.d.ts +5 -1
  178. package/dist/features/categories/components/CategoryDetailTabs.js +31 -16
  179. package/dist/features/categories/components/CategoryProductsListing.js +52 -13
  180. package/dist/features/categories/components/index.d.ts +2 -0
  181. package/dist/features/categories/components/index.js +1 -0
  182. package/dist/features/categories/schemas/index.d.ts +6 -6
  183. package/dist/features/checkout/actions/checkout-actions.js +4 -3
  184. package/dist/features/checkout/hooks/usePaymentCheckout.js +31 -22
  185. package/dist/features/classified/components/ClassifiedFilters.d.ts +12 -0
  186. package/dist/features/classified/components/ClassifiedFilters.js +20 -0
  187. package/dist/features/classified/components/ClassifiedIndexListing.d.ts +4 -0
  188. package/dist/features/classified/components/ClassifiedIndexListing.js +110 -0
  189. package/dist/features/classified/components/ClassifiedListView.d.ts +6 -0
  190. package/dist/features/classified/components/ClassifiedListView.js +43 -0
  191. package/dist/features/classified/components/index.d.ts +6 -0
  192. package/dist/features/classified/components/index.js +3 -0
  193. package/dist/features/collections/api/[slug]/route.js +16 -12
  194. package/dist/features/collections/schemas/index.d.ts +5 -5
  195. package/dist/features/consultation/api/[id]/route.js +12 -9
  196. package/dist/features/consultation/components/ConsultationForm.js +3 -2
  197. package/dist/features/consultation/schemas/index.d.ts +6 -6
  198. package/dist/features/contact/email.js +77 -116
  199. package/dist/features/copilot/components/AdminCopilotView.js +12 -2
  200. package/dist/features/corporate/api/[id]/route.js +12 -9
  201. package/dist/features/corporate/components/CorporateInquiryForm.js +2 -1
  202. package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +12 -0
  203. package/dist/features/digital-codes/components/DigitalCodeFilters.js +17 -0
  204. package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +4 -0
  205. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +107 -0
  206. package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +6 -0
  207. package/dist/features/digital-codes/components/DigitalCodesListView.js +37 -0
  208. package/dist/features/digital-codes/components/index.d.ts +6 -0
  209. package/dist/features/digital-codes/components/index.js +3 -0
  210. package/dist/features/events/actions/event-actions.js +4 -3
  211. package/dist/features/events/components/AdminEventEditorView.js +3 -2
  212. package/dist/features/events/components/AdminEventsView.js +4 -2
  213. package/dist/features/events/components/EventPollWidget.js +5 -5
  214. package/dist/features/events/components/EventsIndexListing.js +2 -2
  215. package/dist/features/events/repository/event-entry.repository.d.ts +1 -0
  216. package/dist/features/events/repository/event-entry.repository.js +5 -0
  217. package/dist/features/events/schemas/index.d.ts +20 -20
  218. package/dist/features/faq/actions/faq-actions.d.ts +8 -8
  219. package/dist/features/faq/components/ContactCTA.js +3 -1
  220. package/dist/features/faq/components/FAQAccordion.js +1 -1
  221. package/dist/features/faq/schemas/index.d.ts +4 -4
  222. package/dist/features/filters/AsyncFacetSection.d.ts +18 -0
  223. package/dist/features/filters/AsyncFacetSection.js +65 -0
  224. package/dist/features/filters/index.d.ts +2 -0
  225. package/dist/features/filters/index.js +1 -0
  226. package/dist/features/forms/Checkbox.js +2 -2
  227. package/dist/features/forms/Input.js +2 -2
  228. package/dist/features/forms/Radio.js +5 -5
  229. package/dist/features/forms/Select.js +2 -2
  230. package/dist/features/forms/Slider.js +2 -2
  231. package/dist/features/forms/Textarea.js +2 -2
  232. package/dist/features/homepage/api/[id]/route.js +4 -3
  233. package/dist/features/homepage/api/sections/[id]/route.js +12 -9
  234. package/dist/features/homepage/components/AdSlot.js +2 -1
  235. package/dist/features/homepage/components/AdvertisementBanner.js +5 -3
  236. package/dist/features/homepage/components/BrandsSection.js +2 -2
  237. package/dist/features/homepage/components/CTABannerSection.js +2 -2
  238. package/dist/features/homepage/components/CharacterHotspot.d.ts +2 -2
  239. package/dist/features/homepage/components/CharacterHotspot.js +119 -157
  240. package/dist/features/homepage/components/CharacterHotspotForm.js +25 -20
  241. package/dist/features/homepage/components/CustomCardsSection.js +8 -6
  242. package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
  243. package/dist/features/homepage/components/GoogleReviewsSection.js +3 -3
  244. package/dist/features/homepage/components/HeroBanner.js +5 -4
  245. package/dist/features/homepage/components/HeroCarousel.js +13 -26
  246. package/dist/features/homepage/components/HowItWorksSection.js +4 -2
  247. package/dist/features/homepage/components/SocialFeedSection.js +2 -2
  248. package/dist/features/homepage/components/SocialPostCard.js +3 -2
  249. package/dist/features/homepage/lib/social-feed-fetcher.js +6 -3
  250. package/dist/features/layout/AppLayoutShell.d.ts +8 -2
  251. package/dist/features/layout/AppLayoutShell.js +54 -78
  252. package/dist/features/layout/BottomActions.js +43 -48
  253. package/dist/features/live/components/LiveItemFilters.d.ts +12 -0
  254. package/dist/features/live/components/LiveItemFilters.js +24 -0
  255. package/dist/features/live/components/LiveItemsIndexListing.d.ts +4 -0
  256. package/dist/features/live/components/LiveItemsIndexListing.js +108 -0
  257. package/dist/features/live/components/LiveItemsListView.d.ts +6 -0
  258. package/dist/features/live/components/LiveItemsListView.js +43 -0
  259. package/dist/features/live/components/index.d.ts +6 -0
  260. package/dist/features/live/components/index.js +3 -0
  261. package/dist/features/media/MediaLightbox.js +8 -14
  262. package/dist/features/media/types/index.d.ts +2 -2
  263. package/dist/features/media/upload/CameraCapture.js +2 -2
  264. package/dist/features/media/upload/ImageUpload.js +4 -2
  265. package/dist/features/media/upload/MediaUploadField.js +24 -8
  266. package/dist/features/media/upload/MediaUploadList.js +1 -1
  267. package/dist/features/orders/actions/order-actions.js +4 -3
  268. package/dist/features/orders/components/MarketplaceOrderCard.js +2 -1
  269. package/dist/features/orders/components/OrderFilters.js +12 -9
  270. package/dist/features/orders/schemas/index.d.ts +6 -6
  271. package/dist/features/pre-orders/api/[id]/route.js +12 -9
  272. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -4
  273. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +29 -22
  274. package/dist/features/pre-orders/components/PreOrderFilters.d.ts +7 -1
  275. package/dist/features/pre-orders/components/PreOrderFilters.js +3 -2
  276. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +17 -52
  277. package/dist/features/pre-orders/components/PreorderCard.d.ts +0 -9
  278. package/dist/features/pre-orders/components/PreorderCard.js +2 -13
  279. package/dist/features/pre-orders/components/index.d.ts +1 -1
  280. package/dist/features/pre-orders/components/index.js +1 -1
  281. package/dist/features/pre-orders/schemas/index.d.ts +10 -10
  282. package/dist/features/products/api/[id]/route.js +9 -7
  283. package/dist/features/products/api/route.js +1 -1
  284. package/dist/features/products/columns/productTableColumns.js +3 -3
  285. package/dist/features/products/components/AuctionsIndexListing.js +15 -51
  286. package/dist/features/products/components/BidHistory.js +2 -2
  287. package/dist/features/products/components/CompareOverlay.d.ts +2 -0
  288. package/dist/features/products/components/CompareOverlay.js +3 -2
  289. package/dist/features/products/components/MakeOfferButton.js +20 -14
  290. package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
  291. package/dist/features/products/components/PrizeDrawCollage.d.ts +1 -15
  292. package/dist/features/products/components/PrizeDrawCollage.js +54 -14
  293. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  294. package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
  295. package/dist/features/products/components/PrizeDrawItemsEditor.js +9 -7
  296. package/dist/features/products/components/PrizeDrawsIndexListing.js +18 -51
  297. package/dist/features/products/components/PrizeRevealModal.js +24 -14
  298. package/dist/features/products/components/ProductDetailPageView.js +2 -1
  299. package/dist/features/products/components/ProductFilters.d.ts +7 -1
  300. package/dist/features/products/components/ProductFilters.js +11 -8
  301. package/dist/features/products/components/ProductForm.js +18 -16
  302. package/dist/features/products/components/ProductGalleryClient.js +2 -1
  303. package/dist/features/products/components/ProductGrid.js +12 -15
  304. package/dist/features/products/components/ProductsIndexListing.js +16 -52
  305. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  306. package/dist/features/products/repository/products.repository.d.ts +4 -0
  307. package/dist/features/products/repository/products.repository.js +22 -3
  308. package/dist/features/products/schemas/firestore.d.ts +7 -1
  309. package/dist/features/products/schemas/index.d.ts +56 -56
  310. package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
  311. package/dist/features/products/types/index.d.ts +4 -0
  312. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  313. package/dist/features/promotions/schemas/index.d.ts +6 -6
  314. package/dist/features/reviews/actions/review-actions.js +6 -5
  315. package/dist/features/reviews/api/[id]/route.js +4 -3
  316. package/dist/features/reviews/components/ReviewDetailPageView.js +2 -2
  317. package/dist/features/reviews/components/ReviewDetailShell.js +6 -3
  318. package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
  319. package/dist/features/reviews/schemas/index.d.ts +6 -6
  320. package/dist/features/scams/components/ScamProfileView.js +19 -10
  321. package/dist/features/scams/components/ScamRegistryView.js +2 -1
  322. package/dist/features/search/components/Search.d.ts +1 -1
  323. package/dist/features/search/components/Search.js +56 -49
  324. package/dist/features/search/schemas/index.d.ts +5 -5
  325. package/dist/features/seller/actions/offer-actions.js +11 -9
  326. package/dist/features/seller/components/SellerAddressesView.js +6 -4
  327. package/dist/features/seller/components/SellerBidsView.js +2 -2
  328. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  329. package/dist/features/seller/components/SellerOffersPanel.js +6 -1
  330. package/dist/features/seller/components/SellerOrdersView.js +1 -1
  331. package/dist/features/seller/components/SellerPayoutSettingsView.js +3 -3
  332. package/dist/features/seller/components/SellerPreOrdersView.js +5 -4
  333. package/dist/features/seller/components/SellerPrizeDrawsView.js +5 -4
  334. package/dist/features/seller/components/SellerProductShell.d.ts +19 -1
  335. package/dist/features/seller/components/SellerProductShell.js +75 -9
  336. package/dist/features/seller/components/SellerProductsView.js +10 -11
  337. package/dist/features/seller/components/SellerShippingView.js +3 -3
  338. package/dist/features/seller/components/SellerSidebar.js +10 -7
  339. package/dist/features/seller/components/SellerStorefrontView.js +3 -3
  340. package/dist/features/seller/schemas/index.d.ts +4 -4
  341. package/dist/features/shell/FormShell.js +2 -1
  342. package/dist/features/shell/QuickFormDrawer.js +4 -3
  343. package/dist/features/shell/StepForm.js +4 -3
  344. package/dist/features/stores/actions/store-query-actions.js +4 -3
  345. package/dist/features/stores/components/StoreAboutView.js +2 -1
  346. package/dist/features/stores/components/StoreAuctionsListing.js +43 -64
  347. package/dist/features/stores/components/StoreDetailLayoutView.js +18 -4
  348. package/dist/features/stores/components/StorePreOrdersListing.js +33 -57
  349. package/dist/features/stores/components/StoreProductsListing.js +16 -49
  350. package/dist/features/stores/components/StoresIndexListing.js +2 -2
  351. package/dist/features/stores/schemas/index.d.ts +2 -2
  352. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +8 -7
  353. package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +5 -5
  354. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +6 -6
  355. package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -5
  356. package/dist/index.d.ts +27 -3
  357. package/dist/index.js +1743 -1725
  358. package/dist/monitoring/server-logger.js +5 -9
  359. package/dist/next/api/apiHandler.js +56 -37
  360. package/dist/next/components/GlobalError.js +2 -1
  361. package/dist/next/routing/route-map.d.ts +41 -0
  362. package/dist/next/routing/route-map.js +17 -0
  363. package/dist/react/ErrorBoundary.js +2 -1
  364. package/dist/react/contexts/SessionContext.js +38 -28
  365. package/dist/react/hooks/useCamera.d.ts +1 -1
  366. package/dist/react/hooks/useCamera.js +8 -7
  367. package/dist/seed/products-auctions-seed-data.js +40 -40
  368. package/dist/seed/products-preorders-seed-data.js +16 -16
  369. package/dist/seed/products-prize-draws-seed-data.js +4 -4
  370. package/dist/seed/products-standard-seed-data.js +202 -202
  371. package/dist/seed/site-settings-seed-data.js +6 -0
  372. package/dist/server-entry.d.ts +3 -0
  373. package/dist/server-entry.js +3 -0
  374. package/dist/server.d.ts +12 -0
  375. package/dist/server.js +15 -0
  376. package/dist/tailwind-utilities.css +1 -1
  377. package/dist/ui/DataTable.js +28 -7
  378. package/dist/ui/components/Button.d.ts +8 -1
  379. package/dist/ui/components/Button.js +47 -8
  380. package/dist/ui/components/CollageLightbox.d.ts +18 -0
  381. package/dist/ui/components/CollageLightbox.js +41 -0
  382. package/dist/ui/components/Dropdown.js +7 -6
  383. package/dist/ui/components/ImageLightbox.d.ts +7 -1
  384. package/dist/ui/components/ImageLightbox.js +15 -5
  385. package/dist/ui/components/PageLoader.js +4 -3
  386. package/dist/ui/components/PaginatedMultiSelect.d.ts +28 -0
  387. package/dist/ui/components/PaginatedMultiSelect.js +141 -0
  388. package/dist/ui/components/PaginatedMultiSelect.style.css +272 -0
  389. package/dist/ui/components/Semantic.js +1 -1
  390. package/dist/ui/components/SideDrawer.js +17 -15
  391. package/dist/ui/components/index.style.css +1 -0
  392. package/dist/ui/index.d.ts +2 -0
  393. package/dist/ui/index.js +1 -0
  394. package/dist/utils/number.formatter.js +5 -13
  395. package/dist/utils/string.formatter.js +21 -18
  396. package/dist/validation/schemas.d.ts +2 -2
  397. package/package.json +1 -1
@@ -11,6 +11,7 @@ import { Button, Div, Heading, Row, Section, Span, Text } from "../../../ui";
11
11
  ----------------------------------------------------------------- */
12
12
  const FALLBACK_IMAGE = "/animevssuperhero.jpg";
13
13
  const FALLBACK_IMAGE_ALT = "DC, Marvel and Anime characters";
14
+ const FONT_BANGERS = "var(--font-bangers, Bangers, cursive)";
14
15
  const DEFAULT_HOTSPOTS = [
15
16
  {
16
17
  id: "spiderman",
@@ -176,6 +177,120 @@ const DEFAULT_UNIVERSE_LINKS = [
176
177
  },
177
178
  { label: "BLEACH", href: "/franchise/bleach", color: "#4A90D9", icon: "⚔" },
178
179
  ];
180
+ function HotspotHeaderOverlay({ heading, subheading, shopAllHref, }) {
181
+ return (_jsx(Div, { className: "absolute top-0 left-0 right-0 z-10 pointer-events-none", style: {
182
+ background: "linear-gradient(to bottom, rgba(10,10,18,0.88) 0%, rgba(10,10,18,0.40) 50%, transparent 100%)",
183
+ }, children: _jsxs(Row, { wrap: true, align: "start", justify: "between", gap: "sm", className: "pointer-events-auto mx-auto max-w-7xl px-4 pt-4 pb-6 gap-y-3", children: [_jsxs(Div, { children: [_jsx(Text, { className: "mb-1 text-xs font-black uppercase tracking-[0.2em]", style: { color: "var(--color-red)" }, children: "Explore the Universe" }), _jsx(Heading, { level: 2, style: {
184
+ fontFamily: FONT_BANGERS,
185
+ fontSize: "clamp(1.8rem, 4.5vw, 3rem)",
186
+ letterSpacing: "0.07em",
187
+ color: "#FFFFFF",
188
+ lineHeight: 1,
189
+ }, children: heading }), subheading ? (_jsx(Text, { className: "mt-2 text-sm font-medium max-w-md", style: { color: "var(--dark-section-muted)" }, children: subheading })) : (_jsxs(Text, { className: "mt-2 text-sm font-medium max-w-md", style: { color: "var(--dark-section-muted)" }, children: ["& beyond \u2014 tap the", " ", _jsx(Span, { className: "inline-flex items-center justify-center rounded-full font-light", style: {
190
+ background: "rgba(255,255,255,0.92)",
191
+ color: "#111111",
192
+ width: 18,
193
+ height: 18,
194
+ border: "1.5px solid rgba(0,0,0,0.18)",
195
+ boxShadow: "0 1px 4px rgba(0,0,0,0.4)",
196
+ verticalAlign: "middle",
197
+ fontSize: 13,
198
+ lineHeight: 1,
199
+ }, children: "+" }), " ", "pins to get & buy each character."] }))] }), _jsx(Link, { href: shopAllHref, className: "hidden sm:inline-flex items-center gap-2 px-5 py-2 text-sm font-black uppercase tracking-widest transition-transform hover:-translate-y-0.5", style: {
200
+ fontFamily: FONT_BANGERS,
201
+ letterSpacing: "0.1em",
202
+ background: "var(--color-red)",
203
+ color: "#FFFFFF",
204
+ border: "3px solid var(--border-ink)",
205
+ boxShadow: "4px 4px 0px var(--border-ink)",
206
+ }, children: "SHOP ALL \u2192" })] }) }));
207
+ }
208
+ function HotspotImageLayer({ panoramicImage, panoramicAlt, }) {
209
+ return (_jsxs(Div, { className: "absolute inset-0 overflow-hidden", children: [_jsx(Image, { src: panoramicImage, alt: panoramicAlt, fill: true, className: "object-cover object-top", sizes: "100vw", priority: false }), _jsx(Div, { className: "absolute inset-0", style: {
210
+ background: "linear-gradient(to right, rgba(10,10,18,0.72) 0%, rgba(10,10,18,0.30) 50%, rgba(10,10,18,0.72) 100%)",
211
+ } }), _jsx(Div, { className: "absolute inset-0", style: {
212
+ background: "linear-gradient(to bottom, rgba(10,10,18,0.25) 0%, transparent 40%, rgba(10,10,18,0.65) 100%)",
213
+ } }), _jsx(Div, { className: "absolute bottom-0 left-0 right-0 h-16 pointer-events-none", style: {
214
+ background: "linear-gradient(to bottom, transparent, #0A0A12)",
215
+ } })] }));
216
+ }
217
+ function HotspotPin({ hotspot, isActive, isMobile, toggle, onClose, }) {
218
+ const popupLeft = hotspot.xPct <= 55;
219
+ const popupAbove = hotspot.yPct > 65;
220
+ return (_jsxs(Div, { className: "absolute", style: {
221
+ left: `${hotspot.xPct}%`,
222
+ top: `${hotspot.yPct}%`,
223
+ zIndex: isActive ? 30 : 10,
224
+ transform: "translate(-50%, -50%)",
225
+ }, children: [!isActive && (_jsx(Span, { className: "absolute rounded-full animate-ping", style: {
226
+ inset: -6,
227
+ background: "rgba(255,255,255,0.2)",
228
+ pointerEvents: "none",
229
+ } })), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => toggle(hotspot.id), "aria-label": `Info about ${hotspot.name}`, "aria-expanded": isActive, className: "relative flex items-center justify-center rounded-full", style: {
230
+ width: isMobile ? 18 : 38,
231
+ height: isMobile ? 18 : 38,
232
+ background: isMobile ? "none" : isActive ? "rgba(30,30,30,0.92)" : "rgba(255,255,255,0.95)",
233
+ border: isMobile ? "none" : isActive ? "2px solid rgba(255,255,255,0.25)" : "2px solid rgba(0,0,0,0.18)",
234
+ boxShadow: isMobile ? "none" : "0 2px 12px rgba(0,0,0,0.55)",
235
+ backdropFilter: isMobile ? "none" : "blur(4px)",
236
+ padding: 0,
237
+ transition: "transform 0.2s ease, opacity 0.2s ease",
238
+ transform: isActive ? "scale(1.2) rotate(45deg)" : "scale(1)",
239
+ color: isMobile ? "#FFFFFF" : isActive ? "#FFFFFF" : "#111111",
240
+ fontSize: isMobile ? 18 : 22,
241
+ fontWeight: 200,
242
+ lineHeight: 1,
243
+ cursor: "pointer",
244
+ textShadow: isMobile ? "0 1px 6px rgba(0,0,0,0.8)" : "none",
245
+ opacity: isActive ? 0.7 : 1,
246
+ }, children: "+" }), isActive && !isMobile && (_jsxs(Div, { className: "absolute", style: {
247
+ ...(popupAbove ? { bottom: "calc(100% + 12px)", top: "auto", transform: "none" } : { top: "50%", transform: "translateY(-50%)" }),
248
+ ...(popupLeft ? { left: "calc(100% + 14px)" } : { right: "calc(100% + 14px)" }),
249
+ width: 300,
250
+ background: "rgba(255,255,255,0.97)",
251
+ boxShadow: "0 12px 48px rgba(0,0,0,0.55), 0 2px 8px rgba(0,0,0,0.3)",
252
+ borderRadius: 4,
253
+ overflow: "hidden",
254
+ zIndex: 40,
255
+ animation: "fadeInUp 0.2s ease both",
256
+ }, children: [_jsx(Div, { style: { height: 4, background: hotspot.accent } }), _jsxs(Div, { className: "px-5 py-4", children: [_jsx(Text, { className: "text-[10px] font-bold uppercase tracking-[0.18em] mb-1", style: { color: hotspot.accent === "#FFE500" ? "#b08800" : hotspot.accent }, children: hotspot.universe }), _jsx(Heading, { level: 3, className: "font-black leading-tight mb-3", style: { fontFamily: FONT_BANGERS, fontSize: "1.45rem", letterSpacing: "0.06em", color: "#111111" }, children: hotspot.name }), _jsx(Text, { className: "text-xs leading-relaxed mb-4", style: { color: "#374151" }, children: hotspot.description }), _jsxs(Link, { href: hotspot.href, onClick: onClose, className: "flex items-center justify-between px-4 py-2.5 text-sm font-black uppercase transition-opacity hover:opacity-85", style: {
257
+ fontFamily: FONT_BANGERS,
258
+ letterSpacing: "0.1em",
259
+ background: hotspot.accent,
260
+ color: hotspot.accent === "#FFE500" ? "#0D0D0D" : "#FFFFFF",
261
+ borderRadius: 2,
262
+ }, children: [hotspot.buyText, _jsx(Span, { "aria-hidden": "true", children: "\u2192" })] })] })] }))] }));
263
+ }
264
+ function MobileHotspotSheet({ active, onClose, }) {
265
+ return (_jsx(Div, { className: "fixed inset-0 z-50 flex items-end", style: { background: "rgba(0,0,0,0.6)", backdropFilter: "blur(3px)" }, onClick: (e) => { if (e.target === e.currentTarget)
266
+ onClose(); }, children: _jsxs(Div, { className: "w-full", style: {
267
+ background: "var(--surface-elevated)",
268
+ borderTopLeftRadius: 16,
269
+ borderTopRightRadius: 16,
270
+ overflow: "hidden",
271
+ animation: "fadeInUp 0.22s ease both",
272
+ }, children: [_jsx(Div, { className: "flex justify-center pt-3 pb-1", children: _jsx(Div, { style: { width: 40, height: 4, borderRadius: 2, background: "#D1D5DB" } }) }), _jsx(Div, { style: { height: 4, background: active.accent } }), _jsxs(Div, { className: "px-5 pt-4 pb-10", children: [_jsx(Text, { className: "text-[10px] font-bold uppercase tracking-[0.18em] mb-1", style: { color: active.accent === "#FFE500" ? "#b08800" : active.accent }, children: active.universe }), _jsx(Heading, { level: 3, className: "font-black leading-tight mb-2", style: { fontFamily: FONT_BANGERS, fontSize: "clamp(1.5rem, 6vw, 2rem)", letterSpacing: "0.06em", color: "#111111" }, children: active.name }), _jsx(Text, { className: "text-sm leading-relaxed mb-5", style: { color: "#374151" }, children: active.description }), _jsxs(Div, { className: "flex gap-3", children: [_jsxs(Link, { href: active.href, onClick: onClose, className: "flex-1 flex items-center justify-between px-4 py-3 font-black uppercase", style: {
273
+ fontFamily: FONT_BANGERS,
274
+ letterSpacing: "0.1em",
275
+ fontSize: "0.9rem",
276
+ background: active.accent,
277
+ color: active.accent === "#FFE500" ? "#0D0D0D" : "#FFFFFF",
278
+ borderRadius: 4,
279
+ }, children: [active.buyText, _jsx(Span, { "aria-hidden": "true", children: "\u2192" })] }), _jsx(Button, { type: "button", variant: "outline", onClick: onClose, className: "px-5 py-3 text-sm font-bold rounded", style: { background: "#F1F5F9", color: "#475569" }, children: "Close" })] })] })] }) }));
280
+ }
281
+ function UniverseBrowseRow({ universeLinks, }) {
282
+ return (_jsx(Div, { className: `mx-auto max-w-7xl px-4 py-6 ${THEME_CONSTANTS.grid.cols6Lg} gap-3`, style: { borderTop: "1px solid rgba(255,255,255,0.08)" }, children: universeLinks.map(({ label, href, color, icon }) => (_jsxs(Link, { href: href, className: "group flex items-center gap-2.5 px-3 py-2.5 rounded-sm transition-all hover:-translate-y-0.5", style: {
283
+ background: "rgba(255,255,255,0.04)",
284
+ border: "1px solid rgba(255,255,255,0.08)",
285
+ transition: "all 0.15s ease",
286
+ }, onMouseEnter: (e) => {
287
+ e.currentTarget.style.borderColor = color;
288
+ e.currentTarget.style.background = `${color}18`;
289
+ }, onMouseLeave: (e) => {
290
+ e.currentTarget.style.borderColor = "rgba(255,255,255,0.08)";
291
+ e.currentTarget.style.background = "rgba(255,255,255,0.04)";
292
+ }, children: [_jsx(Span, { className: "text-base select-none", "aria-hidden": "true", children: icon }), _jsx(Span, { className: "text-xs font-black uppercase tracking-wide", style: { fontFamily: FONT_BANGERS, letterSpacing: "0.1em", color: "#E2E8F0" }, children: label }), _jsx(Span, { className: "ml-auto text-xs", style: { color: "#475569", transition: "color 0.15s" }, children: "\u2192" })] }, label))) }));
293
+ }
179
294
  function CharacterHotspotInner({ panoramicImage, panoramicAlt, hotspots, universeLinks, shopAllHref, heading, subheading, }) {
180
295
  const [activeId, setActiveId] = useState(null);
181
296
  const containerRef = useRef(null);
@@ -185,8 +300,7 @@ function CharacterHotspotInner({ panoramicImage, panoramicAlt, hotspots, univers
185
300
  }, []);
186
301
  useEffect(() => {
187
302
  function handleClick(e) {
188
- if (containerRef.current &&
189
- !containerRef.current.contains(e.target)) {
303
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
190
304
  setActiveId(null);
191
305
  }
192
306
  }
@@ -207,38 +321,7 @@ function CharacterHotspotInner({ panoramicImage, panoramicAlt, hotspots, univers
207
321
  borderTop: "3px solid var(--dark-section-bg)",
208
322
  borderBottom: "3px solid var(--dark-section-bg)",
209
323
  overflow: "hidden",
210
- }, children: [_jsxs(Div, { ref: containerRef, className: "relative w-full", style: { aspectRatio: "16/9", minHeight: "420px" }, children: [_jsx(Div, { className: "absolute top-0 left-0 right-0 z-10 pointer-events-none", style: {
211
- background: "linear-gradient(to bottom, rgba(10,10,18,0.88) 0%, rgba(10,10,18,0.40) 50%, transparent 100%)",
212
- }, children: _jsxs(Row, { wrap: true, align: "start", justify: "between", gap: "sm", className: "pointer-events-auto mx-auto max-w-7xl px-4 pt-4 pb-6 gap-y-3", children: [_jsxs(Div, { children: [_jsx(Text, { className: "mb-1 text-xs font-black uppercase tracking-[0.2em]", style: { color: "var(--color-red)" }, children: "Explore the Universe" }), _jsx(Heading, { level: 2, style: {
213
- fontFamily: "var(--font-bangers, Bangers, cursive)",
214
- fontSize: "clamp(1.8rem, 4.5vw, 3rem)",
215
- letterSpacing: "0.07em",
216
- color: "#FFFFFF",
217
- lineHeight: 1,
218
- }, children: heading }), subheading && (_jsx(Text, { className: "mt-2 text-sm font-medium max-w-md", style: { color: "var(--dark-section-muted)" }, children: subheading })), !subheading && (_jsxs(Text, { className: "mt-2 text-sm font-medium max-w-md", style: { color: "var(--dark-section-muted)" }, children: ["& beyond \u2014 tap the", " ", _jsx(Span, { className: "inline-flex items-center justify-center rounded-full font-light", style: {
219
- background: "rgba(255,255,255,0.92)",
220
- color: "#111111",
221
- width: 18,
222
- height: 18,
223
- border: "1.5px solid rgba(0,0,0,0.18)",
224
- boxShadow: "0 1px 4px rgba(0,0,0,0.4)",
225
- verticalAlign: "middle",
226
- fontSize: 13,
227
- lineHeight: 1,
228
- }, children: "+" }), " ", "pins to get & buy each character."] }))] }), _jsx(Link, { href: shopAllHref, className: "hidden sm:inline-flex items-center gap-2 px-5 py-2 text-sm font-black uppercase tracking-widest transition-transform hover:-translate-y-0.5", style: {
229
- fontFamily: "var(--font-bangers, Bangers, cursive)",
230
- letterSpacing: "0.1em",
231
- background: "var(--color-red)",
232
- color: "#FFFFFF",
233
- border: "3px solid var(--border-ink)",
234
- boxShadow: "4px 4px 0px var(--border-ink)",
235
- }, children: "SHOP ALL \u2192" })] }) }), _jsxs(Div, { className: "absolute inset-0 overflow-hidden", children: [_jsx(Image, { src: panoramicImage, alt: panoramicAlt, fill: true, className: "object-cover object-top", sizes: "100vw", priority: false }), _jsx(Div, { className: "absolute inset-0", style: {
236
- background: "linear-gradient(to right, rgba(10,10,18,0.72) 0%, rgba(10,10,18,0.30) 50%, rgba(10,10,18,0.72) 100%)",
237
- } }), _jsx(Div, { className: "absolute inset-0", style: {
238
- background: "linear-gradient(to bottom, rgba(10,10,18,0.25) 0%, transparent 40%, rgba(10,10,18,0.65) 100%)",
239
- } }), _jsx(Div, { className: "absolute bottom-0 left-0 right-0 h-16 pointer-events-none", style: {
240
- background: "linear-gradient(to bottom, transparent, #0A0A12)",
241
- } })] }), _jsx(Div, { className: "hidden sm:flex absolute left-0 right-0 justify-around items-start pointer-events-none", style: { top: "clamp(120px, 18vh, 165px)", zIndex: 5 }, children: [
324
+ }, children: [_jsxs(Div, { ref: containerRef, className: "relative w-full", style: { aspectRatio: "16/9", minHeight: "420px" }, children: [_jsx(HotspotHeaderOverlay, { heading: heading, subheading: subheading, shopAllHref: shopAllHref }), _jsx(HotspotImageLayer, { panoramicImage: panoramicImage, panoramicAlt: panoramicAlt }), _jsx(Div, { className: "hidden sm:flex absolute left-0 right-0 justify-around items-start pointer-events-none", style: { top: "clamp(120px, 18vh, 165px)", zIndex: 5 }, children: [
242
325
  { label: "MARVEL", color: "#E8001C" },
243
326
  { label: "DC COMICS", color: "#4A90D9" },
244
327
  { label: "ANIME", color: "#FFE500" },
@@ -246,128 +329,7 @@ function CharacterHotspotInner({ panoramicImage, panoramicAlt, hotspots, univers
246
329
  background: color,
247
330
  color: color === "#FFE500" ? "#0D0D0D" : "#FFFFFF",
248
331
  boxShadow: "2px 2px 0px rgba(0,0,0,0.6)",
249
- fontFamily: "var(--font-bangers, Bangers, cursive)",
332
+ fontFamily: FONT_BANGERS,
250
333
  letterSpacing: "0.16em",
251
- }, children: label }), _jsx(Div, { className: "mt-1 h-5 sm:h-8 w-px", style: { background: color, opacity: 0.5 } })] }, label))) }), hotspots.map((hotspot) => {
252
- const isActive = activeId === hotspot.id;
253
- const popupLeft = hotspot.xPct <= 55;
254
- const popupAbove = hotspot.yPct > 65;
255
- return (_jsxs(Div, { className: "absolute", style: {
256
- left: `${hotspot.xPct}%`,
257
- top: `${hotspot.yPct}%`,
258
- zIndex: isActive ? 30 : 10,
259
- transform: "translate(-50%, -50%)",
260
- }, children: [!isActive && (_jsx(Span, { className: "absolute rounded-full animate-ping", style: {
261
- inset: -6,
262
- background: "rgba(255,255,255,0.2)",
263
- pointerEvents: "none",
264
- } })), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => toggle(hotspot.id), "aria-label": `Info about ${hotspot.name}`, "aria-expanded": isActive, className: "relative flex items-center justify-center rounded-full", style: {
265
- width: isMobile ? 18 : 38,
266
- height: isMobile ? 18 : 38,
267
- background: isMobile
268
- ? "none"
269
- : isActive
270
- ? "rgba(30,30,30,0.92)"
271
- : "rgba(255,255,255,0.95)",
272
- border: isMobile
273
- ? "none"
274
- : isActive
275
- ? "2px solid rgba(255,255,255,0.25)"
276
- : "2px solid rgba(0,0,0,0.18)",
277
- boxShadow: isMobile ? "none" : "0 2px 12px rgba(0,0,0,0.55)",
278
- backdropFilter: isMobile ? "none" : "blur(4px)",
279
- padding: 0,
280
- transition: "transform 0.2s ease, opacity 0.2s ease",
281
- transform: isActive ? "scale(1.2) rotate(45deg)" : "scale(1)",
282
- color: isMobile
283
- ? "#FFFFFF"
284
- : isActive
285
- ? "#FFFFFF"
286
- : "#111111",
287
- fontSize: isMobile ? 18 : 22,
288
- fontWeight: 200,
289
- lineHeight: 1,
290
- cursor: "pointer",
291
- textShadow: isMobile ? "0 1px 6px rgba(0,0,0,0.8)" : "none",
292
- opacity: isActive ? 0.7 : 1,
293
- }, children: "+" }), isActive && !isMobile && (_jsxs(Div, { className: "absolute", style: {
294
- ...(popupAbove
295
- ? {
296
- bottom: "calc(100% + 12px)",
297
- top: "auto",
298
- transform: "none",
299
- }
300
- : { top: "50%", transform: "translateY(-50%)" }),
301
- ...(popupLeft
302
- ? { left: "calc(100% + 14px)" }
303
- : { right: "calc(100% + 14px)" }),
304
- width: 300,
305
- background: "rgba(255,255,255,0.97)",
306
- boxShadow: "0 12px 48px rgba(0,0,0,0.55), 0 2px 8px rgba(0,0,0,0.3)",
307
- borderRadius: 4,
308
- overflow: "hidden",
309
- zIndex: 40,
310
- animation: "fadeInUp 0.2s ease both",
311
- }, children: [_jsx(Div, { style: { height: 4, background: hotspot.accent } }), _jsxs(Div, { className: "px-5 py-4", children: [_jsx(Text, { className: "text-[10px] font-bold uppercase tracking-[0.18em] mb-1", style: {
312
- color: hotspot.accent === "#FFE500"
313
- ? "#b08800"
314
- : hotspot.accent,
315
- }, children: hotspot.universe }), _jsx(Heading, { level: 3, className: "font-black leading-tight mb-3", style: {
316
- fontFamily: "var(--font-bangers, Bangers, cursive)",
317
- fontSize: "1.45rem",
318
- letterSpacing: "0.06em",
319
- color: "#111111",
320
- }, children: hotspot.name }), _jsx(Text, { className: "text-xs leading-relaxed mb-4", style: { color: "#374151" }, children: hotspot.description }), _jsxs(Link, { href: hotspot.href, onClick: () => setActiveId(null), className: "flex items-center justify-between px-4 py-2.5 text-sm font-black uppercase transition-opacity hover:opacity-85", style: {
321
- fontFamily: "var(--font-bangers, Bangers, cursive)",
322
- letterSpacing: "0.1em",
323
- background: hotspot.accent,
324
- color: hotspot.accent === "#FFE500" ? "#0D0D0D" : "#FFFFFF",
325
- borderRadius: 2,
326
- }, children: [hotspot.buyText, _jsx(Span, { "aria-hidden": "true", children: "\u2192" })] })] })] }))] }, hotspot.id));
327
- })] }), isMobile && active && (_jsx(Div, { className: "fixed inset-0 z-50 flex items-end", style: { background: "rgba(0,0,0,0.6)", backdropFilter: "blur(3px)" }, onClick: (e) => {
328
- if (e.target === e.currentTarget)
329
- setActiveId(null);
330
- }, children: _jsxs(Div, { className: "w-full", style: {
331
- background: "var(--surface-elevated)",
332
- borderTopLeftRadius: 16,
333
- borderTopRightRadius: 16,
334
- overflow: "hidden",
335
- animation: "fadeInUp 0.22s ease both",
336
- }, children: [_jsx(Div, { className: "flex justify-center pt-3 pb-1", children: _jsx(Div, { style: {
337
- width: 40,
338
- height: 4,
339
- borderRadius: 2,
340
- background: "#D1D5DB",
341
- } }) }), _jsx(Div, { style: { height: 4, background: active.accent } }), _jsxs(Div, { className: "px-5 pt-4 pb-10", children: [_jsx(Text, { className: "text-[10px] font-bold uppercase tracking-[0.18em] mb-1", style: {
342
- color: active.accent === "#FFE500" ? "#b08800" : active.accent,
343
- }, children: active.universe }), _jsx(Heading, { level: 3, className: "font-black leading-tight mb-2", style: {
344
- fontFamily: "var(--font-bangers, Bangers, cursive)",
345
- fontSize: "clamp(1.5rem, 6vw, 2rem)",
346
- letterSpacing: "0.06em",
347
- color: "#111111",
348
- }, children: active.name }), _jsx(Text, { className: "text-sm leading-relaxed mb-5", style: { color: "#374151" }, children: active.description }), _jsxs(Div, { className: "flex gap-3", children: [_jsxs(Link, { href: active.href, onClick: () => setActiveId(null), className: "flex-1 flex items-center justify-between px-4 py-3 font-black uppercase", style: {
349
- fontFamily: "var(--font-bangers, Bangers, cursive)",
350
- letterSpacing: "0.1em",
351
- fontSize: "0.9rem",
352
- background: active.accent,
353
- color: active.accent === "#FFE500" ? "#0D0D0D" : "#FFFFFF",
354
- borderRadius: 4,
355
- }, children: [active.buyText, _jsx(Span, { "aria-hidden": "true", children: "\u2192" })] }), _jsx(Button, { type: "button", variant: "outline", onClick: () => setActiveId(null), className: "px-5 py-3 text-sm font-bold rounded", style: { background: "#F1F5F9", color: "#475569" }, children: "Close" })] })] })] }) })), _jsx(Div, { className: `mx-auto max-w-7xl px-4 py-6 ${THEME_CONSTANTS.grid.cols6Lg} gap-3`, style: { borderTop: "1px solid rgba(255,255,255,0.08)" }, children: universeLinks.map(({ label, href, color, icon }) => (_jsxs(Link, { href: href, className: "group flex items-center gap-2.5 px-3 py-2.5 rounded-sm transition-all hover:-translate-y-0.5", style: {
356
- background: "rgba(255,255,255,0.04)",
357
- border: "1px solid rgba(255,255,255,0.08)",
358
- transition: "all 0.15s ease",
359
- }, onMouseEnter: (e) => {
360
- e.currentTarget.style.borderColor = color;
361
- e.currentTarget.style.background =
362
- `${color}18`;
363
- }, onMouseLeave: (e) => {
364
- e.currentTarget.style.borderColor =
365
- "rgba(255,255,255,0.08)";
366
- e.currentTarget.style.background =
367
- "rgba(255,255,255,0.04)";
368
- }, children: [_jsx(Span, { className: "text-base select-none", "aria-hidden": "true", children: icon }), _jsx(Span, { className: "text-xs font-black uppercase tracking-wide", style: {
369
- fontFamily: "var(--font-bangers, Bangers, cursive)",
370
- letterSpacing: "0.1em",
371
- color: "#E2E8F0",
372
- }, children: label }), _jsx(Span, { className: "ml-auto text-xs", style: { color: "#475569", transition: "color 0.15s" }, children: "\u2192" })] }, label))) })] }));
334
+ }, children: label }), _jsx(Div, { className: "mt-1 h-5 sm:h-8 w-px", style: { background: color, opacity: 0.5 } })] }, label))) }), hotspots.map((hotspot) => (_jsx(HotspotPin, { hotspot: hotspot, isActive: activeId === hotspot.id, isMobile: isMobile, toggle: toggle, onClose: () => setActiveId(null) }, hotspot.id)))] }), isMobile && active && (_jsx(MobileHotspotSheet, { active: active, onClose: () => setActiveId(null) })), _jsx(UniverseBrowseRow, { universeLinks: universeLinks })] }));
373
335
  }
@@ -6,6 +6,11 @@ import { Button, Div, Heading, Input, Label, Li, Row, Span, Text, Textarea, Ul,
6
6
  function randomId() {
7
7
  return Math.random().toString(36).slice(2, 9);
8
8
  }
9
+ const CLS_STEP = "space-y-4 rounded-lg border-2 p-6";
10
+ const CLS_IMG_WRAP = "relative w-full overflow-hidden rounded-lg";
11
+ const CLS_INPUT = "rounded border-2 px-3 py-2 text-sm outline-none";
12
+ const STY_BORDER_INK = "2px solid var(--border-ink)";
13
+ const STY_CENTERED = "translate(-50%, -50%)";
9
14
  export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSave, }) {
10
15
  const [imageUrl, setImageUrl] = useState(initial?.imageUrl ?? "");
11
16
  const [imageAlt, setImageAlt] = useState(initial?.imageAlt ?? "DC, Marvel and Anime characters");
@@ -120,15 +125,15 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
120
125
  : "var(--color-black)",
121
126
  border: i <= stepIndex
122
127
  ? "2px solid var(--color-black)"
123
- : "2px solid var(--border-ink)",
128
+ : STY_BORDER_INK,
124
129
  }, children: i < stepIndex ? "✓" : i + 1 }), i < STEPS.length - 1 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
125
130
  background: i < stepIndex
126
131
  ? "var(--color-black)"
127
132
  : "var(--border-ink)",
128
- } }))] }), _jsx(Span, { className: "mt-1 text-center text-[10px] font-medium", style: { color: "var(--color-muted)" }, children: s.label })] }, s.key))) }), step === "image" && (_jsxs(Div, { className: "space-y-4 rounded-lg border-2 p-6", style: {
133
+ } }))] }), _jsx(Span, { className: "mt-1 text-center text-[10px] font-medium", style: { color: "var(--color-muted)" }, children: s.label })] }, s.key))) }), step === "image" && (_jsxs(Div, { className: CLS_STEP, style: {
129
134
  borderColor: "var(--border-ink)",
130
135
  background: "var(--surface-elevated)",
131
- }, children: [_jsx(Heading, { level: 2, className: "text-lg font-bold", children: "Upload Background Image" }), _jsx(Text, { className: "text-sm", style: { color: "var(--color-muted)" }, children: "Choose a wide panoramic image that shows all the characters. You will place pins on it in the next step." }), _jsxs(Label, { className: "flex cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-8 transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Span, { className: "text-3xl", children: "\uD83D\uDDBC" }), _jsx(Span, { className: "font-medium", children: uploading ? "Uploading…" : "Click to choose image" }), _jsx(Span, { className: "text-xs", style: { color: "var(--color-muted)" }, children: "JPG, PNG, WebP \u2014 wide landscape images work best" }), _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), imageUrl && (_jsxs(Div, { className: "space-y-1", children: [_jsx(Div, { className: "relative w-full overflow-hidden rounded-lg", style: { paddingTop: "37.5%" }, children: _jsx(Image, { src: imageUrl, alt: imageAlt, fill: true, className: "object-cover", sizes: "680px" }) }), _jsx(Text, { className: "text-xs font-medium text-green-700", children: "\u2713 Image uploaded" })] })), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), placeholder: "DC, Marvel and Anime characters", className: "rounded border-2 px-3 py-2 text-sm outline-none", style: {
136
+ }, children: [_jsx(Heading, { level: 2, className: "text-lg font-bold", children: "Upload Background Image" }), _jsx(Text, { className: "text-sm", style: { color: "var(--color-muted)" }, children: "Choose a wide panoramic image that shows all the characters. You will place pins on it in the next step." }), _jsxs(Label, { className: "flex cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-8 transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Span, { className: "text-3xl", children: "\uD83D\uDDBC" }), _jsx(Span, { className: "font-medium", children: uploading ? "Uploading…" : "Click to choose image" }), _jsx(Span, { className: "text-xs", style: { color: "var(--color-muted)" }, children: "JPG, PNG, WebP \u2014 wide landscape images work best" }), _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), imageUrl && (_jsxs(Div, { className: "space-y-1", children: [_jsx(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "37.5%" }, children: _jsx(Image, { src: imageUrl, alt: imageAlt, fill: true, className: "object-cover", sizes: "680px" }) }), _jsx(Text, { className: "text-xs font-medium text-green-700", children: "\u2713 Image uploaded" })] })), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), placeholder: "DC, Marvel and Anime characters", className: CLS_INPUT, style: {
132
137
  borderColor: "var(--border-ink)",
133
138
  background: "var(--surface-elevated)",
134
139
  color: "var(--color-black)",
@@ -138,17 +143,17 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
138
143
  }, children: "Skip to Review" })), _jsx(Button, { type: "button", onClick: () => setStep("place"), disabled: !imageUrl || uploading, variant: "primary", className: "px-4 py-2 text-sm font-bold rounded transition-opacity disabled:opacity-50", style: {
139
144
  background: "var(--color-black)",
140
145
  color: "var(--color-yellow)",
141
- }, children: "Next: Place Pins \u2192" })] })] })), step === "place" && (_jsxs(Div, { className: "space-y-4 rounded-lg border-2 p-6", style: {
146
+ }, children: "Next: Place Pins \u2192" })] })] })), step === "place" && (_jsxs(Div, { className: CLS_STEP, style: {
142
147
  borderColor: "var(--border-ink)",
143
148
  background: "var(--surface-elevated)",
144
- }, children: [_jsx(Heading, { level: 2, className: "text-lg font-bold", children: "Place a Pin" }), _jsxs(Text, { className: "text-sm", style: { color: "var(--color-muted)" }, children: [_jsx("strong", { children: "Click anywhere on the image" }), " to drop a pin, or enter exact coordinates below."] }), _jsxs(Div, { ref: containerRef, className: "relative w-full overflow-hidden rounded-lg", style: {
149
+ }, children: [_jsx(Heading, { level: 2, className: "text-lg font-bold", children: "Place a Pin" }), _jsxs(Text, { className: "text-sm", style: { color: "var(--color-muted)" }, children: [_jsx("strong", { children: "Click anywhere on the image" }), " to drop a pin, or enter exact coordinates below."] }), _jsxs(Div, { ref: containerRef, className: CLS_IMG_WRAP, style: {
145
150
  paddingTop: "56.25%",
146
151
  cursor: "crosshair",
147
152
  background: "#111",
148
153
  }, onClick: handleImageClick, children: [_jsx(Image, { src: imageUrl, alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
149
154
  left: `${pin.xPct}%`,
150
155
  top: `${pin.yPct}%`,
151
- transform: "translate(-50%, -50%)",
156
+ transform: STY_CENTERED,
152
157
  zIndex: 10,
153
158
  }, children: [_jsx(Div, { className: "flex items-center justify-center rounded-full text-xs font-bold text-white", style: {
154
159
  width: 24,
@@ -159,7 +164,7 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
159
164
  }, children: "+" }), pin.name && (_jsx(Div, { className: "pointer-events-none absolute left-7 top-1/2 -translate-y-1/2 whitespace-nowrap rounded px-1.5 py-0.5 text-[9px] font-bold text-white", style: { background: "#0D0D0D" }, children: pin.name }))] }, pin.id))), draftPos && (_jsxs(Div, { className: "absolute", style: {
160
165
  left: `${draftPos.xPct}%`,
161
166
  top: `${draftPos.yPct}%`,
162
- transform: "translate(-50%, -50%)",
167
+ transform: STY_CENTERED,
163
168
  zIndex: 20,
164
169
  }, children: [_jsx(Span, { className: "absolute animate-ping rounded-full", style: {
165
170
  inset: -6,
@@ -201,18 +206,18 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
201
206
  const v = parseFloat(e.target.value);
202
207
  if (!isNaN(v))
203
208
  onChange(v);
204
- }, className: "rounded border-2 px-3 py-2 text-sm outline-none", style: {
209
+ }, className: CLS_INPUT, style: {
205
210
  borderColor: "var(--border-ink)",
206
211
  background: "var(--surface-elevated)",
207
212
  color: "var(--color-black)",
208
213
  } })] }, field))) }), pins.length > 0 && (_jsxs(Text, { className: "text-xs", style: { color: "var(--color-muted)" }, children: [pins.length, " pin", pins.length !== 1 ? "s" : "", " already placed on this image."] })), _jsxs(Row, { justify: "between", className: "border-t pt-4", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => setStep("image"), variant: "ghost", className: "px-4 py-2 text-sm font-medium rounded transition-opacity hover:opacity-70", style: { background: "transparent", color: "var(--color-black)" }, children: "\u2190 Back" }), _jsxs(Row, { gap: "sm", children: [pins.length > 0 && (_jsx(Button, { type: "button", onClick: () => setStep("review"), variant: "outline", className: "px-4 py-2 text-sm font-bold rounded transition-opacity", style: {
209
214
  background: "var(--surface-warm)",
210
215
  color: "var(--color-black)",
211
- border: "2px solid var(--border-ink)",
216
+ border: STY_BORDER_INK,
212
217
  }, children: "Done Adding Pins" })), _jsx(Button, { type: "button", onClick: () => setStep("details"), disabled: !draftPos, variant: "primary", className: "px-4 py-2 text-sm font-bold rounded transition-opacity disabled:opacity-50", style: {
213
218
  background: "var(--color-black)",
214
219
  color: "var(--color-yellow)",
215
- }, children: "Continue: Add Details \u2192" })] })] })] })), step === "details" && (_jsxs(Div, { className: "space-y-4 rounded-lg border-2 p-6", style: {
220
+ }, children: "Continue: Add Details \u2192" })] })] })] })), step === "details" && (_jsxs(Div, { className: CLS_STEP, style: {
216
221
  borderColor: "var(--border-ink)",
217
222
  background: "var(--surface-elevated)",
218
223
  }, children: [_jsx(Heading, { level: 2, className: "text-lg font-bold", children: "Pin Details" }), _jsxs(Text, { className: "text-sm", style: { color: "var(--color-muted)" }, children: ["Fill in the details for the pin at", " ", _jsxs("strong", { children: [draftPos?.xPct, "%, ", draftPos?.yPct, "%"] }), "."] }), _jsx(Div, { className: "grid grid-cols-2 gap-3", children: [
@@ -228,7 +233,7 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
228
233
  onChange: setDraftUniverse,
229
234
  placeholder: "Marvel",
230
235
  },
231
- ].map(({ label, value, onChange, placeholder }) => (_jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: "rounded border-2 px-3 py-2 text-sm outline-none", style: {
236
+ ].map(({ label, value, onChange, placeholder }) => (_jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
232
237
  borderColor: "var(--border-ink)",
233
238
  background: "var(--surface-elevated)",
234
239
  color: "var(--color-black)",
@@ -236,7 +241,7 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
236
241
  borderColor: "var(--border-ink)",
237
242
  background: "var(--surface-elevated)",
238
243
  color: "var(--color-black)",
239
- }, placeholder: "Short description shown in the popup\u2026" })] }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Link (href) *" }), _jsx(Input, { type: "text", value: draftHref, onChange: (e) => setDraftHref(e.target.value), placeholder: "/franchise/marvel", className: "rounded border-2 px-3 py-2 text-sm outline-none", style: {
244
+ }, placeholder: "Short description shown in the popup\u2026" })] }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Link (href) *" }), _jsx(Input, { type: "text", value: draftHref, onChange: (e) => setDraftHref(e.target.value), placeholder: "/franchise/marvel", className: CLS_INPUT, style: {
240
245
  borderColor: "var(--border-ink)",
241
246
  background: "var(--surface-elevated)",
242
247
  color: "var(--color-black)",
@@ -253,11 +258,11 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
253
258
  onChange: setDraftBadge,
254
259
  placeholder: "MARVEL",
255
260
  },
256
- ].map(({ label, value, onChange, placeholder }) => (_jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: "rounded border-2 px-3 py-2 text-sm outline-none", style: {
261
+ ].map(({ label, value, onChange, placeholder }) => (_jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
257
262
  borderColor: "var(--border-ink)",
258
263
  background: "var(--surface-elevated)",
259
264
  color: "var(--color-black)",
260
- } })] }, label))) }), _jsxs(Row, { align: "end", gap: "sm", children: [_jsxs(Div, { className: "flex-1 flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Accent Colour (hex)" }), _jsx(Input, { type: "text", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), placeholder: "#E8001C", className: "rounded border-2 px-3 py-2 text-sm outline-none", style: {
265
+ } })] }, label))) }), _jsxs(Row, { align: "end", gap: "sm", children: [_jsxs(Div, { className: "flex-1 flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Accent Colour (hex)" }), _jsx(Input, { type: "text", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), placeholder: "#E8001C", className: CLS_INPUT, style: {
261
266
  borderColor: "var(--border-ink)",
262
267
  background: "var(--surface-elevated)",
263
268
  color: "var(--color-black)",
@@ -267,20 +272,20 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
267
272
  }, variant: "outline", className: "px-4 py-2 text-sm font-bold rounded transition-opacity disabled:opacity-50", style: {
268
273
  background: "var(--surface-warm)",
269
274
  color: "var(--color-black)",
270
- border: "2px solid var(--border-ink)",
275
+ border: STY_BORDER_INK,
271
276
  }, children: "Save Pin & Finish" }), _jsx(Button, { type: "button", disabled: !draftName || !draftHref, onClick: () => {
272
277
  commitDraftPin();
273
278
  setStep("place");
274
279
  }, variant: "primary", className: "px-4 py-2 text-sm font-bold rounded transition-opacity disabled:opacity-50", style: {
275
280
  background: "var(--color-black)",
276
281
  color: "var(--color-yellow)",
277
- }, children: "Save Pin & Add Another \u2192" })] })] })] })), step === "review" && (_jsxs(Div, { className: "space-y-4 rounded-lg border-2 p-6", style: {
282
+ }, children: "Save Pin & Add Another \u2192" })] })] })] })), step === "review" && (_jsxs(Div, { className: CLS_STEP, style: {
278
283
  borderColor: "var(--border-ink)",
279
284
  background: "var(--surface-elevated)",
280
- }, children: [_jsxs(Row, { justify: "between", children: [_jsx(Heading, { level: 2, className: "text-lg font-bold", children: "Review & Save" }), _jsxs(Span, { className: "rounded-full px-3 py-1 text-sm font-bold", style: { background: "var(--surface-warm)" }, children: [pins.length, " pin", pins.length !== 1 ? "s" : ""] })] }), _jsxs(Div, { className: "relative w-full overflow-hidden rounded-lg", style: { paddingTop: "56.25%", background: "#111" }, children: [_jsx(Image, { src: imageUrl, alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
285
+ }, children: [_jsxs(Row, { justify: "between", children: [_jsx(Heading, { level: 2, className: "text-lg font-bold", children: "Review & Save" }), _jsxs(Span, { className: "rounded-full px-3 py-1 text-sm font-bold", style: { background: "var(--surface-warm)" }, children: [pins.length, " pin", pins.length !== 1 ? "s" : ""] })] }), _jsxs(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "56.25%", background: "#111" }, children: [_jsx(Image, { src: imageUrl, alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
281
286
  left: `${pin.xPct}%`,
282
287
  top: `${pin.yPct}%`,
283
- transform: "translate(-50%, -50%)",
288
+ transform: STY_CENTERED,
284
289
  zIndex: 10,
285
290
  }, children: [_jsx(Div, { className: "flex items-center justify-center rounded-full text-xs font-bold text-white", style: {
286
291
  width: 28,
@@ -291,7 +296,7 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
291
296
  }, children: "+" }), pin.name && (_jsx(Div, { className: "pointer-events-none absolute left-8 top-1/2 -translate-y-1/2 whitespace-nowrap rounded px-1.5 py-0.5 text-[9px] font-bold text-white", style: { background: "#0D0D0D" }, children: pin.name }))] }, pin.id)))] }), pins.length > 0 ? (_jsx(Ul, { className: "divide-y rounded-lg border", style: { borderColor: "var(--border-ink)" }, children: pins.map((pin, i) => (_jsx(Li, { className: "px-4 py-3", children: _jsxs(Row, { gap: "sm", children: [_jsx(Span, { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-bold text-white", style: { background: pin.accent || "#E8001C" }, children: i + 1 }), _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { className: "truncate text-sm font-bold", children: pin.name || (_jsx(Span, { className: "italic", style: { color: "var(--color-muted)" }, children: "Unnamed" })) }), _jsxs(Text, { className: "text-xs", style: { color: "var(--color-muted)" }, children: [pin.universe, " \u00B7 ", pin.xPct.toFixed(0), "%,", " ", pin.yPct.toFixed(0), "%"] })] }), _jsx(Button, { type: "button", onClick: () => deletePin(pin.id), variant: "ghost", className: "shrink-0 rounded p-1 text-xs text-red-500 hover:bg-red-50", title: "Remove pin", children: "\u2715" })] }) }, pin.id))) })) : (_jsx(Div, { className: "rounded-lg border-2 border-dashed p-8 text-center text-sm", style: {
292
297
  borderColor: "var(--border-ink)",
293
298
  color: "var(--color-muted)",
294
- }, children: "No pins yet \u2014 add some using the button below." })), _jsxs("details", { className: "rounded-lg border p-3", style: { borderColor: "var(--border-ink)" }, children: [_jsx("summary", { className: "cursor-pointer text-sm font-medium", children: "Image Settings" }), _jsxs(Div, { className: "mt-3 space-y-3", children: [_jsxs(Label, { className: "inline-flex cursor-pointer items-center gap-2 rounded border-2 border-dashed px-3 py-1.5 text-sm font-medium transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [uploading ? "Uploading…" : "Replace Image", _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), className: "rounded border-2 px-3 py-2 text-sm outline-none", style: {
299
+ }, children: "No pins yet \u2014 add some using the button below." })), _jsxs("details", { className: "rounded-lg border p-3", style: { borderColor: "var(--border-ink)" }, children: [_jsx("summary", { className: "cursor-pointer text-sm font-medium", children: "Image Settings" }), _jsxs(Div, { className: "mt-3 space-y-3", children: [_jsxs(Label, { className: "inline-flex cursor-pointer items-center gap-2 rounded border-2 border-dashed px-3 py-1.5 text-sm font-medium transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [uploading ? "Uploading…" : "Replace Image", _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), _jsxs(Div, { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-sm font-bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), className: CLS_INPUT, style: {
295
300
  borderColor: "var(--border-ink)",
296
301
  background: "var(--surface-elevated)",
297
302
  color: "var(--color-black)",
@@ -301,7 +306,7 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
301
306
  }, variant: "outline", className: "px-4 py-2 text-sm font-bold rounded transition-opacity", style: {
302
307
  background: "var(--surface-warm)",
303
308
  color: "var(--color-black)",
304
- border: "2px solid var(--border-ink)",
309
+ border: STY_BORDER_INK,
305
310
  }, children: "+ Add Another Pin" }), _jsx(Button, { type: "button", onClick: handleSave, disabled: !imageUrl || saving || pins.length === 0, variant: "primary", className: "px-4 py-2 text-sm font-bold rounded transition-opacity disabled:opacity-50", style: {
306
311
  background: "var(--color-black)",
307
312
  color: "var(--color-yellow)",
@@ -1,8 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Heading, HorizontalScroller, Section } from "../../../ui";
2
+ import { Heading, HorizontalScroller, Section, Text } from "../../../ui";
3
3
  import { THEME_CONSTANTS } from "../../../tokens";
4
4
  import { SectionCarousel } from "./SectionCarousel";
5
5
  import { MediaImage } from "../../media/MediaImage";
6
+ // --- Constants ---------------------------------------------------------------
7
+ const CLS_CONTAINER = "w-full max-w-7xl mx-auto px-4";
6
8
  // --- Helpers -----------------------------------------------------------------
7
9
  const COLS_CLASS = {
8
10
  1: "grid-cols-1",
@@ -39,7 +41,7 @@ function CardItem({ card }) {
39
41
  cardStyle.backgroundColor = card.backgroundColor;
40
42
  if (card.textColor)
41
43
  cardStyle.color = card.textColor;
42
- return (_jsxs("div", { className: `flex flex-col overflow-hidden ${radiusClass} ${shadowClass} bg-[var(--appkit-color-surface)]`, style: cardStyle, children: [card.image && (_jsx("div", { className: "relative w-full aspect-video overflow-hidden", children: _jsx(MediaImage, { src: card.image, alt: card.imageAlt ?? "", size: "card" }) })), _jsxs("div", { className: "flex flex-col gap-2 p-4 flex-1", children: [card.eyebrow && (_jsx("p", { className: "text-xs font-semibold uppercase tracking-widest opacity-70", children: card.eyebrow })), card.title && (_jsx("p", { className: "text-base font-bold leading-snug", children: card.title })), card.body && (_jsx("p", { className: "text-sm opacity-80 leading-relaxed flex-1", children: card.body })), card.buttons && card.buttons.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 mt-2", children: card.buttons.map((btn, i) => (_jsx("a", { href: btn.href, target: btn.target ?? "_self", rel: btn.target === "_blank" ? "noopener noreferrer" : undefined, className: VARIANT_CLASS[btn.variant] ?? VARIANT_CLASS.primary, children: btn.label }, i))) })), card.formEmbed && (_jsx("iframe", { src: card.formEmbed, sandbox: "allow-forms allow-scripts", loading: "lazy", className: "w-full mt-3 border-0 rounded-md", style: { minHeight: "200px" }, title: "Embedded form" }))] })] }));
44
+ return (_jsxs("div", { className: `flex flex-col overflow-hidden ${radiusClass} ${shadowClass} bg-[var(--appkit-color-surface)]`, style: cardStyle, children: [card.image && (_jsx("div", { className: "relative w-full aspect-video overflow-hidden", children: _jsx(MediaImage, { src: card.image, alt: card.imageAlt ?? "", size: "card" }) })), _jsxs("div", { className: "flex flex-col gap-2 p-4 flex-1", children: [card.eyebrow && (_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest opacity-70", children: card.eyebrow })), card.title && (_jsx(Text, { className: "text-base font-bold leading-snug", children: card.title })), card.body && (_jsx(Text, { className: "text-sm opacity-80 leading-relaxed flex-1", children: card.body })), card.buttons && card.buttons.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 mt-2", children: card.buttons.map((btn, i) => (_jsx("a", { href: btn.href, target: btn.target ?? "_self", rel: btn.target === "_blank" ? "noopener noreferrer" : undefined, className: VARIANT_CLASS[btn.variant] ?? VARIANT_CLASS.primary, children: btn.label }, i))) })), card.formEmbed && (_jsx("iframe", { src: card.formEmbed, sandbox: "allow-forms allow-scripts", loading: "lazy", className: "w-full mt-3 border-0 rounded-md", style: { minHeight: "200px" }, title: "Embedded form" }))] })] }));
43
45
  }
44
46
  // --- Section Header ----------------------------------------------------------
45
47
  function SectionHeader({ title }) {
@@ -55,11 +57,11 @@ export function CustomCardsSection(config) {
55
57
  return null;
56
58
  // autoScroll: wrap all cards in SectionCarousel (client carousel)
57
59
  if (autoScroll) {
58
- return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsx("div", { className: "w-full max-w-7xl mx-auto px-4", children: _jsx(SectionCarousel, { title: title ?? "", items: cards, renderItem: (card) => _jsx(CardItem, { card: card }), keyExtractor: (card) => card.id, autoScroll: true, autoScrollInterval: scrollIntervalMs ?? 3500, perView: { base: 1, sm: 2, md: columns } }) }) }));
60
+ return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsx("div", { className: CLS_CONTAINER, children: _jsx(SectionCarousel, { title: title ?? "", items: cards, renderItem: (card) => _jsx(CardItem, { card: card }), keyExtractor: (card) => card.id, autoScroll: true, autoScrollInterval: scrollIntervalMs ?? 3500, perView: { base: 1, sm: 2, md: columns } }) }) }));
59
61
  }
60
62
  // Row layout: horizontal scroller
61
63
  if (layout === "row") {
62
- return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsxs("div", { className: "w-full max-w-7xl mx-auto px-4", children: [_jsx(SectionHeader, { title: title }), _jsx(HorizontalScroller, { gap: 16, showArrows: true, snapToItems: true, children: cards.map((card) => (_jsx("div", { className: "w-72 flex-shrink-0", children: _jsx(CardItem, { card: card }) }, card.id))) })] }) }));
64
+ return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsxs("div", { className: CLS_CONTAINER, children: [_jsx(SectionHeader, { title: title }), _jsx(HorizontalScroller, { gap: 16, showArrows: true, snapToItems: true, children: cards.map((card) => (_jsx("div", { className: "w-72 flex-shrink-0", children: _jsx(CardItem, { card: card }) }, card.id))) })] }) }));
63
65
  }
64
66
  // Masonry layout: CSS columns
65
67
  if (layout === "masonry") {
@@ -68,9 +70,9 @@ export function CustomCardsSection(config) {
68
70
  .split(" ")
69
71
  .map((c) => c.replace("grid-cols-", "columns-"))
70
72
  .join(" ");
71
- return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsxs("div", { className: "w-full max-w-7xl mx-auto px-4", children: [_jsx(SectionHeader, { title: title }), _jsx("div", { className: `${masonryClass} gap-4 space-y-4`, children: cards.map((card) => (_jsx("div", { className: "break-inside-avoid", children: _jsx(CardItem, { card: card }) }, card.id))) })] }) }));
73
+ return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsxs("div", { className: CLS_CONTAINER, children: [_jsx(SectionHeader, { title: title }), _jsx("div", { className: `${masonryClass} gap-4 space-y-4`, children: cards.map((card) => (_jsx("div", { className: "break-inside-avoid", children: _jsx(CardItem, { card: card }) }, card.id))) })] }) }));
72
74
  }
73
75
  // Grid layout (default)
74
76
  const colsClass = COLS_CLASS[columns] ?? COLS_CLASS[3];
75
- return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsxs("div", { className: "w-full max-w-7xl mx-auto px-4", children: [_jsx(SectionHeader, { title: title }), _jsx("div", { className: `grid ${colsClass} gap-4`, children: cards.map((card) => (_jsx(CardItem, { card: card }, card.id))) })] }) }));
77
+ return (_jsx(Section, { className: `py-12 ${themed.bgPrimary}`, children: _jsxs("div", { className: CLS_CONTAINER, children: [_jsx(SectionHeader, { title: title }), _jsx("div", { className: `grid ${colsClass} gap-4`, children: cards.map((card) => (_jsx(CardItem, { card: card }, card.id))) })] }) }));
76
78
  }
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef } from "react";
4
4
  import Link from "next/link";
5
5
  import { SectionCarousel } from "./SectionCarousel";
@@ -32,7 +32,7 @@ function ProductGrid({ items, rows, maxItems, pagination, viewMoreHref, viewMore
32
32
  return () => { if (timerRef.current)
33
33
  clearInterval(timerRef.current); };
34
34
  }, [pagination, pageSize, totalItems]);
35
- return (_jsx(Section, { className: `py-12 px-4 ${themed.bgPrimary}`, children: _jsxs("div", { className: "mx-auto max-w-7xl", children: [_jsxs("div", { className: "mb-6 flex items-end justify-between gap-4", children: [_jsxs("div", { children: [_jsx(Heading, { level: 2, className: `text-2xl font-bold md:text-3xl ${themed.textPrimary}`, children: title }), description && (_jsx(Text, { variant: "muted", className: "mt-1 text-sm", children: description }))] }), pagination === "arrows" && (_jsxs("div", { className: "flex shrink-0 gap-2", children: [_jsx("button", { type: "button", onClick: prev, disabled: !canPrev, "aria-label": "Previous", className: "flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 bg-white text-zinc-600 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] disabled:opacity-40 dark:border-slate-700 dark:bg-slate-900 dark:text-zinc-300", children: "\u2039" }), _jsx("button", { type: "button", onClick: next, disabled: !canNext, "aria-label": "Next", className: "flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 bg-white text-zinc-600 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] disabled:opacity-40 dark:border-slate-700 dark:bg-slate-900 dark:text-zinc-300", children: "\u203A" })] }))] }), _jsx("div", { className: "grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5", children: visible.map((product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.PRODUCT_DETAIL(product.slug ?? product.id ?? "")) }, product.id))) }), pagination === "load-more" && canNext && (_jsx("div", { className: "mt-8 text-center", children: _jsx("button", { type: "button", onClick: next, className: "rounded-lg border border-zinc-300 bg-white px-6 py-2 text-sm font-medium text-zinc-700 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] dark:border-slate-600 dark:bg-slate-900 dark:text-zinc-300", children: "Load more" }) })), viewMoreHref && (_jsx("div", { className: "mt-6 text-center", children: _jsx(Link, { href: viewMoreHref, className: "text-sm font-medium text-[var(--appkit-color-primary)] hover:opacity-80", children: viewMoreLabel }) }))] }) }));
35
+ return (_jsx(Section, { className: `py-12 px-4 ${themed.bgPrimary}`, children: _jsxs("div", { className: "mx-auto max-w-7xl", children: [_jsxs("div", { className: "mb-6 flex items-end justify-between gap-4", children: [_jsxs(_Fragment, { children: [_jsx(Heading, { level: 2, className: `text-2xl font-bold md:text-3xl ${themed.textPrimary}`, children: title }), description && (_jsx(Text, { variant: "muted", className: "mt-1 text-sm", children: description }))] }), pagination === "arrows" && (_jsxs("div", { className: "flex shrink-0 gap-2", children: [_jsx("button", { type: "button", onClick: prev, disabled: !canPrev, "aria-label": "Previous", className: "flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 bg-white text-zinc-600 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] disabled:opacity-40 dark:border-slate-700 dark:bg-slate-900 dark:text-zinc-300", children: "\u2039" }), _jsx("button", { type: "button", onClick: next, disabled: !canNext, "aria-label": "Next", className: "flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 bg-white text-zinc-600 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] disabled:opacity-40 dark:border-slate-700 dark:bg-slate-900 dark:text-zinc-300", children: "\u203A" })] }))] }), _jsx("div", { className: "grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5", children: visible.map((product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.PRODUCT_DETAIL(product.slug ?? product.id ?? "")) }, product.id))) }), pagination === "load-more" && canNext && (_jsx("div", { className: "mt-8 text-center", children: _jsx("button", { type: "button", onClick: next, className: "rounded-lg border border-zinc-300 bg-white px-6 py-2 text-sm font-medium text-zinc-700 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] dark:border-slate-600 dark:bg-slate-900 dark:text-zinc-300", children: "Load more" }) })), viewMoreHref && (_jsx("div", { className: "mt-6 text-center", children: _jsx(Link, { href: viewMoreHref, className: "text-sm font-medium text-[var(--appkit-color-primary)] hover:opacity-80", children: viewMoreLabel }) }))] }) }));
36
36
  }
37
37
  // --- Main component -----------------------------------------------------------
38
38
  export function FeaturedProductsSection({ title = "Featured Products", description, viewMoreHref, viewMoreLabel = "View all products →", className = "", filterByBrand, initialItems, rows = 1, maxItems, pagination = "load-more", }) {