spoko-design-system 0.7.6 → 0.7.8
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/.astro/data-store.json +1 -1
- package/.astro/settings.json +1 -1
- package/.github/dependabot.yml +11 -11
- package/.github/todo.yml +3 -3
- package/.github/workflows/deploy.yml +39 -39
- package/.stackblitzrc +5 -5
- package/.vscode/extensions.json +5 -5
- package/.vscode/launch.json +11 -11
- package/.vscode/settings.json +5 -5
- package/LICENSE +21 -21
- package/README.md +114 -114
- package/astro-i18next.config.mjs +17 -17
- package/astro-i18next.config.ts +10 -10
- package/astro.config.mjs +86 -86
- package/dev-dist/sw.js +91 -91
- package/dev-dist/workbox-c676b6d3.js +3391 -3391
- package/icon.config.ts +309 -309
- package/index.ts +66 -66
- package/package.json +38 -38
- package/public/fonts/lg.svg +53 -53
- package/public/fonts/vwhead-bold-demo.html +549 -549
- package/public/fonts/vwhead-regular-demo.html +549 -549
- package/public/fonts/vwtext-bold-demo.html +549 -549
- package/public/fonts/vwtext-regular-demo.html +549 -549
- package/public/github.svg +3 -3
- package/public/grid_dot.svg +4 -4
- package/public/linkedin.svg +44 -44
- package/public/locales/en/translation.json +8 -8
- package/public/locales/pl/translation.json +8 -8
- package/public/make-scrollable-code-focusable.js +3 -3
- package/public/pagefind.yml +3 -3
- package/public/polo.blue.svg +29 -29
- package/public/spoko.space.svg +71 -71
- package/public/twitter.svg +46 -46
- package/renovate.json +6 -6
- package/sandbox.config.json +11 -11
- package/src/MyComponent.astro +8 -8
- package/src/components/Badge.vue +19 -19
- package/src/components/Badges.vue +21 -21
- package/src/components/Breadcrumbs.vue +91 -107
- package/src/components/Button.vue +101 -101
- package/src/components/ButtonCopy.astro +183 -183
- package/src/components/ButtonCopy.vue +36 -36
- package/src/components/Card.astro +27 -27
- package/src/components/Carousel.astro +26 -26
- package/src/components/Category/CategoriesCarousel.astro +101 -101
- package/src/components/Category/CategoryDetails.astro +169 -169
- package/src/components/Category/CategoryLink.vue +28 -28
- package/src/components/Category/CategorySidebarToggler.vue +9 -9
- package/src/components/Category/CategoryTile.astro +37 -37
- package/src/components/Category/CategoryViewToggler.astro +89 -89
- package/src/components/Category/SubCategoryLink.vue +19 -19
- package/src/components/Copyright.astro +12 -12
- package/src/components/Date.astro +7 -7
- package/src/components/Faq.astro +33 -33
- package/src/components/FaqItem.astro +80 -80
- package/src/components/FeaturesList.vue +37 -41
- package/src/components/FuckRussia.vue +62 -62
- package/src/components/HandDrive.astro +29 -29
- package/src/components/Header/Header.astro +210 -210
- package/src/components/Header/SkipToContent.astro +1 -1
- package/src/components/Headline.vue +48 -48
- package/src/components/Image.astro +30 -30
- package/src/components/LeftSidebar.astro +53 -53
- package/src/components/MainColors.vue +22 -22
- package/src/components/MainInput.vue +15 -15
- package/src/components/Modal.astro +27 -27
- package/src/components/PageContent.astro +5 -5
- package/src/components/PartNumber.vue +27 -27
- package/src/components/Post/PostCategories.astro +41 -41
- package/src/components/Post/PostCategories.vue +31 -39
- package/src/components/PostHeader.astro +103 -103
- package/src/components/PrCode.vue +141 -141
- package/src/components/Product/ProductButton.vue +18 -18
- package/src/components/Product/ProductCarousel.astro +35 -35
- package/src/components/Product/ProductEngineType.vue +42 -42
- package/src/components/Product/ProductImage.astro +40 -40
- package/src/components/Product/ProductLink.astro +101 -101
- package/src/components/Product/ProductLink.vue +59 -59
- package/src/components/Product/ProductLinkInfo.astro +37 -37
- package/src/components/Product/ProductNumber.astro +60 -60
- package/src/components/ProductCarousel.astro +38 -38
- package/src/components/ProductCodes.vue +39 -39
- package/src/components/ProductDetailName.vue +52 -52
- package/src/components/ProductDetailsList.vue +130 -158
- package/src/components/ProductTile.astro +48 -48
- package/src/components/Quote.vue +23 -23
- package/src/components/ReloadPrompt.astro +50 -50
- package/src/components/SlimBanner.vue +72 -72
- package/src/components/Table.vue +32 -32
- package/src/components/TableOfContents.astro +15 -15
- package/src/components/Translations.vue +23 -23
- package/src/components/flags/FlagPL.vue +3 -3
- package/src/components/flags/FlagUA.vue +2 -2
- package/src/components/layout/Container.astro +7 -7
- package/src/components/layout/Header.astro +80 -80
- package/src/config.ts +56 -56
- package/src/design.config.ts +98 -98
- package/src/env.d.ts +6 -6
- package/src/layouts/Layout.astro +61 -61
- package/src/layouts/MainLayout.astro +81 -81
- package/src/layouts/partials/FooterCommon.astro +4 -4
- package/src/layouts/partials/HeadCommon.astro +44 -44
- package/src/layouts/partials/HeadSEO.astro +41 -41
- package/src/pages/components/badges.mdx +57 -57
- package/src/pages/components/breadcrumbs.mdx +139 -139
- package/src/pages/components/buttons.mdx +360 -360
- package/src/pages/components/card.mdx +294 -294
- package/src/pages/components/carousel.mdx +62 -62
- package/src/pages/components/copyright.mdx +42 -42
- package/src/pages/components/details-list.mdx +115 -115
- package/src/pages/components/features-list.mdx +37 -37
- package/src/pages/components/flags.mdx +49 -49
- package/src/pages/components/fuck-russia.mdx +39 -39
- package/src/pages/components/hand-drive.mdx +38 -38
- package/src/pages/components/headline.mdx +152 -152
- package/src/pages/components/icons.astro +135 -135
- package/src/pages/components/image.mdx +513 -513
- package/src/pages/components/input.mdx +367 -367
- package/src/pages/components/jumbotron.mdx +359 -359
- package/src/pages/components/modal.mdx +64 -64
- package/src/pages/components/post-header.mdx +64 -64
- package/src/pages/components/pr-code.mdx +65 -65
- package/src/pages/components/product-number.mdx +58 -58
- package/src/pages/components/product-tile.mdx +51 -51
- package/src/pages/components/quote.mdx +33 -33
- package/src/pages/components/slimbanner.mdx +35 -35
- package/src/pages/components/table.mdx +108 -108
- package/src/pages/core/colors.mdx +10 -10
- package/src/pages/core/grid.mdx +89 -89
- package/src/pages/core/introduction.mdx +77 -77
- package/src/pages/core/shadows.astro +20 -20
- package/src/pages/core/typography.astro +49 -49
- package/src/pages/index.astro +133 -133
- package/src/pages/patterns/introduction.mdx +60 -60
- package/src/pwa.ts +12 -12
- package/src/styles/_variables.scss +70 -70
- package/src/styles/base/base.css +184 -184
- package/src/styles/base/grid.css +92 -92
- package/src/styles/base/typography.css +70 -70
- package/src/styles/content.css +73 -73
- package/src/styles/main.css +7 -7
- package/src/types/Product.ts +31 -31
- package/src/types/astro.d.ts +3 -3
- package/src/utils/product/getPriceFormatted.ts +15 -15
- package/src/utils/product/getProductChecklist.ts +17 -17
- package/src/utils/product/useFormatProductNumber.ts +41 -41
- package/src/utils/seo/getShorterDescription.ts +14 -14
- package/src/utils/text/formatDate.ts +5 -5
- package/src/utils/text/formatLocaleNumber.ts +6 -6
- package/src/utils/text/formatPad.ts +12 -12
- package/src/utils/text/getNumberFormatted.ts +33 -33
- package/src/utils/text/getTranslatedLink.ts +5 -5
- package/src/utils/text.ts +19 -19
- package/tailwind.config.cjs +8 -8
- package/tsconfig.json +28 -28
- package/uno-config/index.ts +259 -232
- package/uno-config/theme/breakpoints.ts +9 -9
- package/uno-config/theme/colors.ts +64 -64
- package/uno-config/theme/dimensions.ts +17 -17
- package/uno-config/theme/effects.ts +14 -14
- package/uno-config/theme/grid.ts +10 -10
- package/uno-config/theme/index.ts +28 -28
- package/uno-config/theme/shortcuts/buttons.ts +53 -53
- package/uno-config/theme/shortcuts/components.ts +123 -92
- package/uno-config/theme/shortcuts/index.ts +20 -20
- package/uno-config/theme/shortcuts/layout.ts +64 -64
- package/uno-config/theme/typography.ts +29 -29
- package/uno.config.ts +2 -2
- package/src/components/Product/ProductCodes.vue +0 -174
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
---
|
|
2
|
-
import ProductTile from "../components/ProductTile.astro";
|
|
3
|
-
export const productObject = {
|
|
4
|
-
name: "Combi-instrument MFA+",
|
|
5
|
-
url: "https://google.com",
|
|
6
|
-
number: "6R0920870F",
|
|
7
|
-
photo:
|
|
8
|
-
"https://img.freepik.com/darmowe-wektory/tlo-retro-modeli-geometrycznych_52683-17902.jpg?w=1380&t=st=1706311337",
|
|
9
|
-
};
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<div class="bg-white rounded-lg p-4 w-full">
|
|
13
|
-
<swiper-container
|
|
14
|
-
class="flex w-full max-w-full"
|
|
15
|
-
grid-rows="1"
|
|
16
|
-
mousewheel-force-to-axis="true"
|
|
17
|
-
navigation="false"
|
|
18
|
-
scrollbar="false"
|
|
19
|
-
slides-per-view="auto"
|
|
20
|
-
space-between="0"
|
|
21
|
-
>
|
|
22
|
-
<swiper-slide class="carousel-product-tile">
|
|
23
|
-
<ProductTile productObject={productObject} />
|
|
24
|
-
</swiper-slide>
|
|
25
|
-
<swiper-slide class="carousel-product-tile">
|
|
26
|
-
<ProductTile productObject={productObject} />
|
|
27
|
-
</swiper-slide>
|
|
28
|
-
<swiper-slide class="carousel-product-tile">
|
|
29
|
-
<ProductTile productObject={productObject} />
|
|
30
|
-
</swiper-slide>
|
|
31
|
-
<swiper-slide class="carousel-product-tile">
|
|
32
|
-
<ProductTile productObject={productObject} />
|
|
33
|
-
</swiper-slide>
|
|
34
|
-
<swiper-slide class="carousel-product-tile">
|
|
35
|
-
<ProductTile productObject={productObject} />
|
|
36
|
-
</swiper-slide>
|
|
37
|
-
</swiper-container>
|
|
38
|
-
</div>
|
|
1
|
+
---
|
|
2
|
+
import ProductTile from "../components/ProductTile.astro";
|
|
3
|
+
export const productObject = {
|
|
4
|
+
name: "Combi-instrument MFA+",
|
|
5
|
+
url: "https://google.com",
|
|
6
|
+
number: "6R0920870F",
|
|
7
|
+
photo:
|
|
8
|
+
"https://img.freepik.com/darmowe-wektory/tlo-retro-modeli-geometrycznych_52683-17902.jpg?w=1380&t=st=1706311337",
|
|
9
|
+
};
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<div class="bg-white rounded-lg p-4 w-full">
|
|
13
|
+
<swiper-container
|
|
14
|
+
class="flex w-full max-w-full"
|
|
15
|
+
grid-rows="1"
|
|
16
|
+
mousewheel-force-to-axis="true"
|
|
17
|
+
navigation="false"
|
|
18
|
+
scrollbar="false"
|
|
19
|
+
slides-per-view="auto"
|
|
20
|
+
space-between="0"
|
|
21
|
+
>
|
|
22
|
+
<swiper-slide class="carousel-product-tile">
|
|
23
|
+
<ProductTile productObject={productObject} />
|
|
24
|
+
</swiper-slide>
|
|
25
|
+
<swiper-slide class="carousel-product-tile">
|
|
26
|
+
<ProductTile productObject={productObject} />
|
|
27
|
+
</swiper-slide>
|
|
28
|
+
<swiper-slide class="carousel-product-tile">
|
|
29
|
+
<ProductTile productObject={productObject} />
|
|
30
|
+
</swiper-slide>
|
|
31
|
+
<swiper-slide class="carousel-product-tile">
|
|
32
|
+
<ProductTile productObject={productObject} />
|
|
33
|
+
</swiper-slide>
|
|
34
|
+
<swiper-slide class="carousel-product-tile">
|
|
35
|
+
<ProductTile productObject={productObject} />
|
|
36
|
+
</swiper-slide>
|
|
37
|
+
</swiper-container>
|
|
38
|
+
</div>
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import type { PropType } from 'vue'
|
|
3
|
-
import PrCode from './PrCode.vue';
|
|
4
|
-
|
|
5
|
-
const props = defineProps({
|
|
6
|
-
prcodes: {
|
|
7
|
-
type: Object as PropType<string[] | null>,
|
|
8
|
-
default: null,
|
|
9
|
-
required: true,
|
|
10
|
-
},
|
|
11
|
-
isPdp: {
|
|
12
|
-
type: Boolean,
|
|
13
|
-
default: false,
|
|
14
|
-
required: false,
|
|
15
|
-
},
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const codes = props.prcodes || []
|
|
19
|
-
const decodedCodes = codes ? codes.sort() : []
|
|
20
|
-
|
|
21
|
-
const settings = {
|
|
22
|
-
prcodes: decodedCodes,
|
|
23
|
-
}
|
|
24
|
-
</script>
|
|
25
|
-
|
|
26
|
-
<template>
|
|
27
|
-
|
|
28
|
-
<span
|
|
29
|
-
v-for="(prcode, index) in settings.prcodes"
|
|
30
|
-
:key="index"
|
|
31
|
-
class="not-last:mr-1"
|
|
32
|
-
>
|
|
33
|
-
<PrCode :prcode="prcode" v-if="!String(prcode).includes('+')" />
|
|
34
|
-
<span v-else >
|
|
35
|
-
<PrCode v-for="(splittedCode, index2) in String(prcode).split('+')" :key="index2" :prcode="splittedCode" />
|
|
36
|
-
</span>
|
|
37
|
-
</span>
|
|
38
|
-
</template>
|
|
39
|
-
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { PropType } from 'vue'
|
|
3
|
+
import PrCode from './PrCode.vue';
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
prcodes: {
|
|
7
|
+
type: Object as PropType<string[] | null>,
|
|
8
|
+
default: null,
|
|
9
|
+
required: true,
|
|
10
|
+
},
|
|
11
|
+
isPdp: {
|
|
12
|
+
type: Boolean,
|
|
13
|
+
default: false,
|
|
14
|
+
required: false,
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const codes = props.prcodes || []
|
|
19
|
+
const decodedCodes = codes ? codes.sort() : []
|
|
20
|
+
|
|
21
|
+
const settings = {
|
|
22
|
+
prcodes: decodedCodes,
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
|
|
28
|
+
<span
|
|
29
|
+
v-for="(prcode, index) in settings.prcodes"
|
|
30
|
+
:key="index"
|
|
31
|
+
class="not-last:mr-1"
|
|
32
|
+
>
|
|
33
|
+
<PrCode :prcode="prcode" v-if="!String(prcode).includes('+')" />
|
|
34
|
+
<span v-else >
|
|
35
|
+
<PrCode v-for="(splittedCode, index2) in String(prcode).split('+')" :key="index2" :prcode="splittedCode" />
|
|
36
|
+
</span>
|
|
37
|
+
</span>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { PropType } from 'vue';
|
|
3
|
-
|
|
4
|
-
const props = defineProps({
|
|
5
|
-
as: {
|
|
6
|
-
type: String as PropType< 'th'| 'td' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'div' | 'span'>,
|
|
7
|
-
default: 'div',
|
|
8
|
-
required: true,
|
|
9
|
-
},
|
|
10
|
-
text: {
|
|
11
|
-
type: String,
|
|
12
|
-
default: '',
|
|
13
|
-
required: true,
|
|
14
|
-
},
|
|
15
|
-
styles: {
|
|
16
|
-
type: String,
|
|
17
|
-
default: '',
|
|
18
|
-
required: false,
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<template>
|
|
24
|
-
<component :is="props.as" class="font-bold detail-name w-full sm:w-50 flex 2xl:w-64">
|
|
25
|
-
<span :class="styles && styles.length ? styles : 'mt-auto'">
|
|
26
|
-
<b class="bg-white z-1 colon-after pr-1">{{ props.text }}</b>
|
|
27
|
-
</span>
|
|
28
|
-
</component>
|
|
29
|
-
</template>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<style>
|
|
33
|
-
.detail-name {
|
|
34
|
-
@apply overflow-hidden relative;
|
|
35
|
-
|
|
36
|
-
span {
|
|
37
|
-
@apply block bg-white relative z-10 pr-1.5 w-full;
|
|
38
|
-
|
|
39
|
-
&:before {
|
|
40
|
-
/* // order: 2; */
|
|
41
|
-
@apply text-gray-300 absolute select-none border-b border-gray-200 w-full -z-1 absolute content-empty left-0;
|
|
42
|
-
height: 1em;
|
|
43
|
-
white-space: nowrap;
|
|
44
|
-
font-weight: 100;
|
|
45
|
-
bottom: 2px;
|
|
46
|
-
flex: 1;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { PropType } from 'vue';
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
as: {
|
|
6
|
+
type: String as PropType< 'th'| 'td' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'div' | 'span'>,
|
|
7
|
+
default: 'div',
|
|
8
|
+
required: true,
|
|
9
|
+
},
|
|
10
|
+
text: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: '',
|
|
13
|
+
required: true,
|
|
14
|
+
},
|
|
15
|
+
styles: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: '',
|
|
18
|
+
required: false,
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<component :is="props.as" class="font-bold detail-name w-full sm:w-50 flex 2xl:w-64">
|
|
25
|
+
<span :class="styles && styles.length ? styles : 'mt-auto'">
|
|
26
|
+
<b class="bg-white z-1 colon-after pr-1">{{ props.text }}</b>
|
|
27
|
+
</span>
|
|
28
|
+
</component>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<style>
|
|
33
|
+
.detail-name {
|
|
34
|
+
@apply overflow-hidden relative;
|
|
35
|
+
|
|
36
|
+
span {
|
|
37
|
+
@apply block bg-white relative z-10 pr-1.5 w-full;
|
|
38
|
+
|
|
39
|
+
&:before {
|
|
40
|
+
/* // order: 2; */
|
|
41
|
+
@apply text-gray-300 absolute select-none border-b border-gray-200 w-full -z-1 absolute content-empty left-0;
|
|
42
|
+
height: 1em;
|
|
43
|
+
white-space: nowrap;
|
|
44
|
+
font-weight: 100;
|
|
45
|
+
bottom: 2px;
|
|
46
|
+
flex: 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
53
|
</style>
|
|
@@ -1,158 +1,130 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { PropType, computed } from "vue";
|
|
3
|
-
import ProductDetailName from "./ProductDetailName.vue";
|
|
4
|
-
|
|
5
|
-
interface TableItem {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
value: unknown;
|
|
9
|
-
translated?: boolean;
|
|
10
|
-
icon?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface GroupedLink {
|
|
14
|
-
id: string;
|
|
15
|
-
links: {
|
|
16
|
-
name: string;
|
|
17
|
-
value: string;
|
|
18
|
-
}[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const props = defineProps({
|
|
22
|
-
items: { type: Array as PropType<TableItem[]>, default: () => [] },
|
|
23
|
-
caption: { type: String, default: null }
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
const isLink = (id: string) => {
|
|
28
|
-
return ['blog', 'youtube', 'vimeo'].includes(id);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// Function for specifying header text
|
|
32
|
-
const getHeaderText = (row: TableItem | GroupedLink) => {
|
|
33
|
-
//
|
|
34
|
-
if (row.id === 'blog') {
|
|
35
|
-
return row.id.charAt(0).toUpperCase() + row.id.slice(1); // "Blog" z dużej litery
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// For other types, we use name (if it is GroupedLink, there is no name)
|
|
39
|
-
return 'name' in row ? row.name : row.id.charAt(0).toUpperCase() + row.id.slice(1);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
const getLinkIconClass = (linkId: string) => {
|
|
44
|
-
switch (linkId) {
|
|
45
|
-
case 'blog':
|
|
46
|
-
return 'i-lucide-book-text';
|
|
47
|
-
case 'youtube':
|
|
48
|
-
return 'i-simple-icons-youtube';
|
|
49
|
-
case 'vimeo':
|
|
50
|
-
return 'i-simple-icons-vimeo';
|
|
51
|
-
default:
|
|
52
|
-
return 'i-lucide-link';
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// Grouping of elements by id
|
|
57
|
-
const groupedItems = computed(() => {
|
|
58
|
-
const result: (TableItem | GroupedLink)[] = [];
|
|
59
|
-
const linkGroups = new Map<string, GroupedLink>();
|
|
60
|
-
|
|
61
|
-
// We process all elements
|
|
62
|
-
props.items.forEach(item => {
|
|
63
|
-
// If it's a link (blog, youtube, vimeo)
|
|
64
|
-
if (isLink(item.id)) {
|
|
65
|
-
// Add a link to the relevant group
|
|
66
|
-
if (!linkGroups.has(item.id)) {
|
|
67
|
-
linkGroups.set(item.id, {
|
|
68
|
-
id: item.id,
|
|
69
|
-
links: []
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Dodajemy link do odpowiedniej grupy
|
|
74
|
-
linkGroups.get(item.id)?.links.push({
|
|
75
|
-
name: item.name,
|
|
76
|
-
value: item.value as string
|
|
77
|
-
});
|
|
78
|
-
} else {
|
|
79
|
-
// If it is not a link, we add it normally to the results
|
|
80
|
-
result.push(item);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
// Add all link groups at the end
|
|
85
|
-
linkGroups.forEach(group => {
|
|
86
|
-
result.push(group);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
return result;
|
|
90
|
-
});
|
|
91
|
-
</script>
|
|
92
|
-
|
|
93
|
-
<template>
|
|
94
|
-
<table class="details
|
|
95
|
-
<caption v-if="!!$slots.caption || caption">
|
|
96
|
-
<slot name="caption">{{ caption }}</slot>
|
|
97
|
-
</caption>
|
|
98
|
-
<colgroup>
|
|
99
|
-
<col>
|
|
100
|
-
<col>
|
|
101
|
-
</colgroup>
|
|
102
|
-
<tbody>
|
|
103
|
-
<tr v-for="row, index in groupedItems" :key="index">
|
|
104
|
-
<!-- We use the getHeaderText function to specify the header text -->
|
|
105
|
-
<ProductDetailName
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
</
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
box-shadow: none;
|
|
132
|
-
|
|
133
|
-
col {
|
|
134
|
-
@apply w-1/2 md:w-auto;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
tr {
|
|
138
|
-
@apply border-none;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
tr,
|
|
142
|
-
th {
|
|
143
|
-
@apply leading-none text-3.5 py-2 border-none xl:(py-4) 3xl:(text-4);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
th {
|
|
147
|
-
@apply px-0;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
td {
|
|
151
|
-
@apply relative;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.link-primary {
|
|
156
|
-
@apply leading-none text-brand-primary hover:text-accent-light hover:underline;
|
|
157
|
-
}
|
|
158
|
-
</style>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { PropType, computed } from "vue";
|
|
3
|
+
import ProductDetailName from "./ProductDetailName.vue";
|
|
4
|
+
|
|
5
|
+
interface TableItem {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
value: unknown;
|
|
9
|
+
translated?: boolean;
|
|
10
|
+
icon?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface GroupedLink {
|
|
14
|
+
id: string;
|
|
15
|
+
links: {
|
|
16
|
+
name: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const props = defineProps({
|
|
22
|
+
items: { type: Array as PropType<TableItem[]>, default: () => [] },
|
|
23
|
+
caption: { type: String, default: null }
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Function for checking whether a value is a link
|
|
27
|
+
const isLink = (id: string) => {
|
|
28
|
+
return ['blog', 'youtube', 'vimeo'].includes(id);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Function for specifying header text
|
|
32
|
+
const getHeaderText = (row: TableItem | GroupedLink) => {
|
|
33
|
+
// For the blog, we use id instead of name
|
|
34
|
+
if (row.id === 'blog') {
|
|
35
|
+
return row.id.charAt(0).toUpperCase() + row.id.slice(1); // "Blog" z dużej litery
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// For other types, we use name (if it is GroupedLink, there is no name)
|
|
39
|
+
return 'name' in row ? row.name : row.id.charAt(0).toUpperCase() + row.id.slice(1);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Function to determine the icon class for a link type
|
|
43
|
+
const getLinkIconClass = (linkId: string) => {
|
|
44
|
+
switch (linkId) {
|
|
45
|
+
case 'blog':
|
|
46
|
+
return 'i-lucide-book-text';
|
|
47
|
+
case 'youtube':
|
|
48
|
+
return 'i-simple-icons-youtube';
|
|
49
|
+
case 'vimeo':
|
|
50
|
+
return 'i-simple-icons-vimeo';
|
|
51
|
+
default:
|
|
52
|
+
return 'i-lucide-link';
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Grouping of elements by id
|
|
57
|
+
const groupedItems = computed(() => {
|
|
58
|
+
const result: (TableItem | GroupedLink)[] = [];
|
|
59
|
+
const linkGroups = new Map<string, GroupedLink>();
|
|
60
|
+
|
|
61
|
+
// We process all elements
|
|
62
|
+
props.items.forEach(item => {
|
|
63
|
+
// If it's a link (blog, youtube, vimeo)
|
|
64
|
+
if (isLink(item.id)) {
|
|
65
|
+
// Add a link to the relevant group
|
|
66
|
+
if (!linkGroups.has(item.id)) {
|
|
67
|
+
linkGroups.set(item.id, {
|
|
68
|
+
id: item.id,
|
|
69
|
+
links: []
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Dodajemy link do odpowiedniej grupy
|
|
74
|
+
linkGroups.get(item.id)?.links.push({
|
|
75
|
+
name: item.name,
|
|
76
|
+
value: item.value as string
|
|
77
|
+
});
|
|
78
|
+
} else {
|
|
79
|
+
// If it is not a link, we add it normally to the results
|
|
80
|
+
result.push(item);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Add all link groups at the end
|
|
85
|
+
linkGroups.forEach(group => {
|
|
86
|
+
result.push(group);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return result;
|
|
90
|
+
});
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<table class="details-table">
|
|
95
|
+
<caption v-if="!!$slots.caption || caption">
|
|
96
|
+
<slot name="caption">{{ caption }}</slot>
|
|
97
|
+
</caption>
|
|
98
|
+
<colgroup>
|
|
99
|
+
<col class="details-table-col">
|
|
100
|
+
<col class="details-table-col">
|
|
101
|
+
</colgroup>
|
|
102
|
+
<tbody>
|
|
103
|
+
<tr v-for="row, index in groupedItems" :key="index" class="details-table-row">
|
|
104
|
+
<!-- We use the getHeaderText function to specify the header text -->
|
|
105
|
+
<ProductDetailName
|
|
106
|
+
as="th"
|
|
107
|
+
:text="getHeaderText(row)"
|
|
108
|
+
class="details-table-header"
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
<!-- Handling link groups -->
|
|
112
|
+
<td v-if="'links' in row" class="details-table-cell">
|
|
113
|
+
<ul class="list-none p-0 m-0">
|
|
114
|
+
<li v-for="(link, linkIndex) in row.links" :key="linkIndex" class="mb-2 last:mb-0 flex items-center">
|
|
115
|
+
<span :class="[getLinkIconClass(row.id), 'leading-none inline-block mr-2 w-4 min-w-4 h-4 text-gray-400']" />
|
|
116
|
+
<a :href="link.value" target="_blank" rel="noopener noreferrer" class="link-primary">
|
|
117
|
+
{{ link.name }}
|
|
118
|
+
</a>
|
|
119
|
+
</li>
|
|
120
|
+
</ul>
|
|
121
|
+
</td>
|
|
122
|
+
|
|
123
|
+
<!-- Support for standard types -->
|
|
124
|
+
<slot v-else-if="'id' in row" :name="row.id">
|
|
125
|
+
<td class="details-table-cell">{{ row.value }}</td>
|
|
126
|
+
</slot>
|
|
127
|
+
</tr>
|
|
128
|
+
</tbody>
|
|
129
|
+
</table>
|
|
130
|
+
</template>
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
---
|
|
2
|
-
const { productObject, locale, index } = Astro.props;
|
|
3
|
-
import Image from "./Image.astro"
|
|
4
|
-
import ProductNumber from "./Product/ProductNumber.astro"
|
|
5
|
-
import { t } from "i18next";
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
{ productObject &&
|
|
9
|
-
(
|
|
10
|
-
|
|
11
|
-
<!-- product image -->
|
|
12
|
-
<div class="img--4/3 img--small">
|
|
13
|
-
{ productObject.photo !== null ?
|
|
14
|
-
<Image
|
|
15
|
-
imageObject={
|
|
16
|
-
{
|
|
17
|
-
src: 'https://img.freepik.com/darmowe-wektory/tlo-retro-modeli-geometrycznych_52683-17902.jpg?w=1380&t=st=1706311337',
|
|
18
|
-
alt: 'Image Alt',
|
|
19
|
-
height: '180',
|
|
20
|
-
width: '240',
|
|
21
|
-
class: 'img--overlay object-cover'
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/>
|
|
25
|
-
:
|
|
26
|
-
<img src="/1x1.png" class="bg-gray-100/70" alt={productObject.name} />
|
|
27
|
-
}
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<!-- product deails -->
|
|
31
|
-
<div class="sm:pl-4 flex flex-col" >
|
|
32
|
-
<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)"
|
|
33
|
-
href={productObject.url} itemprop="url"
|
|
34
|
-
title={productObject.number}
|
|
35
|
-
>
|
|
36
|
-
{ productObject.name }
|
|
37
|
-
</a>
|
|
38
|
-
|
|
39
|
-
<ProductNumber productNumber={productObject.number} copyDisabled={false} buttonTexts={{ copy: t('copy'), copied: t('copied') }} />
|
|
40
|
-
|
|
41
|
-
{ index !== null &&
|
|
42
|
-
( <meta itemprop="position" content={String(index)} />
|
|
43
|
-
<meta itemprop="name" content={productObject.name} /> )
|
|
44
|
-
}
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
)}
|
|
48
|
-
|
|
1
|
+
---
|
|
2
|
+
const { productObject, locale, index } = Astro.props;
|
|
3
|
+
import Image from "./Image.astro"
|
|
4
|
+
import ProductNumber from "./Product/ProductNumber.astro"
|
|
5
|
+
import { t } from "i18next";
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
{ productObject &&
|
|
9
|
+
(
|
|
10
|
+
|
|
11
|
+
<!-- product image -->
|
|
12
|
+
<div class="img--4/3 img--small">
|
|
13
|
+
{ productObject.photo !== null ?
|
|
14
|
+
<Image
|
|
15
|
+
imageObject={
|
|
16
|
+
{
|
|
17
|
+
src: 'https://img.freepik.com/darmowe-wektory/tlo-retro-modeli-geometrycznych_52683-17902.jpg?w=1380&t=st=1706311337',
|
|
18
|
+
alt: 'Image Alt',
|
|
19
|
+
height: '180',
|
|
20
|
+
width: '240',
|
|
21
|
+
class: 'img--overlay object-cover'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/>
|
|
25
|
+
:
|
|
26
|
+
<img src="/1x1.png" class="bg-gray-100/70" alt={productObject.name} />
|
|
27
|
+
}
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<!-- product deails -->
|
|
31
|
+
<div class="sm:pl-4 flex flex-col" >
|
|
32
|
+
<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)"
|
|
33
|
+
href={productObject.url} itemprop="url"
|
|
34
|
+
title={productObject.number}
|
|
35
|
+
>
|
|
36
|
+
{ productObject.name }
|
|
37
|
+
</a>
|
|
38
|
+
|
|
39
|
+
<ProductNumber productNumber={productObject.number} copyDisabled={false} buttonTexts={{ copy: t('copy'), copied: t('copied') }} />
|
|
40
|
+
|
|
41
|
+
{ index !== null &&
|
|
42
|
+
( <meta itemprop="position" content={String(index)} />
|
|
43
|
+
<meta itemprop="name" content={productObject.name} /> )
|
|
44
|
+
}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
)}
|
|
48
|
+
|