From bc1910fdcacfb43f0bab84fc71b261cd2af115d4 Mon Sep 17 00:00:00 2001 From: SomeCodecat <88855796+SomeCodecat@users.noreply.github.com> Date: Mon, 23 Jun 2025 11:20:09 +0200 Subject: [PATCH] feat: Implement settings dropdown and page components - Added `SettingsDropdown` component for selecting settings sections with icons and descriptions. - Created `SettingsPage` component to manage user settings, including account details, notifications, calendar availability, privacy, and appearance. - Introduced `SettingsSwitcher` for selecting options within settings. - Integrated command and dialog components for improved user interaction. - Updated `UserDropdown` to include links for settings and logout. - Refactored button styles and card footer layout for consistency. - Added popover functionality for dropdown menus. - Updated dependencies in `yarn.lock` for new components. --- package.json | 2 + src/app/settings/page.tsx | 483 +------------------- src/components/misc/settings-dropdown.tsx | 158 +++++++ src/components/misc/settings-page.tsx | 467 +++++++++++++++++++ src/components/misc/settings-switcher.tsx | 123 +++++ src/components/misc/user-card.tsx | 2 +- src/components/misc/user-dropdown.tsx | 12 +- src/components/ui/button.tsx | 2 +- src/components/ui/card.tsx | 2 +- src/components/ui/command.tsx | 184 ++++++++ src/components/ui/dialog.tsx | 143 ++++++ src/components/ui/popover.tsx | 48 ++ src/components/wrappers/settings-scroll.tsx | 20 +- yarn.lock | 58 ++- 14 files changed, 1202 insertions(+), 502 deletions(-) create mode 100644 src/components/misc/settings-dropdown.tsx create mode 100644 src/components/misc/settings-page.tsx create mode 100644 src/components/misc/settings-switcher.tsx create mode 100644 src/components/ui/command.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/popover.tsx diff --git a/package.json b/package.json index a9aa812..e3e8883 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-hover-card": "^1.1.13", "@radix-ui/react-label": "^2.1.6", + "@radix-ui/react-popover": "^1.1.14", "@radix-ui/react-scroll-area": "^1.2.8", "@radix-ui/react-select": "^2.2.4", "@radix-ui/react-separator": "^1.1.7", @@ -44,6 +45,7 @@ "bcryptjs": "^3.0.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cmdk": "^1.1.1", "lucide-react": "^0.515.0", "next": "15.4.0-canary.92", "next-auth": "^5.0.0-beta.25", diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index 563ebab..e0ad2a5 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -1,482 +1,5 @@ -import { Button } from '@/components/ui/button'; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from '@/components/ui/card'; -import { Input } from '@/components/ui/input'; -import { Label } from '@/components/ui/label'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { ScrollableSettingsWrapper } from '@/components/wrappers/settings-scroll'; -import { Switch } from '@/components/ui/switch'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; +import SettingsPage from '@/components/misc/settings-page'; -export default function SettingsPage() { - return ( -
-
- - - Account - Notifications - Calendar - Privacy - Appearance - - - - - - - Account Settings - - Manage your account details and preferences. - - - -
- - -
-
- - -

- Email is managed by your SSO provider. -

-
-
- - -

- Upload a new profile picture. -

-
-
- - -
- -
- - -
-
- -

- Permanently delete your account and all associated data. -

-
-
-
- - - - -
-
- - - - - - Notification Preferences - - Choose how you want to be notified. - - - -
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - - - -
-
- - - - - - Calendar & Availability - - Manage your calendar display, default availability, and iCal - integrations. - - - -
- - Display - -
- - -
-
- - -
-
- - -
-
- -
- - Availability - -
- -

- Define your typical available hours (e.g., - Monday-Friday, 9 AM - 5 PM). -

- -
-
- -

- Min time before a booking can be made. -

-
- -
-
-
- -

- Max time in advance a booking can be made. -

- -
-
- -
- - iCalendar Integration - -
- - - -
-
- - - -
-
-
-
- - - - -
-
- - - - - - Sharing & Privacy - - Control who can see your calendar and book time with you. - - - -
- - -
-
- -

- (Override for Default Visibility) -
- - This setting will override the default visibility for - your calendar. You can set specific friends or groups to - see your full calendar details. - -

- -
-
- - -
-
- - -

- Prevent specific users from seeing your calendar or - booking time. -

-
-
-
- - - - -
-
- - - - - - Appearance - - Customize the look and feel of the application. - - - -
- - -
-
- - -
-
- - -
-
-
- - - - -
-
-
-
-
- ); +export default function Page() { + return ; } diff --git a/src/components/misc/settings-dropdown.tsx b/src/components/misc/settings-dropdown.tsx new file mode 100644 index 0000000..63a7b20 --- /dev/null +++ b/src/components/misc/settings-dropdown.tsx @@ -0,0 +1,158 @@ +'use client'; + +import type React from 'react'; + +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from '@/components/ui/command'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; +import { cn } from '@/lib/utils'; +import { + Check, + ChevronDown, + User, + Bell, + Calendar, + Shield, + Palette, +} from 'lucide-react'; + +interface SettingsSection { + label: string; + value: string; + description: string; + icon: React.ComponentType<{ className?: string }>; +} + +interface SettingsDropdownProps { + currentSection: string; + onSectionChange: (section: string) => void; + className?: string; +} + +const settingsSections: SettingsSection[] = [ + { + label: 'Account', + value: 'general', + description: 'Manage your account details and preferences', + icon: User, + }, + { + label: 'Notifications', + value: 'notifications', + description: 'Choose how you want to be notified', + icon: Bell, + }, + { + label: 'Calendar', + value: 'calendarAvailability', + description: 'Manage calendar display and availability', + icon: Calendar, + }, + { + label: 'Privacy', + value: 'sharingPrivacy', + description: 'Control who can see your calendar', + icon: Shield, + }, + { + label: 'Appearance', + value: 'appearance', + description: 'Customize the look and feel', + icon: Palette, + }, +]; + +export function SettingsDropdown({ + currentSection, + onSectionChange, + className, +}: SettingsDropdownProps) { + const [open, setOpen] = useState(false); + + const currentSectionData = settingsSections.find( + (section) => section.value === currentSection, + ); + const CurrentIcon = currentSectionData?.icon || User; + + const handleSelect = (value: string) => { + onSectionChange(value); + setOpen(false); + }; + + return ( +
+ + + + + + + + + No settings found. + + {settingsSections.map((section) => { + const Icon = section.icon; + return ( + handleSelect(section.value)} + className='flex items-center justify-between p-3' + > +
+ +
+ {section.label} + + {section.description} + +
+
+ +
+ ); + })} +
+
+
+
+
+
+ ); +} diff --git a/src/components/misc/settings-page.tsx b/src/components/misc/settings-page.tsx new file mode 100644 index 0000000..fb90614 --- /dev/null +++ b/src/components/misc/settings-page.tsx @@ -0,0 +1,467 @@ +'use client'; + +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { ScrollableSettingsWrapper } from '@/components/wrappers/settings-scroll'; +import { Switch } from '@/components/ui/switch'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { SettingsDropdown } from '@/components/misc/settings-dropdown'; +import { useRouter } from 'next/navigation'; + +export default function SettingsPage() { + const router = useRouter(); + const [currentSection, setCurrentSection] = useState('general'); + + const renderSettingsContent = () => { + switch (currentSection) { + case 'general': + return ( + + + + Account Settings + + Manage your account details and preferences. + + + +
+ + +
+
+ + +

+ Email is managed by your SSO provider. +

+
+
+ + +

+ Upload a new profile picture. +

+
+
+ + +
+
+ + +
+
+ +

+ Permanently delete your account and all associated data. +

+
+
+
+
+ ); + + case 'notifications': + return ( + + + + Notification Preferences + + Choose how you want to be notified. + + + +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ ); + + case 'calendarAvailability': + return ( + + + + Calendar & Availability + + Manage your calendar display, default availability, and iCal + integrations. + + + +
+ Display +
+ + +
+
+ + +
+
+ + +
+
+ +
+ + Availability + +
+ +

+ Define your typical available hours (e.g., Monday-Friday, + 9 AM - 5 PM). +

+ +
+
+ +

+ Min time before a booking can be made. +

+
+ +
+
+
+ +

+ Max time in advance a booking can be made. +

+ +
+
+ +
+ + iCalendar Integration + +
+ + + +
+
+ + + +
+
+
+
+
+ ); + + case 'sharingPrivacy': + return ( + + + + Sharing & Privacy + + Control who can see your calendar and book time with you. + + + +
+ + +
+
+ +

+ (Override for Default Visibility) +
+ + This setting will override the default visibility for your + calendar. You can set specific friends or groups to see + your full calendar details. + +

+ +
+
+ + +
+
+ + +

+ Prevent specific users from seeing your calendar or booking + time. +

+
+
+
+
+ ); + + case 'appearance': + return ( + + + + Appearance + + Customize the look and feel of the application. + + + +
+ + +
+
+ + +
+
+ + +
+
+
+
+ ); + + default: + return null; + } + }; + + return ( +
+
+
+
+

Settings

+
+ +
+ +
{renderSettingsContent()}
+
+ + + + +
+
+
+ ); +} diff --git a/src/components/misc/settings-switcher.tsx b/src/components/misc/settings-switcher.tsx new file mode 100644 index 0000000..40e6a05 --- /dev/null +++ b/src/components/misc/settings-switcher.tsx @@ -0,0 +1,123 @@ +'use client'; + +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from '@/components/ui/command'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; +import { cn } from '@/lib/utils'; +import { Check, ChevronDown } from 'lucide-react'; + +interface SettingsOption { + label: string; + value: string; + description?: string; +} + +interface SettingsSwitcherProps { + title: string; + options: SettingsOption[]; + defaultValue?: string; + onValueChange?: (value: string) => void; + placeholder?: string; + searchPlaceholder?: string; + className?: string; +} + +export function SettingsSwitcher({ + title, + options, + defaultValue, + onValueChange, + placeholder = 'Select option...', + searchPlaceholder = 'Search options...', + className, +}: SettingsSwitcherProps) { + const [open, setOpen] = useState(false); + const [selectedValue, setSelectedValue] = useState( + defaultValue || options[0]?.value || '', + ); + + const selectedOption = options.find( + (option) => option.value === selectedValue, + ); + + const handleSelect = (value: string) => { + setSelectedValue(value); + setOpen(false); + onValueChange?.(value); + }; + + return ( +
+ + + + + + + + + + No option found. + + {options.map((option) => ( + handleSelect(option.value)} + className='flex items-center justify-between' + > +
+ {option.label} + {option.description && ( + + {option.description} + + )} +
+ +
+ ))} +
+
+
+
+
+
+ ); +} diff --git a/src/components/misc/user-card.tsx b/src/components/misc/user-card.tsx index faefc35..457d0fc 100644 --- a/src/components/misc/user-card.tsx +++ b/src/components/misc/user-card.tsx @@ -21,7 +21,7 @@ export default function UserCard() { )}
{data?.data.user.name}
-
+
{data?.data.user.email}
diff --git a/src/components/misc/user-dropdown.tsx b/src/components/misc/user-dropdown.tsx index 8f5aa05..c0cc68a 100644 --- a/src/components/misc/user-dropdown.tsx +++ b/src/components/misc/user-dropdown.tsx @@ -5,7 +5,7 @@ import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, - DropdownMenuGroup, + // DropdownMenuGroup, DropdownMenuItem, // DropdownMenuLabel, // DropdownMenuPortal, @@ -48,11 +48,13 @@ export default function UserDropdown() { - Settings + + Settings + - - Logout - + + Logout + ); diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 2a25f66..0b8ce1a 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '@/lib/utils'; const buttonVariants = cva( - "radius-lg inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-button transition-all cursor-pointer disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + "radius-lg inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-button transition-all cursor-pointer disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-nonef", { variants: { variant: { diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx index c0894f8..72c0a9c 100644 --- a/src/components/ui/card.tsx +++ b/src/components/ui/card.tsx @@ -126,7 +126,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { return (
); diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx new file mode 100644 index 0000000..8cb4ca7 --- /dev/null +++ b/src/components/ui/command.tsx @@ -0,0 +1,184 @@ +"use client" + +import * as React from "react" +import { Command as CommandPrimitive } from "cmdk" +import { SearchIcon } from "lucide-react" + +import { cn } from "@/lib/utils" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" + +function Command({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandDialog({ + title = "Command Palette", + description = "Search for a command to run...", + children, + className, + showCloseButton = true, + ...props +}: React.ComponentProps & { + title?: string + description?: string + className?: string + showCloseButton?: boolean +}) { + return ( + + + {title} + {description} + + + + {children} + + + + ) +} + +function CommandInput({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ + +
+ ) +} + +function CommandList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandEmpty({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +} diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..d9ccec9 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,143 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx new file mode 100644 index 0000000..01e468b --- /dev/null +++ b/src/components/ui/popover.tsx @@ -0,0 +1,48 @@ +"use client" + +import * as React from "react" +import * as PopoverPrimitive from "@radix-ui/react-popover" + +import { cn } from "@/lib/utils" + +function Popover({ + ...props +}: React.ComponentProps) { + return +} + +function PopoverTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function PopoverContent({ + className, + align = "center", + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function PopoverAnchor({ + ...props +}: React.ComponentProps) { + return +} + +export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } diff --git a/src/components/wrappers/settings-scroll.tsx b/src/components/wrappers/settings-scroll.tsx index e0f7251..a647493 100644 --- a/src/components/wrappers/settings-scroll.tsx +++ b/src/components/wrappers/settings-scroll.tsx @@ -1,16 +1,16 @@ -import React from 'react'; +import { cn } from '@/lib/utils'; +import type * as React from 'react'; -interface ScrollableContentWrapperProps { - children: React.ReactNode; +interface ScrollableSettingsWrapperProps { className?: string; + children: React.ReactNode; } -export const ScrollableSettingsWrapper: React.FC< - ScrollableContentWrapperProps -> = ({ children, className = '' }) => { +export function ScrollableSettingsWrapper({ + className, + children, +}: ScrollableSettingsWrapperProps) { return ( -
- {children} -
+
{children}
); -}; +} diff --git a/yarn.lock b/yarn.lock index 90dc258..7d3866e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1370,7 +1370,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-compose-refs@npm:1.1.2": +"@radix-ui/react-compose-refs@npm:1.1.2, @radix-ui/react-compose-refs@npm:^1.1.1": version: 1.1.2 resolution: "@radix-ui/react-compose-refs@npm:1.1.2" peerDependencies: @@ -1396,7 +1396,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-dialog@npm:^1.1.14": +"@radix-ui/react-dialog@npm:^1.1.14, @radix-ui/react-dialog@npm:^1.1.6": version: 1.1.14 resolution: "@radix-ui/react-dialog@npm:1.1.14" dependencies: @@ -1550,7 +1550,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-id@npm:1.1.1": +"@radix-ui/react-id@npm:1.1.1, @radix-ui/react-id@npm:^1.1.0": version: 1.1.1 resolution: "@radix-ui/react-id@npm:1.1.1" dependencies: @@ -1620,6 +1620,39 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-popover@npm:^1.1.14": + version: 1.1.14 + resolution: "@radix-ui/react-popover@npm:1.1.14" + dependencies: + "@radix-ui/primitive": "npm:1.1.2" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-dismissable-layer": "npm:1.1.10" + "@radix-ui/react-focus-guards": "npm:1.1.2" + "@radix-ui/react-focus-scope": "npm:1.1.7" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-popper": "npm:1.2.7" + "@radix-ui/react-portal": "npm:1.1.9" + "@radix-ui/react-presence": "npm:1.1.4" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-slot": "npm:1.2.3" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + aria-hidden: "npm:^1.2.4" + react-remove-scroll: "npm:^2.6.3" + 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 + checksum: 10c0/04e557bfcaab4887694d119555b101e16b8a4e99595541ff2cbe805c551be853cb02882a2ada04e6507ffc45bc092bc2b89704b7b79f5025251767d0b4f3230a + languageName: node + linkType: hard + "@radix-ui/react-popper@npm:1.2.7": version: 1.2.7 resolution: "@radix-ui/react-popper@npm:1.2.7" @@ -1688,7 +1721,7 @@ __metadata: languageName: node linkType: hard -"@radix-ui/react-primitive@npm:2.1.3": +"@radix-ui/react-primitive@npm:2.1.3, @radix-ui/react-primitive@npm:^2.0.2": version: 2.1.3 resolution: "@radix-ui/react-primitive@npm:2.1.3" dependencies: @@ -4184,6 +4217,21 @@ __metadata: languageName: node linkType: hard +"cmdk@npm:^1.1.1": + version: 1.1.1 + resolution: "cmdk@npm:1.1.1" + dependencies: + "@radix-ui/react-compose-refs": "npm:^1.1.1" + "@radix-ui/react-dialog": "npm:^1.1.6" + "@radix-ui/react-id": "npm:^1.1.0" + "@radix-ui/react-primitive": "npm:^2.0.2" + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + checksum: 10c0/5605ac4396ec9bc65c82f954da19dd89a0636a54026df72780e2470da1381f9d57434a80a53f2d57eaa4e759660a3ebba9232b74258dc09970576591eae03116 + languageName: node + linkType: hard + "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -6681,6 +6729,7 @@ __metadata: "@radix-ui/react-dropdown-menu": "npm:^2.1.15" "@radix-ui/react-hover-card": "npm:^1.1.13" "@radix-ui/react-label": "npm:^2.1.6" + "@radix-ui/react-popover": "npm:^1.1.14" "@radix-ui/react-scroll-area": "npm:^1.2.8" "@radix-ui/react-select": "npm:^2.2.4" "@radix-ui/react-separator": "npm:^1.1.7" @@ -6698,6 +6747,7 @@ __metadata: bcryptjs: "npm:^3.0.2" class-variance-authority: "npm:^0.7.1" clsx: "npm:^2.1.1" + cmdk: "npm:^1.1.1" dotenv-cli: "npm:8.0.0" eslint: "npm:9.29.0" eslint-config-next: "npm:15.3.4"