command-menu.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import React from 'react'
  2. import { useNavigate } from '@tanstack/react-router'
  3. import {
  4. IconArrowRightDashed,
  5. IconDeviceLaptop,
  6. IconMoon,
  7. IconSun,
  8. } from '@tabler/icons-react'
  9. import { useSearch } from '@/context/search-context'
  10. import { useTheme } from '@/context/theme-context'
  11. import {
  12. CommandDialog,
  13. CommandEmpty,
  14. CommandGroup,
  15. CommandInput,
  16. CommandItem,
  17. CommandList,
  18. CommandSeparator,
  19. } from '@/components/ui/command'
  20. import { sidebarData } from './layout/data/sidebar-data'
  21. import { ScrollArea } from './ui/scroll-area'
  22. export function CommandMenu() {
  23. const navigate = useNavigate()
  24. const { setTheme } = useTheme()
  25. const { open, setOpen } = useSearch()
  26. const runCommand = React.useCallback(
  27. (command: () => unknown) => {
  28. setOpen(false)
  29. command()
  30. },
  31. [setOpen]
  32. )
  33. return (
  34. <CommandDialog modal open={open} onOpenChange={setOpen}>
  35. <CommandInput placeholder='Type a command or search...' />
  36. <CommandList>
  37. <ScrollArea type='hover' className='h-72 pr-1'>
  38. <CommandEmpty>No results found.</CommandEmpty>
  39. {sidebarData.navGroups.map((group) => (
  40. <CommandGroup key={group.title} heading={group.title}>
  41. {group.items.map((navItem, i) => {
  42. if (navItem.url)
  43. return (
  44. <CommandItem
  45. key={`${navItem.url}-${i}`}
  46. value={navItem.title}
  47. onSelect={() => {
  48. runCommand(() => navigate({ to: navItem.url }))
  49. }}
  50. >
  51. <div className='mr-2 flex h-4 w-4 items-center justify-center'>
  52. <IconArrowRightDashed className='size-2 text-muted-foreground/80' />
  53. </div>
  54. {navItem.title}
  55. </CommandItem>
  56. )
  57. return navItem.items?.map((subItem, i) => (
  58. <CommandItem
  59. key={`${subItem.url}-${i}`}
  60. value={subItem.title}
  61. onSelect={() => {
  62. runCommand(() => navigate({ to: subItem.url }))
  63. }}
  64. >
  65. <div className='mr-2 flex h-4 w-4 items-center justify-center'>
  66. <IconArrowRightDashed className='size-2 text-muted-foreground/80' />
  67. </div>
  68. {subItem.title}
  69. </CommandItem>
  70. ))
  71. })}
  72. </CommandGroup>
  73. ))}
  74. <CommandSeparator />
  75. <CommandGroup heading='Theme'>
  76. <CommandItem onSelect={() => runCommand(() => setTheme('light'))}>
  77. <IconSun /> <span>Light</span>
  78. </CommandItem>
  79. <CommandItem onSelect={() => runCommand(() => setTheme('dark'))}>
  80. <IconMoon className='scale-90' />
  81. <span>Dark</span>
  82. </CommandItem>
  83. <CommandItem onSelect={() => runCommand(() => setTheme('system'))}>
  84. <IconDeviceLaptop />
  85. <span>System</span>
  86. </CommandItem>
  87. </CommandGroup>
  88. </ScrollArea>
  89. </CommandList>
  90. </CommandDialog>
  91. )
  92. }