Add dark mode with system preference auto-detection
All user-facing components now support dark mode via prefers-color-scheme. - Dark backgrounds: gray-950/900/800 - Dark text: gray-100/200/300/400 - Orange brand colors adapt with darker tints - Glass effects work in both modes - Skeletons, cards, filters, bottom sheet all themed - Google Maps InfoWindow stays light (maps don't support dark) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
:root {
|
:root {
|
||||||
--background: #ffffff;
|
--background: #ffffff;
|
||||||
--foreground: #171717;
|
--foreground: #171717;
|
||||||
color-scheme: light only;
|
color-scheme: light dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
@@ -14,16 +14,11 @@
|
|||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root {
|
||||||
--background: #ffffff;
|
--background: #0a0a0a;
|
||||||
--foreground: #171717;
|
--foreground: #ededed;
|
||||||
color-scheme: light only;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
|
||||||
color-scheme: light only;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
@@ -34,11 +29,7 @@ html, body, #__next {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input, select, textarea {
|
/* Force Google Maps InfoWindow to light mode (maps don't support dark) */
|
||||||
color-scheme: light;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Force Google Maps InfoWindow to light mode */
|
|
||||||
.gm-style .gm-style-iw,
|
.gm-style .gm-style-iw,
|
||||||
.gm-style .gm-style-iw-c,
|
.gm-style .gm-style-iw-c,
|
||||||
.gm-style .gm-style-iw-d,
|
.gm-style .gm-style-iw-d,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export default function RootLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="ko" style={{ colorScheme: "light" }}>
|
<html lang="ko" className="dark:bg-gray-950" suppressHydrationWarning>
|
||||||
<body className={`${geist.variable} font-sans antialiased`}>
|
<body className={`${geist.variable} font-sans antialiased`}>
|
||||||
<Providers>{children}</Providers>
|
<Providers>{children}</Providers>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -418,9 +418,9 @@ export default function Home() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen flex flex-col">
|
<div className="h-screen flex flex-col bg-white dark:bg-gray-950">
|
||||||
{/* ── Header row 1: Logo + User ── */}
|
{/* ── Header row 1: Logo + User ── */}
|
||||||
<header className="bg-white/80 backdrop-blur-md border-b shrink-0">
|
<header className="bg-white/80 dark:bg-gray-900/80 backdrop-blur-md border-b dark:border-gray-800 shrink-0">
|
||||||
<div className="px-5 py-3 flex items-center justify-between">
|
<div className="px-5 py-3 flex items-center justify-between">
|
||||||
<button onClick={handleReset} className="text-lg font-bold whitespace-nowrap">
|
<button onClick={handleReset} className="text-lg font-bold whitespace-nowrap">
|
||||||
Tasteby
|
Tasteby
|
||||||
@@ -440,7 +440,7 @@ export default function Home() {
|
|||||||
setSelected(null);
|
setSelected(null);
|
||||||
setShowDetail(false);
|
setShowDetail(false);
|
||||||
}}
|
}}
|
||||||
className="border rounded-lg px-3 py-1.5 text-sm text-gray-600"
|
className="border dark:border-gray-700 rounded-lg px-3 py-1.5 text-sm text-gray-600 dark:text-gray-300 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">📺 전체 채널</option>
|
<option value="">📺 전체 채널</option>
|
||||||
{channels.map((ch) => (
|
{channels.map((ch) => (
|
||||||
@@ -452,7 +452,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={cuisineFilter}
|
value={cuisineFilter}
|
||||||
onChange={(e) => setCuisineFilter(e.target.value)}
|
onChange={(e) => setCuisineFilter(e.target.value)}
|
||||||
className="border rounded-lg px-3 py-1.5 text-sm text-gray-600"
|
className="border dark:border-gray-700 rounded-lg px-3 py-1.5 text-sm text-gray-600 dark:text-gray-300 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🍽 전체 장르</option>
|
<option value="">🍽 전체 장르</option>
|
||||||
{CUISINE_GROUPS.map((g) => (
|
{CUISINE_GROUPS.map((g) => (
|
||||||
@@ -462,7 +462,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={priceFilter}
|
value={priceFilter}
|
||||||
onChange={(e) => setPriceFilter(e.target.value)}
|
onChange={(e) => setPriceFilter(e.target.value)}
|
||||||
className="border rounded-lg px-3 py-1.5 text-sm text-gray-600"
|
className="border dark:border-gray-700 rounded-lg px-3 py-1.5 text-sm text-gray-600 dark:text-gray-300 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">💰 전체 가격</option>
|
<option value="">💰 전체 가격</option>
|
||||||
{PRICE_GROUPS.map((g) => (
|
{PRICE_GROUPS.map((g) => (
|
||||||
@@ -475,7 +475,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={countryFilter}
|
value={countryFilter}
|
||||||
onChange={(e) => handleCountryChange(e.target.value)}
|
onChange={(e) => handleCountryChange(e.target.value)}
|
||||||
className="border rounded-lg px-3 py-1.5 text-sm text-gray-600"
|
className="border dark:border-gray-700 rounded-lg px-3 py-1.5 text-sm text-gray-600 dark:text-gray-300 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🌍 전체 나라</option>
|
<option value="">🌍 전체 나라</option>
|
||||||
{countries.map((c) => (
|
{countries.map((c) => (
|
||||||
@@ -486,7 +486,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={cityFilter}
|
value={cityFilter}
|
||||||
onChange={(e) => handleCityChange(e.target.value)}
|
onChange={(e) => handleCityChange(e.target.value)}
|
||||||
className="border rounded-lg px-3 py-1.5 text-sm text-gray-600"
|
className="border dark:border-gray-700 rounded-lg px-3 py-1.5 text-sm text-gray-600 dark:text-gray-300 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🏙 전체 시/도</option>
|
<option value="">🏙 전체 시/도</option>
|
||||||
{cities.map((c) => (
|
{cities.map((c) => (
|
||||||
@@ -498,7 +498,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={districtFilter}
|
value={districtFilter}
|
||||||
onChange={(e) => handleDistrictChange(e.target.value)}
|
onChange={(e) => handleDistrictChange(e.target.value)}
|
||||||
className="border rounded-lg px-3 py-1.5 text-sm text-gray-600"
|
className="border dark:border-gray-700 rounded-lg px-3 py-1.5 text-sm text-gray-600 dark:text-gray-300 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🏘 전체 구/군</option>
|
<option value="">🏘 전체 구/군</option>
|
||||||
{districts.map((d) => (
|
{districts.map((d) => (
|
||||||
@@ -506,13 +506,13 @@ export default function Home() {
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
)}
|
)}
|
||||||
<div className="w-px h-5 bg-gray-200" />
|
<div className="w-px h-5 bg-gray-200 dark:bg-gray-700" />
|
||||||
<button
|
<button
|
||||||
onClick={() => setBoundsFilterOn(!boundsFilterOn)}
|
onClick={() => setBoundsFilterOn(!boundsFilterOn)}
|
||||||
className={`px-3 py-1.5 text-sm border rounded-lg transition-colors ${
|
className={`px-3 py-1.5 text-sm border rounded-lg transition-colors ${
|
||||||
boundsFilterOn
|
boundsFilterOn
|
||||||
? "bg-orange-50 border-orange-300 text-orange-600"
|
? "bg-orange-50 dark:bg-orange-900/30 border-orange-300 dark:border-orange-700 text-orange-600 dark:text-orange-400"
|
||||||
: "hover:bg-gray-100 text-gray-600"
|
: "hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-600 dark:text-gray-400"
|
||||||
}`}
|
}`}
|
||||||
title="지도 영역 내 식당만 표시"
|
title="지도 영역 내 식당만 표시"
|
||||||
>
|
>
|
||||||
@@ -520,7 +520,7 @@ export default function Home() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setViewMode(viewMode === "map" ? "list" : "map")}
|
onClick={() => setViewMode(viewMode === "map" ? "list" : "map")}
|
||||||
className="px-3 py-1.5 text-sm border rounded-lg transition-colors hover:bg-gray-100 text-gray-600"
|
className="px-3 py-1.5 text-sm border rounded-lg transition-colors hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-600 dark:text-gray-400"
|
||||||
title={viewMode === "map" ? "리스트 우선" : "지도 우선"}
|
title={viewMode === "map" ? "리스트 우선" : "지도 우선"}
|
||||||
>
|
>
|
||||||
{viewMode === "map" ? "🗺 지도" : "☰ 리스트"}
|
{viewMode === "map" ? "🗺 지도" : "☰ 리스트"}
|
||||||
@@ -531,8 +531,8 @@ export default function Home() {
|
|||||||
onClick={handleToggleFavorites}
|
onClick={handleToggleFavorites}
|
||||||
className={`px-3.5 py-1.5 text-sm rounded-full border transition-colors ${
|
className={`px-3.5 py-1.5 text-sm rounded-full border transition-colors ${
|
||||||
showFavorites
|
showFavorites
|
||||||
? "bg-rose-50 border-rose-300 text-rose-600"
|
? "bg-rose-50 dark:bg-rose-900/30 border-rose-300 dark:border-rose-700 text-rose-600 dark:text-rose-400"
|
||||||
: "border-gray-300 text-gray-600 hover:bg-gray-100"
|
: "border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-100"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{showFavorites ? "♥ 내 찜" : "♡ 찜"}
|
{showFavorites ? "♥ 내 찜" : "♡ 찜"}
|
||||||
@@ -541,8 +541,8 @@ export default function Home() {
|
|||||||
onClick={handleToggleMyReviews}
|
onClick={handleToggleMyReviews}
|
||||||
className={`px-3.5 py-1.5 text-sm rounded-full border transition-colors ${
|
className={`px-3.5 py-1.5 text-sm rounded-full border transition-colors ${
|
||||||
showMyReviews
|
showMyReviews
|
||||||
? "bg-orange-50 border-orange-300 text-orange-600"
|
? "bg-orange-50 dark:bg-orange-900/30 border-orange-300 dark:border-orange-700 text-orange-600 dark:text-orange-400"
|
||||||
: "border-gray-300 text-gray-600 hover:bg-gray-100"
|
: "border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:bg-gray-100"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{showMyReviews ? "✎ 내 리뷰" : "✎ 리뷰"}
|
{showMyReviews ? "✎ 내 리뷰" : "✎ 리뷰"}
|
||||||
@@ -570,12 +570,12 @@ export default function Home() {
|
|||||||
{(user.nickname || user.email || "?").charAt(0).toUpperCase()}
|
{(user.nickname || user.email || "?").charAt(0).toUpperCase()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<span className="hidden sm:inline text-sm font-medium text-gray-700">
|
<span className="hidden sm:inline text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
{user.nickname || user.email}
|
{user.nickname || user.email}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={logout}
|
onClick={logout}
|
||||||
className="ml-1 px-2.5 py-1 text-xs text-gray-500 border border-gray-300 rounded-full hover:bg-gray-100 hover:text-gray-700 transition-colors"
|
className="ml-1 px-2.5 py-1 text-xs text-gray-500 dark:text-gray-400 border border-gray-300 dark:border-gray-700 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-200 transition-colors"
|
||||||
>
|
>
|
||||||
로그아웃
|
로그아웃
|
||||||
</button>
|
</button>
|
||||||
@@ -604,7 +604,7 @@ export default function Home() {
|
|||||||
onClick={() => setViewMode(viewMode === "map" ? "list" : "map")}
|
onClick={() => setViewMode(viewMode === "map" ? "list" : "map")}
|
||||||
className={`px-3 py-1.5 text-xs border rounded-lg transition-colors ${
|
className={`px-3 py-1.5 text-xs border rounded-lg transition-colors ${
|
||||||
viewMode === "map"
|
viewMode === "map"
|
||||||
? "bg-orange-50 border-orange-300 text-orange-600"
|
? "bg-orange-50 dark:bg-orange-900/30 border-orange-300 dark:border-orange-700 text-orange-600 dark:text-orange-400"
|
||||||
: "text-gray-600"
|
: "text-gray-600"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -614,7 +614,7 @@ export default function Home() {
|
|||||||
onClick={() => setShowMobileFilters(!showMobileFilters)}
|
onClick={() => setShowMobileFilters(!showMobileFilters)}
|
||||||
className={`px-3 py-1.5 text-xs border rounded-lg transition-colors relative ${
|
className={`px-3 py-1.5 text-xs border rounded-lg transition-colors relative ${
|
||||||
showMobileFilters || channelFilter || cuisineFilter || priceFilter || countryFilter || boundsFilterOn
|
showMobileFilters || channelFilter || cuisineFilter || priceFilter || countryFilter || boundsFilterOn
|
||||||
? "bg-orange-50 border-orange-300 text-orange-600"
|
? "bg-orange-50 dark:bg-orange-900/30 border-orange-300 dark:border-orange-700 text-orange-600 dark:text-orange-400"
|
||||||
: "text-gray-600"
|
: "text-gray-600"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -631,8 +631,8 @@ export default function Home() {
|
|||||||
onClick={handleToggleFavorites}
|
onClick={handleToggleFavorites}
|
||||||
className={`px-3 py-1.5 text-xs rounded-full border transition-colors ${
|
className={`px-3 py-1.5 text-xs rounded-full border transition-colors ${
|
||||||
showFavorites
|
showFavorites
|
||||||
? "bg-rose-50 border-rose-300 text-rose-600"
|
? "bg-rose-50 dark:bg-rose-900/30 border-rose-300 dark:border-rose-700 text-rose-600 dark:text-rose-400"
|
||||||
: "border-gray-300 text-gray-600"
|
: "border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-400"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{showFavorites ? "♥ 찜" : "♡ 찜"}
|
{showFavorites ? "♥ 찜" : "♡ 찜"}
|
||||||
@@ -641,8 +641,8 @@ export default function Home() {
|
|||||||
onClick={handleToggleMyReviews}
|
onClick={handleToggleMyReviews}
|
||||||
className={`px-3 py-1.5 text-xs rounded-full border transition-colors ${
|
className={`px-3 py-1.5 text-xs rounded-full border transition-colors ${
|
||||||
showMyReviews
|
showMyReviews
|
||||||
? "bg-orange-50 border-orange-300 text-orange-600"
|
? "bg-orange-50 dark:bg-orange-900/30 border-orange-300 dark:border-orange-700 text-orange-600 dark:text-orange-400"
|
||||||
: "border-gray-300 text-gray-600"
|
: "border-gray-300 dark:border-gray-700 text-gray-600 dark:text-gray-400"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{showMyReviews ? "✎ 리뷰" : "✎ 리뷰"}
|
{showMyReviews ? "✎ 리뷰" : "✎ 리뷰"}
|
||||||
@@ -656,7 +656,7 @@ export default function Home() {
|
|||||||
|
|
||||||
{/* Collapsible filter panel */}
|
{/* Collapsible filter panel */}
|
||||||
{showMobileFilters && (
|
{showMobileFilters && (
|
||||||
<div className="bg-white/70 backdrop-blur-md rounded-xl p-3.5 space-y-3 border border-white/50 shadow-sm">
|
<div className="bg-white/70 dark:bg-gray-900/70 backdrop-blur-md rounded-xl p-3.5 space-y-3 border border-white/50 dark:border-gray-700/50 shadow-sm">
|
||||||
{/* Dropdown filters */}
|
{/* Dropdown filters */}
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<select
|
<select
|
||||||
@@ -666,7 +666,7 @@ export default function Home() {
|
|||||||
setSelected(null);
|
setSelected(null);
|
||||||
setShowDetail(false);
|
setShowDetail(false);
|
||||||
}}
|
}}
|
||||||
className="border rounded-lg px-2.5 py-1.5 text-xs text-gray-600 bg-white"
|
className="border dark:border-gray-700 rounded-lg px-2.5 py-1.5 text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">📺 전체 채널</option>
|
<option value="">📺 전체 채널</option>
|
||||||
{channels.map((ch) => (
|
{channels.map((ch) => (
|
||||||
@@ -678,7 +678,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={cuisineFilter}
|
value={cuisineFilter}
|
||||||
onChange={(e) => setCuisineFilter(e.target.value)}
|
onChange={(e) => setCuisineFilter(e.target.value)}
|
||||||
className="border rounded-lg px-2.5 py-1.5 text-xs text-gray-600 bg-white"
|
className="border dark:border-gray-700 rounded-lg px-2.5 py-1.5 text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🍽 전체 장르</option>
|
<option value="">🍽 전체 장르</option>
|
||||||
{CUISINE_GROUPS.map((g) => (
|
{CUISINE_GROUPS.map((g) => (
|
||||||
@@ -688,7 +688,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={priceFilter}
|
value={priceFilter}
|
||||||
onChange={(e) => setPriceFilter(e.target.value)}
|
onChange={(e) => setPriceFilter(e.target.value)}
|
||||||
className="border rounded-lg px-2.5 py-1.5 text-xs text-gray-600 bg-white"
|
className="border dark:border-gray-700 rounded-lg px-2.5 py-1.5 text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">💰 전체 가격</option>
|
<option value="">💰 전체 가격</option>
|
||||||
{PRICE_GROUPS.map((g) => (
|
{PRICE_GROUPS.map((g) => (
|
||||||
@@ -701,7 +701,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={countryFilter}
|
value={countryFilter}
|
||||||
onChange={(e) => handleCountryChange(e.target.value)}
|
onChange={(e) => handleCountryChange(e.target.value)}
|
||||||
className="border rounded-lg px-2.5 py-1.5 text-xs text-gray-600 bg-white"
|
className="border dark:border-gray-700 rounded-lg px-2.5 py-1.5 text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🌍 전체 나라</option>
|
<option value="">🌍 전체 나라</option>
|
||||||
{countries.map((c) => (
|
{countries.map((c) => (
|
||||||
@@ -712,7 +712,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={cityFilter}
|
value={cityFilter}
|
||||||
onChange={(e) => handleCityChange(e.target.value)}
|
onChange={(e) => handleCityChange(e.target.value)}
|
||||||
className="border rounded-lg px-2.5 py-1.5 text-xs text-gray-600 bg-white"
|
className="border dark:border-gray-700 rounded-lg px-2.5 py-1.5 text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🏙 전체 시/도</option>
|
<option value="">🏙 전체 시/도</option>
|
||||||
{cities.map((c) => (
|
{cities.map((c) => (
|
||||||
@@ -724,7 +724,7 @@ export default function Home() {
|
|||||||
<select
|
<select
|
||||||
value={districtFilter}
|
value={districtFilter}
|
||||||
onChange={(e) => handleDistrictChange(e.target.value)}
|
onChange={(e) => handleDistrictChange(e.target.value)}
|
||||||
className="border rounded-lg px-2.5 py-1.5 text-xs text-gray-600 bg-white"
|
className="border dark:border-gray-700 rounded-lg px-2.5 py-1.5 text-xs text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<option value="">🏘 전체 구/군</option>
|
<option value="">🏘 전체 구/군</option>
|
||||||
{districts.map((d) => (
|
{districts.map((d) => (
|
||||||
@@ -739,8 +739,8 @@ export default function Home() {
|
|||||||
onClick={() => setBoundsFilterOn(!boundsFilterOn)}
|
onClick={() => setBoundsFilterOn(!boundsFilterOn)}
|
||||||
className={`px-2.5 py-1.5 text-xs border rounded-lg transition-colors ${
|
className={`px-2.5 py-1.5 text-xs border rounded-lg transition-colors ${
|
||||||
boundsFilterOn
|
boundsFilterOn
|
||||||
? "bg-orange-50 border-orange-300 text-orange-600"
|
? "bg-orange-50 dark:bg-orange-900/30 border-orange-300 dark:border-orange-700 text-orange-600 dark:text-orange-400"
|
||||||
: "text-gray-600 bg-white"
|
: "text-gray-600 dark:text-gray-400 bg-white dark:bg-gray-800"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{boundsFilterOn ? "📍 영역 ON" : "📍 영역"}
|
{boundsFilterOn ? "📍 영역 ON" : "📍 영역"}
|
||||||
@@ -757,7 +757,7 @@ export default function Home() {
|
|||||||
<div className="hidden md:flex flex-1 overflow-hidden">
|
<div className="hidden md:flex flex-1 overflow-hidden">
|
||||||
{viewMode === "map" ? (
|
{viewMode === "map" ? (
|
||||||
<>
|
<>
|
||||||
<aside className="w-80 bg-white border-r overflow-y-auto shrink-0">
|
<aside className="w-80 bg-white dark:bg-gray-950 border-r dark:border-gray-800 overflow-y-auto shrink-0">
|
||||||
{sidebarContent}
|
{sidebarContent}
|
||||||
</aside>
|
</aside>
|
||||||
<main className="flex-1 relative">
|
<main className="flex-1 relative">
|
||||||
@@ -777,10 +777,10 @@ export default function Home() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<aside className="flex-1 bg-white overflow-y-auto">
|
<aside className="flex-1 bg-white dark:bg-gray-950 overflow-y-auto">
|
||||||
{sidebarContent}
|
{sidebarContent}
|
||||||
</aside>
|
</aside>
|
||||||
<main className="w-[40%] shrink-0 relative border-l">
|
<main className="w-[40%] shrink-0 relative border-l dark:border-gray-800">
|
||||||
<MapView
|
<MapView
|
||||||
restaurants={filteredRestaurants}
|
restaurants={filteredRestaurants}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
@@ -819,7 +819,7 @@ export default function Home() {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="flex-1 bg-white overflow-y-auto">
|
<div className="flex-1 bg-white dark:bg-gray-950 overflow-y-auto">
|
||||||
{mobileListContent}
|
{mobileListContent}
|
||||||
{/* Scroll-down hint to reveal map */}
|
{/* Scroll-down hint to reveal map */}
|
||||||
<div className="flex flex-col items-center py-4 text-gray-300">
|
<div className="flex flex-col items-center py-4 text-gray-300">
|
||||||
@@ -827,7 +827,7 @@ export default function Home() {
|
|||||||
<span className="text-[10px]">아래로 스크롤하면 지도</span>
|
<span className="text-[10px]">아래로 스크롤하면 지도</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-[35vh] shrink-0 relative border-t">
|
<div className="h-[35vh] shrink-0 relative border-t dark:border-gray-800">
|
||||||
<MapView
|
<MapView
|
||||||
restaurants={filteredRestaurants}
|
restaurants={filteredRestaurants}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
@@ -853,7 +853,7 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="shrink-0 border-t bg-white/60 backdrop-blur-sm py-2.5 flex items-center justify-center gap-2 text-[11px] text-gray-400 group">
|
<footer className="shrink-0 border-t dark:border-gray-800 bg-white/60 dark:bg-gray-900/60 backdrop-blur-sm py-2.5 flex items-center justify-center gap-2 text-[11px] text-gray-400 dark:text-gray-500 group">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<img
|
<img
|
||||||
src="/icon.jpg"
|
src="/icon.jpg"
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export default function BottomSheet({ open, onClose, children }: BottomSheetProp
|
|||||||
{/* Sheet */}
|
{/* Sheet */}
|
||||||
<div
|
<div
|
||||||
ref={sheetRef}
|
ref={sheetRef}
|
||||||
className="fixed bottom-0 left-0 right-0 z-50 md:hidden flex flex-col bg-white/85 backdrop-blur-xl rounded-t-2xl shadow-2xl"
|
className="fixed bottom-0 left-0 right-0 z-50 md:hidden flex flex-col bg-white/85 dark:bg-gray-900/90 backdrop-blur-xl rounded-t-2xl shadow-2xl"
|
||||||
style={{
|
style={{
|
||||||
height: `${height * 100}vh`,
|
height: `${height * 100}vh`,
|
||||||
transition: dragging ? "none" : "height 0.3s cubic-bezier(0.2, 0, 0, 1)",
|
transition: dragging ? "none" : "height 0.3s cubic-bezier(0.2, 0, 0, 1)",
|
||||||
@@ -100,7 +100,7 @@ export default function BottomSheet({ open, onClose, children }: BottomSheetProp
|
|||||||
>
|
>
|
||||||
{/* Handle bar */}
|
{/* Handle bar */}
|
||||||
<div className="flex justify-center pt-2 pb-1 shrink-0 cursor-grab">
|
<div className="flex justify-center pt-2 pb-1 shrink-0 cursor-grab">
|
||||||
<div className="w-10 h-1 bg-gray-300 rounded-full" />
|
<div className="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-full" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
|
|||||||
@@ -50,13 +50,13 @@ export default function RestaurantDetail({
|
|||||||
<div className="p-4 space-y-4">
|
<div className="p-4 space-y-4">
|
||||||
<div className="flex justify-between items-start">
|
<div className="flex justify-between items-start">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h2 className="text-lg font-bold">{restaurant.name}</h2>
|
<h2 className="text-lg font-bold dark:text-gray-100">{restaurant.name}</h2>
|
||||||
{getToken() && (
|
{getToken() && (
|
||||||
<button
|
<button
|
||||||
onClick={handleToggleFavorite}
|
onClick={handleToggleFavorite}
|
||||||
disabled={favLoading}
|
disabled={favLoading}
|
||||||
className={`text-xl leading-none transition-colors ${
|
className={`text-xl leading-none transition-colors ${
|
||||||
favorited ? "text-rose-500" : "text-gray-300 hover:text-rose-400"
|
favorited ? "text-rose-500" : "text-gray-300 dark:text-gray-600 hover:text-rose-400"
|
||||||
}`}
|
}`}
|
||||||
title={favorited ? "찜 해제" : "찜하기"}
|
title={favorited ? "찜 해제" : "찜하기"}
|
||||||
>
|
>
|
||||||
@@ -64,19 +64,19 @@ export default function RestaurantDetail({
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{restaurant.business_status === "CLOSED_PERMANENTLY" && (
|
{restaurant.business_status === "CLOSED_PERMANENTLY" && (
|
||||||
<span className="px-2 py-0.5 bg-red-100 text-red-700 rounded text-xs font-semibold">
|
<span className="px-2 py-0.5 bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400 rounded text-xs font-semibold">
|
||||||
폐업
|
폐업
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{restaurant.business_status === "CLOSED_TEMPORARILY" && (
|
{restaurant.business_status === "CLOSED_TEMPORARILY" && (
|
||||||
<span className="px-2 py-0.5 bg-yellow-100 text-yellow-700 rounded text-xs font-semibold">
|
<span className="px-2 py-0.5 bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-400 rounded text-xs font-semibold">
|
||||||
임시휴업
|
임시휴업
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="text-gray-400 hover:text-gray-600 text-xl leading-none"
|
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 text-xl leading-none"
|
||||||
>
|
>
|
||||||
x
|
x
|
||||||
</button>
|
</button>
|
||||||
@@ -84,39 +84,39 @@ export default function RestaurantDetail({
|
|||||||
|
|
||||||
{restaurant.rating && (
|
{restaurant.rating && (
|
||||||
<div className="flex items-center gap-2 text-sm">
|
<div className="flex items-center gap-2 text-sm">
|
||||||
<span className="text-yellow-500">{"★".repeat(Math.round(restaurant.rating))}</span>
|
<span className="text-yellow-500 dark:text-yellow-400">{"★".repeat(Math.round(restaurant.rating))}</span>
|
||||||
<span className="font-medium">{restaurant.rating}</span>
|
<span className="font-medium dark:text-gray-200">{restaurant.rating}</span>
|
||||||
{restaurant.rating_count && (
|
{restaurant.rating_count && (
|
||||||
<span className="text-gray-400 text-xs">({restaurant.rating_count.toLocaleString()})</span>
|
<span className="text-gray-400 dark:text-gray-500 text-xs">({restaurant.rating_count.toLocaleString()})</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="space-y-1 text-sm">
|
<div className="space-y-1 text-sm dark:text-gray-300">
|
||||||
{restaurant.cuisine_type && (
|
{restaurant.cuisine_type && (
|
||||||
<p>
|
<p>
|
||||||
<span className="text-gray-500">종류:</span> {restaurant.cuisine_type}
|
<span className="text-gray-500 dark:text-gray-400">종류:</span> {restaurant.cuisine_type}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{restaurant.address && (
|
{restaurant.address && (
|
||||||
<p>
|
<p>
|
||||||
<span className="text-gray-500">주소:</span> {restaurant.address}
|
<span className="text-gray-500 dark:text-gray-400">주소:</span> {restaurant.address}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{restaurant.region && (
|
{restaurant.region && (
|
||||||
<p>
|
<p>
|
||||||
<span className="text-gray-500">지역:</span> {restaurant.region}
|
<span className="text-gray-500 dark:text-gray-400">지역:</span> {restaurant.region}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{restaurant.price_range && (
|
{restaurant.price_range && (
|
||||||
<p>
|
<p>
|
||||||
<span className="text-gray-500">가격대:</span> {restaurant.price_range}
|
<span className="text-gray-500 dark:text-gray-400">가격대:</span> {restaurant.price_range}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{restaurant.phone && (
|
{restaurant.phone && (
|
||||||
<p>
|
<p>
|
||||||
<span className="text-gray-500">전화:</span>{" "}
|
<span className="text-gray-500 dark:text-gray-400">전화:</span>{" "}
|
||||||
<a href={`tel:${restaurant.phone}`} className="text-orange-600 hover:underline">
|
<a href={`tel:${restaurant.phone}`} className="text-orange-600 dark:text-orange-400 hover:underline">
|
||||||
{restaurant.phone}
|
{restaurant.phone}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -127,7 +127,7 @@ export default function RestaurantDetail({
|
|||||||
href={`https://www.google.com/maps/place/?q=place_id:${restaurant.google_place_id}`}
|
href={`https://www.google.com/maps/place/?q=place_id:${restaurant.google_place_id}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-orange-600 hover:underline text-xs"
|
className="text-orange-600 dark:text-orange-400 hover:underline text-xs"
|
||||||
>
|
>
|
||||||
Google Maps에서 보기
|
Google Maps에서 보기
|
||||||
</a>
|
</a>
|
||||||
@@ -136,37 +136,37 @@ export default function RestaurantDetail({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-sm mb-2">관련 영상</h3>
|
<h3 className="font-semibold text-sm mb-2 dark:text-gray-200">관련 영상</h3>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="space-y-3 animate-pulse">
|
<div className="space-y-3 animate-pulse">
|
||||||
{[1, 2].map((i) => (
|
{[1, 2].map((i) => (
|
||||||
<div key={i} className="border rounded-lg p-3 space-y-2">
|
<div key={i} className="border dark:border-gray-700 rounded-lg p-3 space-y-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="h-4 w-16 bg-gray-200 rounded-sm" />
|
<div className="h-4 w-16 bg-gray-200 dark:bg-gray-700 rounded-sm" />
|
||||||
<div className="h-3 w-20 bg-gray-200 rounded" />
|
<div className="h-3 w-20 bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
</div>
|
</div>
|
||||||
<div className="h-4 w-full bg-gray-200 rounded" />
|
<div className="h-4 w-full bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<div className="h-5 w-14 bg-gray-200 rounded" />
|
<div className="h-5 w-14 bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
<div className="h-5 w-16 bg-gray-200 rounded" />
|
<div className="h-5 w-16 bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : videos.length === 0 ? (
|
) : videos.length === 0 ? (
|
||||||
<p className="text-sm text-gray-500">관련 영상이 없습니다</p>
|
<p className="text-sm text-gray-500 dark:text-gray-400">관련 영상이 없습니다</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{videos.map((v) => (
|
{videos.map((v) => (
|
||||||
<div key={v.video_id} className="border rounded-lg p-3">
|
<div key={v.video_id} className="border dark:border-gray-700 rounded-lg p-3">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1">
|
||||||
{v.channel_name && (
|
{v.channel_name && (
|
||||||
<span className="inline-block px-1.5 py-0.5 bg-orange-50 text-orange-600 rounded text-[10px] font-medium">
|
<span className="inline-block px-1.5 py-0.5 bg-orange-50 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400 rounded text-[10px] font-medium">
|
||||||
{v.channel_name}
|
{v.channel_name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{v.published_at && (
|
{v.published_at && (
|
||||||
<span className="text-[10px] text-gray-400">
|
<span className="text-[10px] text-gray-400 dark:text-gray-500">
|
||||||
{v.published_at.slice(0, 10)}
|
{v.published_at.slice(0, 10)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -175,7 +175,7 @@ export default function RestaurantDetail({
|
|||||||
href={v.url}
|
href={v.url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="block text-sm font-medium text-orange-600 hover:underline"
|
className="block text-sm font-medium text-orange-600 dark:text-orange-400 hover:underline"
|
||||||
>
|
>
|
||||||
{v.title}
|
{v.title}
|
||||||
</a>
|
</a>
|
||||||
@@ -184,7 +184,7 @@ export default function RestaurantDetail({
|
|||||||
{v.foods_mentioned.map((f, i) => (
|
{v.foods_mentioned.map((f, i) => (
|
||||||
<span
|
<span
|
||||||
key={i}
|
key={i}
|
||||||
className="px-2 py-0.5 bg-orange-50 text-orange-700 rounded text-xs"
|
className="px-2 py-0.5 bg-orange-50 dark:bg-orange-900/30 text-orange-700 dark:text-orange-400 rounded text-xs"
|
||||||
>
|
>
|
||||||
{f}
|
{f}
|
||||||
</span>
|
</span>
|
||||||
@@ -192,12 +192,12 @@ export default function RestaurantDetail({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{v.evaluation?.text && (
|
{v.evaluation?.text && (
|
||||||
<p className="mt-1 text-xs text-gray-600">
|
<p className="mt-1 text-xs text-gray-600 dark:text-gray-400">
|
||||||
{v.evaluation.text}
|
{v.evaluation.text}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{v.guests.length > 0 && (
|
{v.guests.length > 0 && (
|
||||||
<p className="mt-1 text-xs text-gray-500">
|
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||||
게스트: {v.guests.join(", ")}
|
게스트: {v.guests.join(", ")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -208,11 +208,11 @@ export default function RestaurantDetail({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{videos.length > 0 && (
|
{videos.length > 0 && (
|
||||||
<div className="bg-gray-50 rounded-lg px-4 py-3 text-center space-y-1">
|
<div className="bg-gray-50 dark:bg-gray-800/50 rounded-lg px-4 py-3 text-center space-y-1">
|
||||||
<p className="text-xs text-gray-500">
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||||
더 자세한 내용은 영상에서 확인하실 수 있습니다.
|
더 자세한 내용은 영상에서 확인하실 수 있습니다.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-gray-400">
|
<p className="text-xs text-gray-400 dark:text-gray-500">
|
||||||
맛집을 소개해주신 크리에이터를 구독과 좋아요로 응원해주세요!
|
맛집을 소개해주신 크리에이터를 구독과 좋아요로 응원해주세요!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default function RestaurantList({
|
|||||||
|
|
||||||
if (!restaurants.length) {
|
if (!restaurants.length) {
|
||||||
return (
|
return (
|
||||||
<div className="p-4 text-center text-gray-500 text-sm">
|
<div className="p-4 text-center text-gray-500 dark:text-gray-400 text-sm">
|
||||||
표시할 식당이 없습니다
|
표시할 식당이 없습니다
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -37,38 +37,38 @@ export default function RestaurantList({
|
|||||||
onClick={() => onSelect(r)}
|
onClick={() => onSelect(r)}
|
||||||
className={`w-full text-left p-3 rounded-xl shadow-sm border transition-all hover:shadow-md hover:-translate-y-0.5 ${
|
className={`w-full text-left p-3 rounded-xl shadow-sm border transition-all hover:shadow-md hover:-translate-y-0.5 ${
|
||||||
selectedId === r.id
|
selectedId === r.id
|
||||||
? "bg-orange-50 border-orange-300 shadow-orange-100"
|
? "bg-orange-50 dark:bg-orange-900/20 border-orange-300 dark:border-orange-700 shadow-orange-100 dark:shadow-orange-900/10"
|
||||||
: "bg-white border-gray-100 hover:bg-gray-50"
|
: "bg-white dark:bg-gray-900 border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<h4 className="font-semibold text-sm">
|
<h4 className="font-semibold text-sm dark:text-gray-100">
|
||||||
<span className="mr-1">{getCuisineIcon(r.cuisine_type)}</span>
|
<span className="mr-1">{getCuisineIcon(r.cuisine_type)}</span>
|
||||||
{r.name}
|
{r.name}
|
||||||
</h4>
|
</h4>
|
||||||
{r.rating && (
|
{r.rating && (
|
||||||
<span className="text-xs text-yellow-600 font-medium whitespace-nowrap shrink-0">
|
<span className="text-xs text-yellow-600 dark:text-yellow-400 font-medium whitespace-nowrap shrink-0">
|
||||||
★ {r.rating}
|
★ {r.rating}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap gap-x-2 gap-y-0.5 mt-1.5 text-xs text-gray-500">
|
<div className="flex flex-wrap gap-x-2 gap-y-0.5 mt-1.5 text-xs">
|
||||||
{r.cuisine_type && (
|
{r.cuisine_type && (
|
||||||
<span className="px-1.5 py-0.5 bg-gray-100 rounded text-gray-600">{r.cuisine_type}</span>
|
<span className="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 rounded text-gray-600 dark:text-gray-400">{r.cuisine_type}</span>
|
||||||
)}
|
)}
|
||||||
{r.price_range && (
|
{r.price_range && (
|
||||||
<span className="px-1.5 py-0.5 bg-gray-50 rounded text-gray-600">{r.price_range}</span>
|
<span className="px-1.5 py-0.5 bg-gray-50 dark:bg-gray-800 rounded text-gray-600 dark:text-gray-400">{r.price_range}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{r.region && (
|
{r.region && (
|
||||||
<p className="mt-1 text-xs text-gray-400 truncate">{r.region}</p>
|
<p className="mt-1 text-xs text-gray-400 dark:text-gray-500 truncate">{r.region}</p>
|
||||||
)}
|
)}
|
||||||
{r.foods_mentioned && r.foods_mentioned.length > 0 && (
|
{r.foods_mentioned && r.foods_mentioned.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-1 mt-1.5">
|
<div className="flex flex-wrap gap-1 mt-1.5">
|
||||||
{r.foods_mentioned.slice(0, 5).map((f, i) => (
|
{r.foods_mentioned.slice(0, 5).map((f, i) => (
|
||||||
<span
|
<span
|
||||||
key={i}
|
key={i}
|
||||||
className="px-1.5 py-0.5 bg-orange-50 text-orange-700 rounded text-[10px]"
|
className="px-1.5 py-0.5 bg-orange-50 dark:bg-orange-900/30 text-orange-700 dark:text-orange-400 rounded text-[10px]"
|
||||||
>
|
>
|
||||||
{f}
|
{f}
|
||||||
</span>
|
</span>
|
||||||
@@ -83,7 +83,7 @@ export default function RestaurantList({
|
|||||||
{r.channels.map((ch) => (
|
{r.channels.map((ch) => (
|
||||||
<span
|
<span
|
||||||
key={ch}
|
key={ch}
|
||||||
className="px-1.5 py-0.5 bg-orange-50 text-orange-600 rounded-full text-[10px] font-medium"
|
className="px-1.5 py-0.5 bg-orange-50 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400 rounded-full text-[10px] font-medium"
|
||||||
>
|
>
|
||||||
{ch}
|
{ch}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ function ReviewForm({
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
className="px-3 py-1 bg-orange-500 text-white text-sm rounded hover:bg-orange-600 disabled:opacity-50"
|
className="px-3 py-1 bg-orange-500 dark:bg-orange-600 text-white text-sm rounded hover:bg-orange-600 dark:hover:bg-orange-500 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{submitting ? "저장 중..." : submitLabel}
|
{submitting ? "저장 중..." : submitLabel}
|
||||||
</button>
|
</button>
|
||||||
@@ -202,13 +202,13 @@ export default function ReviewSection({ restaurantId }: ReviewSectionProps) {
|
|||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="space-y-3 animate-pulse">
|
<div className="space-y-3 animate-pulse">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="h-4 w-24 bg-gray-200 rounded" />
|
<div className="h-4 w-24 bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
<div className="h-4 w-8 bg-gray-200 rounded" />
|
<div className="h-4 w-8 bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
</div>
|
</div>
|
||||||
{[1, 2].map((i) => (
|
{[1, 2].map((i) => (
|
||||||
<div key={i} className="space-y-1">
|
<div key={i} className="space-y-1">
|
||||||
<div className="h-3 w-20 bg-gray-200 rounded" />
|
<div className="h-3 w-20 bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
<div className="h-3 w-full bg-gray-200 rounded" />
|
<div className="h-3 w-full bg-gray-200 dark:bg-gray-700 rounded" />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -225,7 +225,7 @@ export default function ReviewSection({ restaurantId }: ReviewSectionProps) {
|
|||||||
{user && !myReview && !showForm && (
|
{user && !myReview && !showForm && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowForm(true)}
|
onClick={() => setShowForm(true)}
|
||||||
className="mb-3 px-3 py-1 bg-orange-500 text-white text-sm rounded hover:bg-orange-600"
|
className="mb-3 px-3 py-1 bg-orange-500 dark:bg-orange-600 text-white text-sm rounded hover:bg-orange-600 dark:hover:bg-orange-500"
|
||||||
>
|
>
|
||||||
리뷰 작성
|
리뷰 작성
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ export default function SearchBar({ onSearch, isLoading }: SearchBarProps) {
|
|||||||
value={query}
|
value={query}
|
||||||
onChange={(e) => setQuery(e.target.value)}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
placeholder="식당, 지역, 음식..."
|
placeholder="식당, 지역, 음식..."
|
||||||
className="flex-1 min-w-0 px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-400 text-sm"
|
className="flex-1 min-w-0 px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-400 text-sm bg-white dark:bg-gray-800 dark:text-gray-200 dark:placeholder-gray-500"
|
||||||
/>
|
/>
|
||||||
<select
|
<select
|
||||||
value={mode}
|
value={mode}
|
||||||
onChange={(e) => setMode(e.target.value as typeof mode)}
|
onChange={(e) => setMode(e.target.value as typeof mode)}
|
||||||
className="shrink-0 px-2 py-2 border border-gray-300 rounded-lg text-sm bg-white"
|
className="shrink-0 px-2 py-2 border border-gray-300 dark:border-gray-700 rounded-lg text-sm bg-white dark:bg-gray-800 dark:text-gray-300"
|
||||||
>
|
>
|
||||||
<option value="hybrid">통합</option>
|
<option value="hybrid">통합</option>
|
||||||
<option value="keyword">키워드</option>
|
<option value="keyword">키워드</option>
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
/** Pulsing skeleton block */
|
/** Pulsing skeleton block */
|
||||||
function Block({ className = "" }: { className?: string }) {
|
function Block({ className = "" }: { className?: string }) {
|
||||||
return <div className={`animate-pulse bg-gray-200 rounded ${className}`} />;
|
return <div className={`animate-pulse bg-gray-200 dark:bg-gray-700 rounded ${className}`} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Skeleton for a single restaurant card */
|
/** Skeleton for a single restaurant card */
|
||||||
export function RestaurantCardSkeleton() {
|
export function RestaurantCardSkeleton() {
|
||||||
return (
|
return (
|
||||||
<div className="p-3 rounded-xl border border-gray-100 shadow-sm space-y-2">
|
<div className="p-3 rounded-xl border border-gray-100 dark:border-gray-800 shadow-sm space-y-2">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<Block className="h-4 w-3/5" />
|
<Block className="h-4 w-3/5" />
|
||||||
<Block className="h-3 w-10" />
|
<Block className="h-3 w-10" />
|
||||||
@@ -64,7 +64,7 @@ export function RestaurantDetailSkeleton() {
|
|||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<Block className="h-4 w-20" />
|
<Block className="h-4 w-20" />
|
||||||
{[1, 2].map((i) => (
|
{[1, 2].map((i) => (
|
||||||
<div key={i} className="border rounded-lg p-3 space-y-2">
|
<div key={i} className="border dark:border-gray-700 rounded-lg p-3 space-y-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Block className="h-4 w-16 rounded-sm" />
|
<Block className="h-4 w-16 rounded-sm" />
|
||||||
<Block className="h-3 w-20" />
|
<Block className="h-3 w-20" />
|
||||||
|
|||||||
Reference in New Issue
Block a user