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.
Files changed (79) hide show
  1. package/dist/assets/lonely-404.mp4 +0 -0
  2. package/dist/components/core/banner/AdCardBanner.svelte +74 -0
  3. package/dist/components/core/banner/AdCardBanner.svelte.d.ts +4 -0
  4. package/dist/components/core/banner/CtaCardBanner.svelte +118 -0
  5. package/dist/components/core/banner/CtaCardBanner.svelte.d.ts +4 -0
  6. package/dist/components/core/banner/NotificationBanner.svelte +95 -0
  7. package/dist/components/core/banner/NotificationBanner.svelte.d.ts +4 -0
  8. package/dist/components/core/banner/types.d.ts +63 -0
  9. package/dist/components/core/banner/types.js +1 -0
  10. package/dist/components/core/card/highlight/01/CardHighlight01.svelte +20 -27
  11. package/dist/components/core/card/highlight/02/CardHighlight02.svelte +18 -27
  12. package/dist/components/core/card/highlight/data.js +1 -4
  13. package/dist/components/core/card/media/01/CardMedia01.svelte +114 -98
  14. package/dist/components/core/card/media/02/CardMedia02.svelte +115 -99
  15. package/dist/components/core/card/media/CardMedia.svelte +10 -9
  16. package/dist/components/core/card/media/CardMedia.svelte.d.ts +1 -0
  17. package/dist/components/core/card/profile/01/CardProfile01.svelte +104 -86
  18. package/dist/components/core/card/profile/02/CardProfile02.svelte +103 -87
  19. package/dist/components/core/card/profile/CardProfile.svelte +8 -7
  20. package/dist/components/core/card/profile/CardProfile.svelte.d.ts +1 -0
  21. package/dist/components/core/card/promotion/CardPromotion.svelte +10 -4
  22. package/dist/components/core/card/shared/CardButton.svelte +38 -23
  23. package/dist/components/core/card/shared/CardButton.svelte.d.ts +2 -1
  24. package/dist/components/core/card/shared/CardDescription.svelte +30 -30
  25. package/dist/components/core/card/shared/CardLogo.svelte +19 -0
  26. package/dist/components/core/card/shared/CardLogo.svelte.d.ts +7 -0
  27. package/dist/components/core/card/shared/CardStarRating.svelte +18 -14
  28. package/dist/components/core/card/shared/CardStarRating.svelte.d.ts +1 -0
  29. package/dist/components/core/card/shared/CardStartPrice.svelte +1 -1
  30. package/dist/components/core/card/shared/CardThumbnailVideo.svelte +210 -148
  31. package/dist/components/core/card/shared/CardThumbnailVideo.svelte.d.ts +1 -0
  32. package/dist/components/core/card/types.d.ts +5 -0
  33. package/dist/components/core/carousel/grid/media/types.d.ts +11 -0
  34. package/dist/components/core/carousel/grid/media/types.js +1 -0
  35. package/dist/components/core/carousel/grid/media/ui/CarouselGridMedia.svelte +49 -0
  36. package/dist/components/core/carousel/grid/media/ui/CarouselGridMedia.svelte.d.ts +4 -0
  37. package/dist/components/core/carousel/grid/profile/types.d.ts +11 -0
  38. package/dist/components/core/carousel/grid/profile/types.js +1 -0
  39. package/dist/components/core/carousel/grid/profile/ui/CarouselGridProfile.svelte +49 -0
  40. package/dist/components/core/carousel/grid/profile/ui/CarouselGridProfile.svelte.d.ts +4 -0
  41. package/dist/components/core/carousel/grid/shared/ui/CarouselGridSlot.svelte +33 -0
  42. package/dist/components/core/carousel/grid/shared/ui/CarouselGridSlot.svelte.d.ts +11 -0
  43. package/dist/components/core/carousel/hero/CarouselHero.svelte +21 -19
  44. package/dist/components/core/carousel/hero/CarouselHero.svelte.d.ts +1 -0
  45. package/dist/components/core/carousel/highlights/types.d.ts +4 -4
  46. package/dist/components/core/carousel/highlights/ui/CarouselHighlights.svelte +4 -22
  47. package/dist/components/core/carousel/promotion/types.d.ts +5 -5
  48. package/dist/components/core/carousel/promotion/ui/CarouselPromotion.svelte +4 -21
  49. package/dist/components/core/carousel/shared/ui/CarouselHeader.svelte +6 -1
  50. package/dist/components/core/carousel/types.d.ts +1 -0
  51. package/dist/components/core/footer/types.d.ts +23 -0
  52. package/dist/components/core/footer/types.js +1 -0
  53. package/dist/components/core/footer/ui/01/Footer01.svelte +76 -0
  54. package/dist/components/core/footer/ui/01/Footer01.svelte.d.ts +4 -0
  55. package/dist/components/core/footer/ui/02/Footer02.svelte +53 -0
  56. package/dist/components/core/footer/ui/02/Footer02.svelte.d.ts +4 -0
  57. package/dist/components/core/footer/ui/Footer.svelte +18 -0
  58. package/dist/components/core/footer/ui/Footer.svelte.d.ts +7 -0
  59. package/dist/components/core/footer/ui/shared/FooterColumn.svelte +18 -0
  60. package/dist/components/core/footer/ui/shared/FooterColumn.svelte.d.ts +4 -0
  61. package/dist/components/core/footer/ui/shared/FooterNewsLetter.svelte +57 -0
  62. package/dist/components/core/footer/ui/shared/FooterNewsLetter.svelte.d.ts +9 -0
  63. package/dist/components/core/footer/ui/shared/FooterSocialIcon.svelte +62 -0
  64. package/dist/components/core/footer/ui/shared/FooterSocialIcon.svelte.d.ts +4 -0
  65. package/dist/components/core/panel/CarouselSlot.svelte +4 -15
  66. package/dist/components/core/panel/CarouselSlot.svelte.d.ts +2 -12
  67. package/dist/components/core/panel/LeftHero.svelte +2 -2
  68. package/dist/components/core/panel/type.d.ts +11 -0
  69. package/dist/components/core/panel/type.js +1 -0
  70. package/dist/globals.css +463 -47
  71. package/dist/i18n/langs/en.d.ts +4 -0
  72. package/dist/i18n/langs/en.js +4 -0
  73. package/dist/i18n/langs/pt.d.ts +4 -0
  74. package/dist/i18n/langs/pt.js +10 -6
  75. package/dist/i18n/translations.d.ts +8 -0
  76. package/dist/index.d.ts +17 -5
  77. package/dist/index.js +17 -5
  78. package/dist/styles/globals.css +1 -1
  79. 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; // evita trocas sobrepostas se o intervalo disparar antes do preload acabar
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(); // não bloqueia o carousel por uma imagem partida
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); // garante decode/cache antes de trocar a camada -> sem flash
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 items && items.length > 1}
143
- <div
144
- style="position: absolute; bottom: 0.75rem; z-index: 10; display: flex; gap: 0.5rem;"
145
- >
146
- {#each items as item, i (`hero-dot-${i}`)}
147
- <button
148
- aria-label={`Ir para o slide ${i + 1}: ${item.title}`}
149
- class="w-2 h-2 rounded-full transition-colors {i === index
150
- ? 'bg-white'
151
- : 'bg-white/40'}"
152
- onclick={() => goTo(i)}
153
- ></button>
154
- {/each}
155
- </div>
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 extends CarouselHeaderProps {
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
- title,
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
- isBorderBottom={false}
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 extends CarouselHeaderProps {
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
- title,
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
- isBorderBottom={false}
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 class="w-[95%] p-2 rounded-xl border {containerClass}">
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>
@@ -17,6 +17,7 @@ export interface CarouselHeaderProps {
17
17
  containerClass?: string;
18
18
  onButtonViewAll?: () => void;
19
19
  positionButtonPreviousAndNext?: "center" | "top_right";
20
+ isBorder?: boolean;
20
21
  }
21
22
  export interface CarouselBadgeProps {
22
23
  items: ItemCarousel[];
@@ -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,4 @@
1
+ import type { FooterProps } from "../../types";
2
+ declare const Footer01: import("svelte").Component<FooterProps, {}, "">;
3
+ type Footer01 = ReturnType<typeof Footer01>;
4
+ export default Footer01;
@@ -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,4 @@
1
+ import type { FooterProps } from "../../types";
2
+ declare const Footer02: import("svelte").Component<FooterProps, {}, "">;
3
+ type Footer02 = ReturnType<typeof Footer02>;
4
+ export default Footer02;
@@ -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,7 @@
1
+ import type { FooterProps } from "../types";
2
+ type $$ComponentProps = FooterProps & {
3
+ variant?: 1 | 2;
4
+ };
5
+ declare const Footer: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type Footer = ReturnType<typeof Footer>;
7
+ export default Footer;
@@ -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,4 @@
1
+ import type { FooterColumnProps } from "../../types";
2
+ declare const FooterColumn: import("svelte").Component<FooterColumnProps, {}, "">;
3
+ type FooterColumn = ReturnType<typeof FooterColumn>;
4
+ export default FooterColumn;
@@ -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>
@@ -0,0 +1,4 @@
1
+ import type { FooterSocialItem } from "../../types";
2
+ declare const FooterSocialIcon: import("svelte").Component<FooterSocialItem, {}, "">;
3
+ type FooterSocialIcon = ReturnType<typeof FooterSocialIcon>;
4
+ export default FooterSocialIcon;
@@ -1,27 +1,16 @@
1
1
  <script lang="ts">
2
2
  import * as Carousel from "../../ui/carousel/index.js";
3
- import type { Snippet } from "svelte";
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 = true,
21
- containerClass = "",
9
+ isBorderBottom = false,
10
+ containerClass = "w-full",
22
11
  plugins = [],
23
12
  children,
24
- }: Props = $props();
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 { Snippet } from "svelte";
2
- import type { CarouselPlugins } from "../../ui/carousel/context.js";
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;