spoko-design-system 1.3.3 → 1.3.5

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.
Files changed (46) hide show
  1. package/.github/workflows/claude.yml +1 -1
  2. package/.prettierrc +1 -0
  3. package/CHANGELOG.md +12 -0
  4. package/package.json +15 -15
  5. package/src/components/Breadcrumbs.vue +8 -5
  6. package/src/components/ButtonCopy.astro +7 -2
  7. package/src/components/Card.astro +4 -1
  8. package/src/components/Category/CategoriesCarousel.astro +8 -2
  9. package/src/components/Category/CategoryDetails.astro +30 -11
  10. package/src/components/Category/CategoryTile.astro +11 -2
  11. package/src/components/Category/CategoryViewToggler.astro +8 -2
  12. package/src/components/Date.astro +4 -1
  13. package/src/components/FaqItem.astro +14 -3
  14. package/src/components/HandDrive.astro +5 -1
  15. package/src/components/Header/Header.astro +14 -3
  16. package/src/components/Header/SkipToContent.astro +5 -1
  17. package/src/components/Input.vue +3 -2
  18. package/src/components/Jumbotron/index.astro +37 -7
  19. package/src/components/Jumbotron/variants/Default.astro +4 -1
  20. package/src/components/Jumbotron/variants/Hero.astro +9 -2
  21. package/src/components/Jumbotron/variants/Post.astro +13 -3
  22. package/src/components/Jumbotron/variants/PostSplit.astro +13 -3
  23. package/src/components/Jumbotron.astro +12 -3
  24. package/src/components/LanguageSuggestion.astro +4 -1
  25. package/src/components/MainInput.vue +3 -2
  26. package/src/components/Modal.astro +9 -2
  27. package/src/components/PageContent.astro +4 -1
  28. package/src/components/PostHeader.astro +13 -3
  29. package/src/components/Product/ProductDetails.vue +2 -2
  30. package/src/components/Product/ProductLink.astro +17 -4
  31. package/src/components/Product/ProductLink.vue +3 -3
  32. package/src/components/Product/ProductLinkInfo.astro +12 -3
  33. package/src/components/Product/ProductModel.vue +2 -3
  34. package/src/components/Product/ProductNumber.astro +23 -5
  35. package/src/components/ProductDetailsList.vue +9 -6
  36. package/src/components/ProductTile.astro +13 -3
  37. package/src/components/ReloadPrompt.astro +5 -1
  38. package/src/components/SlimBanner.vue +6 -4
  39. package/src/components/layout/CallToAction.astro +4 -1
  40. package/src/components/layout/Header.astro +12 -2
  41. package/src/layouts/Layout.astro +9 -2
  42. package/src/layouts/MainLayout.astro +17 -4
  43. package/src/layouts/partials/HeadCommon.astro +24 -7
  44. package/src/layouts/partials/HeadSEO.astro +44 -11
  45. package/src/pages/components/icons.astro +4 -1
  46. package/src/pages/index.astro +58 -14
@@ -6,7 +6,16 @@ const props = Astro.props as Props;
6
6
  ---
7
7
 
8
8
  <BaseJumbotron {...props}>
9
- <slot name="intro" slot="intro" />
10
- <slot name="subtitle" slot="subtitle" />
11
- <slot name="cta-content" slot="cta-content" />
9
+ <slot
10
+ name="intro"
11
+ slot="intro"
12
+ />
13
+ <slot
14
+ name="subtitle"
15
+ slot="subtitle"
16
+ />
17
+ <slot
18
+ name="cta-content"
19
+ slot="cta-content"
20
+ />
12
21
  </BaseJumbotron>
@@ -33,7 +33,10 @@ const targetPath = customPath
33
33
  ]}
34
34
  role="alert"
35
35
  >
36
- <a href={targetPath} class="flex items-center gap-2 font-medium hover:underline">
36
+ <a
37
+ href={targetPath}
38
+ class="flex items-center gap-2 font-medium hover:underline"
39
+ >
37
40
  {showIcon && <span class="material-icons-outlined text-sm">translate</span>}
38
41
  {new Intl.DisplayNames([preferredLocale], { type: 'language' }).of(preferredLocale)}
39
42
  </a>
@@ -8,10 +8,11 @@ const props = defineProps<{
8
8
  <label class="group text-left w-full max-w-xs flex flex-col">
9
9
  <span
10
10
  class="group-hover:text-blue-medium ml-2 text-slate-600 text-sm group-focus-within:text-blue-medium"
11
- >{{ props.label }}</span>
11
+ >{{ props.label }}</span
12
+ >
12
13
  <input
13
14
  class="group-hover:border-blue-lightest border px-4 py-2 transition-colors rounded-md w-full focus:ring focus:outline-none focus:border-blue-medium"
14
15
  type="text"
15
- >
16
+ />
16
17
  </label>
17
18
  </template>
@@ -17,9 +17,16 @@ import Button from '../components/Button.vue';
17
17
  }
18
18
  </style>
19
19
 
20
- <Button primary onclick={`window.${id}.showModal()`}>{open}</Button>
20
+ <Button
21
+ primary
22
+ onclick={`window.${id}.showModal()`}
23
+ >{open}</Button
24
+ >
21
25
 
22
- <dialog id={id} class="p-6">
26
+ <dialog
27
+ id={id}
28
+ class="p-6"
29
+ >
23
30
  <slot name="main" />
24
31
  <form method="dialog">
25
32
  <slot name="close" />
@@ -1,4 +1,7 @@
1
- <article id="article" class="content">
1
+ <article
2
+ id="article"
3
+ class="content"
4
+ >
2
5
  <section class="main-section">
3
6
  <slot />
4
7
  </section>
@@ -31,11 +31,18 @@ import Date from './Date.astro';
31
31
  >
32
32
  {title}
33
33
  </h1>
34
- <PostCategories categories={categories} lang={lang} />
34
+ <PostCategories
35
+ categories={categories}
36
+ lang={lang}
37
+ />
35
38
  <div class="order-3 flex items-center text-gray-1 00">
36
39
  {
37
40
  author && (
38
- <span class="text-sm" title={author.firstName} data-pagefind-ignore>
41
+ <span
42
+ class="text-sm"
43
+ title={author.firstName}
44
+ data-pagefind-ignore
45
+ >
39
46
  {author.name}
40
47
  </span>
41
48
  )
@@ -46,7 +53,10 @@ import Date from './Date.astro';
46
53
  </div>
47
54
  </div>
48
55
  <div class="featured-image">
49
- <img src={image} alt={title} />
56
+ <img
57
+ src={image}
58
+ alt={title}
59
+ />
50
60
  </div>
51
61
  </header>
52
62
 
@@ -116,8 +116,8 @@ const props = defineProps({
116
116
  <span
117
117
  v-else-if="
118
118
  detail.value !== undefined &&
119
- detail.id === 'for-exterior-colour' &&
120
- detail.isArrayValue
119
+ detail.id === 'for-exterior-colour' &&
120
+ detail.isArrayValue
121
121
  "
122
122
  class=""
123
123
  >
@@ -82,7 +82,11 @@ const nameFormatted = removeSemicolon(productName.toString());
82
82
  }}
83
83
  />
84
84
  ) : (
85
- <img src="/1x1.png" class="bg-neutral-lightest/70" alt={productName} />
85
+ <img
86
+ src="/1x1.png"
87
+ class="bg-neutral-lightest/70"
88
+ alt={productName}
89
+ />
86
90
  )}
87
91
  </div>
88
92
 
@@ -103,12 +107,21 @@ const nameFormatted = removeSemicolon(productName.toString());
103
107
  set:html={nameFormatted}
104
108
  />
105
109
 
106
- <ProductNumber productNumber={product.number} copyDisabled={true} />
110
+ <ProductNumber
111
+ productNumber={product.number}
112
+ copyDisabled={true}
113
+ />
107
114
 
108
115
  {index !== null && (
109
116
  <>
110
- <meta itemprop="position" content={index.toString()} />
111
- <meta itemprop="name" content={nameFormatted} />
117
+ <meta
118
+ itemprop="position"
119
+ content={index.toString()}
120
+ />
121
+ <meta
122
+ itemprop="name"
123
+ content={nameFormatted}
124
+ />
112
125
  </>
113
126
  )}
114
127
  </div>
@@ -13,7 +13,7 @@
13
13
  src="/1x1.png"
14
14
  class="bg-neutral-lightest/70"
15
15
  :alt="productName"
16
- >
16
+ />
17
17
  </slot>
18
18
  </div>
19
19
 
@@ -42,11 +42,11 @@
42
42
  <meta
43
43
  itemprop="position"
44
44
  :content="index.toString()"
45
- >
45
+ />
46
46
  <meta
47
47
  itemprop="name"
48
48
  :content="nameFormatted"
49
- >
49
+ />
50
50
  </template>
51
51
  </div>
52
52
  </div>
@@ -23,12 +23,21 @@ const { product, nameFormatted, price, url, index, bigTile } = Astro.props;
23
23
  title={product.number}
24
24
  set:html={nameFormatted}
25
25
  />
26
- <ProductNumber productNumber={product.number} copyDisabled={true} />
26
+ <ProductNumber
27
+ productNumber={product.number}
28
+ copyDisabled={true}
29
+ />
27
30
  {
28
31
  index !== null && (
29
32
  <>
30
- <meta itemprop="position" content={index} />
31
- <meta itemprop="name" content={nameFormatted} />
33
+ <meta
34
+ itemprop="position"
35
+ content={index}
36
+ />
37
+ <meta
38
+ itemprop="name"
39
+ content={nameFormatted}
40
+ />
32
41
  </>
33
42
  )
34
43
  }
@@ -13,9 +13,8 @@ const props = defineProps({
13
13
  <strong
14
14
  class="product-model"
15
15
  :data-pagefind-filter="`model:${props.carModel.name}`"
16
- >{{
17
- props.carModel.name
18
- }}</strong>
16
+ >{{ props.carModel.name }}</strong
17
+ >
19
18
  </template>
20
19
  <style>
21
20
  .product-model:not(:last-child) {
@@ -29,19 +29,37 @@ const FormattedWrapper = isPdp ? 'h3' : 'div';
29
29
  {
30
30
  productNumber && formatted && (
31
31
  <div class={classNames}>
32
- <div class={['p-number', small ? 'w-full' : ''].join(' ')} itemprop="identifier">
33
- <ProductWrapper id={productNumber} class="product-code">
32
+ <div
33
+ class={['p-number', small ? 'w-full' : ''].join(' ')}
34
+ itemprop="identifier"
35
+ >
36
+ <ProductWrapper
37
+ id={productNumber}
38
+ class="product-code"
39
+ >
34
40
  {productNumber}
35
41
  </ProductWrapper>
36
42
 
37
- {big && <ButtonCopy productNumber={productNumber} texts={buttonTexts} tooltipClasses="" />}
43
+ {big && (
44
+ <ButtonCopy
45
+ productNumber={productNumber}
46
+ texts={buttonTexts}
47
+ tooltipClasses=""
48
+ />
49
+ )}
38
50
  </div>
39
51
 
40
52
  <div class={['code-formatted', trackingClass].join(' ')}>
41
- <div class="relative inset-0" data-pagefind-ignore>
53
+ <div
54
+ class="relative inset-0"
55
+ data-pagefind-ignore
56
+ >
42
57
  {formatted.dot}
43
58
  </div>
44
- <div class="absolute inset-0" data-pagefind-ignore>
59
+ <div
60
+ class="absolute inset-0"
61
+ data-pagefind-ignore
62
+ >
45
63
  {formatted.dash}
46
64
  </div>
47
65
  <FormattedWrapper class="number-secondary">{formatted.standard}</FormattedWrapper>
@@ -38,10 +38,13 @@ const isHtmlValue = (value: unknown): boolean => {
38
38
 
39
39
  // Function for specifying header text
40
40
  const getHeaderText = (row: TableItem) => {
41
- return row.label || row.id
42
- .split('-')
43
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
44
- .join(' ');
41
+ return (
42
+ row.label ||
43
+ row.id
44
+ .split('-')
45
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
46
+ .join(' ')
47
+ );
45
48
  };
46
49
 
47
50
  // Function to determine the icon class for a link type
@@ -77,8 +80,8 @@ const validatedItems = computed(() => {
77
80
  </slot>
78
81
  </caption>
79
82
  <colgroup>
80
- <col class="details-table-col">
81
- <col class="details-table-col">
83
+ <col class="details-table-col" />
84
+ <col class="details-table-col" />
82
85
  </colgroup>
83
86
  <tbody>
84
87
  <tr
@@ -19,7 +19,11 @@ import ProductNumber from './Product/ProductNumber.astro';
19
19
  }}
20
20
  />
21
21
  ) : (
22
- <img src="/1x1.png" class="bg-gray-100/70" alt={productObject.name} />
22
+ <img
23
+ src="/1x1.png"
24
+ class="bg-gray-100/70"
25
+ alt={productObject.name}
26
+ />
23
27
  )}
24
28
  </div>
25
29
 
@@ -41,8 +45,14 @@ import ProductNumber from './Product/ProductNumber.astro';
41
45
 
42
46
  {index !== null && (
43
47
  <>
44
- <meta itemprop="position" content={String(index)} />
45
- <meta itemprop="name" content={productObject.name} />
48
+ <meta
49
+ itemprop="position"
50
+ content={String(index)}
51
+ />
52
+ <meta
53
+ itemprop="name"
54
+ content={productObject.name}
55
+ />
46
56
  </>
47
57
  )}
48
58
  </div>
@@ -1,5 +1,9 @@
1
1
  <script src="./../pwa.ts"></script>
2
- <div id="pwa-toast" role="alert" aria-labelledby="toast-message">
2
+ <div
3
+ id="pwa-toast"
4
+ role="alert"
5
+ aria-labelledby="toast-message"
6
+ >
3
7
  <div class="message">
4
8
  <span id="toast-message"></span>
5
9
  </div>
@@ -23,16 +23,18 @@ const toggleVisibility = () => {
23
23
  <span
24
24
  class="inline-block text-4xl w-6 h-3.5 min-w-[1.25rem] mr-3 bg-gradient-to-b stops-[#0057b7_50%,50%,#ffd700_100%]"
25
25
  />
26
- <span class="leading-none"><span
27
- data-text="We stand with our friends and colleagues in Ukraine. To support Ukraine in their time of need visit "
28
- />
26
+ <span class="leading-none"
27
+ ><span
28
+ data-text="We stand with our friends and colleagues in Ukraine. To support Ukraine in their time of need visit "
29
+ />
29
30
  <a
30
31
  href="https://polo.blue/support-ukraine/"
31
32
  target="_blank"
32
33
  rel="noopener"
33
34
  title="Support Ukraine"
34
35
  class="underline underline-offset-2 hover:text-blue-wrc"
35
- >this page</a>.
36
+ >this page</a
37
+ >.
36
38
  </span>
37
39
 
38
40
  <button
@@ -24,7 +24,10 @@ const hasDescriptionSlotContent = Astro.slots.has('description');
24
24
  >
25
25
  <div class="flex-shrink-0 hidden md:block">
26
26
  <slot name="icon">
27
- <span i-ph:sparkle-thin class="mr-1 text-8 md:text-10 text-brand-secondary"></span>
27
+ <span
28
+ i-ph:sparkle-thin
29
+ class="mr-1 text-8 md:text-10 text-brand-secondary"
30
+ ></span>
28
31
  </slot>
29
32
  </div>
30
33
  <div class="flex-1 text-center md:text-left">
@@ -30,7 +30,10 @@ const navItemsLeft = [
30
30
  <slot name="logo" />
31
31
 
32
32
  <div class="hidden sm:block sm:ml-6">
33
- <div class="flex space-x-4" itemprop="hasPart">
33
+ <div
34
+ class="flex space-x-4"
35
+ itemprop="hasPart"
36
+ >
34
37
  {
35
38
  navItemsLeft.map(({ title, description, url }) => (
36
39
  <a
@@ -57,7 +60,14 @@ const navItemsLeft = [
57
60
  itemscope
58
61
  itemtype="http://schema.org/SiteNavigationElement"
59
62
  >
60
- <a class="icon-btn mx-2" title="" aria-label="" href="#" itemprop="url" data-astro-reload>
63
+ <a
64
+ class="icon-btn mx-2"
65
+ title=""
66
+ aria-label=""
67
+ href="#"
68
+ itemprop="url"
69
+ data-astro-reload
70
+ >
61
71
  <Icon name="carbon:language" />
62
72
  </a>
63
73
  </div>
@@ -9,10 +9,17 @@ const { content = {} } = Astro.props;
9
9
  const canonicalURL = new URL(Astro.url.pathname, Astro.site).toString();
10
10
  ---
11
11
 
12
- <html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial">
12
+ <html
13
+ dir={content.dir ?? 'ltr'}
14
+ lang={content.lang ?? 'en-us'}
15
+ class="initial"
16
+ >
13
17
  <head>
14
18
  <HeadCommon />
15
- <HeadSEO {content} canonicalURL={canonicalURL} />
19
+ <HeadSEO
20
+ {content}
21
+ canonicalURL={canonicalURL}
22
+ />
16
23
  <title>
17
24
  {content.title ? `${content.title} 🚀 ${CONFIG.SITE.title}` : CONFIG.SITE.title}
18
25
  </title>
@@ -20,10 +20,17 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site).toString();
20
20
  });
21
21
  </script>
22
22
 
23
- <html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial">
23
+ <html
24
+ dir={content.dir ?? 'ltr'}
25
+ lang={content.lang ?? 'en-us'}
26
+ class="initial"
27
+ >
24
28
  <head>
25
29
  <HeadCommon />
26
- <HeadSEO content={content} canonicalURL={canonicalURL} />
30
+ <HeadSEO
31
+ content={content}
32
+ canonicalURL={canonicalURL}
33
+ />
27
34
  <title>
28
35
  {content.title ? `${content.title} 🚀 ${CONFIG.SITE.title}` : CONFIG.SITE.title}
29
36
  </title>
@@ -36,12 +43,18 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site).toString();
36
43
 
37
44
  <div class="flex bg-white z-10 mb-11 relative">
38
45
  <div class="sticky top-0 flex lg:(h-screen w-64) z-50">
39
- <div class="mr-auto" transition:name="sidebar">
46
+ <div
47
+ class="mr-auto"
48
+ transition:name="sidebar"
49
+ >
40
50
  <LeftSidebar currentPage={currentPage} />
41
51
  </div>
42
52
  </div>
43
53
  <main class="pb-4 px-4 sm:px-8 col-auto sm:(pb-32) overflow-auto w-full">
44
- <PageContent content={content} transition:name="content">
54
+ <PageContent
55
+ content={content}
56
+ transition:name="content"
57
+ >
45
58
  <slot />
46
59
  </PageContent>
47
60
  </main>
@@ -5,12 +5,26 @@ import { pwaInfo } from 'virtual:pwa-info';
5
5
 
6
6
  <!-- Global Metadata -->
7
7
  <meta charset="utf-8" />
8
- <meta name="viewport" content="width=device-width" />
9
-
10
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
11
- <link rel="alternate icon" type="image/x-icon" href="/favicon.ico" />
12
-
13
- <link rel="sitemap" href="/sitemap-index.xml" />
8
+ <meta
9
+ name="viewport"
10
+ content="width=device-width"
11
+ />
12
+
13
+ <link
14
+ rel="icon"
15
+ type="image/svg+xml"
16
+ href="/favicon.svg"
17
+ />
18
+ <link
19
+ rel="alternate icon"
20
+ type="image/x-icon"
21
+ href="/favicon.ico"
22
+ />
23
+
24
+ <link
25
+ rel="sitemap"
26
+ href="/sitemap-index.xml"
27
+ />
14
28
 
15
29
  <!-- Preload Fonts -->
16
30
  <!-- <link rel="preconnect" href="https://fonts.googleapis.com" />
@@ -18,7 +32,10 @@ import { pwaInfo } from 'virtual:pwa-info';
18
32
  <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital@0;1&display=swap" rel="stylesheet" /> -->
19
33
 
20
34
  <!-- Scrollable a11y code helper -->
21
- <script src="/make-scrollable-code-focusable.js" is:inline></script>
35
+ <script
36
+ src="/make-scrollable-code-focusable.js"
37
+ is:inline
38
+ ></script>
22
39
 
23
40
  <!-- This is intentionally inlined to avoid FOUC -->
24
41
  <script is:inline>
@@ -13,32 +13,65 @@ const imageAlt = content?.image?.alt ?? OPEN_GRAPH.image.alt;
13
13
  ---
14
14
 
15
15
  <!-- Page Metadata -->
16
- <link rel="canonical" href={canonicalURL} />
16
+ <link
17
+ rel="canonical"
18
+ href={canonicalURL}
19
+ />
17
20
 
18
21
  <!-- OpenGraph Tags -->
19
- <meta property="og:title" content={formattedContentTitle} />
20
- <meta property="og:type" content="article" />
21
- <meta property="og:url" content={canonicalURL} />
22
- <meta property="og:locale" content={content.ogLocale ?? SITE.defaultLanguage} />
22
+ <meta
23
+ property="og:title"
24
+ content={formattedContentTitle}
25
+ />
26
+ <meta
27
+ property="og:type"
28
+ content="article"
29
+ />
30
+ <meta
31
+ property="og:url"
32
+ content={canonicalURL}
33
+ />
34
+ <meta
35
+ property="og:locale"
36
+ content={content.ogLocale ?? SITE.defaultLanguage}
37
+ />
23
38
  <!-- <meta property="og:image" content={canonicalImageSrc} /> -->
24
- <meta property="og:image:alt" content={imageAlt} />
39
+ <meta
40
+ property="og:image:alt"
41
+ content={imageAlt}
42
+ />
25
43
  <meta
26
44
  name="description"
27
45
  property="og:description"
28
46
  content={content.description ? content.description : SITE.description}
29
47
  />
30
- <meta property="og:site_name" content={SITE.title} />
48
+ <meta
49
+ property="og:site_name"
50
+ content={SITE.title}
51
+ />
31
52
 
32
53
  <!-- Twitter Tags -->
33
- <meta name="twitter:card" content="summary_large_image" />
34
- <meta name="twitter:site" content={OPEN_GRAPH.twitter} />
35
- <meta name="twitter:title" content={formattedContentTitle} />
54
+ <meta
55
+ name="twitter:card"
56
+ content="summary_large_image"
57
+ />
58
+ <meta
59
+ name="twitter:site"
60
+ content={OPEN_GRAPH.twitter}
61
+ />
62
+ <meta
63
+ name="twitter:title"
64
+ content={formattedContentTitle}
65
+ />
36
66
  <meta
37
67
  name="twitter:description"
38
68
  content={content.description ? content.description : SITE.description}
39
69
  />
40
70
  <!-- <meta name="twitter:image" content={canonicalImageSrc} /> -->
41
- <meta name="twitter:image:alt" content={imageAlt} />
71
+ <meta
72
+ name="twitter:image:alt"
73
+ content={imageAlt}
74
+ />
42
75
 
43
76
  <!--
44
77
  TODO: Add json+ld data, maybe https://schema.org/APIReference makes sense?
@@ -57,7 +57,10 @@ const sortedIconCollections = Object.entries(ICONS)
57
57
  >
58
58
  <div class="flex flex-col items-center">
59
59
  <div class="p-4 bg-gray-50 rounded-lg mb-2 w-full flex justify-center items-center min-h-[64px]">
60
- <Icon name={`${name}:${iconName}`} class="text-3xl text-blue-medium" />
60
+ <Icon
61
+ name={`${name}:${iconName}`}
62
+ class="text-3xl text-blue-medium"
63
+ />
61
64
  </div>
62
65
  <code class="text-sm text-gray-600 text-center break-all">
63
66
  {name}:{iconName}