57 lines
1.9 KiB
Vue
57 lines
1.9 KiB
Vue
<template>
|
|
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-xl overflow-hidden min-w-[12rem] flex flex-col p-1 gap-0.5">
|
|
<template v-if="items.length">
|
|
<button
|
|
v-for="(item, index) in items"
|
|
:key="item.id"
|
|
class="flex items-center gap-2 px-2 py-1.5 text-sm rounded text-left transition-colors w-full"
|
|
:class="{ 'bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-400': index === selectedIndex, 'hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-200': index !== selectedIndex }"
|
|
@click="selectItem(index)"
|
|
>
|
|
<UIcon :name="item.isFolder ? 'i-heroicons-folder' : 'i-heroicons-document-text'" class="w-4 h-4 text-gray-400" />
|
|
<span class="truncate">{{ item.title }}</span>
|
|
</button>
|
|
</template>
|
|
<div v-else class="px-3 py-2 text-xs text-gray-400 text-center">
|
|
Keine Seite gefunden
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, watch } from 'vue'
|
|
|
|
const props = defineProps({
|
|
items: { type: Array, required: true },
|
|
command: { type: Function, required: true },
|
|
})
|
|
|
|
const selectedIndex = ref(0)
|
|
|
|
// Wenn sich die Liste ändert, Reset Selection
|
|
watch(() => props.items, () => { selectedIndex.value = 0 })
|
|
|
|
function selectItem(index: number) {
|
|
const item = props.items[index]
|
|
if (item) props.command({ id: item.id, label: item.title })
|
|
}
|
|
|
|
function onKeyDown({ event }: { event: KeyboardEvent }) {
|
|
if (event.key === 'ArrowUp') {
|
|
selectedIndex.value = (selectedIndex.value + props.items.length - 1) % props.items.length
|
|
return true
|
|
}
|
|
if (event.key === 'ArrowDown') {
|
|
selectedIndex.value = (selectedIndex.value + 1) % props.items.length
|
|
return true
|
|
}
|
|
if (event.key === 'Enter') {
|
|
selectItem(selectedIndex.value)
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Expose für Tiptap Render Logic
|
|
defineExpose({ onKeyDown })
|
|
</script> |