spoko-design-system 0.4.2 → 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
- // Pomocnicze funkcje
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.2",
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": "8.15.2",
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
- // Move SVG definition to a constant to avoid recomputing
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
- // Use a single event listener with event delegation
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) {
@@ -25,6 +25,7 @@ const {
25
25
  <div class="flex border rounded">
26
26
  <button
27
27
  data-view="list"
28
+ data-view-toggle
28
29
  class="view-toggle flex items-center gap-1 px-3 py-0.5 transition-colors"
29
30
  aria-label={listAriaLabel}
30
31
  >
@@ -33,6 +34,7 @@ const {
33
34
  </button>
34
35
  <button
35
36
  data-view="grid"
37
+ data-view-toggle
36
38
  class="view-toggle flex items-center gap-1 px-3 py-0.5 transition-colors"
37
39
  aria-label={gridAriaLabel}
38
40
  >
@@ -48,28 +50,35 @@ const {
48
50
  updateUI(savedView);
49
51
 
50
52
  // Clean up existing listeners to prevent duplicates
51
- document.querySelectorAll('.view-toggle').forEach(btn => {
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
- if (!(e.currentTarget instanceof HTMLElement)) return;
59
- const view = e.currentTarget.dataset.view;
60
- if (!view) return;
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>