spoko-design-system 1.1.2 → 1.1.4
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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/src/components/Card.astro +1 -1
- package/src/components/Category/CategoriesCarousel.astro +1 -1
- package/src/components/Category/CategoryDetails.astro +2 -10
- package/src/components/LeftSidebar.astro +1 -1
- package/src/components/Product/ProductCarousel.astro +1 -1
- package/src/components/Product/ProductLink.astro +78 -57
- package/src/components/Product/ProductNumber.astro +0 -1
- package/src/components/ProductTile.astro +41 -37
- package/src/components/layout/Header.astro +1 -1
- package/src/pages/components/icons.astro +0 -6
- package/src/pages/core/typography.astro +36 -36
- package/src/utils/category/getMainCategoryList.ts +1 -1
- package/src/utils/product/getPriceFormatted.ts +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [1.1.4](https://github.com/polo-blue/sds/compare/v1.1.3...v1.1.4) (2025-09-23)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* remove unused variables and improve TypeScript types ([db637f6](https://github.com/polo-blue/sds/commit/db637f6829bb2a23342a35d8041e803d4c9ad9c4))
|
|
6
|
+
|
|
7
|
+
## [1.1.3](https://github.com/polo-blue/sds/compare/v1.1.2...v1.1.3) (2025-09-23)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* resolve Astro syntax errors in components ([18003e7](https://github.com/polo-blue/sds/commit/18003e78558a1dbc8f34d0e4faed6183eaaa80cb))
|
|
12
|
+
|
|
1
13
|
## [1.1.2](https://github.com/polo-blue/sds/compare/v1.1.1...v1.1.2) (2025-09-23)
|
|
2
14
|
|
|
3
15
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -3,16 +3,8 @@ import CategorySidebarToggler from './CategorySidebarToggler.vue';
|
|
|
3
3
|
import CategoryViewToggler from './CategoryViewToggler.astro';
|
|
4
4
|
import { Icon } from 'astro-icon/components';
|
|
5
5
|
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
subcategory,
|
|
9
|
-
subtitle,
|
|
10
|
-
subsubtitle,
|
|
11
|
-
titleSmall,
|
|
12
|
-
locale,
|
|
13
|
-
showViewToggler,
|
|
14
|
-
viewerLabels,
|
|
15
|
-
} = Astro.props;
|
|
6
|
+
const { category, subcategory, subtitle, subsubtitle, titleSmall, showViewToggler, viewerLabels } =
|
|
7
|
+
Astro.props;
|
|
16
8
|
|
|
17
9
|
const baseURL = '';
|
|
18
10
|
---
|
|
@@ -44,7 +44,7 @@ const getLinkClasses = link => {
|
|
|
44
44
|
</Astronav>
|
|
45
45
|
|
|
46
46
|
<script is:inline>
|
|
47
|
-
window.addEventListener('DOMContentLoaded',
|
|
47
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
48
48
|
var target = document.querySelector('[aria-current="page"]');
|
|
49
49
|
if (target && target.offsetTop > window.innerHeight - 100) {
|
|
50
50
|
document.querySelector('.nav-groups').scrollTop = target.offsetTop;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import ProductLink from './ProductLink.astro';
|
|
3
3
|
|
|
4
4
|
// Get the product directly from the prop on render
|
|
5
|
-
const { locale,
|
|
5
|
+
const { locale, products, isShopProduct = false } = Astro.props;
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
{
|
|
@@ -7,7 +7,7 @@ interface Props {
|
|
|
7
7
|
locale: string;
|
|
8
8
|
index: number;
|
|
9
9
|
bigTile?: boolean;
|
|
10
|
-
loading?:
|
|
10
|
+
loading?: 'eager' | 'lazy';
|
|
11
11
|
isShopProduct?: boolean;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -17,80 +17,101 @@ const {
|
|
|
17
17
|
bigTile,
|
|
18
18
|
locale,
|
|
19
19
|
index,
|
|
20
|
-
loading =
|
|
20
|
+
loading = 'lazy',
|
|
21
21
|
isShopProduct = false,
|
|
22
22
|
} = Astro.props;
|
|
23
23
|
|
|
24
24
|
import { getProductById } from '@utils/product/getProductById';
|
|
25
25
|
import { getShopProductById } from '@utils/product/getShopProductById';
|
|
26
|
-
import { getProductUrl } from
|
|
27
|
-
import { getShopProductUrl } from
|
|
28
|
-
import { getProductTranslation } from
|
|
26
|
+
import { getProductUrl } from '@utils/product/getProductUrl';
|
|
27
|
+
import { getShopProductUrl } from '@utils/product/getShopProductUrl';
|
|
28
|
+
import { getProductTranslation } from '@utils/product/getProductTranslation';
|
|
29
29
|
import { getImageUrl } from '@utils/getImageUrl';
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
ProductImage,
|
|
32
|
+
ProductNumber,
|
|
33
|
+
removeSemicolon,
|
|
34
|
+
getPriceFormatted,
|
|
35
|
+
} from 'spoko-design-system';
|
|
31
36
|
|
|
32
37
|
// Użycie productObject jeśli przekazane, inaczej pobranie produktu na podstawie productId
|
|
33
|
-
const product =
|
|
38
|
+
const product =
|
|
39
|
+
productObject ||
|
|
40
|
+
(productId
|
|
41
|
+
? isShopProduct
|
|
42
|
+
? await getShopProductById(productId)
|
|
43
|
+
: await getProductById(productId)
|
|
44
|
+
: null);
|
|
34
45
|
|
|
35
46
|
// Określenie URL miniatury produktu
|
|
36
|
-
const thumb = product
|
|
37
|
-
isShopProduct
|
|
38
|
-
? await getImageUrl(product.images?.[0]?.path ||
|
|
39
|
-
: await getImageUrl(product.photo ||
|
|
40
|
-
|
|
47
|
+
const thumb = product
|
|
48
|
+
? isShopProduct
|
|
49
|
+
? await getImageUrl(product.images?.[0]?.path || '', 'SHOP')
|
|
50
|
+
: await getImageUrl(product.photo || '', `'ProductLink' ${product.number}`)
|
|
51
|
+
: '';
|
|
41
52
|
|
|
42
53
|
// Product translation removed - using English only
|
|
43
|
-
const productTranslation = productId
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
const productTranslation = productId
|
|
55
|
+
? await getProductTranslation(productId, product?.number || '')
|
|
56
|
+
: null;
|
|
57
|
+
|
|
58
|
+
const productName = product
|
|
59
|
+
? isShopProduct
|
|
47
60
|
? product.name_en || product.name
|
|
48
61
|
: productTranslation?.name || product.name
|
|
49
|
-
|
|
62
|
+
: 'NO NAME';
|
|
50
63
|
|
|
51
64
|
const nameFormatted = removeSemicolon(productName.toString());
|
|
52
65
|
---
|
|
53
66
|
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
{
|
|
68
|
+
product && (
|
|
69
|
+
<>
|
|
70
|
+
<div
|
|
71
|
+
class={bigTile ? 'product-link--big-tile' : 'product-thumb--plp product-thumb--carousel'}
|
|
72
|
+
>
|
|
73
|
+
{product.photo !== null && thumb ? (
|
|
74
|
+
<ProductImage
|
|
75
|
+
imagesApiUrl="https://api.polo.blue"
|
|
76
|
+
imageObject={{
|
|
77
|
+
src: thumb,
|
|
78
|
+
alt: productName,
|
|
79
|
+
height: '180',
|
|
80
|
+
width: '240',
|
|
81
|
+
loading,
|
|
82
|
+
}}
|
|
83
|
+
/>
|
|
84
|
+
) : (
|
|
85
|
+
<img src="/1x1.png" class="bg-neutral-lightest/70" alt={productName} />
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class={bigTile ? '' : 'sm:pl-4'}>
|
|
90
|
+
{product.price_pln && (
|
|
91
|
+
<p class="block mb-2 font-600 font-headbold text-5">{getPriceFormatted(product)}</p>
|
|
92
|
+
)}
|
|
71
93
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
94
|
+
<a
|
|
95
|
+
class="product-link--url"
|
|
96
|
+
href={
|
|
97
|
+
isShopProduct
|
|
98
|
+
? getShopProductUrl(product.slug, locale)
|
|
99
|
+
: getProductUrl(product.number, locale)
|
|
100
|
+
}
|
|
101
|
+
itemprop="url"
|
|
102
|
+
title={product.number}
|
|
103
|
+
set:html={nameFormatted}
|
|
104
|
+
/>
|
|
78
105
|
|
|
79
|
-
|
|
80
|
-
class="product-link--url"
|
|
81
|
-
href={isShopProduct ? getShopProductUrl(product.slug, locale) : getProductUrl(product.number, locale)}
|
|
82
|
-
itemprop="url"
|
|
83
|
-
title={product.number}
|
|
84
|
-
set:html={nameFormatted}
|
|
85
|
-
/>
|
|
106
|
+
<ProductNumber productNumber={product.number} copyDisabled={true} />
|
|
86
107
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
108
|
+
{index !== null && (
|
|
109
|
+
<>
|
|
110
|
+
<meta itemprop="position" content={index.toString()} />
|
|
111
|
+
<meta itemprop="name" content={nameFormatted} />
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
114
|
+
</div>
|
|
115
|
+
</>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
@@ -1,47 +1,51 @@
|
|
|
1
1
|
---
|
|
2
|
-
const { productObject,
|
|
3
|
-
import Image from
|
|
4
|
-
import ProductNumber from
|
|
2
|
+
const { productObject, index } = Astro.props;
|
|
3
|
+
import Image from './Image.astro';
|
|
4
|
+
import ProductNumber from './Product/ProductNumber.astro';
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
{
|
|
8
|
-
(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
imageObject={
|
|
15
|
-
{
|
|
7
|
+
{
|
|
8
|
+
productObject && (
|
|
9
|
+
<>
|
|
10
|
+
<div class="img--4/3 img--small">
|
|
11
|
+
{productObject.photo !== null ? (
|
|
12
|
+
<Image
|
|
13
|
+
imageObject={{
|
|
16
14
|
src: 'https://img.freepik.com/darmowe-wektory/tlo-retro-modeli-geometrycznych_52683-17902.jpg?w=1380&t=st=1706311337',
|
|
17
15
|
alt: 'Image Alt',
|
|
18
16
|
height: '180',
|
|
19
17
|
width: '240',
|
|
20
|
-
class: 'img--overlay object-cover'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<!-- product deails -->
|
|
30
|
-
<div class="sm:pl-4 flex flex-col" >
|
|
31
|
-
<a class="font-light leading-none mb-2 pr-4 line-clamp-2 h-[2em] before:(content-empty absolute left-0 right-4 h-full top-0)"
|
|
32
|
-
href={productObject.url} itemprop="url"
|
|
33
|
-
title={productObject.number}
|
|
34
|
-
>
|
|
35
|
-
{ productObject.name }
|
|
36
|
-
</a>
|
|
18
|
+
class: 'img--overlay object-cover',
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
21
|
+
) : (
|
|
22
|
+
<img src="/1x1.png" class="bg-gray-100/70" alt={productObject.name} />
|
|
23
|
+
)}
|
|
24
|
+
</div>
|
|
37
25
|
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
26
|
+
<div class="sm:pl-4 flex flex-col">
|
|
27
|
+
<a
|
|
28
|
+
class="font-light leading-none mb-2 pr-4 line-clamp-2 h-[2em] before:(content-empty absolute left-0 right-4 h-full top-0)"
|
|
29
|
+
href={productObject.url}
|
|
30
|
+
itemprop="url"
|
|
31
|
+
title={productObject.number}
|
|
32
|
+
>
|
|
33
|
+
{productObject.name}
|
|
34
|
+
</a>
|
|
45
35
|
|
|
46
|
-
|
|
36
|
+
<ProductNumber
|
|
37
|
+
productNumber={productObject.number}
|
|
38
|
+
copyDisabled={false}
|
|
39
|
+
buttonTexts={{ copy: 'Copy', copied: 'Copied' }}
|
|
40
|
+
/>
|
|
47
41
|
|
|
42
|
+
{index !== null && (
|
|
43
|
+
<>
|
|
44
|
+
<meta itemprop="position" content={String(index)} />
|
|
45
|
+
<meta itemprop="name" content={productObject.name} />
|
|
46
|
+
</>
|
|
47
|
+
)}
|
|
48
|
+
</div>
|
|
49
|
+
</>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
@@ -32,7 +32,7 @@ const navItemsLeft = [
|
|
|
32
32
|
<div class="hidden sm:block sm:ml-6">
|
|
33
33
|
<div class="flex space-x-4" itemprop="hasPart">
|
|
34
34
|
{
|
|
35
|
-
navItemsLeft.map(({ title, description, url
|
|
35
|
+
navItemsLeft.map(({ title, description, url }) => (
|
|
36
36
|
<a
|
|
37
37
|
href={url}
|
|
38
38
|
class="text-gray-400 hover:bg-blue-darker hover:text-white px-3 py-1 rounded-full text-sm font-medium"
|
|
@@ -6,12 +6,6 @@ import { iconConfig } from '../../../icon.config';
|
|
|
6
6
|
const iconifyUrl = 'https://icon-sets.iconify.design/';
|
|
7
7
|
const ICONS = iconConfig.include;
|
|
8
8
|
|
|
9
|
-
type IconGroup = {
|
|
10
|
-
name: string;
|
|
11
|
-
icons: string[];
|
|
12
|
-
url: string;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
9
|
const sortedIconCollections = Object.entries(ICONS)
|
|
16
10
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
17
11
|
.map(([name, icons]) => ({
|
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
---
|
|
2
|
-
import MainLayout from '../../layouts/MainLayout.astro'
|
|
3
|
-
import { typography } from '../../../uno-config/theme/typography'
|
|
2
|
+
import MainLayout from '../../layouts/MainLayout.astro';
|
|
3
|
+
import { typography } from '../../../uno-config/theme/typography';
|
|
4
4
|
|
|
5
|
-
const fonts = Object.entries(typography.fontFamily)
|
|
6
|
-
const loremText =
|
|
5
|
+
const fonts = Object.entries(typography.fontFamily);
|
|
6
|
+
const loremText = 'Lorem ipsum dolor sit amet, consectetur adipiscing';
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<MainLayout>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<!-- Font Preview Cards -->
|
|
14
|
-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
|
15
|
-
{fonts.map(([name, family]) => (
|
|
16
|
-
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow">
|
|
17
|
-
<!-- Font Sample -->
|
|
18
|
-
<div class={`font-${name} text-3xl mb-4 min-h-[120px] flex items-center`}>
|
|
19
|
-
{loremText}
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<!-- Font Info -->
|
|
23
|
-
<div class="border-t pt-4">
|
|
24
|
-
<div class="flex items-center justify-between mb-2">
|
|
25
|
-
<span class="text-lg font-medium text-gray-900">{name}</span>
|
|
26
|
-
<span class="px-3 py-1 bg-gray-100 rounded-full text-sm text-gray-600">font-{name}</span>
|
|
27
|
-
</div>
|
|
28
|
-
<code class="text-sm text-gray-500 block overflow-x-auto whitespace-nowrap">
|
|
29
|
-
{family.join(', ')}
|
|
30
|
-
</code>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
))}
|
|
34
|
-
</div>
|
|
10
|
+
<div class="max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
|
|
11
|
+
<h1 class="text-4xl font-bold text-gray-900 mb-8">Font Family Preview</h1>
|
|
35
12
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
13
|
+
<!-- Font Preview Cards -->
|
|
14
|
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
|
15
|
+
{
|
|
16
|
+
fonts.map(([name, family]) => (
|
|
17
|
+
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow">
|
|
18
|
+
<div class={`font-${name} text-3xl mb-4 min-h-[120px] flex items-center`}>
|
|
19
|
+
{loremText}
|
|
40
20
|
</div>
|
|
41
|
-
|
|
21
|
+
|
|
22
|
+
<div class="border-t pt-4">
|
|
23
|
+
<div class="flex items-center justify-between mb-2">
|
|
24
|
+
<span class="text-lg font-medium text-gray-900">{name}</span>
|
|
25
|
+
<span class="px-3 py-1 bg-gray-100 rounded-full text-sm text-gray-600">
|
|
26
|
+
font-{name}
|
|
27
|
+
</span>
|
|
28
|
+
</div>
|
|
29
|
+
<code class="text-sm text-gray-500 block overflow-x-auto whitespace-nowrap">
|
|
30
|
+
{family.join(', ')}
|
|
31
|
+
</code>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
))
|
|
35
|
+
}
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<!-- Font Configuration Code -->
|
|
39
|
+
<div class="bg-gray-900 rounded-lg overflow-hidden">
|
|
40
|
+
<div class="bg-gray-800 px-4 py-2 text-gray-400">Font Configuration</div>
|
|
41
|
+
<pre
|
|
42
|
+
class="p-4 overflow-x-auto">
|
|
42
43
|
<code class="text-gray-200 text-sm">
|
|
43
44
|
{fonts.map(([name, family]) => `font-${name}:\n${family.join(', ')}
|
|
44
45
|
`).join('\n')}</code>
|
|
45
46
|
</pre>
|
|
46
|
-
</div>
|
|
47
47
|
</div>
|
|
48
|
+
</div>
|
|
48
49
|
</MainLayout>
|
|
49
|
-
|
|
@@ -4,7 +4,7 @@ import { getApiCategories } from '@utils/api/getCategories';
|
|
|
4
4
|
import { getSortedCategories } from '@utils/category/getSortedCategories';
|
|
5
5
|
|
|
6
6
|
// Retrieve main categories:
|
|
7
|
-
export const getMainCategoryList = async (
|
|
7
|
+
export const getMainCategoryList = async (): Promise<CatObject[]> => {
|
|
8
8
|
// Fetch categories from API
|
|
9
9
|
const categories = await getApiCategories();
|
|
10
10
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
interface Product {
|
|
2
|
+
price_eur?: number;
|
|
3
|
+
price_pln?: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const getPriceFormatted = (product: Product) => {
|
|
2
7
|
// Default to EUR formatting for English-only design system
|
|
3
8
|
if (product.price_eur) {
|
|
4
9
|
return new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(
|