/* Sentence breakdown view — multi-granularity decomposition 昨日友達と渋谷で美味しいラーメンを食べました The most domain-specific surface in the batch. Sentence as a path through the knowledge graph; each granularity exposes a layer of that path. */ const SentenceBreakdown = () => { const [granularity, setGranularity] = React.useState("morpheme"); const [selectedTok, setSelectedTok] = React.useState(7); // Granularity layers, top-to-bottom: // 1) bunsetsu — phrase chunks // 2) morpheme — MeCab/Sudachi tokens // 3) kanji — kanji components // // Each token carries indices into all three layers. const tokens = [ { i:0, jp:"昨日", kana:"きのう", roma:"kinō", pos:"N · time", gloss:"yesterday", kanji:["昨","日"], bunsetsu:0, lemma:"昨日", freq: 312, jlpt:"N5", state:"mastered" }, { i:1, jp:"友達", kana:"ともだち", roma:"tomodachi", pos:"N", gloss:"friend", kanji:["友","達"], bunsetsu:1, lemma:"友達", freq: 540, jlpt:"N5", state:"mastered" }, { i:2, jp:"と", kana:"と", roma:"to", pos:"PRT · with", gloss:"with", kanji:[], bunsetsu:1, lemma:"と", freq: 18, jlpt:"N5", state:"mastered" }, { i:3, jp:"渋谷", kana:"しぶや", roma:"Shibuya", pos:"N · place", gloss:"Shibuya", kanji:["渋","谷"], bunsetsu:2, lemma:"渋谷", freq:8420, jlpt:"—", state:"learning" }, { i:4, jp:"で", kana:"で", roma:"de", pos:"PRT · loc.", gloss:"at, in", kanji:[], bunsetsu:2, lemma:"で", freq: 5, jlpt:"N5", state:"mastered" }, { i:5, jp:"美味しい", kana:"おいしい", roma:"oishii", pos:"i-adj", gloss:"delicious", kanji:["美","味"], bunsetsu:3, lemma:"美味しい", freq:2104, jlpt:"N5", state:"mastered" }, { i:6, jp:"ラーメン", kana:"らーめん", roma:"rāmen", pos:"N · loanword", gloss:"ramen", kanji:[], bunsetsu:3, lemma:"ラーメン", freq:1840, jlpt:"—", state:"mastered" }, { i:7, jp:"を", kana:"を", roma:"o", pos:"PRT · obj.", gloss:"(direct object)", kanji:[], bunsetsu:3, lemma:"を", freq: 3, jlpt:"N5", state:"frontier" }, // currently selected { i:8, jp:"食べました", kana:"たべました", roma:"tabemashita", pos:"V · past·polite", gloss:"ate", kanji:["食"], bunsetsu:4, lemma:"食べる", freq: 87, jlpt:"N5", state:"mastered" }, ]; // Bunsetsu groupings const bunsetsuGroups = [ { id:0, label:"adverbial", role:"when?", tokens:[0], gloss:"yesterday" }, { id:1, label:"subject(-ish)", role:"who-with?", tokens:[1,2], gloss:"with my friend" }, { id:2, label:"locative", role:"where?", tokens:[3,4], gloss:"in Shibuya" }, { id:3, label:"object", role:"what?", tokens:[5,6,7], gloss:"delicious ramen (obj.)" }, { id:4, label:"predicate", role:"verb", tokens:[8], gloss:"ate (past polite)" }, ]; // Kanji components for each token's kanji const kanjiInfo = { "昨":{r:"日 day", strokes:9, jlpt:"N4"}, "日":{r:"日 day", strokes:4, jlpt:"N5"}, "友":{r:"又 again", strokes:4, jlpt:"N4"}, "達":{r:"⻌ road", strokes:12, jlpt:"N3"}, "渋":{r:"氵water", strokes:11, jlpt:"—"}, "谷":{r:"谷 valley", strokes:7, jlpt:"N3"}, "美":{r:"羊 sheep", strokes:9, jlpt:"N3"}, "味":{r:"口 mouth", strokes:8, jlpt:"N4"}, "食":{r:"食 eat", strokes:9, jlpt:"N5"}, }; const sel = tokens[selectedTok]; return (