- 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.
63 lines
1.8 KiB
TypeScript
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>
|
|
)
|
|
}
|