@akinon/projectzero 2.0.0-beta.20 → 2.0.0-beta.21
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/CHANGELOG.md +8 -0
- package/app-template/CHANGELOG.md +138 -0
- package/app-template/next.config.mjs +0 -1
- package/app-template/package.json +31 -30
- package/app-template/src/app/[pz]/[...prettyurl]/page.tsx +2 -2
- package/app-template/src/app/[pz]/account/layout.tsx +2 -1
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/blog/[slug]/page.tsx +4 -2
- package/app-template/src/app/[pz]/category/[pk]/page.tsx +11 -1
- package/app-template/src/app/[pz]/group-product/[pk]/page.tsx +2 -2
- package/app-template/src/app/[pz]/layout.tsx +3 -1
- package/app-template/src/app/[pz]/list/page.tsx +11 -1
- package/app-template/src/app/[pz]/page.tsx +13 -35
- package/app-template/src/app/[pz]/pages/[slug]/page.tsx +19 -0
- package/app-template/src/app/[pz]/product/[pk]/page.tsx +2 -2
- package/app-template/src/app/api/barcode-search/route.ts +1 -1
- package/app-template/src/app/api/cache/route.ts +1 -1
- package/app-template/src/app/api/image-proxy/route.ts +1 -1
- package/app-template/src/app/api/logout/route.ts +1 -1
- package/app-template/src/app/api/product-categories/route.ts +1 -1
- package/app-template/src/app/api/similar-product-list/route.ts +1 -1
- package/app-template/src/app/api/similar-products/route.ts +1 -1
- package/app-template/src/app/api/virtual-try-on/route.ts +1 -1
- package/app-template/src/app/api/web-vitals/route.ts +1 -1
- package/app-template/src/components/quantity-selector.tsx +16 -4
- package/app-template/src/components/widget-content.tsx +3 -3
- package/app-template/src/routes/index.ts +6 -6
- package/app-template/src/utils/__tests__/theme-page-context.test.ts +145 -0
- package/app-template/src/utils/theme-page-context.ts +309 -0
- package/app-template/src/views/basket/basket-item.tsx +107 -691
- package/app-template/src/views/basket/index.ts +0 -2
- package/app-template/src/views/basket/summary.tsx +75 -496
- package/app-template/src/views/breadcrumb.tsx +38 -13
- package/app-template/src/views/category/category-header.tsx +66 -289
- package/app-template/src/views/category/category-info.tsx +24 -173
- package/app-template/src/views/category/filters/index.tsx +48 -208
- package/app-template/src/views/category/layout.tsx +5 -7
- package/app-template/src/views/checkout/index.tsx +0 -5
- package/app-template/src/views/checkout/steps/payment/index.tsx +2 -5
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +1 -72
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +40 -171
- package/app-template/src/views/checkout/steps/shipping/address-box.tsx +12 -74
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +45 -128
- package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +27 -232
- package/app-template/src/views/checkout/summary.tsx +29 -303
- package/app-template/src/views/footer.tsx +13 -415
- package/app-template/src/views/guest-login/index.tsx +1 -1
- package/app-template/src/views/header/action-menu.tsx +45 -277
- package/app-template/src/views/header/band.tsx +21 -6
- package/app-template/src/views/header/index.tsx +47 -109
- package/app-template/src/views/header/mini-basket.tsx +45 -820
- package/app-template/src/views/header/navbar.tsx +111 -178
- package/app-template/src/views/header/search/index.tsx +32 -71
- package/app-template/src/views/header/search/results.tsx +65 -127
- package/app-template/src/views/product/accordion-wrapper.tsx +43 -135
- package/app-template/src/views/product/index.ts +1 -1
- package/app-template/src/views/product/layout.tsx +7 -2
- package/app-template/src/views/product/misc-buttons.tsx +25 -339
- package/app-template/src/views/product/product-actions.tsx +8 -137
- package/app-template/src/views/product/product-info.tsx +31 -69
- package/app-template/src/views/product/product-share.tsx +8 -11
- package/app-template/src/views/product/slider.tsx +79 -117
- package/app-template/src/views/product-item/index.tsx +46 -119
- package/app-template/src/widgets/footer-social.tsx +16 -47
- package/app-template/src/widgets/footer-subscription/index.tsx +17 -183
- package/dist/commands/plugins.js +23 -2
- package/package.json +1 -1
- package/app-template/src/app/[commerce]/[locale]/[currency]/pages/[slug]/page.tsx +0 -15
- package/app-template/src/views/basket/basket-summary-context.tsx +0 -560
- package/app-template/src/views/basket/designer-context.tsx +0 -617
- package/app-template/src/views/breadcrumb/breadcrumb-client.tsx +0 -190
- package/app-template/src/views/breadcrumb/breadcrumb-registrar.tsx +0 -286
- package/app-template/src/views/breadcrumb/constants.ts +0 -15
- package/app-template/src/views/breadcrumb/index.tsx +0 -127
- package/app-template/src/views/category/native-widget-context.tsx +0 -257
- package/app-template/src/views/category/product-list-registrar.tsx +0 -665
- package/app-template/src/views/checkout/checkout-address-registrar.tsx +0 -254
- package/app-template/src/views/checkout/checkout-buttons-registrar.tsx +0 -183
- package/app-template/src/views/checkout/checkout-delivery-method-registrar.tsx +0 -259
- package/app-template/src/views/checkout/checkout-payment-options-registrar.tsx +0 -253
- package/app-template/src/views/checkout/checkout-summary-registrar.tsx +0 -183
- package/app-template/src/views/checkout/constants.ts +0 -5
- package/app-template/src/views/checkout/steps/payment/options/masterpass-rest.tsx +0 -15
- package/app-template/src/views/checkout/steps/payment/options/saved-card.tsx +0 -18
- package/app-template/src/views/footer/footer-app-banner-context.tsx +0 -326
- package/app-template/src/views/footer/footer-bottom-context.tsx +0 -215
- package/app-template/src/views/footer/footer-bottom-wrapper.tsx +0 -74
- package/app-template/src/views/footer/footer-layout-constants.ts +0 -35
- package/app-template/src/views/footer/footer-layout-registrar.tsx +0 -342
- package/app-template/src/views/footer/footer-layout-switcher.tsx +0 -110
- package/app-template/src/views/footer/footer-menu-context.tsx +0 -211
- package/app-template/src/views/footer/footer-native-widgets.tsx +0 -60
- package/app-template/src/views/footer/footer-social-context.tsx +0 -254
- package/app-template/src/views/footer/footer-subscription-context.tsx +0 -210
- package/app-template/src/views/footer/footer-utils.ts +0 -43
- package/app-template/src/views/footer/footer-value-props-context.tsx +0 -326
- package/app-template/src/views/footer/logo-settings.ts +0 -183
- package/app-template/src/views/footer/native-widget-config.ts +0 -262
- package/app-template/src/views/footer/subscription-settings.ts +0 -122
- package/app-template/src/views/footer/use-footer-logo.ts +0 -162
- package/app-template/src/views/header/designer-context.tsx +0 -261
- package/app-template/src/views/header/header-announcement-registrar.tsx +0 -267
- package/app-template/src/views/header/header-client-wrapper.tsx +0 -496
- package/app-template/src/views/header/header-content.tsx +0 -1026
- package/app-template/src/views/header/header-currency-registrar.tsx +0 -348
- package/app-template/src/views/header/header-icons-context.tsx +0 -262
- package/app-template/src/views/header/header-language-registrar.tsx +0 -348
- package/app-template/src/views/header/header-layout-context.tsx +0 -143
- package/app-template/src/views/header/header-layout-registrar.tsx +0 -658
- package/app-template/src/views/header/header-logo-context.tsx +0 -228
- package/app-template/src/views/header/header-logo.tsx +0 -118
- package/app-template/src/views/header/header-mini-basket-context.tsx +0 -524
- package/app-template/src/views/header/header-search-registrar.tsx +0 -511
- package/app-template/src/views/header/header-text-slider-registrar.tsx +0 -382
- package/app-template/src/views/header/inline-search.tsx +0 -262
- package/app-template/src/views/header/navbar-menu-context.tsx +0 -219
- package/app-template/src/views/header/search/search-input.tsx +0 -61
- package/app-template/src/views/header/server-settings-parser.ts +0 -1105
- package/app-template/src/views/header/use-header-icons.ts +0 -241
- package/app-template/src/views/header/use-header-logo.ts +0 -213
- package/app-template/src/views/header/use-navbar-menu.ts +0 -179
- package/app-template/src/views/product/accordion-section.tsx +0 -61
- package/app-template/src/views/product/custom-button-group.tsx +0 -69
- package/app-template/src/views/product/favorites-button-section.tsx +0 -69
- package/app-template/src/views/product/find-in-store-section.tsx +0 -60
- package/app-template/src/views/product/product-info-section.tsx +0 -140
- package/app-template/src/views/product/quantity-section.tsx +0 -73
- package/app-template/src/views/product/sale-tag.tsx +0 -10
- package/app-template/src/views/product/share-section.tsx +0 -357
- package/app-template/src/views/product/variants-section.tsx +0 -126
- package/app-template/src/views/product-detail/constants.ts +0 -272
- package/app-template/src/views/product-detail/index.ts +0 -10
- package/app-template/src/views/product-detail/product-detail-registrar.tsx +0 -616
- package/app-template/src/widgets/footer-app-banner.tsx +0 -444
- package/app-template/src/widgets/footer-bottom.tsx +0 -127
- package/app-template/src/widgets/footer-menu-compact.tsx +0 -238
- package/app-template/src/widgets/footer-menu-two.tsx +0 -298
- package/app-template/src/widgets/footer-social-client.tsx +0 -251
- package/app-template/src/widgets/footer-value-props.tsx +0 -201
|
@@ -1,665 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Product List Page Registrar
|
|
5
|
-
*
|
|
6
|
-
* This component registers the "Product List Page" placeholder as a native widget.
|
|
7
|
-
* The placeholder contains a "Filters" section that allows customization
|
|
8
|
-
* of styles and layout via the Theme Editor.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
createContext,
|
|
13
|
-
useContext,
|
|
14
|
-
useEffect,
|
|
15
|
-
useRef,
|
|
16
|
-
useState,
|
|
17
|
-
PropsWithChildren
|
|
18
|
-
} from 'react';
|
|
19
|
-
import {
|
|
20
|
-
registerPlaceholder,
|
|
21
|
-
unregisterPlaceholder
|
|
22
|
-
} from '@akinon/next/components/theme-editor/placeholder-registry';
|
|
23
|
-
|
|
24
|
-
// Constants
|
|
25
|
-
const PRODUCT_LIST_PLACEHOLDER_ID = 'product-list-page';
|
|
26
|
-
const FILTERS_SECTION_ID = 'filters-section';
|
|
27
|
-
const PRODUCTS_SECTION_ID = 'products-section';
|
|
28
|
-
|
|
29
|
-
// Re-export constants
|
|
30
|
-
export { PRODUCT_LIST_PLACEHOLDER_ID, FILTERS_SECTION_ID, PRODUCTS_SECTION_ID };
|
|
31
|
-
|
|
32
|
-
// Global flag to track if registration has been done
|
|
33
|
-
declare global {
|
|
34
|
-
interface Window {
|
|
35
|
-
__productListPageRegistered?: boolean;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Check if running inside designer iframe
|
|
41
|
-
*/
|
|
42
|
-
function isInDesignerMode(): boolean {
|
|
43
|
-
if (typeof window === 'undefined') return false;
|
|
44
|
-
return window.self !== window.top;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface ThemeSection {
|
|
48
|
-
id: string;
|
|
49
|
-
visible?: boolean;
|
|
50
|
-
properties?: Record<string, unknown>;
|
|
51
|
-
styles?: Record<string, unknown>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
interface ThemePlaceholder {
|
|
55
|
-
slug: string;
|
|
56
|
-
sections: ThemeSection[];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export interface FilterProperties {
|
|
60
|
-
layout?: 'sidebar' | 'top';
|
|
61
|
-
'item-padding-y'?: number;
|
|
62
|
-
'item-padding-x'?: number;
|
|
63
|
-
'item-margin-bottom'?: number;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface FilterStyles {
|
|
67
|
-
backgroundColor?: string;
|
|
68
|
-
padding?: string;
|
|
69
|
-
borderRadius?: string;
|
|
70
|
-
boxShadow?: string;
|
|
71
|
-
border?: string;
|
|
72
|
-
margin?: string;
|
|
73
|
-
[key: string]: string | undefined;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface ProductsProperties {
|
|
77
|
-
'show-layout-buttons'?: boolean;
|
|
78
|
-
'available-layouts'?: string[];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface ProductsStyles {
|
|
82
|
-
'gap-x'?: string;
|
|
83
|
-
'gap-y'?: string;
|
|
84
|
-
'padding-top'?: string;
|
|
85
|
-
'padding-bottom'?: string;
|
|
86
|
-
'padding-left'?: string;
|
|
87
|
-
'padding-right'?: string;
|
|
88
|
-
[key: string]: string | undefined;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface ProductItemProperties {
|
|
92
|
-
'show-fav-button'?: boolean;
|
|
93
|
-
'fav-button-position'?:
|
|
94
|
-
| 'top-left'
|
|
95
|
-
| 'top-right'
|
|
96
|
-
| 'bottom-left'
|
|
97
|
-
| 'bottom-right';
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface ProductItemStyles {
|
|
101
|
-
'fav-button-size'?: string;
|
|
102
|
-
'fav-button-bg-color'?: string;
|
|
103
|
-
'fav-button-icon-color'?: string;
|
|
104
|
-
'fav-button-border-radius'?: string;
|
|
105
|
-
// Product name styles
|
|
106
|
-
'product-name-font-size'?: string;
|
|
107
|
-
'product-name-color'?: string;
|
|
108
|
-
'product-name-font-weight'?: string;
|
|
109
|
-
'product-name-line-clamp'?: string;
|
|
110
|
-
// Price styles
|
|
111
|
-
'price-font-size'?: string;
|
|
112
|
-
'price-color'?: string;
|
|
113
|
-
'price-font-weight'?: string;
|
|
114
|
-
// Old price styles
|
|
115
|
-
'old-price-font-size'?: string;
|
|
116
|
-
'old-price-color'?: string;
|
|
117
|
-
[key: string]: string | undefined;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export interface PaginationProperties {
|
|
121
|
-
type?: 'list' | 'more' | 'infinite';
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export interface PaginationStyles {
|
|
125
|
-
'margin-top'?: string;
|
|
126
|
-
'margin-bottom'?: string;
|
|
127
|
-
'page-font-size'?: string;
|
|
128
|
-
'page-color'?: string;
|
|
129
|
-
'page-active-color'?: string;
|
|
130
|
-
'page-active-font-weight'?: string;
|
|
131
|
-
'page-gap'?: string;
|
|
132
|
-
'page-bg-color'?: string;
|
|
133
|
-
'page-active-bg-color'?: string;
|
|
134
|
-
'page-padding-x'?: string;
|
|
135
|
-
'page-padding-y'?: string;
|
|
136
|
-
'page-border-radius'?: string;
|
|
137
|
-
'page-border-width'?: string;
|
|
138
|
-
'page-border-color'?: string;
|
|
139
|
-
'page-active-border-color'?: string;
|
|
140
|
-
'arrow-color'?: string;
|
|
141
|
-
'button-bg-color'?: string;
|
|
142
|
-
'button-text-color'?: string;
|
|
143
|
-
'button-border-radius'?: string;
|
|
144
|
-
'button-padding-x'?: string;
|
|
145
|
-
'button-padding-y'?: string;
|
|
146
|
-
[key: string]: string | undefined;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
interface ProductListContextValue {
|
|
150
|
-
isDesigner: boolean;
|
|
151
|
-
selectedSectionId: string | null;
|
|
152
|
-
filterStyles: FilterStyles;
|
|
153
|
-
filterProperties: FilterProperties;
|
|
154
|
-
productsProperties: ProductsProperties;
|
|
155
|
-
productsStyles: ProductsStyles;
|
|
156
|
-
productItemProperties: ProductItemProperties;
|
|
157
|
-
productItemStyles: ProductItemStyles;
|
|
158
|
-
paginationProperties: PaginationProperties;
|
|
159
|
-
paginationStyles: PaginationStyles;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const ProductListContext = createContext<ProductListContextValue>({
|
|
163
|
-
isDesigner: false,
|
|
164
|
-
selectedSectionId: null,
|
|
165
|
-
filterStyles: {},
|
|
166
|
-
filterProperties: { layout: 'top' },
|
|
167
|
-
productsProperties: {
|
|
168
|
-
'show-layout-buttons': true,
|
|
169
|
-
'available-layouts': ['2', '3', '4']
|
|
170
|
-
},
|
|
171
|
-
productsStyles: {},
|
|
172
|
-
productItemProperties: {
|
|
173
|
-
'show-fav-button': true,
|
|
174
|
-
'fav-button-position': 'top-right'
|
|
175
|
-
},
|
|
176
|
-
productItemStyles: {},
|
|
177
|
-
paginationProperties: {
|
|
178
|
-
type: 'list'
|
|
179
|
-
},
|
|
180
|
-
paginationStyles: {}
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
export const useProductList = () => useContext(ProductListContext);
|
|
184
|
-
|
|
185
|
-
interface ProductListRegistrarProps extends PropsWithChildren {
|
|
186
|
-
/**
|
|
187
|
-
* Initial settings from server-side parsing (to avoid flash)
|
|
188
|
-
*/
|
|
189
|
-
initialSettings?: {
|
|
190
|
-
filterStyles?: FilterStyles;
|
|
191
|
-
filterProperties?: FilterProperties;
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* ProductListRegistrar
|
|
197
|
-
*
|
|
198
|
-
* Registers the Product List Page native placeholder with Theme Editor.
|
|
199
|
-
* Contains "Filters" section for customizing filters layout and appearance.
|
|
200
|
-
*/
|
|
201
|
-
export default function ProductListRegistrar({
|
|
202
|
-
children,
|
|
203
|
-
initialSettings
|
|
204
|
-
}: ProductListRegistrarProps) {
|
|
205
|
-
const [isDesigner, setIsDesigner] = useState(false);
|
|
206
|
-
const [selectedSectionId, setSelectedSectionId] = useState<string | null>(
|
|
207
|
-
null
|
|
208
|
-
);
|
|
209
|
-
const [filterStyles, setFilterStyles] = useState<FilterStyles>(
|
|
210
|
-
initialSettings?.filterStyles || {}
|
|
211
|
-
);
|
|
212
|
-
const [filterProperties, setFilterProperties] = useState<FilterProperties>(
|
|
213
|
-
initialSettings?.filterProperties || {
|
|
214
|
-
layout: 'top',
|
|
215
|
-
'item-padding-y': 6,
|
|
216
|
-
'item-padding-x': 0,
|
|
217
|
-
'item-margin-bottom': 0
|
|
218
|
-
}
|
|
219
|
-
);
|
|
220
|
-
const [productsProperties, setProductsProperties] =
|
|
221
|
-
useState<ProductsProperties>({
|
|
222
|
-
'show-layout-buttons': true,
|
|
223
|
-
'available-layouts': ['2', '3', '4']
|
|
224
|
-
});
|
|
225
|
-
const [productsStyles, setProductsStyles] = useState<ProductsStyles>({});
|
|
226
|
-
const [productItemProperties, setProductItemProperties] =
|
|
227
|
-
useState<ProductItemProperties>({
|
|
228
|
-
'show-fav-button': true,
|
|
229
|
-
'fav-button-position': 'top-right'
|
|
230
|
-
});
|
|
231
|
-
const [productItemStyles, setProductItemStyles] = useState<ProductItemStyles>(
|
|
232
|
-
{}
|
|
233
|
-
);
|
|
234
|
-
const [paginationProperties, setPaginationProperties] =
|
|
235
|
-
useState<PaginationProperties>({
|
|
236
|
-
type: 'list'
|
|
237
|
-
});
|
|
238
|
-
const [paginationStyles, setPaginationStyles] = useState<PaginationStyles>(
|
|
239
|
-
{}
|
|
240
|
-
);
|
|
241
|
-
const registeredRef = useRef(false);
|
|
242
|
-
|
|
243
|
-
// Helper to extract responsive value
|
|
244
|
-
const extractValue = (value: unknown): unknown => {
|
|
245
|
-
if (value && typeof value === 'object' && 'desktop' in value) {
|
|
246
|
-
return (value as { desktop: unknown }).desktop;
|
|
247
|
-
}
|
|
248
|
-
return value;
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
useEffect(() => {
|
|
252
|
-
const designerMode = isInDesignerMode();
|
|
253
|
-
setIsDesigner(designerMode);
|
|
254
|
-
|
|
255
|
-
if (!designerMode) return;
|
|
256
|
-
|
|
257
|
-
// Register placeholder for PLACEHOLDERS_AVAILABLE message
|
|
258
|
-
registerPlaceholder(PRODUCT_LIST_PLACEHOLDER_ID);
|
|
259
|
-
|
|
260
|
-
// One-time registration per session
|
|
261
|
-
if (!window.__productListPageRegistered && !registeredRef.current) {
|
|
262
|
-
window.__productListPageRegistered = true;
|
|
263
|
-
registeredRef.current = true;
|
|
264
|
-
|
|
265
|
-
// Send REGISTER_NATIVE_WIDGETS message to parent
|
|
266
|
-
const filtersWidgetConfig = {
|
|
267
|
-
placeholderId: PRODUCT_LIST_PLACEHOLDER_ID,
|
|
268
|
-
autoAdd: true,
|
|
269
|
-
section: {
|
|
270
|
-
id: FILTERS_SECTION_ID,
|
|
271
|
-
type: 'native',
|
|
272
|
-
label: 'Filters',
|
|
273
|
-
blocks: [],
|
|
274
|
-
properties: initialSettings?.filterProperties || {
|
|
275
|
-
layout: 'top',
|
|
276
|
-
'item-padding-y': 6,
|
|
277
|
-
'item-padding-x': 0,
|
|
278
|
-
'item-margin-bottom': 0
|
|
279
|
-
},
|
|
280
|
-
propertySchema: {
|
|
281
|
-
layout: {
|
|
282
|
-
type: 'select',
|
|
283
|
-
label: 'Layout',
|
|
284
|
-
options: [
|
|
285
|
-
{ label: 'Top (Above Products)', value: 'top' },
|
|
286
|
-
{ label: 'Sidebar (Left)', value: 'sidebar' }
|
|
287
|
-
],
|
|
288
|
-
default: 'top'
|
|
289
|
-
},
|
|
290
|
-
'item-padding-y': {
|
|
291
|
-
type: 'slider',
|
|
292
|
-
label: 'Item Vertical Padding',
|
|
293
|
-
default: 6,
|
|
294
|
-
min: 0,
|
|
295
|
-
max: 32,
|
|
296
|
-
unit: 'px'
|
|
297
|
-
},
|
|
298
|
-
'item-padding-x': {
|
|
299
|
-
type: 'slider',
|
|
300
|
-
label: 'Item Horizontal Padding',
|
|
301
|
-
default: 0,
|
|
302
|
-
min: 0,
|
|
303
|
-
max: 32,
|
|
304
|
-
unit: 'px'
|
|
305
|
-
},
|
|
306
|
-
'item-margin-bottom': {
|
|
307
|
-
type: 'slider',
|
|
308
|
-
label: 'Spacing Between Items',
|
|
309
|
-
default: 0,
|
|
310
|
-
min: 0,
|
|
311
|
-
max: 32,
|
|
312
|
-
unit: 'px'
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
styles: initialSettings?.filterStyles || {}
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
const productsWidgetConfig = {
|
|
320
|
-
placeholderId: PRODUCT_LIST_PLACEHOLDER_ID,
|
|
321
|
-
autoAdd: true,
|
|
322
|
-
section: {
|
|
323
|
-
id: PRODUCTS_SECTION_ID,
|
|
324
|
-
type: 'native',
|
|
325
|
-
label: 'Products',
|
|
326
|
-
blocks: [],
|
|
327
|
-
properties: {
|
|
328
|
-
'show-layout-buttons': true,
|
|
329
|
-
'available-layouts': ['2', '3', '4']
|
|
330
|
-
},
|
|
331
|
-
propertySchema: {
|
|
332
|
-
'show-layout-buttons': {
|
|
333
|
-
type: 'toggle',
|
|
334
|
-
label: 'Show Layout Buttons',
|
|
335
|
-
default: true
|
|
336
|
-
},
|
|
337
|
-
'available-layouts': {
|
|
338
|
-
type: 'multiselect',
|
|
339
|
-
label: 'Available Layouts',
|
|
340
|
-
default: ['2', '3', '4'],
|
|
341
|
-
options: [
|
|
342
|
-
{ label: '2 Columns', value: '2' },
|
|
343
|
-
{ label: '3 Columns', value: '3' },
|
|
344
|
-
{ label: '4 Columns', value: '4' },
|
|
345
|
-
{ label: '6 Columns', value: '6' }
|
|
346
|
-
]
|
|
347
|
-
}
|
|
348
|
-
},
|
|
349
|
-
styles: {}
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
const productItemWidgetConfig = {
|
|
354
|
-
placeholderId: PRODUCT_LIST_PLACEHOLDER_ID,
|
|
355
|
-
autoAdd: true,
|
|
356
|
-
section: {
|
|
357
|
-
id: 'product-item-section',
|
|
358
|
-
type: 'native',
|
|
359
|
-
label: 'Product Item',
|
|
360
|
-
blocks: [],
|
|
361
|
-
properties: {
|
|
362
|
-
'show-fav-button': true,
|
|
363
|
-
'fav-button-position': 'top-right'
|
|
364
|
-
},
|
|
365
|
-
propertySchema: {
|
|
366
|
-
'show-fav-button': {
|
|
367
|
-
type: 'toggle',
|
|
368
|
-
label: 'Show Favorite Button',
|
|
369
|
-
default: true
|
|
370
|
-
},
|
|
371
|
-
'fav-button-position': {
|
|
372
|
-
type: 'select',
|
|
373
|
-
label: 'Favorite Button Position',
|
|
374
|
-
default: 'top-right',
|
|
375
|
-
options: [
|
|
376
|
-
{ label: 'Top Left', value: 'top-left' },
|
|
377
|
-
{ label: 'Top Right', value: 'top-right' },
|
|
378
|
-
{ label: 'Bottom Left', value: 'bottom-left' },
|
|
379
|
-
{ label: 'Bottom Right', value: 'bottom-right' }
|
|
380
|
-
]
|
|
381
|
-
}
|
|
382
|
-
},
|
|
383
|
-
styles: {}
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
const paginationWidgetConfig = {
|
|
388
|
-
placeholderId: PRODUCT_LIST_PLACEHOLDER_ID,
|
|
389
|
-
autoAdd: true,
|
|
390
|
-
section: {
|
|
391
|
-
id: 'pagination-section',
|
|
392
|
-
type: 'native',
|
|
393
|
-
label: 'Pagination',
|
|
394
|
-
blocks: [],
|
|
395
|
-
properties: {
|
|
396
|
-
type: 'list'
|
|
397
|
-
},
|
|
398
|
-
propertySchema: {
|
|
399
|
-
type: {
|
|
400
|
-
type: 'select',
|
|
401
|
-
label: 'Pagination Type',
|
|
402
|
-
default: 'list',
|
|
403
|
-
options: [
|
|
404
|
-
{ label: 'Page Numbers', value: 'list' },
|
|
405
|
-
{ label: 'Load More Button', value: 'more' },
|
|
406
|
-
{ label: 'Infinite Scroll', value: 'infinite' }
|
|
407
|
-
]
|
|
408
|
-
}
|
|
409
|
-
},
|
|
410
|
-
styles: {}
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
window.parent?.postMessage(
|
|
415
|
-
{
|
|
416
|
-
type: 'REGISTER_NATIVE_WIDGETS',
|
|
417
|
-
data: {
|
|
418
|
-
widgets: [
|
|
419
|
-
filtersWidgetConfig,
|
|
420
|
-
productsWidgetConfig,
|
|
421
|
-
productItemWidgetConfig,
|
|
422
|
-
paginationWidgetConfig
|
|
423
|
-
]
|
|
424
|
-
}
|
|
425
|
-
},
|
|
426
|
-
'*'
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const handleMessage = (event: MessageEvent) => {
|
|
431
|
-
const { type, data } = event.data || {};
|
|
432
|
-
|
|
433
|
-
// Handle section selection
|
|
434
|
-
if (type === 'SELECT_SECTION') {
|
|
435
|
-
if (data?.placeholderId === PRODUCT_LIST_PLACEHOLDER_ID) {
|
|
436
|
-
setSelectedSectionId(data.sectionId ?? null);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (type === 'CLEAR_SELECTION') {
|
|
441
|
-
setSelectedSectionId(null);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// Handle LOAD_THEME and UPDATE_THEME - theme updates
|
|
445
|
-
if (
|
|
446
|
-
(type === 'LOAD_THEME' || type === 'UPDATE_THEME') &&
|
|
447
|
-
data?.theme?.placeholders
|
|
448
|
-
) {
|
|
449
|
-
const placeholder = data.theme.placeholders.find(
|
|
450
|
-
(p: ThemePlaceholder) => p.slug === PRODUCT_LIST_PLACEHOLDER_ID
|
|
451
|
-
);
|
|
452
|
-
|
|
453
|
-
if (placeholder?.sections) {
|
|
454
|
-
// Process Filters section
|
|
455
|
-
const filtersSection = placeholder.sections.find(
|
|
456
|
-
(s: ThemeSection) => s.id === FILTERS_SECTION_ID
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
if (filtersSection) {
|
|
460
|
-
// Extract styles
|
|
461
|
-
if (filtersSection.styles) {
|
|
462
|
-
const extractedStyles: FilterStyles = {};
|
|
463
|
-
Object.entries(filtersSection.styles).forEach(([key, value]) => {
|
|
464
|
-
const val = extractValue(value);
|
|
465
|
-
if (val !== undefined && val !== null) {
|
|
466
|
-
extractedStyles[key] = String(val);
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
setFilterStyles(extractedStyles);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// Extract properties
|
|
473
|
-
if (filtersSection.properties) {
|
|
474
|
-
const props: FilterProperties = {};
|
|
475
|
-
const {
|
|
476
|
-
layout,
|
|
477
|
-
'item-padding-y': itemPaddingY,
|
|
478
|
-
'item-padding-x': itemPaddingX,
|
|
479
|
-
'item-margin-bottom': itemMarginBottom
|
|
480
|
-
} = filtersSection.properties;
|
|
481
|
-
|
|
482
|
-
if (layout) {
|
|
483
|
-
const layoutVal = extractValue(layout);
|
|
484
|
-
props.layout = (layoutVal as 'sidebar' | 'top') || 'sidebar';
|
|
485
|
-
}
|
|
486
|
-
if (itemPaddingY !== undefined) {
|
|
487
|
-
const val = extractValue(itemPaddingY);
|
|
488
|
-
// Parse string value like '14px' to number 14
|
|
489
|
-
const numVal =
|
|
490
|
-
typeof val === 'string' ? parseInt(val, 10) : val;
|
|
491
|
-
props['item-padding-y'] =
|
|
492
|
-
typeof numVal === 'number' && !isNaN(numVal) ? numVal : 6;
|
|
493
|
-
}
|
|
494
|
-
if (itemPaddingX !== undefined) {
|
|
495
|
-
const val = extractValue(itemPaddingX);
|
|
496
|
-
// Parse string value like '14px' to number 14
|
|
497
|
-
const numVal =
|
|
498
|
-
typeof val === 'string' ? parseInt(val, 10) : val;
|
|
499
|
-
props['item-padding-x'] =
|
|
500
|
-
typeof numVal === 'number' && !isNaN(numVal) ? numVal : 0;
|
|
501
|
-
}
|
|
502
|
-
if (itemMarginBottom !== undefined) {
|
|
503
|
-
const val = extractValue(itemMarginBottom);
|
|
504
|
-
// Parse string value like '14px' to number 14
|
|
505
|
-
const numVal =
|
|
506
|
-
typeof val === 'string' ? parseInt(val, 10) : val;
|
|
507
|
-
props['item-margin-bottom'] =
|
|
508
|
-
typeof numVal === 'number' && !isNaN(numVal) ? numVal : 0;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
setFilterProperties(props);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Process Products section
|
|
516
|
-
const productsSection = placeholder.sections.find(
|
|
517
|
-
(s: ThemeSection) => s.id === PRODUCTS_SECTION_ID
|
|
518
|
-
);
|
|
519
|
-
|
|
520
|
-
if (productsSection) {
|
|
521
|
-
// Extract styles
|
|
522
|
-
if (productsSection.styles) {
|
|
523
|
-
const extractedStyles: ProductsStyles = {};
|
|
524
|
-
Object.entries(productsSection.styles).forEach(([key, value]) => {
|
|
525
|
-
const val = extractValue(value);
|
|
526
|
-
if (val !== undefined && val !== null) {
|
|
527
|
-
extractedStyles[key] = String(val);
|
|
528
|
-
}
|
|
529
|
-
});
|
|
530
|
-
setProductsStyles(extractedStyles);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Extract properties
|
|
534
|
-
if (productsSection.properties) {
|
|
535
|
-
const productsProps: ProductsProperties = {};
|
|
536
|
-
const {
|
|
537
|
-
'show-layout-buttons': showLayoutButtons,
|
|
538
|
-
'available-layouts': availableLayouts
|
|
539
|
-
} = productsSection.properties;
|
|
540
|
-
|
|
541
|
-
if (showLayoutButtons !== undefined) {
|
|
542
|
-
const val = extractValue(showLayoutButtons);
|
|
543
|
-
productsProps['show-layout-buttons'] =
|
|
544
|
-
typeof val === 'boolean' ? val : true;
|
|
545
|
-
}
|
|
546
|
-
if (availableLayouts !== undefined) {
|
|
547
|
-
const val = extractValue(availableLayouts);
|
|
548
|
-
productsProps['available-layouts'] = Array.isArray(val)
|
|
549
|
-
? val
|
|
550
|
-
: ['2', '3', '4'];
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
setProductsProperties(productsProps);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// Process Product Item section
|
|
558
|
-
const productItemSection = placeholder.sections.find(
|
|
559
|
-
(s: ThemeSection) => s.id === 'product-item-section'
|
|
560
|
-
);
|
|
561
|
-
|
|
562
|
-
if (productItemSection) {
|
|
563
|
-
// Extract styles
|
|
564
|
-
if (productItemSection.styles) {
|
|
565
|
-
const extractedStyles: ProductItemStyles = {};
|
|
566
|
-
Object.entries(productItemSection.styles).forEach(
|
|
567
|
-
([key, value]) => {
|
|
568
|
-
const val = extractValue(value);
|
|
569
|
-
if (val !== undefined && val !== null) {
|
|
570
|
-
extractedStyles[key] = String(val);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
);
|
|
574
|
-
setProductItemStyles(extractedStyles);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// Extract properties
|
|
578
|
-
if (productItemSection.properties) {
|
|
579
|
-
const itemProps: ProductItemProperties = {};
|
|
580
|
-
const {
|
|
581
|
-
'show-fav-button': showFavButton,
|
|
582
|
-
'fav-button-position': favButtonPosition
|
|
583
|
-
} = productItemSection.properties;
|
|
584
|
-
|
|
585
|
-
if (showFavButton !== undefined) {
|
|
586
|
-
const val = extractValue(showFavButton);
|
|
587
|
-
itemProps['show-fav-button'] =
|
|
588
|
-
typeof val === 'boolean' ? val : true;
|
|
589
|
-
}
|
|
590
|
-
if (favButtonPosition !== undefined) {
|
|
591
|
-
const val = extractValue(favButtonPosition);
|
|
592
|
-
itemProps['fav-button-position'] =
|
|
593
|
-
(val as ProductItemProperties['fav-button-position']) ||
|
|
594
|
-
'top-right';
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
setProductItemProperties(itemProps);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Process Pagination section
|
|
602
|
-
const paginationSection = placeholder.sections.find(
|
|
603
|
-
(s: ThemeSection) => s.id === 'pagination-section'
|
|
604
|
-
);
|
|
605
|
-
|
|
606
|
-
if (paginationSection) {
|
|
607
|
-
// Extract styles
|
|
608
|
-
if (paginationSection.styles) {
|
|
609
|
-
const extractedStyles: PaginationStyles = {};
|
|
610
|
-
Object.entries(paginationSection.styles).forEach(
|
|
611
|
-
([key, value]) => {
|
|
612
|
-
const val = extractValue(value);
|
|
613
|
-
if (val !== undefined && val !== null) {
|
|
614
|
-
extractedStyles[key] = String(val);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
);
|
|
618
|
-
setPaginationStyles(extractedStyles);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// Extract properties
|
|
622
|
-
if (paginationSection.properties) {
|
|
623
|
-
const paginationProps: PaginationProperties = {};
|
|
624
|
-
const { type } = paginationSection.properties;
|
|
625
|
-
|
|
626
|
-
if (type !== undefined) {
|
|
627
|
-
const val = extractValue(type);
|
|
628
|
-
paginationProps.type =
|
|
629
|
-
(val as PaginationProperties['type']) || 'list';
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
setPaginationProperties(paginationProps);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
};
|
|
638
|
-
|
|
639
|
-
window.addEventListener('message', handleMessage);
|
|
640
|
-
|
|
641
|
-
return () => {
|
|
642
|
-
window.removeEventListener('message', handleMessage);
|
|
643
|
-
unregisterPlaceholder(PRODUCT_LIST_PLACEHOLDER_ID);
|
|
644
|
-
};
|
|
645
|
-
}, [initialSettings]);
|
|
646
|
-
|
|
647
|
-
const contextValue: ProductListContextValue = {
|
|
648
|
-
isDesigner,
|
|
649
|
-
selectedSectionId,
|
|
650
|
-
filterStyles,
|
|
651
|
-
filterProperties,
|
|
652
|
-
productsProperties,
|
|
653
|
-
productsStyles,
|
|
654
|
-
productItemProperties,
|
|
655
|
-
productItemStyles,
|
|
656
|
-
paginationProperties,
|
|
657
|
-
paginationStyles
|
|
658
|
-
};
|
|
659
|
-
|
|
660
|
-
return (
|
|
661
|
-
<ProductListContext.Provider value={contextValue}>
|
|
662
|
-
{children}
|
|
663
|
-
</ProductListContext.Provider>
|
|
664
|
-
);
|
|
665
|
-
}
|