Article creation overhaul

This commit is contained in:
Florian Sylvain
2023-01-09 12:03:03 +01:00
parent 408686a644
commit 29255c047a
4 changed files with 60 additions and 27 deletions
+22 -1
View File
@@ -65,7 +65,8 @@ a,
input, input,
label, label,
button, button,
span { span,
li {
font-family: 'Hind', sans-serif; font-family: 'Hind', sans-serif;
color: var(--neutral-dark); color: var(--neutral-dark);
} }
@@ -99,6 +100,26 @@ span {
border-radius: var(--radius); border-radius: var(--radius);
} }
.label-input .tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0;
padding: 8px;
}
.label-input .tags li {
background-color: var(--neutral-verylight);
border-radius: var(--radius);
padding: 4px 16px;
}
.label-input .tags li::marker {
content: '';
}
.label-input-error input { .label-input-error input {
border: solid 1.75px var(--error); border: solid 1.75px var(--error);
} }
+4 -3
View File
@@ -1,12 +1,13 @@
import { useAuthStore } from "@/stores/AuthStore" import { useAuthStore } from "@/stores/AuthStore"
export interface Article { export interface Article {
idName: string, titleID: string,
title: string,
date: number, date: number,
content: { content: {
html: string html: string
}, },
pageId: string, tags: Array<string>,
online: boolean online: boolean
} }
@@ -24,7 +25,7 @@ export async function getArticle(id: string) : Promise<Article> {
} }
export async function postArticle(article: Article) : Promise<object> { export async function postArticle(article: Article) : Promise<object> {
return await fetch(`${baseURL}/articles/${article.idName}`, { return await fetch(`${baseURL}/articles/${article.titleID}`, {
method: 'POST', method: 'POST',
headers: { "Authorization": `Bearer ${useAuthStore().token}` }, headers: { "Authorization": `Bearer ${useAuthStore().token}` },
body: JSON.stringify(article) body: JSON.stringify(article)
+1 -1
View File
@@ -4,7 +4,7 @@ import Editor from '@tinymce/tinymce-vue';
import { onMounted, ref, type Ref } from 'vue'; import { onMounted, ref, type Ref } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
let article: Ref<Article | void> = ref() const article: Ref<Article | void> = ref()
const editorData: Ref<string> = ref('') const editorData: Ref<string> = ref('')
onMounted(async () => { onMounted(async () => {
+33 -22
View File
@@ -7,33 +7,42 @@ const router = useRouter()
const defaultData = `<h1>Bienvenue</h1><p>Vous &ecirc;tes en mode <em>&eacute;dition</em> d'article.</p><p>Celui-ci semble encore neuf ! Supprimez ces lignes et laissez libre cours &agrave; votre imagination :)</p><p>Pour plus d'infos, rendez-vous sur la <a title="Attention, rickroll incoming" href="https:/www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank" rel="noopener">page d'aide</a>.</p>` const defaultData = `<h1>Bienvenue</h1><p>Vous &ecirc;tes en mode <em>&eacute;dition</em> d'article.</p><p>Celui-ci semble encore neuf ! Supprimez ces lignes et laissez libre cours &agrave; votre imagination :)</p><p>Pour plus d'infos, rendez-vous sur la <a title="Attention, rickroll incoming" href="https:/www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank" rel="noopener">page d'aide</a>.</p>`
const title = ref('') const title = ref('')
const page = ref('') const rawTags = ref('')
const tags: Ref<string[]> = ref([])
function isIdValid(): boolean { const regexAccents = /[\u0300-\u036f]/g
const regex = /^[a-zA-Z0-9]+$/ const regexSymbols = /([-!$%^&*()_+|~=`{}\[\]:";'<>?,.\/])+/g
return regex.test(title.value)
function updateTags(): void {
tags.value = rawTags.value.split(/[,\s]+/g)
tags.value = tags.value.filter(x => x !== '')
}
function generateTitleID(title: string): string {
return title.toLowerCase().normalize('NFD')
.replace(regexAccents, '')
.replace(regexSymbols, '')
.replace(/\s/g, '-')
.replace(/-$/g, '')
} }
function isFormEmpty(): boolean { function isFormEmpty(): boolean {
return title.value === '' || page.value === '' return title.value === '' || rawTags.value === ''
}
function isFormValid(): boolean {
return isIdValid() && !isFormEmpty()
} }
function createArticle() { function createArticle() {
const article: Article = { const article: Article = {
idName: title.value, titleID: generateTitleID(title.value),
title: title.value,
date: new Date().getTime(), date: new Date().getTime(),
content: { content: {
html: defaultData html: defaultData
}, },
online: false, online: false,
pageId: page.value tags: tags.value
} }
postArticle(article) postArticle(article)
router.push(`/articles/edit/${article.idName}`) router.push(`/articles/edit/${article.titleID}`)
} }
</script> </script>
@@ -42,21 +51,23 @@ function createArticle() {
<h2>Créer un nouvel article</h2> <h2>Créer un nouvel article</h2>
<form @submit.prevent="createArticle()"> <form @submit.prevent="createArticle()">
<div class="inputs-group"> <div class="inputs-group">
<div :class="`label-input${isIdValid() || title === '' ? '' : '-error'}`"> <div class="label-input">
<label for="title">Identifiant de l'article</label> <label for="title">Titre de l'article</label>
<input id="title" name="title" placeholder="Identifiant de l'article" type="text" v-model="title"> <input id="title" name="title" placeholder="Titre de l'article" type="text" v-model="title">
<p>⚠️ Doit être unique et composé de caractères alphanumériques, sans espaces !
</p>
</div> </div>
<div class="label-input"> <div class="label-input">
<label for="page">Page</label> <label for="tags">Tags</label>
<input id="page" name="page" placeholder="Page" type="text" v-model="page"> <input id="tags" name="tags" placeholder="Tags" type="text" v-model="rawTags" @input="updateTags">
<p>Spéparez les mots-clés par des virgules ou espaces.</p>
<ul class="tags" v-if="tags.length !== 0">
<li v-for="tag in tags">{{ tag }}</li>
</ul>
</div> </div>
</div> </div>
<div class="buttons-group"> <div class="buttons-group">
<RouterLink class="button-secondary" type="submit" to="/articles">Annuler</RouterLink> <RouterLink class="button-secondary" type="submit" to="/articles">Annuler</RouterLink>
<button :class="`button-${!isFormValid() ? 'disabled' : 'primary'}`" type="submit" <button :class="`button-${isFormEmpty() ? 'disabled' : 'primary'}`" type="submit"
:disabled="!isFormValid()">Créer</button> :disabled="isFormEmpty()">Créer</button>
</div> </div>
</form> </form>
</main> </main>
@@ -73,7 +84,7 @@ main {
display: flex; display: flex;
gap: 8px; gap: 8px;
width: 100%; width: 100%;
margin: 32px 0; margin: 16px 0;
} }
.buttons-group a, .buttons-group a,