Track a recipe under the top bar

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-20 21:13:46 +01:00
parent 722cf0b382
commit a86594594a
5 changed files with 67 additions and 6 deletions

View file

@ -384,7 +384,21 @@ function topbar() {
const w = S.happenings?.weather;
if (w) chips += `<button class="chip" data-nav="town" title="${esc(weatherTip(w))}">${w.icon}</button>`;
if (S.upcoming) chips += `<button class="chip ${["raid", "dragon"].includes(S.upcoming.kind) ? "threat" : ""} ${S.upcoming.at_gates ? "alarm" : ""}" data-nav="council">${eventIcon(S.upcoming.kind)} ${S.upcoming.at_gates ? `<span class="label">${S.upcoming.kind === "dragon" ? "Overhead" : "At the gates"}</span> ` : ""}${eventWhen(S.upcoming, true)}</button>`;
return `<button class="menu-btn" data-menu aria-label="Menu">☰</button><h1>${esc(title)}</h1>${chips}`;
return `<button class="menu-btn" data-menu aria-label="Menu">☰</button><h1>${esc(title)}</h1>${chips}${S.me ? trackedBar() : ""}`;
}
// The recipe you're after, under the top bar on every page: have / need for each input.
function trackedBar() {
const me = S.me, a = me.tracked && C.actions.find((x) => x.id === me.tracked);
if (!a) return "";
const ready = Object.entries(a.inputs).every(([id, q]) => (me.bank[id] || 0) >= q);
const go = !me.blocked[a.id] && me.action?.id !== a.id;
return `<div class="tracked ${ready ? "ready" : ""}">
<button class="tracked-name" data-nav="skill:${a.skill}" data-nav-group="${esc(a.group || "")}" title="${esc(a.name)}">${a.icon}<span class="label">${esc(a.name)}</span></button>
<span class="io">${Object.entries(a.inputs).map(([id, q]) => itemChip(id, q, me.bank[id] || 0)).join("")}</span>
${go ? `<button class="btn sm primary" data-start="${a.id}">Start</button>` : ""}
<button class="pin on" data-track="${a.id}" title="Untrack">📌</button>
</div>`;
}
function eventIcon(kind) {
@ -799,7 +813,7 @@ function actionCard(a) {
<div class="top"><div class="ico">${icon}</div><div>
<div class="name">${esc(a.name)}</div>
<div class="sub">Level ${a.level} · ${dur(time)} · ${a.xp} XP</div>
</div></div>
</div>${Object.keys(a.inputs).length ? `<button class="pin ${me.tracked === a.id ? "on" : ""}" data-track="${a.id}" title="${me.tracked === a.id ? "Untrack" : "Track"}">📌</button>` : ""}</div>
${io ? `<div class="io">${io}</div>` : ""}
${extra}
${me.action?.plot2 && (active || second) ? `<div class="small muted">Plot ${active ? 1 : 2}${growingNow ? " · growing now" : " · next"}</div>` : ""}
@ -1661,6 +1675,7 @@ document.addEventListener("click", (e) => {
if (t.matches("[data-close]") || e.target === $("#modal")) { $("#modal").hidden = true; showThreat(); return; }
if ("menu" in d) { setMenu(!$("#app").classList.contains("open")); return; }
if (d.nav) {
if (d.navGroup) { tabs[d.nav.slice(6)] = d.navGroup; remember(`tab.${d.nav.slice(6)}`, d.navGroup); }
page = d.nav; remember("page", page); selected = null;
history.replaceState(null, "", "#" + page);
setMenu(false);
@ -1716,6 +1731,7 @@ document.addEventListener("click", (e) => {
if (d.garrison) return act("/api/garrison", { join: d.garrison === "1" });
if (d.perk) return act("/api/perk", { perk: d.perk });
if (d.pin) return act("/api/pin", { skill: d.pin });
if (d.track) return act("/api/track", { id: d.track });
if (d.favour) return act("/api/favour", { kind: d.favour });
if (d.food) return act("/api/food", { item: d.food === "cheapest" ? null : d.food });
if (d.potion) return act("/api/potion", { item: d.potion });