From 21546f3a660bf9d7fde7bb3774ac7ece24485133 Mon Sep 17 00:00:00 2001 From: junyi04 Date: Sat, 20 Dec 2025 16:48:01 +0900 Subject: [PATCH 1/3] feat: testing --- app/about/loading.tsx | 10 + app/about/page.tsx | 16 +- app/dashboard/error.tsx | 26 + app/dashboard/loading.tsx | 30 + app/dashboard/page.tsx | 38 +- app/detail/[id]/error.tsx | 36 + app/detail/[id]/loading.tsx | 23 + app/detail/[id]/page.tsx | 85 +- app/detail/layout.tsx | 14 + app/layout.tsx | 45 +- app/page.tsx | 24 +- components/Footer.tsx | 79 ++ components/Header.tsx | 73 +- components/about/BrandStorySection.tsx | 80 +- components/about/CTASection.tsx | 44 +- .../about/CocktailCollectionSection.tsx | 67 ++ components/about/HeroSection.tsx | 117 ++- components/about/MixologySection.tsx | 85 +- components/dashboard/CategoryFilter.tsx | 35 + components/dashboard/ChartSection.tsx | 79 ++ components/dashboard/CocktailGrid.tsx | 79 ++ components/dashboard/CocktailMapping.tsx | 27 - components/dashboard/SearchBar.tsx | 46 +- components/dashboard/StatCard.tsx | 15 - components/dashboard/StatsCards.tsx | 57 ++ components/detail/CocktailHero.tsx | 123 +++ components/detail/HeaderCocktail.tsx | 22 - components/detail/ImageCocktail.tsx | 11 - components/detail/IngredientCocktail.tsx | 28 - components/detail/InstructionCocktail.tsx | 17 - components/detail/RecipeSection.tsx | 64 ++ components/detail/RelatedCocktails.tsx | 61 ++ lib/cocktails.json | 756 +++++------------- types/cocktails.ts | 3 +- 34 files changed, 1365 insertions(+), 950 deletions(-) create mode 100644 app/about/loading.tsx create mode 100644 app/dashboard/error.tsx create mode 100644 app/dashboard/loading.tsx create mode 100644 app/detail/[id]/error.tsx create mode 100644 app/detail/[id]/loading.tsx create mode 100644 app/detail/layout.tsx create mode 100644 components/Footer.tsx create mode 100644 components/about/CocktailCollectionSection.tsx create mode 100644 components/dashboard/CategoryFilter.tsx create mode 100644 components/dashboard/ChartSection.tsx create mode 100644 components/dashboard/CocktailGrid.tsx delete mode 100644 components/dashboard/CocktailMapping.tsx delete mode 100644 components/dashboard/StatCard.tsx create mode 100644 components/dashboard/StatsCards.tsx create mode 100644 components/detail/CocktailHero.tsx delete mode 100644 components/detail/HeaderCocktail.tsx delete mode 100644 components/detail/ImageCocktail.tsx delete mode 100644 components/detail/IngredientCocktail.tsx delete mode 100644 components/detail/InstructionCocktail.tsx create mode 100644 components/detail/RecipeSection.tsx create mode 100644 components/detail/RelatedCocktails.tsx diff --git a/app/about/loading.tsx b/app/about/loading.tsx new file mode 100644 index 0000000..6f415c8 --- /dev/null +++ b/app/about/loading.tsx @@ -0,0 +1,10 @@ +export default function Loading() { + return ( +
+
+
+

로딩 중...

+
+
+ ); +} \ No newline at end of file diff --git a/app/about/page.tsx b/app/about/page.tsx index 06f89ad..7d3a723 100644 --- a/app/about/page.tsx +++ b/app/about/page.tsx @@ -1,15 +1,17 @@ -import { HeroSection } from '@/components/about/HeroSection'; -import { MixologySection } from '@/components/about/MixologySection'; -import { BrandStorySection } from '@/components/about/BrandStorySection'; -import { CTASection } from '@/components/about/CTASection'; +import type { Metadata } from "next"; +import BrandStorySection from "@/components/about/BrandStorySection"; +import MixologySection from "@/components/about/MixologySection"; + +export const metadata: Metadata = { + title: "Obar - About Us", + description: "Learn about Obar's story, values, and commitment to premium cocktails.", +}; export default function AboutPage() { return ( <> - - - + ); } \ No newline at end of file diff --git a/app/dashboard/error.tsx b/app/dashboard/error.tsx new file mode 100644 index 0000000..52c07f3 --- /dev/null +++ b/app/dashboard/error.tsx @@ -0,0 +1,26 @@ +"use client"; + +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + return ( +
+
+

문제가 발생했습니다

+

+ {error.message || "Dashboard를 불러올 수 없습니다."} +

+ +
+
+ ); +} \ No newline at end of file diff --git a/app/dashboard/loading.tsx b/app/dashboard/loading.tsx new file mode 100644 index 0000000..e114f7e --- /dev/null +++ b/app/dashboard/loading.tsx @@ -0,0 +1,30 @@ +export default function Loading() { + return ( +
+
+
+
+
+ +
+ {[...Array(4)].map((_, i) => ( +
+ ))} +
+ +
+ {[...Array(2)].map((_, i) => ( +
+ ))} +
+ +
+ {[...Array(8)].map((_, i) => ( +
+ ))} +
+
+
+
+ ); +} \ No newline at end of file diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index 2aae39f..41263b3 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,22 +1,30 @@ -import { StatCard } from "@/components/dashboard/StatCard"; -import { SeachBar } from "@/components/dashboard/SearchBar"; -import { CocktailMapping } from "@/components/dashboard/CocktailMapping"; +import type { Metadata } from "next"; +import SearchBar from "@/components/dashboard/SearchBar"; +import CategoryFilter from "@/components/dashboard/CategoryFilter"; +import StatsCards from "@/components/dashboard/StatsCards"; +import ChartSection from "@/components/dashboard/ChartSection"; +import CocktailGrid from "@/components/dashboard/CocktailGrid"; +export const metadata: Metadata = { + title: "Obar - Cocktail Dashboard", + description: "Explore our collection of premium cocktails and discover your favorite.", +}; export default function DashboardPage() { return ( -
-

Welcome to the OBar!

+
+
+

Cocktail Dashboard

+

+ Explore our collection of premium cocktails and discover your favorite +

- {/* 통계 카드 영역 */} - - - {/* 검색창 영역 */} - - - {/* 칵테일 리스트 */} - - -
+ + + + + + + ); } \ No newline at end of file diff --git a/app/detail/[id]/error.tsx b/app/detail/[id]/error.tsx new file mode 100644 index 0000000..bd1bd2c --- /dev/null +++ b/app/detail/[id]/error.tsx @@ -0,0 +1,36 @@ +"use client"; + +import Link from "next/link"; + +export default function Error({ + error, + reset, +}: { + error: Error & { digest?: string }; + reset: () => void; +}) { + return ( +
+
+

칵테일을 찾을 수 없습니다

+

+ {error.message || "요청하신 칵테일 정보를 불러올 수 없습니다."} +

+
+ + + 대시보드로 돌아가기 + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/detail/[id]/loading.tsx b/app/detail/[id]/loading.tsx new file mode 100644 index 0000000..8e8f9fb --- /dev/null +++ b/app/detail/[id]/loading.tsx @@ -0,0 +1,23 @@ +export default function Loading() { + return ( +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/app/detail/[id]/page.tsx b/app/detail/[id]/page.tsx index 9239846..21e1190 100644 --- a/app/detail/[id]/page.tsx +++ b/app/detail/[id]/page.tsx @@ -1,41 +1,58 @@ -'use client'; - -import { usePathname } from 'next/navigation'; -import cocktailData from "@/lib/cocktails.json"; -import { useEffect, useState } from 'react'; -import { Cocktail } from '@/types/cocktails'; -import { ImageCocktail } from '@/components/detail/ImageCocktail'; -import { HeaderCocktail } from '@/components/detail/HeaderCocktail'; -import { IngredientCocktail } from '@/components/detail/IngredientCocktail'; -import { InstructionCocktail } from '@/components/detail/InstructionCocktail'; - -export default function DetailPage() { - const pathname = usePathname(); - const id = pathname?.split('/').pop(); - const [cocktail, setCocktail] = useState(null); - - useEffect(() => { - if (id) { - const foundCocktail = cocktailData.find((c) => c.id === Number(id)); - setCocktail(foundCocktail || null); - } - }, [id]); +import type { Metadata } from "next"; +import { notFound } from "next/navigation"; +import cocktailsData from "@/lib/cocktails.json"; +import CocktailHero from "@/components/detail/CocktailHero"; +import RecipeSection from "@/components/detail/RecipeSection"; +import RelatedCocktails from "@/components/detail/RelatedCocktails"; + +interface DetailPageProps { + params: { + id: string; + }; +} + +export async function generateMetadata({ + params, +}: DetailPageProps): Promise { + const cocktail = cocktailsData.cocktails.find((c) => c.id === params.id); if (!cocktail) { - return

Loading...

; + return { + title: "Cocktail Not Found", + }; + } + + return { + title: `${cocktail.name} - Obar`, + description: cocktail.description, + openGraph: { + title: cocktail.name, + description: cocktail.description, + type: "website", + }, + }; +} + +export function generateStaticParams() { + return cocktailsData.cocktails.map((cocktail) => ({ + id: cocktail.id, + })); +} + +export default function DetailPage({ params }: DetailPageProps) { + const cocktail = cocktailsData.cocktails.find((c) => c.id === params.id); + + if (!cocktail) { + notFound(); } return ( -
- {/* 상단 */} -
- - +
+
+ + +
- - {/* 하단 */} - - -
+ ); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/app/detail/layout.tsx b/app/detail/layout.tsx new file mode 100644 index 0000000..9494f74 --- /dev/null +++ b/app/detail/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Obar - Cocktail Details", + description: "Explore detailed information about our premium cocktails.", +}; + +export default function DetailLayout({ + children, +}: { + children: React.ReactNode; +}) { + return <>{children}; +} \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index 5ed959e..570e27d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,7 +1,8 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; -import { Header } from "@/components/Header"; +import Header from "@/components/Header"; +import Footer from "@/components/Footer"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -14,36 +15,32 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Obar - Premium Cocktail Experience", + description: "Discover premium cocktails at Obar. OH, bar. Over the ordinary.", + keywords: "cocktail, bar, mixology, premium drinks", + authors: [{ name: "Obar" }], + openGraph: { + title: "Obar - Premium Cocktail Experience", + description: "Discover premium cocktails at Obar", + type: "website", + url: "https://obar.com", + }, }; -interface RootLayoutProps { - children: React.ReactNode; - about: React.ReactNode; - dashboard: React.ReactNode; - detail: React.ReactNode; -} export default function RootLayout({ children, - about, - dashboard, - detail, -}: RootLayoutProps) { +}: { + children: React.ReactNode; +}) { return ( - + -
-
- {children} - -
{about}
-
{dashboard}
-
{detail}
-
+
+
{children}
+