spoko-design-system 0.3.9 → 0.4.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.
@@ -1 +1 @@
1
- [["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.2.5","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://sds.spoko.space/\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":1234,\"streaming\":true},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[\"placehold.co\",\"api.polo.blue\",\"polo.blue\",\"media.istockphoto.com\",\"img.freepik.com\"],\"remotePatterns\":[]},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":\"shiki\",\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"responsiveImages\":false,\"serializeConfig\":false},\"legacy\":{\"collections\":false}}"]
1
+ [["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.3.0","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://sds.spoko.space/\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":1234,\"streaming\":true},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[\"placehold.co\",\"api.polo.blue\",\"polo.blue\",\"media.istockphoto.com\",\"img.freepik.com\",\"polo6r.pl\"],\"remotePatterns\":[]},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":\"shiki\",\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"responsiveImages\":false,\"serializeConfig\":false},\"legacy\":{\"collections\":false}}"]
package/astro.config.mjs CHANGED
@@ -9,7 +9,7 @@ import sitemap from "@astrojs/sitemap";
9
9
  import pagefind from "astro-pagefind";
10
10
  import AstroPWA from '@vite-pwa/astro';
11
11
  import metaTags from "astro-meta-tags";
12
- import playformInline from "@playform/inline";
12
+
13
13
  import { createSdsConfig } from './uno-config';
14
14
 
15
15
  const unoConfig = createSdsConfig();
@@ -22,68 +22,66 @@ export default defineConfig({
22
22
  },
23
23
  image: {
24
24
  service: sharpImageService(),
25
- domains: ["placehold.co", "api.polo.blue", "polo.blue", "media.istockphoto.com", "img.freepik.com"]
25
+ domains: ["placehold.co", "api.polo.blue", "polo.blue", "media.istockphoto.com", "img.freepik.com", "polo6r.pl"]
26
26
  },
27
27
  integrations: [
28
- // Enable Vue to support Vue3 components.
29
- vue(), mdx(), astroI18next(), AstroPWA({
30
- mode: 'production',
31
- base: '/',
32
- scope: '/',
33
- includeAssets: ['favicon.svg', 'safari-pinned-tab.svg', 'brands/*.svg', 'fonts/*.woff2', 'fonts/*.svg', 'vw.svg', 'polo.blue.svg', 'spoko.space.svg'],
34
- // add this to cache all the static assets in the public folder
35
- // includeAssets: [
36
- // "**/*",
37
- // ],
38
- registerType: 'autoUpdate',
39
- manifest: {
40
- name: 'Spoko Design System',
41
- short_name: 'SDS',
42
- description: 'SDS PWA app description',
43
- categories: ['multimedia'],
44
- screenshots: [{
45
- "src": "pwa-512x512.png",
46
- "sizes": "512x512",
47
- "platform": "windows",
48
- "label": "SDS"
49
- }],
50
- theme_color: '#001e50',
51
- icons: [{
52
- src: 'pwa-192x192.png',
53
- sizes: '192x192',
54
- type: 'image/png'
55
- }, {
56
- src: 'pwa-512x512.png',
57
- sizes: '512x512',
58
- type: 'image/png'
59
- }, {
60
- src: 'pwa-512x512.png',
61
- sizes: '512x512',
62
- type: 'image/png',
63
- purpose: 'any maskable'
64
- }]
65
- },
66
- workbox: {
67
- navigateFallback: '/',
68
- globPatterns: ['**/*.{css,js,html,svg,png,ico,txt}']
69
- // globPatterns: ["**/*"], // add this to cache all the imports
70
- },
71
- devOptions: {
72
- enabled: false,
73
- navigateFallbackAllowlist: [/^\//]
74
- },
75
- experimental: {
76
- directoryAndTrailingSlashHandler: true
77
- }
78
- }),
79
- UnoCSS({
80
- injectReset: true,
81
- ...unoConfig
82
- }),
83
- icon(iconConfig),
84
- metaTags(),
85
- (await import("@playform/inline")).default(),
86
- pagefind(),
87
- sitemap()
88
- ]
28
+ // Enable Vue to support Vue3 components
29
+ vue(),
30
+ mdx(),
31
+ astroI18next(),
32
+ AstroPWA({
33
+ mode: 'production',
34
+ base: '/',
35
+ scope: '/',
36
+ includeAssets: ['favicon.svg', 'safari-pinned-tab.svg', 'brands/*.svg', 'fonts/*.woff2', 'fonts/*.svg', 'vw.svg', 'polo.blue.svg', 'spoko.space.svg'],
37
+ registerType: 'autoUpdate',
38
+ manifest: {
39
+ name: 'Spoko Design System',
40
+ short_name: 'SDS',
41
+ description: 'SDS PWA app description',
42
+ categories: ['multimedia'],
43
+ screenshots: [{
44
+ "src": "pwa-512x512.png",
45
+ "sizes": "512x512",
46
+ "platform": "windows",
47
+ "label": "SDS"
48
+ }],
49
+ theme_color: '#001e50',
50
+ icons: [{
51
+ src: 'pwa-192x192.png',
52
+ sizes: '192x192',
53
+ type: 'image/png'
54
+ }, {
55
+ src: 'pwa-512x512.png',
56
+ sizes: '512x512',
57
+ type: 'image/png'
58
+ }, {
59
+ src: 'pwa-512x512.png',
60
+ sizes: '512x512',
61
+ type: 'image/png',
62
+ purpose: 'any maskable'
63
+ }]
64
+ },
65
+ workbox: {
66
+ navigateFallback: '/',
67
+ globPatterns: ['**/*.{css,js,html,svg,png,ico,txt}']
68
+ },
69
+ devOptions: {
70
+ enabled: false,
71
+ navigateFallbackAllowlist: [/^\//]
72
+ },
73
+ experimental: {
74
+ directoryAndTrailingSlashHandler: true
75
+ }
76
+ }),
77
+ UnoCSS({
78
+ injectReset: true,
79
+ ...unoConfig
80
+ }),
81
+ icon(iconConfig),
82
+ metaTags(),
83
+ (await import("@playform/inline")).default(),
84
+ pagefind(),
85
+ sitemap()
86
+ ]
89
87
  });
package/index.ts CHANGED
@@ -38,6 +38,7 @@ export { default as Copyright } from './src/components/Copyright.astro';
38
38
  export { default as HandDrive } from './src/components/HandDrive.astro';
39
39
  export { default as Faq } from './src/components/Faq.astro';
40
40
  export { default as FaqItem } from './src/components/FaqItem.astro';
41
+ export { default as ButtonCopy } from './src/components/ButtonCopy.astro'; // Add this line
41
42
 
42
43
  export { default as ProductImage } from './src/components/Product/ProductImage.astro';
43
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spoko-design-system",
3
- "version": "0.3.9",
3
+ "version": "0.4.2",
4
4
  "private": false,
5
5
  "main": "./index.ts",
6
6
  "module": "./index.ts",
@@ -0,0 +1,165 @@
1
+ ---
2
+ interface Props {
3
+ productNumber: string;
4
+ tooltipClasses?: string;
5
+ texts: {
6
+ copy: string;
7
+ copied: string;
8
+ };
9
+ }
10
+
11
+ const {
12
+ productNumber,
13
+ tooltipClasses = '',
14
+ texts
15
+ } = Astro.props;
16
+
17
+ // Move SVG definition to a constant to avoid recomputing
18
+ const COPY_ICON = `url("data:image/svg+xml;utf8,${encodeURIComponent(
19
+ `<svg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'><path fill='currentColor' d='M184 66H40a6 6 0 0 0-6 6v144a6 6 0 0 0 6 6h144a6 6 0 0 0 6-6V72a6 6 0 0 0-6-6m-6 144H46V78h132Zm44-170v144a6 6 0 0 1-12 0V46H72a6 6 0 0 1 0-12h144a6 6 0 0 1 6 6'/></svg>`
20
+ )}")`;
21
+ ---
22
+
23
+ <button
24
+ aria-label={texts.copy}
25
+ class="btn-copy has-tooltip"
26
+ data-copy-text={productNumber}
27
+ >
28
+ <span
29
+ class:list={["tooltip rounded-full btn-copy-text", tooltipClasses]}
30
+ data-text={texts.copy}
31
+ data-copied-text={texts.copied}
32
+ />
33
+ <span class="copy-icon" role="img" aria-hidden="true" />
34
+ </button>
35
+
36
+ <script>
37
+ class ClipboardButton {
38
+ private static COPY_TIMEOUT = 2000;
39
+
40
+ constructor(private button: HTMLButtonElement) {
41
+ this.init();
42
+ }
43
+
44
+ private init(): void {
45
+ this.button.addEventListener('click', () => this.handleCopy());
46
+ }
47
+
48
+ private get tooltip(): HTMLSpanElement {
49
+ return this.button.querySelector('.tooltip') as HTMLSpanElement;
50
+ }
51
+
52
+ private get copyText(): string {
53
+ return this.button.dataset.copyText || '';
54
+ }
55
+
56
+ private get originalText(): string {
57
+ return this.tooltip.dataset.text || 'Copy';
58
+ }
59
+
60
+ private get copiedText(): string {
61
+ return this.tooltip.dataset.copiedText || 'Copied';
62
+ }
63
+
64
+ private async handleCopy(): Promise<void> {
65
+ try {
66
+ await this.copyToClipboard();
67
+ this.updateTooltip();
68
+ } catch (err) {
69
+ console.error('Failed to copy text:', err);
70
+ }
71
+ }
72
+
73
+ private async copyToClipboard(): Promise<void> {
74
+ if (navigator.clipboard && window.isSecureContext) {
75
+ await navigator.clipboard.writeText(this.copyText);
76
+ } else {
77
+ this.fallbackCopy();
78
+ }
79
+ }
80
+
81
+ private updateTooltip(): void {
82
+ this.tooltip.dataset.text = this.copiedText;
83
+ setTimeout(() => {
84
+ this.tooltip.dataset.text = this.originalText;
85
+ }, ClipboardButton.COPY_TIMEOUT);
86
+ }
87
+
88
+ private fallbackCopy(): void {
89
+ const textArea = document.createElement('textarea');
90
+ textArea.value = this.copyText;
91
+ textArea.style.position = 'fixed';
92
+ textArea.style.opacity = '0';
93
+
94
+ document.body.appendChild(textArea);
95
+ textArea.select();
96
+
97
+ try {
98
+ document.execCommand('copy');
99
+ } catch (err) {
100
+ console.error('Fallback copy failed:', err);
101
+ } finally {
102
+ document.body.removeChild(textArea);
103
+ }
104
+ }
105
+ }
106
+
107
+ // Use a single event listener with event delegation
108
+ document.addEventListener('astro:page-load', () => {
109
+ document.querySelectorAll('.btn-copy').forEach(button => {
110
+ if (button instanceof HTMLButtonElement) {
111
+ new ClipboardButton(button);
112
+ }
113
+ });
114
+ });
115
+ </script>
116
+
117
+ <style define:vars={{ iconUrl: COPY_ICON }}>
118
+ .btn-copy {
119
+ position: absolute;
120
+ right: -1.75rem;
121
+ margin-left: auto;
122
+ width: 1.5rem;
123
+ height: 1.5rem;
124
+ line-height: 1;
125
+ opacity: 0.1;
126
+ display: inline-flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ transition: opacity 0.2s ease-in-out;
130
+ }
131
+
132
+ .btn-copy:hover {
133
+ opacity: 1;
134
+ }
135
+
136
+ @media (min-width: 640px) {
137
+ .btn-copy {
138
+ right: -1.25rem;
139
+ }
140
+ }
141
+
142
+ .tooltip {
143
+ @apply invisible absolute -top-8 left-1/2 -translate-x-1/2 bg-neutral px-2 py-1 text-xs text-white opacity-0 transition-opacity;
144
+ }
145
+
146
+ .tooltip::before {
147
+ content: attr(data-text);
148
+ }
149
+
150
+ .has-tooltip:hover .tooltip {
151
+ @apply visible opacity-100;
152
+ }
153
+
154
+ .copy-icon {
155
+ width: 1.2em;
156
+ height: 1.2em;
157
+ display: inline-block;
158
+ vertical-align: middle;
159
+ background-color: currentColor;
160
+ -webkit-mask: var(--iconUrl) no-repeat;
161
+ mask: var(--iconUrl) no-repeat;
162
+ -webkit-mask-size: 100% 100%;
163
+ mask-size: 100% 100%;
164
+ }
165
+ </style>
@@ -23,34 +23,71 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
23
23
  transition:name="category-details"
24
24
  transition:animate="fade"
25
25
  >
26
- <CategorySidebarToggler onclick="toggleSidebar()">
27
- <!-- Desktop expanded -->
26
+ <CategorySidebarToggler class="category-sidebar-toggler w-12 md:w-8" data-state="desktop">
27
+ <div class="desktop-icons hidden md:block">
28
+ <!-- Desktop icons container -->
28
29
  <Icon
29
30
  name="ant-design:menu-fold-outlined"
30
- class="toggler-btn md:[&:not(.hidden)]:block"
31
+ class="toggler-btn w-6 expanded-icon"
31
32
  aria-hidden="true"
32
33
  />
33
- <!-- Desktop collapsed -->
34
34
  <Icon
35
35
  name="ant-design:menu-unfold-outlined"
36
- class="toggler-btn hidden md:[&:not(.hidden)]:block"
36
+ class="toggler-btn w-6 collapsed-icon hidden"
37
37
  aria-hidden="true"
38
38
  />
39
- <!-- Mobile icon -->
39
+ </div>
40
+ <!-- Mobile icon in separate container -->
41
+ <div class="mobile-icon block md:hidden">
40
42
  <Icon
41
43
  name="ant-design:menu-outlined"
42
- class="toggler-btn block md:hidden"
44
+ class="toggler-btn w-6"
43
45
  aria-hidden="true"
44
46
  />
45
- </CategorySidebarToggler>
47
+ </div>
48
+ </CategorySidebarToggler>
46
49
 
47
- <!-- Rest of the existing template code -->
48
50
 
49
- { showViewToggler && (
51
+ <div class="overflow-x-auto overflow-y-hidden flex max-w-full items-center">
52
+ {subtitle ? (
53
+ <>
54
+ <a class="text-lg font-vw-headregular whitespace-nowrap block" href={`${baseURL}/${category.slug}/`}>
55
+ {category.name}
56
+ {titleSmall && <small>{titleSmall}</small>}
57
+ </a>
58
+ <span class="text-neutral-lighter text-lg inline-block px-1 font-headlight">/</span>
59
+ {!subsubtitle ? (
60
+ <h1 class="text-lg py-2.5 sm:py-0 whitespace-nowrap underline underline-offset-6 decoration-blue-300 decoration-0.5">
61
+ {subtitle} <span class="sr-only"> {t('catalog.extra-short')}</span>
62
+ </h1>
63
+ ) : (
64
+ <>
65
+ <div class="text-lg py-2.5 sm:py-0 whitespace-nowrap">
66
+ <a href={`${baseURL}/${category.slug}/${subcategory.slug}/`}>
67
+ {subtitle}
68
+ </a>
69
+ </div>
70
+ <span class="text-neutral-lighter text-lg inline-block px-1 font-headlight">/</span>
71
+ <h1 class="text-lg py-2.5 sm:py-0 whitespace-nowrap underline underline-offset-6 decoration-blue-300 decoration-0.5">
72
+ {subsubtitle} <span class="sr-only"> {t('catalog.extra-short')}</span>
73
+ </h1>
74
+ </>
75
+ )}
76
+ </>
77
+ ) : (
78
+ <h1 class="text-lg py-2.5 sm:py-0 whitespace-nowrap">
79
+ {category.name}
80
+ {titleSmall && <small>{titleSmall}</small>}
81
+ <span class="sr-only"> {t('catalog.extra-short')}</span>
82
+ </h1>
83
+ )}
84
+ </div>
85
+
86
+ {showViewToggler && (
50
87
  <CategoryViewToggler
51
88
  {...viewerLabels}
52
89
  class="hidden lg:flex items-center gap-2 ml-auto"
53
- />
90
+ />
54
91
  )}
55
92
  </div>
56
93
 
@@ -61,19 +98,24 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
61
98
 
62
99
  if (sidebar) {
63
100
  sidebar.classList.toggle('collapsed', savedState === 'closed');
101
+ updateTogglers(savedState === 'closed');
102
+ }
103
+ }
104
+
105
+ function updateTogglers(isCollapsed) {
106
+ document.querySelectorAll('.category-sidebar-toggler').forEach(toggler => {
107
+ const expandedIcon = toggler.querySelector('.expanded-icon');
108
+ const collapsedIcon = toggler.querySelector('.collapsed-icon');
64
109
 
65
- const togglers = document.querySelectorAll('.toggler-btn');
66
- if (togglers.length >= 2) {
67
- const isCollapsed = savedState === 'closed';
68
- togglers[0].classList.toggle('hidden', isCollapsed);
69
- togglers[1].classList.toggle('hidden', !isCollapsed);
110
+ if (expandedIcon && collapsedIcon) {
111
+ expandedIcon.classList.toggle('hidden', isCollapsed);
112
+ collapsedIcon.classList.toggle('hidden', !isCollapsed);
70
113
  }
71
- }
114
+ });
72
115
  }
73
116
 
74
117
  function toggleSidebar() {
75
118
  const sidebar = document.getElementById('sidebar');
76
- const togglers = document.querySelectorAll('.toggler-btn');
77
119
  const isMobile = window.matchMedia("(max-width: 768px)").matches;
78
120
 
79
121
  if (sidebar) {
@@ -84,26 +126,28 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
84
126
  const isCollapsed = sidebar.classList.toggle('collapsed');
85
127
  document.body.classList.remove('overflow-hidden');
86
128
  localStorage.setItem('sidebarState', isCollapsed ? 'closed' : 'open');
87
-
88
- if (togglers.length >= 2) {
89
- togglers[0].classList.toggle('hidden', isCollapsed);
90
- togglers[1].classList.toggle('hidden', !isCollapsed);
91
- }
129
+ updateTogglers(isCollapsed);
92
130
  }
93
131
  }
94
132
  }
95
133
 
96
- // Initialize on every page load to maintain state during navigation
97
- document.addEventListener('astro:page-load', initializeSidebar);
98
-
99
- // Initialize on initial page load
100
- document.addEventListener('DOMContentLoaded', initializeSidebar);
134
+ function setupTogglers() {
135
+ document.querySelectorAll('.category-sidebar-toggler').forEach(toggler => {
136
+ toggler.removeEventListener('click', toggleSidebar);
137
+ toggler.addEventListener('click', toggleSidebar);
138
+ });
139
+ }
140
+
141
+ // Initialize on page load
142
+ document.addEventListener('astro:page-load', () => {
143
+ initializeSidebar();
144
+ setupTogglers();
145
+ });
101
146
 
102
- // Handle state during view transitions
147
+ // Preserve state during view transitions
103
148
  document.addEventListener('astro:before-swap', () => {
104
149
  const sidebarState = localStorage.getItem('sidebarState');
105
150
  if (sidebarState) {
106
- // Store state temporarily during transition
107
151
  sessionStorage.setItem('tempSidebarState', sidebarState);
108
152
  }
109
153
  });
@@ -111,7 +155,6 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
111
155
  document.addEventListener('astro:after-swap', () => {
112
156
  const tempState = sessionStorage.getItem('tempSidebarState');
113
157
  if (tempState) {
114
- // Restore state after transition
115
158
  localStorage.setItem('sidebarState', tempState);
116
159
  sessionStorage.removeItem('tempSidebarState');
117
160
  initializeSidebar();
@@ -119,6 +162,7 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
119
162
  });
120
163
  </script>
121
164
 
165
+
122
166
  <style>
123
167
  .toggler-btn {
124
168
  @apply md:-mt-0.5;
@@ -25,7 +25,7 @@ const {
25
25
  <div class="flex border rounded">
26
26
  <button
27
27
  data-view="list"
28
- class="view-toggle flex items-center gap-1 px-3 py-1.5 transition-colors"
28
+ class="view-toggle flex items-center gap-1 px-3 py-0.5 transition-colors"
29
29
  aria-label={listAriaLabel}
30
30
  >
31
31
  <Icon name="ant-design:bars-outlined" class="w-4 h-4" />
@@ -33,7 +33,7 @@ const {
33
33
  </button>
34
34
  <button
35
35
  data-view="grid"
36
- class="view-toggle flex items-center gap-1 px-3 py-1.5 transition-colors"
36
+ class="view-toggle flex items-center gap-1 px-3 py-0.5 transition-colors"
37
37
  aria-label={gridAriaLabel}
38
38
  >
39
39
  <Icon name="ant-design:appstore-outlined" class="w-4 h-4" />
@@ -96,7 +96,7 @@ const commonProps = {
96
96
  />
97
97
  )}
98
98
 
99
- <style is:global>
99
+ <style>
100
100
  .bg-vw {
101
101
  background: radial-gradient(circle at 50% 85%, #00437a 0%, #001e50 100%);
102
102
  }
@@ -1,5 +1,5 @@
1
1
  ---
2
- import ButtonCopy from '../ButtonCopy.vue';
2
+ import ButtonCopy from '../ButtonCopy.astro';
3
3
  import useFormatProductNumber from '../../utils/product/useFormatProductNumber';
4
4
 
5
5
  const {
@@ -41,7 +41,6 @@ const FormattedWrapper = isPdp ? 'h3' : 'div';
41
41
  productNumber={productNumber}
42
42
  texts={buttonTexts}
43
43
  tooltipClasses=""
44
- client:only="vue"
45
44
  />
46
45
  )}
47
46
  </div>
@@ -25,7 +25,7 @@ export const jumbotronShortcuts = [
25
25
 
26
26
  // Metadata and categories
27
27
  ['jumbotron-meta', 'order-3 flex items-center text-gray-100'],
28
- ['jumbotron-categories', 'order-1'],
28
+ ['jumbotron-categories', 'order-1 mt-4'],
29
29
 
30
30
  // Content styles
31
31
  ['jumbotron-description', 'mb-1 line-clamp-3 text-base sm:text-lg leading-none mt-4'],