// Reusable character-sheet renderer for the char.profile shape returned by
// /public/shard/char/:serial. Presentational only — the parent handles loading
// and errors. Styled with the shared theme vocabulary (panel/grid/stat tiles).
//
// `moderation` opts in the in-game kick/ban controls for the character's account;
// they self-gate to staff (ShardAccountActions), so passing it from a page a
// player can reach is safe.
import ShardAccountActions from './ShardAccountActions.jsx'
const RESIST_LABELS = { phys: 'Physical', fire: 'Fire', cold: 'Cold', pois: 'Poison', energy: 'Energy' }
function StatTile({ value, label }) {
return (
)
}
function Vital({ label, cur, max }) {
const pct = max ? Math.min(100, Math.round((cur / max) * 100)) : 0
return (
{label}
{cur ?? '—'} / {max ?? '—'}
)
}
export default function CharacterSheet({ char, moderation = false }) {
if (!char) return null
const stats = char.stats || {}
const resist = stats.resist || {}
// Skills the character actually has, best first.
const skills = (char.skills || [])
.filter((s) => (s.value || s.base || 0) > 0)
.sort((a, b) => (b.value || 0) - (a.value || 0))
const equipment = char.equipment || []
return (
{/* Identity */}
{char.name || 'Unknown'}
{char.title && {char.title}}
{char.online ? 'Online' : 'Offline'}
{char.serial}
{/* Staff moderation for this character's account (self-gates to staff). */}
{moderation && char.acct && (
Account {char.acct}
)}
{/* Core stats */}
{/* Resistances */}
{Object.keys(resist).length > 0 && (
Resistances
{['phys', 'fire', 'cold', 'pois', 'energy'].map((k) => (
{resist[k] ?? 0}
{RESIST_LABELS[k]}
))}
)}
{/* Skills */}
{skills.length > 0 && (
Skills ({skills.length})
{skills.map((s) => {
const cap = s.cap || 100
const pct = Math.min(100, Math.round(((s.value || 0) / cap) * 100))
return (
)
})}
)}
{/* Equipment */}
{equipment.length > 0 && (
Equipment
{equipment.map((it) => (
{it.layer || 'Item'}
id {it.itemId}{it.hue ? ` · hue ${it.hue}` : ''}
{it.mods && Object.keys(it.mods).length > 0 && (
{Object.entries(it.mods).map(([k, v]) => (
{k} {v}
))}
)}
))}
)}
)
}