Files
GerbilManager/gerbil-manager-web/src/components/Charakterbogen.tsx
Gulum 54ffb809c4 CHARAKTERBOGEN-2 (E1): Trait-Katalog in 4 Kategorien + 10 neue Traits + Warnsignale
- de.ts: traits-Array -> traitCategories (4 Kategorien: Sozialverhalten / Eignung &
  Umgang / Hobbys & Eigenarten / Wesen & Temperament); alle 15 bestehenden Keys
  erhalten (stored auf Live-Tieren); 10 neue Keys additiv; warn:true auf
  schwer-vergesellschaftbar + territorial.
- format/traits.ts: TraitEntry/TraitCategory-Interface, TRAIT_CATEGORIES-Export,
  ALL_TRAITS via flatMap, neuer isWarnTrait()-Helper.
- Charakterbogen.tsx: grouped-Rendering nach Kategorie (section + h4); warn-Chips
  mit trait-chip--warn-Klasse + trait-warn-badge.
- charakterbogen.css: .trait-category__heading + .trait-chip--warn (amber) +
  .trait-warn-badge.
- format/__tests__/traits.test.ts: 14 neue Vitest-Tests (Kategorien, Keys, warn,
  traitLabel/traitLabels).
- Gate: vitest 122/122, tsc clean, build clean, eslint clean.
2026-06-06 22:32:16 +02:00

63 lines
1.8 KiB
TypeScript

import { de } from '../strings/de'
import { ALL_TRAITS, TRAIT_CATEGORIES } from '../format/traits'
import './charakterbogen.css'
export interface CharakterbogenProps {
/** Selected trait keys. */
traits: string[]
note: string
onTraitsChange: (traits: string[]) => void
onNoteChange: (note: string) => void
}
export default function Charakterbogen({
traits,
note,
onTraitsChange,
onNoteChange,
}: CharakterbogenProps) {
const t = de.character
const selected = new Set(traits)
const toggle = (key: string) => {
const next = new Set(selected)
if (next.has(key)) next.delete(key)
else next.add(key)
// Preserve vocabulary (category) order for stable output.
onTraitsChange(ALL_TRAITS.filter((tr) => next.has(tr.key)).map((tr) => tr.key))
}
return (
<div className="charakterbogen">
{TRAIT_CATEGORIES.map((cat) => (
<section key={cat.category} className="trait-category">
<h4 className="trait-category__heading">{cat.category}</h4>
<ul className="trait-grid">
{cat.traits.map((tr) => (
<li key={tr.key}>
<label className={`trait-chip${tr.warn ? ' trait-chip--warn' : ''}`}>
<input
type="checkbox"
checked={selected.has(tr.key)}
onChange={() => toggle(tr.key)}
/>
<span>{tr.label}</span>
{tr.warn && <span className="trait-warn-badge">{t.warnLabel}</span>}
</label>
</li>
))}
</ul>
</section>
))}
<label className="field">
<span>{t.noteLabel}</span>
<textarea
value={note}
placeholder={t.notePlaceholder}
onChange={(e) => onNoteChange(e.target.value)}
/>
</label>
</div>
)
}