149 lines
4.5 KiB
Vue
149 lines
4.5 KiB
Vue
<script setup lang="ts">
|
|
import { t } from '@/i18n'
|
|
|
|
import { computed } from 'vue'
|
|
import BuilderStatusChip from '@/components/BuilderStatusChip.vue'
|
|
import ContentState from '@/components/ContentState.vue'
|
|
import DirectoryLoadError from '@/components/DirectoryLoadError.vue'
|
|
import EntryActions from '@/components/EntryActions.vue'
|
|
import EntryDeleteDialog from '@/components/EntryDeleteDialog.vue'
|
|
import EntryEditorSkeleton from '@/components/EntryEditorSkeleton.vue'
|
|
import EntryForm from '@/components/EntryForm.vue'
|
|
import EntryNotices from '@/components/EntryNotices.vue'
|
|
import type { EntryEditorPage } from '@/composables/useEntryEditorPage'
|
|
import { typeEndpoint } from '@/lib/contentEndpoints'
|
|
import { entryLoadErrorLine } from '@/lib/entryMessages'
|
|
import { HOME_PATH, contentPath } from '@/lib/routePaths'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
const props = defineProps<{ page: EntryEditorPage }>()
|
|
|
|
const router = useRouter()
|
|
const { phase, isDesktop, typeKey } = props.page
|
|
|
|
function loadErrorLine() {
|
|
const id = props.page.entryId.value
|
|
const base = typeEndpoint(typeKey)
|
|
return entryLoadErrorLine(
|
|
phase.value === 'entryError' && id !== null ? `${base}/entry/${id}` : base,
|
|
)
|
|
}
|
|
|
|
const actionProps = computed(() => ({
|
|
chip: props.page.chip.value,
|
|
savedClock: props.page.savedClock.value,
|
|
creating: props.page.creating.value,
|
|
saving: props.page.saving.value,
|
|
canSave: props.page.canSave.value,
|
|
}))
|
|
|
|
function goHome() {
|
|
router.push(HOME_PATH)
|
|
}
|
|
|
|
function backToList() {
|
|
router.push(contentPath(typeKey))
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<ContentState
|
|
v-if="phase === 'forbidden' || phase === 'typeNotFound'"
|
|
:kind="phase === 'forbidden' ? 'forbidden' : 'notFound'"
|
|
:name="page.typeName.value"
|
|
@home="goHome"
|
|
/>
|
|
<ContentState
|
|
v-else-if="phase === 'entryNotFound'"
|
|
kind="entryNotFound"
|
|
:name="page.typeName.value"
|
|
@back="backToList"
|
|
/>
|
|
|
|
<div v-else class="flex flex-col gap-4" data-testid="entry-editor">
|
|
<div class="flex flex-wrap items-end gap-4">
|
|
<div class="flex min-w-50 flex-1 flex-col gap-0.5">
|
|
<template v-if="phase === 'loading'">
|
|
<USkeleton class="h-7 w-40 rounded-none bg-accented max-lg:hidden" />
|
|
<USkeleton class="h-5 w-28 rounded-none bg-accented" />
|
|
</template>
|
|
<template v-else>
|
|
<h1 class="text-xl font-semibold text-highlighted max-lg:sr-only">
|
|
{{ page.title.value }}
|
|
</h1>
|
|
<p class="text-muted">{{ page.subtitle.value }}</p>
|
|
</template>
|
|
</div>
|
|
<EntryActions
|
|
v-if="isDesktop && phase === 'ready'"
|
|
v-bind="actionProps"
|
|
@remove="page.removal.open"
|
|
@cancel="page.cancel"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
v-if="!isDesktop && phase === 'ready'"
|
|
class="flex min-h-5 items-center justify-between"
|
|
>
|
|
<BuilderStatusChip :status="page.chip.value" :saved-at="page.savedClock.value" />
|
|
</div>
|
|
|
|
<DirectoryLoadError
|
|
v-if="phase === 'typeError' || phase === 'entryError'"
|
|
:title="t('Couldn\'t load the entry')"
|
|
:description="loadErrorLine()"
|
|
@retry="page.retryLoad"
|
|
/>
|
|
<EntryEditorSkeleton v-else-if="phase === 'loading'" />
|
|
<template v-else>
|
|
<EntryNotices
|
|
:failure="page.failure.value"
|
|
:schema-changed="page.schemaChanged.value"
|
|
:schema-field="page.schemaField.value"
|
|
:issues="page.form.issues.value"
|
|
:fields="page.fields.value"
|
|
:type-name="page.typeName.value"
|
|
@retry="page.submit"
|
|
@reload="page.reload"
|
|
/>
|
|
<EntryForm
|
|
:fields="page.fields.value"
|
|
:values="page.form.values.value"
|
|
:images="page.form.images.value"
|
|
:relations="page.form.relations.value"
|
|
:type-name="page.typeName.value"
|
|
:issues="page.form.issues.value"
|
|
:first-issue="page.form.firstIssue.value"
|
|
:focus-token="page.focusToken.value"
|
|
:locked="page.locked.value"
|
|
:saving="page.saving.value"
|
|
:creating="page.creating.value"
|
|
:is-default="page.form.isDefault"
|
|
:entry-line="page.entryLine.value"
|
|
:created-line="page.createdLine.value"
|
|
:updated-line="page.updatedLine.value"
|
|
@update="page.change"
|
|
@submit="page.submit"
|
|
/>
|
|
</template>
|
|
</div>
|
|
|
|
<div
|
|
v-if="!isDesktop && phase === 'ready'"
|
|
class="sticky bottom-0 -mx-4 mt-auto flex border-t border-default bg-default px-4 py-3"
|
|
>
|
|
<EntryActions v-bind="actionProps" bar @remove="page.removal.open" @cancel="page.cancel" />
|
|
</div>
|
|
|
|
<EntryDeleteDialog
|
|
v-if="page.removal.stage.value !== 'closed'"
|
|
:title="page.title.value"
|
|
:type-name="page.typeName.value"
|
|
:pending="page.removal.pending.value"
|
|
:failed="page.removal.stage.value === 'failed'"
|
|
@confirm="page.removal.confirm"
|
|
@close="page.removal.close"
|
|
/>
|
|
</template>
|