From e5c58b3d6a671e1f9732f869ab208d3b764622f1 Mon Sep 17 00:00:00 2001 From: kjs Date: Thu, 13 Aug 2026 15:33:46 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9E=90=EC=97=B0=20=EC=B9=9C=ED=99=94=20UI=20?= =?UTF-8?q?=EC=A0=84=EB=A9=B4=20=EA=B0=9C=ED=8E=B8=20(=EB=94=94=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=20=EB=AC=B8=EC=84=9C=20=EA=B8=B0=EB=B0=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 폰트: Jua(제목·버튼)·Gowun Dodum(본문)·JetBrains Mono(숫자) next/font 적용 - 팔레트·공통 클래스: 우드/크림/잎사귀 토큰, wood-plank·wood-pill·nature-btn· amber-btn·panel-wood/paper·card-nature·chip-nature·bar-* (globals.css) - HUD: 어두운 나무 바 + 매달린 판자 타이틀(로프) + 우드 자원 pill + 초록 입양 버튼 - 패널: 나무 프레임(나뭇결 텍스처) + 크림 종이 이중 구조 + 잎사귀 장식 - 카드: 비대칭 잎모양 모서리 + 초록 액센트 바, 연두 적성 칩, 초록/앰버 진행 바 - 입양 모달·상점·토스트·배치 힌트 모두 동일 스타일 - 캔버스: 건물 자원 배지를 나뭇결 판자+초록 글로우로, 라벨은 Jua+크림 외곽선 Co-Authored-By: Claude Fable 5 --- src/app/globals.css | 212 +++++++++++++++++-- src/app/layout.tsx | 23 ++- src/components/game/Game.tsx | 305 +++++++++++++++------------- src/components/game/VillageView.tsx | 81 ++++++-- 4 files changed, 443 insertions(+), 178 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41e..098b4b9 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,26 +1,214 @@ @import "tailwindcss"; +/* ── 자연 친화 팔레트 ── */ :root { - --background: #ffffff; - --foreground: #171717; + --background: #f6eeda; + --foreground: #3f2c14; + --wood-dark: #6b4220; + --wood: #8a5a2b; + --wood-light: #b57f42; + --cream: #f6eeda; + --cream-bright: #fffdf6; + --ink: #3f2c14; + --ink-soft: #6f5c39; + --gold-line: rgba(236, 215, 166, 0.28); + --leaf: #7fb539; + --leaf-dark: #4f8420; + --leaf-bright: #b6e05e; } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } + --font-sans: var(--font-gowun); + --font-mono: var(--font-mono); } body { background: var(--background); color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + font-family: var(--font-gowun), sans-serif; +} + +.font-jua { + font-family: var(--font-jua), sans-serif; +} +.font-gowun { + font-family: var(--font-gowun), sans-serif; +} +.font-num { + font-family: var(--font-mono), monospace; +} + +/* ── 공통 컴포넌트 스타일 ── */ + +/* 상단 어두운 나무 바 */ +.nature-topbar { + background: linear-gradient(rgba(30, 20, 8, 0.92), rgba(30, 20, 8, 0.72)); + border-bottom: 1px solid var(--gold-line); +} + +/* 매달린 나무 판자 (타이틀) */ +.wood-plank { + border-radius: 14px 20px 14px 20px; + background: linear-gradient(#8a5a2b, #6b4220); + border: 1px solid rgba(48, 30, 12, 0.6); + box-shadow: + inset 0 1px 0 rgba(255, 236, 196, 0.35), + inset 0 -3px 8px rgba(0, 0, 0, 0.35), + 0 6px 14px rgba(30, 20, 8, 0.35); + color: #fbf1d9; +} + +/* 어두운 우드 pill (자원·보조 버튼) */ +.wood-pill { + border-radius: 999px; + background: linear-gradient(rgba(44, 30, 14, 0.86), rgba(28, 19, 8, 0.9)); + border: 1px solid var(--gold-line); + box-shadow: + inset 0 1px 0 rgba(255, 240, 205, 0.18), + 0 4px 10px rgba(20, 14, 4, 0.3); + color: #f4e9cf; +} +.wood-pill-icon { + border-radius: 50%; + background: radial-gradient(circle at 35% 25%, #f6ecd2, #d8c39a); + box-shadow: inset 0 -2px 4px rgba(120, 95, 50, 0.35); +} + +/* 초록 자연 버튼 (주 액션) */ +.nature-btn { + border-radius: 999px; + background: linear-gradient(#a3d24f, #5d8f22); + border: 1px solid #3f6a13; + box-shadow: + inset 0 1px 0 rgba(255, 255, 235, 0.5), + 0 6px 14px rgba(50, 80, 20, 0.4); + color: #26400c; + font-family: var(--font-jua), sans-serif; +} +.nature-btn:hover:not(:disabled) { + background: linear-gradient(#b0dc60, #6a9e2c); +} + +/* 앰버 우드 버튼 (구매·건설) */ +.amber-btn { + border-radius: 999px; + background: linear-gradient(#d6a43c, #a87a1e); + border: 1px solid #7a5510; + box-shadow: + inset 0 1px 0 rgba(255, 240, 200, 0.5), + 0 5px 12px rgba(90, 60, 10, 0.35); + color: #3d2c07; + font-family: var(--font-jua), sans-serif; +} +.amber-btn:hover:not(:disabled) { + background: linear-gradient(#e2b34e, #b78829); +} + +/* 패널: 바깥 나무 프레임 */ +.panel-wood { + border-radius: 30px; + background-image: + repeating-linear-gradient( + 118deg, + rgba(255, 232, 186, 0.22) 0 3px, + rgba(0, 0, 0, 0) 3px 9px, + rgba(52, 28, 8, 0.4) 9px 15px, + rgba(0, 0, 0, 0) 15px 24px + ), + repeating-linear-gradient( + 62deg, + rgba(255, 232, 186, 0.1) 0 2px, + rgba(0, 0, 0, 0) 2px 11px + ), + linear-gradient(160deg, #b57f42, #8a5a2b 45%, #6d4420); + box-shadow: + inset 0 2px 0 rgba(255, 238, 200, 0.35), + inset 0 -4px 10px rgba(34, 18, 4, 0.4), + 0 12px 28px rgba(20, 14, 4, 0.4); +} + +/* 패널: 안쪽 크림 종이 */ +.panel-paper { + border-radius: 22px; + background-image: + radial-gradient( + 140% 90% at 50% 0%, + rgba(255, 252, 240, 0.9), + rgba(246, 238, 218, 0.94) + ), + repeating-linear-gradient( + 90deg, + rgba(140, 110, 60, 0.05) 0 2px, + rgba(0, 0, 0, 0) 2px 7px + ); + background-color: #f6eeda; + box-shadow: + inset 0 0 0 1px rgba(120, 90, 45, 0.25), + inset 0 6px 18px rgba(140, 110, 60, 0.18); +} + +/* 크림 카드 (잎모양 비대칭 모서리) */ +.card-nature { + position: relative; + border-radius: 6px 22px 6px 22px; + background: linear-gradient(#fffdf6, #f3e9d0); + border: 1px solid rgba(126, 95, 48, 0.3); + box-shadow: + inset 0 1px 0 rgba(255, 255, 250, 0.9), + 0 4px 10px rgba(120, 95, 50, 0.14); +} +.card-accent { + position: absolute; + left: 0; + top: 14px; + bottom: 14px; + width: 4px; + border-radius: 0 4px 4px 0; + background: linear-gradient(#9ccc48, #4f8420); +} + +/* 연두 칩 (적성 등) */ +.chip-nature { + border-radius: 3px 10px 3px 10px; + background: rgba(126, 181, 57, 0.14); + border: 1px solid rgba(94, 140, 42, 0.3); + color: #4d6b21; +} + +/* 잎사귀 장식 */ +.leaf { + position: absolute; + border-radius: 0 100% 0 100%; + background: linear-gradient(140deg, #a8d95c, #59902a); + pointer-events: none; +} +.leaf-bright { + background: linear-gradient(140deg, #bde36f, #6aa233); +} + +/* 진행 바 (포만도 등) */ +.bar-track { + border-radius: 999px; + background: rgba(126, 95, 48, 0.16); + box-shadow: inset 0 1px 2px rgba(100, 75, 35, 0.28); + overflow: hidden; +} +.bar-fill-green { + height: 100%; + border-radius: 999px; + background: linear-gradient(90deg, #7fc23a, #b6e05e); + box-shadow: inset 0 1px 0 rgba(255, 255, 230, 0.6); +} +.bar-fill-amber { + height: 100%; + border-radius: 999px; + background: linear-gradient(90deg, #d6a43c, #eec767); + box-shadow: inset 0 1px 0 rgba(255, 255, 230, 0.6); +} +.bar-fill-red { + height: 100%; + border-radius: 999px; + background: linear-gradient(90deg, #d66a4a, #ee9367); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 00a640c..642b453 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,14 +1,21 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Jua, Gowun_Dodum, JetBrains_Mono } from "next/font/google"; import "./globals.css"; -const geistSans = Geist({ - variable: "--font-geist-sans", +const jua = Jua({ + weight: "400", + variable: "--font-jua", subsets: ["latin"], }); -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", +const gowunDodum = Gowun_Dodum({ + weight: "400", + variable: "--font-gowun", + subsets: ["latin"], +}); + +const jetbrainsMono = JetBrains_Mono({ + variable: "--font-mono", subsets: ["latin"], }); @@ -20,10 +27,10 @@ export const metadata: Metadata = { export default function RootLayout({ children }: LayoutProps<"/">) { return ( - {children} + {children} ); } diff --git a/src/components/game/Game.tsx b/src/components/game/Game.tsx index 4c58a5d..7143e9a 100644 --- a/src/components/game/Game.tsx +++ b/src/components/game/Game.tsx @@ -57,7 +57,7 @@ export default function Game() { if (!state) { return ( -
+
마을 불러오는 중…
); @@ -91,76 +91,85 @@ export default function Game() { {/* ── 배치 모드 힌트 ── */} {placing && ( -
+
📍 {placing.moveId ? "옮길" : "배치할"} 위치를 클릭하세요 {placing.type === "dock" && " (부두는 물가에만)"}
)} - {/* ── 상단 HUD ── */} -
-
- - - 🐱 {state.cats.length}/{state.hall.capacity} - - - 🐟 {Math.floor(state.resources.fish)} - - - 🪵 {Math.floor(state.resources.wood)} - - - 🪨 {Math.floor(state.resources.stone)} - - - 🍖 {meals} - -
-
- - - + {/* ── 상단 HUD (어두운 나무 바) ── */} +
+
+ {/* 매달린 나무 판자 타이틀 */} +
+ + {/* 자원 pill */} +
+ {[ + ["🐱", `${state.cats.length}/${state.hall.capacity}`], + ["🐟", Math.floor(state.resources.fish)], + ["🪵", Math.floor(state.resources.wood)], + ["🪨", Math.floor(state.resources.stone)], + ["🍖", meals], + ].map(([icon, value]) => ( + + + {icon} + + {value} + + ))} +
+
+
+ + + +
{/* ── 메시지 토스트 ── */} {message && ( -
+
⚠️ {message}
)} @@ -255,23 +264,31 @@ function SidePanel({ children: React.ReactNode; }) { return ( -