Feat: Add comment component
This commit is contained in:
parent
19f52d4a48
commit
b88e2fe28a
23
src/components/article/CommentArea.vue
Normal file
23
src/components/article/CommentArea.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<script setup>
|
||||
import CommentForm from './CommentForm.vue';
|
||||
import CommentList from './CommentList.vue';
|
||||
|
||||
const { articleId, comments } = defineProps({ articleId: Number, comments: Array });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="comments">
|
||||
<h2>댓글</h2>
|
||||
<CommentForm :article-id="articleId" />
|
||||
<CommentList :comments="comments" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.comments {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 20px;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
81
src/components/article/CommentForm.vue
Normal file
81
src/components/article/CommentForm.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import FilledButton from '../common/FilledButton.vue';
|
||||
import TextButton from '../common/TextButton.vue';
|
||||
|
||||
const { id } = defineProps({ id: Number });
|
||||
const isActive = ref(false);
|
||||
const textDiv = ref(null);
|
||||
const text = ref('');
|
||||
|
||||
function handleFocus(e) {
|
||||
console.log(e);
|
||||
isActive.value = true;
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
text.value = '';
|
||||
isActive.value = false;
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
console.log(id, text.value);
|
||||
// TODO: add api call
|
||||
text.value = '';
|
||||
isActive.value = false;
|
||||
textDiv.value.blur();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form action="POST" @submit.prevent="handleSubmit">
|
||||
<input type="text" ref="textDiv" v-model="text" @focus="handleFocus" placeholder="댓글 쓰기" />
|
||||
<div class="control" v-if="isActive">
|
||||
<TextButton @click="handleCancel">취소</TextButton>
|
||||
<FilledButton primary type="submit">등록</FilledButton>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.control {
|
||||
display: flex;
|
||||
justify-self: flex-start;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
input {
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
button:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
}
|
||||
|
||||
button[type='submit']:hover {
|
||||
background-color: var(--color-primary-soft);
|
||||
}
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: scale(0.95);
|
||||
background-color: var(--color-background-soft);
|
||||
}
|
||||
|
||||
button[type='submit'] {
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-background);
|
||||
}
|
||||
|
||||
button[type='submit']:active {
|
||||
background-color: var(--color-primary-soft);
|
||||
}
|
||||
</style>
|
50
src/components/article/CommentItem.vue
Normal file
50
src/components/article/CommentItem.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import TextButton from '../common/TextButton.vue';
|
||||
|
||||
const { comment } = defineProps({ comment: Object });
|
||||
const isDeleted = ref(false);
|
||||
|
||||
function handleDelete() {
|
||||
console.log('delete', comment.id);
|
||||
// TODO: add api call
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<li v-if="!isDeleted">
|
||||
<div class="header">
|
||||
<div class="info">
|
||||
<div class="nickname">{{ comment.nickname }}</div>
|
||||
<div class="date">{{ comment.date }}</div>
|
||||
</div>
|
||||
<div v-if="!comment.isAuthor" class="control">
|
||||
<TextButton @click="handleDelete">삭제</TextButton>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text">{{ comment.text }}</p>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
li {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info,
|
||||
.control {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.date {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
</style>
|
@ -1,41 +1,18 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { getComment } from '@/api/comment';
|
||||
import CommentItem from './CommentItem.vue';
|
||||
|
||||
const props = defineProps({ id: Number });
|
||||
const id = props.id;
|
||||
|
||||
const comments = ref([]);
|
||||
const text = ref('');
|
||||
|
||||
getComment(id, ({ data }) => {
|
||||
comments.value = data;
|
||||
});
|
||||
const { comments } = defineProps({ comments: Array });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2>댓글</h2>
|
||||
<input type="text" ref="textDiv" v-model="text" />
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="comment in comments" :key="comment.id">
|
||||
<div class="info">
|
||||
<div class="nickname">{{ comment.nickname }}</div>
|
||||
<div class="date">{{ comment.date }}</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="text">{{ comment.text }}</div>
|
||||
</div>
|
||||
</li>
|
||||
<CommentItem v-for="comment in comments" :key="comment.id" :comment="comment" />
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.info {
|
||||
ul {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-text-secondary);
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user