generated from eblume/project-template
Retire the `A` attention cycle and the duplicate `b` push-to-blue gesture in heph-tui. Attention is now picked directly: press `a` then `1`–`4` (a1=red, a2=orange, a3=white, a4=blue, ordered by intensity). Cycling past blue used to make a task vanish from the current view with no way back — direct selection never does. Quick-add moves from `a` to `n`. Surface the a1–a4 nomenclature everywhere instead of colour words or the old p1–p4 priorities: heph-tui status/legend, the heph-quickadd chip + hint, and the PWA chip/hint plus a new band-picker (replacing its cycle button). The shared quick-add parser now accepts `a1`–`a4` (a1=red … a4=blue) and no longer recognizes `p1`–`p4`. Colour mappings are unchanged; only the words. Add Attention::ui_label() in heph-core so both Rust surfaces share the mapping; bump the PWA service-worker cache; update the PWA how-to. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72 lines
2.4 KiB
JavaScript
72 lines
2.4 KiB
JavaScript
// Display helpers — the PWA mirror of heph-tui's fmt.rs: relative date chips,
|
||
// attention colors/flags, and a stable per-project bullet color.
|
||
|
||
/** Attention color string → the CSS custom-property color used for flags/dots. */
|
||
export const ATTENTION_COLORS = {
|
||
red: "var(--att-red)",
|
||
orange: "var(--att-orange)",
|
||
blue: "var(--att-blue)",
|
||
white: "var(--att-white)",
|
||
};
|
||
|
||
/**
|
||
* The attention bands a user can pick, in `a1`..`a4` order (by intensity).
|
||
* Each entry is the storage color string; the label is its index + 1.
|
||
*/
|
||
export const ATTENTION_BANDS = ["red", "orange", "white", "blue"];
|
||
|
||
/** Attention color string → its `a1`..`a4` UI label (or "" if unset). */
|
||
export function attentionLabel(att) {
|
||
const i = ATTENTION_BANDS.indexOf(att);
|
||
return i < 0 ? "" : `a${i + 1}`;
|
||
}
|
||
|
||
/** Whether an attention band shows a flag glyph (red/orange/blue; not white). */
|
||
export function hasFlag(att) {
|
||
return att === "red" || att === "orange" || att === "blue";
|
||
}
|
||
|
||
function startOfDay(ms) {
|
||
const d = new Date(ms);
|
||
return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
|
||
}
|
||
|
||
/**
|
||
* Compact, relative date label for an epoch-ms date (heph-tui fmt.rs):
|
||
* today/tomorrow/yesterday, else MM-DD within the current year, else YYYY-MM-DD.
|
||
*/
|
||
export function fmtRelative(ms, nowMs = Date.now()) {
|
||
if (ms == null) return "";
|
||
const day = startOfDay(ms);
|
||
const today = startOfDay(nowMs);
|
||
const oneDay = 86_400_000;
|
||
if (day === today) return "today";
|
||
if (day === today + oneDay) return "tomorrow";
|
||
if (day === today - oneDay) return "yesterday";
|
||
const d = new Date(ms);
|
||
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
||
const dd = String(d.getDate()).padStart(2, "0");
|
||
if (d.getFullYear() === new Date(nowMs).getFullYear()) return `${mm}-${dd}`;
|
||
return `${d.getFullYear()}-${mm}-${dd}`;
|
||
}
|
||
|
||
/** True when `lateOn` is strictly in the past — the sole urgency signal (§7). */
|
||
export function isOverdue(lateOn, nowMs = Date.now()) {
|
||
return lateOn != null && nowMs > lateOn;
|
||
}
|
||
|
||
/** A stable hue (0–359) for a project id, so its bullet color is deterministic. */
|
||
export function projectHue(id) {
|
||
if (!id) return null;
|
||
let h = 0;
|
||
for (let i = 0; i < id.length; i++) {
|
||
h = (h * 31 + id.charCodeAt(i)) >>> 0;
|
||
}
|
||
return h % 360;
|
||
}
|
||
|
||
/** CSS color for a project's bullet, or a neutral default when unfiled. */
|
||
export function projectColor(id) {
|
||
const hue = projectHue(id);
|
||
return hue == null ? "var(--bullet-none)" : `hsl(${hue} 55% 62%)`;
|
||
}
|