@mohasinac/appkit 2.7.55 → 2.7.57

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 (276) hide show
  1. package/dist/_internal/shared/actions/action-registry.js +31 -5
  2. package/dist/client.d.ts +1 -3
  3. package/dist/client.js +1 -2
  4. package/dist/constants/field-names.d.ts +3 -0
  5. package/dist/constants/field-names.js +3 -0
  6. package/dist/features/about/components/FAQPageView.js +2 -2
  7. package/dist/features/about/components/FeesView.js +1 -1
  8. package/dist/features/about/components/PolicyPageView.js +1 -1
  9. package/dist/features/about/components/PublicProfileView.js +1 -1
  10. package/dist/features/account/components/AddressesIndexListing.js +1 -1
  11. package/dist/features/account/components/MessagesView.js +1 -1
  12. package/dist/features/account/components/NotificationPreferencesPanel.js +12 -3
  13. package/dist/features/account/components/UserOffersPanel.js +2 -2
  14. package/dist/features/account/components/UserSidebar.js +3 -3
  15. package/dist/features/account/components/UserSupportView.js +1 -1
  16. package/dist/features/admin/components/AdminAllEventEntriesView.js +1 -1
  17. package/dist/features/admin/components/AdminBidsView.js +5 -1
  18. package/dist/features/admin/components/AdminBlogView.js +6 -1
  19. package/dist/features/admin/components/AdminBrandsView.js +6 -1
  20. package/dist/features/admin/components/AdminBundleEditorView.js +13 -9
  21. package/dist/features/admin/components/AdminBundlesView.js +3 -1
  22. package/dist/features/admin/components/AdminCarouselEditorView.js +7 -8
  23. package/dist/features/admin/components/AdminCarouselView.js +4 -2
  24. package/dist/features/admin/components/AdminCartsView.js +1 -1
  25. package/dist/features/admin/components/AdminCategoriesView.js +6 -1
  26. package/dist/features/admin/components/AdminContactView.js +3 -1
  27. package/dist/features/admin/components/AdminCouponsView.js +4 -2
  28. package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -1
  29. package/dist/features/admin/components/AdminFaqsView.js +3 -1
  30. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
  31. package/dist/features/admin/components/AdminFeaturesView.js +4 -0
  32. package/dist/features/admin/components/AdminMediaView.js +10 -5
  33. package/dist/features/admin/components/AdminNavigationView.js +1 -1
  34. package/dist/features/admin/components/AdminNewsletterView.js +3 -1
  35. package/dist/features/admin/components/AdminNotificationsView.js +6 -1
  36. package/dist/features/admin/components/AdminOrdersView.js +10 -1
  37. package/dist/features/admin/components/AdminPayoutsView.js +5 -1
  38. package/dist/features/admin/components/AdminPrizeDrawsView.js +4 -0
  39. package/dist/features/admin/components/AdminProductsView.js +13 -1
  40. package/dist/features/admin/components/AdminReviewsView.js +6 -1
  41. package/dist/features/admin/components/AdminScammersView.js +1 -1
  42. package/dist/features/admin/components/AdminSectionsView.js +1 -1
  43. package/dist/features/admin/components/AdminSessionsView.js +5 -1
  44. package/dist/features/admin/components/AdminSidebar.js +3 -3
  45. package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
  46. package/dist/features/admin/components/AdminStoreEditorView.js +1 -1
  47. package/dist/features/admin/components/AdminStoresView.js +6 -1
  48. package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -0
  49. package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
  50. package/dist/features/admin/components/AdminSupportTicketsView.js +1 -1
  51. package/dist/features/admin/components/AdminTeamView.js +3 -1
  52. package/dist/features/admin/components/AdminUserEditorView.js +1 -1
  53. package/dist/features/admin/components/AdminUsersView.js +5 -1
  54. package/dist/features/admin/components/AdminViewCards.js +2 -2
  55. package/dist/features/admin/constants/filter-tabs.d.ts +9 -0
  56. package/dist/features/admin/constants/filter-tabs.js +3 -0
  57. package/dist/features/auctions/components/AuctionBottomActions.d.ts +7 -0
  58. package/dist/features/auctions/components/AuctionBottomActions.js +24 -0
  59. package/dist/features/auctions/components/AuctionDetailPageView.js +7 -7
  60. package/dist/features/auctions/components/AuctionsListView.js +1 -1
  61. package/dist/features/auctions/components/MarketplaceAuctionGrid.js +1 -1
  62. package/dist/features/auctions/components/PlaceBidFormClient.js +1 -1
  63. package/dist/features/auth/components/LoginForm.js +1 -1
  64. package/dist/features/auth/components/VerifyEmailView.js +2 -2
  65. package/dist/features/before-after/components/BeforeAfterGallery.js +1 -1
  66. package/dist/features/blog/components/BlogFeaturedCard.js +1 -1
  67. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  68. package/dist/features/blog/components/BlogListView.js +2 -2
  69. package/dist/features/blog/components/BlogPostView.js +8 -8
  70. package/dist/features/cart/components/CartDrawer.js +1 -1
  71. package/dist/features/cart/repository/cart.repository.js +11 -4
  72. package/dist/features/cart/schemas/firestore.d.ts +3 -0
  73. package/dist/features/categories/components/BrandDetailPageView.js +1 -1
  74. package/dist/features/categories/components/CategoriesIndexListing.js +1 -1
  75. package/dist/features/categories/components/CategoryDetailPageView.js +39 -3
  76. package/dist/features/categories/components/CategoryDetailTabs.d.ts +4 -1
  77. package/dist/features/categories/components/CategoryDetailTabs.js +7 -2
  78. package/dist/features/categories/components/CategoryGrid.js +1 -1
  79. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  80. package/dist/features/categories/components/CategoryStoresListing.d.ts +5 -0
  81. package/dist/features/categories/components/CategoryStoresListing.js +11 -0
  82. package/dist/features/categories/components/CategoryTableColumns.js +2 -2
  83. package/dist/features/categories/components/CategoryTree.js +1 -1
  84. package/dist/features/categories/components/index.d.ts +2 -0
  85. package/dist/features/categories/components/index.js +1 -0
  86. package/dist/features/checkout/components/CheckoutStepper.js +1 -1
  87. package/dist/features/classified/components/ClassifiedIndexListing.js +2 -0
  88. package/dist/features/classified/components/ClassifiedListView.js +1 -1
  89. package/dist/features/contact/components/ContactInfoSidebar.js +1 -1
  90. package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +2 -0
  91. package/dist/features/digital-codes/components/DigitalCodesListView.js +1 -1
  92. package/dist/features/events/components/AdminEventsView.js +5 -1
  93. package/dist/features/events/components/EventCard.js +1 -1
  94. package/dist/features/events/components/EventPollWidget.js +1 -1
  95. package/dist/features/events/components/EventStatusBadge.js +5 -5
  96. package/dist/features/events/components/EventsIndexListing.js +1 -1
  97. package/dist/features/events/components/EventsListView.js +2 -2
  98. package/dist/features/events/components/SpinWheelView.js +4 -2
  99. package/dist/features/filters/AsyncFacetSection.js +3 -3
  100. package/dist/features/filters/FilterFacetSection.js +5 -5
  101. package/dist/features/filters/RangeFilter.js +1 -1
  102. package/dist/features/forms/Input.js +2 -2
  103. package/dist/features/forms/Select.js +1 -1
  104. package/dist/features/forms/Slider.js +1 -1
  105. package/dist/features/forms/Textarea.js +1 -1
  106. package/dist/features/forms/utils.d.ts +1 -1
  107. package/dist/features/forms/utils.js +1 -1
  108. package/dist/features/history/hooks/useHistory.js +23 -10
  109. package/dist/features/homepage/components/AdvertisementBanner.js +2 -2
  110. package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
  111. package/dist/features/homepage/components/HeroSection.js +1 -1
  112. package/dist/features/homepage/components/NewsletterSection.js +1 -1
  113. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  114. package/dist/features/live/components/LiveItemsIndexListing.js +2 -0
  115. package/dist/features/live/components/LiveItemsListView.js +1 -1
  116. package/dist/features/orders/components/OrdersList.js +12 -12
  117. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
  118. package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
  119. package/dist/features/pre-orders/components/PreOrderBadge.js +5 -5
  120. package/dist/features/pre-orders/components/PreOrderBottomActions.d.ts +5 -0
  121. package/dist/features/pre-orders/components/PreOrderBottomActions.js +22 -0
  122. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +5 -5
  123. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +47 -0
  124. package/dist/features/pre-orders/components/PreOrdersListView.js +1 -1
  125. package/dist/features/pre-orders/components/PreorderCard.js +3 -3
  126. package/dist/features/products/components/AuctionsIndexListing.js +23 -0
  127. package/dist/features/products/components/BidHistory.js +2 -2
  128. package/dist/features/products/components/CompareOverlay.js +1 -1
  129. package/dist/features/products/components/CustomFieldsEditor.js +1 -1
  130. package/dist/features/products/components/CustomSectionTabContent.js +1 -1
  131. package/dist/features/products/components/CustomSectionsEditor.js +1 -1
  132. package/dist/features/products/components/GroupSettingsPanel.js +2 -2
  133. package/dist/features/products/components/MakeOfferButton.js +1 -1
  134. package/dist/features/products/components/PrizeDrawBottomActions.d.ts +6 -0
  135. package/dist/features/products/components/PrizeDrawBottomActions.js +24 -0
  136. package/dist/features/products/components/PrizeDrawDetailPageView.js +3 -5
  137. package/dist/features/products/components/PrizeDrawEntryActions.js +5 -18
  138. package/dist/features/products/components/PrizeRevealModal.js +5 -2
  139. package/dist/features/products/components/ProductDetailActions.d.ts +6 -1
  140. package/dist/features/products/components/ProductDetailActions.js +36 -6
  141. package/dist/features/products/components/ProductDetailPageView.js +17 -16
  142. package/dist/features/products/components/ProductGalleryClient.js +1 -1
  143. package/dist/features/products/components/ProductGrid.js +6 -6
  144. package/dist/features/products/components/ProductTabs.js +1 -1
  145. package/dist/features/products/components/ProductTabsShell.js +1 -1
  146. package/dist/features/products/components/ProductsIndexListing.js +47 -0
  147. package/dist/features/products/components/RelatedProducts.js +1 -1
  148. package/dist/features/products/components/ShowGroupSection.js +1 -1
  149. package/dist/features/products/components/SublistingCarouselSection.js +1 -1
  150. package/dist/features/products/components/SublistingCategorySelect.js +1 -1
  151. package/dist/features/products/components/index.d.ts +0 -2
  152. package/dist/features/products/components/index.js +0 -1
  153. package/dist/features/products/constants/action-defs.d.ts +7 -0
  154. package/dist/features/products/constants/action-defs.js +14 -0
  155. package/dist/features/products/constants/listing-tabs.d.ts +6 -0
  156. package/dist/features/products/constants/listing-tabs.js +1 -0
  157. package/dist/features/promotions/components/CouponCard.js +2 -2
  158. package/dist/features/promotions/components/CouponsIndexListing.js +2 -2
  159. package/dist/features/reviews/components/ReviewDetailPageView.js +1 -1
  160. package/dist/features/reviews/components/ReviewDetailShell.js +3 -3
  161. package/dist/features/reviews/components/ReviewModal.js +2 -2
  162. package/dist/features/reviews/components/ReviewSummary.js +1 -1
  163. package/dist/features/reviews/components/ReviewsIndexListing.js +1 -1
  164. package/dist/features/reviews/components/ReviewsList.js +1 -1
  165. package/dist/features/seller/components/SellerAddressesView.js +4 -3
  166. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +1 -1
  167. package/dist/features/seller/components/SellerAuctionsView.js +10 -3
  168. package/dist/features/seller/components/SellerBidsView.js +22 -7
  169. package/dist/features/seller/components/SellerBundlesView.js +10 -3
  170. package/dist/features/seller/components/SellerClassifiedView.js +10 -3
  171. package/dist/features/seller/components/SellerCouponsView.js +13 -4
  172. package/dist/features/seller/components/SellerDigitalCodesView.js +10 -3
  173. package/dist/features/seller/components/SellerGoogleReviewsView.js +10 -5
  174. package/dist/features/seller/components/SellerGroupedListingsView.js +2 -0
  175. package/dist/features/seller/components/SellerLiveView.js +10 -3
  176. package/dist/features/seller/components/SellerOffersPanel.js +2 -2
  177. package/dist/features/seller/components/SellerOffersView.js +1 -1
  178. package/dist/features/seller/components/SellerOrdersView.js +40 -17
  179. package/dist/features/seller/components/SellerPayoutMethodsView.js +13 -4
  180. package/dist/features/seller/components/SellerPayoutsView.js +1 -1
  181. package/dist/features/seller/components/SellerPreOrdersView.js +7 -2
  182. package/dist/features/seller/components/SellerPrizeDrawsView.js +7 -2
  183. package/dist/features/seller/components/SellerProductShell.js +27 -9
  184. package/dist/features/seller/components/SellerProductsCards.js +2 -1
  185. package/dist/features/seller/components/SellerProductsView.js +21 -8
  186. package/dist/features/seller/components/SellerReviewsView.js +8 -0
  187. package/dist/features/seller/components/SellerShippingConfigsView.js +13 -4
  188. package/dist/features/seller/components/SellerSidebar.js +2 -2
  189. package/dist/features/seller/components/SellerStoreCategoriesView.js +10 -3
  190. package/dist/features/seller/components/SellerTemplatesView.js +19 -6
  191. package/dist/features/shell/StepForm.js +9 -3
  192. package/dist/features/site-settings/components/ActionPermissionsManager.js +1 -1
  193. package/dist/features/site-settings/components/NavPermissionsManager.js +1 -1
  194. package/dist/features/stores/components/InteractiveStoreCard.js +1 -1
  195. package/dist/features/stores/components/StoreDetailLayoutView.js +1 -1
  196. package/dist/features/stores/components/StoreReviewsListing.js +1 -1
  197. package/dist/features/stores/components/StoresIndexListing.js +17 -1
  198. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +1 -1
  199. package/dist/features/wishlist/components/WishlistPage.js +2 -2
  200. package/dist/features/wishlist/hooks/useWishlistToggle.js +6 -1
  201. package/dist/index.d.ts +3 -2
  202. package/dist/index.js +6 -3
  203. package/dist/react/hooks/use-action-dispatch.d.ts +5 -0
  204. package/dist/react/hooks/use-action-dispatch.js +10 -0
  205. package/dist/seed/cart-seed-data.js +50 -3
  206. package/dist/seed/categories-seed-data.js +80 -16
  207. package/dist/seed/index.d.ts +3 -0
  208. package/dist/seed/index.js +3 -0
  209. package/dist/seed/manifest.js +15 -1
  210. package/dist/seed/products-classifieds-seed-data.d.ts +10 -0
  211. package/dist/seed/products-classifieds-seed-data.js +197 -0
  212. package/dist/seed/products-digital-codes-seed-data.d.ts +10 -0
  213. package/dist/seed/products-digital-codes-seed-data.js +204 -0
  214. package/dist/seed/products-live-items-seed-data.d.ts +13 -0
  215. package/dist/seed/products-live-items-seed-data.js +190 -0
  216. package/dist/styles.css +16 -1
  217. package/dist/tailwind-utilities.css +1 -1
  218. package/dist/tokens/index.d.ts +3 -3
  219. package/dist/tokens/index.js +3 -3
  220. package/dist/ui/DataTable.js +3 -3
  221. package/dist/ui/components/Button.style.css +15 -0
  222. package/dist/ui/components/Input.js +1 -1
  223. package/dist/ui/components/ListingToolbar.js +1 -1
  224. package/dist/ui/components/Select.js +1 -1
  225. package/dist/ui/components/StatsGrid.js +1 -1
  226. package/dist/ui/index.d.ts +0 -4
  227. package/dist/ui/index.js +0 -2
  228. package/package.json +1 -1
  229. package/dist/_internal/client/features/seller/print-center/InventoryLabel.d.ts +0 -12
  230. package/dist/_internal/client/features/seller/print-center/InventoryLabel.js +0 -49
  231. package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.d.ts +0 -7
  232. package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.js +0 -32
  233. package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.d.ts +0 -28
  234. package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.js +0 -33
  235. package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.d.ts +0 -12
  236. package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.js +0 -30
  237. package/dist/_internal/client/features/seller/print-center/PrintCenterView.d.ts +0 -12
  238. package/dist/_internal/client/features/seller/print-center/PrintCenterView.js +0 -102
  239. package/dist/_internal/client/features/seller/print-center/PrintGrid.d.ts +0 -12
  240. package/dist/_internal/client/features/seller/print-center/PrintGrid.js +0 -13
  241. package/dist/_internal/client/features/seller/print-center/StoreCard.d.ts +0 -19
  242. package/dist/_internal/client/features/seller/print-center/StoreCard.js +0 -30
  243. package/dist/_internal/client/features/seller/print-center/WebsiteCard.d.ts +0 -11
  244. package/dist/_internal/client/features/seller/print-center/WebsiteCard.js +0 -25
  245. package/dist/_internal/client/features/seller/print-center/index.d.ts +0 -11
  246. package/dist/_internal/client/features/seller/print-center/index.js +0 -10
  247. package/dist/_internal/client/features/seller/print-center/types.d.ts +0 -20
  248. package/dist/_internal/client/features/seller/print-center/types.js +0 -20
  249. package/dist/_internal/client/features/seller/print-center/useInventoryPdf.d.ts +0 -18
  250. package/dist/_internal/client/features/seller/print-center/useInventoryPdf.js +0 -76
  251. package/dist/features/account/repository/address.repository.d.ts +0 -17
  252. package/dist/features/account/repository/address.repository.js +0 -184
  253. package/dist/features/auctions/components/AuctionCard.d.ts +0 -29
  254. package/dist/features/auctions/components/AuctionCard.js +0 -38
  255. package/dist/features/categories/components/BundleAddToCartCta.d.ts +0 -16
  256. package/dist/features/categories/components/BundleAddToCartCta.js +0 -54
  257. package/dist/features/categories/components/CategoriesListView.d.ts +0 -31
  258. package/dist/features/categories/components/CategoriesListView.js +0 -27
  259. package/dist/features/products/components/AuctionsView.d.ts +0 -6
  260. package/dist/features/products/components/AuctionsView.js +0 -5
  261. package/dist/features/products/components/BuyBar.d.ts +0 -21
  262. package/dist/features/products/components/BuyBar.js +0 -19
  263. package/dist/features/products/components/PreOrdersView.d.ts +0 -6
  264. package/dist/features/products/components/PreOrdersView.js +0 -5
  265. package/dist/features/reviews/components/ReviewsListView.d.ts +0 -31
  266. package/dist/features/reviews/components/ReviewsListView.js +0 -16
  267. package/dist/features/stores/components/StoresListView.d.ts +0 -19
  268. package/dist/features/stores/components/StoresListView.js +0 -25
  269. package/dist/features/stores/repository/store-address.repository.d.ts +0 -55
  270. package/dist/features/stores/repository/store-address.repository.js +0 -187
  271. package/dist/ui/components/BulkActionsBar.d.ts +0 -18
  272. package/dist/ui/components/BulkActionsBar.js +0 -25
  273. package/dist/ui/components/CollageLightbox.d.ts +0 -18
  274. package/dist/ui/components/CollageLightbox.js +0 -41
  275. package/dist/ui/components/StickyBottomBar.d.ts +0 -22
  276. package/dist/ui/components/StickyBottomBar.js +0 -20
@@ -1,27 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import React from "react";
4
- import { Container, Div, Heading, Input, SlottedListingView, Text, } from "../../../ui";
5
- import { CategoryFilters } from "./CategoryFilters";
6
- import { CategorySortSelect } from "./CategorySortSelect";
7
- export function CategoriesListView({ labels = {}, table, filterVariant = "public", sortValue, onSortChange, renderSearch, renderSort, renderFilters, renderCategories, renderPagination, items = [], total = 0, isLoading = false, className = "", }) {
8
- const [search, setSearch] = React.useState("");
9
- const [sort, setSort] = React.useState("order");
10
- const resolvedSort = sortValue ?? table?.get("sorts") ?? sort;
11
- const handleSortChange = (next) => {
12
- onSortChange?.(next);
13
- if (!sortValue) {
14
- setSort(next);
15
- }
16
- table?.set("sorts", next);
17
- };
18
- const filtered = React.useMemo(() => {
19
- const q = search.trim().toLowerCase();
20
- if (!q)
21
- return items;
22
- return items.filter((c) => (c.name ?? "").toLowerCase().includes(q) ||
23
- (c.description ?? "").toLowerCase().includes(q));
24
- }, [items, search]);
25
- return (_jsx(Div, { className: `min-h-screen ${className}`, children: _jsx(Container, { size: "full", className: "py-8", children: _jsx(SlottedListingView, { portal: "public", inlineToolbar: true, className: "space-y-4", renderHeader: () => labels.title || labels.subtitle ? (_jsxs(Div, { className: "mb-2", children: [labels.title ? (_jsx(Heading, { level: 1, className: "text-2xl font-bold", children: labels.title })) : null, labels.subtitle ? (_jsx(Text, { variant: "secondary", className: "mt-1", children: labels.subtitle })) : null] })) : null, renderSearch: () => renderSearch?.(search, setSearch) ?? (_jsx(Input, { value: search, onChange: (event) => setSearch(event.target.value), placeholder: "Search categories", className: "max-w-sm" })), renderSort: () => renderSort ? (renderSort(resolvedSort, handleSortChange)) : (_jsx(CategorySortSelect, { value: resolvedSort, onChange: handleSortChange, variant: filterVariant })), renderFilters: () => renderFilters?.() ??
26
- (table ? _jsx(CategoryFilters, { table: table, variant: filterVariant }) : null), renderTable: () => renderCategories(filtered, isLoading), renderPagination: () => renderPagination?.(total) ?? null, total: total, isLoading: isLoading }) }) }));
27
- }
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- import type { SlottedListingViewProps } from "../../../ui";
3
- export interface AuctionsViewProps extends Omit<SlottedListingViewProps, "renderTable"> {
4
- renderGrid: (isLoading: boolean) => React.ReactNode;
5
- }
6
- export declare function AuctionsView({ renderGrid, ...props }: AuctionsViewProps): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { SlottedListingView } from "../../../ui";
3
- export function AuctionsView({ renderGrid, ...props }) {
4
- return (_jsx(SlottedListingView, { portal: "public", ...props, manageSearch: true, manageSort: true, inlineToolbar: true, renderTable: () => renderGrid(props.isLoading ?? false) }));
5
- }
@@ -1,21 +0,0 @@
1
- import React from "react";
2
- export interface BuyBarProps {
3
- children: React.ReactNode;
4
- /** Extra classes on the bar wrapper */
5
- className?: string;
6
- }
7
- /**
8
- * BuyBar — sticky mobile purchase action bar.
9
- *
10
- * Fixed above the bottom navigation (`bottom-16`) on mobile screens.
11
- * Hidden on `lg:` and above — desktop uses inline CTAs on the PDP.
12
- *
13
- * @example
14
- * ```tsx
15
- * <BuyBar>
16
- * <WishlistButton productId={product.id} />
17
- * <AddToCartButton productId={product.id} className="flex-1" />
18
- * </BuyBar>
19
- * ```
20
- */
21
- export declare function BuyBar({ children, className }: BuyBarProps): import("react/jsx-runtime").JSX.Element;
@@ -1,19 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Div } from "../../../ui";
3
- /**
4
- * BuyBar — sticky mobile purchase action bar.
5
- *
6
- * Fixed above the bottom navigation (`bottom-16`) on mobile screens.
7
- * Hidden on `lg:` and above — desktop uses inline CTAs on the PDP.
8
- *
9
- * @example
10
- * ```tsx
11
- * <BuyBar>
12
- * <WishlistButton productId={product.id} />
13
- * <AddToCartButton productId={product.id} className="flex-1" />
14
- * </BuyBar>
15
- * ```
16
- */
17
- export function BuyBar({ children, className }) {
18
- return (_jsx(Div, { className: `fixed bottom-16 inset-x-0 z-40 flex items-center gap-2 px-4 py-3 bg-white/95 dark:bg-zinc-900/95 backdrop-blur-sm border-t border-zinc-100 dark:border-zinc-800 lg:hidden pb-[env(safe-area-inset-bottom)]${className ? ` ${className}` : ""}`, role: "region", "aria-label": "Purchase actions", children: children }));
19
- }
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- import type { SlottedListingViewProps } from "../../../ui";
3
- export interface PreOrdersViewProps extends Omit<SlottedListingViewProps, "renderTable"> {
4
- renderGrid: (isLoading: boolean) => React.ReactNode;
5
- }
6
- export declare function PreOrdersView({ renderGrid, ...props }: PreOrdersViewProps): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { SlottedListingView } from "../../../ui";
3
- export function PreOrdersView({ renderGrid, ...props }) {
4
- return (_jsx(SlottedListingView, { portal: "public", ...props, manageSearch: true, renderTable: () => renderGrid(props.isLoading ?? false) }));
5
- }
@@ -1,31 +0,0 @@
1
- import React from "react";
2
- import type { Review, ReviewListParams, ReviewListResponse } from "../types";
3
- export interface ReviewsListViewProps {
4
- /** Optional initial SSR data */
5
- initialData?: ReviewListResponse;
6
- /** Query params passed to useReviews */
7
- params?: ReviewListParams;
8
- /** Rendered inside the page header */
9
- renderHeader?: (total: number) => React.ReactNode;
10
- /** Render search input */
11
- renderSearch?: (value: string, onChange: (v: string) => void) => React.ReactNode;
12
- /** Render sort dropdown */
13
- renderSort?: (value: string, onChange: (v: string) => void) => React.ReactNode;
14
- /** Render filter panel */
15
- renderFilters?: () => React.ReactNode;
16
- /** Render active filter chips */
17
- renderActiveFilters?: () => React.ReactNode;
18
- /** Render the data table / grid */
19
- renderResults: (items: Review[], isLoading: boolean) => React.ReactNode;
20
- /** Render pagination */
21
- renderPagination?: (total: number) => React.ReactNode;
22
- /** Render empty state */
23
- renderEmptyState?: () => React.ReactNode;
24
- labels?: {
25
- title?: string;
26
- subtitle?: string;
27
- subtitleWithCount?: (count: number) => string;
28
- };
29
- className?: string;
30
- }
31
- export declare function ReviewsListView({ initialData, params, renderHeader, renderSearch, renderSort, renderFilters, renderActiveFilters, renderResults, renderPagination, renderEmptyState, labels, className, }: ReviewsListViewProps): import("react/jsx-runtime").JSX.Element;
@@ -1,16 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import React from "react";
4
- import { Container, Div, Heading, Row, Text } from "../../../ui";
5
- import { useReviews } from "../hooks/useReviews";
6
- export function ReviewsListView({ initialData, params = { status: "approved", perPage: 200 }, renderHeader, renderSearch, renderSort, renderFilters, renderActiveFilters, renderResults, renderPagination, renderEmptyState, labels = {}, className = "", }) {
7
- const [search, setSearch] = React.useState("");
8
- const [sort, setSort] = React.useState("-rating");
9
- const { reviews, total, isLoading } = useReviews(params, { initialData });
10
- return (_jsx(Div, { className: `min-h-screen ${className}`, children: _jsxs(Container, { size: "full", className: "py-8", children: [renderHeader ? (renderHeader(total)) : (_jsxs(Div, { className: "mb-6", children: [_jsx(Heading, { level: 1, children: labels.title ?? "Reviews" }), _jsx(Text, { variant: "secondary", className: "mt-1", children: total > 0
11
- ? (labels.subtitleWithCount?.(total) ??
12
- `${total} reviews from our customers`)
13
- : (labels.subtitle ?? "See what our customers say") })] })), _jsxs(Row, { wrap: true, gap: "3", className: "mb-4", children: [renderSearch?.(search, setSearch), renderSort?.(sort, setSort), renderFilters?.()] }), renderActiveFilters?.(), !isLoading && total === 0 && renderEmptyState
14
- ? renderEmptyState()
15
- : renderResults(reviews, isLoading), renderPagination?.(total)] }) }));
16
- }
@@ -1,19 +0,0 @@
1
- import type { LayoutSlots } from "../../../contracts";
2
- import type { StoreListItem } from "../types";
3
- interface StoresListViewProps<T extends StoreListItem = StoreListItem> {
4
- stores: T[];
5
- labels?: {
6
- products?: string;
7
- reviews?: string;
8
- sold?: string;
9
- empty?: string;
10
- };
11
- total?: number;
12
- currentPage?: number;
13
- totalPages?: number;
14
- className?: string;
15
- /** Render-prop slot overrides — pass via `FeatureExtension.slots`. */
16
- slots?: LayoutSlots<T>;
17
- }
18
- export declare function StoresListView<T extends StoreListItem = StoreListItem>({ stores, labels, total, currentPage, totalPages, className, slots, }: StoresListViewProps<T>): import("react/jsx-runtime").JSX.Element;
19
- export {};
@@ -1,25 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import React from "react";
3
- import Link from "next/link";
4
- import { Div, Grid, Heading, RichText, Row, Span, Text } from "../../../ui";
5
- import { normalizeRichTextHtml } from "../../../utils/string.formatter";
6
- import { THEME_CONSTANTS } from "../../../tokens";
7
- function StoreCard({ store, labels = {}, className = "" }) {
8
- return (_jsxs(Link, { href: `/stores/${store.storeSlug ?? store.id}`, className: `block rounded-xl border border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 overflow-hidden shadow-sm hover:shadow-md transition-shadow ${className}`, children: [store.storeBannerURL ? (_jsx(Div, { className: "h-24 overflow-hidden bg-gray-100 dark:bg-slate-800", children: _jsx(Div, { role: "img", "aria-label": `${store.storeName} banner`, className: "h-full w-full bg-center bg-cover", style: { backgroundImage: `url(${store.storeBannerURL})` } }) })) : (_jsx(Div, { className: "h-24 bg-gradient-to-br from-orange-50 to-orange-100 dark:from-orange-900/20 dark:to-orange-800/20" })), _jsxs(Div, { className: "px-4 pb-4", children: [_jsx(Div, { className: "-mt-6 mb-3", children: store.storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": store.storeName, className: "h-12 w-12 rounded-lg border-2 border-white dark:border-slate-800 bg-center bg-cover shadow-sm", style: { backgroundImage: `url(${store.storeLogoURL})` } })) : (_jsx(Div, { className: "h-12 w-12 rounded-lg border-2 border-white dark:border-slate-800 bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center text-orange-600 dark:text-orange-400 font-bold shadow-sm", children: store.storeName[0]?.toUpperCase() })) }), _jsx(Heading, { level: 3, className: "font-semibold text-gray-900 dark:text-zinc-100 text-sm truncate", children: store.storeName }), store.storeDescription && (_jsx(RichText, { html: normalizeRichTextHtml(store.storeDescription), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: `mt-0.5 text-xs text-gray-500 dark:text-zinc-400 ${THEME_CONSTANTS.utilities.textClamp2}` })), _jsxs(Row, { className: "gap-3 mt-2 text-xs text-gray-400 dark:text-zinc-500", children: [store.totalProducts != null && (_jsxs(Span, { children: [store.totalProducts, " ", labels.products ?? "products"] })), store.itemsSold != null && (_jsxs(Span, { children: [store.itemsSold, " ", labels.sold ?? "sold"] })), store.averageRating != null && (_jsxs(Span, { children: ["\u2605 ", store.averageRating.toFixed(1)] }))] })] })] }));
9
- }
10
- export function StoresListView({ stores, labels = {}, total = 0, currentPage = 1, totalPages = 1, className = "", slots, }) {
11
- if (stores.length === 0) {
12
- if (slots?.renderEmptyState) {
13
- return _jsx(_Fragment, { children: slots.renderEmptyState() });
14
- }
15
- return (_jsx(Text, { className: "text-center text-gray-500 dark:text-zinc-400 py-12", children: labels.empty ?? "No stores found." }));
16
- }
17
- return (_jsxs(Div, { className: "space-y-4", children: [slots?.renderHeader
18
- ? slots.renderHeader({ total })
19
- : null, _jsx(Grid, { cols: "storeCards", gap: "md", className: className, children: stores.map((store, i) => slots?.renderCard ? (_jsx(React.Fragment, { children: slots.renderCard(store, i) }, store.id)) : (_jsx(StoreCard, { store: store, labels: labels }, store.id))) }), slots?.renderFooter
20
- ? slots.renderFooter({
21
- page: currentPage,
22
- totalPages,
23
- })
24
- : null] }));
25
- }
@@ -1,55 +0,0 @@
1
- /**
2
- * Store Address Repository
3
- *
4
- * Data access layer for store address documents stored as a subcollection:
5
- * stores/{storeSlug}/addresses/{addressId}
6
- *
7
- * Mirrors the user address repository but scoped to stores.
8
- */
9
- import type { StoreAddressDocument, StoreAddressCreateInput, StoreAddressUpdateInput } from "../schemas";
10
- declare class StoreAddressRepository {
11
- /**
12
- * Get the addresses subcollection reference for a store.
13
- */
14
- private getCollection;
15
- /** Decrypt PII fields after reading a store address doc from Firestore */
16
- private decryptAddress;
17
- /** Encrypt PII fields before writing a store address doc to Firestore */
18
- private encryptAddressData;
19
- /**
20
- * List all addresses for a store, ordered by createdAt desc.
21
- */
22
- findByStore(storeSlug: string): Promise<StoreAddressDocument[]>;
23
- /**
24
- * Find a single address belonging to a store.
25
- */
26
- findById(storeSlug: string, addressId: string): Promise<StoreAddressDocument | null>;
27
- /**
28
- * Find a single address or throw NotFoundError.
29
- */
30
- findByIdOrFail(storeSlug: string, addressId: string): Promise<StoreAddressDocument>;
31
- /**
32
- * Count the total number of addresses for a store.
33
- */
34
- count(storeSlug: string): Promise<number>;
35
- /**
36
- * Create a new store address.
37
- * If isDefault is true, clears the default flag from all other addresses first.
38
- */
39
- create(storeSlug: string, input: StoreAddressCreateInput): Promise<StoreAddressDocument>;
40
- /**
41
- * Update an existing store address.
42
- * If isDefault is set to true, clears the default flag from all other addresses.
43
- */
44
- update(storeSlug: string, addressId: string, input: StoreAddressUpdateInput): Promise<StoreAddressDocument>;
45
- /**
46
- * Delete a store address.
47
- */
48
- delete(storeSlug: string, addressId: string): Promise<void>;
49
- /**
50
- * Remove the isDefault flag from all addresses of a store.
51
- */
52
- private clearDefaultFlag;
53
- }
54
- export declare const storeAddressRepository: StoreAddressRepository;
55
- export {};
@@ -1,187 +0,0 @@
1
- /**
2
- * Store Address Repository
3
- *
4
- * Data access layer for store address documents stored as a subcollection:
5
- * stores/{storeSlug}/addresses/{addressId}
6
- *
7
- * Mirrors the user address repository but scoped to stores.
8
- */
9
- import { getAdminDb, getFirestoreCount, prepareForFirestore, deserializeTimestamps, } from "../../../providers/db-firebase";
10
- import { DatabaseError, NotFoundError } from "../../../errors";
11
- import { encryptPiiFields, decryptPiiFields, ADDRESS_PII_FIELDS, } from "../../../security";
12
- import { STORE_ADDRESS_SUBCOLLECTION, STORE_ADDRESS_FIELDS, STORE_COLLECTION, } from "../schemas";
13
- import { serverLogger } from "../../../monitoring";
14
- class StoreAddressRepository {
15
- /**
16
- * Get the addresses subcollection reference for a store.
17
- */
18
- getCollection(storeSlug) {
19
- return getAdminDb()
20
- .collection(STORE_COLLECTION)
21
- .doc(storeSlug)
22
- .collection(STORE_ADDRESS_SUBCOLLECTION);
23
- }
24
- /** Decrypt PII fields after reading a store address doc from Firestore */
25
- decryptAddress(doc) {
26
- return decryptPiiFields(doc, [
27
- ...ADDRESS_PII_FIELDS,
28
- ]);
29
- }
30
- /** Encrypt PII fields before writing a store address doc to Firestore */
31
- encryptAddressData(data) {
32
- return encryptPiiFields(data, [...ADDRESS_PII_FIELDS]);
33
- }
34
- /**
35
- * List all addresses for a store, ordered by createdAt desc.
36
- */
37
- async findByStore(storeSlug) {
38
- try {
39
- const snapshot = await this.getCollection(storeSlug)
40
- .orderBy(STORE_ADDRESS_FIELDS.CREATED_AT, "desc")
41
- .get();
42
- return snapshot.docs.map((doc) => this.decryptAddress(deserializeTimestamps({
43
- id: doc.id,
44
- ...doc.data(),
45
- })));
46
- }
47
- catch (error) {
48
- throw new DatabaseError(`Failed to list addresses for store: ${storeSlug}`, error);
49
- }
50
- }
51
- /**
52
- * Find a single address belonging to a store.
53
- */
54
- async findById(storeSlug, addressId) {
55
- try {
56
- const doc = await this.getCollection(storeSlug).doc(addressId).get();
57
- if (!doc.exists)
58
- return null;
59
- return this.decryptAddress(deserializeTimestamps({
60
- id: doc.id,
61
- ...doc.data(),
62
- }));
63
- }
64
- catch (error) {
65
- throw new DatabaseError(`Failed to find address ${addressId} for store ${storeSlug}`, error);
66
- }
67
- }
68
- /**
69
- * Find a single address or throw NotFoundError.
70
- */
71
- async findByIdOrFail(storeSlug, addressId) {
72
- const address = await this.findById(storeSlug, addressId);
73
- if (!address) {
74
- throw new NotFoundError(`Store address not found: ${addressId}`);
75
- }
76
- return address;
77
- }
78
- /**
79
- * Count the total number of addresses for a store.
80
- */
81
- async count(storeSlug) {
82
- try {
83
- return await getFirestoreCount(this.getCollection(storeSlug));
84
- }
85
- catch (error) {
86
- throw new DatabaseError(`Failed to count addresses for store: ${storeSlug}`, error);
87
- }
88
- }
89
- /**
90
- * Create a new store address.
91
- * If isDefault is true, clears the default flag from all other addresses first.
92
- */
93
- async create(storeSlug, input) {
94
- try {
95
- const collection = this.getCollection(storeSlug);
96
- if (input.isDefault) {
97
- await this.clearDefaultFlag(storeSlug);
98
- }
99
- const now = new Date();
100
- const docRef = collection.doc();
101
- const addressData = {
102
- ...input,
103
- createdAt: now,
104
- updatedAt: now,
105
- };
106
- const encrypted = this.encryptAddressData(addressData);
107
- await docRef.set(prepareForFirestore(encrypted));
108
- serverLogger.info("Store address created", {
109
- storeSlug,
110
- addressId: docRef.id,
111
- label: input.label,
112
- });
113
- return { id: docRef.id, ...addressData };
114
- }
115
- catch (error) {
116
- if (error instanceof DatabaseError || error instanceof NotFoundError)
117
- throw error;
118
- throw new DatabaseError(`Failed to create address for store: ${storeSlug}`, error);
119
- }
120
- }
121
- /**
122
- * Update an existing store address.
123
- * If isDefault is set to true, clears the default flag from all other addresses.
124
- */
125
- async update(storeSlug, addressId, input) {
126
- try {
127
- await this.findByIdOrFail(storeSlug, addressId);
128
- if (input.isDefault) {
129
- await this.clearDefaultFlag(storeSlug);
130
- }
131
- const encryptedInput = this.encryptAddressData(input);
132
- const updateData = {
133
- ...prepareForFirestore(encryptedInput),
134
- [STORE_ADDRESS_FIELDS.UPDATED_AT]: new Date(),
135
- };
136
- await this.getCollection(storeSlug).doc(addressId).update(updateData);
137
- const updated = await this.findByIdOrFail(storeSlug, addressId);
138
- serverLogger.info("Store address updated", { storeSlug, addressId });
139
- return updated;
140
- }
141
- catch (error) {
142
- if (error instanceof DatabaseError || error instanceof NotFoundError)
143
- throw error;
144
- throw new DatabaseError(`Failed to update address ${addressId} for store ${storeSlug}`, error);
145
- }
146
- }
147
- /**
148
- * Delete a store address.
149
- */
150
- async delete(storeSlug, addressId) {
151
- try {
152
- await this.findByIdOrFail(storeSlug, addressId);
153
- await this.getCollection(storeSlug).doc(addressId).delete();
154
- serverLogger.info("Store address deleted", { storeSlug, addressId });
155
- }
156
- catch (error) {
157
- if (error instanceof DatabaseError || error instanceof NotFoundError)
158
- throw error;
159
- throw new DatabaseError(`Failed to delete address ${addressId} for store ${storeSlug}`, error);
160
- }
161
- }
162
- /**
163
- * Remove the isDefault flag from all addresses of a store.
164
- */
165
- async clearDefaultFlag(storeSlug) {
166
- try {
167
- const db = getAdminDb();
168
- const snapshot = await this.getCollection(storeSlug)
169
- .where(STORE_ADDRESS_FIELDS.IS_DEFAULT, "==", true)
170
- .get();
171
- if (snapshot.empty)
172
- return;
173
- const batch = db.batch();
174
- snapshot.docs.forEach((doc) => {
175
- batch.update(doc.ref, {
176
- [STORE_ADDRESS_FIELDS.IS_DEFAULT]: false,
177
- [STORE_ADDRESS_FIELDS.UPDATED_AT]: new Date(),
178
- });
179
- });
180
- await batch.commit();
181
- }
182
- catch (error) {
183
- throw new DatabaseError(`Failed to clear default flag for store: ${storeSlug}`, error);
184
- }
185
- }
186
- }
187
- export const storeAddressRepository = new StoreAddressRepository();
@@ -1,18 +0,0 @@
1
- import React from "react";
2
- export interface BulkAction {
3
- key: string;
4
- label: string;
5
- icon?: React.ReactNode;
6
- onClick: () => void;
7
- variant?: "primary" | "secondary" | "danger";
8
- requiresAuth?: boolean;
9
- /** When true the button renders disabled (e.g. selection count out of range). */
10
- disabled?: boolean;
11
- }
12
- export interface BulkActionsBarProps {
13
- selectedCount: number;
14
- onClearSelection: () => void;
15
- actions: BulkAction[];
16
- isAuthenticated?: boolean;
17
- }
18
- export declare function BulkActionsBar({ selectedCount, onClearSelection, actions, isAuthenticated, }: BulkActionsBarProps): import("react/jsx-runtime").JSX.Element;
@@ -1,25 +0,0 @@
1
- "use client";
2
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
- import { X } from "lucide-react";
4
- import { Button } from "./Button";
5
- const ACTION_VARIANT_CLASS = {
6
- primary: "bg-[var(--appkit-color-primary,theme(colors.violet.600))] text-white hover:opacity-90 btn-glow",
7
- secondary: "border border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-slate-800",
8
- danger: "bg-[var(--appkit-color-danger,theme(colors.rose.500))] text-white hover:opacity-90",
9
- };
10
- export function BulkActionsBar({ selectedCount, onClearSelection, actions, isAuthenticated = false, }) {
11
- return (_jsx("div", { className: [
12
- "fixed inset-x-0 bottom-0 transition-transform duration-300 ease-out",
13
- selectedCount > 0 ? "translate-y-0" : "translate-y-full",
14
- ].join(" "), style: { zIndex: "var(--appkit-z-modal, 1000)" }, "aria-live": "polite", "aria-label": `${selectedCount} items selected`, children: _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 bg-white/[.98] dark:bg-slate-900/[.98] backdrop-blur-md px-4 py-3 shadow-2xl", children: _jsxs("div", { className: "mx-auto flex max-w-5xl items-center gap-3", children: [_jsxs("span", { className: "shrink-0 text-sm font-semibold text-zinc-700 dark:text-zinc-200", children: [selectedCount, " selected"] }), _jsx("div", { className: "h-4 w-px shrink-0 bg-zinc-200 dark:bg-slate-700" }), _jsx("div", { className: "flex flex-1 flex-wrap items-center gap-2", children: actions.map((action) => {
15
- if (action.requiresAuth && !isAuthenticated)
16
- return null;
17
- return (_jsxs("button", { type: "button", onClick: action.onClick, disabled: action.disabled, "aria-disabled": action.disabled || undefined, className: [
18
- "flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-semibold transition-all active:scale-95",
19
- ACTION_VARIANT_CLASS[action.variant ?? "secondary"],
20
- action.disabled ? "opacity-50 cursor-not-allowed pointer-events-none" : "",
21
- ]
22
- .filter(Boolean)
23
- .join(" "), children: [action.icon, action.label] }, action.key));
24
- }) }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onClearSelection, "aria-label": "Clear selection", className: "ml-auto flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-zinc-400 hover:bg-zinc-100 dark:hover:bg-slate-800 hover:text-zinc-600 dark:hover:text-zinc-200 transition-colors", children: _jsx(X, { className: "h-4 w-4" }) })] }) }) }));
25
- }
@@ -1,18 +0,0 @@
1
- export interface LightboxImage {
2
- src: string;
3
- alt: string;
4
- /** Short label shown in top-left corner of the enlarged image (e.g. "#1"). */
5
- badge?: string;
6
- /** Title/caption rendered below the image. */
7
- caption?: string;
8
- /** Secondary line below caption (e.g. formatted price or estimated value). */
9
- sub?: string;
10
- }
11
- export interface CollageLightboxProps {
12
- images: LightboxImage[];
13
- /** Index of the image that triggered the open — lightbox starts here. */
14
- initialIndex: number;
15
- onClose: () => void;
16
- }
17
- export declare function CollageLightbox({ images, initialIndex, onClose, }: CollageLightboxProps): import("react/jsx-runtime").JSX.Element;
18
- export default CollageLightbox;
@@ -1,41 +0,0 @@
1
- "use client";
2
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
- /**
4
- * CollageLightbox — full-screen image viewer for collage grids.
5
- *
6
- * Opens at the clicked index and cycles circularly through all images.
7
- * Keyboard: Escape = close, ArrowLeft/Right = navigate.
8
- * Clicking the backdrop closes the lightbox.
9
- */
10
- import React, { useCallback, useEffect } from "react";
11
- import { Div, Text } from "./index";
12
- export function CollageLightbox({ images, initialIndex, onClose, }) {
13
- const [current, setCurrent] = React.useState(initialIndex);
14
- const count = images.length;
15
- const prev = useCallback(() => setCurrent((i) => (i - 1 + count) % count), [count]);
16
- const next = useCallback(() => setCurrent((i) => (i + 1) % count), [count]);
17
- useEffect(() => {
18
- const onKey = (e) => {
19
- if (e.key === "Escape")
20
- onClose();
21
- else if (e.key === "ArrowLeft")
22
- prev();
23
- else if (e.key === "ArrowRight")
24
- next();
25
- };
26
- document.addEventListener("keydown", onKey);
27
- return () => document.removeEventListener("keydown", onKey);
28
- }, [onClose, prev, next]);
29
- const img = images[current];
30
- return (_jsx(Div, { className: "fixed inset-0 z-[var(--appkit-z-modal,9999)] flex items-center justify-center bg-black/92 backdrop-blur-sm", onClick: onClose, role: "dialog", "aria-modal": "true", "aria-label": "Image lightbox", children: _jsxs(Div, { className: "relative flex w-full max-w-5xl flex-col items-center px-4", onClick: (e) => e.stopPropagation(), children: [_jsxs(Div, { className: "mb-3 flex w-full items-center justify-between", children: [_jsxs(Text, { className: "text-sm font-medium text-white/60", children: [current + 1, " / ", count] }), _jsx("button", { onClick: onClose, className: "rounded-full bg-white/10 p-2 text-white transition-colors hover:bg-white/25", "aria-label": "Close lightbox", children: _jsx("svg", { className: "h-5 w-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), _jsxs(Div, { className: "flex w-full items-center gap-3", children: [_jsx("button", { onClick: prev, className: "flex-shrink-0 rounded-full bg-white/10 p-3 text-white transition-colors hover:bg-white/25 disabled:opacity-30", "aria-label": "Previous image", disabled: count <= 1, children: _jsx("svg", { className: "h-5 w-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }), _jsxs(Div, { className: "relative flex max-h-[68vh] flex-1 items-center justify-center overflow-hidden rounded-2xl bg-black/30", children: [img?.src ? (
31
- /* eslint-disable-next-line @next/next/no-img-element */
32
- _jsx("img", { src: img.src, alt: img.alt, className: "max-h-[68vh] w-full object-contain" }, img.src + current)) : (_jsx(Div, { className: "flex h-64 w-full items-center justify-center text-6xl text-white/30", children: "\uD83D\uDDBC\uFE0F" })), img?.badge ? (_jsx(Div, { className: "absolute left-3 top-3 rounded bg-black/70 px-2 py-1 text-xs font-semibold text-white", children: img.badge })) : null] }), _jsx("button", { onClick: next, className: "flex-shrink-0 rounded-full bg-white/10 p-3 text-white transition-colors hover:bg-white/25 disabled:opacity-30", "aria-label": "Next image", disabled: count <= 1, children: _jsx("svg", { className: "h-5 w-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) }) })] }), (img?.caption || img?.sub) && (_jsxs(Div, { className: "mt-3 text-center", children: [img.caption && (_jsx(Text, { className: "text-sm font-medium text-white", children: img.caption })), img.sub && (_jsx(Text, { className: "text-xs text-white/60", children: img.sub }))] })), count > 1 && (_jsx(Div, { className: "mt-4 flex max-w-full gap-2 overflow-x-auto pb-2", children: images.map((thumb, i) => (_jsx("button", { onClick: () => setCurrent(i), className: [
33
- "h-14 w-14 flex-shrink-0 overflow-hidden rounded-lg border-2 transition-all",
34
- i === current
35
- ? "scale-110 border-white"
36
- : "border-transparent opacity-50 hover:opacity-90",
37
- ].join(" "), "aria-label": `Go to image ${i + 1}`, children: thumb.src ? (
38
- /* eslint-disable-next-line @next/next/no-img-element */
39
- _jsx("img", { src: thumb.src, alt: thumb.alt, className: "h-full w-full object-cover" })) : (_jsx(Div, { className: "flex h-full w-full items-center justify-center bg-white/10 text-white/30 text-lg", children: "\uD83D\uDDBC\uFE0F" })) }, i))) }))] }) }));
40
- }
41
- export default CollageLightbox;
@@ -1,22 +0,0 @@
1
- /**
2
- * StickyBottomBar — fixed-bottom action bar that sits above the mobile
3
- * BottomNavLayout (when present) and below any modals.
4
- *
5
- * Reads `--bottom-nav-height` written by `BottomNavLayout` (4rem when the
6
- * navbar is rendered below `lg`, 0px otherwise). Falls back to 0px when the
7
- * variable is unset so the bar still pins to the viewport bottom on routes
8
- * that don't render a bottom nav.
9
- *
10
- * z-index sits above the navbar (`z-40`) but below modal overlays.
11
- */
12
- import React from "react";
13
- export interface StickyBottomBarProps {
14
- children: React.ReactNode;
15
- /** Optional extra className appended to the bar wrapper. */
16
- className?: string;
17
- /** Hide on `lg` and up. Defaults to `true` — matches BottomNavLayout's responsive scope. */
18
- mobileOnly?: boolean;
19
- /** Test id passthrough. */
20
- "data-testid"?: string;
21
- }
22
- export declare function StickyBottomBar({ children, className, mobileOnly, "data-testid": testId, }: StickyBottomBarProps): React.JSX.Element;
@@ -1,20 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- const BAR_STYLE = {
4
- bottom: "var(--bottom-nav-height, 0px)",
5
- zIndex: 45,
6
- };
7
- export function StickyBottomBar({ children, className, mobileOnly = true, "data-testid": testId, }) {
8
- return (_jsx("div", {
9
- // eslint-disable-next-line lir/no-inline-static-style
10
- style: BAR_STYLE, "data-testid": testId, className: [
11
- "fixed left-0 right-0",
12
- mobileOnly ? "lg:hidden" : "",
13
- "bg-white/95 dark:bg-slate-950/95 backdrop-blur-md",
14
- "border-t border-zinc-200 dark:border-slate-800",
15
- "shadow-2xl pb-safe",
16
- className ?? "",
17
- ]
18
- .filter(Boolean)
19
- .join(" "), children: children }));
20
- }