@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.
Files changed (35) hide show
  1. package/.storybook-static/favicon.svg +1 -0
  2. package/.storybook-static/index.html +156 -0
  3. package/.storybook-static/index.json +1 -0
  4. package/.storybook-static/nunito-sans-bold-italic.woff2 +0 -0
  5. package/.storybook-static/nunito-sans-bold.woff2 +0 -0
  6. package/.storybook-static/nunito-sans-italic.woff2 +0 -0
  7. package/.storybook-static/nunito-sans-regular.woff2 +0 -0
  8. package/.storybook-static/sb-addons/a11y-1/manager-bundle.js +5 -0
  9. package/.storybook-static/sb-addons/links-2/manager-bundle.js +3 -0
  10. package/.storybook-static/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +188 -0
  11. package/.storybook-static/sb-addons/themes-3/manager-bundle.js +3 -0
  12. package/.storybook-static/sb-common-assets/favicon.svg +1 -0
  13. package/.storybook-static/sb-common-assets/nunito-sans-bold-italic.woff2 +0 -0
  14. package/.storybook-static/sb-common-assets/nunito-sans-bold.woff2 +0 -0
  15. package/.storybook-static/sb-common-assets/nunito-sans-italic.woff2 +0 -0
  16. package/.storybook-static/sb-common-assets/nunito-sans-regular.woff2 +0 -0
  17. package/.storybook-static/sb-manager/globals-module-info.js +797 -0
  18. package/.storybook-static/sb-manager/globals-runtime.js +72062 -0
  19. package/.storybook-static/sb-manager/globals.js +34 -0
  20. package/.storybook-static/sb-manager/runtime.js +13002 -0
  21. package/dist/css/tailwind-brandCrowd.css +10 -113
  22. package/dist/css/tailwind-brandPage.css +324 -107
  23. package/dist/css/tailwind-crazyDomains.css +110 -213
  24. package/dist/css/tailwind-designCom.css +119 -222
  25. package/dist/css/tailwind-designCrowd.css +88 -191
  26. package/index.js +1 -0
  27. package/package.json +1 -1
  28. package/public/css/tailwind-brandCrowd.css +2508 -0
  29. package/public/css/tailwind-brandPage.css +2188 -0
  30. package/public/css/tailwind-crazyDomains.css +2508 -0
  31. package/public/css/tailwind-designCom.css +2508 -0
  32. package/public/css/tailwind-designCrowd.css +2508 -0
  33. package/src/atoms/components/Button/variants/ButtonGray.vue +7 -5
  34. package/src/atoms/components/Carousel/CarouselSSR.vue +215 -0
  35. 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': !disabled,
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-font-bold tw-text-grayscale-800 hover:tw-text-grayscale-800 tw-uppercase tw-border-solid tw-transition-colors tw-duration-300 tw-no-underline"
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': !disabled,
33
- 'tw-bg-grayscale-100 tw-cursor-not-allowed': disabled,
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
+ };