Files
rippy/rippy-windows/src/fenster/einstellungen/SprachAuswahl.tsx
T
HitonabiandClaude Fable 5.1 f5dab5d1c1 feat(v5): 5.6.0 — Vorgangs-Leiste, mehrere Filme je Disc, Filmnamen für Ordner und Dateien, Untertitel-Vorwahl je Extra, Restzeit, Hell-Modus
Die sechs Punkte des Commanders vom 02.09.2026 abends und seine Entscheide:

* Restzeit der Kompression aus HandBrakes eigener ETA-Klammer (Formatstring
  aus dem Binary 1.11.2 gelesen), KompressionStand.restS.
* Kachel zeigt nach dem Rip nur noch eine Zeile — Balken, Prozent, Ziel in
  der Kompressions-Karte und im Verlauf ("nur in der Kompressions-Karte").
* Kopfzeile bleibt beim Scrollen stehen (sticky), Sektionswahl darunter.
* Untertitel-Vorwahl je Extra ("NUR für Extras, IMMER OPTIONAL"): welche
  Untertitel-Spur beim Abspielen an ist — weiche Spur, nie eingebrannt;
  RipAuftragTitel/RohDatei.untertitelVorwahl, sprachwahl.
* Mehrere Filme je Disc: "anderer Film …" je Titel mit TMDb-Suche;
  filme.ts filmGruppen trennt am Rip-Ende in eigene Roh-Ordner, Vorgänge
  und Kompressions-Aufträge mit voller Zuordnung (erkennung.zuordnungAus).
* Roh-Ordner und Dateien tragen den Filmnamen (filme.ts rohOrdnerName,
  ablage/dateinamen.ts: Akira (1988).mkv, - Fassung n, - Extra nn).
* Hell-Modus: Einstellung design (dunkel/hell/system), data-design auf
  <html>, Token --color-tinte statt white/-Alpha-Klassen.
* Vorgangs-Leiste (Commander: "Phase 1–4 plus Komprimierung — zu einem
  machen"): gemeinsam/vorgangsleiste.ts + uebersicht/VorgangsLeiste.tsx,
  vier Stationen (Rettung als Zwischenstation), Segment-Balken in der
  aktiven Station; Kachel, Kompressions-Karte, Verlauf. PHASE-x/4-Texte weg.
* Automatik-Kasten leert sich, sobald ein Rip startet.

Beweise: 446 Tests (neu: filme, dateinamen, vorgangsleiste; erweitert:
auftrag, handbrake, automatik, ablegen), drei Typprüfungen, Klick-Beweis
33 Schritte inkl. Vorwahl, anderer Film, Vorgangs-Leiste, Restzeit,
Hell-Modus (Bilder beweise/klick/01…11).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 19:17:37 +02:00

69 lines
2.9 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.
// Die Sprach-Auswahl (5.5.0, Commander: „bei Tonspuren und Untertiteln
// können Dropdowns hin") — gewählte Sprachen als Chips in Wunschreihenfolge,
// dazu ein Dropdown zum Hinzufügen. Die erste Tonsprache ist die
// Wunschsprache (auftrag.ts sprachwahl). Leer heißt „alle".
import { SPRACHEN, sprachName, sprachlisteAus, sprachlisteText } from '../../gemeinsam/sprachen'
export function SprachAuswahl({
name,
hinweis,
wert,
aufAendern,
}: {
name: string
hinweis: string
wert: string
aufAendern: (wert: string) => void
}) {
const gewaehlt = sprachlisteAus(wert)
const frei = SPRACHEN.filter((s) => !gewaehlt.includes(s.code))
const setzen = (codes: string[]): void => aufAendern(sprachlisteText(codes))
const verschieben = (code: string, richtung: -1 | 1): void => {
const i = gewaehlt.indexOf(code)
const j = i + richtung
if (i < 0 || j < 0 || j >= gewaehlt.length) return
const neu = [...gewaehlt]
;[neu[i], neu[j]] = [neu[j], neu[i]]
setzen(neu)
}
return (
<div>
<span className="text-xs font-semibold text-dunst">{name}</span>
<span className="ml-2 text-xs text-nebel">{hinweis}</span>
<div className="mt-1 flex min-h-[38px] flex-wrap items-center gap-1.5 rounded-lg border border-tinte/12 bg-samt px-2 py-1.5">
{gewaehlt.length === 0 && <span className="font-mono text-[11px] text-nebel">alle Sprachen der Disc</span>}
{gewaehlt.map((code, i) => (
<span key={code} className="inline-flex items-center gap-1 rounded-md border border-gold/40 bg-gold/12 px-2 py-0.5 text-[11px] text-gold-hell">
<span className="font-mono text-[10px] text-gold/70">{i + 1}.</span>
<span>{sprachName(code)}</span>
<span className="font-mono text-[10px] text-nebel">{code}</span>
<button type="button" onClick={() => verschieben(code, -1)} disabled={i === 0} className="ml-1 text-nebel hover:text-schnee disabled:opacity-30" title="nach vorn">
</button>
<button type="button" onClick={() => verschieben(code, 1)} disabled={i === gewaehlt.length - 1} className="text-nebel hover:text-schnee disabled:opacity-30" title="nach hinten">
</button>
<button type="button" onClick={() => setzen(gewaehlt.filter((c) => c !== code))} className="ml-0.5 text-nebel hover:text-rot" title="entfernen">
×
</button>
</span>
))}
<select
value=""
onChange={(e) => {
if (e.target.value.length > 0) setzen([...gewaehlt, e.target.value])
}}
className="ml-auto rounded-md border border-tinte/12 bg-buehne px-2 py-1 font-mono text-[11px] text-dunst"
>
<option value="">+ Sprache </option>
{frei.map((s) => (
<option key={s.code} value={s.code}>
{s.name} ({s.code})
</option>
))}
</select>
</div>
</div>
)
}