60 lines
1.5 KiB
Vue
60 lines
1.5 KiB
Vue
<template>
|
|
<aside class="w-64 bg-base-100 h-screen flex flex-col border-r border-base-300">
|
|
<div class="p-4 border-b border-base-300">
|
|
<NuxtLink :to="backLink" class="btn btn-sm btn-ghost gap-2">
|
|
<Icon name="lucide:arrow-left" size="18" />
|
|
{{ backLabel }}
|
|
</NuxtLink>
|
|
</div>
|
|
|
|
<div class="p-4 border-b border-base-300">
|
|
<Text weight="semibold">{{ title }}</Text>
|
|
<Text tone="muted" size="sm">{{ itemsCount }} {{ t('catalogMap.labels.items') }}</Text>
|
|
</div>
|
|
|
|
<div v-if="filters && filters.length > 0" class="p-4 border-b border-base-300">
|
|
<CatalogFilters
|
|
:filters="filters"
|
|
:model-value="selectedFilter"
|
|
@update:model-value="$emit('update:selectedFilter', $event)"
|
|
/>
|
|
</div>
|
|
|
|
<div class="flex-1 overflow-y-auto p-2 bg-base-200">
|
|
<div v-if="loading" class="flex items-center justify-center h-32">
|
|
<span class="loading loading-spinner loading-md"></span>
|
|
</div>
|
|
<div v-else class="space-y-2">
|
|
<slot name="cards" />
|
|
<div v-if="itemsCount === 0" class="text-center text-base-content/50 py-8">
|
|
{{ emptyText }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
interface Filter {
|
|
id: string
|
|
label: string
|
|
}
|
|
|
|
const { t } = useI18n()
|
|
|
|
defineProps<{
|
|
title: string
|
|
backLink: string
|
|
backLabel: string
|
|
itemsCount: number
|
|
loading?: boolean
|
|
filters?: Filter[]
|
|
selectedFilter?: string
|
|
emptyText?: string
|
|
}>()
|
|
|
|
defineEmits<{
|
|
'update:selectedFilter': [value: string]
|
|
}>()
|
|
</script>
|