spoko-design-system 0.4.1 → 0.4.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/icon.config.ts
CHANGED
|
@@ -258,7 +258,7 @@ export const iconConfig: IconConfig = {
|
|
|
258
258
|
}
|
|
259
259
|
};
|
|
260
260
|
|
|
261
|
-
//
|
|
261
|
+
// Helpers
|
|
262
262
|
export function isIconIncluded(collection: IconCollectionName, iconName: string): boolean {
|
|
263
263
|
return iconConfig.include[collection]?.includes(iconName) ?? false;
|
|
264
264
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spoko-design-system",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./index.ts",
|
|
6
6
|
"module": "./index.ts",
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
"@iconify/vue": "^4.3.0",
|
|
75
75
|
"@playform/compress": "^0.1.7",
|
|
76
76
|
"@playform/inline": "^0.1.1",
|
|
77
|
-
"@types/node": "^22.13.4",
|
|
78
77
|
"@unocss/astro": "^65.4.3",
|
|
79
78
|
"@unocss/preset-attributify": "^65.4.3",
|
|
80
79
|
"@unocss/preset-typography": "^65.4.3",
|
|
@@ -98,7 +97,6 @@
|
|
|
98
97
|
"i18next-vue": "^5.1.0",
|
|
99
98
|
"swiper": "^11.2.3",
|
|
100
99
|
"unocss": "^65.4.3",
|
|
101
|
-
"vite": "^6.1.0",
|
|
102
100
|
"vue": "^3.5.13"
|
|
103
101
|
},
|
|
104
102
|
"devDependencies": {
|
|
@@ -106,14 +104,21 @@
|
|
|
106
104
|
"@vitejs/plugin-vue": "^5.2.1",
|
|
107
105
|
"@vue/compiler-sfc": "^3.5.13",
|
|
108
106
|
"astro": "^5.3.0",
|
|
109
|
-
"unocss": "^0.65.0"
|
|
107
|
+
"unocss": "^0.65.0",
|
|
108
|
+
"@types/gtag.js": "^0.0.20",
|
|
109
|
+
"vite": "^6.1.0",
|
|
110
|
+
"@types/node": "^22.13.4"
|
|
110
111
|
},
|
|
111
112
|
"packageManager": "pnpm@9.15.3",
|
|
112
113
|
"pnpm": {
|
|
113
|
-
"default": "
|
|
114
|
+
"default": "9.15.3",
|
|
114
115
|
"overrides": {
|
|
115
116
|
"file-type@>=17.0.0 <17.1.3": ">=17.1.3",
|
|
116
117
|
"sharp@<0.30.5": ">=0.30.5"
|
|
117
118
|
}
|
|
119
|
+
},
|
|
120
|
+
"engines": {
|
|
121
|
+
"node": ">=18.14.1",
|
|
122
|
+
"pnpm": ">=9.15.3"
|
|
118
123
|
}
|
|
119
124
|
}
|
|
@@ -14,7 +14,7 @@ const {
|
|
|
14
14
|
texts
|
|
15
15
|
} = Astro.props;
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// SVG icon as data URL for mask
|
|
18
18
|
const COPY_ICON = `url("data:image/svg+xml;utf8,${encodeURIComponent(
|
|
19
19
|
`<svg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'><path fill='currentColor' d='M184 66H40a6 6 0 0 0-6 6v144a6 6 0 0 0 6 6h144a6 6 0 0 0 6-6V72a6 6 0 0 0-6-6m-6 144H46V78h132Zm44-170v144a6 6 0 0 1-12 0V46H72a6 6 0 0 1 0-12h144a6 6 0 0 1 6 6'/></svg>`
|
|
20
20
|
)}")`;
|
|
@@ -24,6 +24,7 @@ const COPY_ICON = `url("data:image/svg+xml;utf8,${encodeURIComponent(
|
|
|
24
24
|
aria-label={texts.copy}
|
|
25
25
|
class="btn-copy has-tooltip"
|
|
26
26
|
data-copy-text={productNumber}
|
|
27
|
+
data-category={Astro.url.pathname.split('/')[1] || ''}
|
|
27
28
|
>
|
|
28
29
|
<span
|
|
29
30
|
class:list={["tooltip rounded-full btn-copy-text", tooltipClasses]}
|
|
@@ -35,7 +36,8 @@ const COPY_ICON = `url("data:image/svg+xml;utf8,${encodeURIComponent(
|
|
|
35
36
|
|
|
36
37
|
<script>
|
|
37
38
|
class ClipboardButton {
|
|
38
|
-
private static COPY_TIMEOUT = 2000;
|
|
39
|
+
private static readonly COPY_TIMEOUT = 2000;
|
|
40
|
+
private static readonly ANALYTICS_EVENT = 'product_code_copy';
|
|
39
41
|
|
|
40
42
|
constructor(private button: HTMLButtonElement) {
|
|
41
43
|
this.init();
|
|
@@ -53,6 +55,10 @@ const COPY_ICON = `url("data:image/svg+xml;utf8,${encodeURIComponent(
|
|
|
53
55
|
return this.button.dataset.copyText || '';
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
private get category(): string {
|
|
59
|
+
return this.button.dataset.category || '';
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
private get originalText(): string {
|
|
57
63
|
return this.tooltip.dataset.text || 'Copy';
|
|
58
64
|
}
|
|
@@ -65,11 +71,24 @@ const COPY_ICON = `url("data:image/svg+xml;utf8,${encodeURIComponent(
|
|
|
65
71
|
try {
|
|
66
72
|
await this.copyToClipboard();
|
|
67
73
|
this.updateTooltip();
|
|
74
|
+
this.trackCopy();
|
|
68
75
|
} catch (err) {
|
|
69
76
|
console.error('Failed to copy text:', err);
|
|
70
77
|
}
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
private trackCopy(): void {
|
|
81
|
+
if (!window.dataLayer) return;
|
|
82
|
+
|
|
83
|
+
window.dataLayer.push({
|
|
84
|
+
event: ClipboardButton.ANALYTICS_EVENT,
|
|
85
|
+
productCode: this.copyText,
|
|
86
|
+
category: this.category,
|
|
87
|
+
pageUrl: window.location.pathname,
|
|
88
|
+
timestamp: new Date().toISOString()
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
private async copyToClipboard(): Promise<void> {
|
|
74
93
|
if (navigator.clipboard && window.isSecureContext) {
|
|
75
94
|
await navigator.clipboard.writeText(this.copyText);
|
|
@@ -104,7 +123,7 @@ const COPY_ICON = `url("data:image/svg+xml;utf8,${encodeURIComponent(
|
|
|
104
123
|
}
|
|
105
124
|
}
|
|
106
125
|
|
|
107
|
-
//
|
|
126
|
+
// Initialize copy buttons on page load
|
|
108
127
|
document.addEventListener('astro:page-load', () => {
|
|
109
128
|
document.querySelectorAll('.btn-copy').forEach(button => {
|
|
110
129
|
if (button instanceof HTMLButtonElement) {
|
|
@@ -23,26 +23,30 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
|
|
|
23
23
|
transition:name="category-details"
|
|
24
24
|
transition:animate="fade"
|
|
25
25
|
>
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
<CategorySidebarToggler class="category-sidebar-toggler w-12 md:w-8" data-state="desktop">
|
|
27
|
+
<div class="desktop-icons hidden md:block">
|
|
28
|
+
<!-- Desktop icons container -->
|
|
28
29
|
<Icon
|
|
29
30
|
name="ant-design:menu-fold-outlined"
|
|
30
|
-
class="toggler-btn
|
|
31
|
+
class="toggler-btn w-6 expanded-icon"
|
|
31
32
|
aria-hidden="true"
|
|
32
33
|
/>
|
|
33
|
-
<!-- Desktop collapsed -->
|
|
34
34
|
<Icon
|
|
35
35
|
name="ant-design:menu-unfold-outlined"
|
|
36
|
-
class="toggler-btn
|
|
36
|
+
class="toggler-btn w-6 collapsed-icon hidden"
|
|
37
37
|
aria-hidden="true"
|
|
38
38
|
/>
|
|
39
|
-
|
|
39
|
+
</div>
|
|
40
|
+
<!-- Mobile icon in separate container -->
|
|
41
|
+
<div class="mobile-icon block md:hidden">
|
|
40
42
|
<Icon
|
|
41
43
|
name="ant-design:menu-outlined"
|
|
42
|
-
class="toggler-btn
|
|
44
|
+
class="toggler-btn w-6"
|
|
43
45
|
aria-hidden="true"
|
|
44
46
|
/>
|
|
45
|
-
</
|
|
47
|
+
</div>
|
|
48
|
+
</CategorySidebarToggler>
|
|
49
|
+
|
|
46
50
|
|
|
47
51
|
<div class="overflow-x-auto overflow-y-hidden flex max-w-full items-center">
|
|
48
52
|
{subtitle ? (
|
|
@@ -99,11 +103,15 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
|
|
|
99
103
|
}
|
|
100
104
|
|
|
101
105
|
function updateTogglers(isCollapsed) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
document.querySelectorAll('.category-sidebar-toggler').forEach(toggler => {
|
|
107
|
+
const expandedIcon = toggler.querySelector('.expanded-icon');
|
|
108
|
+
const collapsedIcon = toggler.querySelector('.collapsed-icon');
|
|
109
|
+
|
|
110
|
+
if (expandedIcon && collapsedIcon) {
|
|
111
|
+
expandedIcon.classList.toggle('hidden', isCollapsed);
|
|
112
|
+
collapsedIcon.classList.toggle('hidden', !isCollapsed);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
107
115
|
}
|
|
108
116
|
|
|
109
117
|
function toggleSidebar() {
|
|
@@ -123,8 +131,18 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
|
|
|
123
131
|
}
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
function setupTogglers() {
|
|
135
|
+
document.querySelectorAll('.category-sidebar-toggler').forEach(toggler => {
|
|
136
|
+
toggler.removeEventListener('click', toggleSidebar);
|
|
137
|
+
toggler.addEventListener('click', toggleSidebar);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Initialize on page load
|
|
142
|
+
document.addEventListener('astro:page-load', () => {
|
|
143
|
+
initializeSidebar();
|
|
144
|
+
setupTogglers();
|
|
145
|
+
});
|
|
128
146
|
|
|
129
147
|
// Preserve state during view transitions
|
|
130
148
|
document.addEventListener('astro:before-swap', () => {
|
|
@@ -144,6 +162,7 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
|
|
|
144
162
|
});
|
|
145
163
|
</script>
|
|
146
164
|
|
|
165
|
+
|
|
147
166
|
<style>
|
|
148
167
|
.toggler-btn {
|
|
149
168
|
@apply md:-mt-0.5;
|
|
@@ -25,7 +25,8 @@ const {
|
|
|
25
25
|
<div class="flex border rounded">
|
|
26
26
|
<button
|
|
27
27
|
data-view="list"
|
|
28
|
-
|
|
28
|
+
data-view-toggle
|
|
29
|
+
class="view-toggle flex items-center gap-1 px-3 py-0.5 transition-colors"
|
|
29
30
|
aria-label={listAriaLabel}
|
|
30
31
|
>
|
|
31
32
|
<Icon name="ant-design:bars-outlined" class="w-4 h-4" />
|
|
@@ -33,7 +34,8 @@ const {
|
|
|
33
34
|
</button>
|
|
34
35
|
<button
|
|
35
36
|
data-view="grid"
|
|
36
|
-
|
|
37
|
+
data-view-toggle
|
|
38
|
+
class="view-toggle flex items-center gap-1 px-3 py-0.5 transition-colors"
|
|
37
39
|
aria-label={gridAriaLabel}
|
|
38
40
|
>
|
|
39
41
|
<Icon name="ant-design:appstore-outlined" class="w-4 h-4" />
|
|
@@ -48,28 +50,35 @@ const {
|
|
|
48
50
|
updateUI(savedView);
|
|
49
51
|
|
|
50
52
|
// Clean up existing listeners to prevent duplicates
|
|
51
|
-
document.querySelectorAll('
|
|
53
|
+
document.querySelectorAll('[data-view-toggle]').forEach(btn => {
|
|
52
54
|
btn.removeEventListener('click', handleViewToggle);
|
|
53
55
|
btn.addEventListener('click', handleViewToggle);
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
function handleViewToggle(e) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
function handleViewToggle(e: Event) {
|
|
60
|
+
const button = e.currentTarget as HTMLElement;
|
|
61
|
+
if (!button?.dataset.view) return;
|
|
62
|
+
|
|
63
|
+
const view = button.dataset.view;
|
|
62
64
|
localStorage.setItem('categoryView', view);
|
|
63
65
|
updateUI(view);
|
|
66
|
+
|
|
67
|
+
// Push to dataLayer directly
|
|
68
|
+
if (window.dataLayer) {
|
|
69
|
+
window.dataLayer.push({
|
|
70
|
+
event: 'view_style_change',
|
|
71
|
+
viewType: view,
|
|
72
|
+
category: window.location.pathname
|
|
73
|
+
});
|
|
74
|
+
}
|
|
64
75
|
}
|
|
65
76
|
|
|
66
|
-
function updateUI(view) {
|
|
67
|
-
// Update toggle buttons
|
|
77
|
+
function updateUI(view: string) {
|
|
68
78
|
document.querySelectorAll('.view-toggle').forEach(btn => {
|
|
69
79
|
btn.classList.toggle('bg-neutral-lightest', btn.dataset.view === view);
|
|
70
80
|
});
|
|
71
81
|
|
|
72
|
-
// Update products container
|
|
73
82
|
const productsContainer = document.querySelector('.products-container');
|
|
74
83
|
if (productsContainer) {
|
|
75
84
|
productsContainer.classList.remove('view-grid', 'view-list');
|
|
@@ -77,6 +86,5 @@ const {
|
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
88
|
|
|
80
|
-
// Initialize on page load and view transitions
|
|
81
89
|
document.addEventListener('astro:page-load', initializeView);
|
|
82
90
|
</script>
|