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:
@@ -50,13 +50,13 @@ export default function RestaurantDetail({
|
||||
<div className="p-4 space-y-4">
|
||||
<div className="flex justify-between items-start">
|
||||
<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() && (
|
||||
<button
|
||||
onClick={handleToggleFavorite}
|
||||
disabled={favLoading}
|
||||
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 ? "찜 해제" : "찜하기"}
|
||||
>
|
||||
@@ -64,19 +64,19 @@ export default function RestaurantDetail({
|
||||
</button>
|
||||
)}
|
||||
{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>
|
||||
)}
|
||||
{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>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
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
|
||||
</button>
|
||||
@@ -84,39 +84,39 @@ export default function RestaurantDetail({
|
||||
|
||||
{restaurant.rating && (
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<span className="text-yellow-500">{"★".repeat(Math.round(restaurant.rating))}</span>
|
||||
<span className="font-medium">{restaurant.rating}</span>
|
||||
<span className="text-yellow-500 dark:text-yellow-400">{"★".repeat(Math.round(restaurant.rating))}</span>
|
||||
<span className="font-medium dark:text-gray-200">{restaurant.rating}</span>
|
||||
{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 className="space-y-1 text-sm">
|
||||
<div className="space-y-1 text-sm dark:text-gray-300">
|
||||
{restaurant.cuisine_type && (
|
||||
<p>
|
||||
<span className="text-gray-500">종류:</span> {restaurant.cuisine_type}
|
||||
<span className="text-gray-500 dark:text-gray-400">종류:</span> {restaurant.cuisine_type}
|
||||
</p>
|
||||
)}
|
||||
{restaurant.address && (
|
||||
<p>
|
||||
<span className="text-gray-500">주소:</span> {restaurant.address}
|
||||
<span className="text-gray-500 dark:text-gray-400">주소:</span> {restaurant.address}
|
||||
</p>
|
||||
)}
|
||||
{restaurant.region && (
|
||||
<p>
|
||||
<span className="text-gray-500">지역:</span> {restaurant.region}
|
||||
<span className="text-gray-500 dark:text-gray-400">지역:</span> {restaurant.region}
|
||||
</p>
|
||||
)}
|
||||
{restaurant.price_range && (
|
||||
<p>
|
||||
<span className="text-gray-500">가격대:</span> {restaurant.price_range}
|
||||
<span className="text-gray-500 dark:text-gray-400">가격대:</span> {restaurant.price_range}
|
||||
</p>
|
||||
)}
|
||||
{restaurant.phone && (
|
||||
<p>
|
||||
<span className="text-gray-500">전화:</span>{" "}
|
||||
<a href={`tel:${restaurant.phone}`} className="text-orange-600 hover:underline">
|
||||
<span className="text-gray-500 dark:text-gray-400">전화:</span>{" "}
|
||||
<a href={`tel:${restaurant.phone}`} className="text-orange-600 dark:text-orange-400 hover:underline">
|
||||
{restaurant.phone}
|
||||
</a>
|
||||
</p>
|
||||
@@ -127,7 +127,7 @@ export default function RestaurantDetail({
|
||||
href={`https://www.google.com/maps/place/?q=place_id:${restaurant.google_place_id}`}
|
||||
target="_blank"
|
||||
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에서 보기
|
||||
</a>
|
||||
@@ -136,37 +136,37 @@ export default function RestaurantDetail({
|
||||
</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 ? (
|
||||
<div className="space-y-3 animate-pulse">
|
||||
{[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="h-4 w-16 bg-gray-200 rounded-sm" />
|
||||
<div className="h-3 w-20 bg-gray-200 rounded" />
|
||||
<div className="h-4 w-16 bg-gray-200 dark:bg-gray-700 rounded-sm" />
|
||||
<div className="h-3 w-20 bg-gray-200 dark:bg-gray-700 rounded" />
|
||||
</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="h-5 w-14 bg-gray-200 rounded" />
|
||||
<div className="h-5 w-16 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 dark:bg-gray-700 rounded" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : 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">
|
||||
{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">
|
||||
{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}
|
||||
</span>
|
||||
)}
|
||||
{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)}
|
||||
</span>
|
||||
)}
|
||||
@@ -175,7 +175,7 @@ export default function RestaurantDetail({
|
||||
href={v.url}
|
||||
target="_blank"
|
||||
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}
|
||||
</a>
|
||||
@@ -184,7 +184,7 @@ export default function RestaurantDetail({
|
||||
{v.foods_mentioned.map((f, i) => (
|
||||
<span
|
||||
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}
|
||||
</span>
|
||||
@@ -192,12 +192,12 @@ export default function RestaurantDetail({
|
||||
</div>
|
||||
)}
|
||||
{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}
|
||||
</p>
|
||||
)}
|
||||
{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(", ")}
|
||||
</p>
|
||||
)}
|
||||
@@ -208,11 +208,11 @@ export default function RestaurantDetail({
|
||||
</div>
|
||||
|
||||
{videos.length > 0 && (
|
||||
<div className="bg-gray-50 rounded-lg px-4 py-3 text-center space-y-1">
|
||||
<p className="text-xs text-gray-500">
|
||||
<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 dark:text-gray-400">
|
||||
더 자세한 내용은 영상에서 확인하실 수 있습니다.
|
||||
</p>
|
||||
<p className="text-xs text-gray-400">
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500">
|
||||
맛집을 소개해주신 크리에이터를 구독과 좋아요로 응원해주세요!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user