feat: media page T1

This commit is contained in:
fsylvain committed 2026-10-01 01:36:35 +02:00
1 parent 67d456baf6
commit 008b0dfbb9
46 files changed
+5742 -204

No files matched your search

@@ -0,0 +1,76 @@
<script setup lang="ts">
import { computed } from 'vue'
import ConfirmDialog from '@/components/ConfirmDialog.vue'
import MediaBadge from '@/components/MediaBadge.vue'
import type { MediaItem } from '@/composables/useMedia'
import { pluralArticles } from '@/lib/mediaFormat'
const BROKEN_IMAGE = 'which will show a broken image.'
const FINAL_WARNING = "This can't be undone."
const props = defineProps<{
items: MediaItem[]
action: () => Promise<void | boolean>
}>()
const emit = defineEmits<{ close: [confirmed: boolean] }>()
const total = computed(() => props.items.length)
const imageLabel = computed(() => `${total.value} ${total.value === 1 ? 'image' : 'images'}`)
const inUse = computed(() => props.items.filter((item) => item.used_in > 0))
const articleCount = computed(() => inUse.value.reduce((sum, item) => sum + item.used_in, 0))
const description = computed(() => {
const usedCount = inUse.value.length
const unusedCount = total.value - usedCount
const articles = pluralArticles(articleCount.value)
if (usedCount === 0) {
return total.value === 1
? `It isn't used in any article. ${FINAL_WARNING}`
: `None of them are used in any article. ${FINAL_WARNING}`
}
if (unusedCount === 0) {
const subject = total.value === 1 ? "It's" : `All ${total.value} are`
return `${subject} used in ${articles}, ${BROKEN_IMAGE} ${FINAL_WARNING}`
}
const rest =
unusedCount === 1
? "The other one isn't used anywhere."
: `The other ${unusedCount} aren't used anywhere.`
return `${usedCount} of them are used in ${articles}, ${BROKEN_IMAGE} ${rest} ${FINAL_WARNING}`
})
</script>
<template>
<ConfirmDialog
:title="`Delete ${imageLabel}?`"
:description="description"
:confirm-label="`Delete ${imageLabel}`"
cancel-label="Cancel"
pending-label="Deleting…"
tone="danger"
:action="action"
@close="emit('close', $event)"
>
<template #body>
<ul class="border border-default">
<li
v-for="(item, index) in items"
:key="item.id"
data-testid="bulk-delete-row"
class="flex min-h-9 items-center gap-2 px-3"
:class="{ 'border-t border-muted': index > 0 }"
>
<span class="min-w-0 flex-1 truncate text-highlighted">{{
item.filename
}}</span>
<MediaBadge
v-if="item.used_in > 0"
kind="used"
:label="`Used in ${item.used_in}`"
/>
<MediaBadge v-else kind="unused" label="Unused" />
</li>
</ul>
</template>
</ConfirmDialog>
</template>