-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from pheralb/next
✨ Add search + improve light/dark mode
- Loading branch information
Showing
10 changed files
with
800 additions
and
3,769 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { allRoutes } from '@/docs.config'; | ||
import { Button } from '@/ui/button'; | ||
|
||
import { | ||
CommandDialog, | ||
CommandEmpty, | ||
CommandGroup, | ||
CommandInput, | ||
CommandItem, | ||
CommandList, | ||
} from '@/ui/command'; | ||
import { FileIcon, SearchIcon } from 'lucide-react'; | ||
import { useEffect, useState } from 'react'; | ||
|
||
const SearchModal = () => { | ||
const [open, setOpen] = useState<boolean>(false); | ||
|
||
useEffect(() => { | ||
const down = (e: KeyboardEvent) => { | ||
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) { | ||
e.preventDefault(); | ||
setOpen((open) => !open); | ||
} | ||
}; | ||
document.addEventListener('keydown', down); | ||
return () => document.removeEventListener('keydown', down); | ||
}, []); | ||
|
||
return ( | ||
<> | ||
<Button | ||
variant="ghost" | ||
size="icon" | ||
title="Search" | ||
onClick={() => setOpen(true)} | ||
> | ||
<SearchIcon size={20} strokeWidth={1.5} /> | ||
<span className="sr-only">Toggle theme</span> | ||
</Button> | ||
<CommandDialog open={open} onOpenChange={setOpen}> | ||
<CommandInput placeholder="Search..." /> | ||
<CommandList> | ||
<CommandEmpty>No results found.</CommandEmpty> | ||
{allRoutes.map((doc) => ( | ||
<> | ||
<CommandGroup | ||
key={doc.category} | ||
heading={doc.category} | ||
title={doc.category} | ||
> | ||
{doc.routes.map((route) => ( | ||
<CommandItem | ||
key={route.path} | ||
title={route.title} | ||
onSelect={() => { | ||
setOpen(false); | ||
window.location.href = route.path; | ||
}} | ||
> | ||
{route.icon ? ( | ||
<route.icon width={14} height={14} strokeWidth={1.5} /> | ||
) : ( | ||
<FileIcon size={14} strokeWidth={1.5} /> | ||
)} | ||
<span>{route.title}</span> | ||
</CommandItem> | ||
))} | ||
</CommandGroup> | ||
</> | ||
))} | ||
</CommandList> | ||
</CommandDialog> | ||
</> | ||
); | ||
}; | ||
|
||
export default SearchModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import * as React from 'react'; | ||
import { type DialogProps } from '@radix-ui/react-dialog'; | ||
import { Command as CommandPrimitive } from 'cmdk'; | ||
|
||
import { cn } from '@/utils'; | ||
import { Dialog, DialogContent } from '@/ui/dialog'; | ||
|
||
const Command = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive> | ||
>(({ className, ...props }, ref) => ( | ||
<CommandPrimitive | ||
ref={ref} | ||
className={cn( | ||
'flex h-full w-full flex-col overflow-hidden rounded-md bg-white text-neutral-950 dark:bg-neutral-900 dark:text-neutral-50', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
Command.displayName = CommandPrimitive.displayName; | ||
|
||
interface CommandDialogProps extends DialogProps {} | ||
|
||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => { | ||
return ( | ||
<Dialog {...props}> | ||
<DialogContent className="overflow-hidden p-0"> | ||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-neutral-500 dark:[&_[cmdk-group-heading]]:text-neutral-400 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-[18px] [&_[cmdk-item]_svg]:w-[18px]"> | ||
{children} | ||
</Command> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
}; | ||
|
||
const CommandInput = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive.Input>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> | ||
>(({ className, ...props }, ref) => ( | ||
<div className="flex items-center px-3" cmdk-input-wrapper=""> | ||
<CommandPrimitive.Input | ||
ref={ref} | ||
className={cn( | ||
'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-neutral-500 disabled:cursor-not-allowed disabled:opacity-50 dark:placeholder:text-neutral-400', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
</div> | ||
)); | ||
|
||
CommandInput.displayName = CommandPrimitive.Input.displayName; | ||
|
||
const CommandList = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive.List>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List> | ||
>(({ className, ...props }, ref) => ( | ||
<CommandPrimitive.List | ||
ref={ref} | ||
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)} | ||
{...props} | ||
/> | ||
)); | ||
|
||
CommandList.displayName = CommandPrimitive.List.displayName; | ||
|
||
const CommandEmpty = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive.Empty>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty> | ||
>((props, ref) => ( | ||
<CommandPrimitive.Empty | ||
ref={ref} | ||
className="py-6 text-center text-sm" | ||
{...props} | ||
/> | ||
)); | ||
|
||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName; | ||
|
||
const CommandGroup = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive.Group>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group> | ||
>(({ className, ...props }, ref) => ( | ||
<CommandPrimitive.Group | ||
ref={ref} | ||
className={cn( | ||
'overflow-hidden p-1 text-neutral-950 dark:text-neutral-50 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-neutral-500 dark:[&_[cmdk-group-heading]]:text-neutral-400', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
|
||
CommandGroup.displayName = CommandPrimitive.Group.displayName; | ||
|
||
const CommandSeparator = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive.Separator>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator> | ||
>(({ className, ...props }, ref) => ( | ||
<CommandPrimitive.Separator | ||
ref={ref} | ||
className={cn( | ||
'-mx-1 my-2 h-px bg-neutral-200 dark:bg-neutral-800', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName; | ||
|
||
const CommandItem = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive.Item>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item> | ||
>(({ className, ...props }, ref) => ( | ||
<CommandPrimitive.Item | ||
ref={ref} | ||
className={cn( | ||
'flex cursor-default items-center gap-2 rounded-md px-2 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-neutral-100 data-[selected=true]:text-neutral-900 data-[disabled=true]:opacity-50 dark:data-[selected=true]:bg-neutral-800 dark:data-[selected=true]:text-neutral-50', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
|
||
CommandItem.displayName = CommandPrimitive.Item.displayName; | ||
|
||
const CommandShortcut = ({ | ||
className, | ||
...props | ||
}: React.HTMLAttributes<HTMLSpanElement>) => { | ||
return ( | ||
<span | ||
className={cn( | ||
'ml-auto text-xs tracking-widest text-neutral-500 dark:text-neutral-400', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
); | ||
}; | ||
CommandShortcut.displayName = 'CommandShortcut'; | ||
|
||
export { | ||
Command, | ||
CommandDialog, | ||
CommandInput, | ||
CommandList, | ||
CommandEmpty, | ||
CommandGroup, | ||
CommandItem, | ||
CommandShortcut, | ||
CommandSeparator, | ||
}; |
Oops, something went wrong.