feat(SPA): media page T0
This commit is contained in:
1 parent
0d99544579
commit
67d456baf6
32 files changed
+4874
-40
No files matched your search
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue'
|
||||
import type { MediaItem } from '@/composables/useMedia'
|
||||
import { isValidFilenameStem, splitFilename } from '@/lib/mediaFormat'
|
||||
|
||||
const INVALID_FILENAME_MESSAGE = 'Enter a filename.'
|
||||
|
||||
const props = defineProps<{
|
||||
item: MediaItem
|
||||
action: (stem: string) => Promise<void>
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{ close: [confirmed: boolean] }>()
|
||||
|
||||
const parts = splitFilename(props.item.filename)
|
||||
const stem = ref(parts.stem)
|
||||
const touched = ref(false)
|
||||
|
||||
const error = computed(() =>
|
||||
touched.value && !isValidFilenameStem(stem.value) ? INVALID_FILENAME_MESSAGE : undefined,
|
||||
)
|
||||
const help = computed(
|
||||
() => `Letters, numbers, dashes and underscores. The ${parts.extension} ending stays.`,
|
||||
)
|
||||
|
||||
async function submit() {
|
||||
touched.value = true
|
||||
if (!isValidFilenameStem(stem.value)) {
|
||||
return false
|
||||
}
|
||||
await props.action(stem.value.trim())
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfirmDialog
|
||||
title="Rename image"
|
||||
description="Only the filename changes. The URL stays the same, so articles that use this image keep working."
|
||||
confirm-label="Rename"
|
||||
cancel-label="Cancel"
|
||||
pending-label="Renaming…"
|
||||
tone="neutral"
|
||||
:action="submit"
|
||||
@close="emit('close', $event)"
|
||||
>
|
||||
<template #body="{ pending, confirm }">
|
||||
<form class="flex flex-col" novalidate @submit.prevent="confirm">
|
||||
<UFormField
|
||||
label="Filename"
|
||||
name="filename"
|
||||
:error="error"
|
||||
:help="help"
|
||||
:ui="{ error: 'mt-1.5 text-xs/5', help: 'mt-1.5 text-xs/5' }"
|
||||
>
|
||||
<template v-if="error" #error="{ error: message }">
|
||||
<span class="flex items-center gap-1.5">
|
||||
<UIcon
|
||||
name="i-lucide-circle-alert"
|
||||
class="size-3.5 shrink-0 text-error"
|
||||
/>
|
||||
{{ message }}
|
||||
</span>
|
||||
</template>
|
||||
<UInput
|
||||
v-model="stem"
|
||||
autocomplete="off"
|
||||
:disabled="pending"
|
||||
class="w-full"
|
||||
:highlight="!!error"
|
||||
:ui="{ base: 'h-11 text-lg md:h-10 md:text-base' }"
|
||||
@blur="touched = true"
|
||||
>
|
||||
<template #trailing>
|
||||
<span class="font-mono text-base text-muted">{{
|
||||
parts.extension
|
||||
}}</span>
|
||||
</template>
|
||||
</UInput>
|
||||
</UFormField>
|
||||
</form>
|
||||
</template>
|
||||
</ConfirmDialog>
|
||||
</template>
|
||||
Reference in new issue
Block a user