From 18a1c17d98cfe1ac8fabe0dd8cd32f1a3d06c01d Mon Sep 17 00:00:00 2001 From: HugoRCD Date: Fri, 4 Jul 2025 10:06:55 +0200 Subject: [PATCH] feat(CommandPalette): add custom slots --- .../app/pages/components/command-palette.vue | 159 +++++++++++++++++- src/runtime/components/CommandPalette.vue | 34 +++- 2 files changed, 182 insertions(+), 11 deletions(-) diff --git a/playground/app/pages/components/command-palette.vue b/playground/app/pages/components/command-palette.vue index 6b06a24e..8d05c537 100644 --- a/playground/app/pages/components/command-palette.vue +++ b/playground/app/pages/components/command-palette.vue @@ -22,10 +22,6 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode const loading = ref(false) const groups = computed(() => [{ - id: 'users', - label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users', - items: users.value || [] -}, { id: 'actions', items: [{ label: 'Add new file', @@ -74,6 +70,12 @@ const groups = computed(() => [{ toast.add({ title: 'Label added!' }) }, kbds: ['meta', 'L'] + }, { + label: 'Set Wallpaper', + suffix: 'Choose from beautiful wallpaper collection.', + icon: 'i-lucide-image', + interface: 'wallpaper', + placeholder: 'Search wallpapers...' }, { label: 'More actions', placeholder: 'Search actions...', @@ -140,6 +142,116 @@ const labels = [{ }] const label = ref() +const wallpapers = [ + { + id: 1, + name: 'red_distortion_1', + gradient: 'from-red-500 via-orange-500 to-pink-500', + category: 'Abstract', + featured: true + }, + { + id: 2, + name: 'blue_distortion_1', + gradient: 'from-blue-600 via-purple-600 to-indigo-600', + category: 'Abstract', + featured: true + }, + { + id: 3, + name: 'mono_dark_distortion_1', + gradient: 'from-gray-900 via-gray-700 to-gray-800', + category: 'Monochrome', + featured: false + }, + { + id: 4, + name: 'chromatic_dark_1', + gradient: 'from-emerald-600 via-teal-600 to-cyan-600', + category: 'Chromatic', + featured: true + }, + { + id: 5, + name: 'red_distortion_2', + gradient: 'from-rose-600 via-red-600 to-orange-600', + category: 'Abstract', + featured: false + }, + { + id: 6, + name: 'purple_cosmic_1', + gradient: 'from-violet-700 via-purple-700 to-fuchsia-700', + category: 'Cosmic', + featured: true + }, + { + id: 7, + name: 'golden_sunset_1', + gradient: 'from-yellow-500 via-orange-500 to-red-500', + category: 'Nature', + featured: false + }, + { + id: 8, + name: 'ocean_deep_1', + gradient: 'from-blue-800 via-blue-900 to-indigo-900', + category: 'Nature', + featured: true + }, + { + id: 9, + name: 'mono_light_distortion_1', + gradient: 'from-gray-200 via-gray-300 to-gray-400', + category: 'Monochrome', + featured: false + }, + { + id: 10, + name: 'green_matrix_1', + gradient: 'from-green-800 via-emerald-700 to-teal-700', + category: 'Chromatic', + featured: false + }, + { + id: 11, + name: 'pink_dreams_1', + gradient: 'from-pink-500 via-rose-500 to-purple-500', + category: 'Abstract', + featured: true + }, + { + id: 12, + name: 'midnight_blue_1', + gradient: 'from-slate-900 via-blue-900 to-indigo-900', + category: 'Nature', + featured: false + } +] + +const filteredWallpapers = computed(() => { + let filtered = wallpapers + + // Filter by search term + if (searchTerm.value.trim()) { + const search = searchTerm.value.toLowerCase() + filtered = filtered.filter(w => + w.name.toLowerCase().includes(search) + || w.category.toLowerCase().includes(search) + ) + } + + return filtered +}) + +function setWallpaper(wallpaper: any) { + toast.add({ + title: `Wallpaper set to ${wallpaper.name}!`, + description: 'Your desktop wallpaper has been updated.', + icon: 'i-lucide-image' + }) +} + // function onSelect(item: typeof groups.value[number]['items'][number]) { function onSelect(item: any) { console.log('Selected', item) @@ -166,7 +278,44 @@ defineShortcuts({ multiple class="sm:max-h-80" @update:model-value="onSelect" - /> + > + +
diff --git a/src/runtime/components/CommandPalette.vue b/src/runtime/components/CommandPalette.vue index 0fa7476b..b3a01e91 100644 --- a/src/runtime/components/CommandPalette.vue +++ b/src/runtime/components/CommandPalette.vue @@ -31,6 +31,11 @@ export interface CommandPaletteItem extends Omit @@ -149,6 +154,7 @@ export type CommandPaletteSlots = CommandPalett 'empty'(props: { searchTerm?: string }): any 'back'(props: { ui: { [K in keyof Required]: (props?: Record) => string } }): any 'close'(props: { ui: { [K in keyof Required]: (props?: Record) => string } }): any + 'interface'(props: { interfaceName?: string, current: any, searchTerm: string, navigateBack: () => void }): any 'item': SlotProps 'item-leading': SlotProps 'item-label': SlotProps @@ -208,12 +214,17 @@ const fuse = computed(() => defu({}, props.fuse, { matchAllWhenSearchEmpty: true })) -const history = ref<(CommandPaletteGroup & { placeholder?: string })[]>([]) +const history = ref<(CommandPaletteGroup & { placeholder?: string, interface?: string })[]>([]) const placeholder = computed(() => history.value[history.value.length - 1]?.placeholder || props.placeholder || t('commandPalette.placeholder')) const groups = computed(() => history.value?.length ? [history.value[history.value.length - 1] as G] : props.groups) +const _currentInterface = computed(() => { + const current = history.value[history.value.length - 1] + return current?.interface ? current : null +}) + const items = computed(() => groups.value?.filter((group) => { if (!group.id) { console.warn(`[@nuxt/ui] CommandPalette group is missing an \`id\` property`) @@ -280,7 +291,7 @@ const filteredGroups = computed(() => { const listboxRootRef = useTemplateRef('listboxRootRef') function navigate(item: T) { - if (!item.children?.length) { + if (!item.children?.length && !item.interface) { return } @@ -289,7 +300,8 @@ function navigate(item: T) { label: item.label, slot: item.slot, placeholder: item.placeholder, - items: item.children + interface: item.interface, + items: item.children || [] } as any) searchTerm.value = '' @@ -316,7 +328,7 @@ function onBackspace() { } function onSelect(e: Event, item: T) { - if (item.children?.length) { + if (item.children?.length || item.interface) { e.preventDefault() navigate(item) @@ -371,7 +383,17 @@ function onSelect(e: Event, item: T) { -
+
+ +
+ +
{{ get(group, props.labelKey as string) }} @@ -415,7 +437,7 @@ function onSelect(e: Event, item: T) {