negodesign 0.0.38 → 0.0.40

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.
@@ -23,7 +23,6 @@
23
23
  content,
24
24
  imageUrl,
25
25
  videoUrl,
26
- //videoAction,
27
26
  startNumber,
28
27
  startMax = 5,
29
28
  isImageButtonMaximized = false,
@@ -33,6 +32,8 @@
33
32
  isLoading = false,
34
33
  buttonProfileClass,
35
34
  buttonDetailsClass,
35
+ isDescriptionIcon,
36
+ isDescriptionLabel,
36
37
  onFavoriteClick,
37
38
  onButtonProfile,
38
39
  onButtonDetails,
@@ -75,8 +76,13 @@
75
76
  </div>
76
77
  </div>
77
78
 
78
- <div class="h-15 my-2">
79
- <CardDescription {content} {isLoading} />
79
+ <div class="h-15 my-2 mb-5 md:mb-0">
80
+ <CardDescription
81
+ {content}
82
+ {isLoading}
83
+ {isDescriptionIcon}
84
+ {isDescriptionLabel}
85
+ />
80
86
  </div>
81
87
 
82
88
  <CardTags
@@ -23,7 +23,6 @@
23
23
  className,
24
24
  imageUrl,
25
25
  videoUrl,
26
- //videoAction,
27
26
  startNumber,
28
27
  startMax = 5,
29
28
  isImageButtonMaximized = false,
@@ -33,6 +32,8 @@
33
32
  isLoading = false,
34
33
  buttonProfileClass,
35
34
  buttonDetailsClass,
35
+ isDescriptionIcon,
36
+ isDescriptionLabel,
36
37
  onFavoriteClick,
37
38
  onButtonProfile,
38
39
  onButtonDetails,
@@ -81,8 +82,13 @@
81
82
  />
82
83
  </div>
83
84
 
84
- <div class="h-15 mb-4">
85
- <CardDescription {content} {isLoading} />
85
+ <div class="h-15 mb-10 md:mb-0">
86
+ <CardDescription
87
+ {content}
88
+ {isLoading}
89
+ {isDescriptionIcon}
90
+ {isDescriptionLabel}
91
+ />
86
92
  </div>
87
93
 
88
94
  <CardThumbnailVideo
@@ -27,7 +27,7 @@
27
27
  let {
28
28
  imageUrl,
29
29
  videoUrl,
30
- class: className = "w-64 h-64",
30
+ class: className = "h-32 md:w-64 md:h-64",
31
31
  isImageButtonMaximized = false,
32
32
  isVideoButtonMaximized = false,
33
33
  isLoading = false,
@@ -48,6 +48,10 @@ export interface CardMediaProps {
48
48
  isVideoButtonMaximized?: boolean;
49
49
  /** Exibe o botão de maximizar na imagem */
50
50
  isImageButtonMaximized?: boolean;
51
+ /** Exibe ícone antes da descrição */
52
+ isDescriptionIcon?: boolean;
53
+ /** Exibe etiqueta (label) na descrição */
54
+ isDescriptionLabel?: boolean;
51
55
  /** Callback acionado ao clicar no botão de favorito */
52
56
  onFavoriteClick?: (id: string | number) => void;
53
57
  /** Callback acionado ao clicar no botão de perfil */
@@ -2,7 +2,6 @@
2
2
  import * as Carousel from "../../../../ui/carousel/index.js";
3
3
  import type { CarouselBadgeProps } from "../../types.js";
4
4
  import { HugeiconsIcon } from "@hugeicons/svelte";
5
- import CarouselSlot from "../../../panel/CarouselSlot.svelte";
6
5
  import Skeleton from "../../../../ui/skeleton/skeleton.svelte";
7
6
  import { useDevice } from "../../../../../hooks/responsive.svelte";
8
7
 
@@ -11,72 +10,72 @@
11
10
  imageClass,
12
11
  iconClass,
13
12
  labelClass,
14
- activeClass,
15
- valueActive,
13
+ activeClass = "bg-gradient text-white rounded-sm px-3",
16
14
  isLoading = false,
17
- itemCarouselClass,
18
15
  orientation = "horizontal",
19
- isBorderItem = false,
20
- isBorderBottom = false,
21
- isButtonPreviousAndNext = true,
22
- buttonPreviousAndNextClass = "",
16
+ onClick,
23
17
  }: CarouselBadgeProps = $props();
24
18
 
25
19
  const DEFAULT_IMG_OR_ICON_CLASS = "size-3";
20
+ const NAV_BUTTON_CLASS =
21
+ "absolute top-1/2 -translate-y-1/2 mt-0.5 md:mr-0 z-50 bg-blue-700! text-white! cursor-pointer!";
22
+
26
23
  const responsive = useDevice();
24
+ const skeletonCount = $derived(responsive.isMobile ? 2 : 8);
25
+
26
+ let selectedValue = $state<unknown>(undefined);
27
+
28
+ function isSelected(item: (typeof items)[number]) {
29
+ return item.value !== undefined && item.value === selectedValue;
30
+ }
31
+
32
+ function selectItem(item: (typeof items)[number]) {
33
+ selectedValue = item.value;
34
+ item.onClick?.(item.value);
35
+ onClick?.(item.value);
36
+ }
27
37
  </script>
28
38
 
29
- <CarouselSlot
30
- {isBorderBottom}
31
- {isButtonPreviousAndNext}
32
- {buttonPreviousAndNextClass}
33
- >
34
- {#if isLoading}
35
- <div class="flex items-center justify-between w-full gap-1 md:gap-2">
36
- {#each Array.from({ length: responsive.isMobile ? 2 : 10 }) as _, i (`skeleton-${i}`)}
37
- <Skeleton class="h-4 w-25 bg-black/20" />
38
- {/each}
39
- </div>
40
- {:else}
41
- {#each (items ?? []) as item, i (`badge-${i}-${item.value ?? item.label ?? i}`)}
42
- <Carousel.Item
43
- onclick={() => item.onClick?.(item.value)}
44
- class={`
45
- flex cursor-pointer items-center justify-center gap-1 basis-auto mx-3 pl-0
46
- ${isBorderItem ? "border border-solid border-gray-300 rounded-lg" : ""}
47
- ${item.value === valueActive ? activeClass : ""}
48
- ${itemCarouselClass}`}
49
- >
50
- <div
51
- class={`
52
- flex gap-1 mx-2 p-0.5 justify-center items-center
53
- ${orientation === "horizontal" ? "flex-row" : "flex-col"}
54
- `}
55
- >
56
- {#if item.image}
57
- <img
58
- src={item.image}
59
- alt={item.label}
60
- class={imageClass || DEFAULT_IMG_OR_ICON_CLASS}
61
- />
62
- {:else if item.icon}
63
- {#if typeof item.icon === "string"}
64
- <div>
65
- <i
66
- class={`${item.icon} ${iconClass || DEFAULT_IMG_OR_ICON_CLASS}`}
67
- >
68
- </i>
69
- </div>
70
- {:else}
71
- <HugeiconsIcon
72
- icon={item.icon}
73
- class={iconClass || DEFAULT_IMG_OR_ICON_CLASS}
74
- />
75
- {/if}
76
- {/if}
77
- <div class={`${labelClass}`}>{item.label}</div>
78
- </div>
79
- </Carousel.Item>
80
- {/each}
39
+ {#snippet itemVisual(item: (typeof items)[number])}
40
+ {#if item.image}
41
+ <img
42
+ src={item.image}
43
+ alt={item.label}
44
+ class={imageClass || DEFAULT_IMG_OR_ICON_CLASS}
45
+ />
46
+ {:else if typeof item.icon === "string"}
47
+ <i class={`${item.icon} ${iconClass || DEFAULT_IMG_OR_ICON_CLASS}`}></i>
48
+ {:else if item.icon}
49
+ <HugeiconsIcon
50
+ icon={item.icon}
51
+ class={iconClass || DEFAULT_IMG_OR_ICON_CLASS}
52
+ />
81
53
  {/if}
82
- </CarouselSlot>
54
+ {/snippet}
55
+
56
+ <Carousel.Root>
57
+ <Carousel.Content>
58
+ {#if isLoading}
59
+ <div class="flex items-center justify-between w-full gap-1 md:gap-2">
60
+ {#each Array.from({ length: skeletonCount }) as _, i (`skeleton-${i}`)}
61
+ <Skeleton class="h-4 w-25 bg-gray-900/90" />
62
+ {/each}
63
+ </div>
64
+ {:else}
65
+ {#each items as item, i (`badge-${i}-${item.value ?? item.label ?? i}`)}
66
+ <Carousel.Item class="basis-auto" onclick={() => selectItem(item)}>
67
+ <div
68
+ class="flex gap-1 mx-2 p-0.5 justify-center items-center cursor-pointer
69
+ {orientation === 'horizontal' ? 'flex-row' : 'flex-col'}
70
+ {isSelected(item) ? activeClass : ''}"
71
+ >
72
+ {@render itemVisual(item)}
73
+ <div class={labelClass}>{item.label}</div>
74
+ </div>
75
+ </Carousel.Item>
76
+ {/each}
77
+ {/if}
78
+ </Carousel.Content>
79
+ <Carousel.Previous class="-left-8 {NAV_BUTTON_CLASS}" />
80
+ <Carousel.Next class="-right-8 {NAV_BUTTON_CLASS}" />
81
+ </Carousel.Root>
@@ -12,6 +12,10 @@ export interface CarouselGridMediaProps {
12
12
  slotProps?: CarouselSlotProps;
13
13
  /** Classe CSS adicional para o container do grid */
14
14
  gridClass?: string;
15
+ /** Exibe ícone antes da descrição */
16
+ isDescriptionIcon?: boolean;
17
+ /** Exibe etiqueta (label) na descrição */
18
+ isDescriptionLabel?: boolean;
15
19
  /** Variante visual do card: 1 ou 2 */
16
20
  variant?: 1 | 2;
17
21
  /** Lista de itens de mídia para exibir nos cards */
@@ -15,6 +15,8 @@
15
15
  items,
16
16
  variant,
17
17
  isLoading = false,
18
+ isDescriptionIcon,
19
+ isDescriptionLabel,
18
20
  }: CarouselGridMediaProps = $props();
19
21
 
20
22
  const responsive = useDevice();
@@ -32,7 +34,7 @@
32
34
  {#if isLoading}
33
35
  {#each Array.from( { length: responsive.isMobile ? 3 : 6 }, ) as _, i (`loading-${i}`)}
34
36
  {#if responsive.isMobile}
35
- <Carousel.Item class="pl-2 basis-auto">
37
+ <Carousel.Item class="pl-2 basis-auto w-[300px]">
36
38
  <CardMedia id={i} {variant} isLoading />
37
39
  </Carousel.Item>
38
40
  {:else}
@@ -44,12 +46,22 @@
44
46
  {:else}
45
47
  {#each items as item, i (`media-${item.id ?? i}`)}
46
48
  {#if responsive.isMobile}
47
- <Carousel.Item class="pl-2 basis-auto">
48
- <CardMedia {...item} {variant} />
49
+ <Carousel.Item class="pl-2 basis-auto w-[300px]">
50
+ <CardMedia
51
+ {...item}
52
+ {variant}
53
+ {isDescriptionIcon}
54
+ {isDescriptionLabel}
55
+ />
49
56
  </Carousel.Item>
50
57
  {:else}
51
58
  <div>
52
- <CardMedia {...item} {variant} />
59
+ <CardMedia
60
+ {...item}
61
+ {variant}
62
+ {isDescriptionIcon}
63
+ {isDescriptionLabel}
64
+ />
53
65
  </div>
54
66
  {/if}
55
67
  {/each}
@@ -59,20 +59,9 @@ export interface CarouselBadgeProps {
59
59
  labelClass?: string;
60
60
  /** Classe CSS personalizada para o estado ativo */
61
61
  activeClass?: string;
62
- /** Valor do item ativo por padrão */
63
- valueActive?: string;
64
62
  /** Estado de carregamento (skeleton) */
65
63
  isLoading?: boolean;
66
- /** Exibe borda em cada item */
67
- isBorderItem?: boolean;
68
- /** Exibe borda inferior no container */
69
- isBorderBottom?: boolean;
70
- /** Classe CSS adicional para cada item do carousel */
71
- itemCarouselClass?: string;
72
- /** Exibe botões anterior/próximo */
73
- isButtonPreviousAndNext?: boolean;
74
- /** Classe CSS personalizada para botões anterior/próximo */
75
- buttonPreviousAndNextClass?: string;
64
+ onClick?: (value: string | number) => void;
76
65
  }
77
66
  /**
78
67
  * Item individual do CarouselHero — slide com imagem,
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import * as Carousel from "../../ui/carousel/index.js";
3
+ import { useDevice } from "../../../hooks/responsive.svelte";
3
4
  import type { CarouselSlotProps } from "./type";
4
5
 
5
6
  const {
@@ -14,7 +15,9 @@
14
15
 
15
16
  const styleTopCenter = "bg-blue-700! text-white! cursor-pointer!";
16
17
  const styleCenter =
17
- "absolute top-1/2 -translate-y-1/2 mt-0.5 mr-0 z-50 bg-blue-700! text-white! cursor-pointer!";
18
+ "absolute top-1/2 -translate-y-1/2 mt-0.5 md:mr-0 z-50 bg-blue-700! text-white! cursor-pointer!";
19
+
20
+ const responsive = useDevice();
18
21
  </script>
19
22
 
20
23
  <div
@@ -26,7 +29,7 @@
26
29
  >
27
30
  {@render children?.()}
28
31
  </Carousel.Content>
29
- {#if positionButtonPreviousAndNext == "center"}
32
+ {#if positionButtonPreviousAndNext == "center" && !responsive.isMobile}
30
33
  {#if isButtonPreviousAndNext}
31
34
  <Carousel.Previous
32
35
  class={`-left-8 ${styleCenter} ${buttonPreviousAndNextClass}`}
@@ -36,14 +39,16 @@
36
39
  />
37
40
  {/if}
38
41
  {/if}
39
- {#if positionButtonPreviousAndNext == "top_right"}
42
+ {#if positionButtonPreviousAndNext == "top_right" || responsive.isMobile}
40
43
  {#if isButtonPreviousAndNext}
41
- <div class="absolute -top-6 right-10 md:right-10 lg:right-12 z-20">
44
+ <div
45
+ class="absolute -top-16 md:-top-10 right-8 md:right-10 lg:right-12 z-20"
46
+ >
42
47
  <Carousel.Previous
43
48
  class={`${styleTopCenter} ${buttonPreviousAndNextClass}`}
44
49
  />
45
50
  <Carousel.Next
46
- class={`${styleTopCenter} ${buttonPreviousAndNextClass}`}
51
+ class={`start-0 ${styleTopCenter} ${buttonPreviousAndNextClass}`}
47
52
  />
48
53
  </div>
49
54
  {/if}
@@ -39,6 +39,6 @@
39
39
  <Skeleton class="h-7 w-28 rounded-md" />
40
40
  {:else if formatted || oldPrice}
41
41
  <div class="flex items-end gap-3">
42
- <CardStartPrice newPrice={formatted} oldPrice={oldPrice} />
42
+ <CardStartPrice newPrice={formatted} {oldPrice} />
43
43
  </div>
44
44
  {/if}
package/dist/globals.css CHANGED
@@ -17,7 +17,6 @@
17
17
  --color-blue-400: oklch(70.7% 0.165 254.624);
18
18
  --color-blue-500: oklch(62.3% 0.214 259.815);
19
19
  --color-blue-700: oklch(48.8% 0.243 264.376);
20
- --color-blue-900: oklch(37.9% 0.146 265.522);
21
20
  --color-indigo-600: oklch(51.1% 0.262 276.966);
22
21
  --color-slate-400: oklch(70.4% 0.04 256.788);
23
22
  --color-slate-500: oklch(55.4% 0.046 257.417);
@@ -297,12 +296,12 @@
297
296
  .end-2 {
298
297
  inset-inline-end: calc(var(--spacing) * 2);
299
298
  }
300
- .-top-6 {
301
- top: calc(var(--spacing) * -6);
302
- }
303
299
  .-top-12 {
304
300
  top: calc(var(--spacing) * -12);
305
301
  }
302
+ .-top-16 {
303
+ top: calc(var(--spacing) * -16);
304
+ }
306
305
  .top-0 {
307
306
  top: 0px;
308
307
  }
@@ -351,8 +350,8 @@
351
350
  .right-4 {
352
351
  right: calc(var(--spacing) * 4);
353
352
  }
354
- .right-10 {
355
- right: calc(var(--spacing) * 10);
353
+ .right-8 {
354
+ right: calc(var(--spacing) * 8);
356
355
  }
357
356
  .-bottom-12 {
358
357
  bottom: calc(var(--spacing) * -12);
@@ -462,9 +461,6 @@
462
461
  .mx-2 {
463
462
  margin-inline: calc(var(--spacing) * 2);
464
463
  }
465
- .mx-3 {
466
- margin-inline: calc(var(--spacing) * 3);
467
- }
468
464
  .mx-3\.5 {
469
465
  margin-inline: calc(var(--spacing) * 3.5);
470
466
  }
@@ -552,9 +548,6 @@
552
548
  .-mr-2 {
553
549
  margin-right: calc(var(--spacing) * -2);
554
550
  }
555
- .mr-0 {
556
- margin-right: 0px;
557
- }
558
551
  .mr-0\.5 {
559
552
  margin-right: calc(var(--spacing) * 0.5);
560
553
  }
@@ -814,9 +807,6 @@
814
807
  .h-50 {
815
808
  height: calc(var(--spacing) * 50);
816
809
  }
817
- .h-64 {
818
- height: calc(var(--spacing) * 64);
819
- }
820
810
  .h-72 {
821
811
  height: calc(var(--spacing) * 72);
822
812
  }
@@ -979,9 +969,6 @@
979
969
  .w-56 {
980
970
  width: calc(var(--spacing) * 56);
981
971
  }
982
- .w-64 {
983
- width: calc(var(--spacing) * 64);
984
- }
985
972
  .w-72 {
986
973
  width: calc(var(--spacing) * 72);
987
974
  }
@@ -1537,10 +1524,6 @@
1537
1524
  --tw-border-style: none;
1538
1525
  border-style: none;
1539
1526
  }
1540
- .border-solid {
1541
- --tw-border-style: solid;
1542
- border-style: solid;
1543
- }
1544
1527
  .border-\(--color-border\) {
1545
1528
  border-color: var(--color-border);
1546
1529
  }
@@ -1700,9 +1683,6 @@
1700
1683
  .bg-blue-700\! {
1701
1684
  background-color: var(--color-blue-700) !important;
1702
1685
  }
1703
- .bg-blue-900 {
1704
- background-color: var(--color-blue-900);
1705
- }
1706
1686
  .bg-border {
1707
1687
  background-color: var(--border);
1708
1688
  }
@@ -1772,6 +1752,12 @@
1772
1752
  background-color: color-mix(in oklab, var(--color-gray-800) 50%, transparent);
1773
1753
  }
1774
1754
  }
1755
+ .bg-gray-900\/90 {
1756
+ background-color: color-mix(in srgb, oklch(21% 0.034 264.665) 90%, transparent);
1757
+ @supports (color: color-mix(in lab, red, red)) {
1758
+ background-color: color-mix(in oklab, var(--color-gray-900) 90%, transparent);
1759
+ }
1760
+ }
1775
1761
  .bg-green-500 {
1776
1762
  background-color: var(--color-green-500);
1777
1763
  }
@@ -3980,6 +3966,9 @@
3980
3966
  }
3981
3967
  }
3982
3968
  @media (width >= 48rem) {
3969
+ .md\:-top-10 {
3970
+ top: calc(var(--spacing) * -10);
3971
+ }
3983
3972
  .md\:right-6 {
3984
3973
  right: calc(var(--spacing) * 6);
3985
3974
  }
@@ -4001,9 +3990,15 @@
4001
3990
  .md\:mt-10 {
4002
3991
  margin-top: calc(var(--spacing) * 10);
4003
3992
  }
3993
+ .md\:mr-0 {
3994
+ margin-right: 0px;
3995
+ }
4004
3996
  .md\:-mb-10 {
4005
3997
  margin-bottom: calc(var(--spacing) * -10);
4006
3998
  }
3999
+ .md\:mb-0 {
4000
+ margin-bottom: 0px;
4001
+ }
4007
4002
  .md\:block {
4008
4003
  display: block;
4009
4004
  }
@@ -4031,6 +4026,9 @@
4031
4026
  .md\:h-50 {
4032
4027
  height: calc(var(--spacing) * 50);
4033
4028
  }
4029
+ .md\:h-64 {
4030
+ height: calc(var(--spacing) * 64);
4031
+ }
4034
4032
  .md\:h-100 {
4035
4033
  height: calc(var(--spacing) * 100);
4036
4034
  }
@@ -4064,6 +4062,9 @@
4064
4062
  .md\:w-25 {
4065
4063
  width: calc(var(--spacing) * 25);
4066
4064
  }
4065
+ .md\:w-64 {
4066
+ width: calc(var(--spacing) * 64);
4067
+ }
4067
4068
  .md\:w-225 {
4068
4069
  width: calc(var(--spacing) * 225);
4069
4070
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "negodesign",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "sideEffects": [