@mohasinac/appkit 4.10.0 → 4.11.1
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/layout/DashboardLayoutClient.d.ts +6 -1
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +4 -1
- package/dist/_internal/client/features/lottery/LotteryPullForm.d.ts +1 -1
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +2 -2
- package/dist/_internal/server/features/admin/daily-digest-actions.d.ts +18 -0
- package/dist/_internal/server/features/admin/daily-digest-actions.js +37 -0
- package/dist/_internal/server/features/audit-log/actions.d.ts +25 -0
- package/dist/_internal/server/features/audit-log/actions.js +38 -0
- package/dist/_internal/server/features/brands/actions.js +0 -2
- package/dist/_internal/server/features/brands/og.d.ts +4 -1
- package/dist/_internal/server/features/brands/og.js +1 -1
- package/dist/_internal/server/features/grouped/data.d.ts +4 -0
- package/dist/_internal/server/features/grouped/data.js +24 -0
- package/dist/_internal/server/features/grouped/index.d.ts +1 -1
- package/dist/_internal/server/features/grouped/index.js +1 -1
- package/dist/_internal/server/features/orders/actions.js +9 -0
- package/dist/_internal/server/features/orders/adapters.js +25 -0
- package/dist/_internal/server/features/products/data.d.ts +2 -2
- package/dist/_internal/server/features/products/data.js +5 -23
- package/dist/_internal/server/functions/scheduled.d.ts +3 -1
- package/dist/_internal/server/functions/scheduled.js +17 -1
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +40 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +164 -0
- package/dist/_internal/server/jobs/core/hardBanCascade.js +11 -0
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +1 -0
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +4 -1
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +12 -0
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +85 -0
- package/dist/_internal/server/jobs/core/whatsappNotify.js +16 -0
- package/dist/_internal/server/jobs/handlers/dailyStatusDigest.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/dailyStatusDigest.js +4 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/index.js +3 -0
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +2 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +27 -0
- package/dist/_internal/server/notifications/channel-health.js +101 -0
- package/dist/_internal/shared/features/brands/schema.d.ts +0 -6
- package/dist/_internal/shared/features/brands/schema.js +0 -1
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +7 -0
- package/dist/_internal/shared/features/categories/bundle-schemas.js +3 -0
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/to-product-item.d.ts +25 -0
- package/dist/_internal/shared/features/products/to-product-item.js +45 -0
- package/dist/client.d.ts +21 -6
- package/dist/client.js +13 -3
- package/dist/constants/api-endpoints.d.ts +6 -9
- package/dist/constants/api-endpoints.js +2 -3
- package/dist/contracts/client-auth.d.ts +3 -7
- package/dist/contracts/email.d.ts +1 -0
- package/dist/features/account/components/AddressForm.js +24 -2
- package/dist/features/account/components/BecomeSellerView.d.ts +1 -2
- package/dist/features/account/components/BecomeSellerView.js +1 -1
- package/dist/features/account/components/NotificationBell.js +1 -1
- package/dist/features/account/components/UserBidsView.d.ts +1 -0
- package/dist/features/account/components/UserBidsView.js +47 -0
- package/dist/features/account/components/UserOrdersView.d.ts +4 -11
- package/dist/features/account/components/UserOrdersView.js +54 -4
- package/dist/features/account/components/UserReturnsView.d.ts +4 -9
- package/dist/features/account/components/UserReturnsView.js +37 -3
- package/dist/features/account/components/index.d.ts +3 -2
- package/dist/features/account/components/index.js +1 -0
- package/dist/features/admin/actions/admin-actions.js +22 -0
- package/dist/features/admin/actions/admin-coupon-actions.js +10 -0
- package/dist/features/admin/actions/notification-actions.js +4 -3
- package/dist/features/admin/components/AdminAdsView.d.ts +2 -3
- package/dist/features/admin/components/AdminAdsView.js +86 -89
- package/dist/features/admin/components/AdminAllEventEntriesView.js +18 -3
- package/dist/features/admin/components/AdminAuditLogView.d.ts +11 -0
- package/dist/features/admin/components/AdminAuditLogView.js +95 -0
- package/dist/features/admin/components/AdminBlogEditorView.js +37 -3
- package/dist/features/admin/components/AdminBrandEditorView.js +10 -6
- package/dist/features/admin/components/AdminBundleEditorView.js +18 -2
- package/dist/features/admin/components/AdminCarouselEditorView.js +2 -2
- package/dist/features/admin/components/AdminCarouselGroupEditorView.js +2 -2
- package/dist/features/admin/components/AdminCartsView.js +34 -4
- package/dist/features/admin/components/AdminCategoryEditorView.js +5 -4
- package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
- package/dist/features/admin/components/AdminFaqEditorView.js +2 -2
- package/dist/features/admin/components/AdminHistoryView.js +11 -1
- package/dist/features/admin/components/AdminNotificationsView.js +27 -1
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +10 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
- package/dist/features/admin/components/AdminOrdersView.js +92 -24
- package/dist/features/admin/components/AdminPayoutMarkPaidModal.d.ts +7 -0
- package/dist/features/admin/components/AdminPayoutMarkPaidModal.js +47 -0
- package/dist/features/admin/components/AdminPayoutsView.js +15 -31
- package/dist/features/admin/components/AdminProductEditorView.js +26 -3
- package/dist/features/admin/components/AdminSiteSettingsView.js +20 -1
- package/dist/features/admin/components/AdminStoreAddressesView.js +22 -2
- package/dist/features/admin/components/AdminStoresView.js +7 -0
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +2 -2
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +2 -2
- package/dist/features/admin/components/AdminUserEditorView.d.ts +2 -2
- package/dist/features/admin/components/AdminUserEditorView.js +4 -2
- package/dist/features/admin/components/AdminUsersView.js +1 -1
- package/dist/features/admin/components/AdminWishlistsView.js +14 -1
- package/dist/features/admin/components/DataListingView.d.ts +2 -2
- package/dist/features/admin/components/ViewAuditLogEntryModal.d.ts +19 -0
- package/dist/features/admin/components/ViewAuditLogEntryModal.js +22 -0
- package/dist/features/admin/components/ViewNotificationModal.d.ts +21 -0
- package/dist/features/admin/components/ViewNotificationModal.js +15 -0
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +4 -7
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +56 -36
- package/dist/features/admin/components/index.d.ts +8 -1
- package/dist/features/admin/components/index.js +4 -0
- package/dist/features/admin/constants/filter-tabs.d.ts +49 -0
- package/dist/features/admin/constants/filter-tabs.js +27 -0
- package/dist/features/admin/hooks/useAdminListing.d.ts +6 -0
- package/dist/features/admin/hooks/useAdminListing.js +3 -1
- package/dist/features/admin/hooks/useAdminListingData.d.ts +9 -1
- package/dist/features/admin/hooks/useAdminListingData.js +9 -2
- package/dist/features/admin/repository/site-settings.repository.d.ts +5 -0
- package/dist/features/admin/schemas/firestore.d.ts +12 -0
- package/dist/features/analytics/types.d.ts +1 -1
- package/dist/features/analytics/types.js +8 -0
- package/dist/features/auctions/schemas/index.d.ts +5 -0
- package/dist/features/audit-log/repository/audit-log.repository.d.ts +45 -0
- package/dist/features/audit-log/repository/audit-log.repository.js +30 -0
- package/dist/features/audit-log/schemas/firestore.d.ts +59 -0
- package/dist/features/audit-log/schemas/firestore.js +35 -0
- package/dist/features/auth/actions/index.d.ts +0 -1
- package/dist/features/auth/actions/index.js +0 -1
- package/dist/features/auth/hooks/useAuth.d.ts +8 -35
- package/dist/features/auth/hooks/useAuth.js +21 -37
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/permissions/constants.js +2 -0
- package/dist/features/blog/schemas/index.d.ts +32 -0
- package/dist/features/catalogue/components/AdminCatalogueApprovalsView.js +31 -3
- package/dist/features/catalogue/components/CatalogueItemEditorView.js +2 -1
- package/dist/features/categories/components/BrandDetailPageView.js +14 -12
- package/dist/features/categories/components/CategoryDetailPageView.js +7 -3
- package/dist/features/categories/components/CategoryHighlightsAndFaqSection.d.ts +14 -0
- package/dist/features/categories/components/CategoryHighlightsAndFaqSection.js +22 -0
- package/dist/features/categories/components/CategoryProductsView.d.ts +1 -5
- package/dist/features/categories/components/CategoryProductsView.js +1 -1
- package/dist/features/categories/components/CategorySelectorCreate.js +16 -2
- package/dist/features/categories/schemas/firestore.d.ts +19 -2
- package/dist/features/categories/schemas/index.d.ts +24 -3
- package/dist/features/categories/schemas/index.js +3 -1
- package/dist/features/categories/types/index.d.ts +7 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +17 -3
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +101 -22
- package/dist/features/contact/components/ContactForm.js +17 -4
- package/dist/features/contact/email.d.ts +1 -0
- package/dist/features/contact/email.js +3 -0
- package/dist/features/events/components/AdminEventEditorView.js +54 -2
- package/dist/features/events/components/AdminEventEntriesView.d.ts +2 -16
- package/dist/features/events/components/AdminEventEntriesView.js +56 -89
- package/dist/features/events/components/EventFormDrawer.js +5 -1
- package/dist/features/events/components/EventRaffleEntryForm.d.ts +1 -3
- package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
- package/dist/features/events/schemas/index.d.ts +22 -0
- package/dist/features/grouped/components/GroupedListingsCarousel.js +4 -1
- package/dist/features/grouped/repository/grouped-listings.repository.d.ts +4 -0
- package/dist/features/grouped/repository/grouped-listings.repository.js +18 -0
- package/dist/features/homepage/components/CharacterHotspotForm.js +202 -187
- package/dist/features/homepage/components/SectionCarousel.d.ts +1 -7
- package/dist/features/homepage/components/SectionCarousel.js +1 -1
- package/dist/features/layout/TitleBarLayout.d.ts +1 -1
- package/dist/features/layout/TitleBarLayout.js +3 -3
- package/dist/features/media/MediaImage.js +39 -3
- package/dist/features/media/types/index.d.ts +10 -0
- package/dist/features/media/types/index.js +1 -0
- package/dist/features/media/upload/MediaUploadField.d.ts +7 -1
- package/dist/features/media/upload/MediaUploadField.js +11 -7
- package/dist/features/media/upload/video-poster.d.ts +2 -0
- package/dist/features/media/upload/video-poster.js +16 -1
- package/dist/features/media/upload/video-poster.test.js +1 -1
- package/dist/features/orders/components/OrderStatusTimeline.d.ts +12 -0
- package/dist/features/orders/components/OrderStatusTimeline.js +55 -0
- package/dist/features/orders/components/index.d.ts +2 -0
- package/dist/features/orders/components/index.js +1 -0
- package/dist/features/orders/constants/payment-window.d.ts +25 -0
- package/dist/features/orders/constants/payment-window.js +25 -0
- package/dist/features/orders/repository/orders.repository.d.ts +32 -0
- package/dist/features/orders/repository/orders.repository.js +56 -0
- package/dist/features/orders/schemas/index.d.ts +24 -24
- package/dist/features/orders/types/index.d.ts +33 -0
- package/dist/features/pre-orders/schemas/index.d.ts +5 -0
- package/dist/features/products/components/BidHistory.js +9 -1
- package/dist/features/products/components/GroupSettingsPanel.js +25 -3
- package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -4
- package/dist/features/products/components/PrizeDrawEntryActions.js +1 -1
- package/dist/features/products/components/ProductDetailActions.d.ts +1 -2
- package/dist/features/products/components/ProductDetailActions.js +1 -1
- package/dist/features/products/components/ProductGrid.js +15 -1
- package/dist/features/products/constants/action-defs.d.ts +1 -0
- package/dist/features/products/constants/action-defs.js +1 -0
- package/dist/features/products/schemas/index.d.ts +5 -0
- package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -3
- package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
- package/dist/features/search/components/SearchView.d.ts +1 -3
- package/dist/features/search/components/SearchView.js +1 -1
- package/dist/features/seller/components/QuickProductForm.js +2 -1
- package/dist/features/seller/components/SellerBidsView.js +66 -107
- package/dist/features/seller/components/SellerGoogleReviewsView.js +17 -1
- package/dist/features/seller/components/SellerOrdersView.d.ts +15 -3
- package/dist/features/seller/components/SellerOrdersView.js +134 -163
- package/dist/features/seller/components/SellerPayoutMethodsView.js +60 -48
- package/dist/features/seller/components/SellerPayoutSettingsView.js +69 -4
- package/dist/features/seller/components/SellerPayoutsView.d.ts +12 -0
- package/dist/features/seller/components/SellerPayoutsView.js +25 -5
- package/dist/features/seller/components/SellerProductShell.d.ts +10 -3
- package/dist/features/seller/components/SellerProductShell.js +89 -36
- package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +2 -7
- package/dist/features/seller/components/SellerProductsFilterDrawer.js +4 -4
- package/dist/features/seller/components/SellerProductsView.d.ts +2 -4
- package/dist/features/seller/components/SellerProductsView.js +131 -189
- package/dist/features/seller/components/SellerReviewsView.js +95 -133
- package/dist/features/seller/components/SellerShippingConfigsView.js +47 -67
- package/dist/features/seller/components/SellerShippingView.js +41 -4
- package/dist/features/seller/components/SellerStoreCategoriesView.js +51 -59
- package/dist/features/seller/components/SellerStorefrontView.d.ts +6 -1
- package/dist/features/seller/components/SellerStorefrontView.js +42 -5
- package/dist/features/seller/components/index.d.ts +2 -2
- package/dist/features/seller/components/index.js +2 -2
- package/dist/features/shell/FormShell.d.ts +24 -4
- package/dist/features/shell/FormShell.js +12 -6
- package/dist/features/shell/QuickFormDrawer.js +67 -12
- package/dist/features/shell/StepForm.d.ts +30 -1
- package/dist/features/shell/StepForm.js +47 -4
- package/dist/features/shell/index.d.ts +1 -1
- package/dist/features/shell/index.js +1 -1
- package/dist/features/shipments/components/AdminShipmentEditorView.js +2 -2
- package/dist/features/shipments/schemas/validation.d.ts +14 -4
- package/dist/features/tester/components/AdminTesterFeedbackListView.js +23 -2
- package/dist/features/tester/components/TesterChecklistStepRow.js +1 -1
- package/dist/features/tester/components/TesterHubView.js +3 -2
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +9 -1
- package/dist/features/tester/seed-data/products-tester-seed-data.js +43 -32
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +404 -15
- package/dist/index.d.ts +15 -3
- package/dist/index.js +22 -5
- package/dist/next/routing/route-map.d.ts +11 -0
- package/dist/next/routing/route-map.js +5 -0
- package/dist/providers/email-resend/provider.js +1 -0
- package/dist/providers/firebase-client/auth.d.ts +1 -0
- package/dist/providers/firebase-client/auth.js +7 -1
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +1 -0
- package/dist/schemas/registry.d.ts +61 -25
- package/dist/security/pii-mask.js +1 -1
- package/dist/seed/categories-seed-data.js +69 -0
- package/dist/seed/products-auctions-seed-data.js +11 -0
- package/dist/seed/products-standard-seed-data.js +93 -4
- package/dist/seed/site-settings-seed-data.js +13 -1
- package/dist/seed/store-extensions-seed-data.js +1 -1
- package/dist/server-entry.d.ts +2 -1
- package/dist/server-entry.js +20 -2
- package/dist/server.d.ts +7 -2
- package/dist/server.js +8 -3
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Form.d.ts +11 -2
- package/dist/ui/components/Form.js +4 -3
- package/dist/ui/components/FormField.d.ts +3 -1
- package/dist/ui/components/FormField.js +22 -4
- package/dist/ui/components/ListingLayout.d.ts +1 -2
- package/dist/ui/components/ListingLayout.js +1 -1
- package/dist/ui/components/RecordDetailModal.d.ts +68 -0
- package/dist/ui/components/RecordDetailModal.js +8 -0
- package/dist/ui/components/SlottedListingView.js +9 -1
- package/dist/ui/forms/FormErrorSummary.d.ts +25 -0
- package/dist/ui/forms/FormErrorSummary.js +37 -0
- package/dist/ui/forms/FormShell.d.ts +37 -2
- package/dist/ui/forms/FormShell.js +37 -7
- package/dist/ui/forms/FormShell.style.css +17 -0
- package/dist/ui/forms/index.d.ts +2 -0
- package/dist/ui/forms/index.js +1 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +5 -0
- package/dist/utils/media-url.d.ts +3 -1
- package/dist/utils/media-url.js +20 -1
- package/dist/validation/schemas.d.ts +4 -4
- package/package.json +1 -1
- package/dist/_internal/client/features/classified/ClassifiedDetailView.d.ts +0 -9
- package/dist/_internal/client/features/classified/ClassifiedDetailView.js +0 -55
- package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.d.ts +0 -18
- package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +0 -21
- package/dist/_internal/client/features/live/LiveItemDetailView.d.ts +0 -9
- package/dist/_internal/client/features/live/LiveItemDetailView.js +0 -25
- package/dist/_internal/server/jobs/core/prizeRevealClose.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealClose.js +0 -28
- package/dist/_internal/server/jobs/core/prizeRevealExpiry.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +0 -61
- package/dist/_internal/server/jobs/core/prizeRevealOpen.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealOpen.js +0 -68
- package/dist/_internal/server/jobs/core/prizeRevealReminder.d.ts +0 -2
- package/dist/_internal/server/jobs/core/prizeRevealReminder.js +0 -49
- package/dist/_internal/server/jobs/handlers/prizeRevealClose.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealClose.js +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealExpiry.js +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealOpen.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealOpen.js +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealReminder.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/prizeRevealReminder.js +0 -2
- package/dist/features/auth/consent-otp.d.ts +0 -57
- package/dist/features/auth/consent-otp.js +0 -127
- package/dist/features/cart/components/CheckoutOtpModal.d.ts +0 -15
- package/dist/features/cart/components/CheckoutOtpModal.js +0 -12
- package/dist/features/checkout/actions/checkout-actions.d.ts +0 -31
- package/dist/features/checkout/actions/checkout-actions.js +0 -124
- package/dist/features/classified/components/ClassifiedIndexListing.d.ts +0 -5
- package/dist/features/classified/components/ClassifiedIndexListing.js +0 -123
- package/dist/features/classified/components/ClassifiedListView.d.ts +0 -6
- package/dist/features/classified/components/ClassifiedListView.js +0 -44
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.d.ts +0 -5
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +0 -114
- package/dist/features/digital-codes/components/DigitalCodesListView.d.ts +0 -6
- package/dist/features/digital-codes/components/DigitalCodesListView.js +0 -38
- package/dist/features/live/components/LiveItemsIndexListing.d.ts +0 -5
- package/dist/features/live/components/LiveItemsIndexListing.js +0 -115
- package/dist/features/live/components/LiveItemsListView.d.ts +0 -6
- package/dist/features/live/components/LiveItemsListView.js +0 -44
- package/dist/features/seller/components/SellerTemplatesView.d.ts +0 -12
- package/dist/features/seller/components/SellerTemplatesView.js +0 -276
- package/dist/react/hooks/useVisibleItems.d.ts +0 -37
- package/dist/react/hooks/useVisibleItems.js +0 -59
- package/dist/ui/components/TabStrip.d.ts +0 -34
- package/dist/ui/components/TabStrip.js +0 -56
- package/dist/ui/components/TabStrip.style.css +0 -97
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
4
|
-
import { useState, useRef } from "react";
|
|
4
|
+
import { useEffect, useState, useRef } from "react";
|
|
5
|
+
import { z } from "zod";
|
|
5
6
|
import Image from "next/image";
|
|
6
7
|
import { Button, Details, Div, Heading, Input, Label, Li, Row, Span, Stack, Summary, Text, Textarea, Ul } from "../../../ui";
|
|
8
|
+
import { useFormShellState, FormShellContext, FormErrorSummary } from "../../../ui/forms";
|
|
7
9
|
import { resolveMediaUrl } from "../../../utils/media-url";
|
|
8
10
|
import { DEFAULT_ACCENT_HEX } from "../lib/franchise-colors";
|
|
11
|
+
// Validates the "Pin Details" step's draft fields — mirrors the existing
|
|
12
|
+
// `disabled={!draftName || !draftHref}` gates on that step's Save buttons.
|
|
13
|
+
const pinDetailsSchema = z.object({
|
|
14
|
+
draftName: z.string().min(1, "Name is required"),
|
|
15
|
+
draftUniverse: z.string().min(1, "Universe/Category is required"),
|
|
16
|
+
draftDescription: z.string().min(1, "Description is required"),
|
|
17
|
+
draftHref: z.string().min(1, "Link (href) is required"),
|
|
18
|
+
});
|
|
9
19
|
function randomId() {
|
|
10
20
|
return Math.random().toString(36).slice(2, 9);
|
|
11
21
|
}
|
|
@@ -36,6 +46,11 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
|
|
|
36
46
|
const [saving, setSaving] = useState(false);
|
|
37
47
|
const [error, setError] = useState(null);
|
|
38
48
|
const [success, setSuccess] = useState(false);
|
|
49
|
+
const { shellCtx, validate: validatePinDetails } = useFormShellState(pinDetailsSchema);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
validatePinDetails({ draftName, draftUniverse, draftDescription, draftHref });
|
|
52
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
+
}, [draftName, draftUniverse, draftDescription, draftHref]);
|
|
39
54
|
const containerRef = useRef(null);
|
|
40
55
|
async function handleImageUpload(e) {
|
|
41
56
|
const file = e.target.files?.[0];
|
|
@@ -119,204 +134,204 @@ export function CharacterHotspotForm({ initial, onUploadImage, onSave, onAfterSa
|
|
|
119
134
|
{ key: "review", label: "Review & Save" },
|
|
120
135
|
];
|
|
121
136
|
const stepIndex = STEPS.findIndex((s) => s.key === step);
|
|
122
|
-
return (_jsxs(Stack, { className: "mx-auto max-w-3xl", gap: "lg", children: [error && (_jsx(Text, { className: CLS_ERROR_BANNER, children: error })), success && (_jsx(Text, { className: CLS_SUCCESS_BANNER, children: "Saved to database successfully!" })), _jsx(Row, { align: "start", children: STEPS.map((s, i) => (_jsxs(Stack, { className: "flex-1", align: "center", children: [_jsxs(Row, { className: "w-full", align: "center", children: [i > 0 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
return (_jsx(FormShellContext.Provider, { value: shellCtx, children: _jsxs(Stack, { className: "mx-auto max-w-3xl", gap: "lg", children: [error && (_jsx(Text, { className: CLS_ERROR_BANNER, children: error })), success && (_jsx(Text, { className: CLS_SUCCESS_BANNER, children: "Saved to database successfully!" })), _jsx(Row, { align: "start", children: STEPS.map((s, i) => (_jsxs(Stack, { className: "flex-1", align: "center", children: [_jsxs(Row, { className: "w-full", align: "center", children: [i > 0 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
|
|
138
|
+
background: i <= stepIndex
|
|
139
|
+
? "var(--color-black)"
|
|
140
|
+
: "var(--border-ink)",
|
|
141
|
+
} })), _jsx(Row, { textWeight: "bold", textSize: "sm", className: "h-8 w-8 shrink-0", align: "center", justify: "center", rounded: "full", style: {
|
|
142
|
+
background: i < stepIndex
|
|
143
|
+
? "var(--color-black)"
|
|
144
|
+
: i === stepIndex
|
|
145
|
+
? "var(--color-yellow)"
|
|
146
|
+
: "var(--surface-elevated)",
|
|
147
|
+
color: i < stepIndex
|
|
130
148
|
? "var(--color-yellow)"
|
|
131
|
-
: "var(--
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
borderColor: "var(--border-ink)",
|
|
146
|
-
background: "var(--surface-elevated)",
|
|
147
|
-
}, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Upload Background Image" }), _jsx(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: "Choose a wide panoramic image that shows all the characters. You will place pins on it in the next step." }), _jsxs(Label, { layout: "flex-col-center", gap: "md", rounded: "lg", padding: "xl", className: "cursor-pointer border-2 border-dashed transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Span, { size: "3xl", children: "\uD83D\uDDBC" }), _jsx(Span, { weight: "medium", children: uploading ? "Uploading…" : "Click to choose image" }), _jsx(Span, { size: "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(Stack, { gap: "xs", children: [_jsx(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "37.5%" }, children: _jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "680px" }) }), _jsx(Text, { className: CLS_SUCCESS_TEXT, children: "\u2713 Image uploaded" })] })), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "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: {
|
|
148
|
-
borderColor: "var(--border-ink)",
|
|
149
|
-
background: "var(--surface-elevated)",
|
|
150
|
-
color: "var(--color-black)",
|
|
151
|
-
} })] }), _jsxs(Label, { layout: "inline-flex", gap: "md", className: "cursor-pointer", size: "sm", weight: "medium", children: [_jsx(Input, { type: "checkbox", checked: active, onChange: (e) => setActive(e.target.checked), className: "h-4 w-4 rounded" }), "Active (show on homepage)"] }), _jsxs(Row, { justify: "end", gap: "sm", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [(initial?.pins?.length ?? 0) > 0 && (_jsx(Button, { type: "button", onClick: () => setStep("review"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: {
|
|
152
|
-
background: "transparent",
|
|
153
|
-
color: "var(--color-black)",
|
|
154
|
-
}, children: "Skip to Review" })), _jsx(Button, { type: "button", onClick: () => setStep("place"), disabled: !imageUrl || uploading, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
|
|
155
|
-
background: "var(--color-black)",
|
|
156
|
-
color: "var(--color-yellow)",
|
|
157
|
-
}, children: "Next: Place Pins \u2192" })] })] })), step === "place" && (_jsxs(Div, { className: CLS_STEP, style: {
|
|
158
|
-
borderColor: "var(--border-ink)",
|
|
159
|
-
background: "var(--surface-elevated)",
|
|
160
|
-
}, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Place a Pin" }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: [_jsx(Span, { weight: "bold", children: "Click anywhere on the image" }), " to drop a pin, or enter exact coordinates below."] }), _jsxs(Div, { ref: containerRef, className: CLS_IMG_WRAP, style: {
|
|
161
|
-
paddingTop: "56.25%",
|
|
162
|
-
cursor: "crosshair",
|
|
163
|
-
background: "black",
|
|
164
|
-
}, onClick: handleImageClick, children: [_jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
|
|
165
|
-
left: `${pin.xPct}%`,
|
|
166
|
-
top: `${pin.yPct}%`,
|
|
167
|
-
transform: STY_CENTERED,
|
|
168
|
-
zIndex: 10,
|
|
169
|
-
}, children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: "text-white", align: "center", justify: "center", rounded: "full", style: {
|
|
170
|
-
width: 24,
|
|
171
|
-
height: 24,
|
|
172
|
-
background: pin.accent || DEFAULT_ACCENT_HEX,
|
|
173
|
-
border: "2px solid white",
|
|
174
|
-
boxShadow: "0 1px 4px rgba(0,0,0,0.5)",
|
|
175
|
-
}, children: "+" }), pin.name && (_jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-7 top-1/2 -translate-y-1/2 whitespace-nowrap text-[9px] text-white", rounded: "default", style: { paddingInline: "0.375rem", paddingBlock: "0.125rem", background: "black" }, children: pin.name }))] }, pin.id))), draftPos && (_jsxs(Div, { className: "absolute", style: {
|
|
176
|
-
left: `${draftPos.xPct}%`,
|
|
177
|
-
top: `${draftPos.yPct}%`,
|
|
178
|
-
transform: STY_CENTERED,
|
|
179
|
-
zIndex: 20,
|
|
180
|
-
}, children: [_jsx(Span, { className: "absolute animate-ping", rounded: "full", style: {
|
|
181
|
-
inset: -6,
|
|
182
|
-
background: "rgba(255,228,0,0.4)",
|
|
183
|
-
pointerEvents: "none",
|
|
184
|
-
} }), _jsx(Row, { textWeight: "bold", className: "relative", align: "center", justify: "center", rounded: "full", style: {
|
|
185
|
-
width: 32,
|
|
186
|
-
height: 32,
|
|
187
|
-
background: "var(--color-yellow)",
|
|
188
|
-
border: "3px solid var(--color-black)",
|
|
189
|
-
boxShadow: "0 2px 8px rgba(0,0,0,0.55)",
|
|
190
|
-
color: "var(--color-black)",
|
|
191
|
-
fontSize: 18,
|
|
192
|
-
}, children: "\u2605" }), _jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-9 top-1/2 -translate-y-1/2 whitespace-nowrap text-[10px]", padding: "x-xs", rounded: "default", style: { paddingBlock: "0.125rem", background: "var(--color-black)", color: "var(--color-yellow)" }, children: "NEW PIN" })] }))] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
|
|
193
|
-
{
|
|
194
|
-
label: "X Position (%)",
|
|
195
|
-
field: "xPct",
|
|
196
|
-
value: draftPos?.xPct ?? "",
|
|
197
|
-
onChange: (v) => setDraftPos((prev) => ({
|
|
198
|
-
id: prev?.id ?? randomId(),
|
|
199
|
-
xPct: Math.max(1, Math.min(99, v)),
|
|
200
|
-
yPct: prev?.yPct ?? 50,
|
|
201
|
-
})),
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
label: "Y Position (%)",
|
|
205
|
-
field: "yPct",
|
|
206
|
-
value: draftPos?.yPct ?? "",
|
|
207
|
-
onChange: (v) => setDraftPos((prev) => ({
|
|
208
|
-
id: prev?.id ?? randomId(),
|
|
209
|
-
xPct: prev?.xPct ?? 50,
|
|
210
|
-
yPct: Math.max(1, Math.min(99, v)),
|
|
211
|
-
})),
|
|
212
|
-
},
|
|
213
|
-
].map(({ label, field, value, onChange }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "number", min: 1, max: 99, step: 0.1, value: value, placeholder: "e.g. 42.5", onChange: (e) => {
|
|
214
|
-
const v = parseFloat(e.target.value);
|
|
215
|
-
if (!isNaN(v))
|
|
216
|
-
onChange(v);
|
|
217
|
-
}, className: CLS_INPUT, style: {
|
|
149
|
+
: "var(--color-black)",
|
|
150
|
+
border: i <= stepIndex
|
|
151
|
+
? "2px solid var(--color-black)"
|
|
152
|
+
: STY_BORDER_INK,
|
|
153
|
+
}, children: i < stepIndex ? "✓" : i + 1 }), i < STEPS.length - 1 && (_jsx(Div, { className: "h-0.5 flex-1", style: {
|
|
154
|
+
background: i < stepIndex
|
|
155
|
+
? "var(--color-black)"
|
|
156
|
+
: "var(--border-ink)",
|
|
157
|
+
} }))] }), _jsx(Span, { weight: "medium",
|
|
158
|
+
// audit-content-alignment-ok: label under a small draggable marker dot, admin editor UI not marketing content
|
|
159
|
+
className: "mt-1 text-center text-[10px]", style: { color: "var(--color-muted)" }, children: s.label })] }, s.key))) }), step === "image" && (_jsxs(Div, { className: CLS_STEP, style: {
|
|
160
|
+
borderColor: "var(--border-ink)",
|
|
161
|
+
background: "var(--surface-elevated)",
|
|
162
|
+
}, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Upload Background Image" }), _jsx(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: "Choose a wide panoramic image that shows all the characters. You will place pins on it in the next step." }), _jsxs(Label, { layout: "flex-col-center", gap: "md", rounded: "lg", padding: "xl", className: "cursor-pointer border-2 border-dashed transition-colors hover:opacity-80", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Span, { size: "3xl", children: "\uD83D\uDDBC" }), _jsx(Span, { weight: "medium", children: uploading ? "Uploading…" : "Click to choose image" }), _jsx(Span, { size: "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(Stack, { gap: "xs", children: [_jsx(Div, { className: CLS_IMG_WRAP, style: { paddingTop: "37.5%" }, children: _jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "680px" }) }), _jsx(Text, { className: CLS_SUCCESS_TEXT, children: "\u2713 Image uploaded" })] })), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "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: {
|
|
218
163
|
borderColor: "var(--border-ink)",
|
|
219
164
|
background: "var(--surface-elevated)",
|
|
220
165
|
color: "var(--color-black)",
|
|
221
|
-
} })] }
|
|
222
|
-
|
|
166
|
+
} })] }), _jsxs(Label, { layout: "inline-flex", gap: "md", className: "cursor-pointer", size: "sm", weight: "medium", children: [_jsx(Input, { type: "checkbox", checked: active, onChange: (e) => setActive(e.target.checked), className: "h-4 w-4 rounded" }), "Active (show on homepage)"] }), _jsxs(Row, { justify: "end", gap: "sm", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [(initial?.pins?.length ?? 0) > 0 && (_jsx(Button, { type: "button", onClick: () => setStep("review"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium rounded transition-opacity hover:opacity-70", style: {
|
|
167
|
+
background: "transparent",
|
|
168
|
+
color: "var(--color-black)",
|
|
169
|
+
}, children: "Skip to Review" })), _jsx(Button, { type: "button", onClick: () => setStep("place"), disabled: !imageUrl || uploading, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
|
|
170
|
+
background: "var(--color-black)",
|
|
171
|
+
color: "var(--color-yellow)",
|
|
172
|
+
}, children: "Next: Place Pins \u2192" })] })] })), step === "place" && (_jsxs(Div, { className: CLS_STEP, style: {
|
|
173
|
+
borderColor: "var(--border-ink)",
|
|
174
|
+
background: "var(--surface-elevated)",
|
|
175
|
+
}, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Place a Pin" }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: [_jsx(Span, { weight: "bold", children: "Click anywhere on the image" }), " to drop a pin, or enter exact coordinates below."] }), _jsxs(Div, { ref: containerRef, className: CLS_IMG_WRAP, style: {
|
|
176
|
+
paddingTop: "56.25%",
|
|
177
|
+
cursor: "crosshair",
|
|
178
|
+
background: "black",
|
|
179
|
+
}, onClick: handleImageClick, children: [_jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
|
|
180
|
+
left: `${pin.xPct}%`,
|
|
181
|
+
top: `${pin.yPct}%`,
|
|
182
|
+
transform: STY_CENTERED,
|
|
183
|
+
zIndex: 10,
|
|
184
|
+
}, children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: "text-white", align: "center", justify: "center", rounded: "full", style: {
|
|
185
|
+
width: 24,
|
|
186
|
+
height: 24,
|
|
187
|
+
background: pin.accent || DEFAULT_ACCENT_HEX,
|
|
188
|
+
border: "2px solid white",
|
|
189
|
+
boxShadow: "0 1px 4px rgba(0,0,0,0.5)",
|
|
190
|
+
}, children: "+" }), pin.name && (_jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-7 top-1/2 -translate-y-1/2 whitespace-nowrap text-[9px] text-white", rounded: "default", style: { paddingInline: "0.375rem", paddingBlock: "0.125rem", background: "black" }, children: pin.name }))] }, pin.id))), draftPos && (_jsxs(Div, { className: "absolute", style: {
|
|
191
|
+
left: `${draftPos.xPct}%`,
|
|
192
|
+
top: `${draftPos.yPct}%`,
|
|
193
|
+
transform: STY_CENTERED,
|
|
194
|
+
zIndex: 20,
|
|
195
|
+
}, children: [_jsx(Span, { className: "absolute animate-ping", rounded: "full", style: {
|
|
196
|
+
inset: -6,
|
|
197
|
+
background: "rgba(255,228,0,0.4)",
|
|
198
|
+
pointerEvents: "none",
|
|
199
|
+
} }), _jsx(Row, { textWeight: "bold", className: "relative", align: "center", justify: "center", rounded: "full", style: {
|
|
200
|
+
width: 32,
|
|
201
|
+
height: 32,
|
|
202
|
+
background: "var(--color-yellow)",
|
|
203
|
+
border: "3px solid var(--color-black)",
|
|
204
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.55)",
|
|
205
|
+
color: "var(--color-black)",
|
|
206
|
+
fontSize: 18,
|
|
207
|
+
}, children: "\u2605" }), _jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-9 top-1/2 -translate-y-1/2 whitespace-nowrap text-[10px]", padding: "x-xs", rounded: "default", style: { paddingBlock: "0.125rem", background: "var(--color-black)", color: "var(--color-yellow)" }, children: "NEW PIN" })] }))] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
|
|
208
|
+
{
|
|
209
|
+
label: "X Position (%)",
|
|
210
|
+
field: "xPct",
|
|
211
|
+
value: draftPos?.xPct ?? "",
|
|
212
|
+
onChange: (v) => setDraftPos((prev) => ({
|
|
213
|
+
id: prev?.id ?? randomId(),
|
|
214
|
+
xPct: Math.max(1, Math.min(99, v)),
|
|
215
|
+
yPct: prev?.yPct ?? 50,
|
|
216
|
+
})),
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
label: "Y Position (%)",
|
|
220
|
+
field: "yPct",
|
|
221
|
+
value: draftPos?.yPct ?? "",
|
|
222
|
+
onChange: (v) => setDraftPos((prev) => ({
|
|
223
|
+
id: prev?.id ?? randomId(),
|
|
224
|
+
xPct: prev?.xPct ?? 50,
|
|
225
|
+
yPct: Math.max(1, Math.min(99, v)),
|
|
226
|
+
})),
|
|
227
|
+
},
|
|
228
|
+
].map(({ label, field, value, onChange }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "number", min: 1, max: 99, step: 0.1, value: value, placeholder: "e.g. 42.5", onChange: (e) => {
|
|
229
|
+
const v = parseFloat(e.target.value);
|
|
230
|
+
if (!isNaN(v))
|
|
231
|
+
onChange(v);
|
|
232
|
+
}, className: CLS_INPUT, style: {
|
|
233
|
+
borderColor: "var(--border-ink)",
|
|
234
|
+
background: "var(--surface-elevated)",
|
|
223
235
|
color: "var(--color-black)",
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
236
|
+
} })] }, field))) }), pins.length > 0 && (_jsxs(Text, { style: { color: "var(--color-muted)" }, size: "xs", children: [pins.length, " pin", pins.length !== 1 ? "s" : "", " already placed on this image."] })), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => setStep("image"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-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-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-bold rounded transition-opacity", style: {
|
|
237
|
+
background: "var(--surface-warm)",
|
|
238
|
+
color: "var(--color-black)",
|
|
239
|
+
border: STY_BORDER_INK,
|
|
240
|
+
}, children: "Done Adding Pins" })), _jsx(Button, { type: "button", onClick: () => setStep("details"), disabled: !draftPos, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
|
|
241
|
+
background: "var(--color-black)",
|
|
242
|
+
color: "var(--color-yellow)",
|
|
243
|
+
}, children: "Continue: Add Details \u2192" })] })] })] })), step === "details" && (_jsxs(Div, { className: CLS_STEP, style: {
|
|
244
|
+
borderColor: "var(--border-ink)",
|
|
245
|
+
background: "var(--surface-elevated)",
|
|
246
|
+
}, children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Pin Details" }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "sm", children: ["Fill in the details for the pin at", " ", _jsxs(Span, { weight: "bold", children: [draftPos?.xPct, "%, ", draftPos?.yPct, "%"] }), "."] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
|
|
247
|
+
{
|
|
248
|
+
label: "Name *",
|
|
249
|
+
value: draftName,
|
|
250
|
+
onChange: setDraftName,
|
|
251
|
+
placeholder: "SPIDER-MAN",
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
label: "Universe / Category *",
|
|
255
|
+
value: draftUniverse,
|
|
256
|
+
onChange: setDraftUniverse,
|
|
257
|
+
placeholder: "Marvel",
|
|
258
|
+
},
|
|
259
|
+
].map(({ label, value, onChange, placeholder }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
|
|
260
|
+
borderColor: "var(--border-ink)",
|
|
261
|
+
background: "var(--surface-elevated)",
|
|
262
|
+
color: "var(--color-black)",
|
|
263
|
+
} })] }, label))) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Description *" }), _jsx(Textarea, { rows: 3, value: draftDescription, onChange: (e) => setDraftDescription(e.target.value), className: "resize-none rounded border-2 px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] outline-none", style: {
|
|
245
264
|
borderColor: "var(--border-ink)",
|
|
246
265
|
background: "var(--surface-elevated)",
|
|
247
266
|
color: "var(--color-black)",
|
|
248
|
-
} })] }
|
|
249
|
-
borderColor: "var(--border-ink)",
|
|
250
|
-
background: "var(--surface-elevated)",
|
|
251
|
-
color: "var(--color-black)",
|
|
252
|
-
}, placeholder: "Short description shown in the popup\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Link (href) *" }), _jsx(Input, { type: "text", value: draftHref, onChange: (e) => setDraftHref(e.target.value), placeholder: "/franchise/marvel", className: CLS_INPUT, style: {
|
|
253
|
-
borderColor: "var(--border-ink)",
|
|
254
|
-
background: "var(--surface-elevated)",
|
|
255
|
-
color: "var(--color-black)",
|
|
256
|
-
} })] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
|
|
257
|
-
{
|
|
258
|
-
label: "Button Text *",
|
|
259
|
-
value: draftBuyText,
|
|
260
|
-
onChange: setDraftBuyText,
|
|
261
|
-
placeholder: "Get Spider-Man Figures",
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
label: "Badge Label",
|
|
265
|
-
value: draftBadge,
|
|
266
|
-
onChange: setDraftBadge,
|
|
267
|
-
placeholder: "MARVEL",
|
|
268
|
-
},
|
|
269
|
-
].map(({ label, value, onChange, placeholder }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
|
|
267
|
+
}, placeholder: "Short description shown in the popup\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Link (href) *" }), _jsx(Input, { type: "text", value: draftHref, onChange: (e) => setDraftHref(e.target.value), placeholder: "/franchise/marvel", className: CLS_INPUT, style: {
|
|
270
268
|
borderColor: "var(--border-ink)",
|
|
271
269
|
background: "var(--surface-elevated)",
|
|
272
270
|
color: "var(--color-black)",
|
|
273
|
-
} })] }
|
|
271
|
+
} })] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2", children: [
|
|
272
|
+
{
|
|
273
|
+
label: "Button Text *",
|
|
274
|
+
value: draftBuyText,
|
|
275
|
+
onChange: setDraftBuyText,
|
|
276
|
+
placeholder: "Get Spider-Man Figures",
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
label: "Badge Label",
|
|
280
|
+
value: draftBadge,
|
|
281
|
+
onChange: setDraftBadge,
|
|
282
|
+
placeholder: "MARVEL",
|
|
283
|
+
},
|
|
284
|
+
].map(({ label, value, onChange, placeholder }) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: label }), _jsx(Input, { type: "text", value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, className: CLS_INPUT, style: {
|
|
274
285
|
borderColor: "var(--border-ink)",
|
|
275
286
|
background: "var(--surface-elevated)",
|
|
276
287
|
color: "var(--color-black)",
|
|
277
|
-
} })] }
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
background: "var(--
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
288
|
+
} })] }, label))) }), _jsxs(Row, { align: "end", gap: "sm", children: [_jsxs(Stack, { className: "flex-1", gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Accent Colour (hex)" }), _jsx(Input, { type: "text", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), placeholder: DEFAULT_ACCENT_HEX, className: CLS_INPUT, style: {
|
|
289
|
+
borderColor: "var(--border-ink)",
|
|
290
|
+
background: "var(--surface-elevated)",
|
|
291
|
+
color: "var(--color-black)",
|
|
292
|
+
} })] }), _jsx(Input, { type: "color", value: draftAccent, onChange: (e) => setDraftAccent(e.target.value), className: "mb-0.5 h-10 w-10 cursor-pointer rounded border-2", style: { borderColor: "var(--border-ink)" }, title: "Pick colour" })] }), _jsx(FormErrorSummary, {}), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => setStep("place"), variant: "ghost", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-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: [_jsx(Button, { type: "button", disabled: !draftName || !draftHref, onClick: () => {
|
|
293
|
+
commitDraftPin();
|
|
294
|
+
setStep("review");
|
|
295
|
+
}, variant: "outline", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
|
|
296
|
+
background: "var(--surface-warm)",
|
|
297
|
+
color: "var(--color-black)",
|
|
298
|
+
border: STY_BORDER_INK,
|
|
299
|
+
}, children: "Save Pin & Finish" }), _jsx(Button, { type: "button", disabled: !draftName || !draftHref, onClick: () => {
|
|
300
|
+
commitDraftPin();
|
|
301
|
+
setStep("place");
|
|
302
|
+
}, variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] rounded-[0.25rem] transition-opacity disabled:opacity-50", style: {
|
|
303
|
+
background: "var(--color-black)",
|
|
304
|
+
color: "var(--color-yellow)",
|
|
305
|
+
}, children: "Save Pin & Add Another \u2192" })] })] })] })), step === "review" && (_jsxs(Div, { className: CLS_STEP, style: {
|
|
306
|
+
borderColor: "var(--border-ink)",
|
|
307
|
+
background: "var(--surface-elevated)",
|
|
308
|
+
}, children: [_jsxs(Row, { justify: "between", children: [_jsx(Heading, { level: 2, size: "lg", weight: "bold", children: "Review & Save" }), _jsxs(Span, { rounded: "full", padding: "pill-md", size: "sm", weight: "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: "black" }, children: [_jsx(Image, { src: resolveMediaUrl(imageUrl), alt: imageAlt, fill: true, className: "object-cover", sizes: "(max-width: 680px) 100vw" }), pins.map((pin) => (_jsxs(Div, { className: "pointer-events-none absolute", style: {
|
|
309
|
+
left: `${pin.xPct}%`,
|
|
310
|
+
top: `${pin.yPct}%`,
|
|
311
|
+
transform: STY_CENTERED,
|
|
312
|
+
zIndex: 10,
|
|
313
|
+
}, children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: "text-white", align: "center", justify: "center", rounded: "full", style: {
|
|
314
|
+
width: 28,
|
|
315
|
+
height: 28,
|
|
316
|
+
background: pin.accent || DEFAULT_ACCENT_HEX,
|
|
317
|
+
border: "2px solid white",
|
|
318
|
+
boxShadow: "0 2px 6px rgba(0,0,0,0.55)",
|
|
319
|
+
}, children: "+" }), pin.name && (_jsx(Div, { textWeight: "bold", className: "pointer-events-none absolute left-8 top-1/2 -translate-y-1/2 whitespace-nowrap text-[9px] text-white", rounded: "default", style: { paddingInline: "0.375rem", paddingBlock: "0.125rem", background: "black" }, children: pin.name }))] }, pin.id)))] }), pins.length > 0 ? (_jsx(Ul, { rounded: "lg", className: "divide-y border", style: { borderColor: "var(--border-ink)" }, children: pins.map((pin, i) => (_jsx(Li, { padding: "inline", children: _jsxs(Row, { gap: "sm", children: [_jsx(Span, { layout: "flex-center", color: "inverse", className: "h-6 w-6 shrink-0", rounded: "full", size: "xs", weight: "bold", style: { background: pin.accent || DEFAULT_ACCENT_HEX }, children: i + 1 }), _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { className: "truncate", size: "sm", weight: "bold", children: pin.name || (_jsx(Span, { className: "italic", style: { color: "var(--color-muted)" }, children: "Unnamed" })) }), _jsxs(Text, { style: { color: "var(--color-muted)" }, size: "xs", children: [pin.universe, " \u00B7 ", pin.xPct.toFixed(0), "%,", " ", pin.yPct.toFixed(0), "%"] })] }), _jsx(Button, { type: "button", onClick: () => deletePin(pin.id), variant: "ghost", className: CLS_DELETE_PIN, title: "Remove pin", children: "\u2715" })] }) }, pin.id))) })) : (_jsx(Div, { textSize: "sm", className: "border-2 border-dashed text-left", rounded: "lg", padding: "xl", style: {
|
|
320
|
+
borderColor: "var(--border-ink)",
|
|
321
|
+
color: "var(--color-muted)",
|
|
322
|
+
}, children: "No pins yet \u2014 add some using the button below." })), _jsxs(Details, { rounded: "lg", padding: "md", className: "border", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Summary, { size: "sm", weight: "medium", children: "Image Settings" }), _jsxs(Stack, { className: "mt-3", gap: "3", children: [_jsxs(Label, { layout: "inline-flex", gap: "md", rounded: "default", padding: "toolbar", className: "cursor-pointer border-2 border-dashed transition-colors hover:opacity-80", size: "sm", weight: "medium", style: { borderColor: "var(--border-ink)" }, children: [uploading ? "Uploading…" : "Replace Image", _jsx(Input, { type: "file", accept: "image/*", className: "hidden", onChange: handleImageUpload, disabled: uploading })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { size: "sm", weight: "bold", children: "Image Alt Text" }), _jsx(Input, { type: "text", value: imageAlt, onChange: (e) => setImageAlt(e.target.value), className: CLS_INPUT, style: {
|
|
323
|
+
borderColor: "var(--border-ink)",
|
|
324
|
+
background: "var(--surface-elevated)",
|
|
325
|
+
color: "var(--color-black)",
|
|
326
|
+
} })] }), _jsxs(Label, { layout: "inline-flex", gap: "md", className: "cursor-pointer", size: "sm", weight: "medium", children: [_jsx(Input, { type: "checkbox", checked: active, onChange: (e) => setActive(e.target.checked), className: "h-4 w-4 rounded" }), "Active (show on homepage)"] })] })] }), _jsxs(Row, { justify: "between", className: "border-t", padding: "t-md", style: { borderColor: "var(--border-ink)" }, children: [_jsx(Button, { type: "button", onClick: () => {
|
|
327
|
+
setDraftPos(null);
|
|
328
|
+
setStep("place");
|
|
329
|
+
}, variant: "outline", className: "px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-bold rounded transition-opacity", style: {
|
|
330
|
+
background: "var(--surface-warm)",
|
|
331
|
+
color: "var(--color-black)",
|
|
332
|
+
border: STY_BORDER_INK,
|
|
333
|
+
}, children: "+ Add Another Pin" }), _jsx(Button, { type: "button", onClick: handleSave, disabled: !imageUrl || saving || pins.length === 0, rounded: "default", variant: "primary", className: "px-[1rem] py-[0.5rem] text-[0.875rem] font-[700] transition-opacity disabled:opacity-50", style: {
|
|
334
|
+
background: "var(--color-black)",
|
|
335
|
+
color: "var(--color-yellow)",
|
|
336
|
+
}, children: saving ? "Saving…" : "Save to Database" })] })] }))] }) }));
|
|
322
337
|
}
|
|
@@ -62,16 +62,10 @@ export interface SectionCarouselProps<T = unknown> {
|
|
|
62
62
|
* Defaults to `true` when `backgroundImage` is provided, `false` otherwise.
|
|
63
63
|
*/
|
|
64
64
|
lightText?: boolean;
|
|
65
|
-
/**
|
|
66
|
-
* When `true`, adds a negative right margin to the scroller wrapper so the
|
|
67
|
-
* last visible item peeks at the edge.
|
|
68
|
-
* Default: false
|
|
69
|
-
*/
|
|
70
|
-
showPeek?: boolean;
|
|
71
65
|
/**
|
|
72
66
|
* Minimum item width in px.
|
|
73
67
|
* Default: 220
|
|
74
68
|
*/
|
|
75
69
|
minItemWidth?: number;
|
|
76
70
|
}
|
|
77
|
-
export declare function SectionCarousel<T = unknown>({ title, description, headingVariant, pillLabel, backgroundImage, viewMoreHref, viewMoreLabel, items, renderItem, perView, gap, autoScroll, autoScrollInterval, loop, keyExtractor, rows, className, isLoading, skeletonCount, lightText,
|
|
71
|
+
export declare function SectionCarousel<T = unknown>({ title, description, headingVariant, pillLabel, backgroundImage, viewMoreHref, viewMoreLabel, items, renderItem, perView, gap, autoScroll, autoScrollInterval, loop, keyExtractor, rows, className, isLoading, skeletonCount, lightText, minItemWidth, }: SectionCarouselProps<T>): React.JSX.Element | null;
|
|
@@ -14,7 +14,7 @@ function CarouselSkeleton({ count }) {
|
|
|
14
14
|
return (_jsx(Div, { layout: "flex", gap: "4", className: `${__O.hidden}`, padding: "x-md", children: Array.from({ length: count }).map((_, i) => (_jsxs(Stack, { className: "flex-none min-w-[clamp(150px,18vw,260px)] max-w-[clamp(240px,36vw,380px)] h-[clamp(180px,26vh,260px)]", gap: "sm", children: [_jsx(Div, { className: `aspect-square ${skeleton.image}`, rounded: "xl" }), _jsx(Div, { className: `${skeleton.text} w-3/4` }), _jsx(Div, { className: `${skeleton.text} w-1/2` })] }, i))) }));
|
|
15
15
|
}
|
|
16
16
|
// --- Component ---------------------------------------------------------------
|
|
17
|
-
export function SectionCarousel({ title, description, headingVariant = "editorial", pillLabel, backgroundImage, viewMoreHref, viewMoreLabel = "View all →", items, renderItem, perView = CAROUSEL_PER_VIEW.standard, gap = 16, autoScroll = false, autoScrollInterval = 3500, loop = true, keyExtractor, rows = 1, className = "", isLoading = false, skeletonCount = 4, lightText,
|
|
17
|
+
export function SectionCarousel({ title, description, headingVariant = "editorial", pillLabel, backgroundImage, viewMoreHref, viewMoreLabel = "View all →", items, renderItem, perView = CAROUSEL_PER_VIEW.standard, gap = 16, autoScroll = false, autoScrollInterval = 3500, loop = true, keyExtractor, rows = 1, className = "", isLoading = false, skeletonCount = 4, lightText, minItemWidth = 220, }) {
|
|
18
18
|
const { hand } = useHandMode();
|
|
19
19
|
if (!isLoading && items.length === 0)
|
|
20
20
|
return null;
|
|
@@ -66,4 +66,4 @@ export interface TitleBarLayoutProps {
|
|
|
66
66
|
*
|
|
67
67
|
* Receives all domain data as props — zero domain imports.
|
|
68
68
|
*/
|
|
69
|
-
export declare function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen
|
|
69
|
+
export declare function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen, brandName, brandShortName, siteLogoUrl, logoHref, promotionsHref, compareHref, wishlistHref, wishlistCount, cartHref, cartCount, profileHref, unreadNotificationCount, notificationsHref, loginHref, registerHref, user, notificationSlot, devSlot, navSlot, promoStripText, isDark, onToggleTheme, onTourStart, hasDashboardNav, onToggleDashboardNav, hideSidebarToggle, id, className, }: TitleBarLayoutProps): React.JSX.Element;
|
|
@@ -14,7 +14,7 @@ const countBadge = "absolute -top-0.5 -right-0.5 flex items-center justify-cente
|
|
|
14
14
|
*
|
|
15
15
|
* Receives all domain data as props — zero domain imports.
|
|
16
16
|
*/
|
|
17
|
-
export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen
|
|
17
|
+
export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, searchOpen, brandName, brandShortName, siteLogoUrl, logoHref, promotionsHref, compareHref, wishlistHref, wishlistCount = 0, cartHref, cartCount = 0, profileHref, unreadNotificationCount = 0, notificationsHref, loginHref, registerHref, user, notificationSlot, devSlot, navSlot, promoStripText, isDark = false, onToggleTheme, onTourStart, hasDashboardNav, onToggleDashboardNav, hideSidebarToggle = false, id = "titlebar", className = "", }) {
|
|
18
18
|
// ── Element builders ────────────────────────────────────────────────────────
|
|
19
19
|
const promotionsEl = promotionsHref ? (_jsxs(Link, { href: promotionsHref, "aria-label": "Today's deals", className: "flex items-center gap-[var(--appkit-space-1)] px-[var(--appkit-space-3)] py-[var(--appkit-space-1)] rounded-full text-[length:var(--appkit-text-xs)] font-bold bg-primary-100 text-primary-700 dark:bg-secondary-900/40 dark:text-secondary-400 hover:bg-primary-200 dark:hover:bg-secondary-900/60 transition-colors border border-primary-200/60 dark:border-secondary-700/40", children: [_jsx("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { d: "M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9-2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.37.86.58 1.41.58.55 0 1.05-.21 1.41-.59l7-7c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7z" }) }), _jsx(Span, { className: "hidden sm:inline", children: "Today's Deals" })] })) : null;
|
|
20
20
|
const themeBtn = onToggleTheme ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": isDark ? "Switch to light mode" : "Switch to dark mode", onClick: onToggleTheme, className: iconBtn, children: isDark ? (_jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 3v1m0 16v1m8.66-9h-1M4.34 12h-1m15.07-6.07-.71.71M6.34 17.66l-.71.71m12.73 0-.71-.71M6.34 6.34l-.71-.71M12 5a7 7 0 1 0 0 14A7 7 0 0 0 12 5z" }) })) : (_jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 12.79A9 9 0 1 1 11.21 3a7 7 0 1 0 9.79 9.79z" }) })) })) : null;
|
|
@@ -22,7 +22,7 @@ export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, s
|
|
|
22
22
|
const hamburgerBtn = !hideSidebarToggle ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": sidebarOpen ? "Close menu" : hasDashboardNav ? "Open dashboard navigation" : "Open menu", "aria-expanded": sidebarOpen, "aria-controls": "secondary-sidebar", onClick: hasDashboardNav && onToggleDashboardNav ? onToggleDashboardNav : onToggleSidebar, className: iconBtn, children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: sidebarOpen ? (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })) : (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" })) }) })) : null;
|
|
23
23
|
// Compare is always lg+ (desktop-only feature, less critical on mobile)
|
|
24
24
|
const compareEl = compareHref ? (_jsx(Link, { href: compareHref, "aria-label": "Compare items", className: `${iconBtn} hidden lg:flex`, children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" }) }) })) : null;
|
|
25
|
-
const searchBtn = (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": "Search", onClick: onSearchToggle, className: iconBtn, "data-tour": "nav-search", children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z" }) }) }));
|
|
25
|
+
const searchBtn = (_jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": "Search", "aria-pressed": searchOpen, onClick: onSearchToggle, className: iconBtn, "data-tour": "nav-search", children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z" }) }) }));
|
|
26
26
|
// Dedicated notification bell — rendered immediately before the wishlist
|
|
27
27
|
// icon (per layout request). Falls back to invisible when no href is set;
|
|
28
28
|
// the count badge mirrors the wishlist/cart pattern.
|
|
@@ -33,7 +33,7 @@ export function TitleBarLayout({ onToggleSidebar, sidebarOpen, onSearchToggle, s
|
|
|
33
33
|
const authButtonsEl = !user && (loginHref || registerHref) ? (_jsxs(Row, { gap: "xs", className: "hidden lg:flex", children: [loginHref && (_jsx(Link, { href: loginHref, className: "px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-sm)] font-medium text-[var(--appkit-color-text-muted)] hover:text-primary-700 dark:hover:text-secondary-400 transition-colors rounded-lg hover:bg-primary-50 dark:hover:bg-[var(--appkit-color-surface-elevated)]", children: "Sign in" })), registerHref && (_jsx(Link, { href: registerHref, className: "px-[var(--appkit-space-3)] py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-sm)] font-semibold rounded-lg bg-primary text-white hover:bg-primary/90 transition-colors btn-glow shadow-sm", children: "Register" }))] })) : null;
|
|
34
34
|
const hasTb2 = !!(notificationsEl || wishlistEl || cartEl || profileEl);
|
|
35
35
|
// ── Render ───────────────────────────────────────────────────────────────────
|
|
36
|
-
return (_jsxs(BlockHeader, { id: id, className: `sticky top-0 z-50 bg-[var(--appkit-color-bg)]/95 backdrop-blur-md border-b border-[var(--appkit-color-border-subtle)] shadow-sm ${className}`, children: [promoStripText && (_jsx(Section, { color: "inverse", tone: "accent-banner", className: "text-[length:var(--appkit-text-xs)] text-center font-medium", padding: "y-2xs", children: promoStripText })), _jsxs(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: [_jsxs(Row, { justify: "between", gap: "none", className: "relative h-14", children: [_jsx(Row, { gap: "3", children: _jsxs(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center gap-[var(--appkit-space-2)] transition-opacity hover:opacity-80", children: [_jsx(Div, { className: "flex md:hidden", children: _jsx(SiteMark, { title: brandName, size: "sm" }) }), _jsx(SiteLogo, { title: brandName, size: "md" })] }) }), _jsx(Row, { className: "hidden md:flex absolute inset-y-0 left-1/2 -translate-x-1/2", align: "center", children: _jsx(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center transition-opacity hover:opacity-80", children: _jsx(SiteMark, { src: siteLogoUrl, title: brandName, size: "lg" }) }) }), _jsxs(Row, { gap: "xs", children: [devSlot, compareEl, notificationSlot, notificationsEl && _jsx(Div, { className: "hidden lg:flex", children: notificationsEl }), wishlistEl && _jsx(Div, { className: "hidden lg:flex", children: wishlistEl }), cartEl && _jsx(Div, { className: "hidden lg:flex", children: cartEl }), user
|
|
36
|
+
return (_jsxs(BlockHeader, { id: id, className: `sticky top-0 z-50 bg-[var(--appkit-color-bg)]/95 backdrop-blur-md border-b border-[var(--appkit-color-border-subtle)] shadow-sm ${className}`, children: [promoStripText && (_jsx(Section, { color: "inverse", tone: "accent-banner", className: "text-[length:var(--appkit-text-xs)] text-center font-medium", padding: "y-2xs", children: promoStripText })), _jsxs(Div, { paddingX: "x-page", className: "container mx-auto max-w-[1920px]", children: [_jsxs(Row, { justify: "between", gap: "none", className: "relative h-14", children: [_jsx(Row, { gap: "3", children: _jsxs(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center gap-[var(--appkit-space-2)] transition-opacity hover:opacity-80", children: [_jsx(Div, { className: "flex md:hidden", children: _jsx(SiteMark, { title: brandShortName ?? brandName, size: "sm" }) }), _jsx(SiteLogo, { title: brandName, size: "md" })] }) }), _jsx(Row, { className: "hidden md:flex absolute inset-y-0 left-1/2 -translate-x-1/2", align: "center", children: _jsx(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center transition-opacity hover:opacity-80", children: _jsx(SiteMark, { src: siteLogoUrl, title: brandName, size: "lg" }) }) }), _jsxs(Row, { gap: "xs", children: [devSlot, navSlot, compareEl, notificationSlot, notificationsEl && _jsx(Div, { className: "hidden lg:flex", children: notificationsEl }), wishlistEl && _jsx(Div, { className: "hidden lg:flex", children: wishlistEl }), cartEl && _jsx(Div, { className: "hidden lg:flex", children: cartEl }), user
|
|
37
37
|
? profileEl && _jsx(Div, { className: "hidden lg:flex", children: profileEl })
|
|
38
38
|
: authButtonsEl ?? (profileEl && _jsx(Div, { className: "hidden lg:flex", children: profileEl })), searchBtn, promotionsEl, tourBtn, themeBtn, hamburgerBtn] })] }), hasTb2 && (_jsxs(Row, { border: "subtle", as: "nav", "aria-label": "Account actions", justify: "end", gap: "xs", className: "flex lg:hidden h-10 border-t px-[var(--appkit-space-1)]", children: [notificationsEl, wishlistEl, cartEl, profileEl] }))] })] }));
|
|
39
39
|
}
|