mirror of
https://github.com/abhinavxd/libredesk.git
synced 2026-09-11 13:28:57 +00:00
cap macro command palette list at 200 and scope highlight observer
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<CommandDialog :open="open" @update:open="toggleOpen" class="transform-gpu z-[51] !min-w-[50vw]">
|
||||
<CommandDialog
|
||||
:open="open"
|
||||
v-model:search-term="searchTerm"
|
||||
:filter-function="isMacroMode ? passThroughFilter : undefined"
|
||||
@update:open="toggleOpen"
|
||||
class="transform-gpu z-[51] !min-w-[50vw]"
|
||||
>
|
||||
<CommandInput :placeholder="t('command.typeCmdOrSearch')" @keydown="onInputKeydown" />
|
||||
<CommandList
|
||||
class="!min-h-[50vh] h-[50vh] !min-w-[50vw]"
|
||||
@@ -41,19 +47,14 @@
|
||||
</CommandGroup>
|
||||
|
||||
<!-- Macros -->
|
||||
<div
|
||||
v-if="
|
||||
nestedCommand === 'apply-macro-to-existing-conversation' ||
|
||||
nestedCommand === 'apply-macro-to-new-conversation'
|
||||
"
|
||||
>
|
||||
<div v-if="isMacroMode">
|
||||
<CommandGroup :heading="$t('actions.applyMacro')">
|
||||
<div class="min-h-[400px]">
|
||||
<div class="h-[60vh] grid grid-cols-12">
|
||||
<!-- Left Column: Macro List (30%) -->
|
||||
<div class="col-span-4 pr-2 border-r overflow-y-auto h-full">
|
||||
<div ref="macroListRef" class="col-span-4 pr-2 border-r overflow-y-auto h-full">
|
||||
<CommandItem
|
||||
v-for="(macro, index) in macroStore.macroOptions"
|
||||
v-for="(macro, index) in visibleMacros"
|
||||
:key="macro.value"
|
||||
:value="macro.label + '|' + index"
|
||||
:data-index="index"
|
||||
@@ -247,6 +248,8 @@ import { Label } from '@shared-ui/components/ui/label'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Letter } from 'vue-letter'
|
||||
|
||||
const RENDER_CAP = 200
|
||||
|
||||
const conversationStore = useConversationStore()
|
||||
const macroStore = useMacroStore()
|
||||
const { t } = useI18n()
|
||||
@@ -257,6 +260,34 @@ const showDatePicker = ref(false)
|
||||
const datePickerOpen = ref(false)
|
||||
const selectedDate = ref(null)
|
||||
const selectedTime = ref('12:00')
|
||||
const searchTerm = ref('')
|
||||
const macroListRef = ref(null)
|
||||
|
||||
const passThroughFilter = (items) => items
|
||||
|
||||
const isMacroMode = computed(
|
||||
() =>
|
||||
nestedCommand.value === 'apply-macro-to-existing-conversation' ||
|
||||
nestedCommand.value === 'apply-macro-to-new-conversation'
|
||||
)
|
||||
|
||||
const macroSearchIndex = computed(() =>
|
||||
macroStore.macroOptions.map((m) => ({ macro: m, labelLower: String(m.label).toLowerCase() }))
|
||||
)
|
||||
|
||||
const visibleMacros = computed(() => {
|
||||
const term = searchTerm.value?.trim().toLowerCase()
|
||||
const index = macroSearchIndex.value
|
||||
if (!term) {
|
||||
const all = macroStore.macroOptions
|
||||
return all.length > RENDER_CAP ? all.slice(0, RENDER_CAP) : all
|
||||
}
|
||||
const matched = []
|
||||
for (let i = 0; i < index.length && matched.length < RENDER_CAP; i++) {
|
||||
if (index[i].labelLower.includes(term)) matched.push(index[i].macro)
|
||||
}
|
||||
return matched
|
||||
})
|
||||
|
||||
const { Meta_K, Ctrl_K } = useMagicKeys({
|
||||
passive: false,
|
||||
@@ -370,24 +401,26 @@ const nestedCommandHandler = (data) => {
|
||||
open.value = data.open
|
||||
}
|
||||
|
||||
let highlightObserver = null
|
||||
|
||||
watch(macroListRef, (el) => {
|
||||
highlightObserver?.disconnect()
|
||||
highlightObserver = null
|
||||
highlightedMacro.value = null
|
||||
if (!el) return
|
||||
highlightObserver = new MutationObserver(() => {
|
||||
const idx = el.querySelector('[data-highlighted]')?.getAttribute('data-index')
|
||||
highlightedMacro.value = idx != null ? visibleMacros.value[idx] : null
|
||||
})
|
||||
highlightObserver.observe(el, { attributes: true, attributeFilter: ['data-highlighted'], subtree: true })
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
emitter.on(EMITTER_EVENTS.SET_NESTED_COMMAND, nestedCommandHandler)
|
||||
watchHighlightedMacro()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off(EMITTER_EVENTS.SET_NESTED_COMMAND, nestedCommandHandler)
|
||||
highlightObserver?.disconnect()
|
||||
})
|
||||
|
||||
const watchHighlightedMacro = () => {
|
||||
const observer = new MutationObserver(() => {
|
||||
const highlightedEl = document.querySelector('[data-highlighted]')?.getAttribute('data-index')
|
||||
highlightedMacro.value = highlightedEl ? macroStore.macroOptions[highlightedEl] : null
|
||||
})
|
||||
|
||||
observer.observe(document.body, {
|
||||
attributes: true,
|
||||
subtree: true
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -7,17 +7,22 @@ const props = defineProps({
|
||||
open: { type: Boolean, required: false },
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
modal: { type: Boolean, required: false },
|
||||
searchTerm: { type: String, required: false },
|
||||
filterFunction: { type: Function, required: false },
|
||||
class: { type: String, required: false }
|
||||
})
|
||||
const emits = defineEmits(['update:open'])
|
||||
const emits = defineEmits(['update:open', 'update:searchTerm'])
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-bind="forwarded">
|
||||
<DialogContent :class="['overflow-hidden p-0 shadow-lg', props.class]">
|
||||
<DialogContent :class="['overflow-hidden p-0 shadow-lg', props.class]">
|
||||
<Command
|
||||
:search-term="props.searchTerm"
|
||||
:filter-function="props.filterFunction"
|
||||
@update:search-term="$emit('update:searchTerm', $event)"
|
||||
class="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
|
||||
>
|
||||
<slot />
|
||||
|
||||
Reference in New Issue
Block a user