command-menu.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import React from 'react'
  2. import { useNavigate } from '@tanstack/react-router'
  3. import { ArrowRight, ChevronRight, Laptop, Moon, Sun } from 'lucide-react'
  4. import { useSearch } from '@/context/search-provider'
  5. import { useTheme } from '@/context/theme-provider'
  6. import { useVisibleNavGroups } from '@/hooks/use-visible-nav'
  7. import {
  8. CommandDialog,
  9. CommandEmpty,
  10. CommandGroup,
  11. CommandInput,
  12. CommandItem,
  13. CommandList,
  14. CommandSeparator,
  15. } from '@/components/ui/command'
  16. import { ScrollArea } from './ui/scroll-area'
  17. export function CommandMenu() {
  18. const navigate = useNavigate()
  19. const { setTheme } = useTheme()
  20. const { open, setOpen } = useSearch()
  21. const navGroups = useVisibleNavGroups()
  22. const runCommand = React.useCallback(
  23. (command: () => unknown) => {
  24. setOpen(false)
  25. command()
  26. },
  27. [setOpen]
  28. )
  29. return (
  30. <CommandDialog modal open={open} onOpenChange={setOpen}>
  31. <CommandInput placeholder='یک دستور تایپ کنید یا جستجو کنید...' />
  32. <CommandList>
  33. <ScrollArea type='hover' className='h-72 pe-1'>
  34. <CommandEmpty>هیچ نتیجه ای یافت نشد.</CommandEmpty>
  35. {navGroups.map((group) => (
  36. <CommandGroup key={group.title} heading={group.title}>
  37. {group.items.map((navItem, i) => {
  38. if (navItem.url)
  39. return (
  40. <CommandItem
  41. key={`${navItem.url}-${i}`}
  42. value={navItem.title}
  43. onSelect={() => {
  44. runCommand(() => navigate({ to: navItem.url }))
  45. }}
  46. >
  47. <div className='flex size-4 items-center justify-center'>
  48. <ArrowRight className='size-2 text-muted-foreground/80' />
  49. </div>
  50. {navItem.title}
  51. </CommandItem>
  52. )
  53. return navItem.items?.map((subItem, i) => (
  54. <CommandItem
  55. key={`${navItem.title}-${subItem.url}-${i}`}
  56. value={`${navItem.title}-${subItem.url}`}
  57. onSelect={() => {
  58. runCommand(() => navigate({ to: subItem.url }))
  59. }}
  60. >
  61. <div className='flex size-4 items-center justify-center'>
  62. <ArrowRight className='size-2 text-muted-foreground/80' />
  63. </div>
  64. {navItem.title} <ChevronRight /> {subItem.title}
  65. </CommandItem>
  66. ))
  67. })}
  68. </CommandGroup>
  69. ))}
  70. <CommandSeparator />
  71. <CommandGroup heading='Theme'>
  72. <CommandItem onSelect={() => runCommand(() => setTheme('light'))}>
  73. <Sun />
  74. <span>روشن</span>
  75. </CommandItem>
  76. <CommandItem onSelect={() => runCommand(() => setTheme('dark'))}>
  77. <Moon className='scale-90' />
  78. <span>دارک</span>
  79. </CommandItem>
  80. <CommandItem onSelect={() => runCommand(() => setTheme('system'))}>
  81. <Laptop />
  82. <span>سیستم</span>
  83. </CommandItem>
  84. </CommandGroup>
  85. </ScrollArea>
  86. </CommandList>
  87. </CommandDialog>
  88. )
  89. }