-
Notifications
You must be signed in to change notification settings - Fork 0
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 #2 from emiliosheinz/feat/keyboard-support
feat: keyboard command bar
- Loading branch information
Showing
13 changed files
with
365 additions
and
32 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
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
68 changes: 68 additions & 0 deletions
68
src/components/command-bar/command-bar-trigger.component.tsx
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,68 @@ | ||
'use client' | ||
|
||
import { useKBar } from 'kbar' | ||
import { useEffect, useState } from 'react' | ||
import { FaArrowRightLong } from 'react-icons/fa6' | ||
|
||
export function CommandBarTriggerFull() { | ||
const { query } = useKBar() | ||
const [isMounted, setIsMounted] = useState(false) | ||
|
||
useEffect(() => { | ||
setIsMounted(true) | ||
}, []) | ||
|
||
const renderLabel = () => { | ||
const isMac = /(Mac)/i.test(navigator.userAgent) | ||
const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent) | ||
|
||
if (isMobile) { | ||
return <span>Tap to start</span> | ||
} | ||
|
||
if (isMac) { | ||
return ( | ||
<span> | ||
Press <kbd>⌘</kbd> <kbd>K</kbd> to start | ||
</span> | ||
) | ||
} | ||
|
||
return ( | ||
<span> | ||
Press <kbd>ctrl</kbd> <kbd>K</kbd> to start | ||
</span> | ||
) | ||
} | ||
|
||
if (!isMounted) { | ||
return <div className='h-10 w-64 bg-codGray-300 animate-pulse rounded-md' /> | ||
} | ||
|
||
return ( | ||
<button | ||
className='px-4 h-10 rounded border bg-white border-white bg-opacity-0 border-opacity-0 hover:bg-opacity-5 hover:border-opacity-20 transition-all ease-in-out' | ||
onClick={query.toggle} | ||
> | ||
{renderLabel()} | ||
<FaArrowRightLong | ||
data-testid='arrow-right-icon' | ||
className='inline transition-all ease-in-out group-hover:translate-x-1 group-hover:text-dodgerBlue ml-3' | ||
/> | ||
</button> | ||
) | ||
} | ||
|
||
export function CommandBarTriggerLite() { | ||
const { query } = useKBar() | ||
|
||
return ( | ||
<button | ||
className='px-2.5 rounded border bg-white border-white bg-opacity-0 border-opacity-0 hover:bg-opacity-5 hover:border-opacity-20 transition-all ease-in-out' | ||
onClick={query.toggle} | ||
title='Open command bar' | ||
> | ||
<span className='text-3xl text-white'>⌘</span> | ||
</button> | ||
) | ||
} |
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,36 @@ | ||
'use client' | ||
|
||
import { | ||
KBarProvider, | ||
KBarPortal, | ||
KBarPositioner, | ||
KBarAnimator, | ||
KBarSearch, | ||
} from 'kbar' | ||
|
||
import { useActions } from './use-actions.hook' | ||
import { Results } from './results.component' | ||
|
||
type CommandBarProps = { | ||
children: React.ReactNode | ||
} | ||
|
||
export function CommandBar(props: CommandBarProps) { | ||
const { children } = props | ||
|
||
const actions = useActions() | ||
|
||
return ( | ||
<KBarProvider actions={actions}> | ||
<KBarPortal> | ||
<KBarPositioner className='z-40 bg-black bg-opacity-80 backdrop-blur-sm'> | ||
<KBarAnimator className='w-full max-w-xl rounded-md bg-codGray-500 bg-opacity-80 backdrop-blur-xl'> | ||
<KBarSearch className='w-full h-12 p-5 bg-transparent rounded-md outline-none' /> | ||
<Results /> | ||
</KBarAnimator> | ||
</KBarPositioner> | ||
</KBarPortal> | ||
{children} | ||
</KBarProvider> | ||
) | ||
} |
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,5 @@ | ||
export { CommandBar } from './command-bar.component' | ||
export { | ||
CommandBarTriggerFull, | ||
CommandBarTriggerLite, | ||
} from './command-bar-trigger.component' |
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,36 @@ | ||
import { KBarResults, useMatches } from 'kbar' | ||
import { classNames } from '~/utils/css.utils' | ||
|
||
export function Results() { | ||
const { results } = useMatches() | ||
|
||
return ( | ||
<KBarResults | ||
items={results} | ||
onRender={({ item, active }) => { | ||
const itemClassNames = classNames( | ||
'px-5 py-3 flex gap-5 items-center', | ||
active ? 'bg-codGray-300 bg-opacity-50' : 'bg-transparent' | ||
) | ||
|
||
if (typeof item === 'string') { | ||
return <div className={itemClassNames}>{item}</div> | ||
} | ||
|
||
return ( | ||
<div className={itemClassNames}> | ||
{item.icon} | ||
<span | ||
className={classNames( | ||
'text-white', | ||
active ? 'opacity-100' : 'opacity-50' | ||
)} | ||
> | ||
{item.name} | ||
</span> | ||
</div> | ||
) | ||
}} | ||
/> | ||
) | ||
} |
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,87 @@ | ||
import { Action } from 'kbar' | ||
import { useRouter } from 'next/navigation' | ||
import { | ||
HiOutlineAtSymbol, | ||
HiOutlineBookOpen, | ||
HiOutlineCodeBracket, | ||
HiOutlineHome, | ||
HiOutlineLightBulb, | ||
HiOutlineLink, | ||
} from 'react-icons/hi2' | ||
import { socialMedias } from '~/data/social-medias' | ||
import { notify } from '~/utils/toast.utils' | ||
|
||
export function useActions(): Action[] { | ||
const router = useRouter() | ||
|
||
const utilActions: Action[] = [ | ||
{ | ||
id: 'copy-url', | ||
name: 'Copy URL', | ||
keywords: 'copy url', | ||
perform: () => { | ||
navigator.clipboard.writeText(window.location.href) | ||
notify.success('URL copied to clipboard') | ||
}, | ||
icon: <HiOutlineLink className='w-5 h-5 text-white' />, | ||
}, | ||
{ | ||
id: 'source-code', | ||
name: 'Source code', | ||
keywords: 'source code', | ||
perform: () => { | ||
window.open( | ||
'https://github.com/emiliosheinz/emiliosheinz.com', | ||
'_blank' | ||
) | ||
}, | ||
icon: <HiOutlineCodeBracket className='w-5 h-5 text-white' />, | ||
}, | ||
{ | ||
id: 'email', | ||
name: 'Send me an email', | ||
keywords: 'email', | ||
perform: () => { | ||
window.open('mailto:[email protected]', '_blank') | ||
}, | ||
icon: <HiOutlineAtSymbol className='w-5 h-5 text-white' />, | ||
}, | ||
].map(action => ({ ...action, section: 'Util' })) | ||
|
||
const socialMediaActions: Action[] = socialMedias.map( | ||
({ Icon, url, name }) => ({ | ||
name, | ||
id: name.toLowerCase(), | ||
keywords: name.toLocaleLowerCase(), | ||
perform: () => window.open(url, '_blank'), | ||
icon: <Icon className='w-5 h-5 text-white' />, | ||
section: 'Social Media', | ||
}) | ||
) | ||
|
||
const goToActions: Action[] = [ | ||
{ | ||
id: 'home', | ||
name: 'Home', | ||
keywords: 'home page start initial', | ||
perform: () => router.push('/'), | ||
icon: <HiOutlineHome className='w-5 h-5 text-white' />, | ||
}, | ||
{ | ||
id: 'experience', | ||
name: 'Experience', | ||
keywords: 'experience work jobs', | ||
perform: () => router.push('/experiences'), | ||
icon: <HiOutlineLightBulb className='w-5 h-5 text-white' />, | ||
}, | ||
{ | ||
id: 'blog-posts', | ||
name: 'Blog Posts', | ||
keywords: 'blog posts articles', | ||
perform: () => router.push('/posts'), | ||
icon: <HiOutlineBookOpen className='w-5 h-5 text-white' />, | ||
}, | ||
].map(action => ({ ...action, section: 'Go to' })) | ||
|
||
return [...utilActions, ...socialMediaActions, ...goToActions] | ||
} |
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
Oops, something went wrong.