diff --git a/LOG.md b/LOG.md
index c8c734e..753d52c 100644
--- a/LOG.md
+++ b/LOG.md
@@ -2,6 +2,15 @@
## 2026-05-28
+- Pretendard Variable WOFF2를 `src/app/fonts`에 self-host로 추가하고 `next/font/local`로 전역 적용했다.
+- 홈을 Apple editorial 톤으로 정리해 히어로, 공지, 대표 글, 최신 글 중심으로 줄이고 최근 업데이트/카테고리 선반/인기 글/하단 아카이브 CTA를 제거했다.
+- TopHeader와 ThemeToggle을 아이콘 중심의 조용한 컨트롤로 낮추고, Sidebar는 모바일 기본 닫힘 + 오버레이 drawer로 바꿨다.
+- 카드/Surface 그림자와 `읽기` 같은 보조 문구를 줄이고, 글 상세의 조회수 메타와 TOC 카드감을 덜어 본문 집중도를 높였다.
+- 검증: `npm run lint` 통과, `npm run build` 통과. build 중 sitemap fetch는 로컬 네트워크 제한으로 기존처럼 경고를 출력했지만 실패하지 않았다. Browser로 `http://localhost:3000/`, 모바일 홈/drawer, `/?keyword=network`, `/archive`, production API 환경의 `/posts/rtr-(refresh-token-rotation)`을 확인했고 Pretendard computed font 적용을 확인했다. 로컬 기본 API 상태에서는 posts/categories 데이터가 비어 보일 수 있어 production API 환경으로 글 상세를 추가 확인했다.
+- 다음 추천 작업: 배포 후 실제 Origin에서 홈 실데이터 카드 밀도와 모바일 상단 컨트롤 간격을 한 번 더 확인한다.
+
+## 2026-05-28
+
- 홈의 `전체 글 둘러보기` CTA가 라이트/다크에서 반전 색상처럼 보이지 않도록 `color-text`/`dark:bg-white` 조합을 제거하고 Apple action blue 토큰으로 통일했다.
- 검증: `npm run lint` 통과.
- 다음 추천 작업: 배포 후 홈 첫 화면에서 primary/secondary CTA 대비가 라이트/다크 모두 자연스러운지 최종 확인한다.
diff --git a/src/app/fonts/PretendardVariable.woff2 b/src/app/fonts/PretendardVariable.woff2
new file mode 100644
index 0000000..49c54b5
Binary files /dev/null and b/src/app/fonts/PretendardVariable.woff2 differ
diff --git a/src/app/globals.css b/src/app/globals.css
index 0cac3d9..d449ef1 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -4,13 +4,15 @@
:root {
--font-apple-sans:
+ var(--font-pretendard),
+ "Pretendard Variable",
+ Pretendard,
+ "Apple SD Gothic Neo",
-apple-system,
BlinkMacSystemFont,
"SF Pro Display",
"SF Pro Text",
- "Apple SD Gothic Neo",
"Helvetica Neue",
- Pretendard,
"Noto Sans KR",
system-ui,
sans-serif;
@@ -34,9 +36,9 @@
--color-accent-hover: #0071e3;
--color-accent-soft: rgba(0, 102, 204, 0.1);
--color-danger-soft: rgba(255, 59, 48, 0.1);
- --shadow-panel: 0 22px 70px rgba(0, 0, 0, 0.1);
- --shadow-card: 0 14px 34px rgba(0, 0, 0, 0.065);
- --shadow-control: 0 8px 24px rgba(0, 0, 0, 0.08);
+ --shadow-panel: 0 18px 45px rgba(0, 0, 0, 0.07);
+ --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.035);
+ --shadow-control: 0 6px 18px rgba(0, 0, 0, 0.055);
--focus-ring: 0 0 0 4px rgba(0, 102, 204, 0.14);
--background: var(--color-page);
--foreground: var(--color-text);
@@ -63,9 +65,9 @@ html[data-theme="dark"] {
--color-accent-hover: #46a6ff;
--color-accent-soft: rgba(41, 151, 255, 0.16);
--color-danger-soft: rgba(255, 69, 58, 0.16);
- --shadow-panel: 0 22px 70px rgba(0, 0, 0, 0.42);
- --shadow-card: 0 14px 34px rgba(0, 0, 0, 0.3);
- --shadow-control: 0 10px 28px rgba(0, 0, 0, 0.32);
+ --shadow-panel: 0 18px 45px rgba(0, 0, 0, 0.32);
+ --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.24);
+ --shadow-control: 0 8px 22px rgba(0, 0, 0, 0.24);
--focus-ring: 0 0 0 4px rgba(41, 151, 255, 0.18);
--background: var(--color-page);
--foreground: var(--color-text);
@@ -76,8 +78,13 @@ body {
background: var(--background);
color: var(--foreground);
font-family: var(--font-apple-sans);
- font-feature-settings: "kern";
+ font-feature-settings: "kern", "ss05";
+ font-size: 16px;
+ font-weight: 450;
letter-spacing: 0;
+ line-height: 1.65;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index a9a7b5c..70c1006 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,4 +1,5 @@
import type { Metadata } from 'next';
+import localFont from 'next/font/local';
import './globals.css';
import Providers from './providers';
import Sidebar from '@/components/layout/Sidebar';
@@ -6,6 +7,13 @@ import TopHeader from '@/components/layout/TopHeader';
import Script from 'next/script';
import { THEME_INIT_SCRIPT } from '@/components/theme/theme';
+const pretendard = localFont({
+ src: './fonts/PretendardVariable.woff2',
+ variable: '--font-pretendard',
+ weight: '45 920',
+ display: 'swap',
+});
+
export const metadata: Metadata = {
title: 'WYPark Blog',
description: '개발 블로그',
@@ -21,7 +29,7 @@ export default function RootLayout({
-
+
diff --git a/src/app/page.tsx b/src/app/page.tsx
index a7e7e21..a3b5f2d 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,24 +1,21 @@
'use client';
-import { Suspense, useMemo } from 'react';
-import { useQueries, useQuery } from '@tanstack/react-query';
+import { Suspense } from 'react';
+import { useQuery } from '@tanstack/react-query';
import { useSearchParams } from 'next/navigation';
import Link from 'next/link';
import {
Archive,
ChevronRight,
Clock,
- FolderTree,
Loader2,
Search,
- Sparkles,
} from 'lucide-react';
-import { getCategories } from '@/api/category';
import { getPosts } from '@/api/posts';
import EmptyState from '@/components/ui/EmptyState';
import StatusBadge from '@/components/ui/StatusBadge';
import Surface from '@/components/ui/Surface';
-import { Category, Post, PostListResponse } from '@/types';
+import { Post, PostListResponse } from '@/types';
const isNoticePost = (post: Post) => {
return post.categoryName === '공지' || post.categoryName.toLowerCase() === 'notice';
@@ -38,7 +35,7 @@ const formatDate = (value?: string) => {
};
const getSummary = (content?: string, maxLength = 118) => {
- if (!content) return '아직 요약할 본문이 없습니다. 글을 열어 전체 내용을 확인해 보세요.';
+ if (!content) return '';
return content
.replace(/```[\s\S]*?```/g, ' ')
@@ -50,23 +47,6 @@ const getSummary = (content?: string, maxLength = 118) => {
.slice(0, maxLength);
};
-const flattenCategories = (categories: Category[] = []): Category[] => {
- return categories.flatMap((category) => [
- category,
- ...flattenCategories(category.children || []),
- ]);
-};
-
-const getHomeCategories = (categories: Category[] = []) => {
- return flattenCategories(categories)
- .filter((category) => {
- const name = category.name.toLowerCase();
- return category.name !== '공지' && name !== 'notice' && name !== '미분류';
- })
- .sort((a, b) => a.id - b.id)
- .slice(0, 3);
-};
-
const getTotalElements = (data?: PostListResponse) => {
return data?.page?.totalElements ?? data?.totalElements ?? 0;
};
@@ -123,7 +103,7 @@ function NoticeStrip({ notices }: { notices: Post[] }) {
공지
@@ -145,33 +125,33 @@ function NoticeStrip({ notices }: { notices: Post[] }) {
function FeaturedPost({ post }: { post?: Post }) {
if (!post) {
return (
-
-
+
+
);
}
+ const summary = getSummary(post.content, 170);
+
return (
-
-
-
{post.categoryName || '미분류'}
-