Files
RenewCMS/web/src/components/EntryEditor.vue
T

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>