@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,181 +1,115 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useState } from 'react';
|
|
4
3
|
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
5
|
-
import { setOpenedMenu } from '@akinon/next/redux/reducers/header';
|
|
4
|
+
import { openSearch, setOpenedMenu } from '@akinon/next/redux/reducers/header';
|
|
6
5
|
import clsx from 'clsx';
|
|
7
6
|
import { MenuItemType } from '@akinon/next/types';
|
|
8
7
|
|
|
9
8
|
import { Icon, Link } from '@theme/components';
|
|
10
9
|
import Search from './search';
|
|
10
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
11
11
|
import { Image } from '@akinon/next/components/image';
|
|
12
|
-
import {
|
|
13
|
-
useNavbarMenuSettings,
|
|
14
|
-
NavbarMenuSettings
|
|
15
|
-
} from './use-navbar-menu';
|
|
16
|
-
import { useDesignerFeatures } from '@akinon/next/components/theme-editor/hooks/use-designer-features';
|
|
17
|
-
import {
|
|
18
|
-
NavbarMenuProvider,
|
|
19
|
-
useNavbarMenuDesigner,
|
|
20
|
-
NAVBAR_MENU_PLACEHOLDER_ID,
|
|
21
|
-
NAVBAR_MENU_SECTION_ID,
|
|
22
|
-
NAVBAR_MENU_BLOCK
|
|
23
|
-
} from './navbar-menu-context';
|
|
24
12
|
|
|
25
13
|
interface NavbarProps {
|
|
26
14
|
menu: MenuItemType[];
|
|
27
|
-
initialNavSettings?: NavbarMenuSettings;
|
|
28
15
|
}
|
|
29
16
|
|
|
30
|
-
|
|
31
|
-
menu
|
|
32
|
-
initialNavSettings?: NavbarMenuSettings;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function NavbarContent({ menu, initialNavSettings }: NavbarContentProps) {
|
|
17
|
+
export default function Navbar(props: NavbarProps) {
|
|
18
|
+
const { menu } = props;
|
|
36
19
|
const dispatch = useAppDispatch();
|
|
37
20
|
const { isSearchOpen, openedMenu } = useAppSelector((state) => state.header);
|
|
38
21
|
|
|
39
|
-
const
|
|
40
|
-
const { isDesigner, selectedBlockId } = useNavbarMenuDesigner();
|
|
41
|
-
const [hoveredItemIndex, setHoveredItemIndex] = useState<number | null>(null);
|
|
42
|
-
|
|
43
|
-
const { handleClick } = useDesignerFeatures({
|
|
44
|
-
blockId: NAVBAR_MENU_BLOCK.id,
|
|
45
|
-
placeholderId: NAVBAR_MENU_PLACEHOLDER_ID,
|
|
46
|
-
sectionId: NAVBAR_MENU_SECTION_ID,
|
|
47
|
-
isDesigner,
|
|
48
|
-
blockInfo: {
|
|
49
|
-
id: NAVBAR_MENU_BLOCK.id,
|
|
50
|
-
type: NAVBAR_MENU_BLOCK.type,
|
|
51
|
-
label: NAVBAR_MENU_BLOCK.label
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const isSelected = selectedBlockId === NAVBAR_MENU_BLOCK.id;
|
|
56
|
-
|
|
57
|
-
const getMenuItemStyle = (isHovered: boolean): React.CSSProperties => {
|
|
58
|
-
const baseStyle: React.CSSProperties = {
|
|
59
|
-
fontSize: navSettings.fontSize,
|
|
60
|
-
color: navSettings.color,
|
|
61
|
-
fontWeight: navSettings.fontWeight as React.CSSProperties['fontWeight'],
|
|
62
|
-
textTransform: navSettings.textTransform as React.CSSProperties['textTransform'],
|
|
63
|
-
letterSpacing: navSettings.letterSpacing,
|
|
64
|
-
transition: 'color 0.2s ease'
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
if (isHovered && navSettings.hoverColor) {
|
|
68
|
-
return { ...baseStyle, color: navSettings.hoverColor };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return baseStyle;
|
|
72
|
-
};
|
|
22
|
+
const { t } = useLocalization();
|
|
73
23
|
|
|
74
24
|
return (
|
|
75
25
|
<>
|
|
76
|
-
<nav
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const isItemHovered = hoveredItemIndex === index;
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<li
|
|
94
|
-
key={index}
|
|
95
|
-
className="flex items-center h-full group py-7"
|
|
96
|
-
onMouseEnter={() => {
|
|
97
|
-
dispatch(setOpenedMenu(item.pk));
|
|
98
|
-
setHoveredItemIndex(index);
|
|
99
|
-
}}
|
|
100
|
-
onMouseLeave={() => {
|
|
101
|
-
dispatch(setOpenedMenu(null));
|
|
102
|
-
setHoveredItemIndex(null);
|
|
103
|
-
}}
|
|
104
|
-
>
|
|
105
|
-
<Link
|
|
106
|
-
href={item.url}
|
|
107
|
-
className="flex items-center"
|
|
108
|
-
style={getMenuItemStyle(isItemHovered)}
|
|
109
|
-
data-testid="navbar-category"
|
|
26
|
+
<nav className="relative flex-wrap items-center justify-center hidden header-grid-area-nav sm:flex justify-items-center">
|
|
27
|
+
<ul className="flex flex-wrap items-center justify-center gap-x-8 gap-y-4 mt-8 justify-items-center">
|
|
28
|
+
{menu.map(
|
|
29
|
+
(item, index) =>
|
|
30
|
+
item.label != null && (
|
|
31
|
+
<li
|
|
32
|
+
key={index}
|
|
33
|
+
className="flex items-center h-full group"
|
|
34
|
+
onMouseEnter={() => {
|
|
35
|
+
dispatch(setOpenedMenu(item.pk));
|
|
36
|
+
}}
|
|
37
|
+
onMouseLeave={() => {
|
|
38
|
+
dispatch(setOpenedMenu(null));
|
|
39
|
+
}}
|
|
110
40
|
>
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
41
|
+
<Link
|
|
42
|
+
href={item.url}
|
|
43
|
+
className="flex items-center p-2.5 text-sm uppercase transition hover:text-secondary"
|
|
44
|
+
data-testid="navbar-category"
|
|
45
|
+
>
|
|
46
|
+
{item.label}
|
|
47
|
+
</Link>
|
|
48
|
+
|
|
49
|
+
{/*
|
|
50
|
+
Performance Note:
|
|
51
|
+
The submenu content in this Navbar component is rendered based on hover-triggered state changes.
|
|
52
|
+
This approach is adopted for performance optimization reasons. It ensures that:
|
|
53
|
+
1. Submenu data is only loaded and rendered when necessary, reducing initial load times and resource usage.
|
|
54
|
+
2. Unnecessary renders are avoided, enhancing the responsiveness and efficiency of the navigation bar.
|
|
55
|
+
Please be cautious about altering this logic, as changes could negatively impact the performance and user experience of the Navbar.
|
|
56
|
+
*/}
|
|
57
|
+
|
|
58
|
+
{openedMenu === item.pk && item.children.length > 0 && (
|
|
59
|
+
<div
|
|
116
60
|
className={clsx(
|
|
117
|
-
|
|
61
|
+
[
|
|
62
|
+
'container',
|
|
63
|
+
'absolute',
|
|
64
|
+
'bottom-0',
|
|
65
|
+
'left-0',
|
|
66
|
+
'z-30',
|
|
67
|
+
'flex',
|
|
68
|
+
'justify-between',
|
|
69
|
+
'invisible',
|
|
70
|
+
'opacity-0',
|
|
71
|
+
'bg-gray',
|
|
72
|
+
'border-x-2',
|
|
73
|
+
'border-gray',
|
|
74
|
+
'pt-20',
|
|
75
|
+
'pb-16',
|
|
76
|
+
'transform',
|
|
77
|
+
'translate-y-full',
|
|
78
|
+
'transition'
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
'before:left-0',
|
|
82
|
+
'before:-translate-x-full',
|
|
83
|
+
'before:content-[""]',
|
|
84
|
+
'before:w-1/2',
|
|
85
|
+
'before:h-full',
|
|
86
|
+
'before:block',
|
|
87
|
+
'before:absolute',
|
|
88
|
+
'before:top-0',
|
|
89
|
+
'before:transform',
|
|
90
|
+
'before:bg-gray'
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
'after:right-0',
|
|
94
|
+
'after:translate-x-full',
|
|
95
|
+
'after:content-[""]',
|
|
96
|
+
'after:w-1/2',
|
|
97
|
+
'after:h-full',
|
|
98
|
+
'after:block',
|
|
99
|
+
'after:absolute',
|
|
100
|
+
'after:top-0',
|
|
101
|
+
'after:transform',
|
|
102
|
+
'after:bg-gray'
|
|
103
|
+
],
|
|
118
104
|
{
|
|
119
|
-
'
|
|
105
|
+
'!visible !opacity-100 delay-500':
|
|
106
|
+
openedMenu === item.pk
|
|
120
107
|
}
|
|
121
108
|
)}
|
|
122
|
-
|
|
123
|
-
)}
|
|
124
|
-
</Link>
|
|
125
|
-
|
|
126
|
-
{openedMenu === item.pk && hasChildren && (
|
|
127
|
-
<div
|
|
128
|
-
className={clsx(
|
|
129
|
-
[
|
|
130
|
-
'absolute',
|
|
131
|
-
'bottom-0',
|
|
132
|
-
'left-0',
|
|
133
|
-
'z-30',
|
|
134
|
-
'w-full',
|
|
135
|
-
'invisible',
|
|
136
|
-
'opacity-0',
|
|
137
|
-
'bg-gray',
|
|
138
|
-
'border-x-2',
|
|
139
|
-
'border-gray',
|
|
140
|
-
'pt-20',
|
|
141
|
-
'pb-16',
|
|
142
|
-
'transform',
|
|
143
|
-
'translate-y-full',
|
|
144
|
-
'transition'
|
|
145
|
-
],
|
|
146
|
-
[
|
|
147
|
-
'before:left-0',
|
|
148
|
-
'before:-translate-x-full',
|
|
149
|
-
'before:content-[""]',
|
|
150
|
-
'before:w-1/2',
|
|
151
|
-
'before:h-full',
|
|
152
|
-
'before:block',
|
|
153
|
-
'before:absolute',
|
|
154
|
-
'before:top-0',
|
|
155
|
-
'before:transform',
|
|
156
|
-
'before:bg-gray'
|
|
157
|
-
],
|
|
158
|
-
[
|
|
159
|
-
'after:right-0',
|
|
160
|
-
'after:translate-x-full',
|
|
161
|
-
'after:content-[""]',
|
|
162
|
-
'after:w-1/2',
|
|
163
|
-
'after:h-full',
|
|
164
|
-
'after:block',
|
|
165
|
-
'after:absolute',
|
|
166
|
-
'after:top-0',
|
|
167
|
-
'after:transform',
|
|
168
|
-
'after:bg-gray'
|
|
169
|
-
],
|
|
170
|
-
{
|
|
171
|
-
'!visible !opacity-100 delay-500': openedMenu === item.pk
|
|
172
|
-
}
|
|
173
|
-
)}
|
|
174
|
-
>
|
|
175
|
-
<div className="container mx-auto flex justify-between">
|
|
109
|
+
>
|
|
176
110
|
<div className="flex space-x-8 lg:space-x-0">
|
|
177
|
-
{item.children
|
|
178
|
-
<div key={
|
|
111
|
+
{item.children.map((child, index) => (
|
|
112
|
+
<div key={index}>
|
|
179
113
|
<Link
|
|
180
114
|
onClick={() => {
|
|
181
115
|
dispatch(setOpenedMenu(null));
|
|
@@ -185,10 +119,10 @@ function NavbarContent({ menu, initialNavSettings }: NavbarContentProps) {
|
|
|
185
119
|
>
|
|
186
120
|
{child.label}
|
|
187
121
|
</Link>
|
|
188
|
-
{child.children &&
|
|
122
|
+
{child.children && (
|
|
189
123
|
<ul>
|
|
190
|
-
{child.children
|
|
191
|
-
<li key={
|
|
124
|
+
{child.children.map((grandChild, index) => (
|
|
125
|
+
<li key={index}>
|
|
192
126
|
<Link
|
|
193
127
|
onClick={() => {
|
|
194
128
|
dispatch(setOpenedMenu(null));
|
|
@@ -205,24 +139,25 @@ function NavbarContent({ menu, initialNavSettings }: NavbarContentProps) {
|
|
|
205
139
|
</div>
|
|
206
140
|
))}
|
|
207
141
|
</div>
|
|
208
|
-
{item.extra_context
|
|
142
|
+
{item.extra_context.attributes.images && (
|
|
209
143
|
<div className="flex">
|
|
210
144
|
{item.extra_context.attributes.images.map(
|
|
211
|
-
(image,
|
|
212
|
-
image.kwargs
|
|
213
|
-
<Link href={image.value
|
|
145
|
+
(image, index) =>
|
|
146
|
+
image.kwargs.value.image && (
|
|
147
|
+
<Link href={image.value.url} key={index}>
|
|
148
|
+
{/* TODO: There is no image. It should be checked. May need fix. */}
|
|
214
149
|
<Image
|
|
215
150
|
src={image.kwargs.value.image?.url}
|
|
216
|
-
alt={image.value
|
|
217
|
-
title={image.value
|
|
151
|
+
alt={image.value.title}
|
|
152
|
+
title={image.value.title}
|
|
218
153
|
width={265}
|
|
219
154
|
height={323}
|
|
220
155
|
/>
|
|
221
156
|
<span className="block mt-4">
|
|
222
|
-
{image.value
|
|
157
|
+
{image.value.title}
|
|
223
158
|
</span>
|
|
224
159
|
<span className="inline-block mt-2 text-xs uppercase border-b border-gray-500">
|
|
225
|
-
{image.value
|
|
160
|
+
{image.value.link_text}
|
|
226
161
|
</span>
|
|
227
162
|
</Link>
|
|
228
163
|
)
|
|
@@ -230,24 +165,22 @@ function NavbarContent({ menu, initialNavSettings }: NavbarContentProps) {
|
|
|
230
165
|
</div>
|
|
231
166
|
)}
|
|
232
167
|
</div>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
168
|
+
)}
|
|
169
|
+
</li>
|
|
170
|
+
)
|
|
171
|
+
)}
|
|
172
|
+
<li>
|
|
173
|
+
<button
|
|
174
|
+
onClick={() => dispatch(openSearch())}
|
|
175
|
+
className="flex items-center gap-2 p-2 text-sm uppercase transition hover:text-secondary cursor-pointer"
|
|
176
|
+
data-testid="header-nav-search"
|
|
177
|
+
>
|
|
178
|
+
<Icon name="search" size={24} /> {t('common.navbar.search')}
|
|
179
|
+
</button>
|
|
180
|
+
</li>
|
|
238
181
|
</ul>
|
|
239
182
|
</nav>
|
|
240
183
|
{isSearchOpen && <Search />}
|
|
241
184
|
</>
|
|
242
185
|
);
|
|
243
186
|
}
|
|
244
|
-
|
|
245
|
-
export default function Navbar({ menu, initialNavSettings }: NavbarProps) {
|
|
246
|
-
return (
|
|
247
|
-
<NavbarMenuProvider>
|
|
248
|
-
<NavbarContent menu={menu} initialNavSettings={initialNavSettings} />
|
|
249
|
-
</NavbarMenuProvider>
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export type { NavbarMenuSettings };
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useEffect,
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
5
5
|
import { closeSearch } from '@akinon/next/redux/reducers/header';
|
|
6
6
|
import clsx from 'clsx';
|
|
7
7
|
|
|
8
8
|
import { Icon } from '@theme/components';
|
|
9
|
-
import { SearchInput } from './search-input';
|
|
10
9
|
import Results from './results';
|
|
11
10
|
import { ROUTES } from '@theme/routes';
|
|
12
|
-
import {
|
|
13
|
-
import { useAutocompleteQuery } from '@akinon/next/data/client/misc';
|
|
11
|
+
import { useLocalization, useRouter } from '@akinon/next/hooks';
|
|
14
12
|
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
|
|
15
13
|
|
|
16
|
-
const MINIMUM_SEARCH_LENGTH = 3;
|
|
17
|
-
|
|
18
14
|
export default function Search() {
|
|
19
15
|
const { t } = useLocalization();
|
|
20
16
|
const router = useRouter();
|
|
@@ -23,24 +19,6 @@ export default function Search() {
|
|
|
23
19
|
const [searchText, setSearchText] = useState('');
|
|
24
20
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
25
21
|
|
|
26
|
-
const debouncedSearchText = useDebounce(searchText, 400);
|
|
27
|
-
const { currentData } = useAutocompleteQuery(debouncedSearchText, {
|
|
28
|
-
refetchOnMountOrArgChange: true,
|
|
29
|
-
skip: debouncedSearchText.length < MINIMUM_SEARCH_LENGTH
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const categoryLabel = useMemo(() => {
|
|
33
|
-
const firstCategory = currentData?.groups.find(
|
|
34
|
-
(group) => group.suggestion_type === 'Category'
|
|
35
|
-
)?.entries?.[0];
|
|
36
|
-
|
|
37
|
-
if (firstCategory?.label) {
|
|
38
|
-
return firstCategory.label;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return t('common.search.all_products');
|
|
42
|
-
}, [currentData, t]);
|
|
43
|
-
|
|
44
22
|
useEffect(() => {
|
|
45
23
|
if (isSearchOpen) {
|
|
46
24
|
inputRef.current?.focus();
|
|
@@ -64,19 +42,11 @@ export default function Search() {
|
|
|
64
42
|
};
|
|
65
43
|
}, [isSearchOpen, dispatch]);
|
|
66
44
|
|
|
67
|
-
const handleSearch = () => {
|
|
68
|
-
if (searchText.trim() !== '') {
|
|
69
|
-
router.push(
|
|
70
|
-
`${ROUTES.LIST}/?search_text=${encodeURIComponent(searchText)}`
|
|
71
|
-
);
|
|
72
|
-
dispatch(closeSearch());
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
45
|
return (
|
|
77
46
|
<>
|
|
78
47
|
<div
|
|
79
48
|
className={clsx(
|
|
49
|
+
// 177px is the height of the header
|
|
80
50
|
'absolute bg-black opacity-75 w-screen h-screen transition duration-500 left-0 bottom-0 translate-y-full z-30',
|
|
81
51
|
isSearchOpen && searchText
|
|
82
52
|
? 'visible opacity-100'
|
|
@@ -85,53 +55,44 @@ export default function Search() {
|
|
|
85
55
|
role="button"
|
|
86
56
|
onClick={() => dispatch(closeSearch())}
|
|
87
57
|
/>
|
|
88
|
-
|
|
89
58
|
<div
|
|
90
59
|
className={clsx(
|
|
91
|
-
'
|
|
92
|
-
'overflow-auto h-screen lg:max-h-[calc(100vh-177px)] bg-white p-6 z-40 transition duration-500',
|
|
60
|
+
'absolute overflow-auto max-h-screen md:max-h-[calc(100vh-177px)] bg-white p-6 left-0 lg:bottom-0 lg:translate-y-full z-40 w-screen transition duration-500',
|
|
93
61
|
isSearchOpen ? 'visible opacity-100' : 'invisible opacity-0'
|
|
94
62
|
)}
|
|
95
63
|
>
|
|
96
|
-
<
|
|
97
|
-
className="
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<div className="max-w-screen-2xl mx-auto flex flex-col gap-12 pt-8 lg:pt-0">
|
|
105
|
-
<div className="flex flex-col items-center gap-8">
|
|
106
|
-
<h1 className="text-2xl text-black-750 font-normal text-center">
|
|
107
|
-
{t('common.search.results_title') || 'Search results'}
|
|
108
|
-
</h1>
|
|
109
|
-
|
|
110
|
-
<div className="w-full max-w-[468px]">
|
|
111
|
-
<SearchInput
|
|
112
|
-
startAdornment={
|
|
113
|
-
<PluginModule
|
|
114
|
-
component={Component.HeaderImageSearchFeature}
|
|
115
|
-
props={{
|
|
116
|
-
enableTextSearch: true,
|
|
117
|
-
isEnabled: false,
|
|
118
|
-
settings: {
|
|
119
|
-
iconNames: {
|
|
120
|
-
imageSearchButton: 'hamburger'
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}}
|
|
124
|
-
/>
|
|
125
|
-
}
|
|
126
|
-
ref={inputRef}
|
|
127
|
-
label={categoryLabel}
|
|
64
|
+
<div className="max-w-screen-2xl mx-auto flex flex-col gap-12">
|
|
65
|
+
<div className="border-b border-gray-400 flex flex-col py-1.5 gap-2 self-center items-center md:flex-row">
|
|
66
|
+
<span className="text-xl lg:text-2xl">
|
|
67
|
+
{t('common.search.results_for')}
|
|
68
|
+
</span>
|
|
69
|
+
<div className="flex items-center">
|
|
70
|
+
<input
|
|
128
71
|
value={searchText}
|
|
129
72
|
onChange={(e) => setSearchText(e.target.value)}
|
|
130
73
|
onKeyDown={(e) => {
|
|
131
|
-
if (e.key === 'Enter'
|
|
74
|
+
if (e.key === 'Enter' && searchText.trim() !== '') {
|
|
75
|
+
router.push(`${ROUTES.LIST}/?search_text=${searchText}`);
|
|
76
|
+
}
|
|
132
77
|
}}
|
|
133
|
-
|
|
134
|
-
placeholder={t('common.search.placeholder')
|
|
78
|
+
className="border-0 text-2xl outline-none text-secondary placeholder:text-xl placeholder:lg:text-2xl"
|
|
79
|
+
placeholder={t('common.search.placeholder')}
|
|
80
|
+
ref={inputRef}
|
|
81
|
+
/>
|
|
82
|
+
|
|
83
|
+
<PluginModule
|
|
84
|
+
component={Component.HeaderImageSearchFeature}
|
|
85
|
+
props={{
|
|
86
|
+
enableTextSearch: true,
|
|
87
|
+
isEnabled: true
|
|
88
|
+
}}
|
|
89
|
+
/>
|
|
90
|
+
|
|
91
|
+
<Icon
|
|
92
|
+
name="close"
|
|
93
|
+
size={14}
|
|
94
|
+
onClick={() => dispatch(closeSearch())}
|
|
95
|
+
className="cursor-pointer"
|
|
135
96
|
/>
|
|
136
97
|
</div>
|
|
137
98
|
</div>
|