feat(ui): use modal dialogs for entity creation and editing
Introduce reusable Modal component for forms Update router to preserve scroll position when toggling modals Refactor admin and entity views to render editors as overlays
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import PageHeader from '../components/PageHeader.vue';
|
||||
import Modal from '../components/Modal.vue';
|
||||
import Skeleton from '../components/Skeleton.vue';
|
||||
import StatusMessage from '../components/StatusMessage.vue';
|
||||
import TagsSelect from '../components/TagsSelect.vue';
|
||||
@@ -49,6 +49,10 @@ function errorText(error: unknown, fallback: string) {
|
||||
return error instanceof Error && error.message ? error.message : fallback;
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
void router.push(cancelTo.value);
|
||||
}
|
||||
|
||||
async function loadOptions() {
|
||||
const [loadedOptions, loadedLanguages] = await Promise.all([api.options(), api.languages()]);
|
||||
options.value = loadedOptions;
|
||||
@@ -153,17 +157,10 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="page-stack">
|
||||
<PageHeader :title="pageTitle" :subtitle="t('pages.items.editSubtitle')">
|
||||
<template #kicker>Item Edit</template>
|
||||
<template #actions>
|
||||
<RouterLink class="ui-button ui-button--blue ui-button--small" :to="cancelTo">{{ t('common.back') }}</RouterLink>
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<Modal :title="pageTitle" :subtitle="t('pages.items.editSubtitle')" :close-label="t('common.close')" size="wide" @close="closeEditor">
|
||||
<StatusMessage v-if="message" variant="danger">{{ message }}</StatusMessage>
|
||||
|
||||
<form v-if="!loading && options" class="detail-section" @submit.prevent="saveItem">
|
||||
<form v-if="!loading && options" id="item-edit-form" class="modal-edit-form" @submit.prevent="saveItem">
|
||||
<TranslationFields
|
||||
id-prefix="item-name"
|
||||
v-model:base-value="itemForm.name"
|
||||
@@ -236,18 +233,18 @@ onMounted(() => {
|
||||
@create="createMultiOption('item-tags', 'favorite-things', $event, itemForm.tagIds)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="link-button" :disabled="busy">{{ busy ? t('common.saving') : t('common.save') }}</button>
|
||||
<RouterLink class="plain-button" :to="cancelTo">{{ t('common.cancel') }}</RouterLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<section v-else class="detail-section skeleton-detail-section" aria-busy="true" :aria-label="t('pages.items.loadingEdit')">
|
||||
<section v-else class="modal-edit-form skeleton-detail-section" aria-busy="true" :aria-label="t('pages.items.loadingEdit')">
|
||||
<div v-for="index in 6" :key="index" class="field">
|
||||
<Skeleton :width="index === 1 ? '52px' : '88px'" />
|
||||
<Skeleton variant="box" height="44px" />
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<template v-if="!loading && options" #footer>
|
||||
<button type="submit" form="item-edit-form" class="link-button" :disabled="busy">{{ busy ? t('common.saving') : t('common.save') }}</button>
|
||||
<button type="button" class="plain-button" :disabled="busy" @click="closeEditor">{{ t('common.cancel') }}</button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user