Personal ledger on the character sheet

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-28 13:20:26 +00:00
parent ece0f101aa
commit 4b0724e6e5
4 changed files with 159 additions and 11 deletions

View file

@ -2733,10 +2733,34 @@ function characterSheet(uid) {
${equipmentPanel(p, mine)}
${mine ? lookPanel(p) : ""}
</div>
<div class="panel"><h2>Skills</h2><div class="sheet-skills">${skillRows}</div></div>
<div>
<div class="panel"><h2>Skills</h2><div class="sheet-skills">${skillRows}</div></div>
${mine ? ledgerPanel(p) : ""}
</div>
</div>`;
}
// What you did, newest first: a stretch at one action is one line ("Mine copper · 3h 20m"), gifts and sales their own.
function ledgerPanel(p) {
const got = (id, q) => id === "gold" ? `<span class="item-chip">${COIN} ${fmt(q)}</span>` : `${itemChip(id, q)} ${esc(item(id).name)}`;
const rows = [...p.ledger].reverse().map((l) => {
let line;
if (l.act) {
const a = C.actions.find((x) => x.id === l.act);
const loot = Object.entries(l.items).map(([id, q]) => `<span>${got(id, q)}</span>`).join("");
const fights = l.won !== undefined ? ` · ${fmt(l.won)} won${l.lost ? `, ${fmt(l.lost)} lost` : ""}` : ` · ×${fmt(l.n)}`;
line = `${skillOf(a.skill).icon} <b>${a.enemy ? "Fought " : ""}${esc(a.name)}</b> <span class="muted">· ${dur(l.at - l.start)}${fights}</span>
<div class="got">${loot}${l.gold ? `<span class="item-chip">${COIN} ${fmt(l.gold)}</span>` : ""}${l.xp ? `<span class="item-chip">${fmt(Math.round(l.xp))} XP</span>` : ""}</div>`;
} else {
const who = l.who ? ` ${l.verb === "Gave" ? "to" : "from"} ${esc(playerName(l.who))}` : "";
line = `<b>${esc(l.verb)}</b> ${l.item ? got(l.item, l.qty) : esc(l.label)}${l.item && l.label ? ` <span class="muted">· ${esc(l.label)}</span>` : ""}${who}`
+ (l.gold ? ` <span class="muted">·</span> <span class="item-chip">${COIN} ${l.verb === "Bought" ? "" : "+"}${fmt(l.gold)}</span>` : "");
}
return `<li>${line}<span class="when">${ago(l.at)}</span></li>`;
}).join("");
return `<div class="panel"><h2>Ledger</h2><ul class="ledger">${rows || `<li class="muted">Nothing yet.</li>`}</ul></div>`;
}
function lookPanel(p) {
const look = p.look, wear = (kind) => Object.keys(C.cosmetics).filter((k) => C.cosmetics[k].kind === kind && (C.free_looks.includes(k) || p.owned.includes(k)));
const swatches = (part) => wear("colour").map((k) => `<button class="swatch ${look[part] === k ? "on" : ""}" style="background:${C.cosmetics[k].value}"