Skip to content

Commit

Permalink
feat: add command palette (#59)
Browse files Browse the repository at this point in the history
* feat: add command palette

* fix: add command empty

---------

Co-authored-by: zernonia <[email protected]>
  • Loading branch information
ahmedmayara and zernonia authored Sep 20, 2023
1 parent d5bb3a8 commit cc49dd5
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 13 deletions.
37 changes: 37 additions & 0 deletions apps/www/.vitepress/theme/components/Kbd.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script setup lang="ts">
import { cva } from 'class-variance-authority'
import { computed } from 'vue'
interface KbdProps {
as?: string
size?: 'xs' | 'sm' | 'md'
}
const props = withDefaults(defineProps<KbdProps>(), {
as: 'kbd',
size: 'sm',
})
const kbdClass = computed(() => {
return cva(
'inline-flex items-center pointer-events-none h-5 select-none items-center gap-1 rounded border border-border bg-muted font-sans font-medium',
{
variants: {
size: {
xs: 'min-h-[16px] text-[10px] h-4 px-1',
sm: 'min-h-[20px] text-[11px] h-5 px-1',
md: 'min-h-[24px] text-[12px] h-6 px-1.5',
},
},
},
)({
size: props.size,
})
})
</script>

<template>
<component :is="props.as" :class="kbdClass">
<slot />
</component>
</template>
125 changes: 115 additions & 10 deletions apps/www/.vitepress/theme/layout/MainLayout.vue
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
<script setup lang="ts">
import { useToggle } from '@vueuse/core'
import { Content, useData, useRoute } from 'vitepress'
import { onMounted, watch } from 'vue'
import { Content, useData, useRoute, useRouter } from 'vitepress'
import { onMounted, onUnmounted, ref } from 'vue'
import { SearchIcon } from 'lucide-vue-next'
import { docsConfig } from '../config/docs'
import Logo from '../components/Logo.vue'
import MobileNav from '../components/MobileNav.vue'
// import { Button } from '@/lib/registry/default/ui/button'
// import { Kbd } from '@/lib/registry/default/ui/kbd'
// import LucideSearch from '~icons/lucide/search'
import Kbd from '../components/Kbd.vue'
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from '@/lib/registry/default/ui/command'
import { Button } from '@/lib/registry/default/ui/button'
import RadixIconsGithubLogo from '~icons/radix-icons/github-logo'
import TablerBrandX from '~icons/tabler/brand-x'
import RadixIconsMoon from '~icons/radix-icons/moon'
import RadixIconsSun from '~icons/radix-icons/sun'
import { useConfigStore } from '@/stores/config'
import { Dialog, DialogContent } from '@/lib/registry/default/ui/dialog'
import File from '~icons/radix-icons/file'
import Circle from '~icons/radix-icons/circle'
const { radius, theme } = useConfigStore()
// Whenever the component is mounted, update the document class list
onMounted(() => {
document.documentElement.style.setProperty('--radius', `${radius.value}rem`)
document.documentElement.classList.add(`theme-${theme.value}`)
window.addEventListener('keydown', onKeyDown)
})
const { frontmatter, isDark } = useData()
const $route = useRoute()
const $router = useRouter()
const toggleDark = useToggle(isDark)
const links = [
Expand All @@ -39,6 +48,27 @@ const links = [
// icon: TablerBrandX,
// },
]
const isOpen = ref<boolean>(false)
function onKeyDown(event: KeyboardEvent) {
if (isOpen.value)
return
if ((event.metaKey || event.ctrlKey) && event.key === 'k') {
event.preventDefault()
isOpen.value = true
}
}
onUnmounted(() => {
window.removeEventListener('keydown', onKeyDown)
})
function openInNewTab(url: string | undefined) {
const win = window.open(url, '_blank')
win?.focus()
}
watch(() => $route.path, (n) => {
// @ts-expect-error View Transition API not supported by all the browser yet
Expand All @@ -48,7 +78,7 @@ watch(() => $route.path, (n) => {
console.log('soft navigating to: ', n)
})
}
})
})
</script>

<template>
Expand Down Expand Up @@ -81,19 +111,19 @@ watch(() => $route.path, (n) => {
</div>

<div class=" flex items-center justify-end space-x-4 ">
<!-- <Button
<Button
variant="outline"
class="w-72 h-8 px-3 hidden lg:flex lg:justify-between lg:items-center"
@click="isOpen = true"
>
<div class="flex items-center">
<LucideSearch class="w-4 h-4 mr-2 text-muted-foreground" />
<SearchIcon class="w-4 h-4 mr-2 text-muted-foreground" />
<span class="text-muted-foreground"> Search for anything... </span>
</div>
<div class="flex items-center gap-x-1">
<Kbd>⌘</Kbd>
<Kbd>K</Kbd>
<Kbd> <span>⌘</span>K </Kbd>
</div>
</Button> -->
</Button>

<div
v-for="link in links"
Expand Down Expand Up @@ -180,5 +210,80 @@ watch(() => $route.path, (n) => {
</div>
</div>
</footer>

<Dialog v-model:open="isOpen">
<DialogContent class="p-0">
<Command>
<CommandInput placeholder="Type a command or search..." />
<CommandEmpty>
No results found.
</CommandEmpty>
<CommandList>
<CommandGroup heading="Links">
<CommandItem
v-for="item in docsConfig.mainNav"
:key="item.title"
:heading="item.title"
:value="item.title"
class="py-3"
@select="() => {
if (item.external) {
openInNewTab(item.href);
}
else {
$router.go(`${item.href}.html`);
}
isOpen = false;
}"
>
<File class="mr-2 h-5 w-5" />
<span>{{ item.title }}</span>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup v-for="item in docsConfig.sidebarNav" :key="item.title" :heading="item.title">
<CommandItem
v-for="subItem in item.items" :key="subItem.title" :heading="subItem.title" :value="subItem.title" class="py-3" @select="() => {
$router.go(`${subItem.href}.html`)
isOpen = false
}"
>
<Circle class="mr-2 h-5 w-5" />
<span>{{ subItem.title }}</span>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Theme">
<CommandItem
value="light-theme"
class="py-3"
@select="
() => {
isDark = false;
isOpen = false;
}
"
>
<RadixIconsSun class="mr-2 h-5 w-5" />
<span>Light Theme</span>
</CommandItem>
<CommandItem
value="dark-theme"
class="py-3"
@select="
() => {
isDark = true;
isOpen = false;
}
"
>
<RadixIconsMoon class="mr-2 h-5 w-5" />
<span>Dark Theme</span>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</DialogContent>
</Dialog>
</div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const props = defineProps<ComboboxGroupProps & {
<template>
<ComboboxGroup
v-bind="props"
:class="cn('overflow-hidden p-1 text-foreground', $attrs.class ?? '')"
:class="cn('p-1 text-foreground', $attrs.class ?? '')"
>
<ComboboxLabel v-if="heading" class="px-2 py-1.5 text-xs font-medium text-muted-foreground">
{{ heading }}
Expand Down
4 changes: 2 additions & 2 deletions apps/www/src/lib/registry/default/ui/dialog/DialogContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ const emitsAsProps = useEmitAsProps(emits)
<slot />

<DialogClose
class="absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary"
class="absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary"
>
<X class="w-4 h-4" />
<X class="w-4 h-4 text-muted-foreground" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
Expand Down

0 comments on commit cc49dd5

Please sign in to comment.