From 0e725d32aa93307e56bcb3bc7276474462d9f825 Mon Sep 17 00:00:00 2001 From: malloc72p Date: Mon, 29 Jun 2026 17:41:34 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat(blog):=20=EB=94=94=EC=9E=90=EC=9D=B8?= =?UTF-8?q?=20=ED=86=A0=ED=81=B0=20+=20=EB=B8=8C=EB=9E=9C=EB=93=9C=20?= =?UTF-8?q?=EC=95=A1=EC=84=BC=ED=8A=B8(=EC=9D=B8=EB=94=94=EA=B3=A0)=20?= =?UTF-8?q?=EB=8F=84=EC=9E=85=20(#94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - global.css: 의미 기반 색 토큰 단일 출처(:root) — --color-brand(#6366f1), --color-ink(#0a0a0a) (Turbopack+v4에서 @theme가 유틸리티를 생성하지 않아, 코드베이스가 이미 쓰는 arbitrary value 방식 bg-[var(--color-*)]으로 통일) - 검정 계열 통일: 헤더·모바일 사이드바·드롭다운·검색 뱃지·skip 링크의 bg-black/gray-900/gray-950 → bg-[var(--color-ink)] - 액센트 적용(절제): 활성 시리즈 필터 칩·현재 시리즈 강조 → bg-[var(--color-brand)], copy/share 포커스 링 → ring-[var(--color-brand)] Co-Authored-By: Claude Opus 4.8 --- apps/blog/src/app/(main)/main-client-layout.tsx | 2 +- apps/blog/src/app/global.css | 11 +++++++++++ apps/blog/src/components/badge.tsx | 2 +- apps/blog/src/components/dropdown-menu.tsx | 2 +- apps/blog/src/components/main-header.tsx | 2 +- apps/blog/src/components/mobile-sidebar.tsx | 2 +- apps/blog/src/components/post-detail/copy-button.tsx | 2 +- .../blog/src/components/post-detail/share-buttons.tsx | 2 +- apps/blog/src/components/search/search-modal.tsx | 2 +- .../src/components/series-detail/series-detail.tsx | 4 ++-- 10 files changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/blog/src/app/(main)/main-client-layout.tsx b/apps/blog/src/app/(main)/main-client-layout.tsx index e32cde9..8f5051a 100644 --- a/apps/blog/src/app/(main)/main-client-layout.tsx +++ b/apps/blog/src/app/(main)/main-client-layout.tsx @@ -52,7 +52,7 @@ export default function MainClientLayout({ 평소엔 sr-only로 숨기고 포커스되면 좌상단에 노출한다. */} 본문으로 건너뛰기 diff --git a/apps/blog/src/app/global.css b/apps/blog/src/app/global.css index 9b8c123..63760b3 100644 --- a/apps/blog/src/app/global.css +++ b/apps/blog/src/app/global.css @@ -1,5 +1,16 @@ @import 'tailwindcss'; +/* === 디자인 토큰 (#94) === + 의미 기반 색 토큰의 단일 출처. 컴포넌트는 bg-[var(--color-brand)] 형태의 + arbitrary 유틸리티로 참조한다(이 프로젝트의 Turbopack+v4 빌드에서 @theme는 + 유틸리티를 생성하지 않아, 코드베이스가 이미 쓰는 arbitrary value 방식으로 통일). */ +:root { + /* 브랜드 액센트(인디고). 활성 칩·현재 시리즈·포커스 링 등에 절제 있게 적용한다. */ + --color-brand: #6366f1; + /* 다크 서피스 단일 토큰. 헤더·드롭다운·사이드바·뱃지의 검정 계열(black/gray-900/950)을 통일한다. */ + --color-ink: #0a0a0a; +} + html, body { height: 100%; diff --git a/apps/blog/src/components/badge.tsx b/apps/blog/src/components/badge.tsx index f4a772f..6c70413 100644 --- a/apps/blog/src/components/badge.tsx +++ b/apps/blog/src/components/badge.tsx @@ -28,7 +28,7 @@ export function Badge({ href, children, onClick, color = 'secondary', active }: 'px-[8px] py-[8px]', 'md:px-[12px] md:py-[6px]', 'whitespace-nowrap', - color === 'primary' ? 'bg-gray-700 text-white' : 'bg-gray-100 text-gray-700', + color === 'primary' ? 'bg-[var(--color-brand)] text-white' : 'bg-gray-100 text-gray-700', 'hover:brightness-95 active:brightness-90', )} > diff --git a/apps/blog/src/components/dropdown-menu.tsx b/apps/blog/src/components/dropdown-menu.tsx index e0872c8..8177042 100644 --- a/apps/blog/src/components/dropdown-menu.tsx +++ b/apps/blog/src/components/dropdown-menu.tsx @@ -151,7 +151,7 @@ export function DropdownMenu({ title, items, leftOffset = 0, ...option }: Dropdo id={listId} ref={dropdownBodyRef} className={classNames( - 'absolute top-6 bg-gray-950 z-50 px-2 py-4 flex-col transition-all duration-300', + 'absolute top-6 bg-[var(--color-ink)] z-50 px-2 py-4 flex-col transition-all duration-300', 'rounded-b-lg drop-shadow-2xl', visible ? 'block' : 'hidden' )} diff --git a/apps/blog/src/components/main-header.tsx b/apps/blog/src/components/main-header.tsx index 6044ab1..dc666b9 100644 --- a/apps/blog/src/components/main-header.tsx +++ b/apps/blog/src/components/main-header.tsx @@ -17,7 +17,7 @@ export function MainHeader({ seriesList, tags }: MainHeaderProps) { className={classNames( 'blog-main-header', 'relative z-50', - 'bg-black text-white', + 'bg-[var(--color-ink)] text-white', 'h-[60px] md:h-[128px]', )} > diff --git a/apps/blog/src/components/mobile-sidebar.tsx b/apps/blog/src/components/mobile-sidebar.tsx index b9bf706..fb61dec 100644 --- a/apps/blog/src/components/mobile-sidebar.tsx +++ b/apps/blog/src/components/mobile-sidebar.tsx @@ -130,7 +130,7 @@ export function MobileSidebar({ seriesList, tags }: MobileSidebarProps) { {/* ------------------------------------------------------ */} {/* SIDEBAR HEADER */} {/* ------------------------------------------------------ */} -
+
diff --git a/apps/blog/src/components/post-detail/copy-button.tsx b/apps/blog/src/components/post-detail/copy-button.tsx index 85a77f1..782ad72 100644 --- a/apps/blog/src/components/post-detail/copy-button.tsx +++ b/apps/blog/src/components/post-detail/copy-button.tsx @@ -50,7 +50,7 @@ export function CopyButton({ getContent }: CopyButtonProps) { // p-3로 키워 터치 타겟을 약 44px 확보(아이콘 20px + 패딩 24px). 'absolute right-5 top-5 p-3 rounded-md opacity-80 hover:opacity-90 active:opacity-100', // 키보드 포커스 시 시각적 표시(focus-visible ring)로 접근성을 높인다. - 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-400', + 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]', classes.copyBtn )} onClick={handleCopy} diff --git a/apps/blog/src/components/post-detail/share-buttons.tsx b/apps/blog/src/components/post-detail/share-buttons.tsx index 2ed4f40..fba4060 100644 --- a/apps/blog/src/components/post-detail/share-buttons.tsx +++ b/apps/blog/src/components/post-detail/share-buttons.tsx @@ -15,7 +15,7 @@ export interface ShareButtonsProps { const buttonClass = classNames( 'flex items-center justify-center p-2.5 rounded-md text-gray-500', 'hover:text-black hover:bg-gray-100 active:bg-gray-200', - 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-400', + 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-brand)]', ); export function ShareButtons({ url, title }: ShareButtonsProps) { diff --git a/apps/blog/src/components/search/search-modal.tsx b/apps/blog/src/components/search/search-modal.tsx index 5b308e7..7bfef49 100644 --- a/apps/blog/src/components/search/search-modal.tsx +++ b/apps/blog/src/components/search/search-modal.tsx @@ -171,7 +171,7 @@ export function SearchModal() { >
{doc.series && ( - + {doc.series} )} diff --git a/apps/blog/src/components/series-detail/series-detail.tsx b/apps/blog/src/components/series-detail/series-detail.tsx index 5d9a041..21313a2 100644 --- a/apps/blog/src/components/series-detail/series-detail.tsx +++ b/apps/blog/src/components/series-detail/series-detail.tsx @@ -52,8 +52,8 @@ export async function SeriesDetail({ series }: SeriesDetailProps) { 'px-3 py-1.5 text-xs md:text-sm', 'transition-all duration-200 ease-in-out', active - ? // 활성 시리즈: 진한 배경으로 강조한다. - 'bg-gray-900 text-white' + ? // 활성 시리즈: 브랜드 액센트로 현재 위치를 강조한다. + 'bg-[var(--color-brand)] text-white' : // 비활성 시리즈: 옅은 배경 + hover 강조로 클릭 가능함을 알린다. 'bg-gray-100 text-gray-700 hover:bg-gray-200', )} From fbea5e503ca713efc6098e0ad1bba65e91bb7422 Mon Sep 17 00:00:00 2001 From: malloc72p Date: Mon, 29 Jun 2026 17:44:36 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor(blog):=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=20=E2=80=94=20=EA=B2=80=EC=83=89=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BC=EB=8F=84=20ink=20=ED=86=A0=ED=81=B0=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - search-modal 오버레이 bg-black/50 → bg-[var(--color-ink)]/50 (v4가 arbitrary value + 투명도 모디파이어를 color-mix로 정상 생성함을 빌드로 확인) - 이로써 raw 검정(bg-black/gray-900/gray-950) 잔존 0 Co-Authored-By: Claude Opus 4.8 --- apps/blog/src/components/search/search-modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/blog/src/components/search/search-modal.tsx b/apps/blog/src/components/search/search-modal.tsx index 7bfef49..ed629b4 100644 --- a/apps/blog/src/components/search/search-modal.tsx +++ b/apps/blog/src/components/search/search-modal.tsx @@ -93,7 +93,7 @@ export function SearchModal() { return ( // 배경 오버레이(클릭 시 닫힘)
{/* 모달 본체(내부 클릭은 닫힘 전파 차단) */}