@designcrowd/fe-shared-lib 1.5.25 → 1.5.26-pre-gt-0007
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/.storybook-static/favicon.svg +1 -0
- package/.storybook-static/index.html +156 -0
- package/.storybook-static/index.json +1 -0
- package/.storybook-static/nunito-sans-bold-italic.woff2 +0 -0
- package/.storybook-static/nunito-sans-bold.woff2 +0 -0
- package/.storybook-static/nunito-sans-italic.woff2 +0 -0
- package/.storybook-static/nunito-sans-regular.woff2 +0 -0
- package/.storybook-static/sb-addons/a11y-1/manager-bundle.js +5 -0
- package/.storybook-static/sb-addons/links-2/manager-bundle.js +3 -0
- package/.storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +188 -0
- package/.storybook-static/sb-addons/themes-3/manager-bundle.js +3 -0
- package/.storybook-static/sb-common-assets/favicon.svg +1 -0
- package/.storybook-static/sb-common-assets/nunito-sans-bold-italic.woff2 +0 -0
- package/.storybook-static/sb-common-assets/nunito-sans-bold.woff2 +0 -0
- package/.storybook-static/sb-common-assets/nunito-sans-italic.woff2 +0 -0
- package/.storybook-static/sb-common-assets/nunito-sans-regular.woff2 +0 -0
- package/.storybook-static/sb-manager/globals-module-info.js +797 -0
- package/.storybook-static/sb-manager/globals-runtime.js +72062 -0
- package/.storybook-static/sb-manager/globals.js +34 -0
- package/.storybook-static/sb-manager/runtime.js +13002 -0
- package/dist/css/tailwind-brandCrowd.css +10 -113
- package/dist/css/tailwind-brandPage.css +324 -107
- package/dist/css/tailwind-crazyDomains.css +110 -213
- package/dist/css/tailwind-designCom.css +119 -222
- package/dist/css/tailwind-designCrowd.css +88 -191
- package/index.js +1 -0
- package/package.json +1 -1
- package/public/css/tailwind-brandCrowd.css +2508 -0
- package/public/css/tailwind-brandPage.css +2188 -0
- package/public/css/tailwind-crazyDomains.css +2508 -0
- package/public/css/tailwind-designCom.css +2508 -0
- package/public/css/tailwind-designCrowd.css +2508 -0
- package/src/atoms/components/Button/variants/ButtonGray.vue +7 -5
- package/src/atoms/components/Carousel/CarouselSSR.vue +215 -0
- package/src/atoms/components/Carousel/carousel.stories.js +135 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<button
|
|
3
3
|
v-if="!url"
|
|
4
|
-
class="tw-font-sans tw-font-bold tw-text-grayscale-800 tw-uppercase tw-border-solid tw-transition-colors tw-duration-300"
|
|
4
|
+
class="tw-font-sans tw-border-2 tw-font-bold tw-text-grayscale-800 tw-uppercase tw-border-solid tw-transition-colors tw-duration-300"
|
|
5
5
|
:class="[
|
|
6
6
|
classes,
|
|
7
7
|
computedClasses,
|
|
8
8
|
{
|
|
9
9
|
'no-rounded-l': !rounded && !roundedLeft,
|
|
10
10
|
'no-rounded-r': !rounded && !roundedRight,
|
|
11
|
-
'tw-cursor-pointer tw-bg-grayscale-300 hover:tw-bg-grayscale-500':
|
|
11
|
+
'tw-cursor-pointer tw-bg-grayscale-300 tw-border-grayscale-300 hover:tw-border-grayscale-500 hover:tw-bg-grayscale-500':
|
|
12
|
+
!disabled,
|
|
12
13
|
'tw-bg-grayscale-100 tw-border-grayscale-300 tw-cursor-not-allowed': disabled,
|
|
13
14
|
},
|
|
14
15
|
]"
|
|
@@ -22,15 +23,16 @@
|
|
|
22
23
|
<a
|
|
23
24
|
v-else
|
|
24
25
|
:href="computedUrl"
|
|
25
|
-
class="tw-justify-center tw-font-sans tw-inline-flex tw-
|
|
26
|
+
class="tw-justify-center tw-font-sans tw-inline-flex tw-border-2 tw-font-bold tw-text-grayscale-800 tw-uppercase tw-border-solid tw-transition-colors tw-duration-300 tw-no-underline"
|
|
26
27
|
:class="[
|
|
27
28
|
classes,
|
|
28
29
|
computedClasses,
|
|
29
30
|
{
|
|
30
31
|
'no-rounded-l': !rounded && !roundedLeft,
|
|
31
32
|
'no-rounded-r': !rounded && !roundedRight,
|
|
32
|
-
'tw-cursor-pointer tw-bg-grayscale-300 hover:tw-bg-grayscale-500':
|
|
33
|
-
|
|
33
|
+
'tw-cursor-pointer tw-bg-grayscale-300 tw-border-grayscale-300 hover:tw-border-grayscale-500 hover:tw-bg-grayscale-500':
|
|
34
|
+
!disabled,
|
|
35
|
+
'tw-bg-grayscale-100 tw-border-grayscale-100 tw-cursor-not-allowed': disabled,
|
|
34
36
|
},
|
|
35
37
|
]"
|
|
36
38
|
:download="download"
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="['carousel tw-flex tw-flex-col tw-box-content', ...normalizedClasses]">
|
|
3
|
+
<!-- SSR Skeleton: rendered server-side and before client mount -->
|
|
4
|
+
<div v-if="!isMounted" class="tw-flex tw-items-center tw-relative">
|
|
5
|
+
<div class="swiper tw-w-full tw-overflow-hidden">
|
|
6
|
+
<div class="swiper-wrapper tw-flex tw-flex-row" :style="skeletonWrapperStyle">
|
|
7
|
+
<div
|
|
8
|
+
v-for="(slide, i) in visibleCards"
|
|
9
|
+
:key="i"
|
|
10
|
+
class="swiper-slide tw-h-auto tw-flex-shrink-0"
|
|
11
|
+
:style="slideStyle(slide)"
|
|
12
|
+
>
|
|
13
|
+
<div class="tw-h-full">
|
|
14
|
+
<slot name="slide" :slide="slide" :index="i"></slot>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<!-- Actual Carousel: only rendered after client-side mount -->
|
|
22
|
+
<Carousel
|
|
23
|
+
v-else
|
|
24
|
+
:ref="swiperRef"
|
|
25
|
+
:swiper-ref="swiperRef"
|
|
26
|
+
:classes="classes"
|
|
27
|
+
:cards="cards"
|
|
28
|
+
:options="options"
|
|
29
|
+
:disable-right-click="disableRightClick"
|
|
30
|
+
:nav-carousel="navCarousel"
|
|
31
|
+
:show-controls="showControls"
|
|
32
|
+
:show-bullets="showBullets"
|
|
33
|
+
:hide-bullets-on-mobile="hideBulletsOnMobile"
|
|
34
|
+
:hide-bullets-element="hideBulletsElement"
|
|
35
|
+
:navigation-unique-indexer="navigationUniqueIndexer"
|
|
36
|
+
:slide-index="slideIndex"
|
|
37
|
+
@on-carousel-load="onCarouselLoad"
|
|
38
|
+
>
|
|
39
|
+
<template #slide="{ slide, index }">
|
|
40
|
+
<slot name="slide" :slide="slide" :index="index"></slot>
|
|
41
|
+
</template>
|
|
42
|
+
<template #arrow-left>
|
|
43
|
+
<slot name="arrow-left"></slot>
|
|
44
|
+
</template>
|
|
45
|
+
<template #arrow-right>
|
|
46
|
+
<slot name="arrow-right"></slot>
|
|
47
|
+
</template>
|
|
48
|
+
</Carousel>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script setup>
|
|
53
|
+
import { ref, computed, onMounted } from 'vue';
|
|
54
|
+
import Carousel from './Carousel.vue';
|
|
55
|
+
|
|
56
|
+
const props = defineProps({
|
|
57
|
+
classes: {
|
|
58
|
+
type: [String, Object, Array],
|
|
59
|
+
required: false,
|
|
60
|
+
default: () => [],
|
|
61
|
+
},
|
|
62
|
+
cards: {
|
|
63
|
+
type: Array,
|
|
64
|
+
required: true,
|
|
65
|
+
},
|
|
66
|
+
options: {
|
|
67
|
+
type: Object,
|
|
68
|
+
required: false,
|
|
69
|
+
default: () => ({}),
|
|
70
|
+
},
|
|
71
|
+
disableRightClick: {
|
|
72
|
+
type: Boolean,
|
|
73
|
+
required: false,
|
|
74
|
+
default: false,
|
|
75
|
+
},
|
|
76
|
+
navCarousel: {
|
|
77
|
+
type: Boolean,
|
|
78
|
+
required: false,
|
|
79
|
+
default: false,
|
|
80
|
+
},
|
|
81
|
+
showControls: {
|
|
82
|
+
type: Boolean,
|
|
83
|
+
required: false,
|
|
84
|
+
default: true,
|
|
85
|
+
},
|
|
86
|
+
showBullets: {
|
|
87
|
+
type: Boolean,
|
|
88
|
+
required: false,
|
|
89
|
+
default: true,
|
|
90
|
+
},
|
|
91
|
+
hideBulletsOnMobile: {
|
|
92
|
+
type: Boolean,
|
|
93
|
+
required: false,
|
|
94
|
+
default: true,
|
|
95
|
+
},
|
|
96
|
+
hideBulletsElement: {
|
|
97
|
+
type: Boolean,
|
|
98
|
+
required: false,
|
|
99
|
+
default: false,
|
|
100
|
+
},
|
|
101
|
+
swiperRef: {
|
|
102
|
+
type: String,
|
|
103
|
+
default: 'js-swiper',
|
|
104
|
+
},
|
|
105
|
+
navigationUniqueIndexer: {
|
|
106
|
+
type: String,
|
|
107
|
+
default: undefined,
|
|
108
|
+
},
|
|
109
|
+
slideIndex: {
|
|
110
|
+
type: Number,
|
|
111
|
+
required: false,
|
|
112
|
+
default: undefined,
|
|
113
|
+
},
|
|
114
|
+
skeletonSlideCount: {
|
|
115
|
+
type: Number,
|
|
116
|
+
required: false,
|
|
117
|
+
default: 6,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const emit = defineEmits(['on-carousel-load']);
|
|
122
|
+
|
|
123
|
+
const isMounted = ref(false);
|
|
124
|
+
|
|
125
|
+
onMounted(() => {
|
|
126
|
+
isMounted.value = true;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const normalizedClasses = computed(() => {
|
|
130
|
+
if (Array.isArray(props.classes)) {
|
|
131
|
+
return props.classes;
|
|
132
|
+
}
|
|
133
|
+
if (typeof props.classes === 'string') {
|
|
134
|
+
return [props.classes];
|
|
135
|
+
}
|
|
136
|
+
return [props.classes];
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const visibleCards = computed(() => {
|
|
140
|
+
return props.cards.slice(0, props.skeletonSlideCount);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const spaceBetween = computed(() => {
|
|
144
|
+
return props.options?.spaceBetween ?? 10;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const skeletonWrapperStyle = computed(() => {
|
|
148
|
+
return {
|
|
149
|
+
gap: `${spaceBetween.value}px`,
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const slideStyle = (slide) => {
|
|
154
|
+
if (slide.width) {
|
|
155
|
+
const width = typeof slide.width === 'number' ? `${slide.width}px` : slide.width;
|
|
156
|
+
return { width, minWidth: width };
|
|
157
|
+
}
|
|
158
|
+
return {};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const onCarouselLoad = () => {
|
|
162
|
+
emit('on-carousel-load');
|
|
163
|
+
};
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<style scoped>
|
|
167
|
+
.carousel :deep(.swiper-button-next, .swiper-button-prev) {
|
|
168
|
+
@apply tw-hidden;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.carousel :deep(.swiper-button-disabled) {
|
|
172
|
+
@apply tw-hidden;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.carousel :deep(.swiper-pagination) {
|
|
176
|
+
@apply tw-static tw-pt-6;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.carousel :deep(.swiper-pagination-bullets) {
|
|
180
|
+
@apply tw-text-center;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.carousel :deep(.swiper-pagination--desktop-only) {
|
|
184
|
+
@apply tw-hidden sm:tw-block;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.carousel :deep(.carousel__button-nav) {
|
|
188
|
+
@apply tw-relative;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.carousel :deep(.swiper-pagination-bullet) {
|
|
192
|
+
border-color: #595959;
|
|
193
|
+
@apply tw-border-2 tw-border-solid tw-opacity-100 tw-bg-transparent tw-w-2 tw-h-2 tw-inline-block tw-rounded tw-cursor-pointer;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.carousel :deep(.swiper-pagination-bullet.swiper-pagination-bullet-active) {
|
|
197
|
+
background-color: #595959;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.carousel :deep(.swiper-pagination-bullet:not(:last-child)) {
|
|
201
|
+
@apply tw-mr-2;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.carousel :deep(.swiper-pagination-bullet:only-child) {
|
|
205
|
+
@apply tw-hidden;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.carousel :deep(.swiper-container) {
|
|
209
|
+
@apply tw-w-full;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.carousel :deep(.swiper-slide) {
|
|
213
|
+
@apply tw-h-auto tw-w-auto;
|
|
214
|
+
}
|
|
215
|
+
</style>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Icon from '../Icon/Icon.vue';
|
|
2
2
|
import { cards } from './Carousel.fixtures';
|
|
3
3
|
import Carousel from './Carousel.vue';
|
|
4
|
+
import CarouselSSR from './CarouselSSR.vue';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
title: 'Components/Carousel',
|
|
@@ -528,3 +529,137 @@ export const ResponsiveBreakpoints = {
|
|
|
528
529
|
},
|
|
529
530
|
},
|
|
530
531
|
};
|
|
532
|
+
|
|
533
|
+
// CarouselSSR - SSR-safe wrapper that prevents hydration mismatches
|
|
534
|
+
export const SSRSafe = {
|
|
535
|
+
args: {
|
|
536
|
+
cards,
|
|
537
|
+
showControls: true,
|
|
538
|
+
showBullets: true,
|
|
539
|
+
options: {
|
|
540
|
+
loop: true,
|
|
541
|
+
spaceBetween: 20,
|
|
542
|
+
slidesPerView: 1,
|
|
543
|
+
breakpoints: {
|
|
544
|
+
640: {
|
|
545
|
+
slidesPerView: 2,
|
|
546
|
+
slidesPerGroup: 2,
|
|
547
|
+
},
|
|
548
|
+
1024: {
|
|
549
|
+
slidesPerView: 3,
|
|
550
|
+
slidesPerGroup: 3,
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
render: (args) => ({
|
|
556
|
+
components: { CarouselSSR },
|
|
557
|
+
setup() {
|
|
558
|
+
return { args };
|
|
559
|
+
},
|
|
560
|
+
template: `
|
|
561
|
+
<div class="tw-p-8">
|
|
562
|
+
<div class="tw-mb-4 tw-p-4 tw-bg-green-50 tw-rounded-lg">
|
|
563
|
+
<p class="tw-text-sm tw-font-semibold tw-text-green-800">CarouselSSR Component</p>
|
|
564
|
+
<p class="tw-text-sm tw-text-green-700 tw-mt-1">
|
|
565
|
+
This wrapper prevents hydration mismatch errors in SSR environments (Nuxt).
|
|
566
|
+
It renders a static skeleton server-side, then switches to the interactive Swiper on the client.
|
|
567
|
+
</p>
|
|
568
|
+
</div>
|
|
569
|
+
<CarouselSSR
|
|
570
|
+
:cards="args.cards"
|
|
571
|
+
:show-controls="args.showControls"
|
|
572
|
+
:show-bullets="args.showBullets"
|
|
573
|
+
:options="args.options"
|
|
574
|
+
>
|
|
575
|
+
<template #slide="{ slide }">
|
|
576
|
+
<div class="tw-flex tw-flex-col tw-items-center tw-cursor-pointer tw-p-4 tw-bg-gray-50 tw-rounded-lg tw-h-full">
|
|
577
|
+
<img :src="slide.imageUrl" :alt="slide.name" class="tw-w-full tw-h-48 tw-object-contain tw-mb-4" />
|
|
578
|
+
<span class="tw-text-lg tw-font-semibold tw-text-center">{{ slide.name }}</span>
|
|
579
|
+
</div>
|
|
580
|
+
</template>
|
|
581
|
+
</CarouselSSR>
|
|
582
|
+
</div>
|
|
583
|
+
`,
|
|
584
|
+
}),
|
|
585
|
+
parameters: {
|
|
586
|
+
docs: {
|
|
587
|
+
description: {
|
|
588
|
+
story: `
|
|
589
|
+
**CarouselSSR** is an SSR-safe wrapper around the Carousel component designed for use in Nuxt/SSR environments.
|
|
590
|
+
|
|
591
|
+
### Why use CarouselSSR?
|
|
592
|
+
Swiper.js initializes client-side and adds classes/styles that don't exist on the server, causing Vue hydration mismatches. CarouselSSR solves this by:
|
|
593
|
+
|
|
594
|
+
1. **Server-side**: Renders a static skeleton that matches the carousel layout (showing actual card content)
|
|
595
|
+
2. **Client-side**: After mount, switches to the interactive Swiper carousel
|
|
596
|
+
|
|
597
|
+
### Migration
|
|
598
|
+
Replace \`Carousel\` with \`CarouselSSR\` - the API is identical:
|
|
599
|
+
|
|
600
|
+
\`\`\`vue
|
|
601
|
+
<!-- Before -->
|
|
602
|
+
<Carousel :cards="cards" :options="options">
|
|
603
|
+
<template #slide="{ slide }">...</template>
|
|
604
|
+
</Carousel>
|
|
605
|
+
|
|
606
|
+
<!-- After -->
|
|
607
|
+
<CarouselSSR :cards="cards" :options="options">
|
|
608
|
+
<template #slide="{ slide }">...</template>
|
|
609
|
+
</CarouselSSR>
|
|
610
|
+
\`\`\`
|
|
611
|
+
|
|
612
|
+
### Additional Props
|
|
613
|
+
- \`skeletonSlideCount\` (Number, default: 6) - How many slides to show in the skeleton
|
|
614
|
+
`,
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
// CarouselSSR with custom skeleton slide count
|
|
621
|
+
export const SSRSafeCustomSkeletonCount = {
|
|
622
|
+
args: {
|
|
623
|
+
cards: [...cards, ...cards],
|
|
624
|
+
skeletonSlideCount: 3,
|
|
625
|
+
options: {
|
|
626
|
+
spaceBetween: 20,
|
|
627
|
+
slidesPerView: 'auto',
|
|
628
|
+
},
|
|
629
|
+
},
|
|
630
|
+
render: (args) => ({
|
|
631
|
+
components: { CarouselSSR },
|
|
632
|
+
setup() {
|
|
633
|
+
return { args };
|
|
634
|
+
},
|
|
635
|
+
template: `
|
|
636
|
+
<div class="tw-p-8">
|
|
637
|
+
<div class="tw-mb-4 tw-p-4 tw-bg-blue-50 tw-rounded-lg">
|
|
638
|
+
<p class="tw-text-sm tw-text-blue-800">
|
|
639
|
+
<strong>skeletonSlideCount: 3</strong> - Only shows 3 slides in the SSR skeleton,
|
|
640
|
+
even though there are more cards. Useful for controlling initial render size.
|
|
641
|
+
</p>
|
|
642
|
+
</div>
|
|
643
|
+
<CarouselSSR
|
|
644
|
+
:cards="args.cards"
|
|
645
|
+
:skeleton-slide-count="args.skeletonSlideCount"
|
|
646
|
+
:options="args.options"
|
|
647
|
+
>
|
|
648
|
+
<template #slide="{ slide }">
|
|
649
|
+
<div class="tw-flex tw-flex-col tw-items-center tw-p-4 tw-bg-white tw-rounded-lg tw-shadow" style="width: 200px;">
|
|
650
|
+
<img :src="slide.imageUrl" :alt="slide.name" class="tw-w-full tw-h-32 tw-object-contain tw-mb-2" />
|
|
651
|
+
<span class="tw-text-center tw-text-sm tw-font-medium">{{ slide.name }}</span>
|
|
652
|
+
</div>
|
|
653
|
+
</template>
|
|
654
|
+
</CarouselSSR>
|
|
655
|
+
</div>
|
|
656
|
+
`,
|
|
657
|
+
}),
|
|
658
|
+
parameters: {
|
|
659
|
+
docs: {
|
|
660
|
+
description: {
|
|
661
|
+
story: 'Control how many slides appear in the SSR skeleton with the `skeletonSlideCount` prop.',
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
};
|