spoko-design-system 0.8.2 → 0.8.4
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spoko-design-system",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./index.ts",
|
|
6
6
|
"module": "./index.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"spoko design system"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@algolia/client-search": "^5.
|
|
43
|
+
"@algolia/client-search": "^5.30.0",
|
|
44
44
|
"@astrojs/mdx": "^4.3.0",
|
|
45
45
|
"@astrojs/node": "^9.2.2",
|
|
46
46
|
"@astrojs/sitemap": "^3.4.1",
|
|
@@ -57,57 +57,57 @@
|
|
|
57
57
|
"@iconify-json/eos-icons": "^1.2.2",
|
|
58
58
|
"@iconify-json/et": "^1.2.1",
|
|
59
59
|
"@iconify-json/flowbite": "^1.2.5",
|
|
60
|
-
"@iconify-json/fluent": "^1.2.
|
|
60
|
+
"@iconify-json/fluent": "^1.2.26",
|
|
61
61
|
"@iconify-json/fluent-emoji": "1.2.3",
|
|
62
62
|
"@iconify-json/ic": "^1.2.2",
|
|
63
63
|
"@iconify-json/icon-park-outline": "^1.2.2",
|
|
64
64
|
"@iconify-json/la": "^1.2.1",
|
|
65
|
-
"@iconify-json/material-symbols-light": "^1.2.
|
|
65
|
+
"@iconify-json/material-symbols-light": "^1.2.28",
|
|
66
66
|
"@iconify-json/mdi": "^1.2.3",
|
|
67
67
|
"@iconify-json/noto-v1": "^1.2.2",
|
|
68
|
-
"@iconify-json/octicon": "^1.2.
|
|
68
|
+
"@iconify-json/octicon": "^1.2.7",
|
|
69
69
|
"@iconify-json/ph": "^1.2.2",
|
|
70
|
-
"@iconify-json/simple-icons": "^1.2.
|
|
70
|
+
"@iconify-json/simple-icons": "^1.2.41",
|
|
71
71
|
"@iconify-json/system-uicons": "^1.2.2",
|
|
72
72
|
"@iconify-json/uil": "^1.2.3",
|
|
73
|
-
"@iconify/json": "^2.2.
|
|
73
|
+
"@iconify/json": "^2.2.354",
|
|
74
74
|
"@iconify/vue": "^5.0.0",
|
|
75
75
|
"@playform/compress": "^0.2.0",
|
|
76
76
|
"@playform/inline": "^0.1.2",
|
|
77
|
-
"@unocss/astro": "66.2
|
|
78
|
-
"@unocss/preset-attributify": "66.2
|
|
79
|
-
"@unocss/preset-typography": "66.2
|
|
80
|
-
"@unocss/preset-uno": "66.2
|
|
81
|
-
"@unocss/preset-web-fonts": "66.2
|
|
82
|
-
"@unocss/preset-wind": "66.2
|
|
83
|
-
"@unocss/reset": "66.2
|
|
77
|
+
"@unocss/astro": "66.3.2",
|
|
78
|
+
"@unocss/preset-attributify": "66.3.2",
|
|
79
|
+
"@unocss/preset-typography": "66.3.2",
|
|
80
|
+
"@unocss/preset-uno": "66.3.2",
|
|
81
|
+
"@unocss/preset-web-fonts": "66.3.2",
|
|
82
|
+
"@unocss/preset-wind": "66.3.2",
|
|
83
|
+
"@unocss/reset": "66.3.2",
|
|
84
84
|
"@vite-pwa/astro": "^1.1.0",
|
|
85
|
-
"@vueuse/core": "^13.
|
|
85
|
+
"@vueuse/core": "^13.5.0",
|
|
86
86
|
"astro-i18next": "1.0.0-beta.21",
|
|
87
87
|
"astro-icon": "^1.1.5",
|
|
88
88
|
"astro-meta-tags": "^0.3.2",
|
|
89
89
|
"astro-navbar": "^2.4.0",
|
|
90
90
|
"astro-pagefind": "^1.8.3",
|
|
91
91
|
"astro-remote": "^0.3.4",
|
|
92
|
-
"dotenv": "^
|
|
93
|
-
"i18next": "^25.
|
|
92
|
+
"dotenv": "^17.0.1",
|
|
93
|
+
"i18next": "^25.3.0",
|
|
94
94
|
"i18next-browser-languagedetector": "^8.2.0",
|
|
95
95
|
"i18next-fs-backend": "^2.6.0",
|
|
96
96
|
"i18next-http-backend": "^3.0.2",
|
|
97
97
|
"i18next-vue": "^5.3.0",
|
|
98
|
-
"swiper": "^11.2.
|
|
99
|
-
"unocss": "66.2
|
|
98
|
+
"swiper": "^11.2.10",
|
|
99
|
+
"unocss": "66.3.2",
|
|
100
100
|
"vue": "^3.5.17"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
103
|
"@types/gtag.js": "^0.0.20",
|
|
104
|
-
"@types/node": "^24.0.
|
|
105
|
-
"@unocss/transformer-variant-group": "66.2
|
|
106
|
-
"@vitejs/plugin-vue": "^
|
|
104
|
+
"@types/node": "^24.0.10",
|
|
105
|
+
"@unocss/transformer-variant-group": "66.3.2",
|
|
106
|
+
"@vitejs/plugin-vue": "^6.0.0",
|
|
107
107
|
"@vue/compiler-sfc": "^3.5.17",
|
|
108
|
-
"astro": "^5.10.
|
|
108
|
+
"astro": "^5.10.2",
|
|
109
109
|
"unocss": "^0.65.0",
|
|
110
|
-
"vite": "^
|
|
110
|
+
"vite": "^7.0.0"
|
|
111
111
|
},
|
|
112
112
|
"packageManager": "pnpm@9.15.3",
|
|
113
113
|
"pnpm": {
|
|
@@ -7,21 +7,17 @@ interface ColorCode {
|
|
|
7
7
|
name: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
interface PaintMark {
|
|
11
|
-
count: number;
|
|
12
|
-
color: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
10
|
interface TableItem {
|
|
16
11
|
id: string;
|
|
17
12
|
name: string;
|
|
18
|
-
value: unknown;
|
|
13
|
+
value: unknown; // Może być string, number, boolean, array (ColorCode[] lub string[])
|
|
19
14
|
translated?: boolean;
|
|
20
15
|
icon?: boolean;
|
|
21
16
|
isArrayValue?: boolean;
|
|
22
|
-
isColorArray?: boolean;
|
|
23
|
-
isPaintMarks?: boolean;
|
|
24
|
-
isGenericArray?: 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ą
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
interface GroupedLink {
|
|
@@ -37,26 +33,34 @@ const props = defineProps({
|
|
|
37
33
|
caption: { type: String, default: null }
|
|
38
34
|
});
|
|
39
35
|
|
|
40
|
-
// Function
|
|
36
|
+
// Function to check if a value is a link
|
|
41
37
|
const isLink = (id: string) => {
|
|
42
38
|
return ['blog', 'youtube', 'vimeo'].includes(id);
|
|
43
39
|
};
|
|
44
40
|
|
|
45
|
-
// Function
|
|
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
|
|
46
43
|
const isColorArray = (item: TableItem) => {
|
|
47
|
-
|
|
44
|
+
const colorIds = ['color', 'thread-color']; // lista ID które są kolorami
|
|
45
|
+
return (item.isColorArray || colorIds.includes(item.id)) && Array.isArray(item.value);
|
|
48
46
|
};
|
|
49
47
|
|
|
50
|
-
// Function
|
|
48
|
+
// Function to check if it's paint marks (value is now a string from API)
|
|
51
49
|
const isPaintMarks = (item: TableItem) => {
|
|
52
|
-
return item.isPaintMarks &&
|
|
50
|
+
return item.isPaintMarks && typeof item.value === 'string';
|
|
53
51
|
};
|
|
54
52
|
|
|
55
|
-
// Function
|
|
53
|
+
// Function to check if it's a generic array (e.g., for position)
|
|
56
54
|
const isGenericArray = (item: TableItem) => {
|
|
57
55
|
return item.isGenericArray && Array.isArray(item.value);
|
|
58
56
|
};
|
|
59
57
|
|
|
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
|
+
|
|
60
64
|
// Function to check if value is HTML string (fallback)
|
|
61
65
|
const isHtmlValue = (value: unknown): boolean => {
|
|
62
66
|
return typeof value === 'string' && (value.includes('<span') || value.includes('<br>'));
|
|
@@ -64,13 +68,13 @@ const isHtmlValue = (value: unknown): boolean => {
|
|
|
64
68
|
|
|
65
69
|
// Function for specifying header text
|
|
66
70
|
const getHeaderText = (row: TableItem | GroupedLink) => {
|
|
67
|
-
// For the blog, we use id instead of name
|
|
68
71
|
if (row.id === 'blog') {
|
|
69
72
|
return row.id.charAt(0).toUpperCase() + row.id.slice(1);
|
|
70
73
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
// Użyj `name` z obiektu `TableItem`, jeśli istnieje, w przeciwnym razie sformatuj `id`.
|
|
75
|
+
return 'name' in row ? row.name : row.id.split('-')
|
|
76
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
77
|
+
.join(' ');
|
|
74
78
|
};
|
|
75
79
|
|
|
76
80
|
// Function to determine the icon class for a link type
|
|
@@ -89,37 +93,43 @@ const getLinkIconClass = (linkId: string) => {
|
|
|
89
93
|
|
|
90
94
|
// Grouping of elements by id
|
|
91
95
|
const groupedItems = computed(() => {
|
|
96
|
+
// ✅ Add validation to ensure props.items is an array
|
|
97
|
+
if (!Array.isArray(props.items)) {
|
|
98
|
+
console.warn('ProductDetailsList: items prop is not an array:', props.items);
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
|
|
92
102
|
const result: (TableItem | GroupedLink)[] = [];
|
|
93
103
|
const linkGroups = new Map<string, GroupedLink>();
|
|
94
|
-
|
|
95
|
-
//
|
|
104
|
+
|
|
105
|
+
// Process all elements
|
|
96
106
|
props.items.forEach(item => {
|
|
97
107
|
// If it's a link (blog, youtube, vimeo)
|
|
98
108
|
if (isLink(item.id)) {
|
|
99
109
|
// Add a link to the relevant group
|
|
100
110
|
if (!linkGroups.has(item.id)) {
|
|
101
|
-
linkGroups.set(item.id, {
|
|
102
|
-
id: item.id,
|
|
103
|
-
links: []
|
|
111
|
+
linkGroups.set(item.id, {
|
|
112
|
+
id: item.id,
|
|
113
|
+
links: []
|
|
104
114
|
});
|
|
105
115
|
}
|
|
106
|
-
|
|
116
|
+
|
|
107
117
|
// Add link to the relevant group
|
|
108
118
|
linkGroups.get(item.id)?.links.push({
|
|
109
119
|
name: item.name,
|
|
110
120
|
value: item.value as string
|
|
111
121
|
});
|
|
112
122
|
} else {
|
|
113
|
-
// If it
|
|
123
|
+
// If it's not a link, add it normally to the results
|
|
114
124
|
result.push(item);
|
|
115
125
|
}
|
|
116
126
|
});
|
|
117
|
-
|
|
127
|
+
|
|
118
128
|
// Add all link groups at the end
|
|
119
129
|
linkGroups.forEach(group => {
|
|
120
130
|
result.push(group);
|
|
121
131
|
});
|
|
122
|
-
|
|
132
|
+
|
|
123
133
|
return result;
|
|
124
134
|
});
|
|
125
135
|
</script>
|
|
@@ -135,63 +145,72 @@ const groupedItems = computed(() => {
|
|
|
135
145
|
</colgroup>
|
|
136
146
|
<tbody>
|
|
137
147
|
<tr v-for="row, index in groupedItems" :key="index" class="details-table-row">
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
as="th"
|
|
141
|
-
:text="getHeaderText(row)"
|
|
142
|
-
class="details-table-header"
|
|
143
|
-
/>
|
|
144
|
-
|
|
145
|
-
<!-- Handling link groups -->
|
|
148
|
+
<ProductDetailName as="th" :text="getHeaderText(row)" class="details-table-header" />
|
|
149
|
+
|
|
146
150
|
<td v-if="'links' in row" class="details-table-cell">
|
|
147
151
|
<ul class="list-none p-0 m-0">
|
|
148
152
|
<li v-for="(link, linkIndex) in row.links" :key="linkIndex" class="mb-2 last:mb-0 flex items-center">
|
|
149
|
-
<span
|
|
153
|
+
<span
|
|
154
|
+
:class="[getLinkIconClass(row.id), 'leading-none inline-block mr-2 w-4 min-w-4 h-4 text-gray-400']" />
|
|
150
155
|
<a :href="link.value" target="_blank" rel="noopener noreferrer" class="link-primary">
|
|
151
156
|
{{ link.name }}
|
|
152
157
|
</a>
|
|
153
158
|
</li>
|
|
154
159
|
</ul>
|
|
155
160
|
</td>
|
|
156
|
-
|
|
157
|
-
<!-- Special handling for color arrays (already translated) -->
|
|
161
|
+
|
|
158
162
|
<td v-else-if="'id' in row && isColorArray(row)" class="details-table-cell">
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
<ul class="list-none p-0 m-0">
|
|
164
|
+
<li v-for="(colorItem, colorIndex) in (row.value as ColorCode[])" :key="colorIndex"
|
|
165
|
+
class="flex items-center gap-1 mb-1 last:mb-0">
|
|
166
|
+
|
|
167
|
+
<template v-if="colorItem.code">
|
|
168
|
+
<code class="font-mono text-sm">
|
|
169
|
+
{{ colorItem.code }}
|
|
170
|
+
</code>
|
|
171
|
+
<span class="text-gray-400">-</span>
|
|
172
|
+
</template>
|
|
173
|
+
<span class="text-gray-700 dark:text-gray-300">{{ colorItem.name }}</span>
|
|
174
|
+
</li>
|
|
168
175
|
</ul>
|
|
169
176
|
</td>
|
|
170
|
-
|
|
171
|
-
<!-- Special handling for paint marks (already translated) -->
|
|
177
|
+
|
|
172
178
|
<td v-else-if="'id' in row && isPaintMarks(row)" class="details-table-cell">
|
|
173
179
|
<span class="text-gray-700 dark:text-gray-300">{{ row.value }}</span>
|
|
174
180
|
</td>
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
|
|
182
|
+
<td v-else-if="'id' in row && isForExteriorColour(row)" class="details-table-cell">
|
|
183
|
+
<ul class="list-none p-0 m-0">
|
|
184
|
+
<li v-for="(colorEntry, colourIndex) in (row.value as ColorCode[])" :key="colourIndex"
|
|
185
|
+
class="flex items-center gap-1 mb-1 last:mb-0">
|
|
186
|
+
|
|
187
|
+
<template v-if="colorEntry.code">
|
|
188
|
+
<code class="font-mono text-sm">
|
|
189
|
+
{{ colorEntry.code }}
|
|
190
|
+
</code>
|
|
191
|
+
<span class="text-gray-400">-</span>
|
|
192
|
+
</template>
|
|
193
|
+
<span class="text-gray-700 dark:text-gray-300">{{ colorEntry.name }}</span>
|
|
194
|
+
</li>
|
|
195
|
+
</ul>
|
|
196
|
+
</td>
|
|
197
|
+
|
|
177
198
|
<td v-else-if="'id' in row && isGenericArray(row)" class="details-table-cell">
|
|
178
199
|
<ul class="list-none p-0 m-0">
|
|
179
|
-
<li v-for="(item, itemIndex) in (row.value as string[])" :key="itemIndex"
|
|
180
|
-
|
|
200
|
+
<li v-for="(item, itemIndex) in (row.value as string[])" :key="itemIndex"
|
|
201
|
+
class="flex items-start gap-2 mb-1 last:mb-0 leading-relaxed">
|
|
181
202
|
<span class="text-gray-500 font-bold flex-shrink-0 mt-0.5">·</span>
|
|
182
203
|
<span class="text-gray-700 dark:text-gray-300 text-sm">{{ item }}</span>
|
|
183
204
|
</li>
|
|
184
205
|
</ul>
|
|
185
206
|
</td>
|
|
186
|
-
|
|
187
|
-
<!-- Handling HTML values (fallback for already formatted HTML) -->
|
|
207
|
+
|
|
188
208
|
<td v-else-if="'id' in row && isHtmlValue(row.value)" class="details-table-cell" v-html="row.value"></td>
|
|
189
|
-
|
|
190
|
-
<!-- Support for standard types -->
|
|
209
|
+
|
|
191
210
|
<slot v-else-if="'id' in row" :name="row.id">
|
|
192
211
|
<td class="details-table-cell">{{ row.value }}</td>
|
|
193
212
|
</slot>
|
|
194
213
|
</tr>
|
|
195
214
|
</tbody>
|
|
196
215
|
</table>
|
|
197
|
-
</template>
|
|
216
|
+
</template>
|
package/src/pages/index.astro
CHANGED
|
@@ -91,10 +91,10 @@ const navItems = [
|
|
|
91
91
|
<div>
|
|
92
92
|
<Headline underline as="div" class="mx-auto text-gray-900" textSize="3xl">Download:</Headline>
|
|
93
93
|
<div class="grid grid-flow-col gap-4 auto-cols-max text-6xl mb-12">
|
|
94
|
-
<a href="https://www.npmjs.com/package/spoko-design-system" rel="noopener" title="npm page" class="hover:text-accent-
|
|
94
|
+
<a href="https://www.npmjs.com/package/spoko-design-system" rel="noopener" title="npm page" class="hover:text-accent-light">
|
|
95
95
|
<Icon name="mdi:npm"/>
|
|
96
96
|
</a>
|
|
97
|
-
<a href="https://github.com/polo-blue/sds" rel="noopener" title="Github Page" class="hover:text-accent-
|
|
97
|
+
<a href="https://github.com/polo-blue/sds" rel="noopener" title="Github Page" class="hover:text-accent-light">
|
|
98
98
|
<Icon name="mdi:github"/>
|
|
99
99
|
</a>
|
|
100
100
|
</div>
|
|
@@ -109,7 +109,7 @@ export const componentShortcuts = [
|
|
|
109
109
|
['breadcrumb-back-btn', 'flex items-center px-3 sm:px-0 py-4.25 sm:py-1 hover:text-accent-light whitespace-nowrap my-auto'],
|
|
110
110
|
|
|
111
111
|
// PostCategories
|
|
112
|
-
['category-link-base', 'text-sm sm:text-base text-accent-
|
|
112
|
+
['category-link-base', 'text-sm sm:text-base text-accent-light uppercase hover:text-blue-500 transition-colors'],
|
|
113
113
|
['category-link-active', 'text-blue-500'],
|
|
114
114
|
|
|
115
115
|
// Details table
|
|
@@ -121,7 +121,7 @@ export const TYPOGRAPHY = {
|
|
|
121
121
|
export const PRODUCT_STYLES = {
|
|
122
122
|
thumb: {
|
|
123
123
|
base: 'h-full w-full object-cover object-center transform scale-100 group-hover:scale-110 absolute inset-0 will-change-transform bg-neutral-lightest',
|
|
124
|
-
container: `${aspectRatios['4/3']} ${LAYOUT.flex.alignCenter} mb-3 sm:mb-
|
|
124
|
+
container: `${aspectRatios['4/3']} ${LAYOUT.flex.alignCenter} mb-3 sm:mb-auto ${IMAGE_STYLES.overlay}`,
|
|
125
125
|
},
|
|
126
126
|
link: {
|
|
127
127
|
base: 'relative flex w-full bg-white after:(absolute bg-accent-light w-[calc(100%-1rem)] left-0 h-px top-[calc(100%-1px)] bottom-1 content-empty scale-x-0 transition-transform-300 origin-top-right) hover:after:(origin-top-left scale-x-100)',
|