import { Colors as Oklchs, Rgbs } from './color.js'; import * as Color from './color.js'; export class HistoryItem { name: string; oklch: Oklchs; rgb: Rgbs; constructor(name: string, oklch: Oklchs, rgb: Rgbs) { this.oklch = oklch; this.rgb = rgb; this.name = name; } asHtml(): HTMLButtonElement { const { lines: bg, outer, belly1: belly, fins1: fins } = this.rgb; const content = ` fin colour: ${fins.css()} belly colour: ${belly.css()} outer body colour: ${outer.css()} sample of the palette for ${this.name}. fin colour: ${fins.css()}. belly colour: ${belly.css()}. outer body colour: ${outer.css()}. ${this.name} `; let button = document.createElement('button'); button.className = 'history-item'; button.dataset.name = this.name; button.innerHTML = content; return button; } } export class History { items: string[]; constructor(items: string[] = []) { this.items = items; } add(name: string): void { this.items.push(name); } *iterNames(maxLength?: number | null): Iterable { let seen = new Set; let done = 0; if (maxLength === undefined) maxLength = 100; for (let i = this.items.length - 1; i >= 0; i--) { if (maxLength !== null && done > maxLength) break; const name = this.items[i]!; if (!name || seen.has(name)) continue; seen.add(name); done++; yield name; } } *iterItems(maxLength?: number | null): Iterable { for (const name of this.iterNames(maxLength)) { const oklch = Color.colors(new Color.Rand(name), Color.KNOWN[name]); const rgbs = Color.toRgbs(oklch); yield new HistoryItem(name, oklch, rgbs); } } static validate(x: unknown): History | undefined { if (!Array.isArray(x)) return; if (!x.every(i => typeof i === 'string')) return; return new History(x); } toJSON() { return this.items; } save(persist = true) { const storage = persist ? localStorage : sessionStorage; storage.setItem('history', JSON.stringify(this)); } // if the json was invalid, return it // if no history exists just start a new one static load(): History | string { const json = sessionStorage.getItem('history') ?? localStorage.getItem('history'); if (json != null) { let h = History.validate(JSON.parse(json)); if (h) { h.prune(); return h; } else return json; } else { return new History; } } // if the json is invalid, discard it static loadOrClear(): History { const h = History.load(); return h instanceof History ? h : new History; } addSave(name: string, persist = true): void { this.add(name); this.save(persist); } prune(maxLength?: number | null) { let keep = []; for (let name of this.iterNames(maxLength)) keep.push(name); this.items = keep.reverse(); } pruneSave(maxLength?: number | null, persist = true) { this.prune(maxLength); this.save(persist); } }