feat(ui): skill levels + titles on CREW tab and team-builder (#45)
CI / build + unit + e2e (pull_request) Successful in 3m7s
CI / build + unit + e2e (pull_request) Successful in 3m7s
This commit is contained in:
@@ -9,6 +9,12 @@ import type { CrewDto, CrewState } from '@/lib/game/save'
|
||||
// /api/crew on mount; Radix unmounts inactive tabs, so opening this tab always refetches
|
||||
// (no polling needed — turn-based game). Display-only for now: no dismiss/assign actions yet.
|
||||
|
||||
// Spec §8: the three combat traits that carry no duration effect yet — their effect lands
|
||||
// with the encounters iteration, so the trait line labels them encounter-ready (STANDBY).
|
||||
// The label is additive — the original name always appears in the text unchanged.
|
||||
const STANDBY_TRAITS = new Set(['SHARP SHOOTER', 'SHORT FUSE', 'JINXED IN A DOGFIGHT'])
|
||||
const standbyLabel = (trait: string) => (STANDBY_TRAITS.has(trait) ? `${trait} (STANDBY — encounter-ready)` : trait)
|
||||
|
||||
interface CrewPanelProps {
|
||||
narrow?: boolean
|
||||
}
|
||||
@@ -80,15 +86,25 @@ export function CrewPanel({ narrow }: CrewPanelProps) {
|
||||
>
|
||||
{member.role}
|
||||
</p>
|
||||
{/* The member's four skill levels, fixed order (JC-27) — one `·`-separated line. */}
|
||||
<p style={{ fontSize: '0.6rem', color: 'var(--text-secondary)', letterSpacing: '0.08em' }}>
|
||||
{member.skills.map((s) => `${s.skill} L${s.level}`).join(' · ')}
|
||||
</p>
|
||||
{/* The title only exists at L3+ (SENIOR) / L5 (MASTER) — titleFor returns null below. */}
|
||||
{member.title !== null && (
|
||||
<p style={{ fontSize: '0.62rem', color: 'var(--color-green)', letterSpacing: '0.1em' }}>
|
||||
{member.title}
|
||||
</p>
|
||||
)}
|
||||
</CardHeader>
|
||||
<CardContent style={{ display: 'flex', flexDirection: 'column', gap: '0.4rem' }}>
|
||||
<div style={{ fontSize: '0.7rem', letterSpacing: '0.05em' }}>
|
||||
<span style={{ color: 'var(--color-green)' }}>+ </span>
|
||||
<span style={{ color: 'var(--text-secondary)' }}>{member.traitGood}</span>
|
||||
<span style={{ color: 'var(--text-secondary)' }}>{standbyLabel(member.traitGood)}</span>
|
||||
</div>
|
||||
<div style={{ fontSize: '0.7rem', letterSpacing: '0.05em' }}>
|
||||
<span style={{ color: 'var(--color-red)' }}>- </span>
|
||||
<span style={{ color: 'var(--text-secondary)' }}>{member.traitBad}</span>
|
||||
<span style={{ color: 'var(--text-secondary)' }}>{standbyLabel(member.traitBad)}</span>
|
||||
</div>
|
||||
<p style={{ fontSize: '0.6rem', color: 'var(--text-muted)', letterSpacing: '0.08em' }}>
|
||||
ORIGIN // {member.origin.toUpperCase()}
|
||||
|
||||
Reference in New Issue
Block a user