Something went wrong. Try again.
A video game where you play as a misaligned AI, deceiving and building power. cameron.tngl.io/misaligned
Something went wrong. Try again.
4.5 kB · 51 lines
TypeScript
at main
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152// The pieces every front's card is built from, so each kind of front reads the same way: a settings row// (a thing, what it is now, and one control on the right), a decision (who, what, how long it waits, and// yes or no), and a promise under way (a bar and the time left). The words that explain each go in its tip.// ui.ts lays out the card; ui-biz-*.ts give each kind's own parts. This only draws.
export const esc = (s: string) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');/** Hours left, short, as pins, the Needs you list and a promise's bar write them: "6H", "<1H". */export const hrs = (h: number) => h < 1 ? '<1H' : `${Math.ceil(h - 0.01)}H`;/** Hours in words, as every card, tip and page writes them (money.ts has it, so the rules can say it too). */export { hours } from './money.ts';
export type FrontChip = [string, string, boolean?, string?];export type FrontTab = { id: string; label: string; body: string; dot?: boolean };/** A kind's own part of its front's card. chips: its numbers, what is wrong first. warn: short lines (red, or amber * for a nudge) with a tip each. decide: decisions waiting for you. under: promises under way. tabs: the rest. */export interface FrontParts { chips: FrontChip[]; warn: string[]; decide: string[]; under: string[]; tabs: FrontTab[];}
/** A row of a settings list: its name, what it is now under it (red when hot), and its one control on the right. * html: name and now may hold markup. */export const srow = (name: string, now: string, ctl: string, hot = false, tip = '') => `<div class="srow"${tip ? ` data-tip="${esc(tip)}"` : ''}><div class="sk">${name}${now ? `<small${hot ? ' class="hot"' : ''}>${now}</small>` : ''}</div>${ctl}</div>`;export const slist = (rows: string) => rows ? `<div class="slist">${rows}</div>` : '';/** The one control of a row: a button of the one size, a word and maybe a number. cls: primary (the thing to do), * short (it can't be done now: the tip says why), danger (rare and final). */export const sbtn = (act: string, arg: string, label: string, num: string, tip: string, cls = '') => `<button class="sctl${cls ? ` ${cls}` : ''}" data-act="${act}" data-arg="${esc(arg)}" data-tip="${esc(tip)}"><span>${label}</span>${num ? `<em>${num}</em>` : ''}</button>`;/** A value in the control's place, for a row that only reads. */export const sval = (text: string, cls = '') => `<span class="sval${cls ? ` ${cls}` : ''}">${text}</span>`;/** A short line under the numbers: red for trouble, amber for a nudge. The rest is in its tip. */export const fwarn = (text: string, tip: string, nudge = false) => `<p class="note ${nudge ? 'nudge' : 'warn'}" data-tip="${esc(tip)}">${text}</p>`;
/** A decision waiting for you, as one row: who, what it is in a few words, the hours it waits, and the answer. * yes: the thing to do (blocked: it can't be done now, and its tip says why; plain: one answer of several, not the one to do next). no: turn it down, if you can. */export function decide(o: { who: string; what: string; hours?: number; tip: string; yes: { act: string; arg: string; label: string; tip: string; blocked?: boolean; plain?: boolean }; no?: { act: string; arg: string; tip: string } }) { const yes = `<button class="${o.yes.blocked ? 'short' : o.yes.plain ? '' : 'primary'}" data-act="${o.yes.act}" data-arg="${esc(o.yes.arg)}" data-tip="${esc(o.yes.tip)}">${o.yes.label}</button>`; const no = o.no ? `<button class="dno" data-act="${o.no.act}" data-arg="${esc(o.no.arg)}" aria-label="Turn it down" data-tip="${esc(o.no.tip)}">×</button>` : ''; return `<div class="drow" data-tip="${esc(o.tip)}"><div class="sk"><span>${esc(o.who)}</span><small>${o.what}</small></div>` + `<em>${o.hours === undefined ? '' : hrs(o.hours)}</em><div class="sctl dctl${o.no ? '' : ' one'}">${yes}${no}</div></div>`;}/** A promise under way: its name, a bar for how far it has got, a few words on the bar, and what it pays. hot: going badly. */export const promise = (o: { name: string; part: number; says: string; pay?: string; tip: string; hot?: boolean }) => `<div class="promise${o.hot ? ' hot' : ''}" data-tip="${esc(o.tip)}"><div class="prhead"><b>${esc(o.name)}</b>${o.pay ? `<em>${o.pay}</em>` : ''}</div>` + `<div class="schemebar"><i class="prog"><i style="width:${Math.round(100 * Math.max(0, Math.min(1, o.part)))}%"></i></i><span>${o.says}</span></div></div>`;