diff --git a/frontend/docs/design-concepts.md b/frontend/docs/design-concepts.md new file mode 100644 index 0000000..8196761 --- /dev/null +++ b/frontend/docs/design-concepts.md @@ -0,0 +1,85 @@ +# Tasteby Design Concept 후보 + +> Oracle의 Redwood처럼, Tasteby만의 디자인 언어를 정의하기 위한 컨셉 후보안. + +--- + +## 1. Saffron (사프란) 🟠 + +따뜻한 금빛 오렌지. 고급스러운 미식 큐레이션 느낌. + +| 역할 | 색상 | Hex | +|------|------|-----| +| Primary | 깊은 오렌지 | `#E8720C` | +| Primary Light | 밝은 오렌지 | `#F59E3F` | +| Primary Dark | 진한 오렌지 | `#C45A00` | +| Accent | 골드 | `#F5A623` | +| Accent Light | 라이트 골드 | `#FFD080` | +| Background | 크림 화이트 | `#FFFAF5` | +| Surface | 웜 그레이 | `#F7F3EF` | +| Text Primary | 다크 브라운 | `#2C1810` | +| Text Secondary | 미디엄 브라운 | `#7A6555` | + +**키워드**: 프리미엄, 미식, 큐레이션, 따뜻함, 신뢰 +**어울리는 폰트**: Pretendard, Noto Sans KR (깔끔 + 웜톤 배경) + +--- + +## 2. Gochujang (고추장) 🔴 + +한국 음식 DNA. 약간 붉은 오렌지 톤으로 대담하고 강렬. + +| 역할 | 색상 | Hex | +|------|------|-----| +| Primary | 고추장 레드 | `#D94F30` | +| Primary Light | 밝은 레드 | `#EF7B5A` | +| Primary Dark | 진한 레드 | `#B53518` | +| Accent | 따뜻한 오렌지 | `#FF8C42` | +| Accent Light | 라이트 피치 | `#FFB88C` | +| Background | 소프트 화이트 | `#FFFBF8` | +| Surface | 웜 베이지 | `#F5F0EB` | +| Text Primary | 차콜 | `#1A1A1A` | +| Text Secondary | 다크 그레이 | `#666052` | + +**키워드**: 한국, 활기, 식욕, 대담, 강렬 +**어울리는 폰트**: Spoqa Han Sans Neo, Pretendard (모던 + 힘있는) + +--- + +## 3. Citrus (시트러스) 🍊 + +밝고 상큼한 비비드 오렌지. 현대적이고 친근한 느낌. + +| 역할 | 색상 | Hex | +|------|------|-----| +| Primary | 비비드 오렌지 | `#FF6B2B` | +| Primary Light | 라이트 오렌지 | `#FF9A6C` | +| Primary Dark | 딥 오렌지 | `#E04D10` | +| Accent | 피치 | `#FFB347` | +| Accent Light | 소프트 피치 | `#FFD9A0` | +| Background | 퓨어 화이트 | `#FFFFFF` | +| Surface | 쿨 그레이 | `#F5F5F7` | +| Text Primary | 뉴트럴 블랙 | `#171717` | +| Text Secondary | 미디엄 그레이 | `#6B7280` | + +**키워드**: 캐주얼, 트렌디, 활발, 친근, 상큼 +**어울리는 폰트**: Geist (현재 사용 중), Inter + +--- + +## 현재 상태 (Before) + +- Tailwind 기본 `orange` 팔레트 사용 (커스텀 없음) +- 폰트: Geist (Google Fonts) +- 다크모드: `prefers-color-scheme` 기반 자동 전환 +- 브랜드 컬러 정의 없음 — 컴포넌트마다 `orange-400~700` 개별 적용 + +## 적용 계획 + +1. 컨셉 선택 +2. CSS 변수로 디자인 토큰 정의 (`globals.css`) +3. Tailwind v4 `@theme` 에 커스텀 컬러 등록 +4. 컴포넌트별 하드코딩된 orange → 시맨틱 토큰으로 교체 +5. 다크모드 팔레트 정의 +6. 폰트 교체 (필요시) +7. 로고/아이콘 톤 맞춤 diff --git a/frontend/src/app/admin/page.tsx b/frontend/src/app/admin/page.tsx index a41be29..949c328 100644 --- a/frontend/src/app/admin/page.tsx +++ b/frontend/src/app/admin/page.tsx @@ -808,7 +808,7 @@ function VideosPanel({ isAdmin }: { isAdmin: boolean }) { @@ -836,7 +836,7 @@ function VideosPanel({ isAdmin }: { isAdmin: boolean }) { @@ -849,7 +849,7 @@ function VideosPanel({ isAdmin }: { isAdmin: boolean }) { @@ -1073,7 +1073,7 @@ function VideosPanel({ isAdmin }: { isAdmin: boolean }) {
@@ -1515,7 +1515,7 @@ function VideosPanel({ isAdmin }: { isAdmin: boolean }) { {r.foods_mentioned.length > 0 && (
{r.foods_mentioned.map((f, j) => ( - {f} + {f} ))}
)} @@ -1769,7 +1769,7 @@ function RestaurantsPanel({ isAdmin }: { isAdmin: boolean }) { finally { setBulkTabling(false); load(); } }} disabled={bulkTabling} - className="px-3 py-1.5 text-xs bg-orange-500 text-white rounded hover:bg-orange-600 disabled:opacity-50" + className="px-3 py-1.5 text-xs bg-brand-500 text-white rounded hover:bg-brand-600 disabled:opacity-50" > {bulkTabling ? `테이블링 검색 중 (${bulkTablingProgress.current}/${bulkTablingProgress.total})` : "벌크 테이블링 연결"} @@ -1825,13 +1825,13 @@ function RestaurantsPanel({ isAdmin }: { isAdmin: boolean }) {
{bulkTabling && bulkTablingProgress.name && ( -
+
{bulkTablingProgress.current}/{bulkTablingProgress.total} - {bulkTablingProgress.name} 연결: {bulkTablingProgress.linked} / 미발견: {bulkTablingProgress.notFound}
-
-
+
+
)} @@ -1987,7 +1987,7 @@ function RestaurantsPanel({ isAdmin }: { isAdmin: boolean }) { finally { setTablingSearching(false); } }} disabled={tablingSearching} - className="px-2 py-0.5 text-[11px] bg-orange-500 text-white rounded hover:bg-orange-600 disabled:opacity-50" + className="px-2 py-0.5 text-[11px] bg-brand-500 text-white rounded hover:bg-brand-600 disabled:opacity-50" > {tablingSearching ? "검색 중..." : "테이블링 검색"} diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 7a860ec..c4aaabc 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -1,15 +1,37 @@ @import "tailwindcss"; :root { - --background: #ffffff; + --background: #FFFAF5; --foreground: #171717; + --brand-50: #FFF8F0; + --brand-100: #FFEDD5; + --brand-200: #FFD6A5; + --brand-300: #FFBC72; + --brand-400: #F5A623; + --brand-500: #F59E3F; + --brand-600: #E8720C; + --brand-700: #C45A00; + --brand-800: #9A4500; + --brand-900: #6B3000; + --brand-950: #3D1A00; color-scheme: light dark; } @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); - --font-sans: var(--font-geist); + --color-brand-50: var(--brand-50); + --color-brand-100: var(--brand-100); + --color-brand-200: var(--brand-200); + --color-brand-300: var(--brand-300); + --color-brand-400: var(--brand-400); + --color-brand-500: var(--brand-500); + --color-brand-600: var(--brand-600); + --color-brand-700: var(--brand-700); + --color-brand-800: var(--brand-800); + --color-brand-900: var(--brand-900); + --color-brand-950: var(--brand-950); + --font-sans: var(--font-pretendard), var(--font-geist), system-ui, sans-serif; } @media (prefers-color-scheme: dark) { diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index dbe35f9..0476482 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { Geist } from "next/font/google"; +import localFont from "next/font/local"; import "./globals.css"; import { Providers } from "./providers"; @@ -8,6 +9,14 @@ const geist = Geist({ subsets: ["latin"], }); +const pretendard = localFont({ + src: [ + { path: "../fonts/PretendardVariable.woff2", style: "normal" }, + ], + variable: "--font-pretendard", + display: "swap", +}); + export const metadata: Metadata = { title: "Tasteby - YouTube Restaurant Map", description: "YouTube food channel restaurant map service", @@ -20,7 +29,7 @@ export default function RootLayout({ }>) { return ( - + {children} diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index d61396f..2513ac9 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -600,7 +600,7 @@ export default function Home() {
)} @@ -992,7 +992,7 @@ export default function Home() { value={countryFilter} onChange={(e) => handleCountryChange(e.target.value)} className={`border dark:border-gray-700 rounded-lg px-2 py-1 bg-white dark:bg-gray-800 ${ - countryFilter ? "text-orange-600 dark:text-orange-400 border-orange-300 dark:border-orange-700" : "text-gray-500 dark:text-gray-400" + countryFilter ? "text-brand-600 dark:text-brand-400 border-brand-300 dark:border-brand-700" : "text-gray-500 dark:text-gray-400" }`} > @@ -1005,7 +1005,7 @@ export default function Home() { value={cityFilter} onChange={(e) => handleCityChange(e.target.value)} className={`border dark:border-gray-700 rounded-lg px-2 py-1 bg-white dark:bg-gray-800 ${ - cityFilter ? "text-orange-600 dark:text-orange-400 border-orange-300 dark:border-orange-700" : "text-gray-500 dark:text-gray-400" + cityFilter ? "text-brand-600 dark:text-brand-400 border-brand-300 dark:border-brand-700" : "text-gray-500 dark:text-gray-400" }`} > @@ -1019,7 +1019,7 @@ export default function Home() { value={districtFilter} onChange={(e) => handleDistrictChange(e.target.value)} className={`border dark:border-gray-700 rounded-lg px-2 py-1 bg-white dark:bg-gray-800 ${ - districtFilter ? "text-orange-600 dark:text-orange-400 border-orange-300 dark:border-orange-700" : "text-gray-500 dark:text-gray-400" + districtFilter ? "text-brand-600 dark:text-brand-400 border-brand-300 dark:border-brand-700" : "text-gray-500 dark:text-gray-400" }`} > @@ -1029,7 +1029,7 @@ export default function Home() { )} {countryFilter && ( - )} @@ -1056,7 +1056,7 @@ export default function Home() { }} className={`flex items-center gap-0.5 rounded-lg px-2 py-1 border transition-colors ${ boundsFilterOn - ? "bg-orange-50 dark:bg-orange-900/30 border-orange-300 dark:border-orange-700 text-orange-600 dark:text-orange-400" + ? "bg-brand-50 dark:bg-brand-900/30 border-brand-300 dark:border-brand-700 text-brand-600 dark:text-brand-400" : "border-gray-200 dark:border-gray-700 text-gray-500 dark:text-gray-400" }`} > @@ -1135,7 +1135,7 @@ export default function Home() { activeChannel={channelFilter || undefined} />
- + 내 주변 {filteredRestaurants.length}개
@@ -1167,7 +1167,7 @@ export default function Home() { {user.avatar_url ? ( ) : ( -
+
{(user.nickname || user.email || "?").charAt(0).toUpperCase()}
)} @@ -1259,7 +1259,7 @@ export default function Home() { onClick={() => handleMobileTab(tab.key)} className={`flex-1 flex flex-col items-center justify-center gap-0.5 py-2 transition-colors ${ mobileTab === tab.key - ? "text-orange-600 dark:text-orange-400" + ? "text-brand-600 dark:text-brand-400" : "text-gray-400 dark:text-gray-500" }`} > @@ -1276,10 +1276,10 @@ export default function Home() { SDJ Labs - - + +
SDJ Labs Co., Ltd. diff --git a/frontend/src/components/LoginMenu.tsx b/frontend/src/components/LoginMenu.tsx index 3b13aa3..c49621c 100644 --- a/frontend/src/components/LoginMenu.tsx +++ b/frontend/src/components/LoginMenu.tsx @@ -15,7 +15,7 @@ export default function LoginMenu({ onGoogleSuccess }: LoginMenuProps) { <> diff --git a/frontend/src/components/MapView.tsx b/frontend/src/components/MapView.tsx index bd52828..8125dcf 100644 --- a/frontend/src/components/MapView.tsx +++ b/frontend/src/components/MapView.tsx @@ -231,7 +231,7 @@ export default function MapView({ restaurants, selected, onSelectRestaurant, onB {onMyLocation && ( @@ -225,7 +225,7 @@ export default function ReviewSection({ restaurantId }: ReviewSectionProps) { {user && !myReview && !showForm && ( diff --git a/frontend/src/components/SearchBar.tsx b/frontend/src/components/SearchBar.tsx index 472e263..b23820a 100644 --- a/frontend/src/components/SearchBar.tsx +++ b/frontend/src/components/SearchBar.tsx @@ -36,11 +36,11 @@ export default function SearchBar({ onSearch, isLoading }: SearchBarProps) { value={query} onChange={(e) => setQuery(e.target.value)} placeholder="식당, 지역, 음식 검색..." - className="w-full pl-9 pr-3 py-2 bg-gray-100 dark:bg-gray-800 border border-transparent focus:border-orange-400 focus:bg-white dark:focus:bg-gray-900 rounded-xl text-sm outline-none transition-all dark:text-gray-200 dark:placeholder-gray-500" + className="w-full pl-9 pr-3 py-2 bg-gray-100 dark:bg-gray-800 border border-transparent focus:border-brand-400 focus:bg-white dark:focus:bg-gray-900 rounded-xl text-sm outline-none transition-all dark:text-gray-200 dark:placeholder-gray-500" /> {isLoading && (
-
+
)} diff --git a/frontend/src/fonts/PretendardVariable.woff2 b/frontend/src/fonts/PretendardVariable.woff2 new file mode 100644 index 0000000..49c54b5 Binary files /dev/null and b/frontend/src/fonts/PretendardVariable.woff2 differ