| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
const board = () => document.getElementById("board"); |
| 9 |
|
| 10 |
async function swapIn(url) { |
| 11 |
const response = await fetch(url, { headers: { accept: "text/html" } }); |
| 12 |
const fresh = new DOMParser().parseFromString(await response.text(), "text/html"); |
| 13 |
for (const id of ["board", "palettes"]) { |
| 14 |
const next = fresh.getElementById(id); |
| 15 |
const here = document.getElementById(id); |
| 16 |
if (next && here) here.replaceWith(next); |
| 17 |
} |
| 18 |
wake(); |
| 19 |
} |
| 20 |
|
| 21 |
document.addEventListener("click", async (event) => { |
| 22 |
const swatch = event.target.closest("[data-palette]"); |
| 23 |
if (swatch) { |
| 24 |
event.preventDefault(); |
| 25 |
const url = new URL(location.href); |
| 26 |
url.searchParams.set("palette", swatch.dataset.palette); |
| 27 |
history.replaceState(null, "", url); |
| 28 |
try { |
| 29 |
localStorage.setItem("glyph.palette", swatch.dataset.palette); |
| 30 |
} catch {} |
| 31 |
await swapIn(url); |
| 32 |
return; |
| 33 |
} |
| 34 |
const copy = event.target.closest(".js-copy"); |
| 35 |
if (copy) { |
| 36 |
const said = copy.textContent; |
| 37 |
try { |
| 38 |
const svg = fetch(copy.dataset.href).then((r) => r.text()); |
| 39 |
|
| 40 |
if (window.ClipboardItem) |
| 41 |
await navigator.clipboard.write([ |
| 42 |
new ClipboardItem({ "text/plain": svg.then((t) => new Blob([t], { type: "text/plain" })) }), |
| 43 |
]); |
| 44 |
else await navigator.clipboard.writeText(await svg); |
| 45 |
copy.textContent = "Copied"; |
| 46 |
} catch { |
| 47 |
copy.textContent = "Couldn't copy"; |
| 48 |
} |
| 49 |
setTimeout(() => (copy.textContent = said), 1600); |
| 50 |
return; |
| 51 |
} |
| 52 |
const example = event.target.closest("[data-example]"); |
| 53 |
if (example) { |
| 54 |
const box = document.getElementById("prompt"); |
| 55 |
if (box) { |
| 56 |
box.value = example.dataset.example; |
| 57 |
box.focus(); |
| 58 |
} |
| 59 |
} |
| 60 |
}); |
| 61 |
|
| 62 |
|
| 63 |
document.addEventListener("keydown", (event) => { |
| 64 |
if (event.target.id === "prompt" && event.key === "Enter" && !event.shiftKey) { |
| 65 |
event.preventDefault(); |
| 66 |
event.target.form.requestSubmit(); |
| 67 |
} |
| 68 |
}); |
| 69 |
|
| 70 |
function wake() { |
| 71 |
for (const el of document.querySelectorAll(".js-copy, .examples")) el.hidden = false; |
| 72 |
} |
| 73 |
|
| 74 |
|
| 75 |
setInterval(() => { |
| 76 |
for (const el of document.querySelectorAll("[data-since]")) { |
| 77 |
const s = Math.max(0, Math.round((Date.now() - Date.parse(el.dataset.since)) / 1000)); |
| 78 |
el.textContent = `Claude is drawing… ${s}s`; |
| 79 |
} |
| 80 |
}, 1000); |
| 81 |
|
| 82 |
|
| 83 |
new MutationObserver(wake).observe(document.body, { childList: true, subtree: true }); |
| 84 |
|
| 85 |
|
| 86 |
try { |
| 87 |
const kept = localStorage.getItem("glyph.palette"); |
| 88 |
const url = new URL(location.href); |
| 89 |
if (kept && !url.searchParams.has("palette") && board()) { |
| 90 |
url.searchParams.set("palette", kept); |
| 91 |
history.replaceState(null, "", url); |
| 92 |
swapIn(url); |
| 93 |
} |
| 94 |
} catch {} |
| 95 |
wake(); |