negodesign 0.0.28 → 0.0.30
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/dist/assets/lonely-404.mp4 +0 -0
- package/dist/components/core/banner/AdCardBanner.svelte +74 -0
- package/dist/components/core/banner/AdCardBanner.svelte.d.ts +4 -0
- package/dist/components/core/banner/CtaCardBanner.svelte +118 -0
- package/dist/components/core/banner/CtaCardBanner.svelte.d.ts +4 -0
- package/dist/components/core/banner/NotificationBanner.svelte +95 -0
- package/dist/components/core/banner/NotificationBanner.svelte.d.ts +4 -0
- package/dist/components/core/banner/types.d.ts +63 -0
- package/dist/components/core/banner/types.js +1 -0
- package/dist/components/core/card/highlight/01/CardHighlight01.svelte +20 -27
- package/dist/components/core/card/highlight/02/CardHighlight02.svelte +18 -27
- package/dist/components/core/card/highlight/data.js +1 -4
- package/dist/components/core/card/media/01/CardMedia01.svelte +114 -98
- package/dist/components/core/card/media/02/CardMedia02.svelte +115 -99
- package/dist/components/core/card/media/CardMedia.svelte +10 -9
- package/dist/components/core/card/media/CardMedia.svelte.d.ts +1 -0
- package/dist/components/core/card/profile/01/CardProfile01.svelte +104 -86
- package/dist/components/core/card/profile/02/CardProfile02.svelte +103 -87
- package/dist/components/core/card/profile/CardProfile.svelte +8 -7
- package/dist/components/core/card/profile/CardProfile.svelte.d.ts +1 -0
- package/dist/components/core/card/promotion/CardPromotion.svelte +10 -4
- package/dist/components/core/card/shared/CardButton.svelte +38 -23
- package/dist/components/core/card/shared/CardButton.svelte.d.ts +2 -1
- package/dist/components/core/card/shared/CardDescription.svelte +30 -30
- package/dist/components/core/card/shared/CardLogo.svelte +19 -0
- package/dist/components/core/card/shared/CardLogo.svelte.d.ts +7 -0
- package/dist/components/core/card/shared/CardStarRating.svelte +18 -14
- package/dist/components/core/card/shared/CardStarRating.svelte.d.ts +1 -0
- package/dist/components/core/card/shared/CardStartPrice.svelte +1 -1
- package/dist/components/core/card/shared/CardThumbnailVideo.svelte +210 -148
- package/dist/components/core/card/shared/CardThumbnailVideo.svelte.d.ts +1 -0
- package/dist/components/core/card/types.d.ts +5 -0
- package/dist/components/core/carousel/grid/media/types.d.ts +11 -0
- package/dist/components/core/carousel/grid/media/types.js +1 -0
- package/dist/components/core/carousel/grid/media/ui/CarouselGridMedia.svelte +49 -0
- package/dist/components/core/carousel/grid/media/ui/CarouselGridMedia.svelte.d.ts +4 -0
- package/dist/components/core/carousel/grid/profile/types.d.ts +11 -0
- package/dist/components/core/carousel/grid/profile/types.js +1 -0
- package/dist/components/core/carousel/grid/profile/ui/CarouselGridProfile.svelte +49 -0
- package/dist/components/core/carousel/grid/profile/ui/CarouselGridProfile.svelte.d.ts +4 -0
- package/dist/components/core/carousel/grid/shared/ui/CarouselGridSlot.svelte +33 -0
- package/dist/components/core/carousel/grid/shared/ui/CarouselGridSlot.svelte.d.ts +11 -0
- package/dist/components/core/carousel/hero/CarouselHero.svelte +21 -19
- package/dist/components/core/carousel/hero/CarouselHero.svelte.d.ts +1 -0
- package/dist/components/core/carousel/highlights/types.d.ts +4 -4
- package/dist/components/core/carousel/highlights/ui/CarouselHighlights.svelte +4 -22
- package/dist/components/core/carousel/promotion/types.d.ts +5 -5
- package/dist/components/core/carousel/promotion/ui/CarouselPromotion.svelte +4 -21
- package/dist/components/core/carousel/shared/ui/CarouselHeader.svelte +6 -1
- package/dist/components/core/carousel/types.d.ts +1 -0
- package/dist/components/core/footer/types.d.ts +23 -0
- package/dist/components/core/footer/types.js +1 -0
- package/dist/components/core/footer/ui/01/Footer01.svelte +76 -0
- package/dist/components/core/footer/ui/01/Footer01.svelte.d.ts +4 -0
- package/dist/components/core/footer/ui/02/Footer02.svelte +53 -0
- package/dist/components/core/footer/ui/02/Footer02.svelte.d.ts +4 -0
- package/dist/components/core/footer/ui/Footer.svelte +18 -0
- package/dist/components/core/footer/ui/Footer.svelte.d.ts +7 -0
- package/dist/components/core/footer/ui/shared/FooterColumn.svelte +18 -0
- package/dist/components/core/footer/ui/shared/FooterColumn.svelte.d.ts +4 -0
- package/dist/components/core/footer/ui/shared/FooterNewsLetter.svelte +57 -0
- package/dist/components/core/footer/ui/shared/FooterNewsLetter.svelte.d.ts +9 -0
- package/dist/components/core/footer/ui/shared/FooterSocialIcon.svelte +62 -0
- package/dist/components/core/footer/ui/shared/FooterSocialIcon.svelte.d.ts +4 -0
- package/dist/components/core/panel/CarouselSlot.svelte +4 -15
- package/dist/components/core/panel/CarouselSlot.svelte.d.ts +2 -12
- package/dist/components/core/panel/LeftHero.svelte +2 -2
- package/dist/components/core/panel/type.d.ts +11 -0
- package/dist/components/core/panel/type.js +1 -0
- package/dist/globals.css +463 -47
- package/dist/i18n/langs/en.d.ts +4 -0
- package/dist/i18n/langs/en.js +4 -0
- package/dist/i18n/langs/pt.d.ts +4 -0
- package/dist/i18n/langs/pt.js +10 -6
- package/dist/i18n/translations.d.ts +8 -0
- package/dist/index.d.ts +17 -5
- package/dist/index.js +17 -5
- package/dist/styles/globals.css +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
2
|
+
import Skeleton from "../../../ui/skeleton/skeleton.svelte";
|
|
3
|
+
import * as StarRating from "../../../ui/star-rating";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
type Props = {
|
|
6
|
+
startNumber: number;
|
|
7
|
+
startMax: number;
|
|
8
|
+
isLoading?: boolean;
|
|
9
|
+
};
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
let { startNumber, startMax, isLoading }: Props = $props();
|
|
10
12
|
</script>
|
|
11
13
|
|
|
12
|
-
{#if
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
{
|
|
19
|
-
|
|
14
|
+
{#if isLoading}
|
|
15
|
+
<Skeleton class="w-12 h-6 rounded-lg bg-gray-300/90" />
|
|
16
|
+
{:else if startNumber}
|
|
17
|
+
<StarRating.Root max={startMax} value={startNumber} class="size-15 h-auto">
|
|
18
|
+
{#snippet children({ items })}
|
|
19
|
+
{#each items as item (item.index)}
|
|
20
|
+
<StarRating.Star {...item} class="py-0! my-0!" />
|
|
21
|
+
{/each}
|
|
22
|
+
{/snippet}
|
|
23
|
+
</StarRating.Root>
|
|
20
24
|
{/if}
|
|
@@ -1,170 +1,232 @@
|
|
|
1
1
|
<!-- CardMedia.svelte -->
|
|
2
2
|
<script lang="ts">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Image thumbnail with hover-to-play video, lazy loading,
|
|
5
|
+
* duration badge, video indicator, and optional maximize overlay.
|
|
6
|
+
* @component
|
|
7
|
+
*/
|
|
8
|
+
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
9
|
+
import {
|
|
10
|
+
Maximize01Icon,
|
|
11
|
+
Cancel01Icon,
|
|
12
|
+
VideoReplayIcon,
|
|
13
|
+
} from "@hugeicons/core-free-icons";
|
|
14
|
+
import Skeleton from "../../../ui/skeleton/skeleton.svelte";
|
|
15
|
+
import ImgPlaceholder from "../../../../assets/placeholder-image.png";
|
|
16
|
+
import VideoPlaceholder from "../../../../assets/lonely-404.mp4";
|
|
17
|
+
|
|
18
|
+
type Props = {
|
|
19
|
+
imageUrl?: string;
|
|
20
|
+
videoUrl?: string;
|
|
21
|
+
class?: string;
|
|
22
|
+
isImageButtonMaximized?: boolean;
|
|
23
|
+
isVideoButtonMaximized?: boolean;
|
|
24
|
+
isLoading?: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
imageUrl,
|
|
29
|
+
videoUrl,
|
|
30
|
+
class: className = "w-64 h-64",
|
|
31
|
+
isImageButtonMaximized = false,
|
|
32
|
+
isVideoButtonMaximized = false,
|
|
33
|
+
isLoading = false,
|
|
34
|
+
}: Props = $props();
|
|
35
|
+
|
|
36
|
+
let containerEl: HTMLDivElement | undefined = $state();
|
|
37
|
+
let videoEl: HTMLVideoElement | undefined = $state();
|
|
38
|
+
|
|
39
|
+
let isHovering = $state(false);
|
|
40
|
+
let isVisible = $state(false);
|
|
41
|
+
let isMaximized = $state(false);
|
|
42
|
+
let duration = $state("");
|
|
43
|
+
|
|
44
|
+
let showVideo = $derived(!imageUrl || isHovering);
|
|
45
|
+
let showMaximize = $derived(
|
|
46
|
+
(imageUrl && isImageButtonMaximized) ||
|
|
47
|
+
(videoUrl && isVideoButtonMaximized),
|
|
48
|
+
);
|
|
49
|
+
let showVideoBadge = $derived(!!imageUrl && !!videoUrl && !isHovering);
|
|
50
|
+
|
|
51
|
+
function onLoadedMetadata() {
|
|
52
|
+
if (!videoEl) return;
|
|
53
|
+
const m = Math.floor(videoEl.duration / 60);
|
|
54
|
+
const s = Math.floor(videoEl.duration % 60);
|
|
55
|
+
duration = `${m}:${s.toString().padStart(2, "0")}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function toggleHover(state: boolean) {
|
|
59
|
+
if (!videoUrl) return;
|
|
60
|
+
isHovering = state;
|
|
61
|
+
if (state) videoEl?.play();
|
|
62
|
+
else {
|
|
63
|
+
videoEl?.pause();
|
|
64
|
+
if (imageUrl && videoEl) videoEl.currentTime = 0;
|
|
44
65
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
$effect(() => {
|
|
69
|
+
if (!containerEl) return;
|
|
70
|
+
const observer = new IntersectionObserver(
|
|
71
|
+
([entry]) => {
|
|
72
|
+
if (entry.isIntersecting) {
|
|
73
|
+
isVisible = true;
|
|
74
|
+
observer.disconnect();
|
|
53
75
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (entry.isIntersecting) {
|
|
61
|
-
isVisible = true;
|
|
62
|
-
observer.disconnect();
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
{ rootMargin: "100px" }
|
|
66
|
-
);
|
|
67
|
-
observer.observe(containerEl);
|
|
68
|
-
return () => observer.disconnect();
|
|
69
|
-
});
|
|
76
|
+
},
|
|
77
|
+
{ rootMargin: "100px" },
|
|
78
|
+
);
|
|
79
|
+
observer.observe(containerEl);
|
|
80
|
+
return () => observer.disconnect();
|
|
81
|
+
});
|
|
70
82
|
</script>
|
|
71
83
|
|
|
72
|
-
<svelte:window
|
|
84
|
+
<svelte:window
|
|
85
|
+
onkeydown={isMaximized
|
|
86
|
+
? (e) => e.key === "Escape" && (isMaximized = false)
|
|
87
|
+
: undefined}
|
|
88
|
+
/>
|
|
73
89
|
|
|
74
90
|
{#snippet maximizeButton()}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
class="absolute top-2 right-2 z-10 rounded-full bg-black/50 p-1.5 text-white transition-colors hover:bg-black/70"
|
|
94
|
+
onclick={(e) => {
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
isMaximized = true;
|
|
97
|
+
videoEl?.pause();
|
|
98
|
+
}}
|
|
99
|
+
aria-label="Maximizar"
|
|
100
|
+
>
|
|
101
|
+
<HugeiconsIcon
|
|
102
|
+
icon={Maximize01Icon}
|
|
103
|
+
size={16}
|
|
104
|
+
color="currentColor"
|
|
105
|
+
strokeWidth={1.5}
|
|
106
|
+
/>
|
|
107
|
+
</button>
|
|
83
108
|
{/snippet}
|
|
84
109
|
|
|
85
|
-
{#if
|
|
110
|
+
{#if isLoading}
|
|
111
|
+
<Skeleton class="w-full h-12.5 md:h-50 bg-gray-500/90" />
|
|
112
|
+
{:else}
|
|
113
|
+
{#if imageUrl || videoUrl}
|
|
86
114
|
<div
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
115
|
+
bind:this={containerEl}
|
|
116
|
+
class="relative w-full {className}"
|
|
117
|
+
role="button"
|
|
118
|
+
tabindex="0"
|
|
119
|
+
onmouseenter={() => toggleHover(true)}
|
|
120
|
+
onmouseleave={() => toggleHover(false)}
|
|
121
|
+
onfocus={() => toggleHover(true)}
|
|
122
|
+
onblur={() => toggleHover(false)}
|
|
123
|
+
onkeydown={(e) =>
|
|
124
|
+
(e.key === "Enter" || e.key === " ") &&
|
|
125
|
+
(e.preventDefault(), toggleHover(!isHovering))}
|
|
96
126
|
>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
127
|
+
{#if imageUrl}
|
|
128
|
+
<img
|
|
129
|
+
src={isVisible ? imageUrl : undefined}
|
|
130
|
+
loading="lazy"
|
|
131
|
+
decoding="async"
|
|
132
|
+
alt={imageUrl}
|
|
133
|
+
class="absolute inset-0 w-full {className} rounded-md object-cover transition-opacity duration-500"
|
|
134
|
+
class:opacity-0={videoUrl && showVideo}
|
|
135
|
+
onerror={(e) => ((e.target as HTMLImageElement).src = ImgPlaceholder)}
|
|
136
|
+
/>
|
|
137
|
+
{/if}
|
|
138
|
+
|
|
139
|
+
{#if videoUrl && isVisible}
|
|
140
|
+
<video
|
|
141
|
+
bind:this={videoEl}
|
|
142
|
+
src={videoUrl}
|
|
143
|
+
preload="metadata"
|
|
144
|
+
onloadedmetadata={onLoadedMetadata}
|
|
145
|
+
class="absolute inset-0 w-full {className} rounded-md object-cover transition-opacity duration-500"
|
|
146
|
+
class:opacity-0={imageUrl && !showVideo}
|
|
147
|
+
muted
|
|
148
|
+
loop
|
|
149
|
+
playsinline
|
|
150
|
+
onerror={(e) =>
|
|
151
|
+
((e.target as HTMLImageElement).src = VideoPlaceholder)}
|
|
152
|
+
></video>
|
|
153
|
+
{/if}
|
|
154
|
+
|
|
155
|
+
{#if showVideoBadge}
|
|
156
|
+
<div
|
|
157
|
+
class="pointer-events-none absolute inset-0 flex items-center justify-center transition-opacity duration-300"
|
|
158
|
+
>
|
|
159
|
+
<div
|
|
160
|
+
class="flex h-11 w-11 items-center justify-center rounded-full bg-black/50 backdrop-blur-sm"
|
|
161
|
+
>
|
|
162
|
+
<HugeiconsIcon
|
|
163
|
+
icon={VideoReplayIcon}
|
|
164
|
+
size={22}
|
|
165
|
+
color="white"
|
|
166
|
+
strokeWidth={1.5}
|
|
105
167
|
/>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
{#if duration}
|
|
171
|
+
<span
|
|
172
|
+
class="absolute bottom-2 right-2 z-10 rounded bg-black/60 px-1.5 py-0.5 text-xs font-medium text-white"
|
|
173
|
+
>
|
|
174
|
+
{duration}
|
|
175
|
+
</span>
|
|
106
176
|
{/if}
|
|
177
|
+
{/if}
|
|
107
178
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
src={videoUrl}
|
|
112
|
-
preload="metadata"
|
|
113
|
-
onloadedmetadata={onLoadedMetadata}
|
|
114
|
-
class="absolute inset-0 w-full {className} rounded-md object-cover transition-opacity duration-500"
|
|
115
|
-
class:opacity-0={imageUrl && !showVideo}
|
|
116
|
-
muted
|
|
117
|
-
loop
|
|
118
|
-
playsinline
|
|
119
|
-
></video>
|
|
120
|
-
{/if}
|
|
121
|
-
|
|
122
|
-
{#if showVideoBadge}
|
|
123
|
-
<div class="pointer-events-none absolute inset-0 flex items-center justify-center transition-opacity duration-300">
|
|
124
|
-
<div class="flex h-11 w-11 items-center justify-center rounded-full bg-black/50 backdrop-blur-sm">
|
|
125
|
-
<HugeiconsIcon icon={VideoReplayIcon} size={22} color="white" strokeWidth={1.5} />
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
{#if duration}
|
|
129
|
-
<span class="absolute bottom-2 right-2 z-10 rounded bg-black/60 px-1.5 py-0.5 text-xs font-medium text-white">
|
|
130
|
-
{duration}
|
|
131
|
-
</span>
|
|
132
|
-
{/if}
|
|
133
|
-
{/if}
|
|
134
|
-
|
|
135
|
-
{#if showMaximize}
|
|
136
|
-
{@render maximizeButton()}
|
|
137
|
-
{/if}
|
|
179
|
+
{#if showMaximize}
|
|
180
|
+
{@render maximizeButton()}
|
|
181
|
+
{/if}
|
|
138
182
|
</div>
|
|
139
|
-
{/if}
|
|
183
|
+
{/if}
|
|
140
184
|
|
|
141
|
-
{#if isMaximized}
|
|
185
|
+
{#if isMaximized}
|
|
142
186
|
<div class="fixed inset-0 z-50">
|
|
143
|
-
|
|
187
|
+
<button
|
|
188
|
+
type="button"
|
|
189
|
+
class="absolute inset-0 h-full w-full cursor-default bg-black/80"
|
|
190
|
+
onclick={() => (isMaximized = false)}
|
|
191
|
+
aria-label="Fechar modal"
|
|
192
|
+
></button>
|
|
193
|
+
|
|
194
|
+
<div
|
|
195
|
+
class="pointer-events-none fixed inset-0 z-50 flex items-center justify-center p-4"
|
|
196
|
+
>
|
|
197
|
+
<div class="pointer-events-auto relative max-h-[90vh] max-w-4xl">
|
|
198
|
+
<button
|
|
144
199
|
type="button"
|
|
145
|
-
class="absolute
|
|
200
|
+
class="absolute top-3 right-3 rounded-full bg-red-900/50 p-2 text-white hover:bg-black/70"
|
|
146
201
|
onclick={() => (isMaximized = false)}
|
|
147
|
-
aria-label="Fechar
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
202
|
+
aria-label="Fechar"
|
|
203
|
+
>
|
|
204
|
+
<HugeiconsIcon
|
|
205
|
+
icon={Cancel01Icon}
|
|
206
|
+
size={20}
|
|
207
|
+
color="currentColor"
|
|
208
|
+
strokeWidth={1.5}
|
|
209
|
+
/>
|
|
210
|
+
</button>
|
|
211
|
+
|
|
212
|
+
{#if videoUrl && showVideo}
|
|
213
|
+
<!-- svelte-ignore a11y_media_has_caption -->
|
|
214
|
+
<video
|
|
215
|
+
src={videoUrl}
|
|
216
|
+
class="max-h-[90vh] max-w-full rounded-md"
|
|
217
|
+
controls
|
|
218
|
+
autoplay
|
|
219
|
+
playsinline
|
|
220
|
+
></video>
|
|
221
|
+
{:else if imageUrl}
|
|
222
|
+
<img
|
|
223
|
+
src={imageUrl}
|
|
224
|
+
alt={imageUrl}
|
|
225
|
+
class="max-h-[90vh] max-w-full rounded-md object-contain"
|
|
226
|
+
/>
|
|
227
|
+
{/if}
|
|
168
228
|
</div>
|
|
229
|
+
</div>
|
|
169
230
|
</div>
|
|
170
|
-
{/if}
|
|
231
|
+
{/if}
|
|
232
|
+
{/if}
|
|
@@ -4,6 +4,7 @@ type Props = {
|
|
|
4
4
|
class?: string;
|
|
5
5
|
isImageButtonMaximized?: boolean;
|
|
6
6
|
isVideoButtonMaximized?: boolean;
|
|
7
|
+
isLoading?: boolean;
|
|
7
8
|
};
|
|
8
9
|
declare const CardThumbnailVideo: import("svelte").Component<Props, {}, "">;
|
|
9
10
|
type CardThumbnailVideo = ReturnType<typeof CardThumbnailVideo>;
|
|
@@ -14,6 +14,7 @@ export interface CardMediaProps {
|
|
|
14
14
|
className?: string;
|
|
15
15
|
tags?: CardTagsProps[];
|
|
16
16
|
isFavorite?: boolean;
|
|
17
|
+
isLoading?: boolean;
|
|
17
18
|
startNumber?: number;
|
|
18
19
|
isTagBorderBottom?: boolean;
|
|
19
20
|
buttonProfileClass?: string;
|
|
@@ -35,6 +36,7 @@ export interface CardProfileProps {
|
|
|
35
36
|
tags?: CardTagsProps[];
|
|
36
37
|
isFavorite?: boolean;
|
|
37
38
|
startNumber?: number;
|
|
39
|
+
isLoading?: boolean;
|
|
38
40
|
isTagBorderBottom?: boolean;
|
|
39
41
|
buttonProfileClass?: string;
|
|
40
42
|
buttonDetailsClass?: string;
|
|
@@ -56,6 +58,7 @@ export interface CardPromotionProps {
|
|
|
56
58
|
oldPrice?: string | number;
|
|
57
59
|
newPrice?: string | number;
|
|
58
60
|
buttonBuyText?: string;
|
|
61
|
+
buttonBuyClass?: string;
|
|
59
62
|
isDescriptionIcon?: boolean;
|
|
60
63
|
isDescriptionLabel?: boolean;
|
|
61
64
|
onClickBuy?: (id: string | number) => void;
|
|
@@ -70,8 +73,10 @@ export interface CardHighlightProps {
|
|
|
70
73
|
className?: string;
|
|
71
74
|
isFavorite?: boolean;
|
|
72
75
|
isLoading?: boolean;
|
|
76
|
+
isExpandButton?: boolean;
|
|
73
77
|
content?: string;
|
|
74
78
|
buttonText?: string;
|
|
79
|
+
buttonClass?: string;
|
|
75
80
|
isDescriptionIcon?: boolean;
|
|
76
81
|
isDescriptionLabel?: boolean;
|
|
77
82
|
tags?: CardTagsProps[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CardMediaProps } from "../../../card/types";
|
|
2
|
+
import type { CarouselSlotProps } from "../../../panel/type";
|
|
3
|
+
import type { CarouselHeaderProps } from "../../types";
|
|
4
|
+
export interface CarouselMediaProps {
|
|
5
|
+
headerProps?: CarouselHeaderProps;
|
|
6
|
+
slotProps?: CarouselSlotProps;
|
|
7
|
+
gridClass?: string;
|
|
8
|
+
variant?: 1 | 2;
|
|
9
|
+
items: CardMediaProps[];
|
|
10
|
+
isLoading?: boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CarouselGridSlot from "../../shared/ui/CarouselGridSlot.svelte";
|
|
3
|
+
import * as Carousel from "../../../../../ui/carousel/index.js";
|
|
4
|
+
import type { CarouselMediaProps } from "../types";
|
|
5
|
+
import CarouselHeader from "../../../shared/ui/CarouselHeader.svelte";
|
|
6
|
+
import { useDevice } from "../../../../../../hooks/responsive.svelte";
|
|
7
|
+
import CardMedia from "../../../../card/media/CardMedia.svelte";
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
headerProps,
|
|
11
|
+
slotProps,
|
|
12
|
+
gridClass,
|
|
13
|
+
items,
|
|
14
|
+
variant,
|
|
15
|
+
isLoading = false,
|
|
16
|
+
}: CarouselMediaProps = $props();
|
|
17
|
+
|
|
18
|
+
const responsive = useDevice();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<CarouselHeader {...headerProps}>
|
|
22
|
+
<CarouselGridSlot {slotProps} {gridClass} totalItems={items.length}>
|
|
23
|
+
{#if isLoading}
|
|
24
|
+
{#each Array.from( { length: responsive.isMobile ? 5 : 9 }, ) as _, i (`loading-${i}`)}
|
|
25
|
+
{#if responsive.isMobile}
|
|
26
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
27
|
+
<CardMedia id={i} {variant} isLoading />
|
|
28
|
+
</Carousel.Item>
|
|
29
|
+
{:else}
|
|
30
|
+
<div>
|
|
31
|
+
<CardMedia id={i} {variant} isLoading />
|
|
32
|
+
</div>
|
|
33
|
+
{/if}
|
|
34
|
+
{/each}
|
|
35
|
+
{:else}
|
|
36
|
+
{#each items as item, i (`media-${item.id ?? i}`)}
|
|
37
|
+
{#if responsive.isMobile}
|
|
38
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
39
|
+
<CardMedia {...item} {variant} />
|
|
40
|
+
</Carousel.Item>
|
|
41
|
+
{:else}
|
|
42
|
+
<div>
|
|
43
|
+
<CardMedia {...item} {variant} />
|
|
44
|
+
</div>
|
|
45
|
+
{/if}
|
|
46
|
+
{/each}
|
|
47
|
+
{/if}
|
|
48
|
+
</CarouselGridSlot>
|
|
49
|
+
</CarouselHeader>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CardProfileProps } from "../../../card/types";
|
|
2
|
+
import type { CarouselSlotProps } from "../../../panel/type";
|
|
3
|
+
import type { CarouselHeaderProps } from "../../types";
|
|
4
|
+
export interface CarouselProfileProps {
|
|
5
|
+
headerProps?: CarouselHeaderProps;
|
|
6
|
+
slotProps?: CarouselSlotProps;
|
|
7
|
+
gridClass?: string;
|
|
8
|
+
variant?: 1 | 2;
|
|
9
|
+
items: CardProfileProps[];
|
|
10
|
+
isLoading?: boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CarouselGridSlot from "../../shared/ui/CarouselGridSlot.svelte";
|
|
3
|
+
import * as Carousel from "../../../../../ui/carousel/index.js";
|
|
4
|
+
import CarouselHeader from "../../../shared/ui/CarouselHeader.svelte";
|
|
5
|
+
import { useDevice } from "../../../../../../hooks/responsive.svelte";
|
|
6
|
+
import type { CarouselProfileProps } from "../types";
|
|
7
|
+
import CardProfile from "../../../../card/profile/CardProfile.svelte";
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
headerProps,
|
|
11
|
+
slotProps,
|
|
12
|
+
gridClass,
|
|
13
|
+
items,
|
|
14
|
+
variant,
|
|
15
|
+
isLoading = false,
|
|
16
|
+
}: CarouselProfileProps = $props();
|
|
17
|
+
|
|
18
|
+
const responsive = useDevice();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<CarouselHeader {...headerProps}>
|
|
22
|
+
<CarouselGridSlot {slotProps} {gridClass} totalItems={items.length}>
|
|
23
|
+
{#if isLoading}
|
|
24
|
+
{#each Array.from( { length: responsive.isMobile ? 5 : 9 }, ) as _, i (`loading-${i}`)}
|
|
25
|
+
{#if responsive.isMobile}
|
|
26
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
27
|
+
<CardProfile id={i} {variant} isLoading />
|
|
28
|
+
</Carousel.Item>
|
|
29
|
+
{:else}
|
|
30
|
+
<div>
|
|
31
|
+
<CardProfile id={i} {variant} isLoading />
|
|
32
|
+
</div>
|
|
33
|
+
{/if}
|
|
34
|
+
{/each}
|
|
35
|
+
{:else}
|
|
36
|
+
{#each items as item, i (`profile-${item.id ?? i}`)}
|
|
37
|
+
{#if responsive.isMobile}
|
|
38
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
39
|
+
<CardProfile {...item} {variant} />
|
|
40
|
+
</Carousel.Item>
|
|
41
|
+
{:else}
|
|
42
|
+
<div>
|
|
43
|
+
<CardProfile {...item} {variant} />
|
|
44
|
+
</div>
|
|
45
|
+
{/if}
|
|
46
|
+
{/each}
|
|
47
|
+
{/if}
|
|
48
|
+
</CarouselGridSlot>
|
|
49
|
+
</CarouselHeader>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import CarouselSlot from "../../../../panel/CarouselSlot.svelte";
|
|
4
|
+
import type { CarouselSlotProps } from "../../../../panel/type";
|
|
5
|
+
import { useDevice } from "../../../../../../hooks/responsive.svelte";
|
|
6
|
+
import Autoplay from "embla-carousel-autoplay";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
slotProps?: CarouselSlotProps;
|
|
10
|
+
totalItems: number;
|
|
11
|
+
gridClass?: string;
|
|
12
|
+
children: Snippet;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const { slotProps, totalItems, gridClass, children }: Props = $props();
|
|
16
|
+
|
|
17
|
+
const responsive = useDevice();
|
|
18
|
+
|
|
19
|
+
const colsClass = $derived(totalItems <= 2 ? "grid-cols-2" : "grid-cols-3");
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
{#if responsive.isMobile}
|
|
23
|
+
<CarouselSlot
|
|
24
|
+
{...slotProps}
|
|
25
|
+
plugins={[Autoplay({ delay: 4000, stopOnInteraction: true })]}
|
|
26
|
+
>
|
|
27
|
+
{@render children()}
|
|
28
|
+
</CarouselSlot>
|
|
29
|
+
{:else}
|
|
30
|
+
<div class="grid {colsClass} gap-4 p-2 {gridClass}">
|
|
31
|
+
{@render children()}
|
|
32
|
+
</div>
|
|
33
|
+
{/if}
|