Move IPA/syllable toggles to vocabulary tab toolbar
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 49s
CI / test-go-edu-search (push) Successful in 43s
CI / test-python-klausur (push) Failing after 2m51s
CI / test-python-agent-core (push) Successful in 34s
CI / test-nodejs-website (push) Successful in 36s

Dropdowns are now in the vocabulary table header (after processing),
not in the worksheet settings (before processing). Changing a mode
automatically reprocesses all successful pages with the new settings.
Same dropdown options as the OCR pipeline grid editor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-12 10:17:14 +02:00
parent bf9d24e108
commit 04fa01661c

View File

@@ -1620,7 +1620,90 @@ export default function VocabWorksheetPage() {
<h2 className={`text-lg font-semibold ${isDark ? 'text-white' : 'text-slate-900'}`}>
Vokabeln ({vocabulary.length})
</h2>
<div className="flex gap-2">
<div className="flex items-center gap-2">
{/* IPA mode */}
<select
value={ipaMode}
onChange={(e) => {
setIpaMode(e.target.value as typeof ipaMode)
// Reprocess pages with new mode
if (session && successfulPages.length > 0) {
const newIpa = e.target.value
setIsExtracting(true)
setExtractionStatus('Verarbeite mit neuen IPA-Einstellungen...')
const pagesToReprocess = successfulPages.map(p => p - 1)
const API_BASE = getApiBase()
;(async () => {
const allVocab: VocabularyEntry[] = []
for (const pageIndex of pagesToReprocess) {
try {
const res = await fetch(`${API_BASE}/api/v1/vocab/sessions/${session.id}/process-single-page/${pageIndex}?ipa_mode=${newIpa}&syllable_mode=${syllableMode}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ocr_prompts: ocrPrompts }),
})
if (res.ok) {
const data = await res.json()
if (data.vocabulary) allVocab.push(...data.vocabulary)
}
} catch {}
}
setVocabulary(allVocab)
setIsExtracting(false)
setExtractionStatus(`${allVocab.length} Vokabeln mit neuen Einstellungen`)
})()
}
}}
className={`px-2 py-1.5 text-xs rounded-md border ${isDark ? 'border-white/20 bg-white/10 text-white' : 'border-gray-200 bg-white text-gray-600'}`}
title="Lautschrift (IPA)"
>
<option value="none">IPA: Aus</option>
<option value="auto">IPA: Auto</option>
<option value="en">IPA: nur EN</option>
<option value="de">IPA: nur DE</option>
<option value="all">IPA: Alle</option>
</select>
{/* Syllable mode */}
<select
value={syllableMode}
onChange={(e) => {
setSyllableMode(e.target.value as typeof syllableMode)
if (session && successfulPages.length > 0) {
const newSyl = e.target.value
setIsExtracting(true)
setExtractionStatus('Verarbeite mit neuen Silben-Einstellungen...')
const pagesToReprocess = successfulPages.map(p => p - 1)
const API_BASE = getApiBase()
;(async () => {
const allVocab: VocabularyEntry[] = []
for (const pageIndex of pagesToReprocess) {
try {
const res = await fetch(`${API_BASE}/api/v1/vocab/sessions/${session.id}/process-single-page/${pageIndex}?ipa_mode=${ipaMode}&syllable_mode=${newSyl}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ocr_prompts: ocrPrompts }),
})
if (res.ok) {
const data = await res.json()
if (data.vocabulary) allVocab.push(...data.vocabulary)
}
} catch {}
}
setVocabulary(allVocab)
setIsExtracting(false)
setExtractionStatus(`${allVocab.length} Vokabeln mit neuen Einstellungen`)
})()
}
}}
className={`px-2 py-1.5 text-xs rounded-md border ${isDark ? 'border-white/20 bg-white/10 text-white' : 'border-gray-200 bg-white text-gray-600'}`}
title="Silbentrennung"
>
<option value="none">Silben: Aus</option>
<option value="auto">Silben: Original</option>
<option value="en">Silben: nur EN</option>
<option value="de">Silben: nur DE</option>
<option value="all">Silben: Alle</option>
</select>
<button onClick={saveVocabulary} className={`px-4 py-2 rounded-xl text-sm font-medium transition-colors ${isDark ? 'bg-white/10 hover:bg-white/20 text-white' : 'bg-slate-100 hover:bg-slate-200 text-slate-900'}`}>
Speichern
</button>
@@ -1960,40 +2043,7 @@ export default function VocabWorksheetPage() {
)}
</div>
{/* OCR display options */}
<div className={`p-4 rounded-xl border ${isDark ? 'bg-white/5 border-white/10' : 'bg-gray-50 border-gray-200'} space-y-3`}>
<h4 className={`text-sm font-medium ${isDark ? 'text-white/70' : 'text-slate-600'}`}>Anzeigeoptionen</h4>
<div className="flex flex-col gap-3">
<div>
<label className={`block text-sm mb-1 ${isDark ? 'text-white/60' : 'text-slate-500'}`}>Lautschrift (IPA)</label>
<select
value={ipaMode}
onChange={(e) => setIpaMode(e.target.value as typeof ipaMode)}
className={`w-full px-3 py-2 rounded-lg border text-sm ${isDark ? 'bg-white/10 border-white/20 text-white' : 'bg-white border-gray-200 text-slate-900'}`}
>
<option value="none">Aus</option>
<option value="auto">Auto (erkannte EN-Woerter)</option>
<option value="en">Nur Englisch</option>
<option value="de">Nur Deutsch</option>
<option value="all">Alle (EN + DE)</option>
</select>
</div>
<div>
<label className={`block text-sm mb-1 ${isDark ? 'text-white/60' : 'text-slate-500'}`}>Silbentrennung</label>
<select
value={syllableMode}
onChange={(e) => setSyllableMode(e.target.value as typeof syllableMode)}
className={`w-full px-3 py-2 rounded-lg border text-sm ${isDark ? 'bg-white/10 border-white/20 text-white' : 'bg-white border-gray-200 text-slate-900'}`}
>
<option value="none">Aus</option>
<option value="auto">Original (nur wo im Scan vorhanden)</option>
<option value="en">Nur Englisch</option>
<option value="de">Nur Deutsch</option>
<option value="all">Alle</option>
</select>
</div>
</div>
</div>
{/* IPA/Syllable options moved to vocabulary tab toolbar */}
<button
onClick={generateWorksheet}