FEAT-14b: trait vocabulary (de.character), Gerbil/sale-ad types, Charakterbogen component
This commit is contained in:
62
gerbil-manager-web/src/components/Charakterbogen.tsx
Normal file
62
gerbil-manager-web/src/components/Charakterbogen.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { de } from '../strings/de'
|
||||
import { ALL_TRAITS } from '../format/traits'
|
||||
import './charakterbogen.css'
|
||||
|
||||
export interface CharakterbogenProps {
|
||||
/** Selected trait keys. */
|
||||
traits: string[]
|
||||
note: string
|
||||
onTraitsChange: (traits: string[]) => void
|
||||
onNoteChange: (note: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* FEAT-14: character sheet — a checkbox grid of traits + a free note.
|
||||
* Controlled & reusable: rendered on the animal detail page (persisted) and in
|
||||
* the Abgabe listing composer (feeds the AI sale-text). German labels from
|
||||
* de.character.traits; the stored value is the trait KEY.
|
||||
*/
|
||||
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 the vocabulary order for stable output.
|
||||
onTraitsChange(ALL_TRAITS.filter((tr) => next.has(tr.key)).map((tr) => tr.key))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="charakterbogen">
|
||||
<ul className="trait-grid">
|
||||
{ALL_TRAITS.map((tr) => (
|
||||
<li key={tr.key}>
|
||||
<label className="trait-chip">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selected.has(tr.key)}
|
||||
onChange={() => toggle(tr.key)}
|
||||
/>
|
||||
<span>{tr.label}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<label className="field">
|
||||
<span>{t.noteLabel}</span>
|
||||
<textarea
|
||||
value={note}
|
||||
placeholder={t.notePlaceholder}
|
||||
onChange={(e) => onNoteChange(e.target.value)}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
41
gerbil-manager-web/src/components/charakterbogen.css
Normal file
41
gerbil-manager-web/src/components/charakterbogen.css
Normal file
@@ -0,0 +1,41 @@
|
||||
/* FEAT-14 Charakterbogen — trait checkbox grid (mobile-first). */
|
||||
|
||||
.charakterbogen .trait-grid {
|
||||
list-style: none;
|
||||
margin: 0 0 0.75rem;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
.charakterbogen .trait-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.charakterbogen .trait-grid {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.trait-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.4rem 0.6rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.5rem;
|
||||
background: var(--color-surface);
|
||||
cursor: pointer;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.trait-chip input {
|
||||
width: 1.1rem;
|
||||
height: 1.1rem;
|
||||
min-height: 0;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
Reference in New Issue
Block a user