@akinon/pz-similar-products 1.115.0-rc.23 → 1.116.0-rc.0
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 +35 -32
- package/README.md +202 -0
- package/package.json +1 -1
- package/src/data/endpoints.ts +14 -5
- package/src/hooks/index.ts +0 -1
- package/src/hooks/use-similar-products.ts +148 -23
- package/src/types/index.ts +51 -0
- package/src/utils/index.ts +38 -3
- package/src/views/filters.tsx +27 -3
- package/src/views/header-image-search-feature.tsx +28 -34
- package/src/views/image-search-button.tsx +19 -23
- package/src/views/main.tsx +82 -5
- package/src/views/product-image-search-feature.tsx +22 -22
- package/src/views/search-button.tsx +12 -2
- package/src/views/search-modal.tsx +169 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,71 +1,74 @@
|
|
|
1
1
|
# @akinon/pz-similar-products
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
4
|
-
|
|
5
|
-
## 1.115.0-rc.22
|
|
3
|
+
## 1.116.0-rc.0
|
|
6
4
|
|
|
7
5
|
### Minor Changes
|
|
8
6
|
|
|
9
7
|
- 143be2b9: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
10
8
|
- d99a6a7d: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
11
9
|
|
|
12
|
-
## 1.
|
|
10
|
+
## 1.115.0
|
|
13
11
|
|
|
14
|
-
## 1.
|
|
12
|
+
## 1.92.0-rc.33
|
|
15
13
|
|
|
16
14
|
### Minor Changes
|
|
17
15
|
|
|
18
|
-
-
|
|
19
|
-
- d99a6a7: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
20
|
-
|
|
21
|
-
## 1.113.0-rc.19
|
|
16
|
+
- 59b275c: ZERO-3532: Pass settings prop to SimilarProductsButton for enhanced functionality
|
|
22
17
|
|
|
23
|
-
## 1.
|
|
18
|
+
## 1.92.0-rc.32
|
|
24
19
|
|
|
25
20
|
### Minor Changes
|
|
26
21
|
|
|
27
|
-
-
|
|
28
|
-
- d99a6a7: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
22
|
+
- 54e3179: ZERO-3532: Added customize options to icons
|
|
29
23
|
|
|
30
|
-
## 1.
|
|
24
|
+
## 1.92.0-rc.31
|
|
31
25
|
|
|
32
|
-
|
|
26
|
+
## 1.92.0-rc.30
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
## 1.92.0-rc.29
|
|
29
|
+
|
|
30
|
+
## 1.92.0-rc.28
|
|
36
31
|
|
|
37
|
-
## 1.
|
|
32
|
+
## 1.92.0-rc.27
|
|
38
33
|
|
|
39
34
|
### Minor Changes
|
|
40
35
|
|
|
41
|
-
-
|
|
42
|
-
- d99a6a7: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
36
|
+
- d606f4a: ZERO-3481: Add locale and currency to list endpoint
|
|
43
37
|
|
|
44
|
-
## 1.
|
|
38
|
+
## 1.92.0-rc.26
|
|
45
39
|
|
|
46
|
-
## 1.
|
|
40
|
+
## 1.92.0-rc.25
|
|
47
41
|
|
|
48
|
-
## 1.
|
|
42
|
+
## 1.92.0-rc.24
|
|
49
43
|
|
|
50
|
-
## 1.
|
|
44
|
+
## 1.92.0-rc.23
|
|
45
|
+
|
|
46
|
+
## 1.92.0-rc.22
|
|
51
47
|
|
|
52
48
|
### Minor Changes
|
|
53
49
|
|
|
54
|
-
-
|
|
55
|
-
- d99a6a7d: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
50
|
+
- 143be2b: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
56
51
|
|
|
57
|
-
## 1.
|
|
52
|
+
## 1.92.0-rc.21
|
|
58
53
|
|
|
59
54
|
### Minor Changes
|
|
60
55
|
|
|
61
|
-
-
|
|
62
|
-
|
|
56
|
+
- d99a6a7: ZERO-3457: Fixed the settings prop and made sure everything is customizable.
|
|
57
|
+
|
|
58
|
+
## 1.92.0-rc.20
|
|
59
|
+
|
|
60
|
+
### Minor Changes
|
|
63
61
|
|
|
64
|
-
|
|
62
|
+
- 8b1d24e: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
65
63
|
|
|
66
|
-
## 1.
|
|
64
|
+
## 1.92.0-rc.19
|
|
67
65
|
|
|
68
66
|
### Minor Changes
|
|
69
67
|
|
|
70
|
-
-
|
|
71
|
-
|
|
68
|
+
- d8be48f: ZERO-3422: Update fetch method to use dynamic request method in wallet complete redirection middleware
|
|
69
|
+
|
|
70
|
+
## 1.92.0-rc.18
|
|
71
|
+
|
|
72
|
+
## 1.92.0-rc.17
|
|
73
|
+
|
|
74
|
+
## 1.92.0-rc.16
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- [Features](#markdown-header-features)
|
|
12
12
|
- [Installation](#markdown-header-installation)
|
|
13
|
+
- [Icon Customization](#markdown-header-icon-customization)
|
|
13
14
|
- [Quick Start](#markdown-header-quick-start)
|
|
14
15
|
- [Available Components](#markdown-header-available-components)
|
|
15
16
|
- [Configuration](#markdown-header-configuration)
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
|
|
65
66
|
- **🖼️ Visual Search**: AI-powered image-based product discovery
|
|
66
67
|
- **✂️ Image Cropping**: Built-in cropping functionality with manual confirmation for precise searches
|
|
68
|
+
- **🔤 Text Search**: Search similar products by text description with customizable input
|
|
67
69
|
- **🎛️ Advanced Filtering**: Dynamic facet-based filtering system
|
|
68
70
|
- **📄 Multiple Pagination Modes**: Traditional pagination, load more button, and infinite scroll
|
|
69
71
|
- **🎨 Granular Customization**: 50+ style targets and 30+ render points
|
|
@@ -79,6 +81,92 @@ npx @akinon/projectzero@latest --plugins
|
|
|
79
81
|
|
|
80
82
|
Select `pz-similar-products` from the plugin list during installation.
|
|
81
83
|
|
|
84
|
+
## Icon Customization
|
|
85
|
+
|
|
86
|
+
The plugin provides complete control over icon appearance and behavior through two complementary approaches:
|
|
87
|
+
|
|
88
|
+
### Icon Names (`iconNames`)
|
|
89
|
+
|
|
90
|
+
Change which icons are displayed by specifying different icon names:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
const iconCustomization = {
|
|
94
|
+
iconNames: {
|
|
95
|
+
searchButton: 'magnifier', // Search button (default: 'search')
|
|
96
|
+
modalClose: 'x', // Modal close buttons (default: 'close')
|
|
97
|
+
filter: 'funnel', // Filter button (default: 'filter')
|
|
98
|
+
filterRemove: 'trash', // Filter tag remove buttons (default: 'close')
|
|
99
|
+
modalSearch: 'search-outline', // Modal search button (default: 'search')
|
|
100
|
+
modalSearchClear: 'clear', // Search input clear button (default: 'close')
|
|
101
|
+
imageSearchButton: 'upload' // Image search button (default: 'search')
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Icon Styles (`customStyles`)
|
|
107
|
+
|
|
108
|
+
Customize the visual appearance of icons with CSS classes:
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
const iconStyling = {
|
|
112
|
+
customStyles: {
|
|
113
|
+
searchButtonIcon: 'fill-blue-500 hover:fill-blue-600 transition-colors',
|
|
114
|
+
modalCloseIcon: 'text-red-500 hover:text-red-700 w-4 h-4',
|
|
115
|
+
filterIcon: 'text-purple-500 w-5 h-5',
|
|
116
|
+
filterRemoveIcon: 'text-orange-500 hover:text-orange-700 w-3 h-3',
|
|
117
|
+
imageSearchButtonIcon: 'text-blue-500 hover:text-blue-600 w-5 h-5'
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Complete Icon Customization Example
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
const completeIconSettings = {
|
|
126
|
+
// Change icon names
|
|
127
|
+
iconNames: {
|
|
128
|
+
searchButton: 'search-alt',
|
|
129
|
+
modalClose: 'times',
|
|
130
|
+
filter: 'filter-alt',
|
|
131
|
+
filterRemove: 'remove',
|
|
132
|
+
modalSearch: 'magnifying-glass',
|
|
133
|
+
modalSearchClear: 'clear-alt',
|
|
134
|
+
imageSearchButton: 'upload-cloud'
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
// Style the icons
|
|
138
|
+
customStyles: {
|
|
139
|
+
searchButtonIcon: 'fill-indigo-500 hover:fill-indigo-600 transition-all duration-200',
|
|
140
|
+
modalCloseIcon: 'text-gray-500 hover:text-gray-700 w-5 h-5',
|
|
141
|
+
filterIcon: 'text-blue-500 hover:text-blue-600 w-4 h-4',
|
|
142
|
+
filterRemoveIcon: 'text-red-400 hover:text-red-600 w-3 h-3 transition-colors',
|
|
143
|
+
modalSearchIcon: 'text-green-500 hover:text-green-600',
|
|
144
|
+
modalSearchClearIcon: 'text-gray-400 hover:text-gray-600',
|
|
145
|
+
imageSearchButtonIcon: 'text-indigo-500 hover:text-indigo-600 w-5 h-5'
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Usage
|
|
150
|
+
<PluginModule
|
|
151
|
+
component={Component.ProductImageSearchFeature}
|
|
152
|
+
props={{
|
|
153
|
+
product,
|
|
154
|
+
activeIndex,
|
|
155
|
+
settings: completeIconSettings
|
|
156
|
+
}}
|
|
157
|
+
/>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Available Icon Customization Points
|
|
161
|
+
|
|
162
|
+
- **Search Button** (`searchButton`): Main search button icon in product images
|
|
163
|
+
- **Modal Close** (`modalClose`): Close buttons in modals and filter tags
|
|
164
|
+
- **Filter** (`filter`): Filter toggle button icon
|
|
165
|
+
- **Filter Remove** (`filterRemove`): Remove icons in active filter tags
|
|
166
|
+
- **Modal Search** (`modalSearch`): Search button icon in text search input
|
|
167
|
+
- **Modal Search Clear** (`modalSearchClear`): Clear button icon in text search input
|
|
168
|
+
- **Image Search Button** (`imageSearchButton`): Camera/upload icon in header search feature
|
|
169
|
+
|
|
82
170
|
## Quick Start
|
|
83
171
|
|
|
84
172
|
### Plugin Module Integration
|
|
@@ -167,6 +255,7 @@ interface SimilarProductsSettings {
|
|
|
167
255
|
resultsPerPage?: number; // Products per page (default: 20)
|
|
168
256
|
enableCropping?: boolean; // Enable image cropping (default: true)
|
|
169
257
|
enableFileUpload?: boolean; // Enable file upload (default: true)
|
|
258
|
+
enableTextSearch?: boolean; // Enable text search input (default: false)
|
|
170
259
|
|
|
171
260
|
// Pagination settings
|
|
172
261
|
paginationType?: 'pagination' | 'load-more' | 'infinite-scroll'; // Pagination mode (default: 'pagination')
|
|
@@ -199,6 +288,21 @@ interface SimilarProductsSettings {
|
|
|
199
288
|
itemCount?: string;
|
|
200
289
|
sortDropdown?: string;
|
|
201
290
|
filterToggleButton?: string;
|
|
291
|
+
|
|
292
|
+
// Text search input
|
|
293
|
+
modalSearchInput?: string;
|
|
294
|
+
modalSearchContainer?: string;
|
|
295
|
+
modalSearchButton?: string;
|
|
296
|
+
modalSearchIcon?: string;
|
|
297
|
+
modalSearchClearButton?: string;
|
|
298
|
+
modalSearchClearIcon?: string;
|
|
299
|
+
|
|
300
|
+
// Icon customization
|
|
301
|
+
searchButtonIcon?: string; // Search button icon styling
|
|
302
|
+
modalCloseIcon?: string; // Modal close button icons styling
|
|
303
|
+
filterIcon?: string; // Filter button icon styling
|
|
304
|
+
filterRemoveIcon?: string; // Filter tag remove icons styling
|
|
305
|
+
imageSearchButtonIcon?: string; // Image search button icon styling
|
|
202
306
|
|
|
203
307
|
// Filter sidebar mobile
|
|
204
308
|
filterSidebarMobileHeader?: string;
|
|
@@ -286,6 +390,17 @@ interface SimilarProductsSettings {
|
|
|
286
390
|
cropSelectionHighlight?: string;
|
|
287
391
|
};
|
|
288
392
|
|
|
393
|
+
// Icon name customization
|
|
394
|
+
iconNames?: {
|
|
395
|
+
searchButton?: string; // Search button icon name (default: 'search')
|
|
396
|
+
modalClose?: string; // Modal close button icon name (default: 'close')
|
|
397
|
+
filter?: string; // Filter button icon name (default: 'filter')
|
|
398
|
+
filterRemove?: string; // Filter tag remove icon name (default: 'close')
|
|
399
|
+
modalSearch?: string; // Modal search button icon name (default: 'search')
|
|
400
|
+
modalSearchClear?: string; // Modal search clear button icon name (default: 'close')
|
|
401
|
+
imageSearchButton?: string; // Image search button icon name (default: 'search')
|
|
402
|
+
};
|
|
403
|
+
|
|
289
404
|
// 25+ render functions for granular control
|
|
290
405
|
customRenderers?: {
|
|
291
406
|
// Component-level renderers (full control)
|
|
@@ -304,6 +419,8 @@ interface SimilarProductsSettings {
|
|
|
304
419
|
renderItemCount?: (props) => React.ReactNode;
|
|
305
420
|
renderSortDropdown?: (props) => React.ReactNode;
|
|
306
421
|
renderFilterToggleButton?: (props) => React.ReactNode;
|
|
422
|
+
renderModalSearchInput?: (props) => React.ReactNode;
|
|
423
|
+
renderSearchIcon?: (props) => React.ReactNode;
|
|
307
424
|
// ... see examples for complete list
|
|
308
425
|
};
|
|
309
426
|
filterSidebar?: {
|
|
@@ -341,6 +458,91 @@ interface SimilarProductsSettings {
|
|
|
341
458
|
}
|
|
342
459
|
```
|
|
343
460
|
|
|
461
|
+
## Text Search Integration
|
|
462
|
+
|
|
463
|
+
The plugin features a built-in text search functionality that allows users to search for similar products using descriptive text.
|
|
464
|
+
|
|
465
|
+
### Text Search Features
|
|
466
|
+
|
|
467
|
+
1. **Search Input**: Appears only when API results are available
|
|
468
|
+
2. **Enter Key Support**: Press Enter to trigger search
|
|
469
|
+
3. **Search Icon**: Clickable icon for mobile users
|
|
470
|
+
4. **Clear Button**: X button to clear text and trigger search without text
|
|
471
|
+
5. **Custom Styling**: Fully customizable input, button, and icon
|
|
472
|
+
6. **Custom Icon**: Replaceable search icon via render functions
|
|
473
|
+
|
|
474
|
+
### Basic Text Search Configuration
|
|
475
|
+
|
|
476
|
+
```tsx
|
|
477
|
+
const textSearchSettings = {
|
|
478
|
+
enableTextSearch: true, // Enable text search input
|
|
479
|
+
|
|
480
|
+
customStyles: {
|
|
481
|
+
modalSearchContainer: 'relative flex items-center',
|
|
482
|
+
modalSearchInput: 'h-10 px-4 pr-20 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500',
|
|
483
|
+
modalSearchButton: 'absolute right-2 top-1/2 -translate-y-1/2 p-2 hover:bg-gray-100 rounded-md',
|
|
484
|
+
modalSearchIcon: 'text-gray-500',
|
|
485
|
+
modalSearchClearButton: 'absolute right-12 top-1/2 -translate-y-1/2 p-2 hover:bg-gray-100 rounded-md',
|
|
486
|
+
modalSearchClearIcon: 'text-gray-400 hover:text-gray-600'
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Custom Search Icon
|
|
492
|
+
|
|
493
|
+
```tsx
|
|
494
|
+
const customIconSettings = {
|
|
495
|
+
enableTextSearch: true,
|
|
496
|
+
|
|
497
|
+
customRenderers: {
|
|
498
|
+
render: {
|
|
499
|
+
modal: {
|
|
500
|
+
renderSearchIcon: ({ disabled, onClick }) => (
|
|
501
|
+
<svg
|
|
502
|
+
className="w-5 h-5 text-blue-500 cursor-pointer hover:text-blue-700"
|
|
503
|
+
onClick={onClick}
|
|
504
|
+
fill="none"
|
|
505
|
+
stroke="currentColor"
|
|
506
|
+
viewBox="0 0 24 24"
|
|
507
|
+
>
|
|
508
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
509
|
+
</svg>
|
|
510
|
+
),
|
|
511
|
+
renderModalSearchInput: ({ searchText, setSearchText, isLoading, placeholder, onSearch }) => (
|
|
512
|
+
<div className="relative">
|
|
513
|
+
<input
|
|
514
|
+
type="text"
|
|
515
|
+
value={searchText}
|
|
516
|
+
onChange={(e) => setSearchText(e.target.value)}
|
|
517
|
+
onKeyDown={(e) => e.key === 'Enter' && onSearch && onSearch()}
|
|
518
|
+
placeholder={placeholder}
|
|
519
|
+
className="w-full h-10 px-4 pr-20 border-2 border-blue-300 rounded-lg focus:border-blue-500"
|
|
520
|
+
disabled={isLoading}
|
|
521
|
+
/>
|
|
522
|
+
{searchText && (
|
|
523
|
+
<button
|
|
524
|
+
onClick={() => setSearchText('')}
|
|
525
|
+
disabled={isLoading}
|
|
526
|
+
className="absolute right-12 top-1/2 -translate-y-1/2 p-2 text-gray-400 hover:text-gray-600"
|
|
527
|
+
>
|
|
528
|
+
✕
|
|
529
|
+
</button>
|
|
530
|
+
)}
|
|
531
|
+
<button
|
|
532
|
+
onClick={onSearch}
|
|
533
|
+
disabled={isLoading}
|
|
534
|
+
className="absolute right-2 top-1/2 -translate-y-1/2 p-2 text-blue-500 hover:text-blue-700"
|
|
535
|
+
>
|
|
536
|
+
🔍
|
|
537
|
+
</button>
|
|
538
|
+
</div>
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
```
|
|
545
|
+
|
|
344
546
|
## Image Cropping with Manual Confirmation
|
|
345
547
|
|
|
346
548
|
The plugin features an advanced image cropping system with manual confirmation for precise control over search queries.
|
package/package.json
CHANGED
package/src/data/endpoints.ts
CHANGED
|
@@ -27,9 +27,9 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
27
27
|
endpoints: (build) => ({
|
|
28
28
|
getSimilarProductsByUrl: build.query<
|
|
29
29
|
SimilarProductsResponse,
|
|
30
|
-
{ url: string; limit?: number; excluded_product_ids?: number[] }
|
|
30
|
+
{ url: string; limit?: number; excluded_product_ids?: number[]; text?: string }
|
|
31
31
|
>({
|
|
32
|
-
query: ({ url, limit = 20, excluded_product_ids }) => {
|
|
32
|
+
query: ({ url, limit = 20, excluded_product_ids, text }) => {
|
|
33
33
|
const params = new URLSearchParams();
|
|
34
34
|
params.append('limit', String(limit));
|
|
35
35
|
params.append('url', url);
|
|
@@ -38,6 +38,10 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
38
38
|
params.append('excluded_product_ids', excluded_product_ids.join(','));
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
if (text) {
|
|
42
|
+
params.append('text', text);
|
|
43
|
+
}
|
|
44
|
+
|
|
41
45
|
return {
|
|
42
46
|
url: `/api/similar-products?${params.toString()}`,
|
|
43
47
|
method: 'GET',
|
|
@@ -50,12 +54,17 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
50
54
|
|
|
51
55
|
getSimilarProductsByImage: build.mutation<
|
|
52
56
|
SimilarProductsResponse,
|
|
53
|
-
{ image: string; limit?: number; excluded_product_ids?: number[] }
|
|
57
|
+
{ image: string; limit?: number; excluded_product_ids?: number[]; text?: string }
|
|
54
58
|
>({
|
|
55
|
-
query: ({ image, limit = 20, excluded_product_ids }) => {
|
|
59
|
+
query: ({ image, limit = 20, excluded_product_ids, text }) => {
|
|
56
60
|
const params = new URLSearchParams();
|
|
57
61
|
params.append('limit', String(limit));
|
|
58
62
|
|
|
63
|
+
const bodyData: any = { image, excluded_product_ids };
|
|
64
|
+
if (text) {
|
|
65
|
+
bodyData.text = text;
|
|
66
|
+
}
|
|
67
|
+
|
|
59
68
|
return {
|
|
60
69
|
url: `/api/similar-products?${params.toString()}`,
|
|
61
70
|
method: 'POST',
|
|
@@ -63,7 +72,7 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
63
72
|
'Content-Type': 'application/json',
|
|
64
73
|
Accept: 'application/json'
|
|
65
74
|
},
|
|
66
|
-
body: JSON.stringify(
|
|
75
|
+
body: JSON.stringify(bodyData)
|
|
67
76
|
};
|
|
68
77
|
}
|
|
69
78
|
}),
|
package/src/hooks/index.ts
CHANGED