Files
RenewCMS/web/src/components/MediaEmptyState.vue
T
2026-10-01 01:36:35 +02:00

82 lines
2.0 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue'
const QUERY_MAX_LENGTH = 40
const props = defineProps<{
variant: 'first-run' | 'no-results' | 'no-duplicates'
query?: string
filterLabel?: string
offline?: boolean
limited?: boolean
}>()
const emit = defineEmits<{ action: [] }>()
const truncatedQuery = computed(() => (props.query ?? '').slice(0, QUERY_MAX_LENGTH))
const current = computed(() => {
if (props.variant === 'first-run') {
return {
icon: 'i-lucide-images',
title: 'No images yet',
description: 'Upload your first image. You can use it in any article.',
action: 'Upload an image',
}
}
if (props.variant === 'no-duplicates') {
return {
icon: 'i-lucide-copy',
title: 'No duplicates',
description: 'Every image in your library is different.',
action: 'Back to all images',
}
}
return {
icon: 'i-lucide-search',
title: truncatedQuery.value
? `No images match "${truncatedQuery.value}"`
: 'No images match this filter',
description: `Nothing matches in ${props.filterLabel ?? 'All'}. Check the spelling, or clear the filters.`,
action: 'Clear filters',
}
})
</script>
<template>
<UEmpty
variant="naked"
:icon="current.icon"
:title="current.title"
:description="current.description"
:ui="{
root: 'gap-3 border border-default bg-default px-6 py-14',
header: 'gap-3',
avatar: 'mb-0 size-11 rounded-none bg-elevated text-toned',
title: 'text-[0.9375rem] font-semibold',
description: 'max-w-80 text-muted text-pretty',
}"
>
<template #actions>
<UButton
v-if="variant === 'first-run'"
icon="i-lucide-upload"
:disabled="offline || limited"
class="h-11 px-4 md:h-8"
@click="emit('action')"
>
{{ current.action }}
</UButton>
<UButton
v-else
color="neutral"
variant="outline"
class="h-11 border border-accented bg-default px-4 text-highlighted ring-0 md:h-8"
@click="emit('action')"
>
{{ current.action }}
</UButton>
</template>
</UEmpty>
</template>