negodesign 0.0.68 → 0.0.70

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 (37) hide show
  1. package/dist/components/core/banner/CtaCardImageBanner.svelte +109 -0
  2. package/dist/components/core/banner/CtaCardImageBanner.svelte.d.ts +4 -0
  3. package/dist/components/core/banner/types.d.ts +37 -0
  4. package/dist/components/core/carousel/grid/shared/ui/CarouselGridSlot.svelte +1 -1
  5. package/dist/components/core/carousel/shared/ui/CarouselHeader.svelte +3 -4
  6. package/dist/components/core/grid/data/types.d.ts +3 -0
  7. package/dist/components/core/grid/ui/01/Grid01.svelte +2 -1
  8. package/dist/components/core/grid/ui/02/Grid02.svelte +2 -1
  9. package/dist/components/core/grid/ui/ItemsPanel.svelte +26 -0
  10. package/dist/components/core/grid/ui/ItemsPanel.svelte.d.ts +7 -0
  11. package/dist/components/core/grid/ui/ItemsPanelCarousel.svelte +37 -0
  12. package/dist/components/core/grid/ui/ItemsPanelCarousel.svelte.d.ts +4 -0
  13. package/dist/components/core/grid/ui/{PanelGrid.svelte → ItemsPanelGrid.svelte} +11 -5
  14. package/dist/components/core/grid/ui/ItemsPanelGrid.svelte.d.ts +4 -0
  15. package/dist/components/core/grid/ui/ItemsSimpleGrid.svelte.d.ts +4 -0
  16. package/dist/components/core/nav/data/types.d.ts +15 -0
  17. package/dist/components/core/nav/ui/ComplexMenu.svelte +27 -9
  18. package/dist/components/core/nav/ui/shared/MenuListItem.svelte +7 -2
  19. package/dist/components/core/nav/ui/shared/MenuListItem.svelte.d.ts +5 -1
  20. package/dist/components/core/nav/ui/shared/navigation/NavDropdown.svelte +23 -14
  21. package/dist/components/core/nav/ui/shared/navigation/NavDropdown.svelte.d.ts +3 -1
  22. package/dist/components/core/nav/ui/shared/navigation/NavigationMenuItem.svelte +12 -9
  23. package/dist/components/core/nav/ui/shared/navigation/NavigationMenuItemCard.svelte +12 -7
  24. package/dist/components/core/nav/ui/shared/navigation/NavigationMenuItemGrid.svelte +9 -3
  25. package/dist/components/core/nav/ui/shared/navigation/NavigationMenuItemList.svelte +7 -4
  26. package/dist/components/core/nav/ui/shared/navigation/NavigationMenuItems.svelte +3 -3
  27. package/dist/components/core/panel/NotFoundEmpty.svelte +2 -15
  28. package/dist/components/core/panel/NotFoundEmpty.svelte.d.ts +2 -14
  29. package/dist/components/core/panel/type.d.ts +25 -0
  30. package/dist/globals.css +125 -11
  31. package/dist/index.d.ts +164 -16
  32. package/dist/index.js +164 -16
  33. package/dist/types/index.d.ts +14 -4
  34. package/package.json +1 -1
  35. package/dist/components/core/grid/ui/PanelGrid.svelte.d.ts +0 -4
  36. package/dist/components/core/grid/ui/SimpleGrid.svelte.d.ts +0 -4
  37. /package/dist/components/core/grid/ui/{SimpleGrid.svelte → ItemsSimpleGrid.svelte} +0 -0
@@ -0,0 +1,109 @@
1
+ <script lang="ts">
2
+ import type { CtaCardImageBannerProps } from "./types";
3
+
4
+ let {
5
+ title,
6
+ description,
7
+ primaryText,
8
+ secondaryText,
9
+ primaryHref,
10
+ secondaryHref,
11
+ onClickPrimary,
12
+ onClickSecondary,
13
+ imageSrc = "https://tailwindcss.com/plus-assets/img/component-images/dark-project-app-screenshot.png",
14
+ imageAlt = "Imagem de destaque",
15
+ imageWidth = 1824,
16
+ imageHeight = 1080,
17
+ class: className = "",
18
+ imageContainerClass = "",
19
+ }: CtaCardImageBannerProps = $props();
20
+ </script>
21
+
22
+ <div class="bg-white">
23
+ <div class="mx-auto max-w-7xl py-24 sm:px-6 sm:py-32 lg:px-8">
24
+ <div
25
+ class="relative isolate overflow-hidden bg-gradient px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0 {className}"
26
+ >
27
+ <svg
28
+ viewBox="0 0 1024 1024"
29
+ aria-hidden="true"
30
+ class="absolute top-1/2 left-1/2 -z-10 size-256 -translate-y-1/2 mask-[radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0"
31
+ >
32
+ <circle
33
+ r="512"
34
+ cx="512"
35
+ cy="512"
36
+ fill="url(#759c1415-0410-454c-8f7c-9a820de03641)"
37
+ fill-opacity="0.7"
38
+ />
39
+ <defs>
40
+ <radialGradient id="759c1415-0410-454c-8f7c-9a820de03641">
41
+ <stop stop-color="#7775D6" />
42
+ <stop offset="1" stop-color="#E935C1" />
43
+ </radialGradient>
44
+ </defs>
45
+ </svg>
46
+
47
+ {#snippet pill(
48
+ label: string,
49
+ href: string | undefined,
50
+ onClick: (() => void) | undefined,
51
+ style: "primary" | "secondary",
52
+ )}
53
+ {#if href}
54
+ <a
55
+ {href}
56
+ class={style === "primary"
57
+ ? "rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-xs hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
58
+ : "text-sm/6 font-semibold text-white hover:text-gray-100"}
59
+ >
60
+ {label}
61
+ {#if style === "secondary"}<span aria-hidden="true">→</span>{/if}
62
+ </a>
63
+ {:else}
64
+ <button
65
+ type="button"
66
+ onclick={() => onClick?.()}
67
+ class={style === "primary"
68
+ ? "rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-xs hover:bg-gray-100 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
69
+ : "text-sm/6 font-semibold text-white hover:text-gray-100"}
70
+ >
71
+ {label}
72
+ {#if style === "secondary"}<span aria-hidden="true">→</span>{/if}
73
+ </button>
74
+ {/if}
75
+ {/snippet}
76
+
77
+ <div
78
+ class="mx-auto max-w-md text-center lg:mx-0 lg:flex-auto lg:py-32 lg:text-left"
79
+ >
80
+ <h2
81
+ class="text-3xl font-semibold tracking-tight text-balance text-white sm:text-4xl"
82
+ >
83
+ {title}
84
+ </h2>
85
+ {#if description}
86
+ <p class="mt-6 text-lg/8 text-pretty text-gray-300">{description}</p>
87
+ {/if}
88
+ <div
89
+ class="mt-10 flex items-center justify-center gap-x-6 lg:justify-start"
90
+ >
91
+ {@render pill(primaryText, primaryHref, onClickPrimary, "primary")}
92
+ {#if secondaryText}
93
+ {@render pill(secondaryText, secondaryHref, onClickSecondary, "secondary")}
94
+ {/if}
95
+ </div>
96
+ </div>
97
+ <div class="relative mt-16 h-80 lg:mt-8 {imageContainerClass}">
98
+ <img
99
+ src={imageSrc}
100
+ alt={imageAlt}
101
+ width={imageWidth}
102
+ height={imageHeight}
103
+ loading="lazy"
104
+ class="absolute top-0 left-0 w-228 max-w-none rounded-md bg-white/5 ring-1 ring-white/10"
105
+ />
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { CtaCardImageBannerProps } from "./types";
2
+ declare const CtaCardImageBanner: import("svelte").Component<CtaCardImageBannerProps, {}, "">;
3
+ type CtaCardImageBanner = ReturnType<typeof CtaCardImageBanner>;
4
+ export default CtaCardImageBanner;
@@ -71,3 +71,40 @@ export type CtaCardBannerProps = {
71
71
  color: string;
72
72
  }>;
73
73
  };
74
+ /**
75
+ * CTA banner com imagem de destaque em fundo gradiente.
76
+ * Título, descrição e até dois CTAs (primário e secundário), cada um com
77
+ * texto, href e/ou callback de clique, além da imagem e seus atributos.
78
+ * Usa `bg-gradient` como fundo padrão (customizável via `containerClass`).
79
+ * @component
80
+ */
81
+ export type CtaCardImageBannerProps = {
82
+ /** Título principal do banner. */
83
+ title: string;
84
+ /** Texto de apoio / descrição. */
85
+ description?: string;
86
+ /** Texto do CTA primário. */
87
+ primaryText: string;
88
+ /** href do CTA primário (link). */
89
+ primaryHref?: string;
90
+ /** Chamado ao clicar no CTA primário. */
91
+ onClickPrimary?: () => void;
92
+ /** Texto do CTA secundário. */
93
+ secondaryText?: string;
94
+ /** href do CTA secundário (link). */
95
+ secondaryHref?: string;
96
+ /** Chamado ao clicar no CTA secundário. */
97
+ onClickSecondary?: () => void;
98
+ /** URL da imagem de destaque. */
99
+ imageSrc?: string;
100
+ /** Texto alternativo da imagem. */
101
+ imageAlt?: string;
102
+ /** Largura da imagem (atributo width). */
103
+ imageWidth?: number;
104
+ /** Altura da imagem (atributo height). */
105
+ imageHeight?: number;
106
+ /** Classe CSS adicional para o artigo (fundo). */
107
+ class?: string;
108
+ /** Classe CSS do container da imagem. */
109
+ imageContainerClass?: string;
110
+ };
@@ -5,7 +5,7 @@
5
5
  import { useDevice } from "../../../../../../hooks/responsive.svelte";
6
6
  import Autoplay from "embla-carousel-autoplay";
7
7
  import type { GridProps } from "../../../../grid/data/types";
8
- import SimpleGrid from "../../../../grid/ui/SimpleGrid.svelte";
8
+ import SimpleGrid from "../../../../grid/ui/ItemsSimpleGrid.svelte";
9
9
 
10
10
  type Props = {
11
11
  slotProps?: CarouselSlotProps;
@@ -24,7 +24,7 @@
24
24
 
25
25
  <div class="w-full flex justify-center">
26
26
  <div
27
- class="w-[95%] p-2 rounded-xl
27
+ class="w-full p-2 rounded-xl
28
28
  {isBorder ? 'border border-gray-50 dark:border-gray-800' : ''}
29
29
  {containerClass}"
30
30
  >
@@ -43,9 +43,8 @@
43
43
  {#if onButtonViewAll}
44
44
  <div>
45
45
  <Button
46
- variant="ghost"
47
- size="sm"
48
- class="flex items-center gap-0.5"
46
+ variant="outline"
47
+ class="flex items-center gap-0.5 border"
49
48
  onclick={onButtonViewAll}
50
49
  >
51
50
  {$t("label.view.full")}
@@ -6,14 +6,17 @@ export interface ItemGridProps {
6
6
  description?: string;
7
7
  iconClass?: string;
8
8
  titleClass?: string;
9
+ itemClassName?: string;
9
10
  descriptionClass?: string;
10
11
  icon: string | IconSvgElement;
11
12
  onClick?: (id: string | number) => void;
12
13
  }
13
14
  export interface GridProps {
14
15
  items?: ItemGridProps[];
16
+ itemClassName?: string;
15
17
  className?: string;
16
18
  variant?: 1 | 2;
17
19
  isLoading?: boolean;
20
+ selectedKey?: string | number;
18
21
  onClick?: (id: string | number) => void;
19
22
  }
@@ -12,6 +12,7 @@
12
12
  iconClass,
13
13
  titleClass,
14
14
  description,
15
+ itemClassName,
15
16
  descriptionClass,
16
17
  onClick,
17
18
  }: ItemGridProps = $props();
@@ -21,7 +22,7 @@
21
22
  onclick={() => {
22
23
  if (id && onClick) onClick(id);
23
24
  }}
24
- class="flex flex-col justify-center items-center gap-2 hover:bg-primary/30 rounded-xl"
25
+ class="flex flex-col justify-center items-center gap-2 rounded-xl {itemClassName}"
25
26
  >
26
27
  <IconRenderGrid {icon} {iconClass} {isLoading} />
27
28
  <TitleGrid {titleClass} {title} {isLoading} />
@@ -12,6 +12,7 @@
12
12
  description,
13
13
  iconClass,
14
14
  titleClass,
15
+ itemClassName,
15
16
  descriptionClass,
16
17
  onClick,
17
18
  }: ItemGridProps = $props();
@@ -21,7 +22,7 @@
21
22
  onclick={() => {
22
23
  if (id && onClick) onClick(id);
23
24
  }}
24
- class="flex flex-col justify-center items-center gap-2 border rounded-lg p-2 cursor-pointer hover:bg-primary/30"
25
+ class="flex flex-col justify-center items-center gap-2 border rounded-lg p-2 cursor-pointer {itemClassName}"
25
26
  >
26
27
  <IconRenderGrid {icon} {iconClass} {isLoading} />
27
28
  <TitleGrid {titleClass} {title} {isLoading} />
@@ -0,0 +1,26 @@
1
+ <script lang="ts">
2
+ import type { GridProps } from "../data/types";
3
+ import PanelCarousel from "./ItemsPanelCarousel.svelte";
4
+ import PanelGrid from "./ItemsPanelGrid.svelte";
5
+
6
+ let {
7
+ style = "grid",
8
+ onClick,
9
+ ...restProps
10
+ }: GridProps & {
11
+ style?: "inline" | "grid";
12
+ } = $props();
13
+
14
+ let selectedKey = $state<string | number | undefined>("");
15
+
16
+ function selectItem(id: string | number) {
17
+ selectedKey = `${id}`;
18
+ onClick?.(id);
19
+ }
20
+ </script>
21
+
22
+ {#if style == "inline"}
23
+ <PanelCarousel {...restProps} {selectedKey} onClick={selectItem} />
24
+ {:else}
25
+ <PanelGrid {...restProps} {selectedKey} onClick={selectItem} />
26
+ {/if}
@@ -0,0 +1,7 @@
1
+ import type { GridProps } from "../data/types";
2
+ type $$ComponentProps = GridProps & {
3
+ style?: "inline" | "grid";
4
+ };
5
+ declare const ItemsPanel: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type ItemsPanel = ReturnType<typeof ItemsPanel>;
7
+ export default ItemsPanel;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import * as Carousel from "../../../ui/carousel/index.js";
3
+ import type { GridProps } from "../data/types";
4
+ import Grid02 from "./02/Grid02.svelte";
5
+ import Grid01 from "./01/Grid01.svelte";
6
+
7
+ let { variant, isLoading, items, itemClassName, onClick }: GridProps =
8
+ $props();
9
+ </script>
10
+
11
+ <Carousel.Root>
12
+ <Carousel.Content>
13
+ {#if isLoading}
14
+ <div class="flex items-center justify-between w-full gap-1 md:gap-2">
15
+ {#each Array.from({ length: 10 }) as _, i (`skeleton-${i}`)}
16
+ <Carousel.Item class="basis-auto relative">
17
+ {#if variant == 2}
18
+ <Grid02 title={`${i}`} description="" icon="" {isLoading} />
19
+ {:else}
20
+ <Grid01 title={`${i}`} description="" icon="" {isLoading} />
21
+ {/if}
22
+ </Carousel.Item>
23
+ {/each}
24
+ </div>
25
+ {:else}
26
+ {#each items as item, i (`panel-${i}`)}
27
+ <Carousel.Item class="basis-auto relative">
28
+ {#if variant == 2}
29
+ <Grid02 {...item} {onClick} {itemClassName} />
30
+ {:else}
31
+ <Grid01 {...item} {onClick} {itemClassName} />
32
+ {/if}
33
+ </Carousel.Item>
34
+ {/each}
35
+ {/if}
36
+ </Carousel.Content>
37
+ </Carousel.Root>
@@ -0,0 +1,4 @@
1
+ import type { GridProps } from "../data/types";
2
+ declare const ItemsPanelCarousel: import("svelte").Component<GridProps, {}, "">;
3
+ type ItemsPanelCarousel = ReturnType<typeof ItemsPanelCarousel>;
4
+ export default ItemsPanelCarousel;
@@ -4,7 +4,14 @@
4
4
  import Grid02 from "./02/Grid02.svelte";
5
5
  import Grid01 from "./01/Grid01.svelte";
6
6
 
7
- let { variant, className, isLoading, items, onClick }: GridProps = $props();
7
+ let {
8
+ variant,
9
+ className,
10
+ isLoading,
11
+ items,
12
+ itemClassName,
13
+ onClick,
14
+ }: GridProps = $props();
8
15
 
9
16
  const styleMobile = "flex justify-between overflow-x-auto no-scrollbar";
10
17
 
@@ -14,8 +21,7 @@
14
21
  <div
15
22
  class="gap-4 my-2 {responsive.isMobile
16
23
  ? styleMobile
17
- : 'grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 max-h-237.5 overflow-y-auto'}
18
- {className}"
24
+ : 'grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 max-h-237.5 overflow-y-auto'} {className}"
19
25
  >
20
26
  {#if isLoading}
21
27
  {#each Array.from({ length: responsive.isMobile ? 3 : 10 }) as it, i (i)}
@@ -28,9 +34,9 @@
28
34
  {:else}
29
35
  {#each items as item, i (i)}
30
36
  {#if variant == 2}
31
- <Grid02 {...item} {onClick} />
37
+ <Grid02 {...item} {onClick} {itemClassName} />
32
38
  {:else}
33
- <Grid01 {...item} {onClick} />
39
+ <Grid01 {...item} {onClick} {itemClassName} />
34
40
  {/if}
35
41
  {/each}
36
42
  {/if}
@@ -0,0 +1,4 @@
1
+ import type { GridProps } from "../data/types";
2
+ declare const ItemsPanelGrid: import("svelte").Component<GridProps, {}, "">;
3
+ type ItemsPanelGrid = ReturnType<typeof ItemsPanelGrid>;
4
+ export default ItemsPanelGrid;
@@ -0,0 +1,4 @@
1
+ import type { GridProps } from "../data/types";
2
+ declare const ItemsSimpleGrid: import("svelte").Component<GridProps, {}, "">;
3
+ type ItemsSimpleGrid = ReturnType<typeof ItemsSimpleGrid>;
4
+ export default ItemsSimpleGrid;
@@ -9,9 +9,14 @@ export type ListItemProps = HTMLAttributes<HTMLAnchorElement> & {
9
9
  export type NavigationMenuItemProps = {
10
10
  label: string;
11
11
  href?: string;
12
+ textClass?: string;
13
+ hoverClass?: string;
12
14
  };
13
15
  export type NavigationMenuItemCardProps = {
14
16
  label?: string;
17
+ textClass?: string;
18
+ subTextClass?: string;
19
+ hoverClass?: string;
15
20
  header?: {
16
21
  label: string;
17
22
  description: string;
@@ -24,14 +29,22 @@ export type NavigationMenuItemCardProps = {
24
29
  };
25
30
  export type NavigationMenuItemGridProps = {
26
31
  label: string;
32
+ textClass?: string;
33
+ hoverClass?: string;
34
+ subTextClass?: string;
27
35
  grids?: ListItemProps[];
28
36
  };
29
37
  export type NavigationMenuItemListProps = {
30
38
  label: string;
39
+ textClass?: string;
40
+ hoverClass?: string;
41
+ subTextClass?: string;
31
42
  list?: ListItemProps[];
32
43
  };
33
44
  export type NavigationMenuItemsProps = {
34
45
  label: string;
46
+ textClass?: string;
47
+ hoverClass?: string;
35
48
  items?: {
36
49
  title: string;
37
50
  href: string;
@@ -40,6 +53,8 @@ export type NavigationMenuItemsProps = {
40
53
  export type ComplexMenuProps = IMenuProps & {
41
54
  menus: (NavigationMenuItemProps | NavigationMenuItemListProps | NavigationMenuItemCardProps | NavigationMenuItemGridProps | NavigationMenuItemsProps)[];
42
55
  textClass?: string;
56
+ subTextClass?: string;
57
+ hoverClass?: string;
43
58
  };
44
59
  export type MenuVarientProps = ComplexMenuProps | SimpleMenuProps;
45
60
  export type MenuProps = IMenuProps & {
@@ -13,21 +13,39 @@
13
13
  import NavigationMenuItemList from "./shared/navigation/NavigationMenuItemList.svelte";
14
14
  import NavigationMenuItems from "./shared/navigation/NavigationMenuItems.svelte";
15
15
 
16
- let { menus: links, textClass }: ComplexMenuProps = $props();
16
+ let { menus, textClass, subTextClass, hoverClass }: ComplexMenuProps =
17
+ $props();
17
18
  </script>
18
19
 
19
- <ul class="flex list-none flex-1 flex-wrap items-center justify-center {textClass}">
20
- {#each links as link, i (i)}
20
+ <ul
21
+ class="flex list-none flex-1 flex-wrap items-center justify-center {textClass}"
22
+ >
23
+ {#each menus as link, i (i)}
21
24
  {#if isCard(link)}
22
- <NavigationMenuItemCard {...link} />
25
+ <NavigationMenuItemCard
26
+ {...link}
27
+ {textClass}
28
+ {subTextClass}
29
+ {hoverClass}
30
+ />
23
31
  {:else if isGrid(link)}
24
- <NavigationMenuItemGrid {...link} />
32
+ <NavigationMenuItemGrid
33
+ {...link}
34
+ {textClass}
35
+ {subTextClass}
36
+ {hoverClass}
37
+ />
25
38
  {:else if isList(link)}
26
- <NavigationMenuItemList {...link} />
39
+ <NavigationMenuItemList
40
+ {...link}
41
+ {textClass}
42
+ {subTextClass}
43
+ {hoverClass}
44
+ />
27
45
  {:else if isItems(link)}
28
- <NavigationMenuItems {...link} />
46
+ <NavigationMenuItems {...link} {textClass} {hoverClass} />
29
47
  {:else if isItem(link)}
30
- <NavigationMenuItem {...link} />
48
+ <NavigationMenuItem {...link} {textClass} {hoverClass} />
31
49
  {/if}
32
50
  {/each}
33
- </ul>
51
+ </ul>
@@ -6,9 +6,14 @@
6
6
  content,
7
7
  href,
8
8
  icon,
9
+ textClass,
10
+ subTextClass,
9
11
  class: className,
10
12
  ...restProps
11
- }: ListItemProps = $props();
13
+ }: ListItemProps & {
14
+ textClass?: string;
15
+ subTextClass?: string;
16
+ } = $props();
12
17
  </script>
13
18
 
14
19
  <li>
@@ -36,4 +41,4 @@
36
41
  {content}
37
42
  </p>
38
43
  </a>
39
- </li>
44
+ </li>
@@ -1,4 +1,8 @@
1
1
  import type { ListItemProps } from "../../data/types";
2
- declare const MenuListItem: import("svelte").Component<ListItemProps, {}, "">;
2
+ type $$ComponentProps = ListItemProps & {
3
+ textClass?: string;
4
+ subTextClass?: string;
5
+ };
6
+ declare const MenuListItem: import("svelte").Component<$$ComponentProps, {}, "">;
3
7
  type MenuListItem = ReturnType<typeof MenuListItem>;
4
8
  export default MenuListItem;
@@ -6,11 +6,15 @@
6
6
  let {
7
7
  label,
8
8
  className = "",
9
+ hoverClass = "",
10
+ onClick,
9
11
  children,
10
12
  }: {
11
13
  label: string;
12
14
  className?: string;
13
- children: Snippet;
15
+ hoverClass?: string;
16
+ children?: Snippet;
17
+ onClick?: () => void;
14
18
  } = $props();
15
19
 
16
20
  let open = $state(false);
@@ -50,25 +54,30 @@
50
54
  type="button"
51
55
  aria-expanded={open}
52
56
  onclick={() => {
53
- clearTimeout(closeTimer);
54
- open = !open;
57
+ if (children) {
58
+ clearTimeout(closeTimer);
59
+ open = !open;
60
+ }
61
+ if (onClick) onClick();
55
62
  }}
56
- class="inline-flex h-9 w-max items-center justify-center rounded-2xl px-4.5 py-2.5 text-sm font-medium transition-all outline-none select-none hover:bg-muted focus:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 {open
57
- ? 'bg-muted'
63
+ class="inline-flex h-9 w-max items-center justify-center rounded-2xl px-4.5 py-2.5 text-sm font-medium transition-all outline-none select-none hover:{hoverClass} focus:{hoverClass} focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 {open
64
+ ? hoverClass
58
65
  : ''}"
59
66
  >
60
67
  {label}
61
- <HugeiconsIcon
62
- icon={ArrowDown01Icon}
63
- strokeWidth={2}
64
- class={`relative top-px ml-1 size-3 transition-transform duration-300 ${
65
- open ? "rotate-180" : ""
66
- }`}
67
- aria-hidden="true"
68
- />
68
+ {#if children}
69
+ <HugeiconsIcon
70
+ icon={ArrowDown01Icon}
71
+ strokeWidth={2}
72
+ class={`relative top-px ml-1 size-3 transition-transform duration-300 ${
73
+ open ? "rotate-180" : ""
74
+ }`}
75
+ aria-hidden="true"
76
+ />
77
+ {/if}
69
78
  </button>
70
79
 
71
- {#if open}
80
+ {#if open && children}
72
81
  <div
73
82
  class="absolute left-0 top-full z-50 md:z-100 mt-1.5 w-max rounded-2xl bg-popover p-2.5 pr-3 overflow-hidden text-popover-foreground shadow-2xl ring-1 ring-foreground/5"
74
83
  >
@@ -2,7 +2,9 @@ import type { Snippet } from "svelte";
2
2
  type $$ComponentProps = {
3
3
  label: string;
4
4
  className?: string;
5
- children: Snippet;
5
+ hoverClass?: string;
6
+ children?: Snippet;
7
+ onClick?: () => void;
6
8
  };
7
9
  declare const NavDropdown: import("svelte").Component<$$ComponentProps, {}, "">;
8
10
  type NavDropdown = ReturnType<typeof NavDropdown>;
@@ -1,14 +1,17 @@
1
1
  <script lang="ts">
2
+ import { goto } from "$app/navigation";
2
3
  import type { NavigationMenuItemProps } from "../../../data/types";
4
+ import NavDropdown from "./NavDropdown.svelte";
3
5
 
4
- let { label, href }: NavigationMenuItemProps = $props();
6
+ let { label, href, textClass, hoverClass }: NavigationMenuItemProps =
7
+ $props();
5
8
  </script>
6
9
 
7
- <li>
8
- <a
9
- {href}
10
- class="inline-flex h-9 w-max items-center justify-center rounded-2xl px-4.5 py-2.5 text-sm font-medium transition-all outline-none select-none hover:bg-muted focus:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
11
- >
12
- {label}
13
- </a>
14
- </li>
10
+ <NavDropdown
11
+ {label}
12
+ className="hidden md:block"
13
+ {hoverClass}
14
+ onClick={() => {
15
+ if (href) goto(href);
16
+ }}
17
+ />
@@ -3,11 +3,18 @@
3
3
  import MenuListItem from "../MenuListItem.svelte";
4
4
  import NavDropdown from "./NavDropdown.svelte";
5
5
 
6
- let { label, header, cards: items }: NavigationMenuItemCardProps = $props();
6
+ let {
7
+ label,
8
+ header,
9
+ cards: items,
10
+ hoverClass,
11
+ }: NavigationMenuItemCardProps = $props();
7
12
  </script>
8
13
 
9
14
  {#snippet headerSnippet(label: string, description: string)}
10
- <div class="mt-4 mb-2 text-lg font-medium {header?.labelClass}">{label}</div>
15
+ <div class="mt-4 mb-2 text-lg font-medium {header?.labelClass}">
16
+ {label}
17
+ </div>
11
18
  <p
12
19
  class="text-sm leading-tight {header?.descriptionClass ||
13
20
  'text-muted-foreground'}"
@@ -16,10 +23,8 @@
16
23
  </p>
17
24
  {/snippet}
18
25
 
19
- <NavDropdown label={label ?? header?.label ?? ""}>
20
- <ul
21
- class="grid gap-2 p-2 w-100 lg:w-125 lg:grid-cols-[.75fr_1fr]"
22
- >
26
+ <NavDropdown label={label ?? header?.label ?? ""} {hoverClass}>
27
+ <ul class="grid gap-2 p-2 w-100 lg:w-125 lg:grid-cols-[.75fr_1fr]">
23
28
  {#if header}
24
29
  <li
25
30
  class="row-span-3 relative"
@@ -45,4 +50,4 @@
45
50
  {/each}
46
51
  {/if}
47
52
  </ul>
48
- </NavDropdown>
53
+ </NavDropdown>