태그 없는 게시물에서 POST 더미 표시 제거(v1.1.2)

This commit is contained in:
2026-05-14 18:42:01 +09:00
parent 17dcd04339
commit 08f0aa0efa
9 changed files with 52 additions and 21 deletions

View File

@@ -28,7 +28,7 @@ defineProps({
{{ post.excerpt }}
</p>
<p class="post-card__meta mt-2 text-xs site-muted">
{{ post.publishedAt }} / {{ post.tag }}
{{ post.publishedAt }}<template v-if="post.tag"> / {{ post.tag }}</template>
</p>
</div>
</div>

View File

@@ -1,5 +1,11 @@
# 의사결정 이력
## 2026-05-14 v1.1.2
### 태그 없을 때 “POST” 더미 표시 제거
태그 배열이 비어 있을 때 UI 폴백으로 `POST` 문자열을 넣어 두어, 사용자는 실제 태그가 붙은 것으로 오해했다. 저장 데이터와 무관한 표시이므로 슬러그가 있을 때만 첫 태그를 노출하고 없으면 태그 영역을 렌더하지 않는다.
## 2026-05-14 v1.1.1
### 공개 문단 행간 기본값으로 복귀

View File

@@ -55,7 +55,7 @@
| components/site/SidebarPrimaryNavList.vue | 상단 네비: 부모·리프 동일 `before` 막대/호버 원형, 내부 현재 경로 `--site-accent`, 행 `w-full`로 패널 호버 배경 폭, `inject`·`localStorage` 펼침 |
| components/site/RightSidebar.vue | 오른쪽 사이드바, 공개 사이트 이미지 로고 fallback, `lg+`는 고정 열 높이·스티키, 모바일은 본문 아래 전체 너비, 하단 푸터 `pr-3` |
| components/site/MainColumn.vue | 메인 화면 중앙, `lg:max-w-[720px]`로 본문 상한 |
| components/site/PostCard.vue | 목록의 게시물 카드, 대표 이미지 썸네일, 카드 hover 인터랙션 |
| components/site/PostCard.vue | 목록의 게시물 카드, 대표 이미지 썸네일, 카드 hover 인터랙션, 태그는 있을 때만 메타에 표시 |
| components/site/TagHeader.vue | 태그 페이지 헤더 |
| components/comments/PostComments.vue | 게시물 상세 `#comments` 영역, 회원 댓글/답글(1단) 작성 및 목록 표시, 작성자 썸네일/좋아요/상대시간 표시 |
@@ -127,10 +127,10 @@
| 파일 | 화면 |
|------|------|
| pages/index.vue | 홈, 중앙 Hero/Featured/Latest 섹션의 내부 컨테이너 보더 정렬과 리스트형 latest 카드, Featured는 모바일 터치 가로 스크롤·스냅과 끝에서 화살표 비활성 |
| pages/posts/index.vue | 게시물 전체 목록 |
| pages/index.vue | 홈, 중앙 Hero/Featured/Latest 섹션의 내부 컨테이너 보더 정렬과 리스트형 latest 카드, Latest 메타는 태그가 있을 때만 태그 배지 표시, Featured는 모바일 터치 가로 스크롤·스냅과 끝에서 화살표 비활성 |
| pages/posts/index.vue | 게시물 전체 목록, 태그는 있을 때만 카드 메타에 표시 |
| pages/posts/[slug].vue | `/post/:slug` 리다이렉트 |
| pages/post/[slug].vue | 블로그 글 상세, 게시물 SEO/OG 메타 출력, 공유 모달(X/Bluesky/Facebook/LinkedIn/Email/링크복사), 회원 댓글 섹션 |
| pages/post/[slug].vue | 블로그 글 상세, 첫 태그가 있을 때만 메타 행에 태그 링크, 게시물 SEO/OG 메타 출력, 공유 모달(X/Bluesky/Facebook/LinkedIn/Email/링크복사), 회원 댓글 섹션 |
| pages/tags/index.vue | 태그 전체 목록, 중앙 히어로와 3열 태그 카드, 좌측 컬러 보더/hover 오버레이 |
| pages/tags/[slug].vue | `/tag/:slug` 리다이렉트 |
| pages/tag/[slug].vue | 태그별 글 목록, 상단 태그 헤더 + 공통 섹션 패딩을 쓰는 리스트형 게시물 카드 |

View File

@@ -506,6 +506,7 @@ components/content/
- 관리자 폼에서는 검색엔진 노출 제외(`noindex`)만 설정할 수 있다.
- Canonical URL은 별도 입력을 받지 않고 기본 글 주소를 사용한다.
- 공개 게시물 상세 화면은 SEO 제목이 없으면 글 제목, SEO 설명이 없으면 요약을 메타 태그 기본값으로 사용한다.
- 저장된 태그가 없는 게시물에는 상세 메타 행·홈 Latest·`/posts` 목록 카드에 태그 배지나 더미 라벨을 표시하지 않는다.
- 검색엔진 노출 제외가 켜진 글은 robots 메타를 `noindex, nofollow`로 출력한다.
- 공개 상세 화면의 `og:image`와 Twitter large image 카드는 대표 이미지를 기본값으로 사용한다.
- 이미지 블록은 관리자 업로드 API로 이미지를 업로드하고 `![alt](url){width=wide}` 형식으로 저장한다.

View File

@@ -1,5 +1,10 @@
# 업데이트 이력
## v1.1.2
- 태그가 없는 게시물에 기본값으로 보이던 `POST` 표기 제거: 공개 상세·홈 Latest·게시물 목록 카드에서 태그가 있을 때만 배지·메타에 표시.
- 패키지 버전 `1.1.2`로 갱신.
## v1.1.1
- 공개 본문 `ContentMarkdownRenderer` 문단에서 `leading-7`을 제거하고 `text-base`(16px)만 적용.

View File

@@ -1,6 +1,6 @@
{
"name": "sori.studio",
"version": "1.1.1",
"version": "1.1.2",
"private": true,
"type": "module",
"imports": {

View File

@@ -53,10 +53,17 @@ const onDocumentPointerDown = (event) => {
* @returns {{name: string, color: string}} 태그 정보
*/
const getTagMeta = (slug) => {
if (!slug) {
return {
name: '',
color: '#4d4d4d'
}
}
const matchedTag = tags.value.find((item) => item.slug === slug)
return {
name: matchedTag?.name || (slug ? slug.toUpperCase() : 'POST'),
name: matchedTag?.name || String(slug).toUpperCase(),
color: matchedTag?.color || '#4d4d4d'
}
}
@@ -454,14 +461,16 @@ const scrollFeatured = (direction) => {
<div class="flex flex-wrap items-center gap-2 text-xs site-muted sm:gap-1.5">
<time v-if="post.publishedAt" :datetime="post.publishedAtIso">{{ post.publishedAt }}</time>
<span class="text-[var(--site-line)]">/</span>
<span
class="rounded-md px-1.5 py-px font-medium text-[var(--site-text)]"
:style="{ backgroundColor: `${post.tagColor}1a` }"
>
{{ post.tagName }}
</span>
<span class="text-[var(--site-line)]">/</span>
<template v-if="post.tagName">
<span v-if="post.publishedAt" class="text-[var(--site-line)]">/</span>
<span
class="rounded-md px-1.5 py-px font-medium text-[var(--site-text)]"
:style="{ backgroundColor: `${post.tagColor}1a` }"
>
{{ post.tagName }}
</span>
</template>
<span v-if="post.publishedAt || post.tagName" class="text-[var(--site-line)]">/</span>
<span class="flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="-mt-px">
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />

View File

@@ -23,12 +23,22 @@ if (!post.value) {
const primaryTagSlug = computed(() => post.value.tags?.[0] || '')
const primaryTagMeta = computed(() => {
const matchedTag = tags.value.find((item) => item.slug === primaryTagSlug.value)
const slug = primaryTagSlug.value
if (!slug) {
return {
name: '',
color: '',
to: '/tags'
}
}
const matchedTag = tags.value.find((item) => item.slug === slug)
return {
name: matchedTag?.name || (primaryTagSlug.value ? primaryTagSlug.value.toUpperCase() : 'POST'),
name: matchedTag?.name || slug.toUpperCase(),
color: matchedTag?.color || '#4d4d4d',
to: primaryTagSlug.value ? `/tag/${primaryTagSlug.value}` : '/tags'
to: `/tag/${slug}`
}
})
@@ -228,8 +238,8 @@ useHead(() => ({
{{ authorLabel }}
</a>
<ul class="flex flex-wrap items-center font-medium">
<li v-if="primaryTagMeta.name" :style="{ '--color-accent': primaryTagMeta.color }">
<ul v-if="primaryTagSlug" class="flex flex-wrap items-center font-medium">
<li :style="{ '--color-accent': primaryTagMeta.color }">
<NuxtLink
class="rounded-sm px-1.5 py-px text-[var(--site-text)] hover:opacity-75"
:style="{ backgroundColor: `${primaryTagMeta.color}1a` }"

View File

@@ -7,7 +7,7 @@ const postCards = computed(() => posts.value.map((post) => ({
title: post.title,
excerpt: post.excerpt,
featuredImage: post.featuredImage,
tag: post.tags?.[0]?.toUpperCase() || 'POST',
tag: post.tags?.[0] ? String(post.tags[0]).toUpperCase() : '',
publishedAt: formatPostDate(post.publishedAt),
to: `/post/${post.slug}`
})))