spoko-design-system 1.1.1 → 1.1.2

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 (110) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/.github/workflows/code-quality.yml +3 -3
  3. package/.prettierrc +1 -0
  4. package/CHANGELOG.md +6 -0
  5. package/package.json +8 -2
  6. package/src/MyComponent.astro +1 -1
  7. package/src/components/Badge.vue +2 -2
  8. package/src/components/Badges.vue +17 -7
  9. package/src/components/Breadcrumbs.vue +47 -39
  10. package/src/components/Button.vue +31 -30
  11. package/src/components/ButtonCopy.astro +12 -17
  12. package/src/components/ButtonCopy.vue +26 -25
  13. package/src/components/Card.astro +4 -6
  14. package/src/components/Carousel.astro +4 -4
  15. package/src/components/Category/CategoriesCarousel.astro +75 -75
  16. package/src/components/Category/CategoryDetails.astro +75 -79
  17. package/src/components/Category/CategoryLink.vue +8 -12
  18. package/src/components/Category/CategorySidebarToggler.vue +2 -7
  19. package/src/components/Category/CategoryTile.astro +3 -3
  20. package/src/components/Category/CategoryViewToggler.astro +18 -18
  21. package/src/components/Category/SubCategoryLink.vue +13 -13
  22. package/src/components/Faq.astro +16 -17
  23. package/src/components/FaqItem.astro +27 -27
  24. package/src/components/FeaturesList.vue +19 -29
  25. package/src/components/FuckRussia.vue +40 -27
  26. package/src/components/HandDrive.astro +11 -15
  27. package/src/components/Header/Header.astro +165 -166
  28. package/src/components/Header/SkipToContent.astro +1 -1
  29. package/src/components/Headline.vue +44 -27
  30. package/src/components/Image.astro +5 -7
  31. package/src/components/Input.vue +143 -153
  32. package/src/components/Jumbotron/index.astro +143 -156
  33. package/src/components/Jumbotron/types.ts +28 -29
  34. package/src/components/Jumbotron/variants/Default.astro +44 -40
  35. package/src/components/Jumbotron/variants/Hero.astro +45 -53
  36. package/src/components/Jumbotron/variants/Post.astro +68 -64
  37. package/src/components/Jumbotron/variants/PostSplit.astro +89 -81
  38. package/src/components/Jumbotron.astro +12 -12
  39. package/src/components/LanguageSuggestion.astro +66 -69
  40. package/src/components/LeftSidebar.astro +10 -10
  41. package/src/components/MainColors.vue +2 -2
  42. package/src/components/MainInput.vue +6 -3
  43. package/src/components/Modal.astro +2 -2
  44. package/src/components/PartNumber.vue +2 -3
  45. package/src/components/Post/PostCategories.astro +2 -4
  46. package/src/components/Post/PostCategories.vue +2 -2
  47. package/src/components/PostHeader.astro +4 -6
  48. package/src/components/PrCode.vue +20 -19
  49. package/src/components/Product/ProductButton.vue +2 -5
  50. package/src/components/Product/ProductCarousel.astro +38 -27
  51. package/src/components/Product/ProductColors.vue +46 -42
  52. package/src/components/Product/ProductDetailName.vue +22 -22
  53. package/src/components/Product/ProductDetails.vue +115 -99
  54. package/src/components/Product/ProductDoc.vue +27 -25
  55. package/src/components/Product/ProductEngineType.vue +13 -10
  56. package/src/components/Product/ProductImage.astro +18 -19
  57. package/src/components/Product/ProductLink.vue +55 -58
  58. package/src/components/Product/ProductLinkInfo.astro +15 -18
  59. package/src/components/Product/ProductModel.vue +25 -24
  60. package/src/components/Product/ProductModels.vue +29 -33
  61. package/src/components/Product/ProductName.vue +15 -15
  62. package/src/components/Product/ProductNumber.astro +23 -31
  63. package/src/components/Product/ProductPositions.vue +32 -34
  64. package/src/components/ProductCarousel.astro +5 -5
  65. package/src/components/ProductCodes.vue +12 -14
  66. package/src/components/ProductDetailName.vue +18 -20
  67. package/src/components/ProductDetailsList.vue +48 -27
  68. package/src/components/Quote.vue +8 -6
  69. package/src/components/ReloadPrompt.astro +39 -47
  70. package/src/components/SlimBanner.vue +44 -19
  71. package/src/components/Table.vue +4 -6
  72. package/src/components/Translations.vue +17 -8
  73. package/src/components/flags/FlagPL.vue +4 -3
  74. package/src/components/flags/FlagUA.vue +2 -2
  75. package/src/components/layout/CallToAction.astro +17 -12
  76. package/src/components/layout/Container.astro +3 -1
  77. package/src/components/layout/Header.astro +12 -21
  78. package/src/config.ts +43 -43
  79. package/src/design.config.ts +63 -63
  80. package/src/env.d.ts +4 -4
  81. package/src/layouts/Layout.astro +10 -19
  82. package/src/layouts/MainLayout.astro +13 -19
  83. package/src/layouts/partials/FooterCommon.astro +2 -2
  84. package/src/layouts/partials/HeadCommon.astro +9 -9
  85. package/src/layouts/partials/HeadSEO.astro +12 -5
  86. package/src/pages/components/icons.astro +130 -121
  87. package/src/pages/core/shadows.astro +18 -11
  88. package/src/pages/index.astro +178 -75
  89. package/src/pwa.ts +4 -4
  90. package/src/styles/base/base.css +14 -19
  91. package/src/styles/base/grid.css +54 -58
  92. package/src/styles/base/typography.css +40 -40
  93. package/src/styles/content.css +25 -23
  94. package/src/styles/main.css +5 -6
  95. package/src/types/Product.ts +31 -31
  96. package/src/types/astro.d.ts +1 -1
  97. package/src/types/index.ts +234 -237
  98. package/src/utils/api/getCategories.ts +9 -9
  99. package/src/utils/category/getMainCategoryList.ts +22 -22
  100. package/src/utils/category/getSortedCategories.ts +7 -11
  101. package/src/utils/product/getPriceFormatted.ts +14 -11
  102. package/src/utils/product/getProductChecklist.ts +10 -11
  103. package/src/utils/product/useFormatProductNumber.ts +18 -9
  104. package/src/utils/seo/getShorterDescription.ts +6 -4
  105. package/src/utils/text/formatDate.ts +2 -3
  106. package/src/utils/text/formatLocaleNumber.ts +2 -2
  107. package/src/utils/text/formatPad.ts +2 -2
  108. package/src/utils/text/getNumberFormatted.ts +10 -10
  109. package/src/utils/text/getTranslatedLink.ts +3 -3
  110. package/src/utils/text.ts +11 -8
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import type { PropType } from 'vue'
2
+ import type { PropType } from 'vue';
3
3
 
4
4
  const props = defineProps({
5
5
  as: {
@@ -8,61 +8,78 @@ const props = defineProps({
8
8
  required: true,
9
9
  },
10
10
  textSize: {
11
- type: String as PropType<'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' | '8xl' | '9xl'>,
11
+ type: String as PropType<
12
+ | 'xs'
13
+ | 'sm'
14
+ | 'base'
15
+ | 'lg'
16
+ | 'xl'
17
+ | '2xl'
18
+ | '3xl'
19
+ | '4xl'
20
+ | '5xl'
21
+ | '6xl'
22
+ | '7xl'
23
+ | '8xl'
24
+ | '9xl'
25
+ >,
12
26
  required: false,
13
- default: null
27
+ default: null,
14
28
  },
15
29
  fontFamily: {
16
30
  type: String as PropType<'head' | 'text' | 'novamono' | 'mono'>,
17
31
  required: false,
18
- default: 'head'
32
+ default: 'head',
19
33
  },
20
34
  fontWeight: {
21
35
  type: String as PropType<'light' | 'regular' | 'bold' | 'light-bold' | 'light-thin'>,
22
36
  required: false,
23
- default: 'regular'
37
+ default: 'regular',
24
38
  },
25
39
  underline: {
26
40
  type: [Boolean, String] as PropType<boolean | 'center'>,
27
41
  required: false,
28
- default: false
29
- }
30
- })
42
+ default: false,
43
+ },
44
+ });
31
45
 
32
46
  // Generate the typography class based on font family and weight
33
47
  const getTypographyClass = (): string => {
34
- const family = props.fontFamily
35
- const weight = props.fontWeight
36
-
48
+ const family = props.fontFamily;
49
+ const weight = props.fontWeight;
50
+
37
51
  // Handle special cases for mono fonts
38
52
  if (family === 'novamono' || family === 'mono') {
39
- return `font-${family}`
53
+ return `font-${family}`;
40
54
  }
41
-
55
+
42
56
  // For head family, generate specific classes
43
57
  if (family === 'head') {
44
- if (weight === 'light') return 'headline-light'
45
- if (weight === 'bold') return 'headline-bold'
46
- if (weight === 'light-bold') return 'headline-light-bold'
47
- if (weight === 'light-thin') return 'headline-light-thin'
48
- return 'headline' // for regular weight
58
+ if (weight === 'light') return 'headline-light';
59
+ if (weight === 'bold') return 'headline-bold';
60
+ if (weight === 'light-bold') return 'headline-light-bold';
61
+ if (weight === 'light-thin') return 'headline-light-thin';
62
+ return 'headline'; // for regular weight
49
63
  }
50
-
64
+
51
65
  // For text family, generate appropriate class
52
66
  if (family === 'text') {
53
- return `font-text${weight}`
67
+ return `font-text${weight}`;
54
68
  }
55
-
69
+
56
70
  // Default fallback
57
- return 'headline'
58
- }
71
+ return 'headline';
72
+ };
59
73
 
60
- const typographyClass = getTypographyClass()
74
+ const typographyClass = getTypographyClass();
61
75
  </script>
62
76
 
63
77
  <template>
64
- <component :is="props.as" class="mb-2.5 leading-none"
65
- :class="`${typographyClass} ${props.textSize ? `text-${props.textSize}` : 'text-xl'} ${props.underline === true ? 'headline--underline' : ''} ${props.underline === 'center' ? 'headline--underline-center block text-center' : 'flex sm:block md:flex items-center'}`">
78
+ <component
79
+ :is="props.as"
80
+ class="mb-2.5 leading-none"
81
+ :class="`${typographyClass} ${props.textSize ? `text-${props.textSize}` : 'text-xl'} ${props.underline === true ? 'headline--underline' : ''} ${props.underline === 'center' ? 'headline--underline-center block text-center' : 'flex sm:block md:flex items-center'}`"
82
+ >
66
83
  <slot />
67
84
  </component>
68
85
  </template>
@@ -105,4 +122,4 @@ const typographyClass = getTypographyClass()
105
122
  left: calc(50% - min(47.5%, 127.5px));
106
123
  }
107
124
  }
108
- </style>
125
+ </style>
@@ -1,16 +1,16 @@
1
1
  ---
2
- import { Image } from "astro:assets";
2
+ import { Image } from 'astro:assets';
3
3
 
4
4
  const { imageObject } = Astro.props;
5
5
  let inputProps = {};
6
6
 
7
7
  if (imageObject.index && imageObject.index === 1) {
8
- inputProps["data-pagefind-meta"] = "image[src], image_alt[alt]";
9
- inputProps["loading"] = "eager";
8
+ inputProps['data-pagefind-meta'] = 'image[src], image_alt[alt]';
9
+ inputProps['loading'] = 'eager';
10
10
  }
11
11
 
12
12
  if (imageObject.srcset && imageObject.srcset.length) {
13
- inputProps["widths"] = imageObject.srcset;
13
+ inputProps['widths'] = imageObject.srcset;
14
14
  }
15
15
  ---
16
16
 
@@ -23,8 +23,6 @@ if (imageObject.srcset && imageObject.srcset.length) {
23
23
  format="avif"
24
24
  data-pagefind-index-attrs="alt"
25
25
  onerror="this.style.display='none';"
26
- class={`h-full w-full select-none pointer-none ${
27
- imageObject.class || "object-cover"
28
- }`}
26
+ class={`h-full w-full select-none pointer-none ${imageObject.class || 'object-cover'}`}
29
27
  {...inputProps}
30
28
  />
@@ -1,153 +1,143 @@
1
- <script setup lang="ts">
2
- import { computed, useAttrs } from 'vue';
3
-
4
- interface InputProps {
5
- id?: string;
6
- name?: string;
7
- label: string;
8
- variant?: 'filled' | 'standard';
9
- type?: string;
10
- modelValue?: string | number;
11
- required?: boolean;
12
- rows?: number;
13
- placeholder?: string;
14
- error?: string | boolean;
15
- success?: string | boolean;
16
- size?: 'sm' | 'md' | 'lg';
17
- class?: string;
18
- [key: string]: any;
19
- }
20
-
21
- const props = withDefaults(defineProps<InputProps>(), {
22
- id: () => `input-${Math.random().toString(36).substring(2, 9)}`,
23
- name: undefined,
24
- variant: 'standard',
25
- type: 'text',
26
- modelValue: '',
27
- required: false,
28
- rows: 3,
29
- placeholder: ' ', // space for "floating label"
30
- error: false,
31
- success: false,
32
- size: 'md',
33
- class: ''
34
- });
35
-
36
- const emit = defineEmits(['update:modelValue', 'input', 'focus', 'blur']);
37
-
38
- // Handle external attrs
39
- const attrs = useAttrs();
40
-
41
- // Compute wrapper class - uses existing shortcut
42
- const wrapperClass = computed(() => `input-wrapper-${props.variant}`);
43
-
44
- // Compute input classes - uses shortcuts
45
- const inputClass = computed(() => {
46
- const classes = ['input-base', 'input-placeholder', `input-${props.variant}`];
47
-
48
- // Add size class
49
- if (props.size) classes.push(`input-${props.size}`);
50
-
51
- // Add textarea class if needed
52
- if (props.type === 'textarea') classes.push('input-textarea');
53
-
54
- // Add status classes
55
- if (props.error) classes.push('input-error');
56
- else if (props.success) classes.push('input-success');
57
-
58
- // Add custom classes
59
- if (props.class) classes.push(props.class);
60
-
61
- return classes.join(' ');
62
- });
63
-
64
- // Compute label classes - using optimized shortcuts
65
- const labelClass = computed(() => {
66
- const classes = [
67
- // Base label style
68
- 'input-label-base',
69
-
70
- // Position styling
71
- `input-label-${props.variant}`,
72
-
73
- // State styling - contains all transformations for the specific variant
74
- `input-label-${props.variant}-state`
75
- ];
76
-
77
- // Add size class
78
- if (props.size) classes.push(`input-label-${props.size}`);
79
-
80
- // Add status classes
81
- if (props.error) classes.push('input-label-error');
82
- else if (props.success) classes.push('input-label-success');
83
-
84
- return classes.join(' ');
85
- });
86
-
87
- // Event handlers
88
- const handleInput = (event: Event) => {
89
- const target = event.target as HTMLInputElement | HTMLTextAreaElement;
90
- emit('update:modelValue', target.value);
91
- emit('input', event);
92
- };
93
-
94
- const handleFocus = (event: FocusEvent) => emit('focus', event);
95
- const handleBlur = (event: FocusEvent) => emit('blur', event);
96
- </script>
97
-
98
- <template>
99
- <div :class="wrapperClass">
100
- <textarea
101
- v-if="type === 'textarea'"
102
- :id="id"
103
- :name="name || id"
104
- :rows="rows"
105
- :required="required"
106
- :class="inputClass + ' peer'"
107
- :placeholder="placeholder"
108
- :value="modelValue"
109
- @input="handleInput"
110
- @focus="handleFocus"
111
- @blur="handleBlur"
112
- v-bind="attrs"
113
- ></textarea>
114
-
115
- <input
116
- v-else
117
- :type="type"
118
- :id="id"
119
- :name="name || id"
120
- :required="required"
121
- :class="inputClass + ' peer'"
122
- :placeholder="placeholder"
123
- :value="modelValue"
124
- @input="handleInput"
125
- @focus="handleFocus"
126
- @blur="handleBlur"
127
- v-bind="attrs"
128
- />
129
-
130
- <label
131
- :for="id"
132
- :class="labelClass"
133
- style="transform-origin: top left;"
134
- >
135
- {{ label }}
136
- <span v-if="required" class="text-red-500 ml-1">*</span>
137
- </label>
138
-
139
- <div
140
- v-if="error && typeof error === 'string'"
141
- class="input-error-message"
142
- >
143
- {{ error }}
144
- </div>
145
-
146
- <div
147
- v-if="success && typeof success === 'string'"
148
- class="input-success-message"
149
- >
150
- {{ success }}
151
- </div>
152
- </div>
153
- </template>
1
+ <script setup lang="ts">
2
+ import { computed, useAttrs } from 'vue';
3
+
4
+ interface InputProps {
5
+ id?: string;
6
+ name?: string;
7
+ label: string;
8
+ variant?: 'filled' | 'standard';
9
+ type?: string;
10
+ modelValue?: string | number;
11
+ required?: boolean;
12
+ rows?: number;
13
+ placeholder?: string;
14
+ error?: string | boolean;
15
+ success?: string | boolean;
16
+ size?: 'sm' | 'md' | 'lg';
17
+ class?: string;
18
+ [key: string]: any;
19
+ }
20
+
21
+ const props = withDefaults(defineProps<InputProps>(), {
22
+ id: () => `input-${Math.random().toString(36).substring(2, 9)}`,
23
+ name: undefined,
24
+ variant: 'standard',
25
+ type: 'text',
26
+ modelValue: '',
27
+ required: false,
28
+ rows: 3,
29
+ placeholder: ' ', // space for "floating label"
30
+ error: false,
31
+ success: false,
32
+ size: 'md',
33
+ class: '',
34
+ });
35
+
36
+ const emit = defineEmits(['update:modelValue', 'input', 'focus', 'blur']);
37
+
38
+ // Handle external attrs
39
+ const attrs = useAttrs();
40
+
41
+ // Compute wrapper class - uses existing shortcut
42
+ const wrapperClass = computed(() => `input-wrapper-${props.variant}`);
43
+
44
+ // Compute input classes - uses shortcuts
45
+ const inputClass = computed(() => {
46
+ const classes = ['input-base', 'input-placeholder', `input-${props.variant}`];
47
+
48
+ // Add size class
49
+ if (props.size) classes.push(`input-${props.size}`);
50
+
51
+ // Add textarea class if needed
52
+ if (props.type === 'textarea') classes.push('input-textarea');
53
+
54
+ // Add status classes
55
+ if (props.error) classes.push('input-error');
56
+ else if (props.success) classes.push('input-success');
57
+
58
+ // Add custom classes
59
+ if (props.class) classes.push(props.class);
60
+
61
+ return classes.join(' ');
62
+ });
63
+
64
+ // Compute label classes - using optimized shortcuts
65
+ const labelClass = computed(() => {
66
+ const classes = [
67
+ // Base label style
68
+ 'input-label-base',
69
+
70
+ // Position styling
71
+ `input-label-${props.variant}`,
72
+
73
+ // State styling - contains all transformations for the specific variant
74
+ `input-label-${props.variant}-state`,
75
+ ];
76
+
77
+ // Add size class
78
+ if (props.size) classes.push(`input-label-${props.size}`);
79
+
80
+ // Add status classes
81
+ if (props.error) classes.push('input-label-error');
82
+ else if (props.success) classes.push('input-label-success');
83
+
84
+ return classes.join(' ');
85
+ });
86
+
87
+ // Event handlers
88
+ const handleInput = (event: Event) => {
89
+ const target = event.target as HTMLInputElement | HTMLTextAreaElement;
90
+ emit('update:modelValue', target.value);
91
+ emit('input', event);
92
+ };
93
+
94
+ const handleFocus = (event: FocusEvent) => emit('focus', event);
95
+ const handleBlur = (event: FocusEvent) => emit('blur', event);
96
+ </script>
97
+
98
+ <template>
99
+ <div :class="wrapperClass">
100
+ <textarea
101
+ v-if="type === 'textarea'"
102
+ :id="id"
103
+ :name="name || id"
104
+ :rows="rows"
105
+ :required="required"
106
+ :class="inputClass + ' peer'"
107
+ :placeholder="placeholder"
108
+ :value="modelValue"
109
+ @input="handleInput"
110
+ @focus="handleFocus"
111
+ @blur="handleBlur"
112
+ v-bind="attrs"
113
+ ></textarea>
114
+
115
+ <input
116
+ v-else
117
+ :type="type"
118
+ :id="id"
119
+ :name="name || id"
120
+ :required="required"
121
+ :class="inputClass + ' peer'"
122
+ :placeholder="placeholder"
123
+ :value="modelValue"
124
+ @input="handleInput"
125
+ @focus="handleFocus"
126
+ @blur="handleBlur"
127
+ v-bind="attrs"
128
+ />
129
+
130
+ <label :for="id" :class="labelClass" style="transform-origin: top left">
131
+ {{ label }}
132
+ <span v-if="required" class="text-red-500 ml-1">*</span>
133
+ </label>
134
+
135
+ <div v-if="error && typeof error === 'string'" class="input-error-message">
136
+ {{ error }}
137
+ </div>
138
+
139
+ <div v-if="success && typeof success === 'string'" class="input-success-message">
140
+ {{ success }}
141
+ </div>
142
+ </div>
143
+ </template>