@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.
- package/dist/_internal/client/features/filters/filter-load-options.d.ts +29 -0
- package/dist/_internal/client/features/filters/filter-load-options.js +98 -0
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
- package/dist/_internal/server/features/checkout/actions.js +42 -35
- package/dist/_internal/server/features/classified/adapters.d.ts +21 -0
- package/dist/_internal/server/features/classified/adapters.js +24 -0
- package/dist/_internal/server/features/classified/index.d.ts +3 -0
- package/dist/_internal/server/features/classified/index.js +3 -0
- package/dist/_internal/server/features/classified/metadata.d.ts +8 -0
- package/dist/_internal/server/features/classified/metadata.js +43 -0
- package/dist/_internal/server/features/classified/og.d.ts +30 -0
- package/dist/_internal/server/features/classified/og.js +76 -0
- package/dist/_internal/server/features/digital-code/adapters.d.ts +21 -0
- package/dist/_internal/server/features/digital-code/adapters.js +29 -0
- package/dist/_internal/server/features/digital-code/index.d.ts +3 -0
- package/dist/_internal/server/features/digital-code/index.js +3 -0
- package/dist/_internal/server/features/digital-code/metadata.d.ts +8 -0
- package/dist/_internal/server/features/digital-code/metadata.js +36 -0
- package/dist/_internal/server/features/digital-code/og.d.ts +27 -0
- package/dist/_internal/server/features/digital-code/og.js +77 -0
- package/dist/_internal/server/features/live/adapters.d.ts +21 -0
- package/dist/_internal/server/features/live/adapters.js +34 -0
- package/dist/_internal/server/features/live/index.d.ts +3 -0
- package/dist/_internal/server/features/live/index.js +3 -0
- package/dist/_internal/server/features/live/metadata.d.ts +8 -0
- package/dist/_internal/server/features/live/metadata.js +39 -0
- package/dist/_internal/server/features/live/og.d.ts +27 -0
- package/dist/_internal/server/features/live/og.js +72 -0
- package/dist/_internal/server/features/promotions/actions.js +4 -3
- package/dist/_internal/server/jobs/core/onOrderCreate.js +19 -16
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +25 -22
- package/dist/_internal/server/jobs/core/onProductWrite.js +48 -58
- package/dist/_internal/shared/actions/action-registry.js +504 -9
- package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
- package/dist/_internal/shared/features/brands/schema.d.ts +5 -5
- package/dist/_internal/shared/features/cart/schema.d.ts +18 -18
- package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +38 -38
- package/dist/_internal/shared/features/events/schema.d.ts +8 -8
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/schema.d.ts +42 -42
- package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
- package/dist/_internal/shared/features/reviews/schema.d.ts +1 -1
- package/dist/_internal/shared/media/limits.js +4 -3
- package/dist/client.d.ts +4 -0
- package/dist/client.js +2 -0
- package/dist/configs/next.js +4 -0
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/constants/field-names.d.ts +1 -0
- package/dist/constants/field-names.js +1 -0
- package/dist/constants/table-keys.d.ts +6 -0
- package/dist/constants/table-keys.js +9 -0
- package/dist/core/hooks/useSyncManager.js +9 -8
- package/dist/features/about/components/FeesView.js +10 -7
- package/dist/features/about/components/HelpPageView.js +10 -1
- package/dist/features/about/components/HowAuctionsWorkView.js +10 -1
- package/dist/features/about/components/HowCheckoutWorksView.js +10 -1
- package/dist/features/about/components/HowOffersWorkView.js +10 -1
- package/dist/features/about/components/HowOrdersWorkView.js +10 -1
- package/dist/features/about/components/HowPayoutsWorkView.js +10 -1
- package/dist/features/about/components/HowPreOrdersWorkView.js +10 -1
- package/dist/features/about/components/HowReviewsWorkView.js +10 -1
- package/dist/features/about/components/PublicProfileView.js +46 -16
- package/dist/features/about/components/SecurityPrivacyView.js +7 -1
- package/dist/features/account/components/AddressesIndexListing.js +2 -2
- package/dist/features/account/components/NotificationBell.js +27 -16
- package/dist/features/account/components/NotificationPreferencesPanel.d.ts +9 -0
- package/dist/features/account/components/NotificationPreferencesPanel.js +91 -0
- package/dist/features/account/components/UserSidebar.js +4 -4
- package/dist/features/account/components/UserSupportView.js +16 -6
- package/dist/features/account/components/index.d.ts +2 -0
- package/dist/features/account/components/index.js +1 -0
- package/dist/features/account/schemas/index.d.ts +4 -4
- package/dist/features/account/types/index.d.ts +34 -0
- package/dist/features/admin/actions/admin-actions.js +4 -3
- package/dist/features/admin/actions/notification-actions.d.ts +24 -22
- package/dist/features/admin/actions/notification-actions.js +122 -22
- package/dist/features/admin/components/AdminAdEditorView.js +29 -15
- package/dist/features/admin/components/AdminAddressEditorView.d.ts +7 -0
- package/dist/features/admin/components/AdminAddressEditorView.js +117 -0
- package/dist/features/admin/components/AdminAdsView.js +22 -28
- package/dist/features/admin/components/AdminAllEventEntriesView.js +6 -1
- package/dist/features/admin/components/AdminBidsView.js +10 -3
- package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
- package/dist/features/admin/components/AdminBlogView.js +8 -3
- package/dist/features/admin/components/AdminBrandsView.js +7 -2
- package/dist/features/admin/components/AdminBundleEditorView.js +5 -2
- package/dist/features/admin/components/AdminCarouselEditorView.js +6 -3
- package/dist/features/admin/components/AdminCarouselView.js +13 -7
- package/dist/features/admin/components/AdminCategoriesView.js +8 -3
- package/dist/features/admin/components/AdminCategoryEditorView.js +12 -9
- package/dist/features/admin/components/AdminContactView.js +6 -1
- package/dist/features/admin/components/AdminCouponEditorView.js +8 -2
- package/dist/features/admin/components/AdminCouponsView.js +6 -1
- package/dist/features/admin/components/AdminEmployeeEditorView.js +12 -9
- package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
- package/dist/features/admin/components/AdminFaqsView.js +7 -2
- package/dist/features/admin/components/AdminFeatureFlagsView.js +58 -13
- package/dist/features/admin/components/AdminFeaturesView.js +4 -3
- package/dist/features/admin/components/AdminMediaView.js +9 -8
- package/dist/features/admin/components/AdminNavigationView.js +10 -17
- package/dist/features/admin/components/AdminNewsletterView.js +6 -1
- package/dist/features/admin/components/AdminNotificationsView.js +11 -3
- package/dist/features/admin/components/AdminOrdersView.js +6 -1
- package/dist/features/admin/components/AdminPayoutsView.js +10 -3
- package/dist/features/admin/components/AdminPrizeDrawsView.js +10 -3
- package/dist/features/admin/components/AdminProductEditorView.d.ts +3 -1
- package/dist/features/admin/components/AdminProductEditorView.js +12 -9
- package/dist/features/admin/components/AdminProductsView.js +18 -12
- package/dist/features/admin/components/AdminReturnRequestsView.js +5 -4
- package/dist/features/admin/components/AdminReviewsView.js +36 -26
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -2
- package/dist/features/admin/components/AdminScammersView.js +28 -26
- package/dist/features/admin/components/AdminSectionsView.js +112 -99
- package/dist/features/admin/components/AdminSessionsView.js +10 -3
- package/dist/features/admin/components/AdminSidebar.js +4 -4
- package/dist/features/admin/components/AdminSiteSettingsView.js +45 -4
- package/dist/features/admin/components/AdminStoresView.js +6 -1
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +0 -1
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +1 -1
- package/dist/features/admin/components/AdminSupportTicketsView.js +32 -34
- package/dist/features/admin/components/AdminTeamView.js +6 -1
- package/dist/features/admin/components/AdminUserEditorView.js +8 -15
- package/dist/features/admin/components/AdminUsersView.js +6 -1
- package/dist/features/admin/components/AdminViewCards.js +4 -3
- package/dist/features/admin/components/DashboardStats.js +2 -2
- package/dist/features/admin/components/DataTable.js +2 -2
- package/dist/features/admin/components/index.d.ts +2 -0
- package/dist/features/admin/components/index.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.js +4 -3
- package/dist/features/admin/repository/chat.repository.js +8 -8
- package/dist/features/admin/repository/site-settings.repository.d.ts +1 -0
- package/dist/features/admin/repository/site-settings.repository.js +11 -9
- package/dist/features/admin/schemas/firestore.d.ts +38 -0
- package/dist/features/admin/schemas/firestore.js +15 -0
- package/dist/features/auctions/components/AuctionBidsTable.d.ts +13 -0
- package/dist/features/auctions/components/AuctionBidsTable.js +62 -0
- package/dist/features/auctions/components/AuctionDetailPageView.js +15 -21
- package/dist/features/auctions/components/AuctionFilters.d.ts +7 -1
- package/dist/features/auctions/components/AuctionFilters.js +3 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +18 -9
- package/dist/features/auctions/components/MarketplaceAuctionGrid.js +3 -2
- package/dist/features/auctions/components/index.d.ts +2 -1
- package/dist/features/auctions/components/index.js +1 -1
- package/dist/features/auctions/schemas/index.d.ts +14 -14
- package/dist/features/auth/actions/realtime-token-actions.js +19 -4
- package/dist/features/auth/components/RegisterForm.js +8 -4
- package/dist/features/auth/consent-otp.d.ts +2 -0
- package/dist/features/auth/consent-otp.js +8 -0
- package/dist/features/auth/schemas/firestore.d.ts +2 -0
- package/dist/features/auth/schemas/firestore.js +18 -25
- package/dist/features/auth/schemas/index.d.ts +2 -2
- package/dist/features/before-after/api/[id]/route.js +8 -6
- package/dist/features/before-after/schemas/index.d.ts +2 -2
- package/dist/features/blog/actions/blog-actions.d.ts +3 -3
- package/dist/features/blog/components/BlogIndexListing.js +21 -2
- package/dist/features/blog/components/BlogPostForm.js +11 -5
- package/dist/features/blog/components/BlogPostView.js +10 -2
- package/dist/features/blog/schemas/index.d.ts +18 -18
- package/dist/features/cart/components/CartDrawer.js +3 -2
- package/dist/features/cart/components/CartView.js +2 -1
- package/dist/features/cart/components/CheckoutView.js +2 -1
- package/dist/features/cart/repository/cart.repository.js +4 -3
- package/dist/features/cart/utils/pending-ops.d.ts +1 -1
- package/dist/features/categories/api/[id]/route.js +4 -3
- package/dist/features/categories/api/route.js +4 -3
- package/dist/features/categories/components/BrandDetailPageView.js +2 -2
- package/dist/features/categories/components/BrandDetailTabs.d.ts +5 -1
- package/dist/features/categories/components/BrandDetailTabs.js +30 -16
- package/dist/features/categories/components/BundleCollage.d.ts +8 -0
- package/dist/features/categories/components/BundleCollage.js +50 -0
- package/dist/features/categories/components/BundleDetailView.js +2 -10
- package/dist/features/categories/components/BundleItemsPicker.js +20 -13
- package/dist/features/categories/components/CategoriesIndexListing.js +28 -9
- package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
- package/dist/features/categories/components/CategoryDetailTabs.d.ts +5 -1
- package/dist/features/categories/components/CategoryDetailTabs.js +31 -16
- package/dist/features/categories/components/CategoryProductsListing.js +52 -13
- package/dist/features/categories/components/index.d.ts +2 -0
- package/dist/features/categories/components/index.js +1 -0
- package/dist/features/categories/schemas/index.d.ts +6 -6
- package/dist/features/checkout/actions/checkout-actions.js +4 -3
- package/dist/features/checkout/hooks/usePaymentCheckout.js +31 -22
- package/dist/features/classified/components/ClassifiedFilters.d.ts +12 -0
- package/dist/features/classified/components/ClassifiedFilters.js +20 -0
- package/dist/features/classified/components/ClassifiedIndexListing.d.ts +4 -0
- package/dist/features/classified/components/ClassifiedIndexListing.js +110 -0
- package/dist/features/classified/components/ClassifiedListView.d.ts +6 -0
- package/dist/features/classified/components/ClassifiedListView.js +43 -0
- package/dist/features/classified/components/index.d.ts +6 -0
- package/dist/features/classified/components/index.js +3 -0
- package/dist/features/collections/api/[slug]/route.js +16 -12
- package/dist/features/collections/schemas/index.d.ts +5 -5
- package/dist/features/consultation/api/[id]/route.js +12 -9
- package/dist/features/consultation/components/ConsultationForm.js +3 -2
- package/dist/features/consultation/schemas/index.d.ts +6 -6
- package/dist/features/contact/email.js +77 -116
- package/dist/features/copilot/components/AdminCopilotView.js +12 -2
- package/dist/features/corporate/api/[id]/route.js +12 -9
- package/dist/features/corporate/components/CorporateInquiryForm.js +2 -1
- package/dist/features/digital-codes/components/DigitalCodeFilters.d.ts +12 -0
- package/dist/features/digital-codes/components/DigitalCodeFilters.js +17 -0
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +4 -0
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +107 -0
- package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +6 -0
- package/dist/features/digital-codes/components/DigitalCodesListView.js +37 -0
- package/dist/features/digital-codes/components/index.d.ts +6 -0
- package/dist/features/digital-codes/components/index.js +3 -0
- package/dist/features/events/actions/event-actions.js +4 -3
- package/dist/features/events/components/AdminEventEditorView.js +3 -2
- package/dist/features/events/components/AdminEventsView.js +4 -2
- package/dist/features/events/components/EventPollWidget.js +5 -5
- package/dist/features/events/components/EventsIndexListing.js +2 -2
- package/dist/features/events/repository/event-entry.repository.d.ts +1 -0
- package/dist/features/events/repository/event-entry.repository.js +5 -0
- package/dist/features/events/schemas/index.d.ts +20 -20
- package/dist/features/faq/actions/faq-actions.d.ts +8 -8
- package/dist/features/faq/components/ContactCTA.js +3 -1
- package/dist/features/faq/components/FAQAccordion.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +4 -4
- package/dist/features/filters/AsyncFacetSection.d.ts +18 -0
- package/dist/features/filters/AsyncFacetSection.js +65 -0
- package/dist/features/filters/index.d.ts +2 -0
- package/dist/features/filters/index.js +1 -0
- package/dist/features/forms/Checkbox.js +2 -2
- package/dist/features/forms/Input.js +2 -2
- package/dist/features/forms/Radio.js +5 -5
- package/dist/features/forms/Select.js +2 -2
- package/dist/features/forms/Slider.js +2 -2
- package/dist/features/forms/Textarea.js +2 -2
- package/dist/features/homepage/api/[id]/route.js +4 -3
- package/dist/features/homepage/api/sections/[id]/route.js +12 -9
- package/dist/features/homepage/components/AdSlot.js +2 -1
- package/dist/features/homepage/components/AdvertisementBanner.js +5 -3
- package/dist/features/homepage/components/BrandsSection.js +2 -2
- package/dist/features/homepage/components/CTABannerSection.js +2 -2
- package/dist/features/homepage/components/CharacterHotspot.d.ts +2 -2
- package/dist/features/homepage/components/CharacterHotspot.js +119 -157
- package/dist/features/homepage/components/CharacterHotspotForm.js +25 -20
- package/dist/features/homepage/components/CustomCardsSection.js +8 -6
- package/dist/features/homepage/components/FeaturedProductsSection.js +2 -2
- package/dist/features/homepage/components/GoogleReviewsSection.js +3 -3
- package/dist/features/homepage/components/HeroBanner.js +5 -4
- package/dist/features/homepage/components/HeroCarousel.js +13 -26
- package/dist/features/homepage/components/HowItWorksSection.js +4 -2
- package/dist/features/homepage/components/SocialFeedSection.js +2 -2
- package/dist/features/homepage/components/SocialPostCard.js +3 -2
- package/dist/features/homepage/lib/social-feed-fetcher.js +6 -3
- package/dist/features/layout/AppLayoutShell.d.ts +8 -2
- package/dist/features/layout/AppLayoutShell.js +54 -78
- package/dist/features/layout/BottomActions.js +43 -48
- package/dist/features/live/components/LiveItemFilters.d.ts +12 -0
- package/dist/features/live/components/LiveItemFilters.js +24 -0
- package/dist/features/live/components/LiveItemsIndexListing.d.ts +4 -0
- package/dist/features/live/components/LiveItemsIndexListing.js +108 -0
- package/dist/features/live/components/LiveItemsListView.d.ts +6 -0
- package/dist/features/live/components/LiveItemsListView.js +43 -0
- package/dist/features/live/components/index.d.ts +6 -0
- package/dist/features/live/components/index.js +3 -0
- package/dist/features/media/MediaLightbox.js +8 -14
- package/dist/features/media/types/index.d.ts +2 -2
- package/dist/features/media/upload/CameraCapture.js +2 -2
- package/dist/features/media/upload/ImageUpload.js +4 -2
- package/dist/features/media/upload/MediaUploadField.js +24 -8
- package/dist/features/media/upload/MediaUploadList.js +1 -1
- package/dist/features/orders/actions/order-actions.js +4 -3
- package/dist/features/orders/components/MarketplaceOrderCard.js +2 -1
- package/dist/features/orders/components/OrderFilters.js +12 -9
- package/dist/features/orders/schemas/index.d.ts +6 -6
- package/dist/features/pre-orders/api/[id]/route.js +12 -9
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +5 -4
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +29 -22
- package/dist/features/pre-orders/components/PreOrderFilters.d.ts +7 -1
- package/dist/features/pre-orders/components/PreOrderFilters.js +3 -2
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +17 -52
- package/dist/features/pre-orders/components/PreorderCard.d.ts +0 -9
- package/dist/features/pre-orders/components/PreorderCard.js +2 -13
- package/dist/features/pre-orders/components/index.d.ts +1 -1
- package/dist/features/pre-orders/components/index.js +1 -1
- package/dist/features/pre-orders/schemas/index.d.ts +10 -10
- package/dist/features/products/api/[id]/route.js +9 -7
- package/dist/features/products/api/route.js +1 -1
- package/dist/features/products/columns/productTableColumns.js +3 -3
- package/dist/features/products/components/AuctionsIndexListing.js +15 -51
- package/dist/features/products/components/BidHistory.js +2 -2
- package/dist/features/products/components/CompareOverlay.d.ts +2 -0
- package/dist/features/products/components/CompareOverlay.js +3 -2
- package/dist/features/products/components/MakeOfferButton.js +20 -14
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -1
- package/dist/features/products/components/PrizeDrawCollage.d.ts +1 -15
- package/dist/features/products/components/PrizeDrawCollage.js +54 -14
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +2 -1
- package/dist/features/products/components/PrizeDrawItemsEditor.js +9 -7
- package/dist/features/products/components/PrizeDrawsIndexListing.js +18 -51
- package/dist/features/products/components/PrizeRevealModal.js +24 -14
- package/dist/features/products/components/ProductDetailPageView.js +2 -1
- package/dist/features/products/components/ProductFilters.d.ts +7 -1
- package/dist/features/products/components/ProductFilters.js +11 -8
- package/dist/features/products/components/ProductForm.js +18 -16
- package/dist/features/products/components/ProductGalleryClient.js +2 -1
- package/dist/features/products/components/ProductGrid.js +12 -15
- package/dist/features/products/components/ProductsIndexListing.js +16 -52
- package/dist/features/products/components/ProductsIndexPageView.js +2 -2
- package/dist/features/products/repository/products.repository.d.ts +4 -0
- package/dist/features/products/repository/products.repository.js +22 -3
- package/dist/features/products/schemas/firestore.d.ts +7 -1
- package/dist/features/products/schemas/index.d.ts +56 -56
- package/dist/features/products/schemas/product-features.validators.d.ts +14 -14
- package/dist/features/products/types/index.d.ts +4 -0
- package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
- package/dist/features/promotions/schemas/index.d.ts +6 -6
- package/dist/features/reviews/actions/review-actions.js +6 -5
- package/dist/features/reviews/api/[id]/route.js +4 -3
- package/dist/features/reviews/components/ReviewDetailPageView.js +2 -2
- package/dist/features/reviews/components/ReviewDetailShell.js +6 -3
- package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
- package/dist/features/reviews/schemas/index.d.ts +6 -6
- package/dist/features/scams/components/ScamProfileView.js +19 -10
- package/dist/features/scams/components/ScamRegistryView.js +2 -1
- package/dist/features/search/components/Search.d.ts +1 -1
- package/dist/features/search/components/Search.js +56 -49
- package/dist/features/search/schemas/index.d.ts +5 -5
- package/dist/features/seller/actions/offer-actions.js +11 -9
- package/dist/features/seller/components/SellerAddressesView.js +6 -4
- package/dist/features/seller/components/SellerBidsView.js +2 -2
- package/dist/features/seller/components/SellerCouponsView.js +1 -1
- package/dist/features/seller/components/SellerOffersPanel.js +6 -1
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +3 -3
- package/dist/features/seller/components/SellerPreOrdersView.js +5 -4
- package/dist/features/seller/components/SellerPrizeDrawsView.js +5 -4
- package/dist/features/seller/components/SellerProductShell.d.ts +19 -1
- package/dist/features/seller/components/SellerProductShell.js +75 -9
- package/dist/features/seller/components/SellerProductsView.js +10 -11
- package/dist/features/seller/components/SellerShippingView.js +3 -3
- package/dist/features/seller/components/SellerSidebar.js +10 -7
- package/dist/features/seller/components/SellerStorefrontView.js +3 -3
- package/dist/features/seller/schemas/index.d.ts +4 -4
- package/dist/features/shell/FormShell.js +2 -1
- package/dist/features/shell/QuickFormDrawer.js +4 -3
- package/dist/features/shell/StepForm.js +4 -3
- package/dist/features/stores/actions/store-query-actions.js +4 -3
- package/dist/features/stores/components/StoreAboutView.js +2 -1
- package/dist/features/stores/components/StoreAuctionsListing.js +43 -64
- package/dist/features/stores/components/StoreDetailLayoutView.js +18 -4
- package/dist/features/stores/components/StorePreOrdersListing.js +33 -57
- package/dist/features/stores/components/StoreProductsListing.js +16 -49
- package/dist/features/stores/components/StoresIndexListing.js +2 -2
- package/dist/features/stores/schemas/index.d.ts +2 -2
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +8 -7
- package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +5 -5
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +6 -6
- package/dist/features/wishlist/utils/guest-wishlist.d.ts +5 -5
- package/dist/index.d.ts +27 -3
- package/dist/index.js +1743 -1725
- package/dist/monitoring/server-logger.js +5 -9
- package/dist/next/api/apiHandler.js +56 -37
- package/dist/next/components/GlobalError.js +2 -1
- package/dist/next/routing/route-map.d.ts +41 -0
- package/dist/next/routing/route-map.js +17 -0
- package/dist/react/ErrorBoundary.js +2 -1
- package/dist/react/contexts/SessionContext.js +38 -28
- package/dist/react/hooks/useCamera.d.ts +1 -1
- package/dist/react/hooks/useCamera.js +8 -7
- package/dist/seed/products-auctions-seed-data.js +40 -40
- package/dist/seed/products-preorders-seed-data.js +16 -16
- package/dist/seed/products-prize-draws-seed-data.js +4 -4
- package/dist/seed/products-standard-seed-data.js +202 -202
- package/dist/seed/site-settings-seed-data.js +6 -0
- package/dist/server-entry.d.ts +3 -0
- package/dist/server-entry.js +3 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.js +15 -0
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/DataTable.js +28 -7
- package/dist/ui/components/Button.d.ts +8 -1
- package/dist/ui/components/Button.js +47 -8
- package/dist/ui/components/CollageLightbox.d.ts +18 -0
- package/dist/ui/components/CollageLightbox.js +41 -0
- package/dist/ui/components/Dropdown.js +7 -6
- package/dist/ui/components/ImageLightbox.d.ts +7 -1
- package/dist/ui/components/ImageLightbox.js +15 -5
- package/dist/ui/components/PageLoader.js +4 -3
- package/dist/ui/components/PaginatedMultiSelect.d.ts +28 -0
- package/dist/ui/components/PaginatedMultiSelect.js +141 -0
- package/dist/ui/components/PaginatedMultiSelect.style.css +272 -0
- package/dist/ui/components/Semantic.js +1 -1
- package/dist/ui/components/SideDrawer.js +17 -15
- package/dist/ui/components/index.style.css +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/number.formatter.js +5 -13
- package/dist/utils/string.formatter.js +21 -18
- package/dist/validation/schemas.d.ts +2 -2
- 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
|
|
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:
|
|
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
|
-
:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
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", }) {
|