'use client' import React, { useMemo } from 'react' interface SyllableBowProps { word: string syllables: string[] onSyllableClick?: (syllable: string, index: number) => void isDark: boolean size?: 'sm' | 'md' | 'lg' } /** * SyllableBow — Renders a word with SVG arcs under each syllable. * * Uses pyphen syllable data from the backend. * Each syllable is clickable (triggers TTS for that syllable). */ export function SyllableBow({ word, syllables, onSyllableClick, isDark, size = 'md' }: SyllableBowProps) { const fontSize = size === 'sm' ? 20 : size === 'md' ? 32 : 44 const charWidth = fontSize * 0.6 const bowHeight = size === 'sm' ? 12 : size === 'md' ? 18 : 24 const gap = 4 const layout = useMemo(() => { let x = 0 return syllables.map((syl) => { const width = syl.length * charWidth const entry = { syllable: syl, x, width } x += width + gap return entry }) }, [syllables, charWidth]) const totalWidth = layout.length > 0 ? layout[layout.length - 1].x + layout[layout.length - 1].width : 0 const svgHeight = bowHeight + 6 return (
{/* Letters */}
{layout.map((item, idx) => ( onSyllableClick?.(item.syllable, idx)} className={`font-bold cursor-pointer select-none transition-colors ${ onSyllableClick ? (isDark ? 'hover:text-blue-300' : 'hover:text-blue-600') : '' } ${isDark ? 'text-white' : 'text-slate-900'}`} style={{ fontSize: `${fontSize}px`, letterSpacing: '0.02em' }} > {item.syllable} ))}
{/* SVG Bows */} {layout.map((item, idx) => { const cx = item.x + item.width / 2 const startX = item.x + 2 const endX = item.x + item.width - 2 const controlY = svgHeight - 2 return ( ) })}
) } /** * Simple client-side syllable splitting fallback. * For accurate results, use the backend pyphen endpoint. */ export function simpleSyllableSplit(word: string): string[] { // Very basic vowel-based heuristic for display purposes const vowels = /[aeiouyäöü]/i const chars = word.split('') const syllables: string[] = [] let current = '' for (let i = 0; i < chars.length; i++) { current += chars[i] if ( vowels.test(chars[i]) && i < chars.length - 1 && current.length >= 2 ) { // Check if next char starts a new consonant cluster if (!vowels.test(chars[i + 1]) && i + 2 < chars.length && vowels.test(chars[i + 2])) { syllables.push(current) current = '' } } } if (current) syllables.push(current) return syllables.length > 0 ? syllables : [word] }