Virtual list in property select
This commit is contained in:
@@ -154,7 +154,7 @@
|
||||
<!-- Panel Extension - Portal target for additional content -->
|
||||
<div
|
||||
id="panel-extension"
|
||||
class="absolute max-h-96 h-full empty:hidden z-30 w-64 top-1.5 bg-foundation border border-outline-2 rounded-lg overflow-hidden"
|
||||
class="absolute max-h-[calc(100dvh-4rem)] empty:hidden z-30 w-64 top-1.5 bg-foundation border border-outline-2 rounded-lg overflow-hidden"
|
||||
:style="`left: ${panelExtensionLeft}px`"
|
||||
>
|
||||
<PortalTarget name="panel-extension"></PortalTarget>
|
||||
|
||||
@@ -6,37 +6,50 @@
|
||||
input-id="property-search"
|
||||
/>
|
||||
|
||||
<div class="flex-1 overflow-y-auto overflow-x-hidden simple-scrollbar p-2">
|
||||
<div class="flex flex-col">
|
||||
<button
|
||||
v-for="property in filteredOptions"
|
||||
:key="property.value"
|
||||
class="p-2 text-foreground rounded hover:bg-highlight-1 text-left flex items-center gap-2"
|
||||
@click="$emit('selectProperty', property.value)"
|
||||
>
|
||||
<component
|
||||
:is="getPropertyTypeDisplay(property.type).icon"
|
||||
class="h-3 w-3 shrink-0"
|
||||
:class="getPropertyTypeDisplay(property.type).classes"
|
||||
/>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="text-body-2xs font-medium text-foreground truncate">
|
||||
{{ property.label }}
|
||||
<div
|
||||
v-bind="containerProps"
|
||||
class="relative simple-scrollbar"
|
||||
:style="{ height: containerHeight }"
|
||||
>
|
||||
<div
|
||||
v-for="{ data: property, index } in list"
|
||||
:key="`${index}-${property.value}`"
|
||||
:style="{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: `${itemHeight}px`,
|
||||
transform: `translateY(${index * itemHeight}px)`
|
||||
}"
|
||||
>
|
||||
<div class="px-1">
|
||||
<button
|
||||
class="w-full h-full py-1.5 px-2 text-foreground rounded hover:bg-highlight-1 text-left flex items-center gap-2"
|
||||
@click="$emit('selectProperty', property.value)"
|
||||
>
|
||||
<component
|
||||
:is="getPropertyTypeDisplay(property.type).icon"
|
||||
class="h-3 w-3 shrink-0"
|
||||
:class="getPropertyTypeDisplay(property.type).classes"
|
||||
/>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="text-body-2xs font-medium text-foreground truncate">
|
||||
{{ property.label }}
|
||||
</div>
|
||||
<div class="text-body-3xs text-foreground-2 truncate -mt-0.5">
|
||||
{{ property.parentPath || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="property.parentPath"
|
||||
class="text-body-3xs text-foreground-2 truncate -mt-1"
|
||||
>
|
||||
{{ property.parentPath }}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVirtualList } from '@vueuse/core'
|
||||
import { useFilterUtilities } from '~~/lib/viewer/composables/filtering'
|
||||
|
||||
type PropertyOption = {
|
||||
@@ -73,4 +86,18 @@ const filteredOptions = computed(() => {
|
||||
option.type.toLowerCase().includes(searchTerm)
|
||||
)
|
||||
})
|
||||
|
||||
// Virtual list setup
|
||||
const itemHeight = 42
|
||||
const maxHeight = 300 // Maximum height for the container
|
||||
|
||||
const containerHeight = computed(() => {
|
||||
const contentHeight = filteredOptions.value.length * itemHeight
|
||||
return `${Math.min(contentHeight, maxHeight)}px`
|
||||
})
|
||||
|
||||
const { list, containerProps } = useVirtualList(filteredOptions, {
|
||||
itemHeight,
|
||||
overscan: 5
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user