mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
up
This commit is contained in:
@@ -10,8 +10,9 @@ const open = ref(false)
|
|||||||
const searchTerm = ref('')
|
const searchTerm = ref('')
|
||||||
// const searchTermDebounced = refDebounced(searchTerm, 200)
|
// const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||||
const selected = ref([])
|
const selected = ref([])
|
||||||
|
const commandPalette = useTemplateRef('commandPalette')
|
||||||
|
|
||||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
const { data: _users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||||
// params: { q: searchTermDebounced },
|
// params: { q: searchTermDebounced },
|
||||||
transform: (data: User[]) => {
|
transform: (data: User[]) => {
|
||||||
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` } })) || []
|
||||||
@@ -259,6 +260,12 @@ function onSelect(item: any) {
|
|||||||
|
|
||||||
defineShortcuts({
|
defineShortcuts({
|
||||||
meta_k: () => open.value = !open.value,
|
meta_k: () => open.value = !open.value,
|
||||||
|
meta_shift_a: {
|
||||||
|
usingInput: true,
|
||||||
|
handler: () => {
|
||||||
|
commandPalette.value?.openView('askAI')
|
||||||
|
}
|
||||||
|
},
|
||||||
...extractShortcuts(groups.value)
|
...extractShortcuts(groups.value)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -266,6 +273,7 @@ defineShortcuts({
|
|||||||
<template>
|
<template>
|
||||||
<DefineTemplate>
|
<DefineTemplate>
|
||||||
<UCommandPalette
|
<UCommandPalette
|
||||||
|
ref="commandPalette"
|
||||||
v-model="selected"
|
v-model="selected"
|
||||||
v-model:search-term="searchTerm"
|
v-model:search-term="searchTerm"
|
||||||
:loading="status === 'pending'"
|
:loading="status === 'pending'"
|
||||||
@@ -279,42 +287,49 @@ defineShortcuts({
|
|||||||
class="sm:max-h-80"
|
class="sm:max-h-80"
|
||||||
@update:model-value="onSelect"
|
@update:model-value="onSelect"
|
||||||
>
|
>
|
||||||
<template #view="{ viewName }">
|
<template #wallpaper>
|
||||||
<div v-if="viewName === 'wallpaper'" class="flex flex-col h-full w-full">
|
<div class="flex-1 overflow-y-auto p-6">
|
||||||
<div class="flex-1 overflow-y-auto p-6">
|
<div class="grid grid-cols-4 gap-4">
|
||||||
<div class="grid grid-cols-4 gap-4">
|
<div
|
||||||
|
v-for="wallpaper in filteredWallpapers"
|
||||||
|
:key="wallpaper.id"
|
||||||
|
class="group relative cursor-pointer"
|
||||||
|
@click="setWallpaper(wallpaper)"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="wallpaper in filteredWallpapers"
|
class="aspect-video rounded-lg bg-gradient-to-br shadow-lg ring-1 ring-black/5"
|
||||||
:key="wallpaper.id"
|
:class="wallpaper.gradient"
|
||||||
class="group relative cursor-pointer"
|
/>
|
||||||
@click="setWallpaper(wallpaper)"
|
<div class="mt-2 px-1">
|
||||||
>
|
<div class="flex items-center gap-2">
|
||||||
<div
|
<h3 class="text-sm font-medium text-highlighted truncate">
|
||||||
class="aspect-video rounded-lg bg-gradient-to-br shadow-lg ring-1 ring-black/5"
|
{{ wallpaper.name }}
|
||||||
:class="wallpaper.gradient"
|
</h3>
|
||||||
/>
|
<UChip
|
||||||
<div class="mt-2 px-1">
|
v-if="wallpaper.featured"
|
||||||
<div class="flex items-center gap-2">
|
label="★"
|
||||||
<h3 class="text-sm font-medium text-highlighted truncate">
|
size="xs"
|
||||||
{{ wallpaper.name }}
|
color="primary"
|
||||||
</h3>
|
class="shrink-0"
|
||||||
<UChip
|
/>
|
||||||
v-if="wallpaper.featured"
|
|
||||||
label="★"
|
|
||||||
size="xs"
|
|
||||||
color="primary"
|
|
||||||
class="shrink-0"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p class="text-xs text-dimmed">
|
|
||||||
{{ wallpaper.category }}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="text-xs text-dimmed">
|
||||||
|
{{ wallpaper.category }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #askAI>
|
||||||
|
<div class="flex flex-col items-center justify-center gap-4 p-6">
|
||||||
|
<UIcon name="i-lucide-sparkles" class="size-8 text-primary" />
|
||||||
|
<span class="text-lg font-semibold text-highlighted">
|
||||||
|
Ask me anything...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</UCommandPalette>
|
</UCommandPalette>
|
||||||
</DefineTemplate>
|
</DefineTemplate>
|
||||||
|
|
||||||
|
|||||||
@@ -154,12 +154,11 @@ export type CommandPaletteSlots<G extends CommandPaletteGroup<T> = CommandPalett
|
|||||||
'empty'(props: { searchTerm?: string }): any
|
'empty'(props: { searchTerm?: string }): any
|
||||||
'back'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
|
'back'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
|
||||||
'close'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
|
'close'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
|
||||||
'view'(props: { viewName?: string, current: any, searchTerm: string, navigateBack: () => void }): any
|
|
||||||
'item': SlotProps<T>
|
'item': SlotProps<T>
|
||||||
'item-leading': SlotProps<T>
|
'item-leading': SlotProps<T>
|
||||||
'item-label': SlotProps<T>
|
'item-label': SlotProps<T>
|
||||||
'item-trailing': SlotProps<T>
|
'item-trailing': SlotProps<T>
|
||||||
} & Record<string, SlotProps<G>> & Record<string, SlotProps<T>>
|
} & Record<string, SlotProps<G>> & Record<string, SlotProps<T>> & Record<string, (props: { current: any, searchTerm: string, navigateBack: () => void, close: () => void }) => any>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -290,6 +289,31 @@ const filteredGroups = computed(() => {
|
|||||||
|
|
||||||
const listboxRootRef = useTemplateRef('listboxRootRef')
|
const listboxRootRef = useTemplateRef('listboxRootRef')
|
||||||
|
|
||||||
|
// Exposed methods for programmatic control
|
||||||
|
function openView(viewName: string) {
|
||||||
|
history.value.push({
|
||||||
|
id: `view-${viewName}`,
|
||||||
|
label: viewName,
|
||||||
|
view: viewName,
|
||||||
|
items: []
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
searchTerm.value = ''
|
||||||
|
listboxRootRef.value?.highlightFirstItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeView() {
|
||||||
|
if (history.value.length > 0) {
|
||||||
|
navigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
openView,
|
||||||
|
closeView,
|
||||||
|
navigateBack
|
||||||
|
})
|
||||||
|
|
||||||
function navigate(item: T) {
|
function navigate(item: T) {
|
||||||
if (!item.children?.length && !item.view) {
|
if (!item.children?.length && !item.view) {
|
||||||
return
|
return
|
||||||
@@ -385,11 +409,11 @@ function onSelect(e: Event, item: T) {
|
|||||||
<ListboxContent :class="ui.content({ class: props.ui?.content })">
|
<ListboxContent :class="ui.content({ class: props.ui?.content })">
|
||||||
<div v-if="currentView" :class="ui.viewport({ class: props.ui?.viewport })">
|
<div v-if="currentView" :class="ui.viewport({ class: props.ui?.viewport })">
|
||||||
<slot
|
<slot
|
||||||
name="view"
|
:name="currentView.view"
|
||||||
:view-name="currentView.view"
|
|
||||||
:current="currentView"
|
:current="currentView"
|
||||||
:search-term="searchTerm"
|
:search-term="searchTerm"
|
||||||
:navigate-back="navigateBack"
|
:navigate-back="navigateBack"
|
||||||
|
:close="closeView"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user