Files
lernbar/src/app/(angemeldet)/handouts/Suchfeld.tsx
T
Florian WildeandClaude Opus 5 1af5613e9b Baustein 2: Inhalte einlesen und pruefen, Handouts, Suche, Glossar
Die fachlichen Inhalte liegen als Dateien unter content/ und werden beim
Start eingelesen, geprueft und in den Speicher geladen.

- Inhaltslader mit Zod-Schemata und Querverweispruefung
- Fehlermeldungen nennen Datei und Zeile, gesammelt statt beim ersten
  Fehler geworfen; die Anwendung startet bei Fehlern nicht
- npm run inhalte:pruefen prueft ohne Start
- Handout-Ansicht mit festem Aufbau, Uebersicht nach Themenbloecken
- Volltextsuche mit Gewichtung und Trefferausschnitt
- Gelesen-Markierung je Handout
- Glossar mit Suche und automatischer Verlinkung in den Handouts
- Beispielinhalte: 4 Wochen, 12 Handouts, 24 Merkkarten, 4 Aufgaben,
  4 Checklisten, 2 Lernzielkontrollen, 24 Glossareintraege
- rahmenplan.yaml aus FIAusbV 2020 und KMK-Rahmenlehrplan, mit Fundstellen
- gray-matter entfernt, YAML-Kopf wird selbst herausgeloest
- npm run screenshots nimmt die Bilder fuer die Anleitung auf
- 39 neue Tests, insgesamt 68

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 07:56:38 +02:00

52 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useRouter } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';
/**
* Suchfeld für die Handouts. Sucht beim Tippen mit kurzer Verzögerung, damit
* nicht bei jedem Buchstaben eine Anfrage losgeht, und funktioniert auch ohne
* JavaScript – dann eben erst beim Absenden.
*/
export function Suchfeld({ anfangswert }: { anfangswert: string }) {
const [wert, setzeWert] = useState(anfangswert);
const router = useRouter();
const erstesMal = useRef(true);
useEffect(() => {
if (erstesMal.current) {
erstesMal.current = false;
return;
}
const zeitgeber = setTimeout(() => {
const ziel = wert.trim() ? `/handouts?suche=${encodeURIComponent(wert.trim())}` : '/handouts';
router.replace(ziel, { scroll: false });
}, 250);
return () => clearTimeout(zeitgeber);
}, [wert, router]);
return (
<form action="/handouts" method="get" role="search" className="nicht-drucken">
<label htmlFor="suche" className="nur-lesehilfe">
Handouts durchsuchen
</label>
<div className="reihe" style={{ gap: '0.5rem', flexWrap: 'nowrap' }}>
<input
id="suche"
name="suche"
type="search"
placeholder="Suchen – z. B. Subnetting, SMART, Vererbung"
value={wert}
onChange={(e) => setzeWert(e.target.value)}
autoComplete="off"
/>
<button type="submit" className="knopf knopf-zweit" style={{ flexShrink: 0 }}>
Suchen
</button>
</div>
</form>
);
}