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
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { CarouselSlotProps } from "../../../../panel/type";
|
|
3
|
+
type Props = {
|
|
4
|
+
slotProps?: CarouselSlotProps;
|
|
5
|
+
totalItems: number;
|
|
6
|
+
gridClass?: string;
|
|
7
|
+
children: Snippet;
|
|
8
|
+
};
|
|
9
|
+
declare const CarouselGridSlot: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type CarouselGridSlot = ReturnType<typeof CarouselGridSlot>;
|
|
11
|
+
export default CarouselGridSlot;
|
|
@@ -12,17 +12,18 @@
|
|
|
12
12
|
descriptionClass,
|
|
13
13
|
intervalMs = 5000,
|
|
14
14
|
transitionMs = 1200,
|
|
15
|
+
indicatorShow = false,
|
|
15
16
|
}: CarouselHeroProps & {
|
|
16
17
|
children?: Snippet;
|
|
17
18
|
intervalMs?: number;
|
|
18
19
|
transitionMs?: number;
|
|
20
|
+
indicatorShow?: boolean;
|
|
19
21
|
} = $props();
|
|
20
22
|
|
|
21
|
-
// Buffer duplo: duas camadas fixas, nunca desmontadas — só a opacidade muda.
|
|
22
23
|
let layers = $state<[string, string]>([items?.[0]?.image ?? "", ""]);
|
|
23
24
|
let active = $state<0 | 1>(0);
|
|
24
25
|
let index = $state(0);
|
|
25
|
-
let switching = false;
|
|
26
|
+
let switching = false;
|
|
26
27
|
|
|
27
28
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
28
29
|
const preloadCache = new Map<string, Promise<void>>();
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
const promise = new Promise<void>((resolve) => {
|
|
36
37
|
const img = new Image();
|
|
37
38
|
img.onload = () => resolve();
|
|
38
|
-
img.onerror = () => resolve();
|
|
39
|
+
img.onerror = () => resolve();
|
|
39
40
|
img.src = src;
|
|
40
41
|
});
|
|
41
42
|
|
|
@@ -43,7 +44,6 @@
|
|
|
43
44
|
return promise;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
// Pré-carrega todas as imagens uma vez, assim que os items ficam disponíveis.
|
|
47
47
|
$effect(() => {
|
|
48
48
|
items?.forEach((item) => void preload(item.image));
|
|
49
49
|
});
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
switching = true;
|
|
54
54
|
|
|
55
55
|
const nextSrc = items[nextIndex].image;
|
|
56
|
-
await preload(nextSrc);
|
|
56
|
+
await preload(nextSrc);
|
|
57
57
|
|
|
58
58
|
const nextLayer = active === 0 ? 1 : 0;
|
|
59
59
|
layers[nextLayer] = nextSrc;
|
|
@@ -139,20 +139,22 @@
|
|
|
139
139
|
</section>
|
|
140
140
|
</div>
|
|
141
141
|
|
|
142
|
-
{#if
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
142
|
+
{#if indicatorShow}
|
|
143
|
+
{#if items && items.length > 1}
|
|
144
|
+
<div
|
|
145
|
+
style="position: absolute; bottom: 0.75rem; z-index: 10; display: flex; gap: 0.5rem;"
|
|
146
|
+
>
|
|
147
|
+
{#each items as item, i (`hero-dot-${i}`)}
|
|
148
|
+
<button
|
|
149
|
+
aria-label={`Ir para o slide ${i + 1}: ${item.title}`}
|
|
150
|
+
class="w-2 h-2 rounded-full transition-colors {i === index
|
|
151
|
+
? 'bg-white'
|
|
152
|
+
: 'bg-white/40'}"
|
|
153
|
+
onclick={() => goTo(i)}
|
|
154
|
+
></button>
|
|
155
|
+
{/each}
|
|
156
|
+
</div>
|
|
157
|
+
{/if}
|
|
156
158
|
{/if}
|
|
157
159
|
</header>
|
|
158
160
|
{/if}
|
|
@@ -4,6 +4,7 @@ type $$ComponentProps = CarouselHeroProps & {
|
|
|
4
4
|
children?: Snippet;
|
|
5
5
|
intervalMs?: number;
|
|
6
6
|
transitionMs?: number;
|
|
7
|
+
indicatorShow?: boolean;
|
|
7
8
|
};
|
|
8
9
|
declare const CarouselHero: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
10
|
type CarouselHero = ReturnType<typeof CarouselHero>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { CardHighlightProps } from "../../card/types";
|
|
2
|
+
import type { CarouselSlotProps } from "../../panel/type";
|
|
2
3
|
import type { CarouselHeaderProps } from "../types";
|
|
3
|
-
export interface CarouselHighlightsProps
|
|
4
|
+
export interface CarouselHighlightsProps {
|
|
5
|
+
headerProps?: CarouselHeaderProps;
|
|
6
|
+
slotProps?: CarouselSlotProps;
|
|
4
7
|
items: CardHighlightProps[];
|
|
5
8
|
varient?: 1 | 2;
|
|
6
|
-
isBorderBottom?: boolean;
|
|
7
9
|
isLoading?: boolean;
|
|
8
10
|
isDescriptionIcon?: boolean;
|
|
9
11
|
isDescriptionLabel?: boolean;
|
|
10
|
-
isButtonPreviousAndNext?: boolean;
|
|
11
|
-
buttonPreviousAndNextClass?: string;
|
|
12
12
|
}
|
|
@@ -8,39 +8,21 @@
|
|
|
8
8
|
import Autoplay from "embla-carousel-autoplay";
|
|
9
9
|
|
|
10
10
|
const {
|
|
11
|
-
|
|
11
|
+
headerProps,
|
|
12
|
+
slotProps,
|
|
12
13
|
items,
|
|
13
|
-
description,
|
|
14
|
-
titleClass,
|
|
15
|
-
descriptionClass,
|
|
16
|
-
isButtonPreviousAndNext = true,
|
|
17
|
-
buttonPreviousAndNextClass = "",
|
|
18
|
-
containerClass = "",
|
|
19
14
|
isLoading = false,
|
|
20
15
|
varient = 1,
|
|
21
16
|
isDescriptionIcon,
|
|
22
17
|
isDescriptionLabel,
|
|
23
|
-
onButtonViewAll,
|
|
24
|
-
positionButtonPreviousAndNext,
|
|
25
18
|
}: CarouselHighlightsProps = $props();
|
|
26
19
|
|
|
27
20
|
const responsive = useDevice();
|
|
28
21
|
</script>
|
|
29
22
|
|
|
30
|
-
<CarouselHeader
|
|
31
|
-
{title}
|
|
32
|
-
{description}
|
|
33
|
-
{titleClass}
|
|
34
|
-
{descriptionClass}
|
|
35
|
-
{containerClass}
|
|
36
|
-
{onButtonViewAll}
|
|
37
|
-
>
|
|
23
|
+
<CarouselHeader {...headerProps}>
|
|
38
24
|
<CarouselSlot
|
|
39
|
-
|
|
40
|
-
{isButtonPreviousAndNext}
|
|
41
|
-
{buttonPreviousAndNextClass}
|
|
42
|
-
{positionButtonPreviousAndNext}
|
|
43
|
-
containerClass="w-full"
|
|
25
|
+
{...slotProps}
|
|
44
26
|
plugins={[Autoplay({ delay: 4000, stopOnInteraction: true })]}
|
|
45
27
|
>
|
|
46
28
|
{#if isLoading}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { CardPromotionProps } from "../../card/types";
|
|
2
|
+
import type { CarouselSlotProps } from "../../panel/type";
|
|
2
3
|
import type { CarouselHeaderProps } from "../types";
|
|
3
|
-
export interface CarouselPromotionProps
|
|
4
|
+
export interface CarouselPromotionProps {
|
|
5
|
+
headerProps?: CarouselHeaderProps;
|
|
6
|
+
slotProps?: CarouselSlotProps;
|
|
4
7
|
items: CardPromotionProps[];
|
|
5
|
-
isBorderBottom?: boolean;
|
|
6
|
-
isLoading?: boolean;
|
|
7
|
-
isButtonPreviousAndNext?: boolean;
|
|
8
|
-
buttonPreviousAndNextClass?: string;
|
|
9
8
|
isDescriptionIcon?: boolean;
|
|
10
9
|
isDescriptionLabel?: boolean;
|
|
10
|
+
isLoading?: boolean;
|
|
11
11
|
}
|
|
@@ -8,37 +8,20 @@
|
|
|
8
8
|
import Autoplay from "embla-carousel-autoplay";
|
|
9
9
|
|
|
10
10
|
const {
|
|
11
|
-
|
|
11
|
+
headerProps,
|
|
12
|
+
slotProps,
|
|
12
13
|
items,
|
|
13
|
-
description,
|
|
14
|
-
titleClass,
|
|
15
|
-
descriptionClass,
|
|
16
|
-
isButtonPreviousAndNext = true,
|
|
17
14
|
isLoading = false,
|
|
18
|
-
buttonPreviousAndNextClass = "",
|
|
19
|
-
containerClass = "",
|
|
20
|
-
positionButtonPreviousAndNext,
|
|
21
15
|
isDescriptionIcon,
|
|
22
16
|
isDescriptionLabel,
|
|
23
|
-
onButtonViewAll,
|
|
24
17
|
}: CarouselPromotionProps = $props();
|
|
25
18
|
|
|
26
19
|
const responsive = useDevice();
|
|
27
20
|
</script>
|
|
28
21
|
|
|
29
|
-
<CarouselHeader
|
|
30
|
-
{title}
|
|
31
|
-
{description}
|
|
32
|
-
{titleClass}
|
|
33
|
-
{descriptionClass}
|
|
34
|
-
{containerClass}
|
|
35
|
-
{onButtonViewAll}
|
|
36
|
-
>
|
|
22
|
+
<CarouselHeader {...headerProps}>
|
|
37
23
|
<CarouselSlot
|
|
38
|
-
|
|
39
|
-
{isButtonPreviousAndNext}
|
|
40
|
-
{buttonPreviousAndNextClass}
|
|
41
|
-
{positionButtonPreviousAndNext}
|
|
24
|
+
{...slotProps}
|
|
42
25
|
containerClass="w-full"
|
|
43
26
|
plugins={[Autoplay({ delay: 4000, stopOnInteraction: true })]}
|
|
44
27
|
>
|
|
@@ -18,11 +18,16 @@
|
|
|
18
18
|
containerClass = "",
|
|
19
19
|
onButtonViewAll,
|
|
20
20
|
children,
|
|
21
|
+
isBorder,
|
|
21
22
|
}: CarouselHeaderProps & Props = $props();
|
|
22
23
|
</script>
|
|
23
24
|
|
|
24
25
|
<div class="w-full flex justify-center">
|
|
25
|
-
<div
|
|
26
|
+
<div
|
|
27
|
+
class="w-[95%] p-2 rounded-xl
|
|
28
|
+
{isBorder ? 'border border-gray-50 dark:border-gray-800' : ''}
|
|
29
|
+
{containerClass}"
|
|
30
|
+
>
|
|
26
31
|
<div class="flex flex-col gap-1">
|
|
27
32
|
<div class="flex justify-between">
|
|
28
33
|
<div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface FooterLinkItem {
|
|
2
|
+
text: string;
|
|
3
|
+
href?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface FooterSocialItem {
|
|
6
|
+
icon: "facebook" | "instagram" | "x" | "github" | "youtube" | "linkedin";
|
|
7
|
+
text: string;
|
|
8
|
+
href?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface FooterColumnProps {
|
|
11
|
+
title: string;
|
|
12
|
+
items: FooterLinkItem[];
|
|
13
|
+
}
|
|
14
|
+
export interface FooterProps {
|
|
15
|
+
items: FooterColumnProps[];
|
|
16
|
+
logo?: string;
|
|
17
|
+
isNewsletter?: boolean;
|
|
18
|
+
socialsMedia: FooterSocialItem[];
|
|
19
|
+
companyName?: string;
|
|
20
|
+
newsletterTitle?: string;
|
|
21
|
+
newsletterDescription?: string;
|
|
22
|
+
onSubscribe?: (email: string) => void;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { t } from "../../../../../i18n";
|
|
3
|
+
import type { FooterProps } from "../../types";
|
|
4
|
+
import FooterColumn from "../shared/FooterColumn.svelte";
|
|
5
|
+
import FooterNewsLetter from "../shared/FooterNewsLetter.svelte";
|
|
6
|
+
import SocialIcon from "../shared/FooterSocialIcon.svelte";
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
items,
|
|
10
|
+
logo,
|
|
11
|
+
isNewsletter = false,
|
|
12
|
+
socialsMedia,
|
|
13
|
+
companyName,
|
|
14
|
+
newsletterTitle,
|
|
15
|
+
newsletterDescription,
|
|
16
|
+
onSubscribe,
|
|
17
|
+
}: FooterProps = $props();
|
|
18
|
+
|
|
19
|
+
let email = $state("");
|
|
20
|
+
const year = new Date().getFullYear();
|
|
21
|
+
|
|
22
|
+
function handleSubscribe(e: SubmitEvent) {
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
const value = email.trim();
|
|
25
|
+
if (!value) return;
|
|
26
|
+
onSubscribe?.(value);
|
|
27
|
+
email = "";
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<footer class="p-10">
|
|
32
|
+
<div
|
|
33
|
+
class="flex flex-col gap-10 md:flex-row md:items-start md:justify-between"
|
|
34
|
+
>
|
|
35
|
+
<div class="shrink-0">
|
|
36
|
+
{#if logo}
|
|
37
|
+
<img src={logo} alt="" class="h-10 w-auto" />
|
|
38
|
+
{/if}
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="flex flex-1 flex-wrap justify-between gap-10">
|
|
42
|
+
{#each items as column, i (i)}
|
|
43
|
+
<FooterColumn title={column.title} items={column.items} />
|
|
44
|
+
{/each}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{#if isNewsletter}
|
|
49
|
+
<div
|
|
50
|
+
class="mt-10 flex flex-col gap-4 border-t border-gray/10 pt-8 md:flex-row md:items-center md:justify-between"
|
|
51
|
+
>
|
|
52
|
+
<FooterNewsLetter
|
|
53
|
+
{isNewsletter}
|
|
54
|
+
{newsletterTitle}
|
|
55
|
+
{newsletterDescription}
|
|
56
|
+
{onSubscribe}
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
{/if}
|
|
60
|
+
|
|
61
|
+
<div
|
|
62
|
+
class="mt-10 flex flex-col gap-4 border-t border-gray/10 pt-6 md:flex-row md:items-center md:justify-between"
|
|
63
|
+
>
|
|
64
|
+
<p class="text-sm">
|
|
65
|
+
©
|
|
66
|
+
{year}
|
|
67
|
+
{companyName}
|
|
68
|
+
{$t("footer.copyr")}
|
|
69
|
+
</p>
|
|
70
|
+
<div class="flex items-center gap-4">
|
|
71
|
+
{#each socialsMedia as social, i (i)}
|
|
72
|
+
<SocialIcon {...social} />
|
|
73
|
+
{/each}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</footer>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { t } from "../../../../../i18n";
|
|
3
|
+
import type { FooterProps } from "../../types";
|
|
4
|
+
import FooterColumn from "../shared/FooterColumn.svelte";
|
|
5
|
+
import FooterNewsLetter from "../shared/FooterNewsLetter.svelte";
|
|
6
|
+
import SocialIcon from "../shared/FooterSocialIcon.svelte";
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
items,
|
|
10
|
+
isNewsletter = false,
|
|
11
|
+
socialsMedia,
|
|
12
|
+
companyName,
|
|
13
|
+
newsletterTitle,
|
|
14
|
+
newsletterDescription,
|
|
15
|
+
onSubscribe,
|
|
16
|
+
}: FooterProps = $props();
|
|
17
|
+
|
|
18
|
+
const year = new Date().getFullYear();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<footer class="p-10">
|
|
22
|
+
<div class="flex flex-wrap justify-between gap-10">
|
|
23
|
+
{#each items as column, i (i)}
|
|
24
|
+
<FooterColumn title={column.title} items={column.items} />
|
|
25
|
+
{/each}
|
|
26
|
+
|
|
27
|
+
{#if isNewsletter}
|
|
28
|
+
<div class="min-w-60">
|
|
29
|
+
<FooterNewsLetter
|
|
30
|
+
{isNewsletter}
|
|
31
|
+
{newsletterTitle}
|
|
32
|
+
{newsletterDescription}
|
|
33
|
+
{onSubscribe}
|
|
34
|
+
/>
|
|
35
|
+
</div>
|
|
36
|
+
{/if}
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div
|
|
40
|
+
class="mt-10 flex flex-col gap-4 border-t border-gray/10 pt-6 md:flex-row md:items-center md:justify-between"
|
|
41
|
+
>
|
|
42
|
+
<p class="text-sm">
|
|
43
|
+
© {year}
|
|
44
|
+
{companyName}
|
|
45
|
+
{$t("footer.copyr")}
|
|
46
|
+
</p>
|
|
47
|
+
<div class="flex items-center gap-4">
|
|
48
|
+
{#each socialsMedia as social, i (i)}
|
|
49
|
+
<SocialIcon icon={social.icon} text={social.text} />
|
|
50
|
+
{/each}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</footer>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Footer01 from "./01/Footer01.svelte";
|
|
3
|
+
import Footer02 from "./02/Footer02.svelte";
|
|
4
|
+
import type { FooterProps } from "../types";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
variant = 1,
|
|
8
|
+
...restProps
|
|
9
|
+
}: FooterProps & {
|
|
10
|
+
variant?: 1 | 2;
|
|
11
|
+
} = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
{#if variant === 2}
|
|
15
|
+
<Footer02 {...restProps} />
|
|
16
|
+
{:else}
|
|
17
|
+
<Footer01 {...restProps} />
|
|
18
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { FooterColumnProps } from "../../types";
|
|
3
|
+
|
|
4
|
+
let { title, items }: FooterColumnProps = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div class="min-w-27.5">
|
|
8
|
+
<h3 class="mb-4 text-sm font-semibold">{title}</h3>
|
|
9
|
+
<ul class="space-y-3">
|
|
10
|
+
{#each items as item, i (i)}
|
|
11
|
+
<li>
|
|
12
|
+
<a href={item.href ?? "#"} class="text-sm transition-colors">
|
|
13
|
+
{item.text}
|
|
14
|
+
</a>
|
|
15
|
+
</li>
|
|
16
|
+
{/each}
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { t } from "../../../../../i18n";
|
|
3
|
+
import type { FooterProps } from "../../types";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
isNewsletter?: boolean;
|
|
7
|
+
newsletterTitle?: string;
|
|
8
|
+
newsletterDescription?: string;
|
|
9
|
+
onSubscribe?: (email: string) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
isNewsletter = false,
|
|
14
|
+
newsletterTitle,
|
|
15
|
+
newsletterDescription,
|
|
16
|
+
onSubscribe,
|
|
17
|
+
}: Props = $props();
|
|
18
|
+
|
|
19
|
+
let email = $state("");
|
|
20
|
+
|
|
21
|
+
function handleSubscribe(e: SubmitEvent) {
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
const value = email.trim();
|
|
24
|
+
if (!value) return;
|
|
25
|
+
onSubscribe?.(value);
|
|
26
|
+
email = "";
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
{#if isNewsletter}
|
|
31
|
+
<div>
|
|
32
|
+
<h3 class="mb-1 text-sm font-semibold">
|
|
33
|
+
{newsletterTitle ?? $t("footer.subscribe.title")}
|
|
34
|
+
</h3>
|
|
35
|
+
<p class="text-sm leading-relaxed">
|
|
36
|
+
{newsletterDescription ?? $t("footer.subscribe.text")}
|
|
37
|
+
</p>
|
|
38
|
+
<form
|
|
39
|
+
onsubmit={handleSubscribe}
|
|
40
|
+
class="flex flex-col items-stretch gap-2 sm:flex-row"
|
|
41
|
+
>
|
|
42
|
+
<input
|
|
43
|
+
type="email"
|
|
44
|
+
bind:value={email}
|
|
45
|
+
placeholder="Enter your email"
|
|
46
|
+
required
|
|
47
|
+
class="w-56 rounded-lg border border-gray px-3.5 py-2 text-sm placeholder:text-slate-500 outline-none"
|
|
48
|
+
/>
|
|
49
|
+
<button
|
|
50
|
+
type="submit"
|
|
51
|
+
class="shrink-0 rounded-lg px-4 py-2 text-sm font-medium text-white transition-colors bg-gradient"
|
|
52
|
+
>
|
|
53
|
+
{$t("footer.subscribe")}
|
|
54
|
+
</button>
|
|
55
|
+
</form>
|
|
56
|
+
</div>
|
|
57
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
isNewsletter?: boolean;
|
|
3
|
+
newsletterTitle?: string;
|
|
4
|
+
newsletterDescription?: string;
|
|
5
|
+
onSubscribe?: (email: string) => void;
|
|
6
|
+
};
|
|
7
|
+
declare const FooterNewsLetter: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type FooterNewsLetter = ReturnType<typeof FooterNewsLetter>;
|
|
9
|
+
export default FooterNewsLetter;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { FooterSocialItem } from "../../types";
|
|
3
|
+
|
|
4
|
+
let { icon, text, href }: FooterSocialItem = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<a
|
|
8
|
+
{href}
|
|
9
|
+
aria-label={text}
|
|
10
|
+
title={text}
|
|
11
|
+
target="_blank"
|
|
12
|
+
class="transition-color"
|
|
13
|
+
>
|
|
14
|
+
{#if icon === "facebook"}
|
|
15
|
+
<svg viewBox="0 0 24 24" fill="currentColor" class="h-4.5 w-4.5">
|
|
16
|
+
<path
|
|
17
|
+
d="M22 12.06C22 6.5 17.52 2 12 2S2 6.5 2 12.06c0 5 3.66 9.15 8.44 9.94v-7.03H7.9v-2.91h2.54V9.85c0-2.5 1.49-3.89 3.77-3.89 1.09 0 2.24.2 2.24.2v2.46h-1.26c-1.24 0-1.63.77-1.63 1.56v1.88h2.78l-.44 2.91h-2.34V22c4.78-.79 8.44-4.94 8.44-9.94Z"
|
|
18
|
+
/>
|
|
19
|
+
</svg>
|
|
20
|
+
{:else if icon === "instagram"}
|
|
21
|
+
<svg
|
|
22
|
+
viewBox="0 0 24 24"
|
|
23
|
+
fill="none"
|
|
24
|
+
stroke="currentColor"
|
|
25
|
+
stroke-width="1.8"
|
|
26
|
+
class="h-4.5 w-4.5"
|
|
27
|
+
>
|
|
28
|
+
<rect x="3" y="3" width="18" height="18" rx="5" />
|
|
29
|
+
<circle cx="12" cy="12" r="4" />
|
|
30
|
+
<circle cx="17.2" cy="6.8" r="1" fill="currentColor" stroke="none" />
|
|
31
|
+
</svg>
|
|
32
|
+
{:else if icon === "x"}
|
|
33
|
+
<svg viewBox="0 0 24 24" fill="currentColor" class="h-4 w-4">
|
|
34
|
+
<path
|
|
35
|
+
d="M18.9 2H22l-7.6 8.7L23.3 22h-7.3l-5.7-7.1L3.7 22H.6l8.1-9.3L.9 2h7.5l5.2 6.5L18.9 2Zm-1.3 18h1.8L6.5 3.9H4.6L17.6 20Z"
|
|
36
|
+
/>
|
|
37
|
+
</svg>
|
|
38
|
+
{:else if icon === "github"}
|
|
39
|
+
<svg viewBox="0 0 24 24" fill="currentColor" class="h-4.5 w-4.5">
|
|
40
|
+
<path
|
|
41
|
+
d="M12 2a10 10 0 0 0-3.16 19.49c.5.1.68-.22.68-.48v-1.7c-2.78.6-3.37-1.34-3.37-1.34-.46-1.15-1.11-1.46-1.11-1.46-.9-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.9 1.52 2.34 1.08 2.91.83.09-.66.35-1.08.63-1.33-2.22-.25-4.56-1.11-4.56-4.93 0-1.09.39-1.98 1.03-2.68-.1-.25-.45-1.27.1-2.65 0 0 .84-.27 2.75 1.02a9.6 9.6 0 0 1 5 0c1.9-1.3 2.74-1.02 2.74-1.02.56 1.38.2 2.4.1 2.65.65.7 1.03 1.59 1.03 2.68 0 3.83-2.34 4.68-4.57 4.92.36.31.68.92.68 1.85v2.74c0 .27.18.58.69.48A10 10 0 0 0 12 2Z"
|
|
42
|
+
/>
|
|
43
|
+
</svg>
|
|
44
|
+
{:else if icon === "youtube"}
|
|
45
|
+
<svg viewBox="0 0 24 24" fill="currentColor" class="h-4.5 w-4.5">
|
|
46
|
+
<path
|
|
47
|
+
d="M22.5 7.2a2.9 2.9 0 0 0-2-2.05C18.7 4.7 12 4.7 12 4.7s-6.7 0-8.5.45a2.9 2.9 0 0 0-2 2.05A30 30 0 0 0 1 12a30 30 0 0 0 .5 4.8 2.9 2.9 0 0 0 2 2.05c1.8.45 8.5.45 8.5.45s6.7 0 8.5-.45a2.9 2.9 0 0 0 2-2.05A30 30 0 0 0 23 12a30 30 0 0 0-.5-4.8ZM9.8 15.2V8.8L15.5 12l-5.7 3.2Z"
|
|
48
|
+
/>
|
|
49
|
+
</svg>
|
|
50
|
+
{:else if icon == "linkedin"}
|
|
51
|
+
<svg
|
|
52
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
53
|
+
viewBox="0 0 384 512"
|
|
54
|
+
fill="currentColor"
|
|
55
|
+
class="h-4.5 w-4.5"
|
|
56
|
+
>
|
|
57
|
+
<path
|
|
58
|
+
d="M204.1 0H180.1C161.9 0 147 14.1 147 32.3V177c0 4.7 0 9.3 1.6 13.7l3.8 11.1-12.2 12.6c-9.3 9.6-16.8 19.7-22.5 30.2-5.7 10.6-8.5 21.5-8.5 32.6V480c0 17.7 14.3 32 32 32h43.3c17.7 0 32-14.3 32-32V256c0-10.7-2.5-21.2-7.5-30.7-5-9.5-12.7-17.2-22.6-22.6l-12.6-6.5 4-11.5c2.5-7.5 4-15.4 4-23.5V32.3c0-17.7-14.1-32.3-32-32.3zM432 0H408c-17.7 0-32 14.3-32 32V256c0 17.7 14.3 32 32 32h44c17.7 0 32-14.3 32-32V32c0-17.7-14.3-32-32-32zm0 192H408v320h44c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM147 323c0-8.4 2.2-16.6 6.4-23.8l13.3-21.7 12.7-6.6c5.5-2.8 11-6.3 16.3-10.4 5.2-4.1 9.6-9 13-14.6 3.4-5.7 5-11.7 5.4-17.9V32.3c0-8.4-2.2-16.6-6.4-23.8l-13.3-21.7-12.7-6.6c-5.5-2.8-11-6.3-16.3-10.4-5.2-4.1-9.6-9-13-14.6-3.4-5.7-5-11.7-5.4-17.9V0c17.7 0 32 14.3 32 32v90.3c0 8.4 2.2 16.6 6.4 23.8l13.3 21.7 12.7 6.6c5.5 2.8 11 6.3 16.3 10.4 5.2 4.1 9.6 9 13 14.6 3.4 5.7 5 11.7 5.4 17.9v90.3c0 17.7-14.3 32-32 32h-44c-17.7 0-32-14.3-32-32v-90.4z"
|
|
59
|
+
/>
|
|
60
|
+
</svg>
|
|
61
|
+
{/if}
|
|
62
|
+
</a>
|
|
@@ -1,27 +1,16 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import * as Carousel from "../../ui/carousel/index.js";
|
|
3
|
-
import type {
|
|
4
|
-
import type { CarouselPlugins } from "../../ui/carousel/context.js";
|
|
5
|
-
|
|
6
|
-
type Props = {
|
|
7
|
-
positionButtonPreviousAndNext?: "center" | "top_right";
|
|
8
|
-
buttonPreviousAndNextClass?: string;
|
|
9
|
-
isButtonPreviousAndNext?: boolean;
|
|
10
|
-
isBorderBottom?: boolean;
|
|
11
|
-
containerClass?: string;
|
|
12
|
-
plugins?: CarouselPlugins;
|
|
13
|
-
children: Snippet;
|
|
14
|
-
};
|
|
3
|
+
import type { CarouselSlotProps } from "./type";
|
|
15
4
|
|
|
16
5
|
const {
|
|
17
6
|
positionButtonPreviousAndNext = "center",
|
|
18
7
|
isButtonPreviousAndNext = true,
|
|
19
8
|
buttonPreviousAndNextClass = "",
|
|
20
|
-
isBorderBottom =
|
|
21
|
-
containerClass = "",
|
|
9
|
+
isBorderBottom = false,
|
|
10
|
+
containerClass = "w-full",
|
|
22
11
|
plugins = [],
|
|
23
12
|
children,
|
|
24
|
-
}:
|
|
13
|
+
}: CarouselSlotProps = $props();
|
|
25
14
|
|
|
26
15
|
const styleTopCenter = "bg-blue-700! text-white! cursor-pointer!";
|
|
27
16
|
const styleCenter =
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
type Props = {
|
|
4
|
-
positionButtonPreviousAndNext?: "center" | "top_right";
|
|
5
|
-
buttonPreviousAndNextClass?: string;
|
|
6
|
-
isButtonPreviousAndNext?: boolean;
|
|
7
|
-
isBorderBottom?: boolean;
|
|
8
|
-
containerClass?: string;
|
|
9
|
-
plugins?: CarouselPlugins;
|
|
10
|
-
children: Snippet;
|
|
11
|
-
};
|
|
12
|
-
declare const CarouselSlot: import("svelte").Component<Props, {}, "">;
|
|
1
|
+
import type { CarouselSlotProps } from "./type";
|
|
2
|
+
declare const CarouselSlot: import("svelte").Component<CarouselSlotProps, {}, "">;
|
|
13
3
|
type CarouselSlot = ReturnType<typeof CarouselSlot>;
|
|
14
4
|
export default CarouselSlot;
|