From bdc759d34ce70446081643fdb7064daa61dfb19b Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Mon, 3 Mar 2025 12:30:28 +0100 Subject: [PATCH] feat(sidebar): sidebar with new functionalities (#7018) --- ui/app/(prowler)/categories/page.tsx | 12 - ui/app/(prowler)/compliance/page.tsx | 8 +- ui/app/(prowler)/findings/page.tsx | 9 +- ui/app/(prowler)/integrations/page.tsx | 10 +- ui/app/(prowler)/invitations/page.tsx | 8 +- ui/app/(prowler)/layout.tsx | 17 +- ui/app/(prowler)/manage-groups/layout.tsx | 16 +- ui/app/(prowler)/page.tsx | 7 +- ui/app/(prowler)/profile/page.tsx | 9 +- ui/app/(prowler)/providers/page.tsx | 9 +- ui/app/(prowler)/roles/page.tsx | 8 +- ui/app/(prowler)/scans/page.tsx | 15 +- ui/app/(prowler)/services/page.tsx | 13 +- ui/app/(prowler)/settings/page.tsx | 12 - ui/app/(prowler)/users/page.tsx | 8 +- ui/app/(prowler)/workloads/page.tsx | 11 +- ui/components/icons/Icons.tsx | 168 +++ ui/components/icons/prowler/ProwlerIcons.tsx | 3 +- ui/components/scans/no-providers-added.tsx | 2 +- ui/components/ui/avatar/avatar.tsx | 50 + ui/components/ui/button/button.tsx | 58 + ui/components/ui/collapsible/collapsible.tsx | 11 + .../ui/content-layout/content-layout.tsx | 24 + .../skeleton-content-layout.tsx | 17 + .../ui/dropdown-menu/dropdown-menu.tsx | 208 +++ ui/components/ui/headers/header.tsx | 20 - ui/components/ui/index.ts | 3 +- ui/components/ui/main-layout/main-layout.tsx | 29 + ui/components/ui/nav-bar/navbar.tsx | 35 + ui/components/ui/scroll-area/scroll-area.tsx | 48 + .../ui/sidebar/collapse-menu-button.tsx | 185 +++ ui/components/ui/sidebar/index.ts | 9 +- ui/components/ui/sidebar/menu.tsx | 171 +++ ui/components/ui/sidebar/sheet-menu.tsx | 42 + ui/components/ui/sidebar/sidebar-items.tsx | 531 -------- ui/components/ui/sidebar/sidebar-toggle.tsx | 29 + ui/components/ui/sidebar/sidebar-wrap.tsx | 370 ------ ui/components/ui/sidebar/sidebar.tsx | 393 +----- ui/components/ui/sidebar/skeleton-profile.tsx | 19 - ui/components/ui/sidebar/team-avatar.tsx | 35 - ui/components/ui/sidebar/user-avatar.tsx | 32 - ui/components/ui/tooltip/tooltip.tsx | 30 + ui/components/ui/user-nav/user-nav.tsx | 98 ++ ui/hooks/index.ts | 2 + ui/hooks/use-sidebar.ts | 49 + ui/hooks/use-store.ts | 17 + ui/lib/index.ts | 1 + ui/lib/menu-list.ts | 185 +++ ui/package-lock.json | 1111 ++++++++++------- ui/package.json | 2 + ui/tailwind.config.js | 12 +- ui/types/components.ts | 33 + 52 files changed, 2312 insertions(+), 1892 deletions(-) delete mode 100644 ui/app/(prowler)/categories/page.tsx delete mode 100644 ui/app/(prowler)/settings/page.tsx create mode 100644 ui/components/ui/avatar/avatar.tsx create mode 100644 ui/components/ui/button/button.tsx create mode 100644 ui/components/ui/collapsible/collapsible.tsx create mode 100644 ui/components/ui/content-layout/content-layout.tsx create mode 100644 ui/components/ui/content-layout/skeleton-content-layout.tsx create mode 100644 ui/components/ui/dropdown-menu/dropdown-menu.tsx delete mode 100644 ui/components/ui/headers/header.tsx create mode 100644 ui/components/ui/main-layout/main-layout.tsx create mode 100644 ui/components/ui/nav-bar/navbar.tsx create mode 100644 ui/components/ui/scroll-area/scroll-area.tsx create mode 100644 ui/components/ui/sidebar/collapse-menu-button.tsx create mode 100644 ui/components/ui/sidebar/menu.tsx create mode 100644 ui/components/ui/sidebar/sheet-menu.tsx delete mode 100644 ui/components/ui/sidebar/sidebar-items.tsx create mode 100644 ui/components/ui/sidebar/sidebar-toggle.tsx delete mode 100644 ui/components/ui/sidebar/sidebar-wrap.tsx delete mode 100644 ui/components/ui/sidebar/skeleton-profile.tsx delete mode 100644 ui/components/ui/sidebar/team-avatar.tsx delete mode 100644 ui/components/ui/sidebar/user-avatar.tsx create mode 100644 ui/components/ui/tooltip/tooltip.tsx create mode 100644 ui/components/ui/user-nav/user-nav.tsx create mode 100644 ui/hooks/use-sidebar.ts create mode 100644 ui/hooks/use-store.ts create mode 100644 ui/lib/menu-list.ts diff --git a/ui/app/(prowler)/categories/page.tsx b/ui/app/(prowler)/categories/page.tsx deleted file mode 100644 index 1a5650d8af..0000000000 --- a/ui/app/(prowler)/categories/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Spacer } from "@nextui-org/react"; - -import { Header } from "@/components/ui"; - -export default async function Categories() { - return ( - <> -
- - - ); -} diff --git a/ui/app/(prowler)/compliance/page.tsx b/ui/app/(prowler)/compliance/page.tsx index ce5fe18e5d..22164bbcc3 100644 --- a/ui/app/(prowler)/compliance/page.tsx +++ b/ui/app/(prowler)/compliance/page.tsx @@ -10,7 +10,7 @@ import { ComplianceSkeletonGrid, } from "@/components/compliance"; import { DataCompliance } from "@/components/compliance/data-compliance"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { ComplianceOverviewData, SearchParamsProps } from "@/types"; export default async function Compliance({ @@ -80,15 +80,13 @@ export default async function Compliance({ } return ( - <> -
- + }> - + ); } diff --git a/ui/app/(prowler)/findings/page.tsx b/ui/app/(prowler)/findings/page.tsx index 0c9b170ddd..9fa50fc115 100644 --- a/ui/app/(prowler)/findings/page.tsx +++ b/ui/app/(prowler)/findings/page.tsx @@ -11,7 +11,7 @@ import { ColumnFindings, SkeletonTableFindings, } from "@/components/findings/table"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; import { createDict } from "@/lib"; import { @@ -101,10 +101,7 @@ export default async function Findings({ completedScans?.map((scan: ScanProps) => scan.id) || []; return ( - <> -
- - + }> - + ); } diff --git a/ui/app/(prowler)/integrations/page.tsx b/ui/app/(prowler)/integrations/page.tsx index a930f1ed36..3760cae57e 100644 --- a/ui/app/(prowler)/integrations/page.tsx +++ b/ui/app/(prowler)/integrations/page.tsx @@ -1,13 +1,11 @@ import React from "react"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; export default function Integrations() { return ( - <> -
- -

Hi hi from Integration page

- + +

Integrations

+
); } diff --git a/ui/app/(prowler)/invitations/page.tsx b/ui/app/(prowler)/invitations/page.tsx index e9cc2a8cb0..b51a315d15 100644 --- a/ui/app/(prowler)/invitations/page.tsx +++ b/ui/app/(prowler)/invitations/page.tsx @@ -10,7 +10,7 @@ import { ColumnsInvitation, SkeletonTableInvitation, } from "@/components/invitations/table"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; import { InvitationProps, Role, SearchParamsProps } from "@/types"; @@ -22,9 +22,7 @@ export default async function Invitations({ const searchParamsKey = JSON.stringify(searchParams || {}); return ( - <> -
- + @@ -35,7 +33,7 @@ export default async function Invitations({ }> - + ); } diff --git a/ui/app/(prowler)/layout.tsx b/ui/app/(prowler)/layout.tsx index 2d74472428..ff931d8f19 100644 --- a/ui/app/(prowler)/layout.tsx +++ b/ui/app/(prowler)/layout.tsx @@ -1,10 +1,10 @@ import "@/styles/globals.css"; import { Metadata, Viewport } from "next"; -import React, { use } from "react"; +import React from "react"; -import { getProfileInfo } from "@/actions/users/users"; -import { SidebarWrap, Toaster } from "@/components/ui"; +import MainLayout from "@/components/ui/main-layout/main-layout"; +import { Toaster } from "@/components/ui/toast"; import { fontSans } from "@/config/fonts"; import { siteConfig } from "@/config/site"; import { cn } from "@/lib/utils"; @@ -34,8 +34,6 @@ export default function RootLayout({ }: { children: React.ReactNode; }) { - const user = use(getProfileInfo()); - return ( @@ -47,13 +45,8 @@ export default function RootLayout({ )} > -
- -
- {children} - -
-
+ {children} +
diff --git a/ui/app/(prowler)/manage-groups/layout.tsx b/ui/app/(prowler)/manage-groups/layout.tsx index a7b52289f7..7a8e214df1 100644 --- a/ui/app/(prowler)/manage-groups/layout.tsx +++ b/ui/app/(prowler)/manage-groups/layout.tsx @@ -1,9 +1,8 @@ import "@/styles/globals.css"; -import { Spacer } from "@nextui-org/react"; import React from "react"; -import { NavigationHeader } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; interface ProviderLayoutProps { children: React.ReactNode; @@ -11,14 +10,11 @@ interface ProviderLayoutProps { export default function ProviderLayout({ children }: ProviderLayoutProps) { return ( - <> - - + {children} - + ); } diff --git a/ui/app/(prowler)/page.tsx b/ui/app/(prowler)/page.tsx index 01d5f93c3d..c2dcded6c7 100644 --- a/ui/app/(prowler)/page.tsx +++ b/ui/app/(prowler)/page.tsx @@ -20,7 +20,7 @@ import { } from "@/components/overview"; import { ColumnNewFindingsToDate } from "@/components/overview/new-findings-table/table/column-new-findings-to-date"; import { SkeletonTableNewFindings } from "@/components/overview/new-findings-table/table/skeleton-table-new-findings"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { DataTable } from "@/components/ui/table"; import { createDict } from "@/lib/helper"; import { FindingProps, SearchParamsProps } from "@/types"; @@ -32,8 +32,7 @@ export default function Home({ }) { const searchParamsKey = JSON.stringify(searchParams || {}); return ( - <> -
+
@@ -67,7 +66,7 @@ export default function Home({
- +
); } diff --git a/ui/app/(prowler)/profile/page.tsx b/ui/app/(prowler)/profile/page.tsx index e09aeae757..6ea66ded18 100644 --- a/ui/app/(prowler)/profile/page.tsx +++ b/ui/app/(prowler)/profile/page.tsx @@ -1,17 +1,14 @@ -import { Spacer } from "@nextui-org/react"; import React, { Suspense } from "react"; import { getProfileInfo } from "@/actions/users/users"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { SkeletonUserInfo } from "@/components/users/profile"; import { UserInfo } from "@/components/users/profile/user-info"; import { UserProfileProps } from "@/types"; export default async function Profile() { return ( - <> -
- +
@@ -23,7 +20,7 @@ export default async function Profile() {
- +
); } diff --git a/ui/app/(prowler)/providers/page.tsx b/ui/app/(prowler)/providers/page.tsx index 54dd5214c2..bd6b0baeb8 100644 --- a/ui/app/(prowler)/providers/page.tsx +++ b/ui/app/(prowler)/providers/page.tsx @@ -9,7 +9,7 @@ import { ColumnProviders, SkeletonTableProviders, } from "@/components/providers/table"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; import { ProviderProps, SearchParamsProps } from "@/types"; @@ -21,10 +21,7 @@ export default async function Providers({ const searchParamsKey = JSON.stringify(searchParams || {}); return ( - <> -
- - +
@@ -42,7 +39,7 @@ export default async function Providers({
- +
); } diff --git a/ui/app/(prowler)/roles/page.tsx b/ui/app/(prowler)/roles/page.tsx index e7603bc9fa..f0515ea546 100644 --- a/ui/app/(prowler)/roles/page.tsx +++ b/ui/app/(prowler)/roles/page.tsx @@ -7,7 +7,7 @@ import { filterRoles } from "@/components/filters/data-filters"; import { AddRoleButton } from "@/components/roles"; import { ColumnsRoles } from "@/components/roles/table"; import { SkeletonTableRoles } from "@/components/roles/table"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; import { SearchParamsProps } from "@/types"; @@ -19,9 +19,7 @@ export default async function Roles({ const searchParamsKey = JSON.stringify(searchParams || {}); return ( - <> -
- + @@ -32,7 +30,7 @@ export default async function Roles({ }> - + ); } diff --git a/ui/app/(prowler)/scans/page.tsx b/ui/app/(prowler)/scans/page.tsx index 05435149da..ea2b812f3e 100644 --- a/ui/app/(prowler)/scans/page.tsx +++ b/ui/app/(prowler)/scans/page.tsx @@ -12,7 +12,7 @@ import { import { LaunchScanWorkflow } from "@/components/scans/launch-workflow"; import { SkeletonTableScans } from "@/components/scans/table"; import { ColumnGetScans } from "@/components/scans/table/scans"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; import { ProviderProps, ScanProps, SearchParamsProps } from "@/types"; @@ -66,23 +66,20 @@ export default async function Scans({ {!thereIsNoProviders && ( <> {thereIsNoProvidersConnected ? ( - <> -
- + - + ) : ( - <> -
+ - + )} -
+
diff --git a/ui/app/(prowler)/services/page.tsx b/ui/app/(prowler)/services/page.tsx index 7e39ad2730..5177ea2310 100644 --- a/ui/app/(prowler)/services/page.tsx +++ b/ui/app/(prowler)/services/page.tsx @@ -4,7 +4,7 @@ import { Suspense } from "react"; import { getServices } from "@/actions/services"; import { FilterControls } from "@/components/filters"; import { ServiceCard, ServiceSkeletonGrid } from "@/components/services"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { SearchParamsProps } from "@/types"; export default async function Services({ @@ -14,18 +14,17 @@ export default async function Services({ }) { const searchParamsKey = JSON.stringify(searchParams || {}); return ( - <> -
+ }> - + ); } diff --git a/ui/app/(prowler)/settings/page.tsx b/ui/app/(prowler)/settings/page.tsx deleted file mode 100644 index 6653c38b1c..0000000000 --- a/ui/app/(prowler)/settings/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Spacer } from "@nextui-org/react"; - -import { Header } from "@/components/ui"; - -export default async function Settings() { - return ( - <> -
- - - ); -} diff --git a/ui/app/(prowler)/users/page.tsx b/ui/app/(prowler)/users/page.tsx index 17c70a3cdd..b4a19ac5fc 100644 --- a/ui/app/(prowler)/users/page.tsx +++ b/ui/app/(prowler)/users/page.tsx @@ -5,7 +5,7 @@ import { getRoles } from "@/actions/roles"; import { getUsers } from "@/actions/users/users"; import { FilterControls } from "@/components/filters"; import { filterUsers } from "@/components/filters/data-filters"; -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; import { AddUserButton } from "@/components/users"; import { ColumnsUser, SkeletonTableUser } from "@/components/users/table"; @@ -19,9 +19,7 @@ export default async function Users({ const searchParamsKey = JSON.stringify(searchParams || {}); return ( - <> -
- + @@ -32,7 +30,7 @@ export default async function Users({ }> - + ); } diff --git a/ui/app/(prowler)/workloads/page.tsx b/ui/app/(prowler)/workloads/page.tsx index 3cadd0d1ca..5ffd6a9802 100644 --- a/ui/app/(prowler)/workloads/page.tsx +++ b/ui/app/(prowler)/workloads/page.tsx @@ -1,12 +1,9 @@ -import { Spacer } from "@nextui-org/react"; - -import { Header } from "@/components/ui"; +import { ContentLayout } from "@/components/ui"; export default async function Workloads() { return ( - <> -
- - + +

Workloads

+
); } diff --git a/ui/components/icons/Icons.tsx b/ui/components/icons/Icons.tsx index 963f7d9b4f..b2ebc70fd2 100644 --- a/ui/components/icons/Icons.tsx +++ b/ui/components/icons/Icons.tsx @@ -832,3 +832,171 @@ export const SpinnerIcon: React.FC = ({ ); + +export const DocIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + + + + + ); +}; + +export const APIdocIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + ); +}; + +export const SupportIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + + + ); +}; + +export const CircleHelpIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + + + ); +}; + +export const AWSIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + ); +}; + +export const AzureIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + ); +}; + +export const GCPIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + ); +}; diff --git a/ui/components/icons/prowler/ProwlerIcons.tsx b/ui/components/icons/prowler/ProwlerIcons.tsx index ae0b989e6b..4a616553a4 100644 --- a/ui/components/icons/prowler/ProwlerIcons.tsx +++ b/ui/components/icons/prowler/ProwlerIcons.tsx @@ -10,6 +10,7 @@ export const ProwlerExtended: React.FC = ({ }) => { return ( = ({ ...props }) => ( { return ( -
+
diff --git a/ui/components/ui/avatar/avatar.tsx b/ui/components/ui/avatar/avatar.tsx new file mode 100644 index 0000000000..9d43d1ccca --- /dev/null +++ b/ui/components/ui/avatar/avatar.tsx @@ -0,0 +1,50 @@ +"use client"; + +import * as AvatarPrimitive from "@radix-ui/react-avatar"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarFallback, AvatarImage }; diff --git a/ui/components/ui/button/button.tsx b/ui/components/ui/button/button.tsx new file mode 100644 index 0000000000..05c76e5127 --- /dev/null +++ b/ui/components/ui/button/button.tsx @@ -0,0 +1,58 @@ +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-default-100 text-default-900 shadow-sm dark:bg-prowler-blue-800 font-bold", + ghost: + "hover:bg-accent hover:text-accent-foreground text-default-600 hover:font-bold hover:bg-default-100 dark:hover:bg-prowler-blue-800", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/ui/components/ui/collapsible/collapsible.tsx b/ui/components/ui/collapsible/collapsible.tsx new file mode 100644 index 0000000000..1fe76f5d16 --- /dev/null +++ b/ui/components/ui/collapsible/collapsible.tsx @@ -0,0 +1,11 @@ +"use client"; + +import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"; + +const Collapsible = CollapsiblePrimitive.Root; + +const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger; + +const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent; + +export { Collapsible, CollapsibleContent, CollapsibleTrigger }; diff --git a/ui/components/ui/content-layout/content-layout.tsx b/ui/components/ui/content-layout/content-layout.tsx new file mode 100644 index 0000000000..b073c1c477 --- /dev/null +++ b/ui/components/ui/content-layout/content-layout.tsx @@ -0,0 +1,24 @@ +import { Suspense, use } from "react"; + +import { getProfileInfo } from "@/actions/users/users"; + +import { Navbar } from "../nav-bar/navbar"; +import { SkeletonContentLayout } from "./skeleton-content-layout"; +interface ContentLayoutProps { + title: string; + icon: string; + children: React.ReactNode; +} + +export function ContentLayout({ title, icon, children }: ContentLayoutProps) { + const user = use(getProfileInfo()); + + return ( + <> + }> + + +
{children}
+ + ); +} diff --git a/ui/components/ui/content-layout/skeleton-content-layout.tsx b/ui/components/ui/content-layout/skeleton-content-layout.tsx new file mode 100644 index 0000000000..712aa73eba --- /dev/null +++ b/ui/components/ui/content-layout/skeleton-content-layout.tsx @@ -0,0 +1,17 @@ +import { Skeleton } from "@nextui-org/react"; + +export const SkeletonContentLayout = () => { + return ( +
+ {/* Theme Switch Skeleton */} + +
+
+ + {/* User Avatar Skeleton */} + +
+
+
+ ); +}; diff --git a/ui/components/ui/dropdown-menu/dropdown-menu.tsx b/ui/components/ui/dropdown-menu/dropdown-menu.tsx new file mode 100644 index 0000000000..7f00df098c --- /dev/null +++ b/ui/components/ui/dropdown-menu/dropdown-menu.tsx @@ -0,0 +1,208 @@ +"use client"; + +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { + CheckIcon, + ChevronRightIcon, + DotFilledIcon, +} from "@radix-ui/react-icons"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)); +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; + +export { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +}; diff --git a/ui/components/ui/headers/header.tsx b/ui/components/ui/headers/header.tsx deleted file mode 100644 index 8bff672896..0000000000 --- a/ui/components/ui/headers/header.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Icon } from "@iconify/react"; -import { Divider } from "@nextui-org/react"; -import React from "react"; - -interface HeaderProps { - title: string; - icon: string; -} - -export const Header: React.FC = ({ title, icon }) => { - return ( - <> -
- -

{title}

-
- - - ); -}; diff --git a/ui/components/ui/index.ts b/ui/components/ui/index.ts index a6ce5369af..e9675ed837 100644 --- a/ui/components/ui/index.ts +++ b/ui/components/ui/index.ts @@ -2,11 +2,12 @@ export * from "./action-card/ActionCard"; export * from "./alert/Alert"; export * from "./alert-dialog/AlertDialog"; export * from "./chart/Chart"; +export * from "./content-layout/content-layout"; export * from "./dialog/dialog"; export * from "./dropdown/Dropdown"; -export * from "./headers/header"; export * from "./headers/navigation-header"; export * from "./label/Label"; +export * from "./main-layout/main-layout"; export * from "./select/Select"; export * from "./sidebar"; export * from "./toast"; diff --git a/ui/components/ui/main-layout/main-layout.tsx b/ui/components/ui/main-layout/main-layout.tsx new file mode 100644 index 0000000000..f5e00259c4 --- /dev/null +++ b/ui/components/ui/main-layout/main-layout.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { useSidebar } from "@/hooks/use-sidebar"; +import { useStore } from "@/hooks/use-store"; +import { cn } from "@/lib/utils"; + +import { Sidebar } from "../sidebar/sidebar"; +export default function MainLayout({ + children, +}: { + children: React.ReactNode; +}) { + const sidebar = useStore(useSidebar, (x) => x); + if (!sidebar) return null; + const { getOpenState, settings } = sidebar; + return ( +
+ +
+ {children} +
+
+ ); +} diff --git a/ui/components/ui/nav-bar/navbar.tsx b/ui/components/ui/nav-bar/navbar.tsx new file mode 100644 index 0000000000..5cebc9586f --- /dev/null +++ b/ui/components/ui/nav-bar/navbar.tsx @@ -0,0 +1,35 @@ +import { Icon } from "@iconify/react"; + +import { ThemeSwitch } from "@/components/ThemeSwitch"; +import { UserProfileProps } from "@/types"; + +import { SheetMenu } from "../sidebar/sheet-menu"; +import { UserNav } from "../user-nav/user-nav"; +interface NavbarProps { + title: string; + icon: string; + user: UserProfileProps; +} + +export function Navbar({ title, icon, user }: NavbarProps) { + return ( +
+
+
+ + +

{title}

+
+
+ + +
+
+
+ ); +} diff --git a/ui/components/ui/scroll-area/scroll-area.tsx b/ui/components/ui/scroll-area/scroll-area.tsx new file mode 100644 index 0000000000..62e20e12c7 --- /dev/null +++ b/ui/components/ui/scroll-area/scroll-area.tsx @@ -0,0 +1,48 @@ +"use client"; + +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = "vertical", ...props }, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +export { ScrollArea, ScrollBar }; diff --git a/ui/components/ui/sidebar/collapse-menu-button.tsx b/ui/components/ui/sidebar/collapse-menu-button.tsx new file mode 100644 index 0000000000..cf9450a930 --- /dev/null +++ b/ui/components/ui/sidebar/collapse-menu-button.tsx @@ -0,0 +1,185 @@ +"use client"; + +import { DropdownMenuArrow } from "@radix-ui/react-dropdown-menu"; +import { ChevronDown } from "lucide-react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { useState } from "react"; + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible/collapsible"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu/dropdown-menu"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip/tooltip"; +import { cn } from "@/lib/utils"; +import { CollapseMenuButtonProps } from "@/types"; + +import { Button } from "../button/button"; + +export const CollapseMenuButton = ({ + icon: Icon, + label, + submenus, + defaultOpen, + isOpen, +}: CollapseMenuButtonProps) => { + const pathname = usePathname(); + const isSubmenuActive = submenus.some((submenu) => + submenu.active === undefined ? submenu.href === pathname : submenu.active, + ); + const [isCollapsed, setIsCollapsed] = useState( + isSubmenuActive || defaultOpen, + ); + + return isOpen ? ( + + + + + + {submenus.map( + ({ href, label, active, icon: SubIcon, target }, index) => ( + + ), + )} + + + ) : ( + + + + + + + + + + {label} + + + + + + {label} + + + {submenus.map(({ href, label, active, icon: SubIcon }, index) => ( + + + +

{label}

+ +
+ ))} + +
+
+ ); +}; diff --git a/ui/components/ui/sidebar/index.ts b/ui/components/ui/sidebar/index.ts index 4b8fddb786..166c6083cf 100644 --- a/ui/components/ui/sidebar/index.ts +++ b/ui/components/ui/sidebar/index.ts @@ -1,6 +1,5 @@ +export * from "./collapse-menu-button"; +export * from "./menu"; +export * from "./sheet-menu"; export * from "./sidebar"; -export * from "./sidebar-items"; -export * from "./sidebar-wrap"; -export * from "./skeleton-profile"; -export * from "./team-avatar"; -export * from "./user-avatar"; +export * from "./sidebar-toggle"; diff --git a/ui/components/ui/sidebar/menu.tsx b/ui/components/ui/sidebar/menu.tsx new file mode 100644 index 0000000000..ed65bcc406 --- /dev/null +++ b/ui/components/ui/sidebar/menu.tsx @@ -0,0 +1,171 @@ +"use client"; + +import { Ellipsis, LogOut } from "lucide-react"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; + +import { logOut } from "@/actions/auth"; +import { AddIcon } from "@/components/icons"; +import { CollapseMenuButton } from "@/components/ui/sidebar/collapse-menu-button"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip/tooltip"; +import { getMenuList } from "@/lib/menu-list"; +import { cn } from "@/lib/utils"; + +import { Button } from "../button/button"; +import { CustomButton } from "../custom/custom-button"; +import { ScrollArea } from "../scroll-area/scroll-area"; + +export const Menu = ({ isOpen }: { isOpen: boolean }) => { + const pathname = usePathname(); + const menuList = getMenuList(pathname); + + return ( + <> +
+ : null} + > + {isOpen ? "Launch Scan" : } + +
+ + + +
+ + + + + + {isOpen === false && ( + Sign out + )} + + +
+ + ); +}; diff --git a/ui/components/ui/sidebar/sheet-menu.tsx b/ui/components/ui/sidebar/sheet-menu.tsx new file mode 100644 index 0000000000..43c2dc40c4 --- /dev/null +++ b/ui/components/ui/sidebar/sheet-menu.tsx @@ -0,0 +1,42 @@ +import { MenuIcon } from "lucide-react"; +import Link from "next/link"; + +import { ProwlerExtended } from "@/components/icons"; +import { + Sheet, + SheetContent, + SheetHeader, + SheetTrigger, +} from "@/components/ui/sheet"; +import { Menu } from "@/components/ui/sidebar/menu"; + +import { Button } from "../button/button"; + +export function SheetMenu() { + return ( + + + + + + + + + + + + ); +} diff --git a/ui/components/ui/sidebar/sidebar-items.tsx b/ui/components/ui/sidebar/sidebar-items.tsx deleted file mode 100644 index ce4c2b1e89..0000000000 --- a/ui/components/ui/sidebar/sidebar-items.tsx +++ /dev/null @@ -1,531 +0,0 @@ -import { Icon } from "@iconify/react"; -import { Chip } from "@nextui-org/react"; - -import { SidebarItem, SidebarItemType } from "./sidebar"; -import { TeamAvatar } from "./team-avatar"; - -/** - * Please check the https://nextui.org/docs/guide/routing to have a seamless router integration - */ - -export const items: SidebarItem[] = [ - { - key: "home", - href: "#", - icon: "solar:home-2-linear", - title: "Home", - }, - { - key: "projects", - href: "#", - icon: "solar:widget-2-outline", - title: "Projects", - endContent: ( - - ), - }, - { - key: "invitations", - href: "#", - icon: "solar:checklist-minimalistic-outline", - title: "Invitations", - endContent: ( - - ), - }, - { - key: "team", - href: "#", - icon: "solar:users-group-two-rounded-outline", - title: "Team", - }, - { - key: "tracker", - href: "#", - icon: "solar:sort-by-time-linear", - title: "Tracker", - endContent: ( - - New - - ), - }, - { - key: "analytics", - href: "#", - icon: "solar:chart-outline", - title: "Analytics", - }, - { - key: "perks", - href: "#", - icon: "solar:gift-linear", - title: "Perks", - endContent: ( - - 3 - - ), - }, - { - key: "expenses", - href: "#", - icon: "solar:bill-list-outline", - title: "Expenses", - }, - { - key: "settings", - href: "#", - icon: "solar:settings-outline", - title: "Settings", - }, -]; - -export const sectionItems: SidebarItem[] = [ - // { - // key: "dashboards", - // title: "Dashboard", - // items: [ - // { - // key: "overview", - // href: "/", - // icon: "solar:pie-chart-2-outline", - // title: "Overview", - // }, - // { - // key: "projects", - // href: "#", - // icon: "solar:widget-2-outline", - // title: "Projects", - // endContent: ( - // - // ), - // }, - // ], - // }, - - { - key: "analytics", - title: "Analytics", - items: [ - { - key: "overview", - href: "/", - icon: "solar:pie-chart-2-outline", - title: "Overview", - }, - { - key: "compliance", - href: "/compliance", - icon: "fluent-mdl2:compliance-audit", - title: "Compliance", - // endContent: ( - // - // New - // - // ), - }, - // { - // key: "services", - // href: "/services", - // icon: "material-symbols:linked-services-outline", - // title: "Services", - // }, - ], - }, - - { - key: "issues", - title: "Issues", - items: [ - { - key: "cloud-misconfigurations", - href: "/findings?filter[status__in]=FAIL&sort=severity,-inserted_at", - icon: "solar:danger-triangle-linear", - title: "Cloud Misconfigurations", - }, - { - key: "iam-issues", - href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=aws%2Cazure%2Cgcp%2Ckubernetes&filter[service__in]=iam%2Crbac&sort=-inserted_at", - icon: "solar:shield-user-linear", - title: "IAM Issues", - }, - { - key: "aws-findings", - href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=aws&sort=severity,-inserted_at", - icon: "ri:amazon-line", - title: "AWS Top Failed Findings", - }, - { - key: "azure-findings", - href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=azure&sort=severity,-inserted_at", - icon: "ri:microsoft-line", - title: "Azure Top Failed Findings", - }, - { - key: "gcp-findings", - href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=gcp&sort=severity,-inserted_at", - icon: "ri:google-line", - title: "GCP Top Failed Findings", - }, - { - key: "kubernetes-findings", - href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=kubernetes&sort=severity,-inserted_at", - icon: "ri:steering-2-line", - title: "Kubernetes Top Failed Findings", - }, - { - key: "all-findings", - href: "/findings", - icon: "solar:document-text-linear", - title: "Browse All Findings", - }, - ], - }, - - { - key: "settings", - title: "Settings", - items: [ - { - key: "providers", - href: "/providers", - icon: "fluent:cloud-sync-24-regular", - title: "Cloud Providers", - }, - { - key: "provider-groups", - href: "/manage-groups", - icon: "solar:settings-outline", - title: "Provider Groups", - }, - { - key: "scans", - href: "/scans", - icon: "lucide:scan-search", - title: "Scan Jobs", - }, - { - key: "roles", - href: "/roles", - icon: "mdi:account-key-outline", - title: "Roles", - }, - // { - // key: "integrations", - // href: "/integrations", - // icon: "tabler:puzzle", - // title: "Integrations", - // }, - ], - }, -]; - -export const sectionItemsWithTeams: SidebarItem[] = [ - ...sectionItems, - { - key: "memberships", - title: "Membership", - items: [ - { - key: "users", - href: "/users", - title: "Users", - icon: "ci:users", - }, - { - key: "invitations", - href: "/invitations", - icon: "solar:checklist-minimalistic-outline", - title: "Invitations", - }, - ], - }, -]; - -export const brandItems: SidebarItem[] = [ - { - key: "overview", - title: "Overview", - items: [ - { - key: "home", - href: "/", - icon: "solar:home-2-linear", - title: "Home", - }, - { - key: "projects", - href: "#", - icon: "solar:widget-2-outline", - title: "Projects", - endContent: ( - - ), - }, - { - key: "tasks", - href: "#", - icon: "solar:checklist-minimalistic-outline", - title: "Tasks", - endContent: ( - - ), - }, - { - key: "team", - href: "#", - icon: "solar:users-group-two-rounded-outline", - title: "Team", - }, - { - key: "tracker", - href: "#", - icon: "solar:sort-by-time-linear", - title: "Tracker", - endContent: ( - - New - - ), - }, - ], - }, - { - key: "your-teams", - title: "Your Teams", - items: [ - { - key: "nextui", - href: "#", - title: "NextUI", - startContent: ( - - ), - }, - { - key: "tailwind-variants", - href: "#", - title: "Tailwind Variants", - startContent: ( - - ), - }, - { - key: "nextui-pro", - href: "#", - title: "NextUI Pro", - startContent: ( - - ), - }, - ], - }, -]; - -export const sectionLongList: SidebarItem[] = [ - ...sectionItems, - { - key: "payments", - title: "Payments", - items: [ - { - key: "payroll", - href: "#", - title: "Payroll", - icon: "solar:dollar-minimalistic-linear", - }, - { - key: "invoices", - href: "#", - title: "Invoices", - icon: "solar:file-text-linear", - }, - { - key: "billing", - href: "#", - title: "Billing", - icon: "solar:card-outline", - }, - { - key: "payment-methods", - href: "#", - title: "Payment Methods", - icon: "solar:wallet-money-outline", - }, - { - key: "payouts", - href: "#", - title: "Payouts", - icon: "solar:card-transfer-outline", - }, - ], - }, - { - key: "your-teams", - title: "Your Teams", - items: [ - { - key: "nextui", - href: "#", - title: "NextUI", - startContent: , - }, - { - key: "tailwind-variants", - href: "#", - title: "Tailwind Variants", - startContent: , - }, - { - key: "nextui-pro", - href: "#", - title: "NextUI Pro", - startContent: , - }, - ], - }, -]; - -export const sectionNestedItems: SidebarItem[] = [ - { - key: "home", - href: "#", - icon: "solar:home-2-linear", - title: "Home", - }, - { - key: "projects", - href: "#", - icon: "solar:widget-2-outline", - title: "Projects", - endContent: ( - - ), - }, - { - key: "tasks", - href: "#", - icon: "solar:checklist-minimalistic-outline", - title: "Tasks", - endContent: ( - - ), - }, - { - key: "team", - href: "#", - icon: "solar:users-group-two-rounded-outline", - title: "Team", - }, - { - key: "tracker", - href: "#", - icon: "solar:sort-by-time-linear", - title: "Tracker", - endContent: ( - - New - - ), - }, - { - key: "analytics", - href: "#", - icon: "solar:chart-outline", - title: "Analytics", - }, - { - key: "perks", - href: "#", - icon: "solar:gift-linear", - title: "Perks", - endContent: ( - - 3 - - ), - }, - { - key: "cap_table", - title: "Cap Table", - icon: "solar:pie-chart-2-outline", - type: SidebarItemType.Nest, - items: [ - { - key: "shareholders", - icon: "solar:users-group-rounded-linear", - href: "#", - title: "Shareholders", - }, - { - key: "note_holders", - icon: "solar:notes-outline", - href: "#", - title: "Note Holders", - }, - { - key: "transactions_log", - icon: "solar:clipboard-list-linear", - href: "#", - title: "Transactions Log", - }, - ], - }, - { - key: "expenses", - href: "#", - icon: "solar:bill-list-outline", - title: "Expenses", - }, -]; diff --git a/ui/components/ui/sidebar/sidebar-toggle.tsx b/ui/components/ui/sidebar/sidebar-toggle.tsx new file mode 100644 index 0000000000..751cf9ebac --- /dev/null +++ b/ui/components/ui/sidebar/sidebar-toggle.tsx @@ -0,0 +1,29 @@ +import { ChevronLeft } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +import { Button } from "../button/button"; +interface SidebarToggleProps { + isOpen: boolean | undefined; + setIsOpen?: () => void; +} + +export function SidebarToggle({ isOpen, setIsOpen }: SidebarToggleProps) { + return ( +
+ +
+ ); +} diff --git a/ui/components/ui/sidebar/sidebar-wrap.tsx b/ui/components/ui/sidebar/sidebar-wrap.tsx deleted file mode 100644 index ac6bd4d355..0000000000 --- a/ui/components/ui/sidebar/sidebar-wrap.tsx +++ /dev/null @@ -1,370 +0,0 @@ -"use client"; - -import { Icon } from "@iconify/react"; -import { Button, ScrollShadow, Spacer, Tooltip } from "@nextui-org/react"; -import clsx from "clsx"; -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import React, { useCallback } from "react"; -import { useMediaQuery } from "usehooks-ts"; - -import { logOut } from "@/actions/auth"; -import { AddIcon } from "@/components/icons"; -import { useUIStore } from "@/store"; -import { UserProfileProps } from "@/types"; - -import { - ProwlerExtended, - ProwlerShort, -} from "../../icons/prowler/ProwlerIcons"; -import { ThemeSwitch } from "../../ThemeSwitch"; -import { CustomButton } from "../custom"; -import Sidebar from "./sidebar"; -import { sectionItemsWithTeams } from "./sidebar-items"; -import { SkeletonProfile } from "./skeleton-profile"; -import { UserAvatar } from "./user-avatar"; - -export const SidebarWrap = ({ user }: { user: UserProfileProps }) => { - const pathname = usePathname(); - const isCollapsed = useUIStore((state) => state.isSideMenuOpen); - const openSideMenu = useUIStore((state) => state.openSideMenu); - const closeSideMenu = useUIStore((state) => state.closeSideMenu); - - const isMobile = useMediaQuery("(max-width: 768px)"); - const isCompact = isCollapsed || isMobile; - - const onToggle = useCallback(() => { - if (!isCollapsed) openSideMenu(); - if (isCollapsed) closeSideMenu(); - }, [isCollapsed, openSideMenu, closeSideMenu]); - - const currentPath = pathname === "/" ? "overview" : pathname.split("/")?.[1]; - - return ( -
-
- -
- -
-
- -
- - - {!user ? ( - - ) : ( - - )} - -
- } - > - Launch Scan - -
-
- - - - - -
- - - - - - - - - - - {/* - - */} - - - - -
-
- -
- -
-
- - - -
-
- ); -}; diff --git a/ui/components/ui/sidebar/sidebar.tsx b/ui/components/ui/sidebar/sidebar.tsx index bbd2943aa4..e4c7a21cba 100644 --- a/ui/components/ui/sidebar/sidebar.tsx +++ b/ui/components/ui/sidebar/sidebar.tsx @@ -1,330 +1,73 @@ "use client"; -import { Icon } from "@iconify/react"; -import { - Accordion, - AccordionItem, - type ListboxProps, - type ListboxSectionProps, - type Selection, -} from "@nextui-org/react"; -import { - Listbox, - ListboxItem, - ListboxSection, - Tooltip, -} from "@nextui-org/react"; import clsx from "clsx"; -import React, { useState } from "react"; - -export enum SidebarItemType { - Nest = "nest", -} - -export type SidebarItem = { - key: string; - title: string; - icon?: string; - href?: string; - type?: SidebarItemType.Nest; - startContent?: React.ReactNode; - endContent?: React.ReactNode; - items?: SidebarItem[]; - className?: string; -}; - -export type SidebarProps = Omit, "children"> & { - items: SidebarItem[]; - isCompact?: boolean; - hideEndContent?: boolean; - iconClassName?: string; - sectionClasses?: ListboxSectionProps["classNames"]; - classNames?: ListboxProps["classNames"]; - defaultSelectedKey: string; - onSelect?: (key: string) => void; -}; - -const Sidebar = React.forwardRef( - ( - { - items, - isCompact, - defaultSelectedKey, - onSelect, - hideEndContent, - sectionClasses: sectionClassesProp = {}, - itemClasses: itemClassesProp = {}, - iconClassName, - classNames, - className, - ...props - }, - ref, - ) => { - const [selected, setSelected] = useState(defaultSelectedKey); - - const sectionClasses = { - ...sectionClassesProp, - base: clsx(sectionClassesProp?.base, "w-full", { - "p-0 max-w-[44px]": isCompact, - }), - group: clsx(sectionClassesProp?.group, { - "flex flex-col gap-1": isCompact, - }), - heading: clsx(sectionClassesProp?.heading, { - hidden: isCompact, - }), - }; - - const itemClasses = { - ...itemClassesProp, - base: clsx(itemClassesProp?.base, { - "w-11 h-11 gap-0 p-0": isCompact, - }), - }; - - const renderNestItem: (item: SidebarItem) => JSX.Element = - React.useCallback( - (item) => { - const isNestType = - item.items && - item.items?.length > 0 && - item?.type === SidebarItemType.Nest; - - if (isNestType) { - // Is a nest type item , so we need to remove the href - delete item.href; - } - - return ( - - ) : ( - (item.startContent ?? null) - ) - } - title={isCompact || isNestType ? null : item.title} - > - {isCompact ? ( - -
- {item.icon ? ( - - ) : ( - (item.startContent ?? null) - )} -
-
- ) : null} - {!isCompact && isNestType ? ( - - -
- ) : ( - (item.startContent ?? null) - ) - } - > - {item.items && item.items?.length > 0 ? ( - - {item.items.map(renderItem)} - - ) : ( - renderItem(item) - )} - - - ) : null} - - ); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [isCompact, hideEndContent, iconClassName], - ); - - const renderItem: (item: SidebarItem) => JSX.Element = React.useCallback( - (item) => { - const isNestType = - item.items && - item.items?.length > 0 && - item?.type === SidebarItemType.Nest; - - if (isNestType) { - return renderNestItem(item); - } - - return ( - - ) : ( - (item.startContent ?? null) - ) - } - textValue={item.title} - title={isCompact ? null : item.title} - > - {isCompact ? ( - -
- {item.icon ? ( - - ) : ( - (item.startContent ?? null) - )} -
-
- ) : null} -
- ); - }, - [isCompact, hideEndContent, iconClassName, renderNestItem], - ); - - return ( - { - const key = Array.from(keys)[0]; - - setSelected(key as React.Key); - onSelect?.(key as string); - }} - {...props} +import Link from "next/link"; + +import { ProwlerShort } from "@/components/icons"; +import { ProwlerExtended } from "@/components/icons"; +import { useSidebar } from "@/hooks/use-sidebar"; +import { useStore } from "@/hooks/use-store"; +import { cn } from "@/lib/utils"; + +import { Button } from "../button/button"; +import { Menu } from "./menu"; +import { SidebarToggle } from "./sidebar-toggle"; + +export function Sidebar() { + const sidebar = useStore(useSidebar, (x) => x); + if (!sidebar) return null; + const { isOpen, toggleOpen, getOpenState, setIsHover, settings } = sidebar; + return ( + + ); +} diff --git a/ui/components/ui/sidebar/skeleton-profile.tsx b/ui/components/ui/sidebar/skeleton-profile.tsx deleted file mode 100644 index 2268352233..0000000000 --- a/ui/components/ui/sidebar/skeleton-profile.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Skeleton } from "@nextui-org/react"; - -export const SkeletonProfile = () => { - return ( -
- -
-
-
- -
-
- -
-
-
-
- ); -}; diff --git a/ui/components/ui/sidebar/team-avatar.tsx b/ui/components/ui/sidebar/team-avatar.tsx deleted file mode 100644 index 14122c7b30..0000000000 --- a/ui/components/ui/sidebar/team-avatar.tsx +++ /dev/null @@ -1,35 +0,0 @@ -"use client"; - -import type { AvatarProps } from "@nextui-org/react"; -import { Avatar } from "@nextui-org/react"; -import clsx from "clsx"; -import React from "react"; - -export const TeamAvatar = React.forwardRef( - ({ name, className, classNames = {}, ...props }, ref) => ( - - (name[0] || "") + (name[name.lastIndexOf(" ") + 1] || "").toUpperCase() - } - name={name} - radius="md" - size="sm" - /> - ), -); - -TeamAvatar.displayName = "TeamAvatar"; diff --git a/ui/components/ui/sidebar/user-avatar.tsx b/ui/components/ui/sidebar/user-avatar.tsx deleted file mode 100644 index 83745f7bc3..0000000000 --- a/ui/components/ui/sidebar/user-avatar.tsx +++ /dev/null @@ -1,32 +0,0 @@ -"use client"; - -import { Avatar } from "@nextui-org/react"; -import clsx from "clsx"; -import React from "react"; - -interface UserAvatarProps { - userName: string; - position: string; - isCompact: boolean; -} -export const UserAvatar: React.FC = ({ - userName, - position, - isCompact = false, -}) => { - return ( -
- -
-

- {userName} -

-

{position}

-
-
- ); -}; diff --git a/ui/components/ui/tooltip/tooltip.tsx b/ui/components/ui/tooltip/tooltip.tsx new file mode 100644 index 0000000000..41c4348b89 --- /dev/null +++ b/ui/components/ui/tooltip/tooltip.tsx @@ -0,0 +1,30 @@ +"use client"; + +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const TooltipProvider = TooltipPrimitive.Provider; + +const Tooltip = TooltipPrimitive.Root; + +const TooltipTrigger = TooltipPrimitive.Trigger; + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; + +export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }; diff --git a/ui/components/ui/user-nav/user-nav.tsx b/ui/components/ui/user-nav/user-nav.tsx new file mode 100644 index 0000000000..b5023a9ece --- /dev/null +++ b/ui/components/ui/user-nav/user-nav.tsx @@ -0,0 +1,98 @@ +"use client"; + +import { LogOut, User } from "lucide-react"; +import Link from "next/link"; + +import { logOut } from "@/actions/auth"; +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/components/ui/avatar/avatar"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu/dropdown-menu"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip/tooltip"; +import { UserProfileProps } from "@/types"; + +import { Button } from "../button/button"; + +export const UserNav = ({ user }: { user?: UserProfileProps }) => { + if (!user || !user.data) return null; + + const { name, email, company_name } = user.data.attributes; + + return ( + + + + + + + + + Profile + + + + + +
+

+ {name} + {company_name && ( + {` | ${company_name}`} + )} +

+

+ {email} +

+
+
+ + + + + + Account + + + + + logOut()} + > + + Sign out + +
+
+ ); +}; diff --git a/ui/hooks/index.ts b/ui/hooks/index.ts index 709aadd864..2d03f3ba70 100644 --- a/ui/hooks/index.ts +++ b/ui/hooks/index.ts @@ -1 +1,3 @@ +export * from "./use-sidebar"; +export * from "./use-store"; export * from "./useLocalStorage"; diff --git a/ui/hooks/use-sidebar.ts b/ui/hooks/use-sidebar.ts new file mode 100644 index 0000000000..feaf5af9f2 --- /dev/null +++ b/ui/hooks/use-sidebar.ts @@ -0,0 +1,49 @@ +import { produce } from "immer"; +import { create } from "zustand"; +import { createJSONStorage, persist } from "zustand/middleware"; + +type SidebarSettings = { disabled: boolean; isHoverOpen: boolean }; +type SidebarStore = { + isOpen: boolean; + isHover: boolean; + settings: SidebarSettings; + toggleOpen: () => void; + setIsOpen: (isOpen: boolean) => void; + setIsHover: (isHover: boolean) => void; + getOpenState: () => boolean; + setSettings: (settings: Partial) => void; +}; + +export const useSidebar = create( + persist( + (set, get) => ({ + isOpen: true, + isHover: false, + settings: { disabled: false, isHoverOpen: false }, + toggleOpen: () => { + set({ isOpen: !get().isOpen }); + }, + setIsOpen: (isOpen: boolean) => { + set({ isOpen }); + }, + setIsHover: (isHover: boolean) => { + set({ isHover }); + }, + getOpenState: () => { + const state = get(); + return state.isOpen || (state.settings.isHoverOpen && state.isHover); + }, + setSettings: (settings: Partial) => { + set( + produce((state: SidebarStore) => { + state.settings = { ...state.settings, ...settings }; + }), + ); + }, + }), + { + name: "sidebar", + storage: createJSONStorage(() => localStorage), + }, + ), +); diff --git a/ui/hooks/use-store.ts b/ui/hooks/use-store.ts new file mode 100644 index 0000000000..7318c41d96 --- /dev/null +++ b/ui/hooks/use-store.ts @@ -0,0 +1,17 @@ +import { useEffect, useState } from "react"; +/** + * This hook fix hydration when use persist to save hook data to localStorage + */ +export const useStore = ( + store: (callback: (state: T) => unknown) => unknown, + callback: (state: T) => F, +) => { + const result = store(callback) as F; + const [data, setData] = useState(); + + useEffect(() => { + setData(result); + }, [result]); + + return data; +}; diff --git a/ui/lib/index.ts b/ui/lib/index.ts index 56ebefcc21..6560f7b5a9 100644 --- a/ui/lib/index.ts +++ b/ui/lib/index.ts @@ -1,2 +1,3 @@ export * from "./helper"; +export * from "./menu-list"; export * from "./utils"; diff --git a/ui/lib/menu-list.ts b/ui/lib/menu-list.ts new file mode 100644 index 0000000000..bae5330fe0 --- /dev/null +++ b/ui/lib/menu-list.ts @@ -0,0 +1,185 @@ +"use client"; + +import { + AlertCircle, + Bookmark, + Boxes, + CloudCog, + Group, + LayoutGrid, + Mail, + Settings, + ShieldCheck, + SquareChartGantt, + SquarePen, + Tag, + Timer, + User, + UserCog, + Users, +} from "lucide-react"; + +import { + APIdocIcon, + AWSIcon, + AzureIcon, + CircleHelpIcon, + DocIcon, + GCPIcon, + SupportIcon, +} from "@/components/icons/Icons"; +import { GroupProps } from "@/types"; + +export const getMenuList = (pathname: string): GroupProps[] => { + return [ + { + groupLabel: "", + menus: [ + { + href: "", + label: "Analytics", + icon: LayoutGrid, + submenus: [ + { + href: "/", + label: "Overview", + icon: SquareChartGantt, + active: pathname === "/", + }, + { + href: "/compliance", + label: "Compliance", + icon: ShieldCheck, + active: pathname === "/compliance", + }, + ], + defaultOpen: true, + }, + ], + }, + + { + groupLabel: "Issues", + menus: [ + { + href: "", + label: "Top failed issues", + icon: Bookmark, + submenus: [ + { + href: "/findings?filter[status__in]=FAIL&sort=severity,-inserted_at", + label: "Misconfigurations", + icon: AlertCircle, + }, + { + href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=aws%2Cazure%2Cgcp%2Ckubernetes&filter[service__in]=iam%2Crbac&sort=-inserted_at", + label: "IAM Issues", + icon: ShieldCheck, + }, + ], + defaultOpen: false, + }, + { + href: "", + label: "High-risk findings", + icon: SquarePen, + submenus: [ + { + href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=aws&sort=severity,-inserted_at", + label: "Amazon Web Services", + icon: AWSIcon, + }, + { + href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=azure&sort=severity,-inserted_at", + label: "Microsoft Azure", + icon: AzureIcon, + }, + { + href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=gcp&sort=severity,-inserted_at", + label: "Google Cloud", + icon: GCPIcon, + }, + { + href: "/findings?filter[status__in]=FAIL&filter[severity__in]=critical%2Chigh%2Cmedium&filter[provider_type__in]=kubernetes&sort=severity,-inserted_at", + label: "Kubernetes", + icon: Boxes, + }, + ], + defaultOpen: false, + }, + { + href: "/findings", + label: "Browse all findings", + icon: Tag, + }, + ], + }, + + { + groupLabel: "Settings", + menus: [ + { + href: "", + label: "Configuration", + icon: Settings, + submenus: [ + { href: "/providers", label: "Cloud Providers", icon: CloudCog }, + { href: "/manage-groups", label: "Provider Groups", icon: Group }, + { href: "/scans", label: "Scan Jobs", icon: Timer }, + { href: "/roles", label: "Roles", icon: UserCog }, + ], + defaultOpen: true, + }, + ], + }, + { + groupLabel: "Workspace", + menus: [ + { + href: "", + label: "Memberships", + icon: Users, + submenus: [ + { href: "/users", label: "Users", icon: User }, + { href: "/invitations", label: "Invitations", icon: Mail }, + ], + defaultOpen: false, + }, + ], + }, + { + groupLabel: "", + menus: [ + { + href: "", + label: "Support & Help", + icon: SupportIcon, + submenus: [ + { + href: "https://docs.prowler.com/", + target: "_blank", + label: "Documentation", + icon: DocIcon, + }, + { + href: + process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true" + ? "https://api.prowler.com/api/v1/docs" + : `${process.env.NEXT_PUBLIC_API_DOCS_URL}`, + target: "_blank", + label: "API reference", + icon: APIdocIcon, + }, + { + href: "https://github.com/prowler-cloud/prowler/issues", + target: "_blank", + label: "Support", + icon: CircleHelpIcon, + }, + ], + defaultOpen: false, + }, + ], + }, + ]; +}; diff --git a/ui/package-lock.json b/ui/package-lock.json index fe7529820a..9e8848a1d0 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -31,6 +31,7 @@ "cmdk": "^1.0.0", "date-fns": "^4.1.0", "framer-motion": "^11.16.0", + "immer": "^10.1.1", "intl-messageformat": "^10.5.0", "jose": "^5.9.3", "jwt-decode": "^4.0.0", @@ -38,6 +39,7 @@ "next": "^14.2.22", "next-auth": "^5.0.0-beta.25", "next-themes": "^0.2.1", + "radix-ui": "^1.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.52.2", @@ -4396,22 +4398,18 @@ "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==" }, "node_modules/@radix-ui/primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", - "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" - }, - "node_modules/@radix-ui/react-alert-dialog": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.1.tgz", - "integrity": "sha512-wmCoJwj7byuVuiLKqDLlX7ClSUU0vd9sdCeM+2Ls+uf13+cpSJoMgwysHq1SGVVkJj5Xn0XWi1NoRCdkMpr6Mw==", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.2.tgz", + "integrity": "sha512-+rnMO0SEfzkcHr93RshkQVpOA26MtGOv4pcS9QUnLg4F8+GDmCJ8c2FEPhPz5e7arf31EzbTqJxFbzg3qen14g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dialog": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0" + "@radix-ui/react-visually-hidden": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -4428,26 +4426,21 @@ } } }, - "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", - "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.3.tgz", + "integrity": "sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collapsible": "1.1.3", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -4464,54 +4457,41 @@ } } }, - "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.6.tgz", + "integrity": "sha512-p4XnPqgej8sZAAReCAKgz1REYZEBLR8hU9Pg27wFnCWIMc8g1ccCs0FjBcy05V15VTu8pAePw/VDYeOm/uZ6yQ==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dialog": "1.1.6", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - } - } - }, - "node_modules/@radix-ui/react-alert-dialog/node_modules/react-remove-scroll": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", - "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.4", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { + }, + "@types/react-dom": { "optional": true } } }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", - "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz", + "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==", + "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -4528,15 +4508,13 @@ } } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", - "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.2.tgz", + "integrity": "sha512-TaJxYoCpxJ7vfEkv2PTNox/6zzmpKXT6ewvCuf2tTOIVN45/Jahhlld29Yw4pciOXS2Xq91/rSGEdmEnUWZCqA==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -4553,71 +4531,46 @@ } } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.3.tgz", + "integrity": "sha512-Paen00T4P8L8gd9bNsRMw7Cbaz85oxiv+hzomsRZgFm2byltPFDtfcoqlWJ8GyZlIBWgLssJlzLCnKU0G0302g==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", - "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - } - } - }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", - "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { + }, + "@types/react-dom": { "optional": true } } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz", - "integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==", + "node_modules/@radix-ui/react-checkbox": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.4.tgz", + "integrity": "sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.1", - "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.2", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.6.0" + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -4634,32 +4587,46 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", - "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.3.tgz", + "integrity": "sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw==", "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz", - "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==", + "node_modules/@radix-ui/react-collection": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz", + "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -4676,10 +4643,10 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-guards": { + "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", - "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -4691,38 +4658,33 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz", - "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==", + "node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", - "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.6.tgz", + "integrity": "sha512-aUP99QZ3VU84NPsHeaFt4cQUNgJqFsLLOt/RbbWXszZ6MP0DpDyjkFZORr4RpAEx3sUBk+Kc8h13yGtC5Qw8dg==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-menu": "2.1.6", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -4739,44 +4701,38 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz", + "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - } - } - }, - "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz", - "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.6", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { + }, + "@types/react-dom": { "optional": true } } @@ -4796,13 +4752,14 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", - "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", + "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", + "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, @@ -4822,17 +4779,17 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz", - "integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.6.tgz", + "integrity": "sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-menu": "2.1.1", - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-menu": "2.1.6", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { @@ -4851,9 +4808,10 @@ } }, "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", - "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -4865,12 +4823,13 @@ } }, "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", - "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz", + "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { @@ -4888,6 +4847,65 @@ } } }, + "node_modules/@radix-ui/react-form": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.2.tgz", + "integrity": "sha512-Owj1MjLq6/Rp85bgzYI+zRK5APLiWDtXDM63Z39FW15bNdehrcS+FjQgLGQYswFzipYu4GAA+t5w/VqvvNZ3ag==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-label": "2.1.2", + "@radix-ui/react-primitive": "2.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.6.tgz", + "integrity": "sha512-E4ozl35jq0VRlrdc4dhHrNSV0JqBb4Jy73WAhBEK7JoYnQ83ED5r0Rb/XdVKw89ReAJN38N492BAPBZQ57VmqQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-icons": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", @@ -4915,12 +4933,12 @@ } }, "node_modules/@radix-ui/react-label": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", - "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.2.tgz", + "integrity": "sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -4938,29 +4956,29 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz", - "integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.6.tgz", + "integrity": "sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-roving-focus": "1.1.0", - "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-callback-ref": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", @@ -4977,58 +4995,122 @@ } } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.6.tgz", + "integrity": "sha512-FHq7+3DlXwh/7FOM4i0G4bC4vPjiq89VEEvNF4VMLchGnaUuUbE5uKXMUCjdKaOghEEMeiKa5XCa2Pk4kteWmg==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-menu": "2.1.6", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-menu/node_modules/react-remove-scroll": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", - "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.5.tgz", + "integrity": "sha512-myMHHQUZ3ZLTi8W381/Vu43Ia0NqakkQZ2vzynMmTUtQQ9kNkjzhOwkZC9TAM5R07OZUVIQyHC06f/9JZJpvvA==", "license": "MIT", "dependencies": { - "react-remove-scroll-bar": "^2.3.4", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.2" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.6.tgz", + "integrity": "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, "node_modules/@radix-ui/react-popper": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", - "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz", + "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==", + "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-arrow": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-rect": "1.1.0", @@ -5050,12 +5132,37 @@ } } }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", - "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", + "node_modules/@radix-ui/react-portal": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", + "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { @@ -5073,13 +5180,13 @@ } } }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", - "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0" + "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -5096,12 +5203,14 @@ } } }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", - "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "node_modules/@radix-ui/react-progress": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.2.tgz", + "integrity": "sha512-u1IgJFQ4zNAUTjGdDL5dcl/U8ntOR6jsnhxKb5RKp5Ozwl88xKR9EqRZOe/Mk8tnx0x5tNUe2F+MzsyjqMg0MA==", + "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.1.0" + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -5118,36 +5227,51 @@ } } }, - "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "node_modules/@radix-ui/react-radio-group": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.2.3.tgz", + "integrity": "sha512-xtCsqt8Rp09FK50ItqEqTJ7Sxanz8EM8dnkVIhJrc/wkMMomSmXHvYbhv3E7Zx4oXh98aaLt9W679SUYXg4IDA==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", - "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz", + "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, @@ -5166,32 +5290,21 @@ } } }, - "node_modules/@radix-ui/react-select": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.1.tgz", - "integrity": "sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==", + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.3.tgz", + "integrity": "sha512-l7+NNBfBYYJa9tNqVcP2AGvxdE3lmE6kFTBXdvHgUaZuy+4wGCL1Cl2AfaR7RKyimj7lZURGLwFO59k4eBnDJQ==", + "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.0", - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-use-previous": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" + "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -5208,68 +5321,113 @@ } } }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "node_modules/@radix-ui/react-select": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.6.tgz", + "integrity": "sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-select/node_modules/react-remove-scroll": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", - "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "node_modules/@radix-ui/react-separator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.2.tgz", + "integrity": "sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==", + "license": "MIT", "dependencies": { - "react-remove-scroll-bar": "^2.3.4", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", - "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "node_modules/@radix-ui/react-slider": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.2.3.tgz", + "integrity": "sha512-nNrLAWLjGESnhqBqcCNW4w2nn7LxudyMzeB6VgdyAnFLC6kfQgnAjSL2v6UkQTnDctJBlxrmxfplWS4iYjdUTw==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1" + "@radix-ui/number": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-slot/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", - "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "node_modules/@radix-ui/react-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", + "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -5280,23 +5438,19 @@ } } }, - "node_modules/@radix-ui/react-toast": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.4.tgz", - "integrity": "sha512-Sch9idFJHJTMH9YNpxxESqABcAFweJG4tKv+0zo0m5XBvUSL8FM5xKcJLFLXononpePs8IclyX1KieL5SDUNgA==", + "node_modules/@radix-ui/react-switch": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.3.tgz", + "integrity": "sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-collection": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.3", - "@radix-ui/react-portal": "1.1.3", - "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.1" + "@radix-ui/react-use-previous": "1.1.0", + "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -5313,20 +5467,20 @@ } } }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", - "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==" - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-collection": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", - "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==", + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz", + "integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/primitive": "1.1.1", "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-slot": "1.1.1" + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -5343,44 +5497,24 @@ } } }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", - "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-context": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", - "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", - "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "node_modules/@radix-ui/react-toast": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.6.tgz", + "integrity": "sha512-gN4dpuIVKEgpLn1z5FhzT9mYRUitbfZq9XqN/7kkBMUgFTzTG8x/KszWJugJXHcwxckY8xcKDZPz7kG3o6DsUA==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -5397,13 +5531,15 @@ } } }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-portal": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", - "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.2.tgz", + "integrity": "sha512-lntKchNWx3aCHuWKiDY+8WudiegQvBpDRAYL8dKLRvKEH8VOpl0XX6SSU/bUBqIRJbcTy4+MW06Wv8vgp10rzQ==", + "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-layout-effect": "1.1.0" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -5420,13 +5556,19 @@ } } }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-presence": { + "node_modules/@radix-ui/react-toggle-group": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", - "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.2.tgz", + "integrity": "sha512-JBm6s6aVG/nwuY5eadhU2zDi/IwYS0sDM5ZWb4nymv/hn3hZdkw+gENn0LP4iY1yCd7+bgJaCwueMYJIU3vk4A==", + "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.0" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-toggle": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -5443,12 +5585,19 @@ } } }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", - "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.2.tgz", + "integrity": "sha512-wT20eQ7ScFk+kBMDmHp+lMk18cgxhu35b2Bn5deUcPxiVwfn5vuZgi7NGcHu8ocdkinahmp4FaSZysKDyRVPWQ==", + "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.1.1" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-separator": "1.1.2", + "@radix-ui/react-toggle-group": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -5465,12 +5614,24 @@ } } }, - "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-visually-hidden": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz", - "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==", + "node_modules/@radix-ui/react-tooltip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz", + "integrity": "sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==", + "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -5598,11 +5759,12 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", - "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz", + "integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==", + "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -10830,6 +10992,16 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -13016,6 +13188,78 @@ } ] }, + "node_modules/radix-ui": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.1.3.tgz", + "integrity": "sha512-W8L6soM1vQnIXVvVa31AkQhoZBDPwVoNHhT13R3aB9Qq7ARYIUS9DLaCopRBsbTdZm1NEEPx3rnq659CiNOBDw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-accessible-icon": "1.1.2", + "@radix-ui/react-accordion": "1.2.3", + "@radix-ui/react-alert-dialog": "1.1.6", + "@radix-ui/react-aspect-ratio": "1.1.2", + "@radix-ui/react-avatar": "1.1.3", + "@radix-ui/react-checkbox": "1.1.4", + "@radix-ui/react-collapsible": "1.1.3", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-context-menu": "2.2.6", + "@radix-ui/react-dialog": "1.1.6", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-dropdown-menu": "2.1.6", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-form": "0.1.2", + "@radix-ui/react-hover-card": "1.1.6", + "@radix-ui/react-label": "2.1.2", + "@radix-ui/react-menu": "2.1.6", + "@radix-ui/react-menubar": "1.1.6", + "@radix-ui/react-navigation-menu": "1.2.5", + "@radix-ui/react-popover": "1.1.6", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-progress": "1.1.2", + "@radix-ui/react-radio-group": "1.2.3", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-scroll-area": "1.2.3", + "@radix-ui/react-select": "2.1.6", + "@radix-ui/react-separator": "1.1.2", + "@radix-ui/react-slider": "1.2.3", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-switch": "1.1.3", + "@radix-ui/react-tabs": "1.1.3", + "@radix-ui/react-toast": "1.2.6", + "@radix-ui/react-toggle": "1.1.2", + "@radix-ui/react-toggle-group": "1.1.2", + "@radix-ui/react-toolbar": "1.1.2", + "@radix-ui/react-tooltip": "1.1.8", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -13060,16 +13304,16 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-remove-scroll": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", - "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.1", + "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.2" + "use-sidecar": "^1.1.3" }, "engines": { "node": ">=10" @@ -14624,9 +14868,10 @@ } }, "node_modules/use-sidecar": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", - "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" @@ -14635,8 +14880,8 @@ "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { diff --git a/ui/package.json b/ui/package.json index d1a72e5458..2a7f862873 100644 --- a/ui/package.json +++ b/ui/package.json @@ -23,6 +23,7 @@ "cmdk": "^1.0.0", "date-fns": "^4.1.0", "framer-motion": "^11.16.0", + "immer": "^10.1.1", "intl-messageformat": "^10.5.0", "jose": "^5.9.3", "jwt-decode": "^4.0.0", @@ -30,6 +31,7 @@ "next": "^14.2.22", "next-auth": "^5.0.0-beta.25", "next-themes": "^0.2.1", + "radix-ui": "^1.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.52.2", diff --git a/ui/tailwind.config.js b/ui/tailwind.config.js index df4c5a6301..8245f1971f 100644 --- a/ui/tailwind.config.js +++ b/ui/tailwind.config.js @@ -141,6 +141,14 @@ module.exports = { from: { height: "var(--radix-accordion-content-height)" }, to: { height: "0" }, }, + "collapsible-down": { + from: { height: "0" }, + to: { height: "var(--radix-collapsible-content-height)" }, + }, + "collapsible-up": { + from: { height: "var(--radix-collapsible-content-height)" }, + to: { height: "0" }, + }, advance: { from: { width: 0 }, to: { width: "100%" } }, "fade-in": { from: { opacity: 0 }, to: { opacity: 1 } }, "fade-out": { from: { opacity: 1 }, to: { opacity: 0 } }, @@ -164,8 +172,8 @@ module.exports = { }, }, animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", + "collapsible-down": "collapsible-down 0.2s ease-out", + "collapsible-up": "collapsible-up 0.2s ease-out", }, screens: { "3xl": "1920px", // Add breakpoint to optimize layouts for large screens. diff --git a/ui/types/components.ts b/ui/types/components.ts index 6818f3199c..312cb51a18 100644 --- a/ui/types/components.ts +++ b/ui/types/components.ts @@ -1,3 +1,4 @@ +import { LucideIcon } from "lucide-react"; import { SVGProps } from "react"; export type IconSvgProps = SVGProps & { @@ -9,6 +10,38 @@ export type IconProps = { style?: React.CSSProperties; }; +export type IconComponent = LucideIcon | React.FC; + +export type SubmenuProps = { + href: string; + target?: string; + label: string; + active?: boolean; + icon: IconComponent; +}; + +export type MenuProps = { + href: string; + label: string; + active?: boolean; + icon: IconComponent; + submenus?: SubmenuProps[]; + defaultOpen?: boolean; +}; + +export type GroupProps = { + groupLabel: string; + menus: MenuProps[]; +}; + +export interface CollapseMenuButtonProps { + icon: IconComponent; + label: string; + submenus: SubmenuProps[]; + defaultOpen: boolean; + isOpen: boolean | undefined; +} + export type NextUIVariants = | "solid" | "faded"