feat: entry editor at /content/:key/new and /content/:key/:id

This commit is contained in:
Florian Sylvain committed 2026-10-21 00:12:34 +02:00
1 parent 91d916fb74
commit fba20f83c5
94 files changed
+7116 -423

No files matched your search

+90
View File
@@ -0,0 +1,90 @@
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { t } from '@/i18n'
import { useLocalizedToast } from '@/i18n/presentation'
import { ApiError } from '@/composables/useApi'
import { useEntries } from '@/composables/useEntries'
import type { EntryDraft } from '@/composables/useEntryDraft'
import { isGoneError } from '@/lib/entryServerError'
import { contentPath } from '@/lib/routePaths'
const UNAUTHORIZED = 401
const TOAST_ID = 'entry-deleted'
export type RemovalStage = 'closed' | 'confirm' | 'failed'
export function useEntryRemoval(editor: EntryDraft, typeName: () => string, title: () => string) {
const router = useRouter()
const toast = useLocalizedToast()
const { deleteEntry } = useEntries()
const stage = ref<RemovalStage>('closed')
const pending = ref(false)
const done = ref(false)
function open() {
if (!pending.value && !editor.saving.value && editor.entryId.value !== null) {
stage.value = 'confirm'
}
}
function close() {
if (!pending.value) {
stage.value = 'closed'
}
}
function announce(deletedTitle: string) {
toast.add(() => ({
id: TOAST_ID,
color: 'success',
icon: 'i-lucide-circle-check',
title: t('Entry deleted'),
description: t('"{0}" was deleted from {1}.', [deletedTitle, typeName()]),
}))
}
function refuse(error: unknown) {
if (error instanceof ApiError && error.status === UNAUTHORIZED) {
return
}
if (isGoneError(error)) {
stage.value = 'closed'
editor.load.markGone(error)
return
}
stage.value = 'failed'
}
async function confirm() {
const id = editor.entryId.value
if (pending.value || id === null) {
return
}
const deletedTitle = title()
pending.value = true
stage.value = 'confirm'
try {
await deleteEntry(editor.typeKey, id)
} catch (error) {
pending.value = false
refuse(error)
return
}
pending.value = false
done.value = true
stage.value = 'closed'
announce(deletedTitle)
const arrived = await router.replace(contentPath(editor.typeKey)).then(
(failure) => !failure,
() => false,
)
if (!arrived) {
done.value = false
}
}
return { stage, pending, done, open, close, confirm }
}
export type EntryRemoval = ReturnType<typeof useEntryRemoval>