'use client'; import Link from 'next/link'; import { useEffect, useRef, useState } from 'react'; /* ═══════════════════════════════════════ SVG ICONS ═══════════════════════════════════════ */ const BookOpenIcon = () => ( ); const StarIcon = ({ filled = true }: { filled?: boolean }) => ( ); const QuoteIcon = () => ( ); const CheckIcon = () => ( ); const ArrowUpRight = () => ( ); const ChevronDown = () => ( ); /* ═══════════════════════════════════════ COUNTUP HOOK ═══════════════════════════════════════ */ function useCountUp(target: number, duration = 1600) { const [count, setCount] = useState(0); const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const obs = new IntersectionObserver( ([entry]) => { if (!entry.isIntersecting) return; obs.disconnect(); const start = performance.now(); const tick = (now: number) => { const elapsed = now - start; const progress = Math.min(elapsed / duration, 1); const ease = 1 - Math.pow(1 - progress, 3); setCount(Math.round(target * ease)); if (progress < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }, { threshold: 0.4 } ); obs.observe(el); return () => obs.disconnect(); }, [target, duration]); return { count, ref }; } /* ═══════════════════════════════════════ STAT ITEM ═══════════════════════════════════════ */ function StatItem({ value, suffix, label }: { value: number; suffix?: string; label: string }) { const { count, ref } = useCountUp(value); return (
{count} {suffix && {suffix}}

{label}

); } /* ═══════════════════════════════════════ BOOK CARD ═══════════════════════════════════════ */ interface Book { seed: string; title: string; author: string; rating: number; genre: string; year: number; note?: string; } const books: Book[] = [ { seed: 'book1', title: '파친코', author: '이민진', rating: 5, genre: '소설', year: 2024, note: '역사 속에 묻힌 삶의 무게를 느꼈다' }, { seed: 'book2', title: '어린 왕자', author: '생텍쥐페리', rating: 5, genre: '고전', year: 2023 }, { seed: 'book3', title: '원씽', author: '게리 켈러', rating: 4, genre: '자기계발', year: 2024 }, { seed: 'book4', title: '채식주의자', author: '한강', rating: 5, genre: '소설', year: 2023, note: '불편함 속의 아름다움' }, { seed: 'book5', title: '지능의 본질', author: '제프 호킨스', rating: 4, genre: '과학', year: 2024 }, { seed: 'book6', title: '82년생 김지영', author: '조남주', rating: 4, genre: '소설', year: 2022 }, { seed: 'book7', title: '노인과 바다', author: '헤밍웨이', rating: 5, genre: '고전', year: 2022 }, { seed: 'book8', title: '생각에 관한 생각', author: '다니엘 카너먼', rating: 4, genre: '심리학', year: 2023 }, ]; const genreColors: Record = { '소설': '#6B5B95', '고전': '#D4A853', '자기계발': '#4A7C59', '과학': '#2E6EA6', '심리학': '#8B4E62' }; function BookCard({ book, large = false }: { book: Book; large?: boolean }) { return (
{ (e.currentTarget as HTMLElement).style.transform = 'translateY(-6px)'; (e.currentTarget as HTMLElement).style.boxShadow = '0 20px 60px rgba(212,168,83,0.12)'; }} onMouseLeave={e => { (e.currentTarget as HTMLElement).style.transform = 'translateY(0)'; (e.currentTarget as HTMLElement).style.boxShadow = 'none'; }} > {/* cover */}
{book.title}
{/* genre badge */}
{book.genre}
{/* rating */}
{[1,2,3,4,5].map(i => )}
{/* info */}

{book.author} · {book.year}

{book.title}

{book.note &&

"{book.note}"

}
); } /* ═══════════════════════════════════════ MAIN PAGE ═══════════════════════════════════════ */ export default function ReadingPage() { const [activeGenre, setActiveGenre] = useState('전체'); const [showTop, setShowTop] = useState(false); useEffect(() => { const scroller: HTMLElement = (document.querySelector('.main-content') as HTMLElement | null) ?? document.documentElement; const onScroll = () => 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('rd-visible'); }), { threshold: 0.1, root: scroller === document.documentElement ? null : scroller } ); document.querySelectorAll('.rd-reveal').forEach(el => obs.observe(el)); return () => { scroller.removeEventListener('scroll', onScroll); obs.disconnect(); }; }, []); const genres = ['전체', '소설', '고전', '자기계발', '과학', '심리학']; const filteredBooks = activeGenre === '전체' ? books : books.filter(b => b.genre === activeGenre); const quotes = [ { text: '당신이 무엇을 읽느냐가 당신이 누구인지를 말해준다. 책은 당신이 선택한 삶의 궤적이다.', author: '파친코 — 이민진', genre: '소설' }, { text: '어른들은 숫자를 좋아한다. 새 친구 이야기를 해줄 때, 중요한 것을 절대 묻지 않는다. 그의 목소리가 어떤지, 어떤 놀이를 좋아하는지.', author: '어린 왕자 — 생텍쥐페리', genre: '고전' }, { text: '성공한 사람들은 하나에 집중하고 나머지를 내려놓는 법을 배웠다. 한 가지를 잘하면 나머지가 따라온다.', author: '원씽 — 게리 켈러', genre: '자기계발' }, { text: '빠른 생각은 직관이고 느린 생각은 이성이다. 우리는 대부분 빠른 생각이 옳다고 착각하며 살아간다.', author: '생각에 관한 생각 — 다니엘 카너먼', genre: '심리학' }, ]; const currentlyReading = { seed: 'current1', title: '도둑맞은 집중력', author: '요한 하리', genre: '자기계발', progress: 67, totalPages: 380, currentPage: 255, startDate: '2024.03.10', note: '현대 사회가 어떻게 우리의 집중력을 앗아가는지 설득력 있게 풀어냄' }; const tbr = [ { seed: 'tbr1', title: '총, 균, 쇠', author: '재레드 다이아몬드', genre: '역사', priority: '높음' }, { seed: 'tbr2', title: '코스모스', author: '칼 세이건', genre: '과학', priority: '높음' }, { seed: 'tbr3', title: '사피엔스', author: '유발 하라리', genre: '역사', priority: '중간' }, ]; const monthlyData = [ { month: '10월', books: 2 }, { month: '11월', books: 3 }, { month: '12월', books: 1 }, { month: '1월', books: 4 }, { month: '2월', books: 3 }, { month: '3월', books: 2 }, ]; const maxBooks = Math.max(...monthlyData.map(d => d.books)); return ( <>