mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-05 03:57:03 -04:00
261 lines
9.6 KiB
Vue
261 lines
9.6 KiB
Vue
<script setup lang="ts">
|
|
import { loadPronounLibrary } from '../src/data.ts';
|
|
|
|
import useConfig from '~/composables/useConfig.ts';
|
|
import useDialogue from '~/composables/useDialogue.ts';
|
|
import { Source } from '~/src/classes.ts';
|
|
|
|
type FormData = Pick<Source, 'pronouns' | 'type' | 'author' | 'title' | 'extra' | 'year' | 'fragments' | 'comment'
|
|
| 'images' | 'link' | 'spoiler' | 'key'> & { base: string | null };
|
|
|
|
const config = useConfig();
|
|
|
|
const form = ref<FormData>({
|
|
pronouns: [''],
|
|
type: '',
|
|
author: '',
|
|
title: '',
|
|
extra: '',
|
|
year: null,
|
|
fragments: [],
|
|
comment: '',
|
|
images: [],
|
|
link: '',
|
|
spoiler: false,
|
|
key: null,
|
|
base: null,
|
|
});
|
|
|
|
const submitting = ref(false);
|
|
const afterSubmit = ref(false);
|
|
|
|
const dialogue = useDialogue();
|
|
const submit = async (): Promise<void> => {
|
|
submitting.value = true;
|
|
try {
|
|
await dialogue.postWithAlertOnError('/api/sources/submit', form.value);
|
|
|
|
afterSubmit.value = true;
|
|
form.value = {
|
|
pronouns: [''],
|
|
type: '',
|
|
author: '',
|
|
title: '',
|
|
extra: '',
|
|
year: null,
|
|
fragments: [],
|
|
comment: '',
|
|
images: [],
|
|
link: '',
|
|
spoiler: false,
|
|
key: null,
|
|
base: null,
|
|
};
|
|
} finally {
|
|
submitting.value = false;
|
|
}
|
|
};
|
|
|
|
const section = useTemplateRef('section');
|
|
const edit = (source: Source): void => {
|
|
form.value = {
|
|
pronouns: source.pronouns,
|
|
type: source.type,
|
|
author: source.author,
|
|
title: source.title,
|
|
extra: source.extra,
|
|
year: source.year,
|
|
fragments: source.fragments,
|
|
comment: source.comment,
|
|
images: source.images,
|
|
link: source.link,
|
|
spoiler: source.spoiler,
|
|
key: source.key,
|
|
base: source.id,
|
|
};
|
|
afterSubmit.value = false;
|
|
section.value?.scrollIntoView();
|
|
};
|
|
|
|
defineExpose({ edit });
|
|
|
|
const pronounLibrary = await loadPronounLibrary(config);
|
|
const { data: keys } = await useFetch('/api/sources/keys', { lazy: true, default: () => ({}) });
|
|
</script>
|
|
|
|
<template>
|
|
<div ref="section" class="card">
|
|
<div class="card-header">
|
|
<Icon v="plus-circle" />
|
|
<T>sources.submit.header</T>
|
|
</div>
|
|
<div v-if="$user()" class="card-body">
|
|
<div v-if="afterSubmit" class="alert alert-success text-center">
|
|
<p>
|
|
<T>sources.submit.thanks</T>
|
|
</p>
|
|
<p>
|
|
<button type="button" class="btn btn-success" @click="afterSubmit = false">
|
|
<Icon v="plus" />
|
|
<T>sources.submit.another</T>
|
|
</button>
|
|
</p>
|
|
</div>
|
|
<form v-else @submit.prevent="submit">
|
|
<div class="form-group">
|
|
<label for="type" class="required"><T>sources.submit.type</T></label>
|
|
<select id="type" v-model="form.type" class="form-control" required>
|
|
<option value=""></option>
|
|
<template v-for="t in Object.keys(Source.TYPES)">
|
|
<option v-if="t !== ''" :key="t" :value="t">
|
|
{{ $t(`sources.type.${t}`) }}
|
|
</option>
|
|
</template>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="author"><T>sources.submit.author</T></label>
|
|
<input
|
|
id="author"
|
|
v-model="form.author"
|
|
type="text"
|
|
class="form-control"
|
|
maxlength="255"
|
|
>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="title" class="required"><T>sources.submit.title</T></label>
|
|
<input
|
|
id="title"
|
|
v-model="form.title"
|
|
type="text"
|
|
class="form-control"
|
|
required
|
|
maxlength="255"
|
|
>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="extra"><T>sources.submit.extra</T></label>
|
|
<input
|
|
id="extra"
|
|
v-model="form.extra"
|
|
type="text"
|
|
class="form-control"
|
|
maxlength="255"
|
|
>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="year"><T>sources.submit.year</T></label>
|
|
<input
|
|
id="year"
|
|
v-model="form.year"
|
|
type="number"
|
|
class="form-control"
|
|
min="0"
|
|
max="2100"
|
|
>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="fragments"><T>sources.submit.fragments</T></label>
|
|
<p class="small text-muted mb-0">
|
|
<T>sources.submit.fragmentsInfo</T>
|
|
</p>
|
|
<ListInput id="fragments" v-slot="s" v-model="form.fragments">
|
|
<textarea v-model="s.val" class="form-control" rows="3" required @keyup="s.update(s.val)"></textarea>
|
|
</ListInput>
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="form-check form-switch my-2">
|
|
<label>
|
|
<input v-model="form.spoiler" class="form-check-input" type="checkbox" role="switch">
|
|
<T>sources.submit.spoiler</T>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="pronouns" class="required"><T>sources.submit.pronouns</T></label>
|
|
<p class="small text-muted mb-0">
|
|
<T>sources.submit.pronounsInfo</T>
|
|
</p>
|
|
<ListInput v-model="form.pronouns">
|
|
<template #default="s">
|
|
<input
|
|
v-model="s.val"
|
|
type="text"
|
|
class="form-control"
|
|
required
|
|
maxlength="24"
|
|
@keyup="s.update(s.val)"
|
|
>
|
|
</template>
|
|
<template #validation="s">
|
|
<p
|
|
v-if="s.val && !pronounLibrary.isCanonical(s.val) && !(config.sources.extraTypes || []).includes(s.val)"
|
|
class="small text-danger"
|
|
>
|
|
<Icon v="exclamation-triangle" />
|
|
<span class="ml-1"><T>profile.pronounsNotFound</T></span>
|
|
</p>
|
|
</template>
|
|
</ListInput>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="comment"><T>sources.submit.comment</T></label>
|
|
<input
|
|
id="comment"
|
|
v-model="form.comment"
|
|
type="text"
|
|
class="form-control"
|
|
maxlength="255"
|
|
>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="link"><T>sources.submit.link</T></label>
|
|
<input
|
|
id="link"
|
|
v-model="form.link"
|
|
type="url"
|
|
class="form-control"
|
|
maxlength="255"
|
|
>
|
|
</div>
|
|
<div class="form-group">
|
|
<label><T>sources.submit.images</T></label>
|
|
<ImageWidget v-model="form.images" multiple sizes="big,thumb" />
|
|
</div>
|
|
<div v-if="$isGranted('sources')" class="form-group">
|
|
<label for="key"><T>sources.submit.key</T></label>
|
|
<AutocompleteSelect
|
|
id="key"
|
|
v-model="form.key"
|
|
maxlength="255"
|
|
:options="keys"
|
|
freeform
|
|
/>
|
|
<p class="small text-muted">
|
|
<T>sources.submit.keyInfo</T>
|
|
<T>sources.submit.keyInfoConvention</T>
|
|
</p>
|
|
</div>
|
|
<div v-if="form.base" class="alert alert-info">
|
|
<Icon v="info-circle" />
|
|
<T>nouns.editing</T>
|
|
<button type="button" class="btn btn-sm float-end" @click="form.base = null">
|
|
<Icon v="times" />
|
|
</button>
|
|
</div>
|
|
<button type="submit" class="btn btn-success w-100" :disabled="submitting">
|
|
<Icon v="plus-circle" />
|
|
<T>sources.submit.action</T>
|
|
</button>
|
|
<p class="small text-muted mt-1">
|
|
<T>sources.submit.moderation</T>
|
|
</p>
|
|
</form>
|
|
</div>
|
|
<div v-else class="card-body py-5 text-center">
|
|
<T>crud.loginRequired</T>
|
|
</div>
|
|
</div>
|
|
</template>
|