@nexxtmove/ui 0.1.22 → 0.1.23

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 (66) hide show
  1. package/dist/index.d.ts +75 -8
  2. package/dist/index.js +2408 -252
  3. package/dist/nuxt.d.ts +1 -0
  4. package/dist/nuxt.js +49 -0
  5. package/package.json +23 -13
  6. package/src/assets/images/Template_aanvragen.jpg +0 -0
  7. package/src/assets/svg/type_post.svg +1 -0
  8. package/src/assets/svg/type_reel.svg +54 -0
  9. package/src/assets/svg/type_story.svg +46 -0
  10. package/src/assets/svg/type_tiktok.svg +1 -0
  11. package/src/assets/video/Template_aanvragen.mp4 +0 -0
  12. package/src/components/AnimatedNumber/AnimatedNumber.stories.ts +15 -0
  13. package/src/components/AnimatedNumber/AnimatedNumber.test.ts +56 -0
  14. package/src/components/AnimatedNumber/AnimatedNumber.vue +61 -0
  15. package/src/components/Button/Button.stories.ts +212 -0
  16. package/src/components/Button/Button.test.ts +318 -0
  17. package/src/components/Button/Button.vue +67 -0
  18. package/src/components/Calendar/Calendar.stories.ts +91 -0
  19. package/src/components/Calendar/Calendar.test.ts +269 -0
  20. package/src/components/Calendar/Calendar.vue +221 -0
  21. package/src/components/Calendar/_CalendarDayView.test.ts +145 -0
  22. package/src/components/Calendar/_CalendarDayView.vue +156 -0
  23. package/src/components/Calendar/_CalendarHeader.test.ts +86 -0
  24. package/src/components/Calendar/_CalendarHeader.vue +123 -0
  25. package/src/components/Calendar/_CalendarMonthView.test.ts +68 -0
  26. package/src/components/Calendar/_CalendarMonthView.vue +70 -0
  27. package/src/components/Calendar/_CalendarYearView.vue +77 -0
  28. package/src/components/Calendar/calendar.types.ts +10 -0
  29. package/src/components/Chip/Chip.stories.ts +42 -0
  30. package/src/components/Chip/Chip.test.ts +51 -0
  31. package/src/components/Chip/Chip.vue +37 -0
  32. package/src/components/DatePicker/DatePicker.stories.ts +149 -0
  33. package/src/components/DatePicker/DatePicker.test.ts +191 -0
  34. package/src/components/DatePicker/DatePicker.vue +142 -0
  35. package/src/components/Header/Header.stories.ts +48 -0
  36. package/src/components/Header/Header.test.ts +169 -0
  37. package/src/components/Header/Header.vue +42 -0
  38. package/src/components/Icon/Icon.stories.ts +50 -0
  39. package/src/components/Icon/Icon.test.ts +73 -0
  40. package/src/components/Icon/Icon.vue +20 -0
  41. package/src/components/InfoBlock/InfoBlock.stories.ts +90 -0
  42. package/src/components/InfoBlock/InfoBlock.test.ts +101 -0
  43. package/src/components/InfoBlock/InfoBlock.vue +70 -0
  44. package/src/components/ProgressBar/ProgressBar.stories.ts +30 -0
  45. package/src/components/ProgressBar/ProgressBar.test.ts +314 -0
  46. package/src/components/ProgressBar/ProgressBar.vue +102 -0
  47. package/src/components/SocialIcons/SocialIcons.stories.ts +34 -0
  48. package/src/components/SocialIcons/SocialIcons.test.ts +58 -0
  49. package/src/components/SocialIcons/SocialIcons.vue +58 -0
  50. package/src/components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.stories.ts +11 -0
  51. package/src/components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.test.ts +131 -0
  52. package/src/components/SocialMediaCustomTemplate/SocialMediaCustomTemplate.vue +55 -0
  53. package/src/components/SocialMediaTemplate/SocialMediaTemplate.stories.ts +71 -0
  54. package/src/components/SocialMediaTemplate/SocialMediaTemplate.test.ts +466 -0
  55. package/src/components/SocialMediaTemplate/SocialMediaTemplate.vue +130 -0
  56. package/src/components/SocialMediaType/SocialMediaType.stories.ts +43 -0
  57. package/src/components/SocialMediaType/SocialMediaType.test.ts +126 -0
  58. package/src/components/SocialMediaType/SocialMediaType.vue +117 -0
  59. package/src/components/StepperHeader/StepperHeader.stories.ts +47 -0
  60. package/src/components/StepperHeader/StepperHeader.test.ts +244 -0
  61. package/src/components/StepperHeader/StepperHeader.vue +37 -0
  62. package/src/components.json +16 -0
  63. package/src/env.d.ts +23 -0
  64. package/src/index.css +2 -0
  65. package/src/index.ts +15 -0
  66. package/src/nuxt.ts +50 -0
@@ -0,0 +1,466 @@
1
+ import { mount } from '@vue/test-utils'
2
+ import { describe, it, expect, vi } from 'vitest'
3
+ import SocialMediaTemplate from './SocialMediaTemplate.vue'
4
+
5
+ describe('SocialMediaTemplate', () => {
6
+ it('renders an image when media is an image file', () => {
7
+ const wrapper = mount(SocialMediaTemplate, {
8
+ props: {
9
+ variant: 'post',
10
+ media: 'https://example.com/image.jpg',
11
+ mediaType: 'image',
12
+ name: 'Amsterdam',
13
+ type: 'Woning',
14
+ },
15
+ })
16
+
17
+ expect(wrapper.find('img').exists()).toBe(true)
18
+ expect(wrapper.find('video').exists()).toBe(false)
19
+ })
20
+
21
+ it('renders a video when media is a video file', () => {
22
+ const wrapper = mount(SocialMediaTemplate, {
23
+ props: {
24
+ variant: 'video',
25
+ media: '/barcelona.mp4',
26
+ mediaType: 'video',
27
+ name: 'Barcelona',
28
+ type: 'Woning',
29
+ muted: true,
30
+ },
31
+ })
32
+
33
+ expect(wrapper.find('video').exists()).toBe(true)
34
+ expect(wrapper.find('img').exists()).toBe(false)
35
+ })
36
+
37
+ it('displays the name and type correctly', () => {
38
+ const wrapper = mount(SocialMediaTemplate, {
39
+ props: {
40
+ variant: 'post',
41
+ media: 'https://example.com/image.png',
42
+ mediaType: 'image',
43
+ name: 'Amsterdam',
44
+ type: 'Woning',
45
+ },
46
+ })
47
+
48
+ expect(wrapper.text()).toContain('Amsterdam')
49
+ expect(wrapper.text()).toContain('Woning')
50
+ })
51
+
52
+ it('shows play icon when variant is video', () => {
53
+ const wrapper = mount(SocialMediaTemplate, {
54
+ props: {
55
+ variant: 'video',
56
+ media: '/test.mp4',
57
+ mediaType: 'video',
58
+ name: 'Test',
59
+ type: 'Video',
60
+ },
61
+ })
62
+
63
+ const icons = wrapper.findAllComponents({ name: 'NexxtIcon' })
64
+ const playIcon = icons.find((icon) => icon.props('name') === 'play-circle')
65
+ expect(playIcon).toBeDefined()
66
+ })
67
+
68
+ it('does not show play icon when variant is post', () => {
69
+ const wrapper = mount(SocialMediaTemplate, {
70
+ props: {
71
+ variant: 'post',
72
+ media: '/test.jpg',
73
+ mediaType: 'image',
74
+ name: 'Test',
75
+ type: 'Image',
76
+ },
77
+ })
78
+
79
+ const icons = wrapper.findAllComponents({ name: 'NexxtIcon' })
80
+ const playIcon = icons.find((icon) => icon.props('name') === 'play')
81
+ expect(playIcon).toBeUndefined()
82
+ })
83
+
84
+ it('shows selected overlay when selected prop is true', () => {
85
+ const wrapper = mount(SocialMediaTemplate, {
86
+ props: {
87
+ variant: 'post',
88
+ media: '/test.jpg',
89
+ mediaType: 'image',
90
+ name: 'Test',
91
+ type: 'Image',
92
+ selected: true,
93
+ },
94
+ })
95
+
96
+ const overlay = wrapper.find('.bg-cornflower-blue-200\\/70')
97
+ expect(overlay.classes()).toContain('opacity-100')
98
+ })
99
+
100
+ it('hides selected overlay when selected prop is false', () => {
101
+ const wrapper = mount(SocialMediaTemplate, {
102
+ props: {
103
+ variant: 'post',
104
+ media: '/test.jpg',
105
+ mediaType: 'image',
106
+ name: 'Test',
107
+ type: 'Image',
108
+ selected: false,
109
+ },
110
+ })
111
+
112
+ const overlay = wrapper.find('.bg-cornflower-blue-200\\/70')
113
+ expect(overlay.classes()).toContain('opacity-0')
114
+ })
115
+
116
+ it('plays video on mouseenter when media is video', async () => {
117
+ const wrapper = mount(SocialMediaTemplate, {
118
+ props: {
119
+ variant: 'video',
120
+ media: '/test.mp4',
121
+ mediaType: 'video',
122
+ name: 'Test',
123
+ type: 'Video',
124
+ muted: true,
125
+ },
126
+ })
127
+
128
+ const video = wrapper.find('video').element as HTMLVideoElement
129
+ const playSpy = vi.spyOn(video, 'play').mockImplementation(() => Promise.resolve())
130
+
131
+ await wrapper.trigger('mouseenter')
132
+
133
+ expect(playSpy).toHaveBeenCalled()
134
+ })
135
+
136
+ it('pauses video on mouseleave when media is video', async () => {
137
+ const wrapper = mount(SocialMediaTemplate, {
138
+ props: {
139
+ variant: 'video',
140
+ media: '/test.mp4',
141
+ mediaType: 'video',
142
+ name: 'Test',
143
+ type: 'Video',
144
+ muted: true,
145
+ },
146
+ })
147
+
148
+ const video = wrapper.find('video').element as HTMLVideoElement
149
+ const pauseSpy = vi.spyOn(video, 'pause')
150
+
151
+ await wrapper.trigger('mouseleave')
152
+
153
+ expect(pauseSpy).toHaveBeenCalled()
154
+ })
155
+
156
+ it('applies aspect-9/16 class when variant is video', () => {
157
+ const wrapper = mount(SocialMediaTemplate, {
158
+ props: {
159
+ variant: 'video',
160
+ media: '/test.mp4',
161
+ mediaType: 'video',
162
+ name: 'Test',
163
+ type: 'Video',
164
+ },
165
+ })
166
+
167
+ expect(wrapper.classes()).toContain('aspect-9/16')
168
+ })
169
+
170
+ it('applies h-80 class when variant is post', () => {
171
+ const wrapper = mount(SocialMediaTemplate, {
172
+ props: {
173
+ variant: 'post',
174
+ media: '/test.jpg',
175
+ mediaType: 'image',
176
+ name: 'Test',
177
+ type: 'Image',
178
+ },
179
+ })
180
+
181
+ expect(wrapper.classes()).toContain('h-80')
182
+ })
183
+
184
+ it('uses media_type prop for image rendering', () => {
185
+ const wrapper = mount(SocialMediaTemplate, {
186
+ props: {
187
+ variant: 'post',
188
+ media: '/test-without-extension',
189
+ mediaType: 'image',
190
+ name: 'Test',
191
+ type: 'Image',
192
+ },
193
+ })
194
+
195
+ expect(wrapper.find('img').exists()).toBe(true)
196
+ expect(wrapper.find('video').exists()).toBe(false)
197
+ })
198
+
199
+ it('uses media_type prop for video rendering', () => {
200
+ const wrapper = mount(SocialMediaTemplate, {
201
+ props: {
202
+ variant: 'video',
203
+ media: '/test-video-without-extension',
204
+ mediaType: 'video',
205
+ name: 'Test',
206
+ type: 'Video',
207
+ muted: true,
208
+ },
209
+ })
210
+
211
+ expect(wrapper.find('video').exists()).toBe(true)
212
+ expect(wrapper.find('img').exists()).toBe(false)
213
+ })
214
+
215
+ it('correctly map various media extensions to mime types', () => {
216
+ const extensions = {
217
+ mp4: 'video/mp4',
218
+ webm: 'video/webm',
219
+ ogg: 'video/ogg',
220
+ mov: 'video/quicktime',
221
+ avi: 'video/x-msvideo',
222
+ mkv: 'video/x-matroska',
223
+ unknown: 'video/mp4',
224
+ }
225
+
226
+ Object.entries(extensions).forEach(([ext, expectedMime]) => {
227
+ const wrapper = mount(SocialMediaTemplate, {
228
+ props: {
229
+ variant: 'video',
230
+ media: `/test.${ext}`,
231
+ mediaType: 'video',
232
+ mediaExtension: ext === 'unknown' ? undefined : ext,
233
+ name: 'Test',
234
+ type: 'Video',
235
+ },
236
+ })
237
+
238
+ const source = wrapper.find('source')
239
+ expect(source.attributes('type')).toBe(expectedMime)
240
+ })
241
+ })
242
+
243
+ it('handles custom aspect ratio correctly', () => {
244
+ const wrapper = mount(SocialMediaTemplate, {
245
+ props: {
246
+ variant: 'video',
247
+ media: '/test.mp4',
248
+ mediaType: 'video',
249
+ name: 'Test',
250
+ type: 'Video',
251
+ aspectRatio: '16:9',
252
+ },
253
+ })
254
+
255
+ expect(wrapper.classes()).toContain('aspect-16/9')
256
+ })
257
+
258
+ it('applies video-specific colors when variant is video', () => {
259
+ const wrapper = mount(SocialMediaTemplate, {
260
+ props: {
261
+ variant: 'video',
262
+ media: '/test.mp4',
263
+ mediaType: 'video',
264
+ name: 'Test',
265
+ type: 'Video',
266
+ selected: true,
267
+ },
268
+ })
269
+
270
+ // Check overlay background
271
+ const overlay = wrapper.find('.z-10')
272
+ expect(overlay.classes()).toContain('bg-purple-200/70')
273
+
274
+ // Check checkmark background
275
+ const checkmarkCircle = overlay.find('.rounded-full')
276
+ expect(checkmarkCircle.classes()).toContain('bg-purple-500')
277
+
278
+ // Check info block background
279
+ const infoBlock = wrapper.find('.z-20')
280
+ expect(infoBlock.classes()).toContain('bg-purple-500')
281
+ })
282
+
283
+ it('uses correct icons based on variant', () => {
284
+ const variants = [
285
+ { variant: 'post', icon: 'image' },
286
+ { variant: 'video', icon: 'play-circle' },
287
+ { variant: 'slideshow', icon: 'images' },
288
+ ]
289
+
290
+ variants.forEach(({ variant, icon }) => {
291
+ const wrapper = mount(SocialMediaTemplate, {
292
+ props: {
293
+ variant: variant as 'post' | 'video' | 'slideshow',
294
+ media: '/test.jpg',
295
+ mediaType: 'image',
296
+ name: 'Test',
297
+ type: 'Test',
298
+ },
299
+ })
300
+ const nexxtIcon = wrapper.find('.z-20').findComponent({ name: 'NexxtIcon' })
301
+ expect(nexxtIcon.props('name')).toBe(icon)
302
+ })
303
+ })
304
+
305
+ it('shows image-stack icon when variant is slideshow', () => {
306
+ const wrapper = mount(SocialMediaTemplate, {
307
+ props: {
308
+ variant: 'slideshow',
309
+ media: '/test.jpg',
310
+ mediaType: 'image',
311
+ name: 'Test',
312
+ type: 'Slideshow',
313
+ },
314
+ })
315
+
316
+ const icons = wrapper.findAllComponents({ name: 'NexxtIcon' })
317
+ const stackIcon = icons.find((icon) => icon.props('name') === 'images')
318
+ expect(stackIcon).toBeDefined()
319
+ })
320
+
321
+ it('correctly uses parsedAspectRatio for slideshow variant', () => {
322
+ const wrapper = mount(SocialMediaTemplate, {
323
+ props: {
324
+ variant: 'slideshow',
325
+ media: '/test.jpg',
326
+ mediaType: 'image',
327
+ name: 'Test',
328
+ type: 'Slideshow',
329
+ aspectRatio: '1:1',
330
+ },
331
+ })
332
+
333
+ expect(wrapper.classes()).toContain('aspect-1/1')
334
+ })
335
+
336
+ it('correctly returns empty string aspect ratio when mediaType is image and no aspect ratio is provided', () => {
337
+ const wrapper = mount(SocialMediaTemplate, {
338
+ props: {
339
+ variant: 'video', // TriggerparsedAspectRatio evaluation
340
+ media: '/test.jpg',
341
+ mediaType: 'image',
342
+ name: 'Test',
343
+ type: 'Test',
344
+ },
345
+ })
346
+
347
+ // Classes should not include any aspect ratio class
348
+ const classes = wrapper.classes()
349
+ expect(classes.some((c) => c.startsWith('aspect-'))).toBe(false)
350
+ })
351
+
352
+ it('computes undefined mime type when mediaType is image', () => {
353
+ const wrapper = mount(SocialMediaTemplate, {
354
+ props: {
355
+ variant: 'post',
356
+ media: 'test.jpg',
357
+ mediaType: 'image',
358
+ name: 'Test',
359
+ type: 'Test',
360
+ },
361
+ })
362
+
363
+ // @ts-expect-error - testing computed property internal
364
+ expect(wrapper.vm.videoMimeType).toBeUndefined()
365
+ })
366
+
367
+ it('handles custom aspect ratio with aspect- prefix correctly', () => {
368
+ const wrapper = mount(SocialMediaTemplate, {
369
+ props: {
370
+ variant: 'video',
371
+ media: '/test.mp4',
372
+ mediaType: 'video',
373
+ name: 'Test',
374
+ type: 'Video',
375
+ aspectRatio: 'aspect-4:3',
376
+ },
377
+ })
378
+
379
+ expect(wrapper.classes()).toContain('aspect-4/3')
380
+ })
381
+
382
+ it('emits click event on click', async () => {
383
+ const wrapper = mount(SocialMediaTemplate, {
384
+ props: {
385
+ variant: 'post',
386
+ media: '/test.jpg',
387
+ mediaType: 'image',
388
+ name: 'Test',
389
+ type: 'Test',
390
+ },
391
+ })
392
+
393
+ await wrapper.trigger('click')
394
+ expect(wrapper.emitted('click')).toBeTruthy()
395
+ })
396
+
397
+ it('emits click event on enter key down', async () => {
398
+ const wrapper = mount(SocialMediaTemplate, {
399
+ props: {
400
+ variant: 'post',
401
+ media: '/test.jpg',
402
+ mediaType: 'image',
403
+ name: 'Test',
404
+ type: 'Test',
405
+ },
406
+ })
407
+
408
+ await wrapper.trigger('keydown.enter')
409
+ expect(wrapper.emitted('click')).toBeTruthy()
410
+ })
411
+
412
+ it('emits click event on space key down', async () => {
413
+ const wrapper = mount(SocialMediaTemplate, {
414
+ props: {
415
+ variant: 'post',
416
+ media: '/test.jpg',
417
+ mediaType: 'image',
418
+ name: 'Test',
419
+ type: 'Test',
420
+ },
421
+ })
422
+
423
+ await wrapper.trigger('keydown.space')
424
+ expect(wrapper.emitted('click')).toBeTruthy()
425
+ })
426
+
427
+ it('plays video on focus when media is video', async () => {
428
+ const wrapper = mount(SocialMediaTemplate, {
429
+ props: {
430
+ variant: 'video',
431
+ media: '/test.mp4',
432
+ mediaType: 'video',
433
+ name: 'Test',
434
+ type: 'Video',
435
+ muted: true,
436
+ },
437
+ })
438
+
439
+ const video = wrapper.find('video').element as HTMLVideoElement
440
+ const playSpy = vi.spyOn(video, 'play').mockImplementation(() => Promise.resolve())
441
+
442
+ await wrapper.trigger('focus')
443
+
444
+ expect(playSpy).toHaveBeenCalled()
445
+ })
446
+
447
+ it('pauses video on blur when media is video', async () => {
448
+ const wrapper = mount(SocialMediaTemplate, {
449
+ props: {
450
+ variant: 'video',
451
+ media: '/test.mp4',
452
+ mediaType: 'video',
453
+ name: 'Test',
454
+ type: 'Video',
455
+ muted: true,
456
+ },
457
+ })
458
+
459
+ const video = wrapper.find('video').element as HTMLVideoElement
460
+ const pauseSpy = vi.spyOn(video, 'pause')
461
+
462
+ await wrapper.trigger('blur')
463
+
464
+ expect(pauseSpy).toHaveBeenCalled()
465
+ })
466
+ })
@@ -0,0 +1,130 @@
1
+ <script lang="ts" setup>
2
+ import { computed, ref } from 'vue'
3
+ import Icon from '../Icon/Icon.vue'
4
+
5
+ interface NexxtSocialMediaTemplateProps {
6
+ variant: 'post' | 'video' | 'slideshow'
7
+ media: string
8
+ mediaType: 'image' | 'video'
9
+ name: string
10
+ type: string
11
+ mediaExtension?: string
12
+ selected?: boolean
13
+ muted?: boolean
14
+ aspectRatio?: string
15
+ }
16
+
17
+ defineOptions({
18
+ name: 'NexxtSocialMediaTemplate',
19
+ })
20
+
21
+ const emit = defineEmits(['click'])
22
+
23
+ const { mediaType, media, mediaExtension, aspectRatio } =
24
+ defineProps<NexxtSocialMediaTemplateProps>()
25
+
26
+ const videoRef = ref<HTMLVideoElement | null>(null)
27
+
28
+ const videoMimeType = computed(() => {
29
+ if (mediaType !== 'video') return undefined
30
+
31
+ const mimeTypes: Record<string, string> = {
32
+ mp4: 'video/mp4',
33
+ webm: 'video/webm',
34
+ ogg: 'video/ogg',
35
+ mov: 'video/quicktime',
36
+ avi: 'video/x-msvideo',
37
+ mkv: 'video/x-matroska',
38
+ }
39
+
40
+ return mimeTypes[mediaExtension || ''] || 'video/mp4'
41
+ })
42
+
43
+ const parsedAspectRatio = computed(() => {
44
+ if (aspectRatio) {
45
+ return aspectRatio.startsWith('aspect-')
46
+ ? aspectRatio.replace(':', '/')
47
+ : `aspect-${aspectRatio.replace(':', '/')}`
48
+ }
49
+
50
+ if (mediaType === 'video') {
51
+ return 'aspect-9/16'
52
+ }
53
+
54
+ return ''
55
+ })
56
+
57
+ const handleMouseEnter = () => {
58
+ if (videoRef.value) {
59
+ videoRef.value.play()
60
+ }
61
+ }
62
+
63
+ const handleMouseLeave = () => {
64
+ if (videoRef.value) {
65
+ videoRef.value.pause()
66
+ }
67
+ }
68
+ </script>
69
+
70
+ <template>
71
+ <div
72
+ class="group grid w-64 cursor-pointer grid-cols-1 grid-rows-[1fr_auto] overflow-hidden rounded-3xl outline-1 -outline-offset-1 transition-all focus-visible:outline-2 focus-visible:outline-cornflower-blue-600"
73
+ :class="[
74
+ variant !== 'post' ? parsedAspectRatio : 'h-80',
75
+ selected ? 'outline-cornflower-blue-500' : 'outline-gray-200',
76
+ ]"
77
+ role="button"
78
+ tabindex="0"
79
+ :aria-pressed="selected"
80
+ @mouseenter="handleMouseEnter"
81
+ @mouseleave="handleMouseLeave"
82
+ @focus="handleMouseEnter"
83
+ @blur="handleMouseLeave"
84
+ @click="emit('click')"
85
+ @keydown.enter.prevent="emit('click')"
86
+ @keydown.space.prevent="emit('click')"
87
+ >
88
+ <picture v-if="mediaType === 'image'" class="col-start-1 row-span-2 row-start-1">
89
+ <source :srcset="media" />
90
+ <img :src="media" alt="Media content" class="h-full w-full object-cover object-center" />
91
+ </picture>
92
+ <video
93
+ v-else
94
+ ref="videoRef"
95
+ :muted="muted"
96
+ loop="true"
97
+ class="col-start-1 row-span-2 row-start-1 h-full w-full object-cover"
98
+ >
99
+ <source :src="media" :type="videoMimeType" />
100
+ Your browser does not support the video tag.
101
+ </video>
102
+ <div
103
+ class="z-10 col-start-1 row-span-2 row-start-1 flex items-center justify-center transition-opacity duration-300"
104
+ :class="[
105
+ selected ? 'opacity-100' : 'opacity-0',
106
+ variant === 'video' ? 'bg-purple-200/70' : 'bg-cornflower-blue-200/70',
107
+ ]"
108
+ >
109
+ <div
110
+ class="flex aspect-square items-center justify-center rounded-full px-2"
111
+ :class="variant === 'video' ? 'bg-purple-500' : 'bg-cornflower-blue-500'"
112
+ >
113
+ <Icon name="check" class="ml-auto block shrink-0 text-3xl text-white" />
114
+ </div>
115
+ </div>
116
+ <div
117
+ class="goup-hover:opacity-0 z-20 col-start-1 row-start-2 flex items-center px-5 pt-2.5 pb-3.5 text-white transition-all duration-300 ease-out group-hover:translate-y-full"
118
+ :class="variant === 'video' ? 'bg-purple-500' : 'bg-social-media-template-info-bg'"
119
+ >
120
+ <div>
121
+ <div class="heading-4">{{ name }}</div>
122
+ <div class="extra-small">{{ type }}</div>
123
+ </div>
124
+ <Icon
125
+ :name="variant === 'post' ? 'image' : variant === 'video' ? 'play-circle' : 'images'"
126
+ class="mb-1 ml-auto block shrink-0 self-end text-lg"
127
+ />
128
+ </div>
129
+ </div>
130
+ </template>
@@ -0,0 +1,43 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite'
2
+ import SocialMediaType from './SocialMediaType.vue'
3
+
4
+ export default {
5
+ title: 'Components/Organisms/Social Media Type',
6
+ component: SocialMediaType,
7
+ parameters: {
8
+ design: {
9
+ type: 'figma',
10
+ url: 'https://www.figma.com/design/CdbFJ7qUga6mtjagcPDvYK/Design-System?node-id=533-28&t=CbHvOQfEMIr7M5mO-11',
11
+ },
12
+ },
13
+ } satisfies Meta<typeof SocialMediaType>
14
+
15
+ type Story = StoryObj<typeof SocialMediaType>
16
+
17
+ export const Post: Story = {
18
+ args: {
19
+ variant: 'post',
20
+ icons: ['facebook', 'instagram', 'linkedin', 'x', 'google'],
21
+ },
22
+ }
23
+
24
+ export const Reel: Story = {
25
+ args: {
26
+ variant: 'reel',
27
+ chip: 'Nieuw!',
28
+ },
29
+ }
30
+
31
+ export const Story: Story = {
32
+ args: {
33
+ variant: 'story',
34
+ icons: ['instagram'],
35
+ },
36
+ }
37
+
38
+ export const ReelSelected: Story = {
39
+ args: {
40
+ variant: 'reel',
41
+ selected: true,
42
+ },
43
+ }