Astro 블로그에서 카테고리 설계하기

2026. 1. 8 4분

Content Collection, 타입 안전성, UI 배지까지 Astro 블로그 카테고리 설계 방법 정리

AstroContent CollectionCategory
목차

블로그의 글 목록 가시성 개선을 위해 카테고리 컴포넌트를 추가했다.

해당 컴포넌트 구현 과정을 정리하려고 한다.

1. 카테고리 정의

이번 블로그에서 사용하는 카테고리는 3가지로 고정한다.


카테고리가 고정되어 있으므로, 명확한 타입 정의가 핵심이다.


2. 카테고리 상수 & 타입 정의

constants.ts
import type { SvgComponent } from 'astro/types';
import DiaryIcon from '@/components/icons/Diary.svg';
import TechIcon from '@/components/icons/Tech.svg';
import ProjectIcon from '@/components/icons/Project.svg';
 
export const CATEGORY_TYPES = ['diary', 'tech', 'project'] as const;
 
export type CategoryType = (typeof CATEGORY_TYPES)[number];
 
export interface Category {
  type: CategoryType;
  label: string;
  icon: SvgComponent;
}
 
export const CATEGORIES: Record<CategoryType, Category> = {
  diary: {
    type: 'diary',
    label: 'Diary',
    icon: DiaryIcon,
  },
  tech: {
    type: 'tech',
    label: 'Tech',
    icon: TechIcon,
  },
  project: {
    type: 'project',
    label: 'Project',
    icon: ProjectIcon,
  },
};

이 구조의 장점

  1. 카테고리 추가/수정 시 한 곳만 수정
  2. UI, 스키마, 타입 불일치 방지
  3. CATEGORIES[category] 형태로 즉시 매핑 가능

3. Content Collection 스키마 수정

기존에는 카테고리를 단순 문자열로 두었으나, 타입 안정성을 위해 z.enum 을 사용해주었다.

Collection
import { z } from 'astro:content';
import { CATEGORY_TYPES } from '@/constants/categories';
 
export const collections = {
  blog: {
    schema: z.object({
      title: z.string(),
      date: z.date(),
      category: z.enum(CATEGORY_TYPES),
    }),
  },
};

enum을 사용함으로써 얻는 효과

  1. 마크다운에서 잘못된 값 입력 시 빌드 에러
  2. 타입 자동 추론
  3. 에디터 자동완성 지원
  4. UI에서 undefined 접근 문제 제거

4. 카테고리 컴포넌트

Category.astro
 
import { CATEGORIES, type CategoryType } from "@/constants/categories";
 
interface Props {
  category: CategoryType;
}
 
const { category } = Astro.props;
const data = CATEGORIES[category];
---
 
<span class={`category-badge ${category}`}>
  <data.icon class="category-icon" />
  <span class="sr-only">{data.label}</span>
</span>

| 접근성을 위해 텍스트는 sr-only 로 유지한다.

5. 카테고리 컴포넌트 배치

카테고리는 제목의 왼쪽, 제목의 일부처럼 배치하는 것이 가장 자연스럽다.

PostItem.astro
 
<a href={link} class="group block p-2">
  <div class="flex items-center gap-2">
    <PostCategoryBadge category={category} />
 
    <span class="text-primary text-lg transition group-hover:text-accent">
      {title}
    </span>
  </div>
 
  <p class="text-sub my-1 text-sm">
    {description}
  </p>
 
  <FormattedDate date={publishedDate} />
</a>
 

6. 카테고리 설계 핵심 요약

항목선택
카테고리 역할게시글 메타 정보
스키마 타입z.enum
타입 관리as const 단일 소스
UI 표현아이콘 중심 배지
위치제목 왼쪽
확장성색상 / 애니메이션 / 필터 가능

7. 마무리

카테고리는 단순한 문자열이 아니라 콘텐츠의 성격을 드러내는 핵심 메타 정보다.

타입으로 보호하고 UI에서 일관되게 표현하고 구조적으로 확장 가능하게 설계하면

블로그 전체의 완성도가 자연스럽게 올라간다.

이 구조는 개인 기록용 블로그에 특히 잘 어울리며, 나중에 태그·필터·아카이브로 확장하기에도 부담이 없다.