feat: Statement Creation + objects_created workflow + native language

ObjectCreation:
- Filter: only shows pictures where objects_created=false
- New '✓ Alle Objekte erstellt' button (enabled when ≥1 object linked)
  → PATCHes picture with objects_created:true + auto timestamp
  → removes picture from list immediately

ContentHub:
- Statement Creation tile enabled (was: grayed out)

api.js:
- getUserLang() → reads native_lang from stored user (default 'de')
- langField(suffix) → returns e.g. 'sentence_de' based on user lang
- login() stores native_lang in localStorage user object

StatementCreation (/content/statements):
- Shows pictures where objects_created=true
- Left 1/5: clickable objects list → highlights selections on canvas
- Center 2/5: image with canvas, draws selected object's polygons in color
- Right 2/5: PairsPanel
  - answer_type dropdown + 'Add new pair' toggle
  - PairForm: Question / Positive / Negative textareas
  - HighlightedTextarea: overlay technique, auto-detects words from DB
    (debounced GET /words?titel_de=, colored mark via rgba background)
  - 'Als Wort erstellen' button when text is selected
  - 'Save pair' → creates question + 2 separate statements + pair
    → sentences stored with {{uuid}} placeholders for matched words
    → pair linked to selected object
  - List of existing pairs with question/positive/negative preview

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 19:23:50 +02:00
parent e1d5390386
commit c92191db63
5 changed files with 662 additions and 6 deletions

View File

@@ -24,7 +24,9 @@ export async function login(email, password) {
}
const data = await res.json();
localStorage.setItem('cmt_token', data.token);
localStorage.setItem('cmt_user', JSON.stringify(data.user));
// Merge native_lang (may come top-level or inside user object)
const userWithLang = { ...data.user, native_lang: data.user.native_lang || data.native_lang || 'de' };
localStorage.setItem('cmt_user', JSON.stringify(userWithLang));
return data;
}
@@ -32,6 +34,20 @@ export function getUser() {
try { return JSON.parse(localStorage.getItem('cmt_user')); } catch { return null; }
}
/** Returns ISO 639-1 code of the logged-in user's native language (default 'de') */
export function getUserLang() {
try {
const user = JSON.parse(localStorage.getItem('cmt_user'));
return user?.native_lang || 'de';
} catch { return 'de'; }
}
/** Map lang code → sentence field suffix for questions/statements */
export function langField(suffix) {
const lang = getUserLang();
return `${suffix}_${lang}`; // e.g. 'sentence_de', 'titel_de'
}
export async function apiFetch(path, options = {}) {
const token = getToken();
const res = await fetch(`${API_URL}${path}`, {