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 || '미분류'} -