negodesign 0.0.31 → 0.0.33

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.
@@ -1,17 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { ModeWatcher } from "mode-watcher";
3
3
  import { setUserTranslations } from "../i18n/config";
4
+ import type { NegoDesignProps } from "../types";
4
5
 
5
- type Translations = Record<string, Record<string, string>>;
6
-
7
- let {
8
- translations,
9
- children,
10
- }: {
11
- /** Custom translations per language. Merged with the library's base translations. */
12
- translations?: Translations;
13
- children: any;
14
- } = $props();
6
+ let { translations, children }: NegoDesignProps = $props();
15
7
 
16
8
  $effect(() => {
17
9
  if (translations) {
@@ -1,9 +1,4 @@
1
- type Translations = Record<string, Record<string, string>>;
2
- type $$ComponentProps = {
3
- /** Custom translations per language. Merged with the library's base translations. */
4
- translations?: Translations;
5
- children: any;
6
- };
7
- declare const NegoDesign: import("svelte").Component<$$ComponentProps, {}, "">;
1
+ import type { NegoDesignProps } from "../types";
2
+ declare const NegoDesign: import("svelte").Component<NegoDesignProps, {}, "">;
8
3
  type NegoDesign = ReturnType<typeof NegoDesign>;
9
4
  export default NegoDesign;
@@ -3,7 +3,7 @@
3
3
  * Card component with a title and content.
4
4
  * @component
5
5
  */
6
- import { InformationCircleIcon, UserIcon } from "@hugeicons/core-free-icons";
6
+ import { UserIcon } from "@hugeicons/core-free-icons";
7
7
  import { t } from "../../../../../i18n";
8
8
  import type { CardProfileProps } from "../../types";
9
9
  import CardStarRating from "../../shared/CardStarRating.svelte";
@@ -12,6 +12,8 @@
12
12
  import CardButton from "../../shared/CardButton.svelte";
13
13
  import CardFavorite from "../../shared/CardFavorite.svelte";
14
14
  import Skeleton from "../../../../ui/skeleton/skeleton.svelte";
15
+ import CardPhoneOrWhatsapp from "../../shared/CardPhoneOrWhatsapp.svelte";
16
+ import CardThumbnailVideo from "../../shared/CardThumbnailVideo.svelte";
15
17
 
16
18
  let {
17
19
  id,
@@ -24,93 +26,116 @@
24
26
  isTagBorderBottom = true,
25
27
  isFavorite = false,
26
28
  buttonProfileClass,
27
- buttonDetailsClass,
28
29
  isLoading = false,
30
+ imageUrl,
31
+ videoUrl,
32
+ isImageButtonMaximized = false,
33
+ isVideoButtonMaximized = false,
34
+ isDescriptionIcon = false,
35
+ isDescriptionLabel = false,
36
+ onEmailClick,
37
+ onWhatsappClick,
29
38
  onFavoriteClick,
30
39
  onButtonProfile,
31
- onButtonDetails,
32
40
  }: CardProfileProps = $props();
33
-
34
- let isShowButtonProfileAndDetails = $derived(
35
- onButtonProfile != null && onButtonDetails != null,
36
- );
37
41
  </script>
38
42
 
39
43
  <article
40
- class="border border-gray-300 dark:border-gray-700 bg-gray-100 dark:bg-transparent rounded-lg p-5 space-y-1 md:space-y-3"
44
+ class="border border-gray-300 dark:border-gray-700 bg-gray-100 dark:bg-transparent rounded-lg relative"
41
45
  >
42
- <div class="flex justify-between items-center w-full mb-4">
43
- <div class="flex justify-start gap-2">
44
- <div class="flex justify-center items-center">
45
- {#if isLoading}
46
- <Skeleton class="w-12 h-12 rounded-lg bg-gray-300" />
47
- {:else if logo}
48
- <img src={logo} alt={logo} class="w-12 h-12 rounded-lg" />
49
- {/if}
46
+ <div class="p-5">
47
+ <div class="flex justify-between items-center w-full">
48
+ <div class="w-full flex flex-col justify-center items-center relative">
49
+ <div>
50
+ {#if isLoading}
51
+ <Skeleton
52
+ class="w-12 h-12 md:w-14 md:h-14 lg:w-20 lg:h-20 rounded-full bg-gray-300"
53
+ />
54
+ {:else if imageUrl}
55
+ <img
56
+ src={imageUrl}
57
+ alt={imageUrl}
58
+ class="w-12 h-12 md:w-14 md:h-14 lg:w-20 lg:h-20 rounded-full"
59
+ />
60
+ {/if}
61
+ </div>
62
+ <div>
63
+ {#if title}
64
+ <div class="text-center font-bold">{title}</div>
65
+ {:else if isLoading}
66
+ <Skeleton class="w-40 h-5 rounded-lg bg-gray-400 mb-0.5" />
67
+ {/if}
68
+ </div>
69
+ <div>
70
+ {#if startNumber}
71
+ <CardStarRating {startNumber} {startMax} {isLoading} />
72
+ {:else if isLoading}
73
+ <Skeleton class="w-20 h-4 rounded-lg bg-gray-300 mt-0.5" />
74
+ {/if}
75
+ </div>
50
76
  </div>
51
- <div class="flex-col">
52
- {#if title}
53
- <div class="text-center font-bold text-lg">{title}</div>
54
- {:else if isLoading}
55
- <Skeleton class="w-40 h-5 rounded-lg bg-gray-400 mb-0.5" />
56
- {/if}
57
77
 
58
- {#if startNumber}
59
- <CardStarRating {startNumber} {startMax} {isLoading} />
60
- {:else if isLoading}
61
- <Skeleton class="w-20 h-4 rounded-lg bg-gray-300 mt-0.5" />
62
- {/if}
78
+ <div class="flex justify-end items-center absolute top-1 right-1">
79
+ <CardFavorite
80
+ {id}
81
+ {isFavorite}
82
+ onFavoriteClick={() => onFavoriteClick!(id)}
83
+ {isLoading}
84
+ />
63
85
  </div>
64
86
  </div>
65
- <div class="flex justify-end items-center">
66
- <CardFavorite
67
- {id}
68
- {isFavorite}
69
- onFavoriteClick={() => onFavoriteClick!(id)}
87
+
88
+ <div class="my-2">
89
+ <CardDescription
90
+ {content}
70
91
  {isLoading}
92
+ {isDescriptionIcon}
93
+ {isDescriptionLabel}
71
94
  />
72
95
  </div>
73
- </div>
74
96
 
75
- <div class="h-15 my-2">
76
- <CardDescription {content} {isLoading} />
77
- </div>
97
+ {#if tags}
98
+ <CardTags
99
+ className="my-4"
100
+ tags={tags ?? []}
101
+ {isTagBorderBottom}
102
+ {isLoading}
103
+ />
104
+ {:else}
105
+ <CardTags
106
+ className="my-4"
107
+ tags={[{ text: "- - -" }]}
108
+ {isTagBorderBottom}
109
+ {isLoading}
110
+ />
111
+ {/if}
78
112
 
79
- <CardTags
80
- className="my-6"
81
- tags={tags ?? []}
82
- {isTagBorderBottom}
83
- {isLoading}
84
- />
113
+ <CardThumbnailVideo
114
+ {imageUrl}
115
+ {videoUrl}
116
+ {isImageButtonMaximized}
117
+ {isVideoButtonMaximized}
118
+ {isLoading}
119
+ class="md:h-32.5 lg:h-44"
120
+ />
85
121
 
86
- {#if onButtonProfile || onButtonDetails}
87
- <div class="flex justify-center items-center gap-2 mt-4 w-full">
88
- {#if onButtonProfile}
89
- <CardButton
90
- {id}
91
- icon={UserIcon}
92
- className={buttonProfileClass}
93
- text={$t("label.view.profile")}
94
- onClick={onButtonProfile}
95
- isFlex={isShowButtonProfileAndDetails}
96
- {isLoading}
97
- />
98
- {:else if isLoading}
99
- <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
100
- {/if}
101
- {#if onButtonDetails}
102
- <CardButton
103
- {id}
104
- icon={InformationCircleIcon}
105
- className={buttonDetailsClass}
106
- text={$t("label.more.details")}
107
- onClick={onButtonDetails}
108
- isFlex={isShowButtonProfileAndDetails}
109
- {isLoading}
110
- />
111
- {:else if isLoading}
112
- <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
113
- {/if}
114
- </div>
115
- {/if}
122
+ {#if onButtonProfile}
123
+ <div class="flex justify-center items-center gap-2 w-full mt-3 -mb-1">
124
+ {#if onButtonProfile}
125
+ <CardButton
126
+ {id}
127
+ icon={UserIcon}
128
+ className={buttonProfileClass}
129
+ text={$t("label.view.profile")}
130
+ onClick={onButtonProfile}
131
+ {isLoading}
132
+ isFlex
133
+ />
134
+ {:else if isLoading}
135
+ <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
136
+ {/if}
137
+ </div>
138
+ {/if}
139
+ </div>
140
+ <CardPhoneOrWhatsapp {id} {onEmailClick} {onWhatsappClick} />
116
141
  </article>
@@ -12,6 +12,8 @@
12
12
  import CardButton from "../../shared/CardButton.svelte";
13
13
  import CardFavorite from "../../shared/CardFavorite.svelte";
14
14
  import Skeleton from "../../../../ui/skeleton/skeleton.svelte";
15
+ import CardThumbnailVideo from "../../shared/CardThumbnailVideo.svelte";
16
+ import CardPhoneOrWhatsapp from "../../shared/CardPhoneOrWhatsapp.svelte";
15
17
  let {
16
18
  id,
17
19
  tags,
@@ -24,45 +26,50 @@
24
26
  isTagBorderBottom = true,
25
27
  isFavorite = false,
26
28
  buttonProfileClass,
27
- buttonDetailsClass,
29
+ onEmailClick,
30
+ onWhatsappClick,
28
31
  isLoading = false,
29
32
  onFavoriteClick,
30
33
  onButtonProfile,
31
- onButtonDetails,
34
+ imageUrl,
35
+ videoUrl,
36
+ isImageButtonMaximized = false,
37
+ isVideoButtonMaximized = false,
38
+ isDescriptionLabel = false,
39
+ isDescriptionIcon = false,
32
40
  }: CardProfileProps = $props();
33
-
34
- let isShowButtonProfileAndDetails = $derived(
35
- onButtonProfile != null && onButtonDetails != null,
36
- );
37
41
  </script>
38
42
 
39
43
  <article
40
- class="border border-gray-300 dark:border-gray-700 bg-gray-100 dark:bg-transparent rounded-lg p-5 space-y-1 md:space-y-3 {className}"
44
+ class="border border-gray-300 dark:border-gray-700 bg-gray-100 dark:bg-transparent rounded-lg space-y-1 md:space-y-3 relative {className}"
41
45
  >
42
- <div class="flex flex-col justify-center items-center w-full relative">
43
- <div class="flex flex-col justify-start gap-2">
44
- <div class="flex justify-center items-center">
45
- {#if isLoading}
46
- <Skeleton class="w-12 h-12 rounded-lg bg-gray-400 mt-0.5" />
47
- {:else if logo}
48
- <img src={logo} alt={logo} class="w-12 h-12 rounded-lg" />
49
- {/if}
50
- </div>
51
- <div class="flex flex-col justify-center items-center">
52
- {#if title}
53
- <div class="text-center font-bold text-lg">{title}</div>
54
- {:else if isLoading}
55
- <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
56
- {/if}
46
+ <div class="p-5">
47
+ <div class="flex justify-start items-center w-full relative">
48
+ <div class="flex justify-start gap-2">
49
+ <div class="flex justify-center items-center">
50
+ {#if isLoading}
51
+ <Skeleton class="w-12 h-12 rounded-lg bg-gray-400 mt-0.5" />
52
+ {:else if logo}
53
+ <img src={logo} alt={logo} class="w-12 h-12 rounded-lg" />
54
+ {/if}
55
+ </div>
56
+ <div class="flex flex-col justify-start items-start">
57
+ {#if title}
58
+ <div class="text-left font-bold">{title}</div>
59
+ {:else if isLoading}
60
+ <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
61
+ {/if}
57
62
 
58
- {#if startNumber}
59
- <CardStarRating {startNumber} {startMax} {isLoading} />
60
- {:else if isLoading}
61
- <Skeleton class="w-20 h-4 rounded-lg bg-gray-300 mt-0.5" />
62
- {/if}
63
+ {#if startNumber}
64
+ <CardStarRating {startNumber} {startMax} {isLoading} />
65
+ {:else if isLoading}
66
+ <Skeleton class="w-20 h-4 rounded-lg bg-gray-300 mt-0.5" />
67
+ {/if}
68
+ </div>
63
69
  </div>
64
70
  </div>
65
- <div class="flex justify-end items-center absolute top-0 right-0">
71
+
72
+ <div class="flex justify-end items-center absolute top-1 right-1">
66
73
  <CardFavorite
67
74
  {id}
68
75
  {isFavorite}
@@ -70,45 +77,57 @@
70
77
  {isLoading}
71
78
  />
72
79
  </div>
73
- </div>
74
80
 
75
- <div class="h-15 mb-8">
76
- <CardDescription {content} {isLoading} />
77
- </div>
81
+ <div class="mb-4">
82
+ <CardDescription
83
+ {content}
84
+ {isLoading}
85
+ {isDescriptionLabel}
86
+ {isDescriptionIcon}
87
+ />
88
+ </div>
78
89
 
79
- <CardTags
80
- className="my-4"
81
- tags={tags ?? []}
82
- {isTagBorderBottom}
83
- {isLoading}
84
- />
90
+ {#if tags && tags.length > 0}
91
+ <CardTags
92
+ className="my-4"
93
+ tags={tags ?? []}
94
+ {isTagBorderBottom}
95
+ {isLoading}
96
+ />
97
+ {:else}
98
+ <CardTags
99
+ className="my-4"
100
+ tags={[{ text: "- - -" }]}
101
+ {isTagBorderBottom}
102
+ {isLoading}
103
+ />
104
+ {/if}
85
105
 
86
- {#if onButtonProfile || onButtonDetails}
87
- <div class="flex justify-center items-center gap-2 mt-4 w-full">
88
- {#if onButtonProfile}
89
- <CardButton
90
- {id}
91
- icon={UserIcon}
92
- className={buttonProfileClass}
93
- text={$t("label.view.profile")}
94
- onClick={onButtonProfile}
95
- isFlex={isShowButtonProfileAndDetails}
96
- />
97
- {:else if isLoading}
98
- <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
99
- {/if}
100
- {#if onButtonDetails}
101
- <CardButton
102
- {id}
103
- icon={InformationCircleIcon}
104
- className={buttonDetailsClass}
105
- text={$t("label.more.details")}
106
- onClick={onButtonDetails}
107
- isFlex={isShowButtonProfileAndDetails}
108
- />
109
- {:else if isLoading}
110
- <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
111
- {/if}
112
- </div>
113
- {/if}
106
+ <CardThumbnailVideo
107
+ {imageUrl}
108
+ {videoUrl}
109
+ {isImageButtonMaximized}
110
+ {isVideoButtonMaximized}
111
+ {isLoading}
112
+ class="md:h-32.5 lg:h-44"
113
+ />
114
+
115
+ {#if onButtonProfile}
116
+ <div class="flex justify-center items-center gap-2 mt-2 -mb-2 w-full">
117
+ {#if onButtonProfile}
118
+ <CardButton
119
+ {id}
120
+ icon={UserIcon}
121
+ className={buttonProfileClass}
122
+ text={$t("label.view.profile")}
123
+ onClick={onButtonProfile}
124
+ isFlex
125
+ />
126
+ {:else if isLoading}
127
+ <Skeleton class="w-20 h-4 rounded-lg bg-gray-400 mt-0.5" />
128
+ {/if}
129
+ </div>
130
+ {/if}
131
+ </div>
132
+ <CardPhoneOrWhatsapp {id} {onEmailClick} {onWhatsappClick} />
114
133
  </article>
@@ -8,6 +8,8 @@ const items = [
8
8
  startNumber: 5,
9
9
  startMax: 5,
10
10
  isFavorite: true,
11
+ imageUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
12
+ videoUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
11
13
  tags: [
12
14
  {
13
15
  icon: GlobalIcon,
@@ -30,6 +32,8 @@ const items = [
30
32
  content: 'Suítes modernas no coração da cidade, com spa completo e serviço de quarto 24 horas.',
31
33
  startNumber: 4,
32
34
  startMax: 5,
35
+ imageUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
36
+ videoUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
33
37
  tags: [
34
38
  {
35
39
  icon: GlobalIcon,
@@ -57,6 +61,8 @@ const items = [
57
61
  startNumber: 5,
58
62
  startMax: 5,
59
63
  isFavorite: true,
64
+ imageUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
65
+ videoUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
60
66
  tags: [
61
67
  {
62
68
  icon: GlobalIcon,
@@ -75,6 +81,8 @@ const items = [
75
81
  content: 'Localização privilegiada no centro urbano, ideal para viagens de negócios, com centro de conferências.',
76
82
  startNumber: 3,
77
83
  startMax: 5,
84
+ imageUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
85
+ videoUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
78
86
  tags: [
79
87
  {
80
88
  icon: NecklaceIcon,
@@ -102,6 +110,8 @@ const items = [
102
110
  startNumber: 4,
103
111
  startMax: 5,
104
112
  isFavorite: true,
113
+ imageUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
114
+ videoUrl: 'https://api.dicebear.com/9.x/initials/svg?seed=Hotel%20Baía%20Azul&backgroundColor=1a2420&textColor=e3b563',
105
115
  },
106
116
  ];
107
117
  export default items;
@@ -15,7 +15,7 @@
15
15
  let {
16
16
  content,
17
17
  isLoading = false,
18
- isDescriptionIcon = true,
18
+ isDescriptionIcon = false,
19
19
  isDescriptionLabel = true,
20
20
  }: CardDescriptionProps = $props();
21
21
  </script>
@@ -27,12 +27,12 @@
27
27
  <div class="mb-1 text-[14px] md:text-[15px] flex items-center gap-1">
28
28
  {#if isDescriptionIcon}
29
29
  <HugeiconsIcon icon={Message01Icon} class="h-4 w-4" />
30
- {/if}11
30
+ {/if}
31
31
  <div>{$t("label.description")}</div>
32
32
  </div>
33
33
  {/if}
34
34
  <TruncatableText
35
35
  text={content}
36
- class="text-justify text-[13px] md:text-[14px] text-gray-800 dark:text-gray-50 mt-3 my-4"
36
+ class="text-justify text-[13px] md:text-[14px] text-gray-800 dark:text-gray-50 mt-3 my-2"
37
37
  />
38
38
  {/if}
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { Mail01Icon, WhatsappIcon } from "@hugeicons/core-free-icons";
3
+ import { HugeiconsIcon } from "@hugeicons/svelte";
4
+ import type { CardPhoneOrWhatsappProps } from "../types";
5
+
6
+ let { id, onEmailClick, onWhatsappClick }: CardPhoneOrWhatsappProps =
7
+ $props();
8
+
9
+ let isFlex = $derived(onEmailClick && onWhatsappClick);
10
+ </script>
11
+
12
+ <div class="flex border-t border-gray-300 dark:border-gray-700">
13
+ {#if onEmailClick}
14
+ <button
15
+ class="flex-1 flex justify-center items-center gap-2 p-3 hover:bg-red-800 hover:text-white cursor-pointer rounded-bl-lg"
16
+ onclick={() => onEmailClick?.(id)}
17
+ >
18
+ <HugeiconsIcon icon={Mail01Icon} size={20} />
19
+ <span>Email</span>
20
+ </button>
21
+ {/if}
22
+ {#if isFlex}
23
+ <div class="border-l border-gray-300 dark:border-gray-700"></div>
24
+ {/if}
25
+ {#if onWhatsappClick}
26
+ <button
27
+ class="flex-1 flex justify-center items-center gap-2 p-3 hover:bg-green-600 hover:text-white cursor-pointer rounded-br-lg"
28
+ onclick={() => onWhatsappClick?.(id)}
29
+ >
30
+ <HugeiconsIcon icon={WhatsappIcon} size={20} />
31
+ <span>Whatsapp</span>
32
+ </button>
33
+ {/if}
34
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { CardPhoneOrWhatsappProps } from "../types";
2
+ declare const CardPhoneOrWhatsapp: import("svelte").Component<CardPhoneOrWhatsappProps, {}, "">;
3
+ type CardPhoneOrWhatsapp = ReturnType<typeof CardPhoneOrWhatsapp>;
4
+ export default CardPhoneOrWhatsapp;
@@ -19,7 +19,7 @@
19
19
  />
20
20
  {/if}
21
21
  {#if newPrice && oldPrice}
22
- <div class="z-20 flex justify-center items-center">
22
+ <div class="z-20 flex justify-start items-center">
23
23
  <div class="font-extrabold text-lg">{newPrice}</div>
24
24
  <div class="mx-2">/</div>
25
25
  <div class="font-semibold line-through text-red-600 text-[10px]">
@@ -86,14 +86,24 @@ export interface CardProfileProps {
86
86
  isTagBorderBottom?: boolean;
87
87
  /** Classe CSS personalizada para botão de perfil */
88
88
  buttonProfileClass?: string;
89
- /** Classe CSS personalizada para botão de detalhes */
90
- buttonDetailsClass?: string;
91
89
  /** Callback ao clicar no botão favorito */
92
90
  onFavoriteClick?: (id: string | number) => void;
93
91
  /** Callback ao clicar no botão perfil */
94
92
  onButtonProfile?: (id: string | number) => void;
95
- /** Callback ao clicar no botão detalhes */
96
- onButtonDetails?: (id: string | number) => void;
93
+ /** Callback ao clicar no botão email */
94
+ onEmailClick?: (id: string | number) => void;
95
+ /** Callback ao clicar no botão whatsapp */
96
+ onWhatsappClick?: (id: string | number) => void;
97
+ /** URL da foto/imagem do perfil */
98
+ imageUrl?: string;
99
+ /** URL do vídeo do perfil */
100
+ videoUrl?: string;
101
+ /** Indica se o botão de maximizar imagem está ativo */
102
+ isImageButtonMaximized?: boolean;
103
+ /** Indica se o botão de maximizar vídeo está ativo */
104
+ isVideoButtonMaximized?: boolean;
105
+ isDescriptionIcon?: boolean;
106
+ isDescriptionLabel?: boolean;
97
107
  }
98
108
  /**
99
109
  * Props do CardPromotion — card de promoção com preço antigo/novo,
@@ -177,3 +187,8 @@ export interface CardHighlightProps {
177
187
  /** Callback ao clicar no botão principal */
178
188
  onClickBtn?: (id: string | number) => void;
179
189
  }
190
+ export interface CardPhoneOrWhatsappProps {
191
+ id: string | number;
192
+ onEmailClick?: (id: string | number) => void;
193
+ onWhatsappClick?: (id: string | number) => void;
194
+ }
@@ -5,7 +5,7 @@ import type { CarouselHeaderProps } from "../../types";
5
5
  * Props do CarouselGridMedia — layout em grid de cards de mídia
6
6
  * (imagens/vídeos). Em telas mobile o grid vira carousel com swipe.
7
7
  */
8
- export interface CarouselMediaProps {
8
+ export interface CarouselGridMediaProps {
9
9
  /** Props do cabeçalho do carousel (título, descrição, etc.) */
10
10
  headerProps?: CarouselHeaderProps;
11
11
  /** Props do slot/container do carousel (botões navegação, plugins) */
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
2
  import CarouselGridSlot from "../../shared/ui/CarouselGridSlot.svelte";
3
3
  import * as Carousel from "../../../../../ui/carousel/index.js";
4
- import type { CarouselMediaProps } from "../types";
5
4
  import CarouselHeader from "../../../shared/ui/CarouselHeader.svelte";
6
5
  import { useDevice } from "../../../../../../hooks/responsive.svelte";
7
6
  import CardMedia from "../../../../card/media/CardMedia.svelte";
7
+ import type { CarouselGridMediaProps } from "../../../../../../types";
8
8
 
9
9
  const {
10
10
  headerProps,
@@ -13,7 +13,7 @@
13
13
  items,
14
14
  variant,
15
15
  isLoading = false,
16
- }: CarouselMediaProps = $props();
16
+ }: CarouselGridMediaProps = $props();
17
17
 
18
18
  const responsive = useDevice();
19
19
  </script>
@@ -21,7 +21,7 @@
21
21
  <CarouselHeader {...headerProps}>
22
22
  <CarouselGridSlot {slotProps} {gridClass} totalItems={items.length}>
23
23
  {#if isLoading}
24
- {#each Array.from( { length: responsive.isMobile ? 5 : 9 }, ) as _, i (`loading-${i}`)}
24
+ {#each Array.from( { length: responsive.isMobile ? 3 : 6 }, ) as _, i (`loading-${i}`)}
25
25
  {#if responsive.isMobile}
26
26
  <Carousel.Item class="pl-2 basis-auto">
27
27
  <CardMedia id={i} {variant} isLoading />
@@ -1,4 +1,4 @@
1
- import type { CarouselMediaProps } from "../types";
2
- declare const CarouselGridMedia: import("svelte").Component<CarouselMediaProps, {}, "">;
1
+ import type { CarouselGridMediaProps } from "../../../../../../types";
2
+ declare const CarouselGridMedia: import("svelte").Component<CarouselGridMediaProps, {}, "">;
3
3
  type CarouselGridMedia = ReturnType<typeof CarouselGridMedia>;
4
4
  export default CarouselGridMedia;
@@ -5,7 +5,7 @@ import type { CarouselHeaderProps } from "../../types";
5
5
  * Props do CarouselGridProfile — layout em grid de cards de perfil
6
6
  * (guias, intérpretes, organizações). Em mobile vira carousel com swipe.
7
7
  */
8
- export interface CarouselProfileProps {
8
+ export interface CarouselGridProfileProps {
9
9
  /** Props do cabeçalho do carousel (título, descrição, etc.) */
10
10
  headerProps?: CarouselHeaderProps;
11
11
  /** Props do slot/container do carousel (botões navegação, plugins) */
@@ -18,4 +18,13 @@ export interface CarouselProfileProps {
18
18
  items: CardProfileProps[];
19
19
  /** Estado de carregamento (skeleton) */
20
20
  isLoading?: boolean;
21
+ isDescriptionIcon?: boolean;
22
+ isDescriptionLabel?: boolean;
23
+ onFavoriteClick?: (id: string | number) => void;
24
+ /** Callback ao clicar no botão perfil */
25
+ onButtonProfile?: (id: string | number) => void;
26
+ /** Callback ao clicar no botão email */
27
+ onEmailClick?: (id: string | number) => void;
28
+ /** Callback ao clicar no botão whatsapp */
29
+ onWhatsappClick?: (id: string | number) => void;
21
30
  }
@@ -3,17 +3,23 @@
3
3
  import * as Carousel from "../../../../../ui/carousel/index.js";
4
4
  import CarouselHeader from "../../../shared/ui/CarouselHeader.svelte";
5
5
  import { useDevice } from "../../../../../../hooks/responsive.svelte";
6
- import type { CarouselProfileProps } from "../types";
7
6
  import CardProfile from "../../../../card/profile/CardProfile.svelte";
7
+ import type { CarouselGridProfileProps } from "../../../../../../types";
8
8
 
9
9
  const {
10
10
  headerProps,
11
11
  slotProps,
12
- gridClass,
12
+ gridClass = "lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6",
13
13
  items,
14
14
  variant,
15
15
  isLoading = false,
16
- }: CarouselProfileProps = $props();
16
+ isDescriptionIcon = false,
17
+ isDescriptionLabel = false,
18
+ onEmailClick,
19
+ onWhatsappClick,
20
+ onButtonProfile,
21
+ onFavoriteClick,
22
+ }: CarouselGridProfileProps = $props();
17
23
 
18
24
  const responsive = useDevice();
19
25
  </script>
@@ -21,7 +27,7 @@
21
27
  <CarouselHeader {...headerProps}>
22
28
  <CarouselGridSlot {slotProps} {gridClass} totalItems={items.length}>
23
29
  {#if isLoading}
24
- {#each Array.from( { length: responsive.isMobile ? 5 : 9 }, ) as _, i (`loading-${i}`)}
30
+ {#each Array.from( { length: responsive.isMobile ? 3 : 6 }, ) as _, i (`loading-${i}`)}
25
31
  {#if responsive.isMobile}
26
32
  <Carousel.Item class="pl-2 basis-auto">
27
33
  <CardProfile id={i} {variant} isLoading />
@@ -36,11 +42,29 @@
36
42
  {#each items as item, i (`profile-${item.id ?? i}`)}
37
43
  {#if responsive.isMobile}
38
44
  <Carousel.Item class="pl-2 basis-auto">
39
- <CardProfile {...item} {variant} />
45
+ <CardProfile
46
+ {...item}
47
+ {variant}
48
+ {isDescriptionIcon}
49
+ {isDescriptionLabel}
50
+ {onEmailClick}
51
+ {onWhatsappClick}
52
+ {onButtonProfile}
53
+ {onFavoriteClick}
54
+ />
40
55
  </Carousel.Item>
41
56
  {:else}
42
57
  <div>
43
- <CardProfile {...item} {variant} />
58
+ <CardProfile
59
+ {...item}
60
+ {variant}
61
+ {isDescriptionIcon}
62
+ {isDescriptionLabel}
63
+ {onEmailClick}
64
+ {onWhatsappClick}
65
+ {onButtonProfile}
66
+ {onFavoriteClick}
67
+ />
44
68
  </div>
45
69
  {/if}
46
70
  {/each}
@@ -1,4 +1,4 @@
1
- import type { CarouselProfileProps } from "../types";
2
- declare const CarouselGridProfile: import("svelte").Component<CarouselProfileProps, {}, "">;
1
+ import type { CarouselGridProfileProps } from "../../../../../../types";
2
+ declare const CarouselGridProfile: import("svelte").Component<CarouselGridProfileProps, {}, "">;
3
3
  type CarouselGridProfile = ReturnType<typeof CarouselGridProfile>;
4
4
  export default CarouselGridProfile;
@@ -27,7 +27,7 @@
27
27
  >
28
28
  {#if isLoading}
29
29
  {#each Array.from( { length: responsive.isMobile ? 5 : 10 }, ) as _, i (`loading-${i}`)}
30
- <Carousel.Item class="pl-2 w-75 basis-auto">
30
+ <Carousel.Item class="pl-5 w-75 basis-auto">
31
31
  <CardPromotion
32
32
  id={i}
33
33
  {isLoading}
@@ -0,0 +1,6 @@
1
+ export type NegoDesignProps = {
2
+ /** Custom translations per language. Merged with the library's base translations. */
3
+ translations?: Record<string, Record<string, string>>;
4
+ /** Conteúdo da aplicação */
5
+ children?: any;
6
+ };
@@ -0,0 +1 @@
1
+ export {};
package/dist/globals.css CHANGED
@@ -1,4 +1,5 @@
1
1
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @charset "UTF-8";
2
3
  @layer properties;
3
4
  @layer theme, base, components, utilities;
4
5
  @layer theme {
@@ -7,9 +8,11 @@
7
8
  "Courier New", monospace;
8
9
  --color-red-500: oklch(63.7% 0.237 25.331);
9
10
  --color-red-600: oklch(57.7% 0.245 27.325);
11
+ --color-red-800: oklch(44.4% 0.177 26.899);
10
12
  --color-red-900: oklch(39.6% 0.141 25.723);
11
13
  --color-yellow-500: oklch(79.5% 0.184 86.047);
12
14
  --color-green-500: oklch(72.3% 0.219 149.579);
15
+ --color-green-600: oklch(62.7% 0.194 149.214);
13
16
  --color-blue-50: oklch(97% 0.014 254.604);
14
17
  --color-blue-400: oklch(70.7% 0.165 254.624);
15
18
  --color-blue-500: oklch(62.3% 0.214 259.815);
@@ -539,6 +542,12 @@
539
542
  .mr-2 {
540
543
  margin-right: calc(var(--spacing) * 2);
541
544
  }
545
+ .-mb-1 {
546
+ margin-bottom: calc(var(--spacing) * -1);
547
+ }
548
+ .-mb-2 {
549
+ margin-bottom: calc(var(--spacing) * -2);
550
+ }
542
551
  .-mb-8 {
543
552
  margin-bottom: calc(var(--spacing) * -8);
544
553
  }
@@ -1437,6 +1446,9 @@
1437
1446
  .rounded-tr-lg {
1438
1447
  border-top-right-radius: var(--radius);
1439
1448
  }
1449
+ .rounded-br-lg {
1450
+ border-bottom-right-radius: var(--radius);
1451
+ }
1440
1452
  .rounded-bl-lg {
1441
1453
  border-bottom-left-radius: var(--radius);
1442
1454
  }
@@ -2999,6 +3011,9 @@
2999
3011
  background-color: color-mix(in oklab, var(--destructive) 20%, transparent);
3000
3012
  }
3001
3013
  }
3014
+ .hover\:bg-green-600:hover {
3015
+ background-color: var(--color-green-600);
3016
+ }
3002
3017
  .hover\:bg-input\/50:hover {
3003
3018
  background-color: var(--input);
3004
3019
  }
@@ -3037,6 +3052,9 @@
3037
3052
  background-color: color-mix(in oklab, var(--primary) 80%, transparent);
3038
3053
  }
3039
3054
  }
3055
+ .hover\:bg-red-800:hover {
3056
+ background-color: var(--color-red-800);
3057
+ }
3040
3058
  .hover\:bg-secondary\/80:hover {
3041
3059
  background-color: var(--secondary);
3042
3060
  }
@@ -3835,9 +3853,15 @@
3835
3853
  .md\:flex {
3836
3854
  display: flex;
3837
3855
  }
3856
+ .md\:h-14 {
3857
+ height: calc(var(--spacing) * 14);
3858
+ }
3838
3859
  .md\:h-20 {
3839
3860
  height: calc(var(--spacing) * 20);
3840
3861
  }
3862
+ .md\:h-32\.5 {
3863
+ height: calc(var(--spacing) * 32.5);
3864
+ }
3841
3865
  .md\:h-50 {
3842
3866
  height: calc(var(--spacing) * 50);
3843
3867
  }
@@ -3865,6 +3889,9 @@
3865
3889
  .md\:w-11\/12 {
3866
3890
  width: calc(11 / 12 * 100%);
3867
3891
  }
3892
+ .md\:w-14 {
3893
+ width: calc(var(--spacing) * 14);
3894
+ }
3868
3895
  .md\:w-20 {
3869
3896
  width: calc(var(--spacing) * 20);
3870
3897
  }
@@ -4009,15 +4036,24 @@
4009
4036
  .lg\:block {
4010
4037
  display: block;
4011
4038
  }
4039
+ .lg\:h-20 {
4040
+ height: calc(var(--spacing) * 20);
4041
+ }
4012
4042
  .lg\:h-24 {
4013
4043
  height: calc(var(--spacing) * 24);
4014
4044
  }
4045
+ .lg\:h-44 {
4046
+ height: calc(var(--spacing) * 44);
4047
+ }
4015
4048
  .lg\:h-105 {
4016
4049
  height: calc(var(--spacing) * 105);
4017
4050
  }
4018
4051
  .lg\:h-225 {
4019
4052
  height: calc(var(--spacing) * 225);
4020
4053
  }
4054
+ .lg\:w-20 {
4055
+ width: calc(var(--spacing) * 20);
4056
+ }
4021
4057
  .lg\:w-32 {
4022
4058
  width: calc(var(--spacing) * 32);
4023
4059
  }
@@ -4033,6 +4069,9 @@
4033
4069
  .lg\:grid-cols-3 {
4034
4070
  grid-template-columns: repeat(3, minmax(0, 1fr));
4035
4071
  }
4072
+ .lg\:grid-cols-4 {
4073
+ grid-template-columns: repeat(4, minmax(0, 1fr));
4074
+ }
4036
4075
  .lg\:grid-cols-\[1fr_22rem\] {
4037
4076
  grid-template-columns: 1fr 22rem;
4038
4077
  }
@@ -4056,6 +4095,14 @@
4056
4095
  .xl\:grid-cols-4 {
4057
4096
  grid-template-columns: repeat(4, minmax(0, 1fr));
4058
4097
  }
4098
+ .xl\:grid-cols-5 {
4099
+ grid-template-columns: repeat(5, minmax(0, 1fr));
4100
+ }
4101
+ }
4102
+ @media (width >= 96rem) {
4103
+ .\32 xl\:grid-cols-6 {
4104
+ grid-template-columns: repeat(6, minmax(0, 1fr));
4105
+ }
4059
4106
  }
4060
4107
  .ltr\:fill-current:where(:dir(ltr), [dir="ltr"], [dir="ltr"] *) {
4061
4108
  fill: currentcolor;
@@ -1,3 +1,5 @@
1
+ @charset "UTF-8";
2
+
1
3
  @import "tailwindcss";
2
4
  @import "tw-animate-css";
3
5
  @import "shadcn-svelte/tailwind.css";
@@ -146,4 +148,4 @@
146
148
  html {
147
149
  @apply font-sans;
148
150
  }
149
- }
151
+ }
@@ -6,8 +6,8 @@ import type { NavMenuLinksProps, NavMenuLogoProps, NavMenuActionsProps, NavMenuP
6
6
  import type { NavMenuSidebarProps, NavMenuAndSubmenuSidebarProps, GroupMenuSidebarProps, SubMenuSidebarProps, NavMenuItem } from "../components/core/nav/data/nav-menu-sidebar";
7
7
  import type { NavUserSidebarProps } from "../components/core/nav/data/nav-user-sidebar";
8
8
  import type { CardMediaProps, CardProfileProps, CardPromotionProps, CardHighlightProps, CardTagsProps } from "../components/core/card/types";
9
- import type { CarouselMediaProps } from "../components/core/carousel/grid/media/types";
10
- import type { CarouselProfileProps } from "../components/core/carousel/grid/profile/types";
9
+ import type { CarouselGridMediaProps } from "../components/core/carousel/grid/media/types";
10
+ import type { CarouselGridProfileProps } from "../components/core/carousel/grid/profile/types";
11
11
  import type { CarouselHighlightsProps } from "../components/core/carousel/highlights/types";
12
12
  import type { CarouselPromotionProps } from "../components/core/carousel/promotion/types";
13
13
  import type { ItemCarousel, CarouselHeaderProps, CarouselBadgeProps, CarouselHeroItem, CarouselHeroProps } from "../components/core/carousel/types";
@@ -24,26 +24,7 @@ import type { ProfileUserProps, ProfileUserData, ProfileUserVariant, ProfileUser
24
24
  import type { ProductDetailsProps, ProductDetailsData, ProductDetailsBreadcrumbItem, ProductDetailsTag, ProductDetailsImage, ProductDetailsLocation, ProductDetailsReview, ProductDetailsTab } from "../components/pages/product-details/types";
25
25
  import type { PrivacyPolicyOrTermsOfUseProps, DocPageData, DocSection, ContentBlock, BreadcrumbItem, TocItem } from "../components/pages/privacy-policy-or-terms-of-use/types";
26
26
  import type { InputLabelProps } from "../components/core/form/data/InputLabel.svelte";
27
- export interface NegoDesignProps {
28
- /** Custom translations per language. Merged with the library's base translations. */
29
- translations?: Record<string, Record<string, string>>;
30
- /** Conteúdo da aplicação */
31
- children?: any;
32
- }
33
- export type InputEmailProps = InputLabelProps;
34
- export type InputPhoneProps = InputLabelProps;
35
- export type InputEmailOrPhoneProps = InputLabelProps;
36
- export interface InputCodeOtpProps extends InputLabelProps {
37
- /** Number of OTP code boxes. Default: 6 */
38
- length?: number;
39
- /** Show separator between groups. Default: true */
40
- separator?: boolean;
41
- }
42
- export type InputPasswordProps = InputLabelProps;
43
- export type InputUsernameProps = InputLabelProps;
44
- export type InputPasswordConfirmProps = InputLabelProps;
45
- export type CarouselGridMediaProps = CarouselMediaProps;
46
- export type CarouselGridProfileProps = CarouselProfileProps;
27
+ import type { NegoDesignProps } from "../components/types";
47
28
  export type {
48
29
  /** Props de um link individual no menu de navegação. @see NavMenuLinksProps */
49
30
  NavMenuLinksProps,
@@ -87,10 +68,10 @@ CarouselBadgeProps,
87
68
  CarouselHeroItem,
88
69
  /** Props do CarouselHero — carousel hero principal com menu sobreposto. @see CarouselHeroProps */
89
70
  CarouselHeroProps,
90
- /** Props do CarouselGridMedia — layout em grid de cards de mídia (img/vídeo). @see CarouselMediaProps */
91
- CarouselMediaProps,
92
- /** Props do CarouselGridProfile — grid de cards de perfil (guias, organizações). @see CarouselProfileProps */
93
- CarouselProfileProps,
71
+ /** Props do CarouselGridMedia — layout em grid de cards de mídia (img/vídeo). @see CarouselGridMediaProps */
72
+ CarouselGridMediaProps,
73
+ /** Props do CarouselGridProfile — grid de cards de perfil (guias, organizações). @see CarouselGridProfileProps */
74
+ CarouselGridProfileProps,
94
75
  /** Props do CarouselHighlights — carousel de cards de destaque/organizações. @see CarouselHighlightsProps */
95
76
  CarouselHighlightsProps,
96
77
  /** Props do CarouselPromotion — carousel de cards de promoção com preços. @see CarouselPromotionProps */
@@ -171,20 +152,6 @@ ProfileUserData,
171
152
  ProfileUserProps,
172
153
  /** Props do NegoDesign — componente raiz do Negodesign. */
173
154
  NegoDesignProps,
174
- /** Props do input de email. @see InputLabelProps */
175
- InputEmailProps,
176
- /** Props do input de telefone. @see InputLabelProps */
177
- InputPhoneProps,
178
- /** Props do input híbrido email ou telefone. @see InputLabelProps */
179
- InputEmailOrPhoneProps,
180
- /** Props do input de código OTP. */
181
- InputCodeOtpProps,
182
- /** Props do input de password. @see InputLabelProps */
183
- InputPasswordProps,
184
- /** Props do input de nome de utilizador. @see InputLabelProps */
185
- InputUsernameProps,
186
- /** Props do input de confirmação de password. @see InputLabelProps */
187
- InputPasswordConfirmProps,
188
155
  /** Props base para inputs de formulário com label. */
189
156
  InputLabelProps,
190
157
  /** Item individual do breadcrumb do ProductDetails. @see ProductDetailsBreadcrumbItem */
@@ -214,8 +181,4 @@ DocPageData,
214
181
  /** Item da tabela de conteúdos (TOC). @see TocItem */
215
182
  TocItem,
216
183
  /** Props do componente PrivacyPolicyOrTermsOfUse. @see PrivacyPolicyOrTermsOfUseProps */
217
- PrivacyPolicyOrTermsOfUseProps,
218
- /** Alias para CarouselMediaProps — props do componente CarouselGridMedia. @see CarouselMediaProps */
219
- CarouselGridMediaProps,
220
- /** Alias para CarouselProfileProps — props do componente CarouselGridProfile. @see CarouselProfileProps */
221
- CarouselGridProfileProps };
184
+ PrivacyPolicyOrTermsOfUseProps, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "negodesign",
3
- "version": "0.0.31",
3
+ "version": "0.0.33",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "sideEffects": [