/** * 가요 다방 — 턴테이블 하나 + 도넛판 캐러셀. * * 판을 누르면 톤암이 내려오고 판이 돈다. 가사를 못 싣는 제약(DB_Guide: 원문 전재 금지)을 * 숨기지 않고 라벨 아래 각인으로 드러낸다 — 제약이 곧 이 아이템의 인상이다. */ import {useState} from 'react'; import {SectionBody, SectionFrame} from '../../primitives'; import type {SectionRenderProps} from '../../types'; import {parseSectionData, type SongItem} from '../../dataSpec'; import { CarouselNav, ParseError, PasteHint, RETRO_BODY, RETRO_SIGN, SourceLine, useCarousel, } from '../retro/common'; import '../retro/retro.css'; const FALLBACK_LABEL = '#d4551f'; export function SongsTurntable(props: SectionRenderProps) { const {section, isSelected, onSelect, template} = props; const parsed = parseSectionData(section.type, section.data); const [playing, setPlaying] = useState(0); const {ref, scrollBy} = useCarousel(); // 항목이 줄어 인덱스가 범위를 벗어나도 첫 곡으로 떨어진다 — 빈 화면을 만들지 않는다. const current = parsed.items[playing] ?? parsed.items[0]; return (

33⅓ RPM

{parsed.title || section.name}

{(parsed.subtitle || section.description) && (

{parsed.subtitle || section.description}

)}
{parsed.error ? ( ) : !current ? ( ) : ( <>
{/* 턴테이블 */}
{/* 톤암 — 곡이 얹혀 있으니 항상 내려와 있다. */}
{/* 지금 도는 곡 */}

A면 · {playing + 1} / {parsed.items.length}

{current.title}

{[ current.artist, current.year ? String(current.year) : undefined, current.lyricist || current.composer ? `작사 ${current.lyricist ?? '미상'} / 작곡 ${current.composer ?? '미상'}` : undefined, current.label, ] .filter(Boolean) .join(' · ')}

{current.story && (

{current.story}

)} {current.connection && (

{current.connection}

)} ◎ 가사 대신 이야기 — 원문은 싣지 않습니다
{/* 판 고르기 */}
{parsed.items.map((song, index) => ( ))}
{parsed.items.length > 3 && ( scrollBy(-1)} onNext={() => scrollBy(1)} tone="dark" label="곡" /> )}
)} ); }