'use client'; import Link from 'next/link'; import { useState, useEffect, useRef } from 'react'; /* ═══════════════════════════════════════════ DATA ═══════════════════════════════════════════ */ type Category = '전체' | '의류' | '액세서리' | '라이프'; const products = [ { id: 1, name: 'Linen Over Shirt', sub: '린넨 오버셔츠', price: 89000, tag: '신상', cat: '의류' as Category, seed: 'mel01', badge: 'NEW' }, { id: 2, name: 'Capsule Tote Bag', sub: '카프슐 토트백', price: 145000, tag: '베스트', cat: '액세서리' as Category, seed: 'mel02' }, { id: 3, name: 'Wide Crop Pants', sub: '와이드 크롭 팬츠', price: 97000, cat: '의류' as Category, seed: 'mel03' }, { id: 4, name: 'Knit Cardigan', sub: '니트 카디건', price: 125000, cat: '의류' as Category, seed: 'mel04', badge: 'BEST' }, { id: 5, name: 'Ceramic Mug Set', sub: '세라믹 머그 세트', price: 58000, cat: '라이프' as Category, seed: 'mel05' }, { id: 6, name: 'Brass Ring Set', sub: '브라스 링 세트', price: 42000, cat: '액세서리' as Category, seed: 'mel06' }, { id: 7, name: 'Minimal Slip Dress', sub: '미니멀 슬립 드레스', price: 112000, cat: '의류' as Category, seed: 'mel07', badge: 'NEW' }, { id: 8, name: 'Linen Cushion Cover', sub: '린넨 쿠션 커버', price: 35000, cat: '라이프' as Category, seed: 'mel08' }, ]; const reviews = [ { name: '김민서', location: '서울', rating: 5, text: '소재부터 다릅니다. 린넨 셔츠 착용감이 정말 좋아요. 세탁 후에도 형태 유지가 잘 돼서 재구매할 것 같아요.', product: 'Linen Over Shirt' }, { name: '이하은', location: '부산', rating: 5, text: '미니멀한 디자인인데 어디에나 잘 어울립니다. 포장도 너무 예쁘게 해주셔서 선물 받은 기분이었어요.', product: 'Capsule Tote Bag' }, { name: '박지수', location: '대구', rating: 5, text: '세라믹 머그 세트 배송이 빠르고 파손 없이 왔어요. 질감이 정말 고급스러워서 매일 아침 쓰고 있어요.', product: 'Ceramic Mug Set' }, ]; const storyImages = [ { seed: 'story1', aspect: '3/4' }, { seed: 'story2', aspect: '1/1' }, { seed: 'story3', aspect: '3/4' }, ]; /* ═══════════════════════════════════════════ CONSTANTS ═══════════════════════════════════════════ */ const BANNER_H = 40; const NAV_H = 64; const BEIGE = '#FAFAF8'; const DARK = '#1A1A1A'; const TAUPE = '#8B7355'; const MUTED = '#B5A898'; const SOFT = '#F3EFE9'; const WARM = '#C4A882'; /* ═══════════════════════════════════════════ SVG ICONS ═══════════════════════════════════════════ */ const CartIcon = () => ( ); const HeartIcon = ({ filled = false }: { filled?: boolean }) => ( ); const SearchIcon = () => ( ); const StarFull = () => ( ); /* ═══════════════════════════════════════════ PRODUCT CARD ═══════════════════════════════════════════ */ function ProductCard({ product, large = false }: { product: typeof products[0]; large?: boolean }) { const [liked, setLiked] = useState(false); const [hovered, setHovered] = useState(false); return (
setHovered(true)} onMouseLeave={() => setHovered(false)} > {/* Image */}
{product.name} {/* Overlay */}
{/* Badge */} {product.badge && (
{product.badge}
)} {/* Like */} {/* Quick add */}
{/* Info */}

{product.cat}

{product.name}

{product.sub}

{product.price.toLocaleString()}원

); } /* ═══════════════════════════════════════════ MAIN PAGE ═══════════════════════════════════════════ */ export default function ShoppingPage() { const [activeCategory, setActiveCategory] = useState('전체'); const [scrolled, setScrolled] = useState(false); const [showTop, setShowTop] = useState(false); const [cartCount, setCartCount] = useState(0); useEffect(() => { const scroller: HTMLElement = (document.querySelector('.main-content') as HTMLElement | null) ?? document.documentElement; const onScroll = () => { setScrolled(scroller.scrollTop > 60); setShowTop(scroller.scrollTop > 400); }; scroller.addEventListener('scroll', onScroll, { passive: true }); const obs = new IntersectionObserver( (entries) => entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('ms-visible'); }), { threshold: 0.08, root: scroller === document.documentElement ? null : scroller } ); document.querySelectorAll('.ms-reveal').forEach(el => obs.observe(el)); return () => { scroller.removeEventListener('scroll', onScroll); obs.disconnect(); }; }, []); const categories: (Category | '전체')[] = ['전체', '의류', '액세서리', '라이프']; const filtered = activeCategory === '전체' ? products : products.filter(p => p.cat === activeCategory); return (
{/* ── 폰트 + CSS ── */}