Fix catalog UI: navbar alignment, selection panel, map search, infinite scroll
All checks were successful
Build Docker Image / build (push) Successful in 3m37s
All checks were successful
Build Docker Image / build (push) Successful in 3m37s
- Fix team selector alignment in navbar (use items-center, fixed height) - Fix SelectionPanel header padding to account for parent p-4 - Add map search input (white glass, positioned next to panel) - Add infinite scroll to SelectionPanel with IntersectionObserver - Products load all at once (no server-side pagination yet) - Hubs and Suppliers support pagination with loadMore
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col h-full">
|
||||
<div class="flex flex-col h-full -m-4">
|
||||
<!-- Header + Search (white glass, sticky) -->
|
||||
<div class="sticky top-0 z-10 -m-4 mb-0 p-3 rounded-t-xl bg-white/90 backdrop-blur-md border-b border-white/20">
|
||||
<div class="sticky top-0 z-10 p-4 rounded-t-xl bg-white/90 backdrop-blur-md border-b border-white/20">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="font-semibold text-base text-base-content">{{ title }}</h3>
|
||||
<button class="btn btn-ghost btn-xs btn-circle text-base-content/60 hover:text-base-content" @click="emit('close')">
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
|
||||
<!-- List -->
|
||||
<div class="flex-1 pt-3">
|
||||
<div class="flex-1 px-4 pt-3 pb-4 overflow-y-auto">
|
||||
<div v-if="loading" class="flex items-center justify-center py-8">
|
||||
<span class="loading loading-spinner loading-md" />
|
||||
</div>
|
||||
@@ -64,6 +64,15 @@
|
||||
@select="onSelect(item)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- Infinite scroll sentinel -->
|
||||
<div
|
||||
v-if="hasMore && !searchQuery"
|
||||
ref="loadMoreSentinel"
|
||||
class="flex items-center justify-center py-4"
|
||||
>
|
||||
<span v-if="loadingMore" class="loading loading-spinner loading-sm text-base-content/60" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -85,16 +94,48 @@ const props = defineProps<{
|
||||
suppliers?: Item[]
|
||||
selectedId?: string
|
||||
loading?: boolean
|
||||
loadingMore?: boolean
|
||||
hasMore?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'select': [type: string, item: Item]
|
||||
'close': []
|
||||
'load-more': []
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const searchQuery = ref('')
|
||||
const loadMoreSentinel = ref<HTMLElement | null>(null)
|
||||
|
||||
// Infinite scroll using IntersectionObserver
|
||||
let observer: IntersectionObserver | null = null
|
||||
|
||||
onMounted(() => {
|
||||
observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
const entry = entries[0]
|
||||
if (entry?.isIntersecting && props.hasMore && !props.loadingMore && !searchQuery.value) {
|
||||
emit('load-more')
|
||||
}
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
)
|
||||
})
|
||||
|
||||
watch(loadMoreSentinel, (el) => {
|
||||
if (el && observer) {
|
||||
observer.observe(el)
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
observer = null
|
||||
}
|
||||
})
|
||||
|
||||
const title = computed(() => {
|
||||
switch (props.selectMode) {
|
||||
|
||||
Reference in New Issue
Block a user