diff --git a/static/index.html b/static/index.html index 79d4af5..d81fd02 100644 --- a/static/index.html +++ b/static/index.html @@ -201,6 +201,11 @@ } .btn.small { padding: 5px 10px; font-size: 12px; } .def-actions { display: flex; gap: 8px; } + .suggest { + border: 1px dashed var(--line); border-radius: 10px; + padding: 10px 12px 12px; margin-bottom: 14px; + } + .suggest .res-label { margin-top: 0; color: var(--accent); } .chip { font-size: 13px; background: var(--panel-2); border: 1px solid var(--line); color: var(--ink); padding: 5px 10px; border-radius: 999px; cursor: pointer; @@ -266,6 +271,7 @@ Double-click any word to look it up on the right.">
+
@@ -516,10 +522,54 @@ function buildReadout(){ schemeReadout.innerHTML = parts.join('    '); } -editor.addEventListener('input', ()=>{ render(); analyzeSoon(); }); +editor.addEventListener('input', ()=>{ render(); analyzeSoon(); refreshSuggestSoon(); }); editor.addEventListener('scroll', ()=>{ highlight.scrollTop = editor.scrollTop; highlight.scrollLeft = editor.scrollLeft; }); -editor.addEventListener('keyup', buildReadout); -editor.addEventListener('click', buildReadout); +editor.addEventListener('keyup', ()=>{ buildReadout(); refreshSuggestSoon(); }); +editor.addEventListener('click', ()=>{ buildReadout(); refreshSuggestSoon(); }); + +/* ============================================================ + CARET-FOLLOWING SUGGESTIONS — the panel always offers rhymes + for the ending of the line you're writing. +============================================================ */ +const suggestBox = document.getElementById('suggestBox'); +const suggestCache = new Map(); +let lastSuggestWord = null; + +function caretEndWord(){ + const line = editor.value.split('\n')[caretLine()] || ''; + if(/^\s*[#([]/.test(line)) return null; // annotation lines + const m = line.match(/([A-Za-z][A-Za-z']*)[^A-Za-z']*$/); + return m ? m[1].toLowerCase() : null; +} + +async function refreshSuggest(){ + const w = caretEndWord(); + if(w === lastSuggestWord) return; + lastSuggestWord = w; + if(!w){ suggestBox.innerHTML = ''; return; } + let data = suggestCache.get(w); + if(!data){ + try{ + const r = await fetch(`/api/lookup?word=${encodeURIComponent(w)}&mode=rhyme&limit=12`); + data = await r.json(); + suggestCache.set(w, data); + }catch(e){ return; } + } + if(lastSuggestWord !== w) return; // caret moved on while we fetched + const perfect = (data.words || []).slice(0, 9).map(d=>d.word); + const near = (data.near || []).slice(0, 5).map(d=>d.word); + if(!perfect.length && !near.length){ suggestBox.innerHTML = ''; return; } + suggestBox.innerHTML = + `
rhymes for this line — “${esc(w)}”
` + + chipHtml(perfect) + (near.length ? chipHtml(near, 'near') : '') + '
'; + suggestBox.querySelectorAll('.chip').forEach(c=>{ + c.addEventListener('click', ()=>{ + document.getElementById('lookupInput').value = c.dataset.w; + doLookup(); + }); + }); +} +const refreshSuggestSoon = debounce(refreshSuggest, 350); /* ---------- double-click a word -> look it up ---------- */ editor.addEventListener('dblclick', ()=>{