diff --git a/docs/map.md b/docs/map.md index e10cd31..1c405d9 100644 --- a/docs/map.md +++ b/docs/map.md @@ -75,7 +75,7 @@ | 파일 | 화면 | |------|------| -| pages/index.vue | 홈 | +| pages/index.vue | 홈, 중앙 Hero/Featured/Latest 섹션의 내부 컨테이너 보더 정렬과 리스트형 latest 카드 | | pages/posts/index.vue | 게시물 전체 목록 | | pages/posts/[slug].vue | `/post/:slug` 리다이렉트 | | pages/post/[slug].vue | 블로그 글 상세, 게시물 SEO/OG 메타 출력 | diff --git a/docs/update.md b/docs/update.md index fd448a5..26e570e 100644 --- a/docs/update.md +++ b/docs/update.md @@ -15,6 +15,7 @@ - 태그 상세 페이지 게시물 메타 영역에 featured 강조, 태그 컬러 배지, 구분자 스타일을 원본 패턴에 맞춰 보정. - 태그 상세 페이지에서 복수 태그 글은 첫 번째 태그만 배지로 표시하고, 배지와 `/` 구분자가 겹치지 않도록 메타 구조 수정. - 오른쪽 사이드바 Follow 영역을 원본 패턴의 소셜 아이콘 링크 행으로 교체. +- 홈 중앙 메인 영역을 원본 Thred 구조에 맞춰 Hero/Featured/Latest 섹션 간격과 내부 보더 정렬 기준으로 재구성. - 기술 명세 현재 버전을 v0.0.45로 갱신. ## v0.0.44 diff --git a/pages/index.vue b/pages/index.vue index 41701b6..e1dbe16 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -3,6 +3,10 @@ const { data: posts } = await useFetch('/api/posts', { default: () => [] }) +const { data: tags } = await useFetch('/api/tags', { + default: () => [] +}) + /** * 날짜 표시 형식 변환 * @param {string | null} value - ISO 날짜 문자열 @@ -13,90 +17,177 @@ const formatPostDate = (value) => { return '' } - const date = new Date(value) - const year = date.getFullYear() - const month = String(date.getMonth() + 1).padStart(2, '0') - const day = String(date.getDate()).padStart(2, '0') - - return `${year}.${month}.${day}` + return new Intl.DateTimeFormat('en-US', { + month: 'short', + day: 'numeric' + }).format(new Date(value)) } /** - * 게시물 카드 데이터 변환 - * @param {Object} post - API 게시물 - * @returns {Object} 게시물 카드 데이터 + * 태그 슬러그로 태그 정보 조회 + * @param {string | undefined} slug - 태그 슬러그 + * @returns {{name: string, color: string}} 태그 정보 */ -const mapPostCard = (post) => ({ - title: post.title, - excerpt: post.excerpt, - featuredImage: post.featuredImage, - tag: post.tags?.[0]?.toUpperCase() || 'POST', - publishedAt: formatPostDate(post.publishedAt), - to: `/post/${post.slug}` -}) +const getTagMeta = (slug) => { + const matchedTag = tags.value.find((item) => item.slug === slug) -const postCards = computed(() => posts.value.map(mapPostCard)) + return { + name: matchedTag?.name || (slug ? slug.toUpperCase() : 'POST'), + color: matchedTag?.color || '#4d4d4d' + } +} + +/** + * Latest 목록 데이터 변환 + * @param {Object} post - API 게시물 + * @param {number} index - 목록 인덱스 + * @returns {Object} 화면 표시 데이터 + */ +const mapLatestPost = (post, index) => { + const primaryTagSlug = post.tags?.[0] + const tagMeta = getTagMeta(primaryTagSlug) + + return { + title: post.title, + excerpt: post.excerpt, + featuredImage: post.featuredImage, + tagName: tagMeta.name, + tagColor: tagMeta.color, + publishedAt: formatPostDate(post.publishedAt), + to: `/post/${post.slug}`, + isFeatured: index === 0 + } +} + +const featuredPosts = computed(() => posts.value.slice(0, 6)) +const latestPosts = computed(() => posts.value.map(mapLatestPost))