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
- # Run format check
16
- echo "🎨 Checking code formatting..."
17
- pnpm run format:check
18
- if [ $? -ne 0 ]; then
19
- echo "❌ Format check failed! Run 'pnpm run format' to fix."
20
- exit 1
21
- fi
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..."
@@ -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
- "eslint.validate": [
16
- "javascript",
17
- "javascriptreact",
18
- "typescript",
19
- "typescriptreact",
20
- "vue"
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spoko-design-system",
3
- "version": "1.21.1",
3
+ "version": "1.23.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./index.ts",
@@ -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
- itemprop="item"
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
- itemprop="itemListElement"
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
- itemprop="item"
97
+ v-bind="withMicrodata ? { itemprop: 'item' } : {}"
78
98
  :title="`Polo 6R ${crumb.name}`"
79
99
  >
80
- <strong class="font-normal" itemprop="name">{{ crumb.name }}</strong>
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
- itemprop="item"
109
+ v-bind="withMicrodata ? { itemprop: 'item' } : {}"
88
110
  >
89
- <span class="font-normal" itemprop="name">
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">&nbsp;{{ productNumber }}</b>
92
114
  </span>
93
115
  </a>
94
116
 
95
- <meta itemprop="position" :content="String(props.showHome ? index + 2 : index + 1)" />
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
- itemscope
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
- itemprop="hasPart"
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 itemprop="url" href={getTranslatedLink(`/${category.slug}/`)} class="carousel-item">
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="name">
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