프로젝트 목록 추가
This commit is contained in:
parent
8427dce4cc
commit
8a15c9c1cc
125
src/components/list/ProjectCard.vue
Normal file
125
src/components/list/ProjectCard.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div class="card mb-3 shadow-sm">
|
||||
<div class="row g-0">
|
||||
<!-- 게시물 내용 섹션 -->
|
||||
<div :class="contentColClass">
|
||||
<div class="card-body">
|
||||
<!-- 제목 -->
|
||||
<h5 class="card-title">
|
||||
{{ title }}
|
||||
<span class="text-muted me-3" v-if="attachment">
|
||||
<i class="fa-solid fa-paperclip"></i>
|
||||
</span>
|
||||
</h5>
|
||||
<!-- 본문 -->
|
||||
<div class="card-text str_wrap my-5">{{ content }}</div>
|
||||
<!-- 날짜 -->
|
||||
<div class="d-flex flex-column flex-sm-row justify-content-between align-items-start">
|
||||
<small class="text-muted">{{ formattedDate }}</small>
|
||||
<!-- 조회수, 좋아요, 댓글 -->
|
||||
<div class="d-flex mt-2 mt-sm-0">
|
||||
<span class="text-muted me-3">
|
||||
<i class="fa-regular fa-eye"></i> {{ views || 0 }}
|
||||
</span>
|
||||
<span class="text-muted me-3" v-if="likes != null">
|
||||
<i class="bx bx-like"></i> {{ likes }}
|
||||
</span>
|
||||
<span class="text-muted" v-if="comments !== null">
|
||||
<i class="bx bx-comment"></i> {{ comments }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
// Props 정의
|
||||
const props = defineProps({
|
||||
category: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
date: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
views: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
likes: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
comments: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
attachment: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
|
||||
// computed 속성
|
||||
const contentColClass = computed(() => {
|
||||
return props.img ? 'col-sm-10 col-12' : 'col-sm-12';
|
||||
});
|
||||
|
||||
// formattedDate을 computed로 정의
|
||||
const formattedDate = computed(() => {
|
||||
const date = new Date(props.date);
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(
|
||||
date.getDate()
|
||||
).padStart(2, "0")} ${String(date.getHours()).padStart(2, "0")}:${String(
|
||||
date.getMinutes()
|
||||
).padStart(2, "0")}`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 카드 스타일 */
|
||||
.card {
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 8px;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
/* 텍스트 줄임 표시 */
|
||||
.str_wrap {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
/* 이미지 스타일 */
|
||||
.img-fluid {
|
||||
border-radius: 8px 0 0 8px;
|
||||
}
|
||||
|
||||
/* 태그 배지 스타일 */
|
||||
.badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
</style>
|
||||
67
src/components/list/ProjectCardList.vue
Normal file
67
src/components/list/ProjectCardList.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="mt-4">
|
||||
<div v-if="posts.length === 0" class="text-center">
|
||||
<p class="text-muted mt-4">게시물이 없습니다.</p>
|
||||
</div>
|
||||
|
||||
<div v-for="post in posts" :key="post.id" @click="goDetail(post.id)">
|
||||
<ProjectCard
|
||||
:category="post.category || ''"
|
||||
:title="post.title"
|
||||
:content="post.content"
|
||||
:date="post.date"
|
||||
:views="post.views || 0"
|
||||
v-bind="getProjectCardProps(post)"
|
||||
:attachment="post.attachment || false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineEmits } from 'vue';
|
||||
import ProjectCard from './ProjectCard.vue';
|
||||
|
||||
// 테스트용 데이터
|
||||
const posts = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: 'Vue 3 Composition API 소개',
|
||||
content: 'Composition API를 사용하여 Vue 3에서 효율적으로 개발하는 방법을 알아봅니다.',
|
||||
date: '2025-02-10',
|
||||
views: 120,
|
||||
likes: 15,
|
||||
comments: 4,
|
||||
attachment: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Spring Boot로 REST API 만들기',
|
||||
content: 'Spring Boot를 사용하여 간단한 RESTful API를 구현하는 방법을 다룹니다.',
|
||||
date: '2025-02-09',
|
||||
views: 89,
|
||||
likes: 8,
|
||||
comments: 2,
|
||||
attachment: false
|
||||
}
|
||||
]);
|
||||
|
||||
const emit = defineEmits(['click']);
|
||||
|
||||
// 상세 페이지 이동
|
||||
const goDetail = (id) => {
|
||||
emit('click', id);
|
||||
};
|
||||
|
||||
// 없는 데이터는 상위 페이지에서 삭제해도 되게끔 설정
|
||||
const getProjectCardProps = (post) => {
|
||||
const projectCardProps = {};
|
||||
if ('likes' in post) {
|
||||
projectCardProps.likes = post.likes;
|
||||
}
|
||||
if ('comments' in post) {
|
||||
projectCardProps.comments = post.comments;
|
||||
}
|
||||
return projectCardProps;
|
||||
};
|
||||
</script>
|
||||
@ -61,6 +61,12 @@
|
||||
<div class="text-truncate">vacation</div>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li class="menu-item" :class="$route.path.includes('/projectlist') ? 'active' : ''">
|
||||
<RouterLink class="menu-link" to="/projectlist">
|
||||
<i class="menu-icon icon-base bx bx-list-ul"></i>
|
||||
<div class="text-truncate">project</div>
|
||||
</RouterLink>
|
||||
</li>
|
||||
<li class="menu-item" :class="$route.path.includes('/sample') ? 'active' : ''">
|
||||
<RouterLink class="menu-link" to="/sample"> <i class="bi "></i>
|
||||
<i class="menu-icon tf-icons bx bx-calendar"></i>
|
||||
|
||||
@ -76,6 +76,10 @@ const routes = [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/projectlist',
|
||||
component: () => import('@v/projectlist/TheProjectList.vue'),
|
||||
},
|
||||
{
|
||||
path: '/sample',
|
||||
component: () => import('@c/calendar/SampleCalendar.vue'),
|
||||
|
||||
24
src/views/projectlist/TheProjectList.vue
Normal file
24
src/views/projectlist/TheProjectList.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<SearchBar />
|
||||
<CategoryBtn :lists="testData" />
|
||||
<ProjectCardList :category="selectedCategory" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import SearchBar from '@c/search/SearchBar.vue';
|
||||
import ProjectCardList from '@c/list/ProjectCardList.vue';
|
||||
import CategoryBtn from '@c/category/CategoryBtn.vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const selectedCategory = ref(null);
|
||||
|
||||
// 테스트용 데이터
|
||||
const testData = [
|
||||
{ CMNCODVAL: 'cat1', CMNCODNAM: 'All' },
|
||||
{ CMNCODVAL: 'cat2', CMNCODNAM: '2024' },
|
||||
{ CMNCODVAL: 'cat3', CMNCODNAM: '2025' },
|
||||
];
|
||||
|
||||
</script>
|
||||
Loading…
Reference in New Issue
Block a user