spoko-design-system 1.21.1 → 1.23.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/.husky/pre-commit
CHANGED
|
@@ -12,13 +12,14 @@ if git diff --cached --name-only | xargs grep -n "console\\.log" 2>/dev/null; th
|
|
|
12
12
|
echo " Consider removing them before committing to production"
|
|
13
13
|
fi
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
echo "🎨
|
|
17
|
-
pnpm run format
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
# Auto-format code
|
|
16
|
+
echo "🎨 Auto-formatting code..."
|
|
17
|
+
pnpm run format
|
|
18
|
+
|
|
19
|
+
# Re-add formatted files to staging
|
|
20
|
+
git add -u
|
|
21
|
+
|
|
22
|
+
echo "✅ Code formatted successfully!"
|
|
22
23
|
|
|
23
24
|
# Run linting
|
|
24
25
|
echo "🔍 Running linter..."
|
package/.vscode/settings.json
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"editor.formatOnSave": true,
|
|
3
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
3
4
|
"editor.codeActionsOnSave": {
|
|
4
5
|
"source.fixAll.eslint": "explicit"
|
|
5
6
|
},
|
|
6
7
|
"[vue]": {
|
|
7
8
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
8
9
|
},
|
|
10
|
+
"[astro]": {
|
|
11
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
12
|
+
},
|
|
9
13
|
"[typescript]": {
|
|
10
14
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
11
15
|
},
|
|
12
16
|
"[javascript]": {
|
|
13
17
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
14
18
|
},
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
]
|
|
19
|
+
"[json]": {
|
|
20
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
21
|
+
},
|
|
22
|
+
"[markdown]": {
|
|
23
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
24
|
+
},
|
|
25
|
+
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue"]
|
|
22
26
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [1.23.0](https://github.com/polo-blue/sds/compare/v1.22.0...v1.23.0) (2025-12-15)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **breadcrumbs:** add withMicrodata prop to control Schema.org rendering ([0ca52cc](https://github.com/polo-blue/sds/commit/0ca52cccb90a30f532cdb381e428480f59a6d433))
|
|
6
|
+
|
|
7
|
+
## [1.22.0](https://github.com/polo-blue/sds/compare/v1.21.1...v1.22.0) (2025-12-15)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **category:** add withMicrodata prop to control Schema.org rendering ([95c96cd](https://github.com/polo-blue/sds/commit/95c96cd71ec15a233432abec2d0c0f109ccd8f5d))
|
|
12
|
+
|
|
1
13
|
## [1.21.1](https://github.com/polo-blue/sds/compare/v1.21.0...v1.21.1) (2025-12-15)
|
|
2
14
|
|
|
3
15
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ export interface Breadcrumb {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
import type { PropType } from 'vue';
|
|
8
|
+
import { computed } from 'vue';
|
|
8
9
|
|
|
9
10
|
const props = defineProps({
|
|
10
11
|
showBack: {
|
|
@@ -29,11 +30,36 @@ const props = defineProps({
|
|
|
29
30
|
required: false,
|
|
30
31
|
default: null,
|
|
31
32
|
},
|
|
33
|
+
withMicrodata: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
required: false,
|
|
36
|
+
default: true,
|
|
37
|
+
},
|
|
32
38
|
});
|
|
33
39
|
|
|
34
40
|
const isLast = (index: number) => {
|
|
35
41
|
return index === props.breadcrumbs.length - 1;
|
|
36
42
|
};
|
|
43
|
+
|
|
44
|
+
// Microdata attributes - only added when withMicrodata is true
|
|
45
|
+
const listMicrodata = computed(() =>
|
|
46
|
+
props.withMicrodata
|
|
47
|
+
? {
|
|
48
|
+
itemscope: true,
|
|
49
|
+
itemtype: 'https://schema.org/BreadcrumbList',
|
|
50
|
+
}
|
|
51
|
+
: {}
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const listItemMicrodata = computed(() =>
|
|
55
|
+
props.withMicrodata
|
|
56
|
+
? {
|
|
57
|
+
itemprop: 'itemListElement',
|
|
58
|
+
itemscope: true,
|
|
59
|
+
itemtype: 'https://schema.org/ListItem',
|
|
60
|
+
}
|
|
61
|
+
: {}
|
|
62
|
+
);
|
|
37
63
|
</script>
|
|
38
64
|
|
|
39
65
|
<template>
|
|
@@ -45,28 +71,22 @@ const isLast = (index: number) => {
|
|
|
45
71
|
</button>
|
|
46
72
|
</li>
|
|
47
73
|
</ul>
|
|
48
|
-
<ul
|
|
49
|
-
class="breadcrumbs-base overflow-x-auto overflow-y-hidden sm:mr-12"
|
|
50
|
-
itemscope
|
|
51
|
-
itemtype="https://schema.org/BreadcrumbList"
|
|
52
|
-
>
|
|
74
|
+
<ul class="breadcrumbs-base overflow-x-auto overflow-y-hidden sm:mr-12" v-bind="listMicrodata">
|
|
53
75
|
<li v-if="props.showHome" class="breadcrumb-item">
|
|
54
76
|
<a
|
|
55
77
|
href="/"
|
|
56
78
|
class="breadcrumb-link flex items-center px-3 sm:px-0 py-4.25 sm:py-1 hover:text-brand-secondary whitespace-nowrap translate-y-0 text-sm my-auto"
|
|
57
79
|
:title="props.textBack"
|
|
58
|
-
|
|
80
|
+
v-bind="withMicrodata ? { itemprop: 'item' } : {}"
|
|
59
81
|
i-carbon-home
|
|
60
82
|
/>
|
|
61
|
-
<meta itemprop="position" content="1" />
|
|
83
|
+
<meta v-if="withMicrodata" itemprop="position" content="1" />
|
|
62
84
|
</li>
|
|
63
85
|
<li
|
|
64
86
|
v-for="(crumb, index) in breadcrumbs"
|
|
65
87
|
:key="index"
|
|
66
88
|
class="breadcrumb-item"
|
|
67
|
-
|
|
68
|
-
itemscope
|
|
69
|
-
itemtype="https://schema.org/ListItem"
|
|
89
|
+
v-bind="listItemMicrodata"
|
|
70
90
|
>
|
|
71
91
|
<span v-if="index > 0 || props.showHome" class="text-gray-400 px-1 py-4.25 sm:py-1">/</span>
|
|
72
92
|
|
|
@@ -74,25 +94,31 @@ const isLast = (index: number) => {
|
|
|
74
94
|
v-if="!isLast(index)"
|
|
75
95
|
:href="crumb.path"
|
|
76
96
|
class="breadcrumb-link"
|
|
77
|
-
|
|
97
|
+
v-bind="withMicrodata ? { itemprop: 'item' } : {}"
|
|
78
98
|
:title="`Polo 6R ${crumb.name}`"
|
|
79
99
|
>
|
|
80
|
-
<strong class="font-normal"
|
|
100
|
+
<strong class="font-normal" v-bind="withMicrodata ? { itemprop: 'name' } : {}">
|
|
101
|
+
{{ crumb.name }}
|
|
102
|
+
</strong>
|
|
81
103
|
</a>
|
|
82
104
|
<a
|
|
83
105
|
v-else
|
|
84
106
|
:href="crumb.path"
|
|
85
107
|
class="breadcrumb-link breadcrumb-link-disabled"
|
|
86
108
|
:title="`Polo 6R ${crumb.name} ${productNumber}`"
|
|
87
|
-
|
|
109
|
+
v-bind="withMicrodata ? { itemprop: 'item' } : {}"
|
|
88
110
|
>
|
|
89
|
-
<span class="font-normal"
|
|
111
|
+
<span class="font-normal" v-bind="withMicrodata ? { itemprop: 'name' } : {}">
|
|
90
112
|
<span v-html="crumb.name" />
|
|
91
113
|
<b v-if="productNumber" class="hidden sm:inline font-normal ml-1"> {{ productNumber }}</b>
|
|
92
114
|
</span>
|
|
93
115
|
</a>
|
|
94
116
|
|
|
95
|
-
<meta
|
|
117
|
+
<meta
|
|
118
|
+
v-if="withMicrodata"
|
|
119
|
+
itemprop="position"
|
|
120
|
+
:content="String(props.showHome ? index + 2 : index + 1)"
|
|
121
|
+
/>
|
|
96
122
|
</li>
|
|
97
123
|
</ul>
|
|
98
124
|
</nav>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
const { activeCategorySlug, class: className } = Astro.props;
|
|
2
|
+
const { activeCategorySlug, class: className, withMicrodata = true } = Astro.props;
|
|
3
3
|
|
|
4
4
|
import { getTranslatedLink } from '@utils/text/getTranslatedLink';
|
|
5
5
|
import { getMainCategoryList } from '@utils/category/getMainCategoryList';
|
|
@@ -10,6 +10,22 @@ const imgDomain = 'https://api.polo.blue/img/';
|
|
|
10
10
|
|
|
11
11
|
const activeIndex =
|
|
12
12
|
activeCategorySlug && categories ? categories.map(a => a.slug).findIndex(e => e === activeCategorySlug) : 0;
|
|
13
|
+
|
|
14
|
+
// Microdata attributes - only added when withMicrodata is true
|
|
15
|
+
const containerMicrodata = withMicrodata
|
|
16
|
+
? {
|
|
17
|
+
itemscope: true,
|
|
18
|
+
itemtype: 'https://schema.org/SiteNavigationElement',
|
|
19
|
+
}
|
|
20
|
+
: {};
|
|
21
|
+
|
|
22
|
+
const slideMicrodata = withMicrodata
|
|
23
|
+
? {
|
|
24
|
+
itemprop: 'hasPart',
|
|
25
|
+
itemscope: true,
|
|
26
|
+
itemtype: 'https://schema.org/SiteNavigationElement',
|
|
27
|
+
}
|
|
28
|
+
: {};
|
|
13
29
|
---
|
|
14
30
|
|
|
15
31
|
<!-- <div class={`cat-menu ${className ? className : ''}`}
|
|
@@ -21,8 +37,7 @@ const activeIndex =
|
|
|
21
37
|
<swiper-container
|
|
22
38
|
class={`categories-carousel flex pb-1 sm:pb-0 bg-white cat-menu ${className ? className : ''}`}
|
|
23
39
|
data-pagefind-ignore
|
|
24
|
-
|
|
25
|
-
itemtype="https://schema.org/SiteNavigationElement"
|
|
40
|
+
{...containerMicrodata}
|
|
26
41
|
transition:persist={`catcarousel${activeIndex}`}
|
|
27
42
|
transition:animate="none"
|
|
28
43
|
data-active={activeIndex}
|
|
@@ -39,13 +54,15 @@ const activeIndex =
|
|
|
39
54
|
{
|
|
40
55
|
categories.map(category => (
|
|
41
56
|
<swiper-slide
|
|
42
|
-
|
|
43
|
-
itemscope
|
|
44
|
-
itemtype="https://schema.org/SiteNavigationElement"
|
|
57
|
+
{...slideMicrodata}
|
|
45
58
|
role="presentation"
|
|
46
59
|
class={`swiper-slide cats-slide group ${category.slug === activeCategorySlug ? 'active' : ''}`}
|
|
47
60
|
>
|
|
48
|
-
<a
|
|
61
|
+
<a
|
|
62
|
+
{...(withMicrodata ? { itemprop: 'url' } : {})}
|
|
63
|
+
href={getTranslatedLink(`/${category.slug}/`)}
|
|
64
|
+
class="carousel-item"
|
|
65
|
+
>
|
|
49
66
|
<Image
|
|
50
67
|
src={`${imgDomain}${category.photo}`}
|
|
51
68
|
alt={category.name}
|
|
@@ -58,7 +75,7 @@ const activeIndex =
|
|
|
58
75
|
/>
|
|
59
76
|
<div class="swiper-lazy-preloader" />
|
|
60
77
|
|
|
61
|
-
<div class="cat-name" itemprop
|
|
78
|
+
<div class="cat-name" {...(withMicrodata ? { itemprop: 'name' } : {})}>
|
|
62
79
|
{category.name}
|
|
63
80
|
</div>
|
|
64
81
|
</a>
|
|
@@ -102,6 +102,35 @@ https://schema.org/ListItem
|
|
|
102
102
|
/>
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
## Props
|
|
106
|
+
|
|
107
|
+
| Prop | Type | Default | Description |
|
|
108
|
+
| --------------- | --------- | ------- | --------------------------------------------------------------------------- |
|
|
109
|
+
| `breadcrumbs` | Array | - | Array of breadcrumb objects with `name` and `path` properties (required) |
|
|
110
|
+
| `showBack` | Boolean | `false` | Show back button |
|
|
111
|
+
| `textBack` | String | `'Back'`| Text for back button title |
|
|
112
|
+
| `showHome` | Boolean | `false` | Show home icon as first breadcrumb |
|
|
113
|
+
| `productNumber` | String | `null` | Product number to display after last breadcrumb (mobile hidden) |
|
|
114
|
+
| `withMicrodata` | Boolean | `true` | Include Schema.org BreadcrumbList microdata (set to `false` for duplicates) |
|
|
115
|
+
|
|
116
|
+
## Microdata Control
|
|
117
|
+
|
|
118
|
+
When rendering breadcrumbs multiple times on the same page (e.g., mobile and desktop versions), use `withMicrodata` to prevent duplicate Schema.org markup:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
<!-- Desktop version - WITH microdata (default) -->
|
|
122
|
+
<Breadcrumbs
|
|
123
|
+
breadcrumbs={[...]}
|
|
124
|
+
class="hidden md:block"
|
|
125
|
+
/>
|
|
126
|
+
|
|
127
|
+
<!-- Mobile version - WITHOUT microdata -->
|
|
128
|
+
<Breadcrumbs
|
|
129
|
+
breadcrumbs={[...]}
|
|
130
|
+
class="block md:hidden"
|
|
131
|
+
:withMicrodata="false"
|
|
132
|
+
/>
|
|
133
|
+
```
|
|
105
134
|
|
|
106
135
|
### Schema support:
|
|
107
136
|
- https://developers.google.com/search/docs/appearance/structured-data/breadcrumb?hl=en
|