spoko-design-system 1.5.3 → 1.7.0
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 +12 -0
- package/index.ts +2 -0
- package/package.json +7 -5
- package/src/components/PrCode.vue +14 -52
- package/src/components/Product/ProductEngine.vue +240 -0
- package/src/components/Product/ProductEngines.vue +116 -0
- package/src/config.ts +1 -0
- package/src/layouts/MainLayout.astro +5 -0
- package/src/pages/components/product-engine.mdx +370 -0
- package/src/scripts/tooltips.ts +46 -0
- package/src/styles/tippy-theme.css +131 -0
- package/uno-config/theme/colors.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [1.7.0](https://github.com/polo-blue/sds/compare/v1.6.0...v1.7.0) (2025-10-29)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* add Tippy.js tooltips with ProductEngine components and API-driven translations ([eb18a17](https://github.com/polo-blue/sds/commit/eb18a171a3e5d80889f64a645d82767898561764))
|
|
6
|
+
|
|
7
|
+
## [1.6.0](https://github.com/polo-blue/sds/compare/v1.5.3...v1.6.0) (2025-10-28)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* add accent.medium color ([#0082d6](https://github.com/polo-blue/sds/issues/0082d6)) to theme palette ([0cb1f3b](https://github.com/polo-blue/sds/commit/0cb1f3b095a745a4991e5062af5ee5d5679297c7)), closes [#0099da](https://github.com/polo-blue/sds/issues/0099da) [#0087c1](https://github.com/polo-blue/sds/issues/0087c1)
|
|
12
|
+
|
|
1
13
|
## [1.5.3](https://github.com/polo-blue/sds/compare/v1.5.2...v1.5.3) (2025-10-28)
|
|
2
14
|
|
|
3
15
|
### Bug Fixes
|
package/index.ts
CHANGED
|
@@ -19,6 +19,8 @@ export { default as Headline } from './src/components/Headline.vue';
|
|
|
19
19
|
export { default as Quote } from './src/components/Quote.vue';
|
|
20
20
|
|
|
21
21
|
export { default as ProductEngineType } from './src/components/Product/ProductEngineType.vue';
|
|
22
|
+
export { default as ProductEngine } from './src/components/Product/ProductEngine.vue';
|
|
23
|
+
export { default as ProductEngines } from './src/components/Product/ProductEngines.vue';
|
|
22
24
|
export { default as ProductButton } from './src/components/Product/ProductButton.vue';
|
|
23
25
|
export { default as ProductColors } from './src/components/Product/ProductColors.vue';
|
|
24
26
|
export { default as ProductDetailName } from './src/components/Product/ProductDetailName.vue';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spoko-design-system",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./index.ts",
|
|
6
6
|
"module": "./index.ts",
|
|
@@ -53,12 +53,13 @@
|
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@algolia/client-search": "^5.41.0",
|
|
56
|
-
"@astrojs/mdx": "^4.3.
|
|
56
|
+
"@astrojs/mdx": "^4.3.9",
|
|
57
57
|
"@astrojs/node": "^9.5.0",
|
|
58
58
|
"@astrojs/sitemap": "^3.6.0",
|
|
59
59
|
"@astrojs/ts-plugin": "^1.10.5",
|
|
60
|
-
"@astrojs/vue": "^5.1.
|
|
60
|
+
"@astrojs/vue": "^5.1.2",
|
|
61
61
|
"@docsearch/css": "^4.2.0",
|
|
62
|
+
"@floating-ui/vue": "^1.1.9",
|
|
62
63
|
"@iconify-json/ant-design": "^1.2.5",
|
|
63
64
|
"@iconify-json/bi": "^1.2.6",
|
|
64
65
|
"@iconify-json/bx": "^1.2.2",
|
|
@@ -107,6 +108,7 @@
|
|
|
107
108
|
"astro-remote": "^0.3.4",
|
|
108
109
|
"dotenv": "^17.2.3",
|
|
109
110
|
"swiper": "^12.0.3",
|
|
111
|
+
"tippy.js": "^6.3.7",
|
|
110
112
|
"unocss": "66.5.4",
|
|
111
113
|
"vite-plugin-pwa": "^1.1.0",
|
|
112
114
|
"vue": "^3.5.22"
|
|
@@ -115,14 +117,14 @@
|
|
|
115
117
|
"@semantic-release/changelog": "^6.0.3",
|
|
116
118
|
"@semantic-release/git": "^10.0.1",
|
|
117
119
|
"@types/gtag.js": "^0.0.20",
|
|
118
|
-
"@types/node": "^24.9.
|
|
120
|
+
"@types/node": "^24.9.2",
|
|
119
121
|
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
|
120
122
|
"@typescript-eslint/parser": "^8.46.2",
|
|
121
123
|
"@unocss/transformer-variant-group": "66.5.4",
|
|
122
124
|
"@vitejs/plugin-vue": "^6.0.1",
|
|
123
125
|
"@vue/compiler-sfc": "^3.5.22",
|
|
124
126
|
"@vue/eslint-config-typescript": "^14.6.0",
|
|
125
|
-
"astro": "^5.15.
|
|
127
|
+
"astro": "^5.15.2",
|
|
126
128
|
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
127
129
|
"eslint": "^9.38.0",
|
|
128
130
|
"eslint-plugin-astro": "^1.4.0",
|
|
@@ -27,69 +27,31 @@ const props = defineProps({
|
|
|
27
27
|
</script>
|
|
28
28
|
|
|
29
29
|
<template>
|
|
30
|
-
<span
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
</span>
|
|
41
|
-
|
|
42
|
-
<!-- Dynamic Tooltip with description from API -->
|
|
43
|
-
<div v-if="props.prcode.description" class="tooltip">
|
|
44
|
-
<div class="tooltip-content">
|
|
45
|
-
{{ props.prcode.description }}
|
|
46
|
-
<span v-if="props.prcode.group" class="tooltip-group">
|
|
47
|
-
({{ props.prcode.group }})
|
|
48
|
-
</span>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
30
|
+
<span
|
|
31
|
+
data-pagefind-filter="PR-Code"
|
|
32
|
+
class="btn-prcode"
|
|
33
|
+
:class="[
|
|
34
|
+
prcode.variant_category ? `btn-prcode--variant-${prcode.variant_category.toLowerCase()}` : '',
|
|
35
|
+
{ 'btn-prcode--pdp': isPdp }
|
|
36
|
+
]"
|
|
37
|
+
:data-tippy-content="prcode.description || undefined"
|
|
38
|
+
>
|
|
39
|
+
{{ prcode.code }}
|
|
51
40
|
</span>
|
|
52
41
|
</template>
|
|
53
42
|
|
|
54
43
|
<style scoped>
|
|
55
|
-
/* Base PrCode
|
|
44
|
+
/* Base PrCode Styles */
|
|
56
45
|
.btn-prcode {
|
|
57
|
-
@apply inline-block
|
|
46
|
+
@apply inline-block cursor-default;
|
|
47
|
+
@apply px-1.5 py-0.5;
|
|
48
|
+
@apply rounded;
|
|
58
49
|
}
|
|
59
50
|
|
|
60
51
|
.btn-prcode--pdp {
|
|
61
52
|
@apply mb-1;
|
|
62
53
|
}
|
|
63
54
|
|
|
64
|
-
/* Tooltip Styles - Similar to ProductEngine */
|
|
65
|
-
.tooltip {
|
|
66
|
-
@apply invisible absolute left-1/2 -translate-x-1/2 bottom-full mb-2 z-50;
|
|
67
|
-
@apply px-3 py-1.5 rounded-lg shadow-lg whitespace-nowrap;
|
|
68
|
-
@apply bg-blue-darker text-white text-xs;
|
|
69
|
-
@apply pointer-events-none;
|
|
70
|
-
max-width: 300px;
|
|
71
|
-
white-space: normal;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.has-tooltip:hover .tooltip {
|
|
75
|
-
@apply visible;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.tooltip-content {
|
|
79
|
-
@apply relative;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.tooltip-group {
|
|
83
|
-
@apply ml-2 opacity-75 text-xs font-light;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* Tooltip Arrow */
|
|
87
|
-
.tooltip::after {
|
|
88
|
-
content: '';
|
|
89
|
-
@apply absolute left-1/2 -translate-x-1/2 top-full;
|
|
90
|
-
@apply border-4 border-transparent border-t-blue-darker;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
55
|
/* Semantic Variant Category Colors */
|
|
94
56
|
/* GTI - Red */
|
|
95
57
|
.btn-prcode--variant-gti {
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { ref, onMounted, onUnmounted } from 'vue';
|
|
3
|
+
import type { PropType } from 'vue';
|
|
4
|
+
import tippy, { type Instance } from 'tippy.js';
|
|
5
|
+
import 'tippy.js/dist/tippy.css';
|
|
6
|
+
import '../../styles/tippy-theme.css';
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
VAG group (VW/Audi/Skoda/Seat/Porsche/Bentley/Lamborghini/Ducati/Cupra/Scania/MAN) manufacturer Engine Code
|
|
10
|
+
Displays engine code with detailed tooltip showing: name, power, displacement, dates, etc.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface Engine {
|
|
14
|
+
id?: number;
|
|
15
|
+
code: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
info?: string | null;
|
|
18
|
+
serie?: {
|
|
19
|
+
value: string;
|
|
20
|
+
label: string;
|
|
21
|
+
};
|
|
22
|
+
type?: {
|
|
23
|
+
value: string;
|
|
24
|
+
translated: string;
|
|
25
|
+
label: string;
|
|
26
|
+
};
|
|
27
|
+
power?: {
|
|
28
|
+
kw: number;
|
|
29
|
+
ps: number;
|
|
30
|
+
ps_label: string;
|
|
31
|
+
label: string;
|
|
32
|
+
};
|
|
33
|
+
date?: {
|
|
34
|
+
value: string;
|
|
35
|
+
label: string;
|
|
36
|
+
};
|
|
37
|
+
displacement?: {
|
|
38
|
+
value: number;
|
|
39
|
+
label: string;
|
|
40
|
+
};
|
|
41
|
+
compression_ratio?: {
|
|
42
|
+
value: string | null;
|
|
43
|
+
label: string;
|
|
44
|
+
};
|
|
45
|
+
valves?: {
|
|
46
|
+
value: number | null;
|
|
47
|
+
label: string;
|
|
48
|
+
};
|
|
49
|
+
euro?: {
|
|
50
|
+
value: number;
|
|
51
|
+
label: string;
|
|
52
|
+
};
|
|
53
|
+
pivot?: any;
|
|
54
|
+
|
|
55
|
+
// Backward compatibility - old flat structure
|
|
56
|
+
kw?: number;
|
|
57
|
+
ps?: number;
|
|
58
|
+
cc?: number;
|
|
59
|
+
c_ratio?: string | null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const props = defineProps({
|
|
63
|
+
engine: {
|
|
64
|
+
type: Object as PropType<Engine>,
|
|
65
|
+
required: true,
|
|
66
|
+
},
|
|
67
|
+
showComma: {
|
|
68
|
+
type: Boolean,
|
|
69
|
+
default: false,
|
|
70
|
+
required: false,
|
|
71
|
+
},
|
|
72
|
+
translations: {
|
|
73
|
+
type: Object as PropType<{
|
|
74
|
+
power?: string;
|
|
75
|
+
cc?: string;
|
|
76
|
+
compressionRatio?: string;
|
|
77
|
+
valves?: string;
|
|
78
|
+
euro?: string;
|
|
79
|
+
horsepowerUnit?: string; // 'PS' for German, 'KM' for Polish, 'HP' for English
|
|
80
|
+
}>,
|
|
81
|
+
default: () => ({
|
|
82
|
+
power: 'Power',
|
|
83
|
+
cc: 'CC',
|
|
84
|
+
compressionRatio: 'C. Ratio',
|
|
85
|
+
valves: 'Valves',
|
|
86
|
+
euro: 'Euro',
|
|
87
|
+
horsepowerUnit: 'PS',
|
|
88
|
+
}),
|
|
89
|
+
required: false,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const engineRef = ref<HTMLElement | null>(null);
|
|
94
|
+
let tippyInstance: Instance | null = null;
|
|
95
|
+
|
|
96
|
+
// Helper to get series value (supports both old and new API)
|
|
97
|
+
const getSerieValue = (): string => {
|
|
98
|
+
if (props.engine.serie && typeof props.engine.serie === 'object') {
|
|
99
|
+
return props.engine.serie.value;
|
|
100
|
+
}
|
|
101
|
+
// Backward compatibility - old API
|
|
102
|
+
const serie = props.engine.serie as any;
|
|
103
|
+
if (!serie) return '';
|
|
104
|
+
return serie === 3 ? 'EA288' : serie === 2 ? 'EA189' : `Serie ${serie}`;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Generate tooltip HTML content
|
|
108
|
+
const getTooltipContent = () => {
|
|
109
|
+
// Header section
|
|
110
|
+
let headerContent = `<strong>${props.engine.name || props.engine.code}</strong>`;
|
|
111
|
+
if (props.engine.info) {
|
|
112
|
+
headerContent += ` <span class="info">${props.engine.info}</span>`;
|
|
113
|
+
}
|
|
114
|
+
const serieValue = getSerieValue();
|
|
115
|
+
if (serieValue) {
|
|
116
|
+
headerContent += `<div class="series-badge">${serieValue}</div>`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const header = `<div class="tooltip-header">${headerContent}</div>`;
|
|
120
|
+
|
|
121
|
+
// Specs rows
|
|
122
|
+
const rows = [];
|
|
123
|
+
|
|
124
|
+
// Power (supports both new and old API structure)
|
|
125
|
+
const power = props.engine.power;
|
|
126
|
+
const oldKw = props.engine.kw;
|
|
127
|
+
const oldPs = props.engine.ps;
|
|
128
|
+
|
|
129
|
+
if (power || oldKw || oldPs) {
|
|
130
|
+
const powerValues = [];
|
|
131
|
+
const kw = power?.kw || oldKw;
|
|
132
|
+
const ps = power?.ps || oldPs;
|
|
133
|
+
const psLabel = power?.ps_label || props.translations.horsepowerUnit;
|
|
134
|
+
const powerLabel = power?.label || props.translations.power;
|
|
135
|
+
|
|
136
|
+
if (kw) powerValues.push(`${kw} kW`);
|
|
137
|
+
if (ps) powerValues.push(`${ps} ${psLabel}`);
|
|
138
|
+
|
|
139
|
+
if (powerValues.length) {
|
|
140
|
+
rows.push(`<div class="tooltip-row"><span class="tooltip-label">${powerLabel}:</span><span class="tooltip-value">${powerValues.join(' / ')}</span></div>`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Displacement (CC)
|
|
145
|
+
const displacement = props.engine.displacement;
|
|
146
|
+
const oldCc = props.engine.cc;
|
|
147
|
+
|
|
148
|
+
if (displacement || oldCc) {
|
|
149
|
+
const ccValue = displacement?.value || oldCc;
|
|
150
|
+
const ccLabel = displacement?.label || props.translations.cc;
|
|
151
|
+
|
|
152
|
+
if (ccValue) {
|
|
153
|
+
rows.push(`<div class="tooltip-row"><span class="tooltip-label">${ccLabel}:</span><span class="tooltip-value">${ccValue} cm³</span></div>`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Euro standard
|
|
158
|
+
const euro = props.engine.euro;
|
|
159
|
+
|
|
160
|
+
if (euro && typeof euro === 'object') {
|
|
161
|
+
if (euro.value) {
|
|
162
|
+
rows.push(`<div class="tooltip-row"><span class="tooltip-label">${euro.label}:</span><span class="tooltip-value">Euro ${euro.value}</span></div>`);
|
|
163
|
+
}
|
|
164
|
+
} else if (euro) {
|
|
165
|
+
// Backward compatibility - old API
|
|
166
|
+
rows.push(`<div class="tooltip-row"><span class="tooltip-label">${props.translations.euro}:</span><span class="tooltip-value">Euro ${euro}</span></div>`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const specsContent = rows.length
|
|
170
|
+
? `<div class="tooltip-specs">${rows.join('')}</div>`
|
|
171
|
+
: '';
|
|
172
|
+
|
|
173
|
+
return header + specsContent;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
onMounted(() => {
|
|
177
|
+
if (engineRef.value) {
|
|
178
|
+
tippyInstance = tippy(engineRef.value, {
|
|
179
|
+
content: getTooltipContent(),
|
|
180
|
+
allowHTML: true,
|
|
181
|
+
theme: 'sds',
|
|
182
|
+
placement: 'top',
|
|
183
|
+
arrow: true,
|
|
184
|
+
animation: 'shift-away',
|
|
185
|
+
duration: [200, 150],
|
|
186
|
+
maxWidth: 280,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
onUnmounted(() => {
|
|
192
|
+
if (tippyInstance) {
|
|
193
|
+
tippyInstance.destroy();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
</script>
|
|
197
|
+
|
|
198
|
+
<template>
|
|
199
|
+
<span
|
|
200
|
+
ref="engineRef"
|
|
201
|
+
class="engine-code"
|
|
202
|
+
:class="`engine-code-${engine.code}`"
|
|
203
|
+
>
|
|
204
|
+
{{ engine.code }}<span v-if="showComma">,</span>
|
|
205
|
+
</span>
|
|
206
|
+
</template>
|
|
207
|
+
|
|
208
|
+
<style scoped>
|
|
209
|
+
/* Engine Code Styles */
|
|
210
|
+
.engine-code {
|
|
211
|
+
@apply inline-block mr-1;
|
|
212
|
+
@apply underline decoration-dotted underline-offset-4 py-0.5;
|
|
213
|
+
@apply decoration-neutral-light cursor-default;
|
|
214
|
+
@apply transition-colors duration-200;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.engine-code:hover {
|
|
218
|
+
@apply decoration-blue-darker dark:decoration-blue-light;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* Semantic Engine Code Colors */
|
|
222
|
+
/* GTI Engines - Red */
|
|
223
|
+
.engine-code-CAVE,
|
|
224
|
+
.engine-code-CTHE,
|
|
225
|
+
.engine-code-DAJA,
|
|
226
|
+
.engine-code-DAYB {
|
|
227
|
+
@apply text-red-600 dark:text-red-500;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* WRC R Engine - Blue */
|
|
231
|
+
.engine-code-CDLJ {
|
|
232
|
+
@apply text-blue-600 dark:text-blue-500;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Special Blue Engines */
|
|
236
|
+
.engine-code-CPTA,
|
|
237
|
+
.engine-code-CZEA {
|
|
238
|
+
@apply text-blue-700 dark:text-blue-600;
|
|
239
|
+
}
|
|
240
|
+
</style>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import type { PropType } from 'vue';
|
|
4
|
+
import ProductEngine from './ProductEngine.vue';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
ProductEngines wrapper component
|
|
8
|
+
Displays a list of engine codes with tooltips
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface Engine {
|
|
12
|
+
id?: number;
|
|
13
|
+
code: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
info?: string | null;
|
|
16
|
+
serie?: {
|
|
17
|
+
value: string;
|
|
18
|
+
label: string;
|
|
19
|
+
} | number;
|
|
20
|
+
type?: {
|
|
21
|
+
value: string;
|
|
22
|
+
translated: string;
|
|
23
|
+
label: string;
|
|
24
|
+
};
|
|
25
|
+
power?: {
|
|
26
|
+
kw: number;
|
|
27
|
+
ps: number;
|
|
28
|
+
ps_label: string;
|
|
29
|
+
label: string;
|
|
30
|
+
};
|
|
31
|
+
date?: {
|
|
32
|
+
value: string;
|
|
33
|
+
label: string;
|
|
34
|
+
};
|
|
35
|
+
displacement?: {
|
|
36
|
+
value: number;
|
|
37
|
+
label: string;
|
|
38
|
+
};
|
|
39
|
+
compression_ratio?: {
|
|
40
|
+
value: string | null;
|
|
41
|
+
label: string;
|
|
42
|
+
};
|
|
43
|
+
valves?: {
|
|
44
|
+
value: number | null;
|
|
45
|
+
label: string;
|
|
46
|
+
};
|
|
47
|
+
euro?: {
|
|
48
|
+
value: number;
|
|
49
|
+
label: string;
|
|
50
|
+
} | number;
|
|
51
|
+
pivot?: any;
|
|
52
|
+
|
|
53
|
+
// Backward compatibility
|
|
54
|
+
kw?: number;
|
|
55
|
+
ps?: number;
|
|
56
|
+
cc?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const props = defineProps({
|
|
60
|
+
engines: {
|
|
61
|
+
type: Array as PropType<Engine[]>,
|
|
62
|
+
default: () => [],
|
|
63
|
+
required: true,
|
|
64
|
+
},
|
|
65
|
+
isPdp: {
|
|
66
|
+
type: Boolean,
|
|
67
|
+
default: false,
|
|
68
|
+
required: false,
|
|
69
|
+
},
|
|
70
|
+
translations: {
|
|
71
|
+
type: Object as PropType<{
|
|
72
|
+
power?: string;
|
|
73
|
+
cc?: string;
|
|
74
|
+
compressionRatio?: string;
|
|
75
|
+
valves?: string;
|
|
76
|
+
euro?: string;
|
|
77
|
+
horsepowerUnit?: string;
|
|
78
|
+
}>,
|
|
79
|
+
default: () => ({
|
|
80
|
+
power: 'Power',
|
|
81
|
+
cc: 'CC',
|
|
82
|
+
compressionRatio: 'C. Ratio',
|
|
83
|
+
valves: 'Valves',
|
|
84
|
+
euro: 'Euro',
|
|
85
|
+
horsepowerUnit: 'PS',
|
|
86
|
+
}),
|
|
87
|
+
required: false,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Sort engines by code
|
|
92
|
+
const sortedEngines = computed(() => {
|
|
93
|
+
if (!props.engines || !props.engines.length) return [];
|
|
94
|
+
return [...props.engines].sort((a, b) => {
|
|
95
|
+
return (a.code || '').localeCompare(b.code || '');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
</script>
|
|
99
|
+
|
|
100
|
+
<template>
|
|
101
|
+
<div v-if="sortedEngines.length" class="engines-list inline-flex flex-wrap items-center gap-x-0.5">
|
|
102
|
+
<ProductEngine
|
|
103
|
+
v-for="(engine, index) in sortedEngines"
|
|
104
|
+
:key="engine.id || index"
|
|
105
|
+
:engine="engine"
|
|
106
|
+
:show-comma="index !== sortedEngines.length - 1"
|
|
107
|
+
:translations="translations"
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<style scoped>
|
|
113
|
+
.engines-list {
|
|
114
|
+
@apply leading-none;
|
|
115
|
+
}
|
|
116
|
+
</style>
|
package/src/config.ts
CHANGED
|
@@ -41,6 +41,7 @@ export const SIDEBAR = [
|
|
|
41
41
|
{ text: 'Modal', link: '/components/modal/' },
|
|
42
42
|
{ text: 'PostHeader', link: '/components/post-header/' },
|
|
43
43
|
{ text: 'PR-Code', link: '/components/pr-code/' },
|
|
44
|
+
{ text: 'Product Engine', link: '/components/product-engine/' },
|
|
44
45
|
{ text: 'Product Number', link: '/components/product-number/' },
|
|
45
46
|
{ text: 'Product Tile', link: '/components/product-tile/' },
|
|
46
47
|
{ text: 'Quote', link: '/components/quote/' },
|
|
@@ -20,6 +20,11 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site).toString();
|
|
|
20
20
|
});
|
|
21
21
|
</script>
|
|
22
22
|
|
|
23
|
+
<script>
|
|
24
|
+
// Global Tooltips - Tippy.js
|
|
25
|
+
import '../scripts/tooltips.ts';
|
|
26
|
+
</script>
|
|
27
|
+
|
|
23
28
|
<html
|
|
24
29
|
dir={content.dir ?? 'ltr'}
|
|
25
30
|
lang={content.lang ?? 'en-us'}
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "ProductEngine"
|
|
3
|
+
layout: "../../layouts/MainLayout.astro"
|
|
4
|
+
---
|
|
5
|
+
import ProductEngine from '../../components/Product/ProductEngine.vue'
|
|
6
|
+
import ProductEngines from '../../components/Product/ProductEngines.vue'
|
|
7
|
+
|
|
8
|
+
# ProductEngine
|
|
9
|
+
|
|
10
|
+
Engine codes with detailed tooltips showing specifications like power, displacement, dates, and more.
|
|
11
|
+
|
|
12
|
+
## Single Engine Code
|
|
13
|
+
|
|
14
|
+
Display a single engine code with tooltip showing detailed engine information.
|
|
15
|
+
|
|
16
|
+
### import:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
import ProductEngine from 'spoko-design-system/src/components/Product/ProductEngine.vue'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Basic Usage (New API Structure):
|
|
23
|
+
|
|
24
|
+
<div class="component-preview">
|
|
25
|
+
<div class="bg-white p-6 w-full flex gap-2">
|
|
26
|
+
<ProductEngine client:load engine={{
|
|
27
|
+
code: "CAYA",
|
|
28
|
+
name: "1.6 TDI",
|
|
29
|
+
serie: { value: "EA189", label: "Seria silnika" },
|
|
30
|
+
power: { kw: 55, ps: 75, ps_label: "KM", label: "Moc" },
|
|
31
|
+
displacement: { value: 1598, label: "Pojemność" },
|
|
32
|
+
euro: { value: 5, label: "Norma Euro" }
|
|
33
|
+
}} />
|
|
34
|
+
<ProductEngine client:load engine={{
|
|
35
|
+
code: "CAYB",
|
|
36
|
+
name: "1.6 TDI",
|
|
37
|
+
serie: { value: "EA189", label: "Seria silnika" },
|
|
38
|
+
power: { kw: 66, ps: 90, ps_label: "KM", label: "Moc" },
|
|
39
|
+
displacement: { value: 1598, label: "Pojemność" },
|
|
40
|
+
euro: { value: 5, label: "Norma Euro" }
|
|
41
|
+
}} />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<!-- New API structure (with built-in translations) -->
|
|
47
|
+
<ProductEngine :engine="{
|
|
48
|
+
code: 'CAYA',
|
|
49
|
+
name: '1.6 TDI',
|
|
50
|
+
serie: { value: 'EA189', label: 'Seria silnika' },
|
|
51
|
+
power: { kw: 55, ps: 75, ps_label: 'KM', label: 'Moc' },
|
|
52
|
+
displacement: { value: 1598, label: 'Pojemność' },
|
|
53
|
+
euro: { value: 5, label: 'Norma Euro' }
|
|
54
|
+
}" />
|
|
55
|
+
|
|
56
|
+
<!-- Old API structure (backward compatible) -->
|
|
57
|
+
<ProductEngine
|
|
58
|
+
:engine="{ code: 'CAYA', name: '1.6 TDI', kw: 55, ps: 75, cc: 1598, serie: 3, euro: 5 }"
|
|
59
|
+
:translations="{ power: 'Moc', cc: 'Pojemność', euro: 'Euro', horsepowerUnit: 'KM' }"
|
|
60
|
+
/>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Special Engine Variants (Colored):
|
|
64
|
+
|
|
65
|
+
Engine codes for special editions are automatically color-coded:
|
|
66
|
+
|
|
67
|
+
<div class="component-preview">
|
|
68
|
+
<div class="bg-white p-6 w-full flex flex-wrap gap-3">
|
|
69
|
+
<div class="flex flex-col gap-1">
|
|
70
|
+
<small class="text-xs text-gray-500">GTI Engine (Red)</small>
|
|
71
|
+
<ProductEngine client:load engine={{
|
|
72
|
+
code: "CAVE",
|
|
73
|
+
name: "1.4 TSI",
|
|
74
|
+
power: { kw: 132, ps: 180, ps_label: "KM", label: "Moc" },
|
|
75
|
+
displacement: { value: 1390, label: "Pojemność" },
|
|
76
|
+
euro: { value: 5, label: "Norma Euro" }
|
|
77
|
+
}} />
|
|
78
|
+
</div>
|
|
79
|
+
<div class="flex flex-col gap-1">
|
|
80
|
+
<small class="text-xs text-gray-500">WRC Engine (Blue)</small>
|
|
81
|
+
<ProductEngine client:load engine={{
|
|
82
|
+
code: "CDLJ",
|
|
83
|
+
name: "1.6 TDI",
|
|
84
|
+
power: { kw: 165, ps: 220, ps_label: "KM", label: "Moc" },
|
|
85
|
+
displacement: { value: 1598, label: "Pojemność" },
|
|
86
|
+
euro: { value: 6, label: "Norma Euro" }
|
|
87
|
+
}} />
|
|
88
|
+
</div>
|
|
89
|
+
<div class="flex flex-col gap-1">
|
|
90
|
+
<small class="text-xs text-gray-500">Special Blue</small>
|
|
91
|
+
<ProductEngine client:load engine={{
|
|
92
|
+
code: "CPTA",
|
|
93
|
+
name: "1.0 TSI",
|
|
94
|
+
power: { kw: 70, ps: 95, ps_label: "KM", label: "Moc" },
|
|
95
|
+
displacement: { value: 999, label: "Pojemność" },
|
|
96
|
+
euro: { value: 6, label: "Norma Euro" }
|
|
97
|
+
}} />
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
```vue
|
|
103
|
+
<!-- GTI Engine - Red -->
|
|
104
|
+
<ProductEngine :engine="{
|
|
105
|
+
code: 'CAVE',
|
|
106
|
+
name: '1.4 TSI',
|
|
107
|
+
power: { kw: 132, ps: 180, ps_label: 'KM', label: 'Moc' },
|
|
108
|
+
displacement: { value: 1390, label: 'Pojemność' },
|
|
109
|
+
euro: { value: 5, label: 'Norma Euro' }
|
|
110
|
+
}" />
|
|
111
|
+
|
|
112
|
+
<!-- WRC Engine - Blue -->
|
|
113
|
+
<ProductEngine :engine="{
|
|
114
|
+
code: 'CDLJ',
|
|
115
|
+
name: '1.6 TDI',
|
|
116
|
+
power: { kw: 165, ps: 220, ps_label: 'KM', label: 'Moc' },
|
|
117
|
+
displacement: { value: 1598, label: 'Pojemność' },
|
|
118
|
+
euro: { value: 6, label: 'Norma Euro' }
|
|
119
|
+
}" />
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Engine List
|
|
123
|
+
|
|
124
|
+
Display multiple engine codes from an array (from API response).
|
|
125
|
+
|
|
126
|
+
### import:
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
import ProductEngines from 'spoko-design-system/src/components/Product/ProductEngines.vue'
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Usage:
|
|
133
|
+
|
|
134
|
+
<div class="component-preview">
|
|
135
|
+
<div class="bg-white p-6 w-full">
|
|
136
|
+
<ProductEngines client:load engines={[
|
|
137
|
+
{
|
|
138
|
+
id: 13,
|
|
139
|
+
code: "CAYA",
|
|
140
|
+
name: "1.6 TDI",
|
|
141
|
+
serie: { value: "EA189", label: "Seria silnika" },
|
|
142
|
+
power: { kw: 55, ps: 75, ps_label: "KM", label: "Moc" },
|
|
143
|
+
displacement: { value: 1598, label: "Pojemność" },
|
|
144
|
+
euro: { value: 5, label: "Norma Euro" }
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 14,
|
|
148
|
+
code: "CAYB",
|
|
149
|
+
name: "1.6 TDI",
|
|
150
|
+
serie: { value: "EA189", label: "Seria silnika" },
|
|
151
|
+
power: { kw: 66, ps: 90, ps_label: "KM", label: "Moc" },
|
|
152
|
+
displacement: { value: 1598, label: "Pojemność" },
|
|
153
|
+
euro: { value: 5, label: "Norma Euro" }
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
id: 15,
|
|
157
|
+
code: "CAYC",
|
|
158
|
+
name: "1.6 TDI",
|
|
159
|
+
serie: { value: "EA189", label: "Seria silnika" },
|
|
160
|
+
power: { kw: 77, ps: 105, ps_label: "KM", label: "Moc" },
|
|
161
|
+
displacement: { value: 1598, label: "Pojemność" },
|
|
162
|
+
euro: { value: 5, label: "Norma Euro" }
|
|
163
|
+
},
|
|
164
|
+
]} />
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
```vue
|
|
169
|
+
<ProductEngines :engines="[
|
|
170
|
+
{
|
|
171
|
+
id: 13,
|
|
172
|
+
code: 'CAYA',
|
|
173
|
+
name: '1.6 TDI',
|
|
174
|
+
serie: { value: 'EA189', label: 'Seria silnika' },
|
|
175
|
+
power: { kw: 55, ps: 75, ps_label: 'KM', label: 'Moc' },
|
|
176
|
+
displacement: { value: 1598, label: 'Pojemność' },
|
|
177
|
+
euro: { value: 5, label: 'Norma Euro' }
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: 14,
|
|
181
|
+
code: 'CAYB',
|
|
182
|
+
name: '1.6 TDI',
|
|
183
|
+
serie: { value: 'EA189', label: 'Seria silnika' },
|
|
184
|
+
power: { kw: 66, ps: 90, ps_label: 'KM', label: 'Moc' },
|
|
185
|
+
displacement: { value: 1598, label: 'Pojemność' },
|
|
186
|
+
euro: { value: 5, label: 'Norma Euro' }
|
|
187
|
+
}
|
|
188
|
+
]" />
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### With API Data:
|
|
192
|
+
|
|
193
|
+
When using data from the API, pass the `part_engines` array directly. The component automatically extracts translations from the nested structure:
|
|
194
|
+
|
|
195
|
+
```vue
|
|
196
|
+
<ProductEngines
|
|
197
|
+
:engines="product.part_engines"
|
|
198
|
+
:isPdp="true"
|
|
199
|
+
/>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Note**: The new API structure includes labels and translations, so you no longer need to pass the `translations` prop. The component will use labels from the API (e.g., "Moc", "Pojemność", "KM").
|
|
203
|
+
|
|
204
|
+
### API Response Structure:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"part_engines": [
|
|
209
|
+
{
|
|
210
|
+
"id": 13,
|
|
211
|
+
"code": "CAYA",
|
|
212
|
+
"name": "1.6 TDI",
|
|
213
|
+
"info": null,
|
|
214
|
+
"serie": {
|
|
215
|
+
"value": "EA189",
|
|
216
|
+
"label": "Seria silnika"
|
|
217
|
+
},
|
|
218
|
+
"type": {
|
|
219
|
+
"value": "diesel",
|
|
220
|
+
"translated": "Diesel",
|
|
221
|
+
"label": "Typ paliwa"
|
|
222
|
+
},
|
|
223
|
+
"power": {
|
|
224
|
+
"kw": 55,
|
|
225
|
+
"ps": 75,
|
|
226
|
+
"ps_label": "KM",
|
|
227
|
+
"label": "Moc"
|
|
228
|
+
},
|
|
229
|
+
"date": {
|
|
230
|
+
"value": "03/2009–05/2010",
|
|
231
|
+
"label": "Data produkcji"
|
|
232
|
+
},
|
|
233
|
+
"displacement": {
|
|
234
|
+
"value": 1598,
|
|
235
|
+
"label": "Pojemność"
|
|
236
|
+
},
|
|
237
|
+
"compression_ratio": {
|
|
238
|
+
"value": "16,5:1",
|
|
239
|
+
"label": "Stopień sprężania"
|
|
240
|
+
},
|
|
241
|
+
"valves": {
|
|
242
|
+
"value": 16,
|
|
243
|
+
"label": "Zawory"
|
|
244
|
+
},
|
|
245
|
+
"euro": {
|
|
246
|
+
"value": 5,
|
|
247
|
+
"formatted": "Norma Euro 5",
|
|
248
|
+
"label": "Norma Euro"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"id": 14,
|
|
253
|
+
"code": "CAYB",
|
|
254
|
+
"name": "1.6 TDI",
|
|
255
|
+
"info": null,
|
|
256
|
+
"serie": {
|
|
257
|
+
"value": "EA189",
|
|
258
|
+
"label": "Seria silnika"
|
|
259
|
+
},
|
|
260
|
+
"type": {
|
|
261
|
+
"value": "diesel",
|
|
262
|
+
"translated": "Diesel",
|
|
263
|
+
"label": "Typ paliwa"
|
|
264
|
+
},
|
|
265
|
+
"power": {
|
|
266
|
+
"kw": 66,
|
|
267
|
+
"ps": 90,
|
|
268
|
+
"ps_label": "KM",
|
|
269
|
+
"label": "Moc"
|
|
270
|
+
},
|
|
271
|
+
"date": {
|
|
272
|
+
"value": "03/2009–03/2014",
|
|
273
|
+
"label": "Data produkcji"
|
|
274
|
+
},
|
|
275
|
+
"displacement": {
|
|
276
|
+
"value": 1598,
|
|
277
|
+
"label": "Pojemność"
|
|
278
|
+
},
|
|
279
|
+
"compression_ratio": {
|
|
280
|
+
"value": "16,5:1",
|
|
281
|
+
"label": "Stopień sprężania"
|
|
282
|
+
},
|
|
283
|
+
"valves": {
|
|
284
|
+
"value": 16,
|
|
285
|
+
"label": "Zawory"
|
|
286
|
+
},
|
|
287
|
+
"euro": {
|
|
288
|
+
"value": 5,
|
|
289
|
+
"formatted": "Norma Euro 5",
|
|
290
|
+
"label": "Norma Euro"
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Props
|
|
298
|
+
|
|
299
|
+
### ProductEngine Props:
|
|
300
|
+
|
|
301
|
+
| Prop | Type | Required | Default | Description |
|
|
302
|
+
|------|------|----------|---------|-------------|
|
|
303
|
+
| `engine` | `Object` | Yes | - | Engine object with nested structure from API |
|
|
304
|
+
| `engine.code` | `String` | Yes | - | Engine code (e.g., "CAYA") |
|
|
305
|
+
| `engine.name` | `String` | No | - | Engine name (e.g., "1.6 TDI") |
|
|
306
|
+
| `engine.info` | `String` | No | - | Additional info shown in header |
|
|
307
|
+
| `engine.serie` | `Object` | No | - | Engine series object |
|
|
308
|
+
| `engine.serie.value` | `String` | No | - | Series value (e.g., "EA189", "EA288") |
|
|
309
|
+
| `engine.serie.label` | `String` | No | - | Series label (e.g., "Seria silnika") |
|
|
310
|
+
| `engine.power` | `Object` | No | - | Power object with kw, ps, labels |
|
|
311
|
+
| `engine.power.kw` | `Number` | No | - | Power in kilowatts |
|
|
312
|
+
| `engine.power.ps` | `Number` | No | - | Power in horsepower |
|
|
313
|
+
| `engine.power.ps_label` | `String` | No | - | Unit label (e.g., "KM", "PS") |
|
|
314
|
+
| `engine.power.label` | `String` | No | - | Power label (e.g., "Moc") |
|
|
315
|
+
| `engine.displacement` | `Object` | No | - | Displacement object |
|
|
316
|
+
| `engine.displacement.value` | `Number` | No | - | Displacement in cm³ |
|
|
317
|
+
| `engine.displacement.label` | `String` | No | - | Label (e.g., "Pojemność") |
|
|
318
|
+
| `engine.euro` | `Object` | No | - | Euro standard object |
|
|
319
|
+
| `engine.euro.value` | `Number` | No | - | Euro standard number |
|
|
320
|
+
| `engine.euro.label` | `String` | No | - | Label (e.g., "Norma Euro") |
|
|
321
|
+
| `engine.euro.formatted` | `String` | No | - | Formatted string (e.g., "Norma Euro 5") |
|
|
322
|
+
| `showComma` | `Boolean` | No | `false` | Show comma after code (for lists) |
|
|
323
|
+
| `translations` | `Object` | No | API labels | Fallback translations (used only with old API) |
|
|
324
|
+
|
|
325
|
+
**Note**: The component supports both the new nested API structure (with built-in labels) and the old flat structure for backward compatibility.
|
|
326
|
+
|
|
327
|
+
### ProductEngines Props:
|
|
328
|
+
|
|
329
|
+
| Prop | Type | Required | Default | Description |
|
|
330
|
+
|------|------|----------|---------|-------------|
|
|
331
|
+
| `engines` | `Array<Object>` | Yes | `[]` | Array of engine objects (new nested structure) |
|
|
332
|
+
| `isPdp` | `Boolean` | No | `false` | Product detail page styling |
|
|
333
|
+
| `translations` | `Object` | No | API labels | Fallback translations (used only with old API) |
|
|
334
|
+
|
|
335
|
+
## Features
|
|
336
|
+
|
|
337
|
+
- ✅ **Rich Tooltips**: Shows detailed engine specifications on hover (Tippy.js)
|
|
338
|
+
- ✅ **API-Driven Translations**: Labels and units come directly from API
|
|
339
|
+
- ✅ **Multi-language**: Supports Polish (KM), German (PS), English (HP)
|
|
340
|
+
- ✅ **Two-Tone Design**: Dark blue header with light body for better hierarchy
|
|
341
|
+
- ✅ **Semantic Colors**: Automatic color coding for special engines (GTI, WRC, etc.)
|
|
342
|
+
- ✅ **Clean Layout**: Flexbox-based design with semantic CSS classes
|
|
343
|
+
- ✅ **Smart Data**: Only shows relevant fields (power, displacement, euro)
|
|
344
|
+
- ✅ **Auto-sorting**: Engines automatically sorted alphabetically by code
|
|
345
|
+
- ✅ **SEO-Friendly**: Static HTML enhanced with client-side tooltips
|
|
346
|
+
- ✅ **Backward Compatible**: Works with both new and old API structures
|
|
347
|
+
- ✅ **Touch Friendly**: Works on mobile devices
|
|
348
|
+
|
|
349
|
+
## Engine Color Coding
|
|
350
|
+
|
|
351
|
+
Special engine codes are automatically color-coded:
|
|
352
|
+
|
|
353
|
+
| Engine Codes | Color | Description |
|
|
354
|
+
|--------------|-------|-------------|
|
|
355
|
+
| CAVE, CTHE, DAJA, DAYB | Red | GTI Performance engines |
|
|
356
|
+
| CDLJ | Blue | WRC/R Street engines |
|
|
357
|
+
| CPTA, CZEA | Light Blue | Special blue engines |
|
|
358
|
+
|
|
359
|
+
## Notes
|
|
360
|
+
|
|
361
|
+
- Hover over any engine code to see full specifications in a detailed tooltip
|
|
362
|
+
- Tooltips use Tippy.js with custom two-tone SDS theme
|
|
363
|
+
- **New API structure**: Labels come from API (e.g., "Moc", "Pojemność", "KM")
|
|
364
|
+
- **No manual translations needed**: The API provides all labels and units
|
|
365
|
+
- The component automatically extracts series value from nested structure
|
|
366
|
+
- Date field is not shown in tooltips (only power, displacement, and euro)
|
|
367
|
+
- Missing data fields are gracefully hidden
|
|
368
|
+
- Commas between engine codes are automatically handled in lists
|
|
369
|
+
- **Backward compatible**: Still works with old flat API structure
|
|
370
|
+
- Tooltip has dark blue header (#001e50) with light gray body (#f3f4f6)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import tippy from 'tippy.js';
|
|
2
|
+
import 'tippy.js/dist/tippy.css';
|
|
3
|
+
import '../styles/tippy-theme.css';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Global Tooltip Initializer
|
|
7
|
+
* Automatically enhances all elements with data-tippy-content attribute
|
|
8
|
+
* Works with static HTML - perfect for SEO and Astro static pages
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
function initTooltips() {
|
|
12
|
+
// Destroy existing tooltips to avoid duplicates
|
|
13
|
+
document.querySelectorAll('[data-tippy-content]').forEach((el: any) => {
|
|
14
|
+
if (el._tippy) {
|
|
15
|
+
el._tippy.destroy();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Initialize tooltips for all elements with data-tippy-content
|
|
20
|
+
tippy('[data-tippy-content]', {
|
|
21
|
+
theme: 'sds',
|
|
22
|
+
placement: 'top',
|
|
23
|
+
arrow: true,
|
|
24
|
+
animation: 'shift-away',
|
|
25
|
+
duration: [200, 150],
|
|
26
|
+
maxWidth: 280,
|
|
27
|
+
allowHTML: true, // Allow HTML content for rich tooltips
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Initialize on page load
|
|
32
|
+
if (typeof window !== 'undefined') {
|
|
33
|
+
// Initial load
|
|
34
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
35
|
+
initTooltips();
|
|
36
|
+
// Reinitialize after a short delay to catch Vue components
|
|
37
|
+
setTimeout(initTooltips, 100);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Reinitialize on Astro page transitions (for View Transitions)
|
|
41
|
+
document.addEventListener('astro:page-load', () => {
|
|
42
|
+
initTooltips();
|
|
43
|
+
// Reinitialize after a short delay to catch Vue components
|
|
44
|
+
setTimeout(initTooltips, 100);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Custom Tippy.js Theme for SDS
|
|
3
|
+
* Matches the design system colors and styling
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* SDS Theme for Tippy */
|
|
7
|
+
.tippy-box[data-theme~='sds'] {
|
|
8
|
+
background-color: #f3f4f6 !important; /* neutral-lightest */
|
|
9
|
+
color: #1e293b !important; /* slate-darkest */
|
|
10
|
+
font-size: 0.75rem;
|
|
11
|
+
line-height: 1.5;
|
|
12
|
+
border-radius: 0.5rem;
|
|
13
|
+
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
14
|
+
max-width: 280px;
|
|
15
|
+
border: 1px solid #e5e7eb; /* neutral-lighter */
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.tippy-box[data-theme~='sds'][data-placement^='top'] > .tippy-arrow::before {
|
|
19
|
+
border-top-color: #f3f4f6;
|
|
20
|
+
}
|
|
21
|
+
.tippy-box[data-theme~='sds'][data-placement^='bottom'] > .tippy-arrow::before {
|
|
22
|
+
border-bottom-color: #f3f4f6;
|
|
23
|
+
}
|
|
24
|
+
.tippy-box[data-theme~='sds'][data-placement^='left'] > .tippy-arrow::before {
|
|
25
|
+
border-left-color: #f3f4f6;
|
|
26
|
+
}
|
|
27
|
+
.tippy-box[data-theme~='sds'][data-placement^='right'] > .tippy-arrow::before {
|
|
28
|
+
border-right-color: #f3f4f6;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Content styling */
|
|
32
|
+
.tippy-box[data-theme~='sds'] .tippy-content {
|
|
33
|
+
padding: 0.5rem 0.75rem;
|
|
34
|
+
background-color: transparent !important;
|
|
35
|
+
color: #1e293b !important; /* slate-darkest */
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Remove padding for structured tooltips (with tooltip-header) */
|
|
39
|
+
.tippy-box[data-theme~='sds'] .tippy-content:has(.tooltip-header) {
|
|
40
|
+
padding: 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Force all child elements to inherit text color */
|
|
44
|
+
.tippy-box[data-theme~='sds'] * {
|
|
45
|
+
color: inherit;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Engine tooltip header - dark blue background */
|
|
49
|
+
.tippy-box[data-theme~='sds'] .tooltip-header {
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
padding: 0.375rem 0.5rem;
|
|
53
|
+
background-color: #001e50;
|
|
54
|
+
border-radius: 0.5rem 0.5rem 0 0;
|
|
55
|
+
color: white;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.tippy-box[data-theme~='sds'] .tooltip-header strong {
|
|
59
|
+
font-weight: 600;
|
|
60
|
+
color: white;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.tippy-box[data-theme~='sds'] .tooltip-header .info {
|
|
64
|
+
font-weight: 300;
|
|
65
|
+
margin-left: 0.5rem;
|
|
66
|
+
color: rgba(255, 255, 255, 0.9);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.tippy-box[data-theme~='sds'] .tooltip-header .series-badge {
|
|
70
|
+
margin-left: auto;
|
|
71
|
+
font-weight: 400;
|
|
72
|
+
color: #00b0f0;
|
|
73
|
+
font-size: 0.75rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Engine tooltip specs */
|
|
77
|
+
.tippy-box[data-theme~='sds'] .tooltip-specs {
|
|
78
|
+
padding: 0.375rem 0.5rem;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.tippy-box[data-theme~='sds'] .tooltip-row {
|
|
82
|
+
display: flex;
|
|
83
|
+
justify-content: space-between;
|
|
84
|
+
align-items: center;
|
|
85
|
+
padding: 0.25rem 0;
|
|
86
|
+
border-bottom: 1px solid #e5e7eb;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.tippy-box[data-theme~='sds'] .tooltip-row:last-child {
|
|
90
|
+
border-bottom: none;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.tippy-box[data-theme~='sds'] .tooltip-label {
|
|
94
|
+
font-size: 0.7rem;
|
|
95
|
+
color: #64748B;
|
|
96
|
+
font-weight: 400;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.tippy-box[data-theme~='sds'] .tooltip-value {
|
|
100
|
+
font-size: 0.75rem;
|
|
101
|
+
color: #1e293b;
|
|
102
|
+
font-weight: 500;
|
|
103
|
+
margin-left: 1rem;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Engine tooltip table styling */
|
|
107
|
+
.tippy-box[data-theme~='sds'] table {
|
|
108
|
+
width: 100%;
|
|
109
|
+
margin-top: 0.25rem;
|
|
110
|
+
border-collapse: collapse;
|
|
111
|
+
color: white;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.tippy-box[data-theme~='sds'] th {
|
|
115
|
+
text-align: left;
|
|
116
|
+
padding: 0.125rem 0.5rem 0.125rem 0;
|
|
117
|
+
color: rgba(255, 255, 255, 0.7) !important;
|
|
118
|
+
font-weight: 400;
|
|
119
|
+
font-size: 0.7rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.tippy-box[data-theme~='sds'] td {
|
|
123
|
+
padding: 0.125rem 0;
|
|
124
|
+
font-weight: 500;
|
|
125
|
+
text-align: right;
|
|
126
|
+
color: white !important;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.tippy-box[data-theme~='sds'] strong {
|
|
130
|
+
font-weight: 600;
|
|
131
|
+
}
|