negodesign 0.0.12 → 0.0.14
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/components/core/card/promotion/CardPromotion.svelte +44 -0
- package/dist/components/core/card/promotion/CardPromotion.svelte.d.ts +8 -0
- package/dist/components/core/card/promotion/data.d.ts +3 -0
- package/dist/components/core/card/promotion/data.js +31 -0
- package/dist/components/core/card/shared/CardFavorite.svelte +20 -20
- package/dist/components/core/card/shared/CardFavorite.svelte.d.ts +1 -1
- package/dist/components/core/card/types.d.ts +10 -0
- package/dist/components/core/carousel/hero/CarouselHero.svelte +140 -0
- package/dist/components/core/carousel/hero/CarouselHero.svelte.d.ts +10 -0
- package/dist/components/core/carousel/promotion/ui/CarouselPromotion.svelte +53 -0
- package/dist/components/core/carousel/promotion/ui/CarouselPromotion.svelte.d.ts +4 -0
- package/dist/components/core/carousel/shared/ui/SimpleBadgeCarousel.svelte +59 -0
- package/dist/components/core/carousel/shared/ui/SimpleBadgeCarousel.svelte.d.ts +4 -0
- package/dist/components/core/carousel/types.d.ts +22 -1
- package/dist/components/core/hero/SimpleHero.svelte +65 -0
- package/dist/components/core/hero/SimpleHero.svelte.d.ts +4 -0
- package/dist/components/core/hero/types.d.ts +18 -0
- package/dist/components/core/hero/types.js +1 -0
- package/dist/components/core/nav/data/nav-menu.d.ts +5 -1
- package/dist/components/core/nav/ui/nav-menu.svelte +94 -87
- package/dist/components/core/panel/CarouselSlot.svelte +38 -0
- package/dist/components/core/panel/CarouselSlot.svelte.d.ts +11 -0
- package/dist/globals.css +3756 -56
- package/dist/i18n/langs/en.d.ts +1 -0
- package/dist/i18n/langs/en.js +1 -0
- package/dist/i18n/langs/pt.d.ts +1 -0
- package/dist/i18n/langs/pt.js +1 -0
- package/dist/i18n/translations.d.ts +2 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/styles/animate.min.css +4385 -0
- package/dist/styles/globals.css +7 -2
- package/package.json +2 -2
- package/dist/components/core/carousel/ui/SimpleCarousel.svelte +0 -62
- package/dist/components/core/carousel/ui/SimpleCarousel.svelte.d.ts +0 -4
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CardFavorite from "../shared/CardFavorite.svelte";
|
|
3
|
+
/**
|
|
4
|
+
* Card component with a title and content.
|
|
5
|
+
* @component
|
|
6
|
+
*/
|
|
7
|
+
import type { CardPromotionProps } from "../types";
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
logo,
|
|
11
|
+
imageUrl,
|
|
12
|
+
title,
|
|
13
|
+
isFavorite = false,
|
|
14
|
+
}: CardPromotionProps = $props();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<article class="relative rounded-sm">
|
|
18
|
+
{#if logo}
|
|
19
|
+
<div class="absolute top-1 left-1 z-2 flex gap-1 p-2">
|
|
20
|
+
<img src={logo} width={30} height={30} alt={title} class="rounded-lg" />
|
|
21
|
+
</div>
|
|
22
|
+
{/if}
|
|
23
|
+
|
|
24
|
+
<div class="absolute top-1 right-1 z-2 flex gap-1 p-2">
|
|
25
|
+
<CardFavorite {isFavorite} />
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
{#if imageUrl}
|
|
29
|
+
<img
|
|
30
|
+
src={imageUrl}
|
|
31
|
+
alt={imageUrl}
|
|
32
|
+
class="rounded-lg md:h-37.5 md:w-37.5 lg:h-50 lg:w-50 object-cover object-center"
|
|
33
|
+
/>
|
|
34
|
+
{/if}
|
|
35
|
+
<div class="absolute inset-0 bg-black/5 rounded-sm h-full w-full"></div>
|
|
36
|
+
|
|
37
|
+
<div
|
|
38
|
+
class="absolute bottom-1 inset-x-0 flex justify-center m-auto bg-black/10 backdrop-blur-sm max-w-11/12 p-2 rounded-md"
|
|
39
|
+
>
|
|
40
|
+
{#if title}
|
|
41
|
+
<div class="text-center font-semibold text-[12px]">{title}</div>
|
|
42
|
+
{/if}
|
|
43
|
+
</div>
|
|
44
|
+
</article>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card component with a title and content.
|
|
3
|
+
* @component
|
|
4
|
+
*/
|
|
5
|
+
import type { CardPromotionProps } from "../types";
|
|
6
|
+
declare const CardPromotion: import("svelte").Component<CardPromotionProps, {}, "">;
|
|
7
|
+
type CardPromotion = ReturnType<typeof CardPromotion>;
|
|
8
|
+
export default CardPromotion;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const items = [
|
|
2
|
+
{
|
|
3
|
+
id: 1,
|
|
4
|
+
imageUrl: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
5
|
+
title: 'Hotel Baía Azul',
|
|
6
|
+
isFavorite: true,
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
id: 2,
|
|
10
|
+
imageUrl: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
11
|
+
title: 'Miramar Suites',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: 3,
|
|
15
|
+
imageUrl: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
16
|
+
title: 'Palm Resort & Spa',
|
|
17
|
+
isFavorite: true
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 4,
|
|
21
|
+
imageUrl: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
22
|
+
title: 'Hotel Central Park',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 5,
|
|
26
|
+
imageUrl: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
|
|
27
|
+
title: 'Villa Serena Boutique',
|
|
28
|
+
isFavorite: true,
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
export default items;
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { Button } from "../../../ui/button/index.js";
|
|
3
|
+
import { HeartAddIcon, HeartRemoveIcon } from "@hugeicons/core-free-icons";
|
|
4
|
+
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
type Props = {
|
|
7
|
+
isFavorite: boolean;
|
|
8
|
+
onFavoriteClick?: () => void;
|
|
9
|
+
};
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
let { isFavorite, onFavoriteClick }: Props = $props();
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
14
|
{#if isFavorite}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
<Button
|
|
16
|
+
class="w-8 h-8 rounded-full bg-[#ce2356]"
|
|
17
|
+
onclick={() => onFavoriteClick!()}
|
|
18
|
+
>
|
|
19
|
+
<HugeiconsIcon icon={HeartRemoveIcon} />
|
|
20
|
+
</Button>
|
|
21
21
|
{:else}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
<Button
|
|
23
|
+
class="w-8 h-8 rounded-full bg-[#808080]"
|
|
24
|
+
onclick={() => onFavoriteClick!()}
|
|
25
|
+
>
|
|
26
|
+
<HugeiconsIcon icon={HeartAddIcon} />
|
|
27
|
+
</Button>
|
|
28
28
|
{/if}
|
|
@@ -42,3 +42,13 @@ export interface CardProfileProps {
|
|
|
42
42
|
onButtonProfile?: (id: string | number) => void;
|
|
43
43
|
onButtonDetails?: (id: string | number) => void;
|
|
44
44
|
}
|
|
45
|
+
export interface CardPromotionProps {
|
|
46
|
+
id: string | number;
|
|
47
|
+
logo?: string;
|
|
48
|
+
imageUrl?: string;
|
|
49
|
+
title?: string;
|
|
50
|
+
className?: string;
|
|
51
|
+
isFavorite?: boolean;
|
|
52
|
+
oldPrice?: string | number;
|
|
53
|
+
newPrice?: string | number;
|
|
54
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { CarouselHeroItem, CarouselHeroProps } from "../types";
|
|
3
|
+
import NavMenu from "../../nav/ui/nav-menu.svelte";
|
|
4
|
+
import type { Snippet } from "svelte";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
navMenu,
|
|
8
|
+
items,
|
|
9
|
+
children,
|
|
10
|
+
intervalMs = 5000,
|
|
11
|
+
transitionMs = 1200,
|
|
12
|
+
}: CarouselHeroProps & {
|
|
13
|
+
children?: Snippet;
|
|
14
|
+
intervalMs?: number;
|
|
15
|
+
transitionMs?: number;
|
|
16
|
+
} = $props();
|
|
17
|
+
|
|
18
|
+
// Buffer duplo: duas camadas fixas, nunca desmontadas — só a opacidade muda.
|
|
19
|
+
let layers = $state<[string, string]>([items?.[0]?.image ?? "", ""]);
|
|
20
|
+
let active = $state<0 | 1>(0);
|
|
21
|
+
let index = $state(0);
|
|
22
|
+
let switching = false; // evita trocas sobrepostas se o intervalo disparar antes do preload acabar
|
|
23
|
+
|
|
24
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
25
|
+
const preloadCache = new Map<string, Promise<void>>();
|
|
26
|
+
|
|
27
|
+
function preload(src: string): Promise<void> {
|
|
28
|
+
if (!src) return Promise.resolve();
|
|
29
|
+
const cached = preloadCache.get(src);
|
|
30
|
+
if (cached) return cached;
|
|
31
|
+
|
|
32
|
+
const promise = new Promise<void>((resolve) => {
|
|
33
|
+
const img = new Image();
|
|
34
|
+
img.onload = () => resolve();
|
|
35
|
+
img.onerror = () => resolve(); // não bloqueia o carousel por uma imagem partida
|
|
36
|
+
img.src = src;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
preloadCache.set(src, promise);
|
|
40
|
+
return promise;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Pré-carrega todas as imagens uma vez, assim que os items ficam disponíveis.
|
|
44
|
+
$effect(() => {
|
|
45
|
+
items?.forEach((item) => void preload(item.image));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
async function goTo(nextIndex: number) {
|
|
49
|
+
if (!items || nextIndex === index || switching) return;
|
|
50
|
+
switching = true;
|
|
51
|
+
|
|
52
|
+
const nextSrc = items[nextIndex].image;
|
|
53
|
+
await preload(nextSrc); // garante decode/cache antes de trocar a camada -> sem flash
|
|
54
|
+
|
|
55
|
+
const nextLayer = active === 0 ? 1 : 0;
|
|
56
|
+
layers[nextLayer] = nextSrc;
|
|
57
|
+
active = nextLayer;
|
|
58
|
+
index = nextIndex;
|
|
59
|
+
switching = false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
$effect(() => {
|
|
63
|
+
if (!items || items.length <= 1) return;
|
|
64
|
+
|
|
65
|
+
const timer = setInterval(() => {
|
|
66
|
+
goTo((index + 1) % items.length);
|
|
67
|
+
}, intervalMs);
|
|
68
|
+
|
|
69
|
+
return () => clearInterval(timer);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
function fadeIn(node: HTMLElement) {
|
|
73
|
+
requestAnimationFrame(() => {
|
|
74
|
+
node.style.opacity = "1";
|
|
75
|
+
});
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let selected = $derived<CarouselHeroItem | undefined>(items?.[index]);
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
{#if selected}
|
|
83
|
+
<header
|
|
84
|
+
class="w-full relative flex flex-col justify-center items-center h-[300px] md:h-[400px] overflow-hidden"
|
|
85
|
+
>
|
|
86
|
+
{#each layers as bg, i (i)}
|
|
87
|
+
<div
|
|
88
|
+
class="absolute inset-0 bg-cover bg-center will-change-[opacity]"
|
|
89
|
+
style="
|
|
90
|
+
background-image: {bg ? `url(${bg})` : 'none'};
|
|
91
|
+
opacity: {i === active ? 1 : 0};
|
|
92
|
+
transition: opacity {transitionMs}ms ease-in-out;
|
|
93
|
+
"
|
|
94
|
+
></div>
|
|
95
|
+
{/each}
|
|
96
|
+
|
|
97
|
+
<div class="absolute inset-0 bg-black/40"></div>
|
|
98
|
+
|
|
99
|
+
<div class="relative z-10 w-full flex flex-col items-center flex-1">
|
|
100
|
+
<NavMenu {...navMenu} />
|
|
101
|
+
|
|
102
|
+
<section
|
|
103
|
+
class="flex flex-col justify-center items-center flex-1 w-full h-auto text-center px-4"
|
|
104
|
+
>
|
|
105
|
+
{#key selected.title}
|
|
106
|
+
<div
|
|
107
|
+
style="transition: opacity {transitionMs * 0.6}ms ease-in-out;"
|
|
108
|
+
class="opacity-0"
|
|
109
|
+
use:fadeIn
|
|
110
|
+
>
|
|
111
|
+
<h1 class="text-white text-2xl md:text-4xl font-bold">
|
|
112
|
+
{selected.title}
|
|
113
|
+
</h1>
|
|
114
|
+
<p class="text-white/90 mt-2 max-w-2xl">
|
|
115
|
+
{selected.description}
|
|
116
|
+
</p>
|
|
117
|
+
</div>
|
|
118
|
+
{/key}
|
|
119
|
+
|
|
120
|
+
{#if children}
|
|
121
|
+
{@render children()}
|
|
122
|
+
{/if}
|
|
123
|
+
</section>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
{#if items && items.length > 1}
|
|
127
|
+
<div class="absolute bottom-3 z-10 flex gap-2">
|
|
128
|
+
{#each items as item, i (i)}
|
|
129
|
+
<button
|
|
130
|
+
aria-label={`Ir para o slide ${i + 1}: ${item.title}`}
|
|
131
|
+
class="w-2 h-2 rounded-full transition-colors {i === index
|
|
132
|
+
? 'bg-white'
|
|
133
|
+
: 'bg-white/40'}"
|
|
134
|
+
onclick={() => goTo(i)}
|
|
135
|
+
></button>
|
|
136
|
+
{/each}
|
|
137
|
+
</div>
|
|
138
|
+
{/if}
|
|
139
|
+
</header>
|
|
140
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CarouselHeroProps } from "../types";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
type $$ComponentProps = CarouselHeroProps & {
|
|
4
|
+
children?: Snippet;
|
|
5
|
+
intervalMs?: number;
|
|
6
|
+
transitionMs?: number;
|
|
7
|
+
};
|
|
8
|
+
declare const CarouselHero: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type CarouselHero = ReturnType<typeof CarouselHero>;
|
|
10
|
+
export default CarouselHero;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CardPromotion from "../../../card/promotion/CardPromotion.svelte";
|
|
3
|
+
import type { CarouselPromotionProps } from "../../types.js";
|
|
4
|
+
import Button from "../../../../ui/button/button.svelte";
|
|
5
|
+
import CarouselSlot from "../../../panel/CarouselSlot.svelte";
|
|
6
|
+
import { t } from "../../../../../i18n";
|
|
7
|
+
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
8
|
+
import { ArrowRight02Icon } from "@hugeicons/core-free-icons";
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
title,
|
|
12
|
+
items,
|
|
13
|
+
isButtonPreviousAndNext = true,
|
|
14
|
+
buttonPreviousAndNextClass = "",
|
|
15
|
+
containerClass = "",
|
|
16
|
+
onButtonViewAll,
|
|
17
|
+
}: CarouselPromotionProps = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<div class="w-full flex justify-center">
|
|
21
|
+
<div class="w-[95%] p-2 rounded-xl {containerClass}">
|
|
22
|
+
<div class="ml-10 flex flex-col gap-1">
|
|
23
|
+
<div class="flex justify-between">
|
|
24
|
+
<div class="text-xl">{title ?? $t("label.promotion")}</div>
|
|
25
|
+
{#if onButtonViewAll}
|
|
26
|
+
<div>
|
|
27
|
+
<Button
|
|
28
|
+
variant="ghost"
|
|
29
|
+
size="sm"
|
|
30
|
+
class="flex items-center gap-0.5"
|
|
31
|
+
onclick={onButtonViewAll}
|
|
32
|
+
>
|
|
33
|
+
{$t("label.view.full")}
|
|
34
|
+
<HugeiconsIcon icon={ArrowRight02Icon} />
|
|
35
|
+
</Button>
|
|
36
|
+
</div>
|
|
37
|
+
{/if}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<CarouselSlot
|
|
41
|
+
isBorderBottom={false}
|
|
42
|
+
{isButtonPreviousAndNext}
|
|
43
|
+
{buttonPreviousAndNextClass}
|
|
44
|
+
containerClass="w-full"
|
|
45
|
+
>
|
|
46
|
+
{#each items as item (item.id)}
|
|
47
|
+
<div class="mx-2">
|
|
48
|
+
<CardPromotion {...item} />
|
|
49
|
+
</div>
|
|
50
|
+
{/each}
|
|
51
|
+
</CarouselSlot>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Carousel from "../../../../ui/carousel/index.js";
|
|
3
|
+
import type { SimpleBadgeCarouselProps } from "../../types.js";
|
|
4
|
+
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
5
|
+
import CarouselSlot from "../../../panel/CarouselSlot.svelte";
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
items,
|
|
9
|
+
imageClass,
|
|
10
|
+
iconClass,
|
|
11
|
+
labelClass,
|
|
12
|
+
activeClass,
|
|
13
|
+
valueActive,
|
|
14
|
+
orientation = "horizontal",
|
|
15
|
+
isBorderItem = true,
|
|
16
|
+
isBorderBottom = true,
|
|
17
|
+
isButtonPreviousAndNext = true,
|
|
18
|
+
buttonPreviousAndNextClass = "",
|
|
19
|
+
}: SimpleBadgeCarouselProps = $props();
|
|
20
|
+
|
|
21
|
+
const DEFAULT_IMG_OR_ICON_CLASS = "size-5 rounded-lg";
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<CarouselSlot
|
|
25
|
+
{isBorderBottom}
|
|
26
|
+
{isButtonPreviousAndNext}
|
|
27
|
+
{buttonPreviousAndNextClass}
|
|
28
|
+
>
|
|
29
|
+
{#each items as item (item.value)}
|
|
30
|
+
<Carousel.Item
|
|
31
|
+
onclick={() => item.onClick?.(item.value)}
|
|
32
|
+
class={`
|
|
33
|
+
flex cursor-pointer items-center justify-center gap-1 basis-auto mx-3 pl-0
|
|
34
|
+
${isBorderItem ? "border border-solid border-gray-300 rounded-lg" : ""}
|
|
35
|
+
${item.value === valueActive ? activeClass : ""}`}
|
|
36
|
+
>
|
|
37
|
+
<div
|
|
38
|
+
class={`
|
|
39
|
+
flex gap-1 mx-2 p-0.5 justify-center items-center
|
|
40
|
+
${orientation === "horizontal" ? "flex-row" : "flex-col"}
|
|
41
|
+
`}
|
|
42
|
+
>
|
|
43
|
+
{#if item.image}
|
|
44
|
+
<img
|
|
45
|
+
src={item.image}
|
|
46
|
+
alt={item.label}
|
|
47
|
+
class={imageClass || DEFAULT_IMG_OR_ICON_CLASS}
|
|
48
|
+
/>
|
|
49
|
+
{:else if item.icon}
|
|
50
|
+
<HugeiconsIcon
|
|
51
|
+
icon={item.icon}
|
|
52
|
+
class={iconClass || DEFAULT_IMG_OR_ICON_CLASS}
|
|
53
|
+
/>
|
|
54
|
+
{/if}
|
|
55
|
+
<div class={`${labelClass}`}>{item.label}</div>
|
|
56
|
+
</div>
|
|
57
|
+
</Carousel.Item>
|
|
58
|
+
{/each}
|
|
59
|
+
</CarouselSlot>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { IconSvgElement } from "@hugeicons/svelte";
|
|
2
|
+
import type { CardPromotionProps } from "../card/types";
|
|
3
|
+
import type { NavMenuProps } from "../nav/data/nav-menu";
|
|
2
4
|
export interface ItemCarousel {
|
|
3
5
|
value: string;
|
|
4
6
|
label: string;
|
|
@@ -8,7 +10,7 @@ export interface ItemCarousel {
|
|
|
8
10
|
isActive?: boolean;
|
|
9
11
|
onClick?: (value: string) => void;
|
|
10
12
|
}
|
|
11
|
-
export interface
|
|
13
|
+
export interface SimpleBadgeCarouselProps {
|
|
12
14
|
items: ItemCarousel[];
|
|
13
15
|
orientation?: "horizontal" | "vertical";
|
|
14
16
|
imageClass?: string;
|
|
@@ -21,3 +23,22 @@ export interface SimpleCarouselProps {
|
|
|
21
23
|
isButtonPreviousAndNext?: boolean;
|
|
22
24
|
buttonPreviousAndNextClass?: string;
|
|
23
25
|
}
|
|
26
|
+
export interface CarouselPromotionProps {
|
|
27
|
+
title?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
items: CardPromotionProps[];
|
|
30
|
+
isBorderBottom?: boolean;
|
|
31
|
+
isButtonPreviousAndNext?: boolean;
|
|
32
|
+
buttonPreviousAndNextClass?: string;
|
|
33
|
+
containerClass?: string;
|
|
34
|
+
onButtonViewAll?: () => void;
|
|
35
|
+
}
|
|
36
|
+
export interface CarouselHeroItem {
|
|
37
|
+
title: string;
|
|
38
|
+
image: string;
|
|
39
|
+
description: string;
|
|
40
|
+
}
|
|
41
|
+
export interface CarouselHeroProps {
|
|
42
|
+
navMenu: NavMenuProps;
|
|
43
|
+
items: CarouselHeroItem[];
|
|
44
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from "../../ui/button/index.js";
|
|
3
|
+
import type { HeroSimpleProps } from "./types";
|
|
4
|
+
let {
|
|
5
|
+
title,
|
|
6
|
+
subTitle,
|
|
7
|
+
description,
|
|
8
|
+
image,
|
|
9
|
+
buttons,
|
|
10
|
+
titleClass,
|
|
11
|
+
subTitleClass,
|
|
12
|
+
descriptionClass,
|
|
13
|
+
imageClass,
|
|
14
|
+
}: HeroSimpleProps = $props();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<section class="relative flex p-2">
|
|
18
|
+
<div class="w-full grid grid-cols-10 md:grid-cols-2 min-h-50 md:min-h-125">
|
|
19
|
+
<div class="flex justify-center items-center">
|
|
20
|
+
<div class="space-y-1">
|
|
21
|
+
{#if title}
|
|
22
|
+
<h1
|
|
23
|
+
class="font-bold text-[24px] md:text-[60px] lg:text-[80px] {titleClass}"
|
|
24
|
+
>
|
|
25
|
+
{title}
|
|
26
|
+
</h1>
|
|
27
|
+
{/if}
|
|
28
|
+
{#if subTitle}
|
|
29
|
+
<p class="font-semibold text-[16px] md:text-[40px] {subTitleClass}">
|
|
30
|
+
{subTitle}
|
|
31
|
+
</p>
|
|
32
|
+
{/if}
|
|
33
|
+
{#if description}
|
|
34
|
+
<p
|
|
35
|
+
class="text-[12px] md:text-[20px] md:w-8/12 mt-5 {descriptionClass}"
|
|
36
|
+
>
|
|
37
|
+
{description}
|
|
38
|
+
</p>
|
|
39
|
+
{/if}
|
|
40
|
+
{#if buttons}
|
|
41
|
+
<div class="flex flex-wrap gap-2 mt-5 md:mt-10">
|
|
42
|
+
{#each buttons as button, i (i)}
|
|
43
|
+
<Button
|
|
44
|
+
href={button.href}
|
|
45
|
+
class={button.className}
|
|
46
|
+
onclick={button.onClick}
|
|
47
|
+
>
|
|
48
|
+
{button.label}
|
|
49
|
+
</Button>
|
|
50
|
+
{/each}
|
|
51
|
+
</div>
|
|
52
|
+
{/if}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="flex justify-center items-center">
|
|
56
|
+
{#if image}
|
|
57
|
+
<img
|
|
58
|
+
src={image}
|
|
59
|
+
alt={image}
|
|
60
|
+
class="rounded-lg h-50 md:h-125 w-[60%] object-cover {imageClass}"
|
|
61
|
+
/>
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</section>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface HeroButtonProps {
|
|
2
|
+
label: string;
|
|
3
|
+
href: string;
|
|
4
|
+
variant?: "primary" | "outline" | "ghost";
|
|
5
|
+
className?: string;
|
|
6
|
+
onClick?: () => void;
|
|
7
|
+
}
|
|
8
|
+
export interface HeroSimpleProps {
|
|
9
|
+
title?: string;
|
|
10
|
+
subTitle?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
image?: string;
|
|
13
|
+
buttons?: HeroButtonProps[];
|
|
14
|
+
titleClass?: string;
|
|
15
|
+
subTitleClass?: string;
|
|
16
|
+
descriptionClass?: string;
|
|
17
|
+
imageClass?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IconSvgElement } from "@hugeicons/svelte";
|
|
2
2
|
export interface NavMenuLogoProps {
|
|
3
3
|
img?: string;
|
|
4
|
+
url?: string;
|
|
4
5
|
label: string;
|
|
5
6
|
className?: string;
|
|
6
7
|
onclick?: () => void;
|
|
@@ -20,12 +21,15 @@ export interface NavMenuActionsProps {
|
|
|
20
21
|
onclick?: () => void;
|
|
21
22
|
}
|
|
22
23
|
export interface NavMenuProps {
|
|
24
|
+
navClass?: string;
|
|
23
25
|
linkClass?: string;
|
|
24
26
|
buttonClass?: string;
|
|
25
27
|
logo?: NavMenuLogoProps;
|
|
26
28
|
links: NavMenuLinksProps[];
|
|
27
|
-
actions
|
|
29
|
+
actions?: NavMenuActionsProps[];
|
|
28
30
|
align?: 'LINK_SEPARATED_ACTIONS' | 'LINK_INTO_ACTIONS';
|
|
31
|
+
isLightSwitch?: boolean;
|
|
32
|
+
isLanguageSwitcher?: boolean;
|
|
29
33
|
onclickButtonLogin?: () => void;
|
|
30
34
|
onclickButtonRegister?: () => void;
|
|
31
35
|
}
|