spoko-design-system 1.3.1 → 1.3.2
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 +2 -0
- package/package.json +1 -1
- package/src/components/ProductDetailsList.vue +30 -147
package/CHANGELOG.md
CHANGED
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
|
>
|
|
@@ -160,84 +93,35 @@ const groupedItems = computed(() => {
|
|
|
160
93
|
/>
|
|
161
94
|
|
|
162
95
|
<td
|
|
163
|
-
v-if="
|
|
96
|
+
v-if="isLinksArray(row)"
|
|
164
97
|
class="details-table-cell"
|
|
165
98
|
>
|
|
166
99
|
<ul class="list-none p-0 m-0">
|
|
167
100
|
<li
|
|
168
|
-
v-for="(link, linkIndex) in row.
|
|
101
|
+
v-for="(link, linkIndex) in row.value as Link[]"
|
|
169
102
|
:key="linkIndex"
|
|
170
103
|
class="mb-2 last:mb-0 flex items-center"
|
|
171
104
|
>
|
|
172
105
|
<span
|
|
173
106
|
:class="[
|
|
174
|
-
getLinkIconClass(
|
|
107
|
+
getLinkIconClass(link.type),
|
|
175
108
|
'leading-none inline-block mr-2 w-4 min-w-4 h-4 text-gray-400',
|
|
176
109
|
]"
|
|
177
110
|
/>
|
|
178
111
|
<a
|
|
179
|
-
:href="link.
|
|
112
|
+
:href="link.url"
|
|
180
113
|
target="_blank"
|
|
181
114
|
rel="noopener noreferrer"
|
|
182
115
|
class="link-primary"
|
|
183
116
|
>
|
|
184
|
-
{{ link.
|
|
117
|
+
{{ link.anchor }}
|
|
185
118
|
</a>
|
|
186
119
|
</li>
|
|
187
120
|
</ul>
|
|
188
121
|
</td>
|
|
189
122
|
|
|
190
123
|
<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)"
|
|
124
|
+
v-else-if="isGenericArray(row)"
|
|
241
125
|
class="details-table-cell"
|
|
242
126
|
>
|
|
243
127
|
<ul class="list-none p-0 m-0">
|
|
@@ -253,13 +137,12 @@ const groupedItems = computed(() => {
|
|
|
253
137
|
</td>
|
|
254
138
|
|
|
255
139
|
<td
|
|
256
|
-
v-else-if="
|
|
140
|
+
v-else-if="isHtmlValue(row.value)"
|
|
257
141
|
class="details-table-cell"
|
|
258
142
|
v-html="row.value"
|
|
259
143
|
/>
|
|
260
144
|
|
|
261
145
|
<slot
|
|
262
|
-
v-else-if="'id' in row"
|
|
263
146
|
:name="row.id"
|
|
264
147
|
>
|
|
265
148
|
<td class="details-table-cell">
|