@mohasinac/appkit 3.5.5 → 3.5.6
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.js +24 -3
- package/dist/_internal/client/scaffolds/index.d.ts +0 -2
- package/dist/_internal/client/scaffolds/index.js +0 -1
- package/dist/client-entry.d.ts +2 -2
- package/dist/client-entry.js +2 -2
- package/dist/features/account/components/UserSidebar.js +1 -1
- package/dist/features/admin/components/AdminFeaturesView.js +1 -1
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/admin/components/DataTable.js +1 -1
- package/dist/features/admin/components/index.d.ts +0 -2
- package/dist/features/admin/components/index.js +0 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +1 -1
- package/dist/features/before-after/components/BeforeAfterSlider.js +4 -0
- package/dist/features/blog/components/BlogFeaturedCard.js +1 -1
- package/dist/features/categories/components/BundleDynamicRuleEditor.js +2 -9
- package/dist/features/events/components/EventCard.js +1 -1
- package/dist/features/events/components/EventRafflesSection.d.ts +1 -1
- package/dist/features/events/components/EventRafflesSection.js +3 -3
- package/dist/features/homepage/components/BeforeAfterCard.js +5 -0
- package/dist/features/homepage/components/FeaturedBundlesSection.d.ts +1 -1
- package/dist/features/homepage/components/FeaturedBundlesSection.js +3 -1
- package/dist/features/homepage/components/GoogleReviewsSection.js +2 -2
- package/dist/features/homepage/components/HeroCarousel.js +1 -1
- package/dist/features/layout/NavbarLayout.js +1 -1
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/media/MediaLightbox.js +7 -1
- package/dist/features/media/components/MediaSlider.js +4 -1
- package/dist/features/media/modals/ImageCropModal.js +1 -1
- package/dist/features/media/upload/ImageUpload.js +24 -12
- package/dist/features/orders/components/MarketplaceOrderCard.js +1 -1
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
- package/dist/features/products/components/MarketplaceBundleCard.js +1 -1
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +1 -1
- package/dist/features/products/components/PrizeDrawsSection.d.ts +1 -1
- package/dist/features/products/components/PrizeDrawsSection.js +3 -2
- package/dist/features/products/components/ProductForm.js +4 -9
- package/dist/features/products/components/ProductGrid.js +1 -1
- package/dist/features/promotions/components/CouponCard.js +1 -1
- package/dist/features/seller/components/SellerProductShell.js +4 -4
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/shipments/components/ShipmentItemLinkModal.js +5 -5
- package/dist/features/stores/components/InteractiveStoreCard.js +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/react/hooks/useClickOutside.js +3 -0
- package/dist/seed/site-settings-seed-data.js +9 -2
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +1 -1
- package/dist/styles.css +11 -4
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/cobalt-night.d.ts +17 -0
- package/dist/tokens/themes/cobalt-night.js +50 -0
- package/dist/tokens/themes/index.d.ts +9 -1
- package/dist/tokens/themes/index.js +12 -1
- package/dist/tokens/themes/sunset.d.ts +18 -0
- package/dist/tokens/themes/sunset.js +51 -0
- package/dist/tokens/tokens.css +10 -3
- package/dist/ui/components/BaseListingCard.d.ts +2 -1
- package/dist/ui/components/BaseListingCard.js +4 -4
- package/dist/ui/components/Card.d.ts +1 -1
- package/dist/ui/components/Card.js +2 -2
- package/dist/ui/components/Div.js +2 -2
- package/dist/ui/components/Form.d.ts +1 -1
- package/dist/ui/components/Form.js +2 -2
- package/dist/ui/components/Input.js +1 -0
- package/dist/ui/components/ListingToolbar.js +1 -1
- package/dist/ui/components/QuickCreateModal.style.css +1 -1
- package/dist/ui/components/Slider.js +5 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { normalizeError } from "../../../../errors/normalize";
|
|
4
4
|
/**
|
|
5
5
|
* DashboardLayoutClient — unified client island that replaces the ~75 lines of
|
|
@@ -23,6 +23,7 @@ import { normalizeError } from "../../../../errors/normalize";
|
|
|
23
23
|
*/
|
|
24
24
|
import { useCallback, useEffect, useState, startTransition } from "react";
|
|
25
25
|
import { usePathname } from "next/navigation";
|
|
26
|
+
import Link from "next/link";
|
|
26
27
|
import { useDashboardNav } from "../../../../features/layout/DashboardNavContext";
|
|
27
28
|
import { AdminSidebar } from "../../../../features/admin/components/AdminSidebar";
|
|
28
29
|
import { StoreSidebar } from "../../../../features/seller/components/SellerSidebar";
|
|
@@ -31,7 +32,8 @@ import { DASHBOARD_DESKTOP_MEDIA_QUERY } from "../../../shared/features/layout/c
|
|
|
31
32
|
import { filterNavItems } from "./filterNavItems";
|
|
32
33
|
import { useSiteSettings } from "../../../../core/hooks/useSiteSettings";
|
|
33
34
|
import { useTheme } from "../../theme";
|
|
34
|
-
import { BackgroundRenderer, Div } from "../../../../ui";
|
|
35
|
+
import { BackgroundRenderer, Div, Nav, Span } from "../../../../ui";
|
|
36
|
+
import { useVisualViewportInset } from "../../../../react/hooks/useVisualViewportInset";
|
|
35
37
|
/**
|
|
36
38
|
* Hoisted drawer-state hook — the matchMedia-aware open/close logic that was
|
|
37
39
|
* triplicated across admin/store/user layouts. Used internally by
|
|
@@ -125,6 +127,24 @@ function filterGroups(groups, navConfig, permissions) {
|
|
|
125
127
|
}))
|
|
126
128
|
.filter((group) => group.items.length > 0);
|
|
127
129
|
}
|
|
130
|
+
const MAX_BOTTOM_NAV_ITEMS = 5;
|
|
131
|
+
/**
|
|
132
|
+
* Mobile bottom tab bar (<lg) for the dashboard shells. Admin/store/user
|
|
133
|
+
* previously had no bottom-nav — this was the source of "hard to navigate
|
|
134
|
+
* on mobile" (the sidebar's only mobile affordance was an off-canvas drawer
|
|
135
|
+
* behind a hamburger toggle). Pattern lifted from the unused
|
|
136
|
+
* `DashboardScaffold` scaffold, which has since been retired in favour of
|
|
137
|
+
* wiring it directly here where the sidebars already live.
|
|
138
|
+
*/
|
|
139
|
+
function DashboardBottomNav({ items, activeHref }) {
|
|
140
|
+
const isKeyboardOpen = useVisualViewportInset();
|
|
141
|
+
if (items.length === 0)
|
|
142
|
+
return null;
|
|
143
|
+
return (_jsx(Nav, { "aria-label": "Dashboard bottom navigation", "aria-hidden": isKeyboardOpen, className: `fixed bottom-0 left-0 right-0 z-[var(--appkit-z-bottom-nav)] flex items-stretch justify-around border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] lg:hidden transition-transform duration-200 ease-out ${isKeyboardOpen ? "translate-y-full pointer-events-none" : "translate-y-0"}`, children: items.slice(0, MAX_BOTTOM_NAV_ITEMS).map((item) => {
|
|
144
|
+
const isActive = activeHref === item.href || activeHref.startsWith(`${item.href}/`);
|
|
145
|
+
return (_jsxs(Link, { href: item.href, className: `flex flex-1 flex-col items-center justify-center gap-[var(--appkit-space-0-5)] py-[var(--appkit-space-2)] ${isActive ? "text-[var(--appkit-color-primary)]" : "text-[var(--appkit-color-text-muted)]"}`, "aria-current": isActive ? "page" : undefined, children: [item.icon && _jsx(Span, { size: "base", children: item.icon }), _jsx(Span, { size: "xs", className: "max-w-full truncate", children: item.label })] }, item.href));
|
|
146
|
+
}) }));
|
|
147
|
+
}
|
|
128
148
|
const DEFAULT_CONTENT_PADDING = "px-[var(--appkit-space-5)] py-[var(--appkit-space-8)] lg:pl-14 lg:pr-6 xl:pl-16 xl:pr-10";
|
|
129
149
|
const DEFAULT_CONTENT_MAX_WIDTH = "max-w-screen-2xl";
|
|
130
150
|
export function DashboardLayoutClient({ variant, groups, permissions, activeHref: explicitActiveHref, responsive: _responsive, className, contentPadding, contentSurface, contentMaxWidth, lightBackground, darkBackground, children, }) {
|
|
@@ -147,7 +167,8 @@ export function DashboardLayoutClient({ variant, groups, permissions, activeHref
|
|
|
147
167
|
: groups;
|
|
148
168
|
return (_jsxs(_Fragment, { children: [hasBackground && (_jsx(BackgroundRenderer, { mode: theme === "dark" ? "dark" : "light", lightMode: resolvedLightBackground ?? { type: "color", value: "" }, darkMode: resolvedDarkBackground ?? { type: "color", value: "" } })), variant === "admin" && (_jsx(AdminSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activePath: activeHref, groups: adminGroups, onCloseMobile: close, onToggle: toggle, className: className })), variant === "store" && (_jsx(StoreSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activeHref: activeHref, items: [], groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className })), variant === "user" && (_jsx(UserSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, items: filteredGroups.flatMap((g) => g.items), groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className })), _jsx(Div, { className: [
|
|
149
169
|
"w-full flex-1 flex flex-col min-h-[calc(100dvh-var(--header-height,3.5rem))]",
|
|
170
|
+
"pb-[var(--appkit-space-16)] lg:pb-[0]", // clears the fixed mobile bottom-nav
|
|
150
171
|
contentPadding ?? DEFAULT_CONTENT_PADDING,
|
|
151
172
|
contentSurface,
|
|
152
|
-
].filter(Boolean).join(" "), children: _jsx(Div, { className: ["w-full flex-1 mx-auto", contentMaxWidth ?? DEFAULT_CONTENT_MAX_WIDTH].filter(Boolean).join(" "), children: children }) })] }));
|
|
173
|
+
].filter(Boolean).join(" "), children: _jsx(Div, { className: ["w-full flex-1 mx-auto", contentMaxWidth ?? DEFAULT_CONTENT_MAX_WIDTH].filter(Boolean).join(" "), children: children }) }), _jsx(DashboardBottomNav, { items: filteredGroups.flatMap((g) => g.items), activeHref: activeHref })] }));
|
|
153
174
|
}
|
package/dist/client-entry.d.ts
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
export * from "./index";
|
|
16
16
|
export { LabelsProvider, useLabels } from "./_internal/client/i18n/LabelsProvider";
|
|
17
17
|
export type { AppkitLabelSet } from "./_internal/client/i18n/LabelsProvider";
|
|
18
|
-
export { AppShell
|
|
19
|
-
export type { AppShellProps, AppShellRenderContext,
|
|
18
|
+
export { AppShell } from "./_internal/client/scaffolds/index";
|
|
19
|
+
export type { AppShellProps, AppShellRenderContext, } from "./_internal/client/scaffolds/index";
|
|
20
20
|
export { toClient, clientInitial } from "./_internal/shared/serialization/index";
|
|
21
21
|
export type { AppkitConfig, AppkitFirebaseConfig, AppkitFirebaseExtensions, AppkitVercelConfig, AppkitBrandConfig, AppkitSeoConfig, AppkitI18nConfig, FirestoreIndex, FirestoreIndexField, FirestoreFieldOverride, } from "./_internal/shared/config/schema";
|
|
22
22
|
export { SEMANTIC_COLORS, SEMANTIC_COLORS_DARK, SEMANTIC_RADIUS, SEMANTIC_SHADOWS, SEMANTIC_Z_INDEX, MOTION_TOKENS, BREAKPOINTS, PLATFORM_LIMITS, } from "./_internal/shared/tokens/index";
|
package/dist/client-entry.js
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
export * from "./index";
|
|
21
21
|
// New i18n contract — available to consumers immediately
|
|
22
22
|
export { LabelsProvider, useLabels } from "./_internal/client/i18n/LabelsProvider";
|
|
23
|
-
// Scaffolds — slot-driven shell
|
|
24
|
-
export { AppShell
|
|
23
|
+
// Scaffolds — slot-driven shell chrome (S6)
|
|
24
|
+
export { AppShell } from "./_internal/client/scaffolds/index";
|
|
25
25
|
// Hydration helpers (CC-3) — safe to call from RSC and client
|
|
26
26
|
export { toClient, clientInitial } from "./_internal/shared/serialization/index";
|
|
27
27
|
export { SEMANTIC_COLORS, SEMANTIC_COLORS_DARK, SEMANTIC_RADIUS, SEMANTIC_SHADOWS, SEMANTIC_Z_INDEX, MOTION_TOKENS, BREAKPOINTS, PLATFORM_LIMITS, } from "./_internal/shared/tokens/index";
|
|
@@ -27,7 +27,7 @@ function NavLink({ item, isActive, onClick }) {
|
|
|
27
27
|
const linkClass = `flex items-center gap-[var(--appkit-space-2-5)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[0.8125rem] font-medium leading-tight transition-colors ${isActive
|
|
28
28
|
? "bg-primary-50 dark:bg-primary-900/25 text-primary-700 dark:text-primary-300"
|
|
29
29
|
: "text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)] hover:text-zinc-900 dark:hover:text-zinc-100"}`;
|
|
30
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Link, { href: item.href, onClick: handleClick, className: linkClass, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-70", children: item.icon }), _jsx(Span, {
|
|
30
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Link, { href: item.href, onClick: handleClick, className: linkClass, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-70", children: item.icon }), _jsx(Span, { className: "flex-1 truncate", children: item.label })] }), showConfirm && item.confirm && (_jsx(ConfirmDeleteModal, { isOpen: true, title: item.confirm.title ?? "Confirm", message: item.confirm.message, confirmText: "Continue", variant: "warning", onConfirm: () => {
|
|
31
31
|
setShowConfirm(false);
|
|
32
32
|
onClick?.();
|
|
33
33
|
window.location.href = item.href;
|
|
@@ -12,7 +12,7 @@ import { AdminFeatureEditorView } from "./AdminFeatureEditorView";
|
|
|
12
12
|
import { PRODUCT_FEATURE_SCOPE_TABS } from "../../products/constants/product-features.constants";
|
|
13
13
|
const PAGE_SIZE = 50;
|
|
14
14
|
const DEFAULT_SCOPE = "platform";
|
|
15
|
-
const STICKY_TABS_CLASS = "sticky top-[calc(var(--header-height,0px)+44px)] z-10 bg-
|
|
15
|
+
const STICKY_TABS_CLASS = "sticky top-[calc(var(--header-height,0px)+44px)] z-10 bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-[var(--appkit-space-3)] py-[var(--appkit-space-2)]";
|
|
16
16
|
function mapFeatureRow(item, index) {
|
|
17
17
|
const productTypes = Array.isArray(item.productTypes) ? item.productTypes : [];
|
|
18
18
|
const isActive = typeof item.isActive === "boolean" ? item.isActive : true;
|
|
@@ -16,7 +16,7 @@ function isNavItemActive(item, activePath) {
|
|
|
16
16
|
function NavLink({ item, isActive, onClick }) {
|
|
17
17
|
return (_jsxs(Link, { href: item.href, onClick: onClick, className: `flex items-center gap-[var(--appkit-space-2-5)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[0.8125rem] font-medium leading-tight transition-colors ${isActive
|
|
18
18
|
? "bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-surface-elevated)] text-[var(--appkit-color-text)]"
|
|
19
|
-
: "text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]/60 hover:text-zinc-800 hover:text-[var(--appkit-color-text-muted)]"}`, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-60", children: item.icon }), _jsx(Span, {
|
|
19
|
+
: "text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]/60 hover:text-zinc-800 hover:text-[var(--appkit-color-text-muted)]"}`, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-60", children: item.icon }), _jsx(Span, { className: "flex-1 truncate", children: item.label })] }));
|
|
20
20
|
}
|
|
21
21
|
function GroupsContent({ groups, activePath, onItemClick, }) {
|
|
22
22
|
const [openGroups, setOpenGroups] = useState(() => Object.fromEntries(groups.map((g) => [
|
|
@@ -39,7 +39,7 @@ function SelectableRow({ row, columns, isSelected, onToggle, renderRowActions, o
|
|
|
39
39
|
}
|
|
40
40
|
: undefined;
|
|
41
41
|
const isInteractive = Boolean(onRowClick ?? rowHref);
|
|
42
|
-
return (_jsxs(Tr, { "data-testid": "data-table-row", onClick: handleClick, onKeyDown: handleKeyDown, role: isInteractive ? "link" : undefined, tabIndex: isInteractive ? 0 : undefined, onMouseDown: selectionEnabled && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: selectionEnabled && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: selectionEnabled && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: selectionEnabled && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: selectionEnabled && !isSelected ? longPress.onTouchEnd : undefined, className: `hover:bg-[var(--appkit-color-bg)] dark:hover:bg-[var(--appkit-color-bg)] ${isInteractive ? "cursor-pointer" : ""} ${isSelected ? "bg-primary/5 dark:bg-primary/10" : ""}`, border: "default", children: [selectionEnabled && (_jsx(Td, { padding: "xs-3", className: "relative w-10", onClick: (e) => e.stopPropagation(), children: _jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onToggle?.(row.id, !isSelected); }, label: isSelected ? "Deselect row" : "Select row", position: "top-1/2 left-2 -translate-y-1/2", "data-testid": "row-checkbox" }) })), columns.map((col) => (_jsx(Td, { color: "muted", className: col.className ?? "", padding: "md", children: col.render
|
|
42
|
+
return (_jsxs(Tr, { "data-testid": "data-table-row", onClick: handleClick, onKeyDown: handleKeyDown, role: isInteractive ? "link" : undefined, tabIndex: isInteractive ? 0 : undefined, onMouseDown: selectionEnabled && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: selectionEnabled && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: selectionEnabled && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: selectionEnabled && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: selectionEnabled && !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: selectionEnabled && !isSelected ? longPress.onTouchCancel : undefined, className: `hover:bg-[var(--appkit-color-bg)] dark:hover:bg-[var(--appkit-color-bg)] ${isInteractive ? "cursor-pointer" : ""} ${isSelected ? "bg-primary/5 dark:bg-primary/10" : ""}`, border: "default", children: [selectionEnabled && (_jsx(Td, { padding: "xs-3", className: "relative w-10", onClick: (e) => e.stopPropagation(), children: _jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onToggle?.(row.id, !isSelected); }, label: isSelected ? "Deselect row" : "Select row", position: "top-1/2 left-2 -translate-y-1/2", "data-testid": "row-checkbox" }) })), columns.map((col) => (_jsx(Td, { color: "muted", className: col.className ?? "", padding: "md", children: col.render
|
|
43
43
|
? col.render(row)
|
|
44
44
|
: String(row[col.key] ?? "") }, col.key))), renderRowActions && (_jsx(Td, { padding: "xs-3", onClick: (e) => e.stopPropagation(), children: renderRowActions(row) }))] }));
|
|
45
45
|
}
|
|
@@ -109,8 +109,6 @@ export { AdminCarouselEditorView } from "./AdminCarouselEditorView";
|
|
|
109
109
|
export type { AdminCarouselEditorViewProps } from "./AdminCarouselEditorView";
|
|
110
110
|
export { AdminDashboardView } from "./AdminDashboardView";
|
|
111
111
|
export type { AdminDashboardViewProps } from "./AdminDashboardView";
|
|
112
|
-
export { QuickActionsPanel } from "./QuickActionsPanel";
|
|
113
|
-
export type { QuickActionItem, QuickActionsPanelProps, } from "./QuickActionsPanel";
|
|
114
112
|
export { AdminSiteView } from "./AdminSiteView";
|
|
115
113
|
export type { AdminSiteViewProps } from "./AdminSiteView";
|
|
116
114
|
export { AdminSiteSettingsView } from "./AdminSiteSettingsView";
|
|
@@ -59,7 +59,6 @@ export { AdminAdEditorView } from "./AdminAdEditorView";
|
|
|
59
59
|
export { AdminCarouselView } from "./AdminCarouselView";
|
|
60
60
|
export { AdminCarouselEditorView } from "./AdminCarouselEditorView";
|
|
61
61
|
export { AdminDashboardView } from "./AdminDashboardView";
|
|
62
|
-
export { QuickActionsPanel } from "./QuickActionsPanel";
|
|
63
62
|
export { AdminSiteView } from "./AdminSiteView";
|
|
64
63
|
export { AdminSiteSettingsView } from "./AdminSiteSettingsView";
|
|
65
64
|
export { AdminAnalyticsView } from "./AdminAnalyticsView";
|
|
@@ -161,5 +161,5 @@ export function MarketplaceAuctionCard({ product, buyoutPrice, className = "", v
|
|
|
161
161
|
remaining, resolvedBuyoutPrice, inWishlist, wishlistLoading, wishlistActions,
|
|
162
162
|
countdownClass, mergedLabels, handleWishlist, handleNavigate,
|
|
163
163
|
};
|
|
164
|
-
return (_jsxs(BaseListingCard, { isSelected: isSelected, isDisabled: isEnded, variant: baseVariant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, children: [renderAuctionCardHero({ product, auctionHref, currentSrc, hovered, images, imageIndex, hasVideo, isEnded, isEndingSoon, isSelected, selectable, mergedLabels, onSelect, setHovered, handleSelect }), _jsx(BaseListingCard.Info, { variant: baseVariant, children: baseVariant === "list" ? renderAuctionCardInfoList(cardInfoProps) : renderAuctionCardInfoGrid(cardInfoProps) })] }));
|
|
164
|
+
return (_jsxs(BaseListingCard, { isSelected: isSelected, isDisabled: isEnded, variant: baseVariant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [renderAuctionCardHero({ product, auctionHref, currentSrc, hovered, images, imageIndex, hasVideo, isEnded, isEndingSoon, isSelected, selectable, mergedLabels, onSelect, setHovered, handleSelect }), _jsx(BaseListingCard.Info, { variant: baseVariant, children: baseVariant === "list" ? renderAuctionCardInfoList(cardInfoProps) : renderAuctionCardInfoGrid(cardInfoProps) })] }));
|
|
165
165
|
}
|
|
@@ -10,6 +10,10 @@ export function BeforeAfterSlider({ item, className = "", }) {
|
|
|
10
10
|
return;
|
|
11
11
|
move(e.clientX);
|
|
12
12
|
}
|
|
13
|
+
// audit-touch-handler-ok: position is derived fresh from each move event's
|
|
14
|
+
// coordinates, no "dragging in progress" flag or timer persists across
|
|
15
|
+
// gestures — a cancelled touch just leaves `position` at its last value,
|
|
16
|
+
// which is the same outcome as the user simply stopping mid-drag.
|
|
13
17
|
function handleTouchMove(e) {
|
|
14
18
|
move(e.touches[0].clientX);
|
|
15
19
|
}
|
|
@@ -31,5 +31,5 @@ export function BlogFeaturedCard({ post, href, labels = {}, className = "", sele
|
|
|
31
31
|
day: "numeric",
|
|
32
32
|
})
|
|
33
33
|
: "";
|
|
34
|
-
return (_jsxs(Article, { rounded: "xl", shadow: "hover-md", className: `group relative h-full overflow-hidden border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] ${isSelected ? "ring-2 ring-primary outline outline-2 outline-primary" : ""} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(post.id, !isSelected); }, label: isSelected ? "Deselect post" : "Select post", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsxs(TextLink, { href: href, layout: "flex-col", className: "h-full", children: [_jsx(Div, { className: `relative aspect-video ${__O.hidden} flex-shrink-0`, children: coverImageUrl ? (_jsx(MediaImage, { src: coverImageUrl, alt: safeTitle, size: "card", className: "transition-transform duration-300 group-hover:scale-105" })) : (_jsx(Div, { role: "img", "aria-label": safeTitle, surface: "muted", className: "h-full w-full" })) }), _jsxs(Stack, { className: `flex-1 ${__P.p4}`, children: [_jsxs(Row, { gap: "xs", className: "mb-2", wrap: true, children: [_jsx(Span, { size: "xs", weight: "medium", className: `inline-block capitalize ${CATEGORY_BADGE[post.category] ?? "bg-[var(--appkit-color-bg)] text-[var(--appkit-color-text-muted)]"}`, rounded: "full", padding: "pill-xs", children: post.category }), post.isFeatured && (_jsx(Span, { size: "xs", weight: "medium", className: CLS_FEATURED_BADGE, children: labels.featuredBadge ?? "Featured" }))] }), _jsx(Heading, { level: 3, className: `leading-snug mb-1`, color: "primary", truncate: 2, size: "base", weight: "semibold", children: safeTitle }), post.excerpt && (_jsx(Text, { className: `mb-3`, color: "muted", truncate: 2, size: "sm", children: post.excerpt })), _jsxs(Row, { color: "muted", textSize: "xs", className: "mt-auto", gap: "3", wrap: true, children: [post.authorName && (_jsx(Span, { children: safeDisplayName(post.authorName, "Author") })), post.readTimeMinutes != null && (_jsxs(Span, { children: [post.readTimeMinutes, " ", labels.readTime ?? "min read"] })), date && _jsx(Span, { children: date })] })] })] })] }));
|
|
34
|
+
return (_jsxs(Article, { rounded: "xl", shadow: "hover-md", className: `group relative h-full overflow-hidden border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] ${isSelected ? "ring-2 ring-primary outline outline-2 outline-primary" : ""} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: onSelect && !isSelected ? longPress.onTouchCancel : undefined, children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(post.id, !isSelected); }, label: isSelected ? "Deselect post" : "Select post", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsxs(TextLink, { href: href, layout: "flex-col", className: "h-full", children: [_jsx(Div, { className: `relative aspect-video ${__O.hidden} flex-shrink-0`, children: coverImageUrl ? (_jsx(MediaImage, { src: coverImageUrl, alt: safeTitle, size: "card", className: "transition-transform duration-300 group-hover:scale-105" })) : (_jsx(Div, { role: "img", "aria-label": safeTitle, surface: "muted", className: "h-full w-full" })) }), _jsxs(Stack, { className: `flex-1 ${__P.p4}`, children: [_jsxs(Row, { gap: "xs", className: "mb-2", wrap: true, children: [_jsx(Span, { size: "xs", weight: "medium", className: `inline-block capitalize ${CATEGORY_BADGE[post.category] ?? "bg-[var(--appkit-color-bg)] text-[var(--appkit-color-text-muted)]"}`, rounded: "full", padding: "pill-xs", children: post.category }), post.isFeatured && (_jsx(Span, { size: "xs", weight: "medium", className: CLS_FEATURED_BADGE, children: labels.featuredBadge ?? "Featured" }))] }), _jsx(Heading, { level: 3, className: `leading-snug mb-1`, color: "primary", truncate: 2, size: "base", weight: "semibold", children: safeTitle }), post.excerpt && (_jsx(Text, { className: `mb-3`, color: "muted", truncate: 2, size: "sm", children: post.excerpt })), _jsxs(Row, { color: "muted", textSize: "xs", className: "mt-auto", gap: "3", wrap: true, children: [post.authorName && (_jsx(Span, { children: safeDisplayName(post.authorName, "Author") })), post.readTimeMinutes != null && (_jsxs(Span, { children: [post.readTimeMinutes, " ", labels.readTime ?? "min read"] })), date && _jsx(Span, { children: date })] })] })] })] }));
|
|
35
35
|
}
|
|
@@ -14,7 +14,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
14
14
|
* `bundleQueryResolvedAt` timestamp. This editor only writes the rule.
|
|
15
15
|
*/
|
|
16
16
|
import { useCallback } from "react";
|
|
17
|
-
import { Div, Input, Row, Select, Stack, Text } from "../../../ui";
|
|
17
|
+
import { Div, Input, Row, Select, Stack, TagInput, Text } from "../../../ui";
|
|
18
18
|
import { CategoryInlineSelect } from "../../seller/components/CategoryInlineSelect";
|
|
19
19
|
import { BrandInlineSelect } from "../../seller/components/BrandInlineSelect";
|
|
20
20
|
import { BUNDLE_MAX_ITEMS } from "../../../_internal/shared/features/categories/bundle-config";
|
|
@@ -40,14 +40,7 @@ export function BundleDynamicRuleEditor({ value, onChange, disabled = false, })
|
|
|
40
40
|
const rule = value ?? DEFAULT_DYNAMIC_RULE;
|
|
41
41
|
const patch = useCallback((next) => onChange({ ...rule, ...next }), [rule, onChange]);
|
|
42
42
|
const patchFilter = useCallback((next) => onChange({ ...rule, filter: { ...rule.filter, ...next } }), [rule, onChange]);
|
|
43
|
-
|
|
44
|
-
return (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { gap: "sm", align: "center", justify: "between", wrap: true, children: [_jsx(Text, { size: "sm", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.title }), _jsx(Text, { size: "xs", color: "muted", children: BUNDLE_COPY.adminEditor.dynamic.hint })] }), _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-2", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.categorySlug }), _jsx(CategoryInlineSelect, { value: rule.filter.categorySlug ?? "", onChange: (id) => patchFilter({ categorySlug: id || undefined }), disabled: disabled, placeholder: "Filter by category\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.brandSlug }), _jsx(BrandInlineSelect, { value: rule.filter.brandSlug ?? "", onChange: (id) => patchFilter({ brandSlug: id || undefined }), disabled: disabled, placeholder: "Filter by brand\u2026" })] })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.tags }), _jsx(Input, { type: "text", value: tagsValue, onChange: (e) => {
|
|
45
|
-
const parsed = e.target.value
|
|
46
|
-
.split(",")
|
|
47
|
-
.map((t) => t.trim())
|
|
48
|
-
.filter(Boolean);
|
|
49
|
-
patchFilter({ tags: parsed.length ? parsed : undefined });
|
|
50
|
-
}, placeholder: "pokemon, starter-deck", disabled: disabled })] }), _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-3", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.listingType }), _jsx(Select, { options: LISTING_TYPE_OPTIONS, value: rule.filter.listingType ?? "", onValueChange: (next) => patchFilter({
|
|
43
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsxs(Row, { gap: "sm", align: "center", justify: "between", wrap: true, children: [_jsx(Text, { size: "sm", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.title }), _jsx(Text, { size: "xs", color: "muted", children: BUNDLE_COPY.adminEditor.dynamic.hint })] }), _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-2", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.categorySlug }), _jsx(CategoryInlineSelect, { value: rule.filter.categorySlug ?? "", onChange: (id) => patchFilter({ categorySlug: id || undefined }), disabled: disabled, placeholder: "Filter by category\u2026" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.brandSlug }), _jsx(BrandInlineSelect, { value: rule.filter.brandSlug ?? "", onChange: (id) => patchFilter({ brandSlug: id || undefined }), disabled: disabled, placeholder: "Filter by brand\u2026" })] })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.tags }), _jsx(TagInput, { value: rule.filter.tags ?? [], onChange: (tags) => patchFilter({ tags: tags.length ? tags : undefined }), placeholder: "pokemon, starter-deck", disabled: disabled })] }), _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-3", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.listingType }), _jsx(Select, { options: LISTING_TYPE_OPTIONS, value: rule.filter.listingType ?? "", onValueChange: (next) => patchFilter({
|
|
51
44
|
listingType: next === "" ? undefined : next,
|
|
52
45
|
}), disabled: disabled, "aria-label": BUNDLE_COPY.adminEditor.dynamic.fields.listingType })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", weight: "semibold", children: BUNDLE_COPY.adminEditor.dynamic.fields.orderBy }), _jsx(Select, { options: ORDER_BY_OPTIONS.map((o) => ({
|
|
53
46
|
label: o.label,
|
|
@@ -33,6 +33,6 @@ export function EventCard({ event, labels = {}, onParticipate, className = "", s
|
|
|
33
33
|
const msLeft = endsAt.getTime() - now.getTime();
|
|
34
34
|
const daysLeft = Math.max(0, Math.ceil(msLeft / (1000 * 60 * 60 * 24)));
|
|
35
35
|
const detailHref = String(ROUTES.PUBLIC.EVENT_DETAIL(event.slug ?? event.id));
|
|
36
|
-
return (_jsxs(Article, { border: "default", rounded: "xl", shadow: "hover-md", className: `group relative h-full ${LAYOUT.cardHeight.event} overflow-hidden bg-[var(--appkit-color-surface)] ${isSelected ? "border-primary outline outline-2 outline-primary" : " "} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(event.id, !isSelected); }, label: isSelected ? "Deselect event" : "Select event", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsx(Link, { href: detailHref, className: "block flex-shrink-0", children: event.coverImageUrl ? (_jsx(Div, { className: `relative aspect-video ${__O.hidden}`, children: _jsx(MediaImage, { src: event.coverImageUrl, alt: safeTitle, size: "card", className: "transition-transform duration-300 group-hover:scale-105" }) })) : (_jsx(Row, { surface: "muted", className: "aspect-video", align: "center", justify: "center", children: _jsx(Span, { className: "opacity-40", size: "5xl", "aria-hidden": "true", children: TYPE_ICONS[event.type] }) })) }), _jsxs(Stack, { className: `flex-1 ${__P.p4}`, children: [_jsxs(Row, { className: "mb-2", align: "start", justify: "between", gap: "sm", children: [_jsx(Span, { size: "lg", "aria-hidden": "true", children: TYPE_ICONS[event.type] }), _jsx(EventStatusBadge, { status: event.status })] }), _jsx(Link, { href: detailHref, className: "block", children: _jsx(Heading, { level: 3, className: "text-[var(--appkit-color-text)] leading-snug mb-1 group-hover:text-primary transition-colors", size: "base", weight: "semibold", children: safeTitle }) }), _jsx(RichText, { html: normalizeRichTextHtml(event.description ?? ""), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "mb-3 line-clamp-3 text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)]" }), _jsxs(Row, { color: "muted", textSize: "xs", className: "mb-3 mt-auto", align: "center", justify: "between", children: [event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE &&
|
|
36
|
+
return (_jsxs(Article, { border: "default", rounded: "xl", shadow: "hover-md", className: `group relative h-full ${LAYOUT.cardHeight.event} overflow-hidden bg-[var(--appkit-color-surface)] ${isSelected ? "border-primary outline outline-2 outline-primary" : " "} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: onSelect && !isSelected ? longPress.onTouchCancel : undefined, children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (e) => { e.preventDefault(); onSelect(event.id, !isSelected); }, label: isSelected ? "Deselect event" : "Select event", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), _jsx(Link, { href: detailHref, className: "block flex-shrink-0", children: event.coverImageUrl ? (_jsx(Div, { className: `relative aspect-video ${__O.hidden}`, children: _jsx(MediaImage, { src: event.coverImageUrl, alt: safeTitle, size: "card", className: "transition-transform duration-300 group-hover:scale-105" }) })) : (_jsx(Row, { surface: "muted", className: "aspect-video", align: "center", justify: "center", children: _jsx(Span, { className: "opacity-40", size: "5xl", "aria-hidden": "true", children: TYPE_ICONS[event.type] }) })) }), _jsxs(Stack, { className: `flex-1 ${__P.p4}`, children: [_jsxs(Row, { className: "mb-2", align: "start", justify: "between", gap: "sm", children: [_jsx(Span, { size: "lg", "aria-hidden": "true", children: TYPE_ICONS[event.type] }), _jsx(EventStatusBadge, { status: event.status })] }), _jsx(Link, { href: detailHref, className: "block", children: _jsx(Heading, { level: 3, className: "text-[var(--appkit-color-text)] leading-snug mb-1 group-hover:text-primary transition-colors", size: "base", weight: "semibold", children: safeTitle }) }), _jsx(RichText, { html: normalizeRichTextHtml(event.description ?? ""), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "mb-3 line-clamp-3 text-[length:var(--appkit-text-sm)] text-[var(--appkit-color-text-muted)]" }), _jsxs(Row, { color: "muted", textSize: "xs", className: "mb-3 mt-auto", align: "center", justify: "between", children: [event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE &&
|
|
37
37
|
daysLeft > 0 && _jsxs(Span, { children: ["\u23F1 ", daysLeft, "d remaining"] }), _jsxs(Span, { children: ["\uD83D\uDC65 ", event.stats.totalEntries, " ", labels.entries ?? "entries"] })] }), event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE && onParticipate ? (_jsx(Button, { rounded: "lg", type: "button", onClick: () => onParticipate(event), className: "w-full bg-primary py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-medium text-white transition-colors hover:bg-primary-600", children: labels.participate ?? "Participate" })) : (_jsxs(TextLink, { rounded: "lg", paddingX: "sm", paddingY: "xs", href: detailHref, layout: "inline-flex", align: "center", justify: "center", gap: "xs", className: "w-full border border-[var(--appkit-color-border)] transition-colors hover:bg-[var(--appkit-color-bg)]", color: "primary", size: "sm", weight: "medium", children: [labels.viewDetails ?? "View details", " \u2192"] }))] })] }));
|
|
38
38
|
}
|
|
@@ -6,4 +6,4 @@ export interface EventRafflesSectionProps {
|
|
|
6
6
|
* Renders a live-raffle/spin-wheel strip on the homepage.
|
|
7
7
|
* W1-38 (2026-05-23): fetches events with hasRaffle=true and renders the EventCard grid.
|
|
8
8
|
*/
|
|
9
|
-
export declare function EventRafflesSection({ config, }: EventRafflesSectionProps): Promise<import("react").JSX.Element>;
|
|
9
|
+
export declare function EventRafflesSection({ config, }: EventRafflesSectionProps): Promise<import("react").JSX.Element | null>;
|
|
@@ -2,9 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { normalizeError } from "../../../errors/normalize";
|
|
3
3
|
import { sieveFilter, sieveAnd, SIEVE_OP } from "@mohasinac/appkit";
|
|
4
4
|
import { sortBy } from "@mohasinac/appkit";
|
|
5
|
-
import Link from "next/link";
|
|
6
5
|
import { Container, Div, Heading, Section, Stack, Text, } from "../../../ui";
|
|
7
|
-
import { ROUTES } from "../../../next";
|
|
8
6
|
import { eventRepository } from "../repository/events.repository";
|
|
9
7
|
import { EventCard } from "./EventCard";
|
|
10
8
|
/**
|
|
@@ -28,5 +26,7 @@ export async function EventRafflesSection({ config, }) {
|
|
|
28
26
|
void normalizeError(_err);
|
|
29
27
|
events = [];
|
|
30
28
|
}
|
|
31
|
-
|
|
29
|
+
if (events.length === 0)
|
|
30
|
+
return null;
|
|
31
|
+
return (_jsx(Section, { padding: "y-2xl", children: _jsx(Container, { size: "xl", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Heading, { level: 2, size: "2xl", weight: "semibold", color: "primary", children: title }), subtitle ? (_jsx(Text, { size: "sm", color: "muted", children: subtitle })) : null] }), _jsx(Div, { gap: "3", className: "fluid-grid-card", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })] }) }) }));
|
|
32
32
|
}
|
|
@@ -45,11 +45,16 @@ export function BeforeAfterCard({ item, beforeLabel = "Before", afterLabel = "Af
|
|
|
45
45
|
window.addEventListener("mouseup", onUp);
|
|
46
46
|
window.addEventListener("touchmove", onMove, { passive: false });
|
|
47
47
|
window.addEventListener("touchend", onUp);
|
|
48
|
+
// Without this, an interrupted touch (OS/browser gesture takeover)
|
|
49
|
+
// never fires touchend — `dragging` stays true forever, leaking these
|
|
50
|
+
// window-level listeners for the rest of the component's lifetime.
|
|
51
|
+
window.addEventListener("touchcancel", onUp);
|
|
48
52
|
return () => {
|
|
49
53
|
window.removeEventListener("mousemove", onMove);
|
|
50
54
|
window.removeEventListener("mouseup", onUp);
|
|
51
55
|
window.removeEventListener("touchmove", onMove);
|
|
52
56
|
window.removeEventListener("touchend", onUp);
|
|
57
|
+
window.removeEventListener("touchcancel", onUp);
|
|
53
58
|
};
|
|
54
59
|
}, [dragging, updatePosition]);
|
|
55
60
|
return (_jsxs(Div, { className: `border-border ${__O.hidden} border bg-card`, rounded: "2xl", shadow: "sm", children: [_jsxs(Div, { ref: containerRef, className: "relative aspect-[4/3] cursor-col-resize overflow-hidden select-none", onMouseDown: (e) => {
|
|
@@ -17,4 +17,4 @@ export interface FeaturedBundlesSectionProps {
|
|
|
17
17
|
bundleSlug: string;
|
|
18
18
|
}) => Promise<unknown>;
|
|
19
19
|
}
|
|
20
|
-
export declare function FeaturedBundlesSection({ title, description, initialItems, className, onBuyNow, }: FeaturedBundlesSectionProps): React.JSX.Element;
|
|
20
|
+
export declare function FeaturedBundlesSection({ title, description, initialItems, className, onBuyNow, }: FeaturedBundlesSectionProps): React.JSX.Element | null;
|
|
@@ -15,7 +15,9 @@ const __O = {
|
|
|
15
15
|
const PLACEHOLDER_EMOJI = "📦";
|
|
16
16
|
export function FeaturedBundlesSection({ title = BUNDLE_COPY.featuredDefaultTitle, description, initialItems = [], className = "", onBuyNow, }) {
|
|
17
17
|
const items = initialItems.filter((c) => c.categoryType === "bundle");
|
|
18
|
-
|
|
18
|
+
if (items.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
return (_jsx(Section, { className: `${className}`, padding: "y-2xl", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { gap: "sm", align: "center", justify: "between", wrap: true, children: [_jsxs(Stack, { gap: "xs", children: [_jsx(Heading, { level: 2, size: "2xl", weight: "semibold", color: "primary", children: title }), description && (_jsx(Text, { size: "sm", color: "muted", children: description }))] }), _jsx(Link, { href: String(ROUTES.PUBLIC.BUNDLES), className: "text-[length:var(--appkit-text-sm)] font-medium text-[var(--appkit-color-primary)] hover:underline", children: BUNDLE_COPY.featured.viewAll })] }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", children: items.map((bundle) => (_jsx(FeaturedBundleCard, { bundle: bundle, onBuyNow: onBuyNow }, bundle.id))) })] }) }));
|
|
19
21
|
}
|
|
20
22
|
function FeaturedBundleCard({ bundle, onBuyNow }) {
|
|
21
23
|
const stock = bundle.bundleStockStatus ?? "in_stock";
|
|
@@ -31,10 +31,10 @@ function ReviewCard({ review, showRating, showDate, }) {
|
|
|
31
31
|
}
|
|
32
32
|
// --- Empty / Not Configured States -------------------------------------------
|
|
33
33
|
function NotConfiguredState() {
|
|
34
|
-
return (_jsxs(Stack, { textSize: "sm", justify: "center", color: "faint", padding: "y-4xl", align: "
|
|
34
|
+
return (_jsxs(Stack, { textSize: "sm", justify: "center", color: "faint", padding: "y-4xl", align: "center", children: [_jsxs("svg", { className: "w-10 h-10 mb-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 8v4m0 4h.01" })] }), "Google Reviews not configured. Add your Google Maps API key in Site Settings."] }));
|
|
35
35
|
}
|
|
36
36
|
function EmptyState() {
|
|
37
|
-
return (_jsxs(Stack, { textSize: "sm", justify: "center", color: "faint", padding: "y-4xl", align: "
|
|
37
|
+
return (_jsxs(Stack, { textSize: "sm", justify: "center", color: "faint", padding: "y-4xl", align: "center", children: [_jsx("svg", { className: "w-10 h-10 mb-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: _jsx("path", { d: "M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" }) }), "No reviews yet."] }));
|
|
38
38
|
}
|
|
39
39
|
export async function GoogleReviewsSection(config) {
|
|
40
40
|
const { placeId: configPlaceId, maxReviews = 6, minRating = 0, layout = "grid", showRating = true, showDate = true, linkToGoogleMaps = true, googleMapsUrl, } = config;
|
|
@@ -177,7 +177,7 @@ export function HeroCarousel({ initialSlides, push } = {}) {
|
|
|
177
177
|
}
|
|
178
178
|
};
|
|
179
179
|
if (isLoading) {
|
|
180
|
-
return (_jsx(Div, { className: `relative w-full ${heightClass} ${HERO_PLACEHOLDER_BG} animate-pulse`, children: _jsx(Div, { layout: "flex", align: "center", justify: "
|
|
180
|
+
return (_jsx(Div, { className: `relative w-full ${heightClass} ${HERO_PLACEHOLDER_BG} animate-pulse`, children: _jsx(Div, { layout: "flex", align: "center", justify: "center", className: `${POSITION_FILL} p-[var(--appkit-space-4)]`, children: _jsx(Text, { variant: "secondary", children: "Loading..." }) }) }));
|
|
181
181
|
}
|
|
182
182
|
if (!slides || slides.length === 0) {
|
|
183
183
|
return (_jsxs(Div, { gap: "4", layout: "flex-col", align: "start", justify: "center", className: "relative w-full min-h-[260px] md:min-h-[60vh] bg-[image:var(--appkit-gradient-section-cool)] px-[var(--appkit-space-6)]", children: [_jsx(Heading, { level: 2, className: "text-primary", size: "2xl", weight: "bold", align: "start", children: "Coming Soon" }), _jsx(Text, { variant: "secondary", className: "max-w-md", align: "start", children: "Amazing deals are on their way. Stay tuned!" })] }));
|
|
@@ -51,5 +51,5 @@ export function NavbarLayout({ items, activeHref, id = "main-navbar", ariaLabel
|
|
|
51
51
|
if (inline) {
|
|
52
52
|
return (_jsx(Ul, { "aria-label": ariaLabel, className: "hidden xl:flex items-center justify-end gap-[var(--appkit-space-0-5)] xl:gap-[var(--appkit-space-1)] w-full", children: items.map((item) => (_jsx(Li, { children: renderItem ? (renderItem(item, activeHref === item.href)) : (_jsx(DefaultNavItem, { item: item, isActive: activeHref === item.href })) }, item.href))) }));
|
|
53
53
|
}
|
|
54
|
-
return (_jsx(Nav, { border: "subtle", id: id, "aria-label": ariaLabel, className: "hidden lg:block bg-
|
|
54
|
+
return (_jsx(Nav, { border: "subtle", id: id, "aria-label": ariaLabel, className: "hidden lg:block bg-[var(--appkit-color-bg)]/95 backdrop-blur-md border-b", children: _jsxs(Row, { className: "container mx-auto sm:px-[var(--appkit-space-6)] lg:px-[var(--appkit-space-8)] max-w-[1920px] h-10", padding: "x-md", align: "center", children: [_jsxs(Div, { className: `relative flex-1 ${__O.hidden}`, children: [canScrollLeft && (_jsx(NavbarChevron, { direction: "left", onClick: () => scroll("left") })), _jsx(Ul, { ref: scrollRef, className: "flex items-center justify-end gap-[var(--appkit-space-0-5)] lg:gap-[var(--appkit-space-1)] overflow-x-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: items.map((item) => (_jsx(Li, { className: "shrink-0", children: renderItem ? (renderItem(item, activeHref === item.href)) : (_jsx(DefaultNavItem, { item: item, isActive: activeHref === item.href })) }, item.href))) }), canScrollRight && (_jsx(NavbarChevron, { direction: "right", onClick: () => scroll("right") }))] }), rightSlot && _jsx(Div, { className: "shrink-0 ml-2", children: rightSlot })] }) }));
|
|
55
55
|
}
|
|
@@ -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 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-
|
|
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: _jsx(Link, { href: logoHref, "aria-label": brandName, className: "flex items-center transition-opacity hover:opacity-80", children: _jsx(SiteLogo, { title: brandName, size: "md" }) }) }), siteLogoUrl ? (_jsx(Row, { className: "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(SiteLogo, { src: siteLogoUrl, title: brandName, size: "md" }) }) })) : (navSlot && _jsx(Div, { className: "hidden md:flex ml-auto", children: navSlot })), _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
|
|
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
|
}
|
|
@@ -220,10 +220,16 @@ export function MediaLightbox({ items, initialIndex = 0, isOpen, onClose, labels
|
|
|
220
220
|
}
|
|
221
221
|
touchState.current = {};
|
|
222
222
|
}, [zoom, goNext, goPrev]);
|
|
223
|
+
// An interrupted gesture (OS/browser takeover) never fires touchend —
|
|
224
|
+
// without this, stale touchState.current values corrupt the math for the
|
|
225
|
+
// next unrelated pinch/swipe gesture.
|
|
226
|
+
const handleTouchCancel = useCallback(() => {
|
|
227
|
+
touchState.current = {};
|
|
228
|
+
}, []);
|
|
223
229
|
if (!isOpen || items.length === 0)
|
|
224
230
|
return null;
|
|
225
231
|
const current = items[index];
|
|
226
|
-
return (_jsxs(Div, { layout: "flex", ref: containerRef, className: "fixed inset-0 z-[var(--appkit-z-tooltip)] bg-black/95 flex-col", role: "dialog", "aria-modal": "true", "aria-label": L.lightboxTitle, children: [_jsx(Div, { ref: imageAreaRef, className: "flex-1 relative overflow-hidden select-none", onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, style: {
|
|
232
|
+
return (_jsxs(Div, { layout: "flex", ref: containerRef, className: "fixed inset-0 z-[var(--appkit-z-tooltip)] bg-black/95 flex-col", role: "dialog", "aria-modal": "true", "aria-label": L.lightboxTitle, children: [_jsx(Div, { ref: imageAreaRef, className: "flex-1 relative overflow-hidden select-none", onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, onTouchCancel: handleTouchCancel, style: {
|
|
227
233
|
cursor: zoom > 1 ? (isDragging ? "grabbing" : "grab") : "default",
|
|
228
234
|
touchAction: "none",
|
|
229
235
|
}, onClick: (e) => {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
export function MediaSlider({ value, min = 0, max = 100, step = 1, onChange, onChangeEnd, className = "", }) {
|
|
3
|
-
return (_jsx("input", { type: "range", min: min, max: max, step: step, value: value, onChange: (e) => onChange?.(parseFloat(e.target.value)), onMouseUp: (e) => onChangeEnd?.(parseFloat(e.target.value)),
|
|
3
|
+
return (_jsx("input", { type: "range", min: min, max: max, step: step, value: value, onChange: (e) => onChange?.(parseFloat(e.target.value)), onMouseUp: (e) => onChangeEnd?.(parseFloat(e.target.value)),
|
|
4
|
+
// audit-touch-handler-ok: native <input type="range"> owns its own
|
|
5
|
+
// drag/cancel state; nothing here persists across a cancelled touch.
|
|
6
|
+
onTouchEnd: (e) => onChangeEnd?.(parseFloat(e.target.value)), className: [
|
|
4
7
|
"w-full h-2 appearance-none cursor-pointer rounded-full",
|
|
5
8
|
"bg-zinc-200 bg-[var(--appkit-color-border)]",
|
|
6
9
|
"accent-primary-600 dark:accent-secondary-400",
|
|
@@ -89,7 +89,7 @@ export function ImageCropModal({ isOpen, imageUrl, onClose, onSave, initialCropD
|
|
|
89
89
|
setZoom(1);
|
|
90
90
|
setPosition({ x: 50, y: 50 });
|
|
91
91
|
};
|
|
92
|
-
return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, title: t("cropTitle"), size: "lg", children: _jsxs(Stack, { gap: "3", children: [_jsx(Text, { variant: "secondary", size: "xs", children: t("cropInstruction") }), _jsxs(Div, { ref: containerRef, className: "relative w-full max-w-sm mx-auto aspect-square overflow-hidden cursor-move max-h-[280px] touch-none", surface: "subtle", rounded: "lg", "data-disable-swipe": "true", tabIndex: 0, role: "application", "aria-label": t("cropInstruction"), onKeyDown: handleKeyDown, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, children: [_jsx("img", { src: imageUrl, alt: t("cropPreviewAlt"), draggable: false, className: "absolute select-none pointer-events-none object-cover", style: {
|
|
92
|
+
return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, title: t("cropTitle"), size: "lg", children: _jsxs(Stack, { gap: "3", children: [_jsx(Text, { variant: "secondary", size: "xs", children: t("cropInstruction") }), _jsxs(Div, { ref: containerRef, className: "relative w-full max-w-sm mx-auto aspect-square overflow-hidden cursor-move max-h-[280px] touch-none", surface: "subtle", rounded: "lg", "data-disable-swipe": "true", tabIndex: 0, role: "application", "aria-label": t("cropInstruction"), onKeyDown: handleKeyDown, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, onTouchCancel: handleTouchEnd, children: [_jsx("img", { src: imageUrl, alt: t("cropPreviewAlt"), draggable: false, className: "absolute select-none pointer-events-none object-cover", style: {
|
|
93
93
|
width: `${zoom * 100}%`,
|
|
94
94
|
height: `${zoom * 100}%`,
|
|
95
95
|
left: `${position.x}%`,
|
|
@@ -11,7 +11,7 @@ import { normalizeError } from "../../../errors/normalize";
|
|
|
11
11
|
import { useState, useRef } from "react";
|
|
12
12
|
import { useTranslations } from "next-intl";
|
|
13
13
|
import { useCamera } from "../../../react";
|
|
14
|
-
import { Alert, Button, Div, Label, Progress, Row, Spinner, Stack, Text } from "../../../ui";
|
|
14
|
+
import { Alert, Button, Div, Label, Progress, Row, Spinner, Stack, Text, useToast } from "../../../ui";
|
|
15
15
|
import { MediaImage } from "../MediaImage";
|
|
16
16
|
import { ImageCropModal } from "../modals/ImageCropModal";
|
|
17
17
|
import { ImageEditor } from "../modals/ImageEditor";
|
|
@@ -51,6 +51,7 @@ export function ImageUpload({ currentImage, onUpload, onChange, accept = "image/
|
|
|
51
51
|
const tUpload = useTranslations("upload");
|
|
52
52
|
const tMediaEditor = useTranslations("mediaEditor");
|
|
53
53
|
const { isSupported: isCameraSupported } = useCamera();
|
|
54
|
+
const { showToast } = useToast();
|
|
54
55
|
const showCamera = captureSource === "camera-only" ||
|
|
55
56
|
(captureSource === "both" && captureMode === "camera");
|
|
56
57
|
const showFileInput = captureSource === "file-only" ||
|
|
@@ -65,12 +66,18 @@ export function ImageUpload({ currentImage, onUpload, onChange, accept = "image/
|
|
|
65
66
|
onChange?.(url);
|
|
66
67
|
if (cropData)
|
|
67
68
|
onCropDataChange?.(cropData);
|
|
69
|
+
return true;
|
|
68
70
|
}
|
|
69
71
|
catch (err) {
|
|
70
72
|
void normalizeError(err);
|
|
71
73
|
const message = err instanceof Error ? err.message : "Upload failed";
|
|
72
74
|
setError(message);
|
|
73
75
|
setPreview(currentImage || "");
|
|
76
|
+
// The crop/advanced-editor modal stays open on failure (callers only
|
|
77
|
+
// close it when this resolves true) — without a toast too, the error
|
|
78
|
+
// was easy to miss below the button the closed modal used to cover.
|
|
79
|
+
showToast(message, "error");
|
|
80
|
+
return false;
|
|
74
81
|
}
|
|
75
82
|
finally {
|
|
76
83
|
setUploading(false);
|
|
@@ -97,12 +104,15 @@ export function ImageUpload({ currentImage, onUpload, onChange, accept = "image/
|
|
|
97
104
|
};
|
|
98
105
|
reader.readAsDataURL(file);
|
|
99
106
|
};
|
|
100
|
-
const handleCropSave = (cropData) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
const handleCropSave = async (cropData) => {
|
|
108
|
+
if (!pendingFile)
|
|
109
|
+
return;
|
|
110
|
+
const ok = await performUpload(pendingFile, cropData);
|
|
111
|
+
if (ok) {
|
|
112
|
+
setShowCropModal(false);
|
|
113
|
+
setCropPreviewUrl(null);
|
|
114
|
+
setPendingFile(null);
|
|
115
|
+
}
|
|
106
116
|
};
|
|
107
117
|
const handleCropClose = () => {
|
|
108
118
|
setShowCropModal(false);
|
|
@@ -112,11 +122,13 @@ export function ImageUpload({ currentImage, onUpload, onChange, accept = "image/
|
|
|
112
122
|
setPendingFile(null);
|
|
113
123
|
}
|
|
114
124
|
};
|
|
115
|
-
const handleAdvancedEditorSave = (croppedFile) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
const handleAdvancedEditorSave = async (croppedFile) => {
|
|
126
|
+
const ok = await performUpload(croppedFile);
|
|
127
|
+
if (ok) {
|
|
128
|
+
setShowAdvancedEditor(false);
|
|
129
|
+
setCropPreviewUrl(null);
|
|
130
|
+
setPendingFile(null);
|
|
131
|
+
}
|
|
120
132
|
};
|
|
121
133
|
const openEditor = (url) => {
|
|
122
134
|
setCropPreviewUrl(url);
|
|
@@ -53,5 +53,5 @@ export function MarketplaceOrderCard({ order, links, labels, className = "", var
|
|
|
53
53
|
const actionsRow = (_jsxs(Row, { align: "center", gap: "sm", wrap: true, children: [(isShipped || isDelivered) &&
|
|
54
54
|
trackHref &&
|
|
55
55
|
order.trackingNumber && (_jsx(Button, { variant: "ghost", size: "sm", className: CLS_ACTION_BUTTON, onClick: () => navigate(trackHref), children: mergedLabels.trackOrder })), isDelivered && reviewHref && (_jsx(Button, { variant: "outline", size: "sm", className: CLS_ACTION_BUTTON, onClick: () => navigate(reviewHref), children: mergedLabels.writeReview })), _jsx(Button, { variant: "secondary", size: "sm", className: CLS_ACTION_BUTTON, onClick: () => navigate(detailHref), children: mergedLabels.viewOrder })] }));
|
|
56
|
-
return (_jsxs(Div, { rounded: "xl", border: "subtle", shadow: "hover-md", className: `group relative overflow-hidden bg-[var(--appkit-color-surface)] transition-all duration-200 ${isSelected ? "ring-2 ring-primary-500 dark:ring-primary-400" : ""} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, "data-section": "marketplaceordercard-div-411", children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: handleSelect, label: isSelected ? "Deselect order" : "Select order", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), isListVariant ? (_jsxs(Row, { align: "center", justify: "between", gap: "md", padding: "md", "data-section": "marketplaceordercard-div-412", children: [_jsx(Div, { layout: "flex", align: "start", gap: "3", paddingX: selectable ? "l-xl" : undefined, className: "min-w-0 flex-1", "data-section": "marketplaceordercard-div-413", children: infoBlock }), _jsxs(Row, { align: "center", gap: "md", className: "flex-shrink-0", "data-section": "marketplaceordercard-div-416", children: [_jsx(Row, { align: "center", gap: "md", "data-section": "marketplaceordercard-div-417", children: statusPriceBlock }), actionsRow] })] })) : (_jsxs(Stack, { gap: "md", padding: "md", "data-section": "marketplaceordercard-div-412", children: [_jsx(Div, { layout: "flex", align: "start", gap: "3", paddingX: selectable ? "l-xl" : undefined, "data-section": "marketplaceordercard-div-413", children: infoBlock }), _jsxs(Stack, { gap: "3", "data-section": "marketplaceordercard-div-416", children: [_jsx(Row, { wrap: true, align: "center", justify: "between", gap: "3", "data-section": "marketplaceordercard-div-417", children: statusPriceBlock }), actionsRow] })] }))] }));
|
|
56
|
+
return (_jsxs(Div, { rounded: "xl", border: "subtle", shadow: "hover-md", className: `group relative overflow-hidden bg-[var(--appkit-color-surface)] transition-all duration-200 ${isSelected ? "ring-2 ring-primary-500 dark:ring-primary-400" : ""} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: onSelect && !isSelected ? longPress.onTouchCancel : undefined, "data-section": "marketplaceordercard-div-411", children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: handleSelect, label: isSelected ? "Deselect order" : "Select order", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" })), isListVariant ? (_jsxs(Row, { align: "center", justify: "between", gap: "md", padding: "md", "data-section": "marketplaceordercard-div-412", children: [_jsx(Div, { layout: "flex", align: "start", gap: "3", paddingX: selectable ? "l-xl" : undefined, className: "min-w-0 flex-1", "data-section": "marketplaceordercard-div-413", children: infoBlock }), _jsxs(Row, { align: "center", gap: "md", className: "flex-shrink-0", "data-section": "marketplaceordercard-div-416", children: [_jsx(Row, { align: "center", gap: "md", "data-section": "marketplaceordercard-div-417", children: statusPriceBlock }), actionsRow] })] })) : (_jsxs(Stack, { gap: "md", padding: "md", "data-section": "marketplaceordercard-div-412", children: [_jsx(Div, { layout: "flex", align: "start", gap: "3", paddingX: selectable ? "l-xl" : undefined, "data-section": "marketplaceordercard-div-413", children: infoBlock }), _jsxs(Stack, { gap: "3", "data-section": "marketplaceordercard-div-416", children: [_jsx(Row, { wrap: true, align: "center", justify: "between", gap: "3", "data-section": "marketplaceordercard-div-417", children: statusPriceBlock }), actionsRow] })] }))] }));
|
|
57
57
|
}
|
|
@@ -57,7 +57,7 @@ export function MarketplacePreorderCard({ product, className = "", variant = "gr
|
|
|
57
57
|
// The hook rolls back optimistic state when the mutation fails.
|
|
58
58
|
}
|
|
59
59
|
}, [toggle]);
|
|
60
|
-
return (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: detailHref, className: "absolute inset-0 block", children: _jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "card", fallback: "Product image" }) }), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { layout: "inline-flex", color: "inverse", size: "xs", weight: "medium", className: "bg-cobalt", rounded: "full", padding: "pill-xs", children: mergedLabels.preOrderBadge }), product.featured && (_jsx(Span, { size: "xs", weight: "medium", className: CLS_PREORDER_BADGE, children: mergedLabels.featuredBadge }))] }), _jsxs(Stack, { className: "absolute left-2 top-2 pointer-events-none", gap: "xs", children: [product.partOfBundleIds && product.partOfBundleIds.length > 0 && (_jsx(Span, { className: CLS_SALE_BADGE, title: product.partOfBundleTitles?.[0] ? `In bundle: ${product.partOfBundleTitles[0]}` : "In a bundle", children: "Bundled" })), product.groupId && (_jsx(Span, { className: CLS_TRENDING_BADGE, title: product.groupTitle ? `Part of set: ${product.groupTitle}` : "Part of a set", children: product.isGroupParent ? "Set Parent" : "In Set" })), product.sublistingCategoryId && (_jsx(Span, { className: CLS_LIMITED_BADGE, title: "Has variants or sub-listings", children: "Has Variants" }))] }), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
|
|
60
|
+
return (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: detailHref, className: "absolute inset-0 block", children: _jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "card", fallback: "Product image" }) }), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { layout: "inline-flex", color: "inverse", size: "xs", weight: "medium", className: "bg-cobalt", rounded: "full", padding: "pill-xs", children: mergedLabels.preOrderBadge }), product.featured && (_jsx(Span, { size: "xs", weight: "medium", className: CLS_PREORDER_BADGE, children: mergedLabels.featuredBadge }))] }), _jsxs(Stack, { className: "absolute left-2 top-2 pointer-events-none", gap: "xs", children: [product.partOfBundleIds && product.partOfBundleIds.length > 0 && (_jsx(Span, { className: CLS_SALE_BADGE, title: product.partOfBundleTitles?.[0] ? `In bundle: ${product.partOfBundleTitles[0]}` : "In a bundle", children: "Bundled" })), product.groupId && (_jsx(Span, { className: CLS_TRENDING_BADGE, title: product.groupTitle ? `Part of set: ${product.groupTitle}` : "Part of a set", children: product.isGroupParent ? "Set Parent" : "In Set" })), product.sublistingCategoryId && (_jsx(Span, { className: CLS_LIMITED_BADGE, title: "Has variants or sub-listings", children: "Has Variants" }))] }), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
|
|
61
61
|
event.stopPropagation();
|
|
62
62
|
onSelect(product.id, !isSelected);
|
|
63
63
|
}, className: selectable || isSelected ? "opacity-100" : "opacity-0 group-hover:opacity-100 transition-opacity" }))] }), _jsx(BaseListingCard.Info, { variant: variant, children: variant === "list" ? (
|