Feat: Add article write form
This commit is contained in:
parent
2fb1f9e234
commit
034e4b1126
130
src/components/article/ArticleForm.vue
Normal file
130
src/components/article/ArticleForm.vue
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
import BoardHeader from './BoardHeader.vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { addArticle } from '@/api/article';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const title = ref('');
|
||||||
|
const text = ref('');
|
||||||
|
const titleDiv = ref();
|
||||||
|
const textDiv = ref();
|
||||||
|
const titleErrorMsg = ref('');
|
||||||
|
const textErrorMsg = ref('');
|
||||||
|
|
||||||
|
watch(title, (value) => {
|
||||||
|
if (value.trim()) {
|
||||||
|
titleErrorMsg.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(text, (value) => {
|
||||||
|
if (value.trim()) {
|
||||||
|
textErrorMsg.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
if (!title.value.trim()) {
|
||||||
|
titleErrorMsg.value = '제목을 입력해주세요.';
|
||||||
|
titleDiv.value.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!text.value.trim()) {
|
||||||
|
textErrorMsg.value = '내용을 입력해주세요.';
|
||||||
|
textDiv.value.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const article = {
|
||||||
|
title: title.value,
|
||||||
|
text: text.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
addArticle(article, ({ data }) => {
|
||||||
|
if (!isNaN(data)) {
|
||||||
|
router.replace({ name: 'article', params: { id: data } });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
titleDiv.value.focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<BoardHeader>
|
||||||
|
<template #title>
|
||||||
|
<h1>글쓰기</h1>
|
||||||
|
</template>
|
||||||
|
</BoardHeader>
|
||||||
|
|
||||||
|
<form @submit.prevent="handleSubmit">
|
||||||
|
<div :class="['inputWrapper', titleErrorMsg ? 'error' : '']">
|
||||||
|
<label for="title">제목</label>
|
||||||
|
<input id="title" ref="titleDiv" v-model="title" />
|
||||||
|
<div class="errorMessage" v-if="titleErrorMsg">{{ titleErrorMsg }}</div>
|
||||||
|
</div>
|
||||||
|
<div :class="['inputWrapper', textErrorMsg ? 'error' : '']">
|
||||||
|
<label for="text">내용</label>
|
||||||
|
<textarea id="text" ref="textDiv" v-model="text"></textarea>
|
||||||
|
<div class="errorMessage" v-if="textErrorMsg">{{ textErrorMsg }}</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" @click="handleSubmit">작성</button>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#text {
|
||||||
|
font-size: 1rem;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error input,
|
||||||
|
.error textarea {
|
||||||
|
border-color: var(--color-error);
|
||||||
|
outline-color: var(--color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.errorMessage {
|
||||||
|
color: var(--color-error);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 12px;
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
transition:
|
||||||
|
scale 0.25s,
|
||||||
|
background-color 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
scale: 0.98;
|
||||||
|
background-color: var(--color-primary-soft);
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user