spoko-design-system 1.3.1 → 1.3.3
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/package.json +1 -1
- package/src/components/ProductDetailsList.vue +35 -147
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [1.3.3](https://github.com/polo-blue/sds/compare/v1.3.2...v1.3.3) (2025-10-07)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* prevent double rendering of links array with slot fallback ([ac7ec23](https://github.com/polo-blue/sds/commit/ac7ec2349b2098912ed27a303a7502c9a1c63678))
|
|
6
|
+
|
|
7
|
+
## [1.3.2](https://github.com/polo-blue/sds/compare/v1.3.1...v1.3.2) (2025-10-07)
|
|
8
|
+
|
|
1
9
|
## [1.3.1](https://github.com/polo-blue/sds/compare/v1.3.0...v1.3.1) (2025-10-05)
|
|
2
10
|
|
|
3
11
|
## [1.3.0](https://github.com/polo-blue/sds/compare/v1.2.2...v1.3.0) (2025-10-05)
|
package/package.json
CHANGED
|
@@ -2,30 +2,18 @@
|
|
|
2
2
|
import { PropType, computed } from 'vue';
|
|
3
3
|
import ProductDetailName from './ProductDetailName.vue';
|
|
4
4
|
|
|
5
|
-
interface
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
interface Link {
|
|
6
|
+
type: string;
|
|
7
|
+
url: string;
|
|
8
|
+
anchor: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
interface TableItem {
|
|
11
12
|
id: string;
|
|
12
|
-
|
|
13
|
-
value: unknown; //
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
isArrayValue?: boolean;
|
|
17
|
-
isColorArray?: boolean; // dla product.colors (color_ids)
|
|
18
|
-
isPaintMarks?: boolean; // dla product.paint_marks_text
|
|
19
|
-
isGenericArray?: boolean; // dla ogólnych tablic stringów (np. position)
|
|
20
|
-
isForExteriorColour?: boolean; // Ta flaga będzie ustawiana przez getProductDetails na true, jeśli 'value' jest tablicą
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface GroupedLink {
|
|
24
|
-
id: string;
|
|
25
|
-
links: {
|
|
26
|
-
name: string;
|
|
27
|
-
value: string;
|
|
28
|
-
}[];
|
|
13
|
+
label: string; // Display name from API
|
|
14
|
+
value: unknown; // Can be string, number, boolean, string array, or Link array
|
|
15
|
+
type?: string; // 'links' for link arrays
|
|
16
|
+
isGenericArray?: boolean; // for generic string arrays (e.g., position)
|
|
29
17
|
}
|
|
30
18
|
|
|
31
19
|
const props = defineProps({
|
|
@@ -33,21 +21,9 @@ const props = defineProps({
|
|
|
33
21
|
caption: { type: String, default: null },
|
|
34
22
|
});
|
|
35
23
|
|
|
36
|
-
// Function to check if a
|
|
37
|
-
const
|
|
38
|
-
return
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// Function to check if it's a color array (for 'color_ids' field from product.colors)
|
|
42
|
-
// This will still apply to the 'color' detail if its value is an array of ColorCode objects
|
|
43
|
-
const isColorArray = (item: TableItem) => {
|
|
44
|
-
const colorIds = ['color', 'thread-color']; // lista ID które są kolorami
|
|
45
|
-
return (item.isColorArray || colorIds.includes(item.id)) && Array.isArray(item.value);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// Function to check if it's paint marks (value is now a string from API)
|
|
49
|
-
const isPaintMarks = (item: TableItem) => {
|
|
50
|
-
return item.isPaintMarks && typeof item.value === 'string';
|
|
24
|
+
// Function to check if it's a links array from new API
|
|
25
|
+
const isLinksArray = (item: TableItem) => {
|
|
26
|
+
return item.type === 'links' && Array.isArray(item.value);
|
|
51
27
|
};
|
|
52
28
|
|
|
53
29
|
// Function to check if it's a generic array (e.g., for position)
|
|
@@ -55,33 +31,23 @@ const isGenericArray = (item: TableItem) => {
|
|
|
55
31
|
return item.isGenericArray && Array.isArray(item.value);
|
|
56
32
|
};
|
|
57
33
|
|
|
58
|
-
// ✅ Zaktualizowana funkcja: Sprawdzamy ID i czy value jest faktycznie tablicą ColorCode[]
|
|
59
|
-
const isForExteriorColour = (item: TableItem) => {
|
|
60
|
-
return item.id === 'for-exterior-colour' && Array.isArray(item.value);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
34
|
// Function to check if value is HTML string (fallback)
|
|
64
35
|
const isHtmlValue = (value: unknown): boolean => {
|
|
65
36
|
return typeof value === 'string' && (value.includes('<span') || value.includes('<br>'));
|
|
66
37
|
};
|
|
67
38
|
|
|
68
39
|
// Function for specifying header text
|
|
69
|
-
const getHeaderText = (row: TableItem
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return 'name' in row
|
|
75
|
-
? row.name
|
|
76
|
-
: row.id
|
|
77
|
-
.split('-')
|
|
78
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
79
|
-
.join(' ');
|
|
40
|
+
const getHeaderText = (row: TableItem) => {
|
|
41
|
+
return row.label || row.id
|
|
42
|
+
.split('-')
|
|
43
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
44
|
+
.join(' ');
|
|
80
45
|
};
|
|
81
46
|
|
|
82
47
|
// Function to determine the icon class for a link type
|
|
83
|
-
const getLinkIconClass = (
|
|
84
|
-
|
|
48
|
+
const getLinkIconClass = (linkType: string) => {
|
|
49
|
+
const type = linkType.toLowerCase();
|
|
50
|
+
switch (type) {
|
|
85
51
|
case 'blog':
|
|
86
52
|
return 'i-lucide-book-text';
|
|
87
53
|
case 'youtube':
|
|
@@ -93,46 +59,13 @@ const getLinkIconClass = (linkId: string) => {
|
|
|
93
59
|
}
|
|
94
60
|
};
|
|
95
61
|
|
|
96
|
-
//
|
|
97
|
-
const
|
|
98
|
-
// ✅ Add validation to ensure props.items is an array
|
|
62
|
+
// Validate items
|
|
63
|
+
const validatedItems = computed(() => {
|
|
99
64
|
if (!Array.isArray(props.items)) {
|
|
100
65
|
console.warn('ProductDetailsList: items prop is not an array:', props.items);
|
|
101
66
|
return [];
|
|
102
67
|
}
|
|
103
|
-
|
|
104
|
-
const result: (TableItem | GroupedLink)[] = [];
|
|
105
|
-
const linkGroups = new Map<string, GroupedLink>();
|
|
106
|
-
|
|
107
|
-
// Process all elements
|
|
108
|
-
for (const item of props.items) {
|
|
109
|
-
// If it's a link (blog, youtube, vimeo)
|
|
110
|
-
if (isLink(item.id)) {
|
|
111
|
-
// Add a link to the relevant group
|
|
112
|
-
if (!linkGroups.has(item.id)) {
|
|
113
|
-
linkGroups.set(item.id, {
|
|
114
|
-
id: item.id,
|
|
115
|
-
links: [],
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Add link to the relevant group
|
|
120
|
-
linkGroups.get(item.id)?.links.push({
|
|
121
|
-
name: item.name,
|
|
122
|
-
value: item.value as string,
|
|
123
|
-
});
|
|
124
|
-
} else {
|
|
125
|
-
// If it's not a link, add it normally to the results
|
|
126
|
-
result.push(item);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Add all link groups at the end
|
|
131
|
-
for (const group of linkGroups.values()) {
|
|
132
|
-
result.push(group);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return result;
|
|
68
|
+
return props.items;
|
|
136
69
|
});
|
|
137
70
|
</script>
|
|
138
71
|
|
|
@@ -149,7 +82,7 @@ const groupedItems = computed(() => {
|
|
|
149
82
|
</colgroup>
|
|
150
83
|
<tbody>
|
|
151
84
|
<tr
|
|
152
|
-
v-for="(row, index) in
|
|
85
|
+
v-for="(row, index) in validatedItems"
|
|
153
86
|
:key="index"
|
|
154
87
|
class="details-table-row"
|
|
155
88
|
>
|
|
@@ -159,85 +92,38 @@ const groupedItems = computed(() => {
|
|
|
159
92
|
class="details-table-header"
|
|
160
93
|
/>
|
|
161
94
|
|
|
95
|
+
<!-- Links Array -->
|
|
162
96
|
<td
|
|
163
|
-
v-if="
|
|
97
|
+
v-if="isLinksArray(row)"
|
|
164
98
|
class="details-table-cell"
|
|
165
99
|
>
|
|
166
100
|
<ul class="list-none p-0 m-0">
|
|
167
101
|
<li
|
|
168
|
-
v-for="(link, linkIndex) in row.
|
|
102
|
+
v-for="(link, linkIndex) in row.value as Link[]"
|
|
169
103
|
:key="linkIndex"
|
|
170
104
|
class="mb-2 last:mb-0 flex items-center"
|
|
171
105
|
>
|
|
172
106
|
<span
|
|
173
107
|
:class="[
|
|
174
|
-
getLinkIconClass(
|
|
108
|
+
getLinkIconClass(link.type),
|
|
175
109
|
'leading-none inline-block mr-2 w-4 min-w-4 h-4 text-gray-400',
|
|
176
110
|
]"
|
|
177
111
|
/>
|
|
178
112
|
<a
|
|
179
|
-
:href="link.
|
|
113
|
+
:href="link.url"
|
|
180
114
|
target="_blank"
|
|
181
115
|
rel="noopener noreferrer"
|
|
182
116
|
class="link-primary"
|
|
183
117
|
>
|
|
184
|
-
{{ link.
|
|
118
|
+
{{ link.anchor }}
|
|
185
119
|
</a>
|
|
186
120
|
</li>
|
|
187
121
|
</ul>
|
|
188
122
|
</td>
|
|
189
123
|
|
|
124
|
+
<!-- Generic String Array -->
|
|
190
125
|
<td
|
|
191
|
-
v-else-if="
|
|
192
|
-
class="details-table-cell"
|
|
193
|
-
>
|
|
194
|
-
<ul class="list-none p-0 m-0">
|
|
195
|
-
<li
|
|
196
|
-
v-for="(colorItem, colorIndex) in row.value as ColorCode[]"
|
|
197
|
-
:key="colorIndex"
|
|
198
|
-
class="flex items-center gap-1 mb-1 last:mb-0"
|
|
199
|
-
>
|
|
200
|
-
<template v-if="colorItem.code">
|
|
201
|
-
<code class="font-mono text-sm">
|
|
202
|
-
{{ colorItem.code }}
|
|
203
|
-
</code>
|
|
204
|
-
<span class="text-gray-400">-</span>
|
|
205
|
-
</template>
|
|
206
|
-
<span class="text-gray-700 dark:text-gray-300">{{ colorItem.name }}</span>
|
|
207
|
-
</li>
|
|
208
|
-
</ul>
|
|
209
|
-
</td>
|
|
210
|
-
|
|
211
|
-
<td
|
|
212
|
-
v-else-if="'id' in row && isPaintMarks(row)"
|
|
213
|
-
class="details-table-cell"
|
|
214
|
-
>
|
|
215
|
-
<span class="text-gray-700 dark:text-gray-300">{{ row.value }}</span>
|
|
216
|
-
</td>
|
|
217
|
-
|
|
218
|
-
<td
|
|
219
|
-
v-else-if="'id' in row && isForExteriorColour(row)"
|
|
220
|
-
class="details-table-cell"
|
|
221
|
-
>
|
|
222
|
-
<ul class="list-none p-0 m-0">
|
|
223
|
-
<li
|
|
224
|
-
v-for="(colorEntry, colourIndex) in row.value as ColorCode[]"
|
|
225
|
-
:key="colourIndex"
|
|
226
|
-
class="flex items-center gap-1 mb-1 last:mb-0"
|
|
227
|
-
>
|
|
228
|
-
<template v-if="colorEntry.code">
|
|
229
|
-
<code class="font-mono text-sm">
|
|
230
|
-
{{ colorEntry.code }}
|
|
231
|
-
</code>
|
|
232
|
-
<span class="text-gray-400">-</span>
|
|
233
|
-
</template>
|
|
234
|
-
<span class="text-gray-700 dark:text-gray-300">{{ colorEntry.name }}</span>
|
|
235
|
-
</li>
|
|
236
|
-
</ul>
|
|
237
|
-
</td>
|
|
238
|
-
|
|
239
|
-
<td
|
|
240
|
-
v-else-if="'id' in row && isGenericArray(row)"
|
|
126
|
+
v-else-if="isGenericArray(row)"
|
|
241
127
|
class="details-table-cell"
|
|
242
128
|
>
|
|
243
129
|
<ul class="list-none p-0 m-0">
|
|
@@ -252,14 +138,16 @@ const groupedItems = computed(() => {
|
|
|
252
138
|
</ul>
|
|
253
139
|
</td>
|
|
254
140
|
|
|
141
|
+
<!-- HTML Value -->
|
|
255
142
|
<td
|
|
256
|
-
v-else-if="
|
|
143
|
+
v-else-if="isHtmlValue(row.value)"
|
|
257
144
|
class="details-table-cell"
|
|
258
145
|
v-html="row.value"
|
|
259
146
|
/>
|
|
260
147
|
|
|
148
|
+
<!-- Slot or Default Value -->
|
|
261
149
|
<slot
|
|
262
|
-
v-else
|
|
150
|
+
v-else
|
|
263
151
|
:name="row.id"
|
|
264
152
|
>
|
|
265
153
|
<td class="details-table-cell">
|