generated at
作業時間を🍅でリアルタイムに表示するUserScript
可視化方法として良さげに思えた
30minごとに🍅を増やす
2025-02-06 22:01:47 未完了の作業は、1分ごとに🍅の数を更新する

$ deno check --remote -r=https://scrapbox.io https://scrapbox.io/api/code/takker/作業時間を🍅で表示するUserScript/main.ts
main.ts
/// <reference no-default-lib="true" /> /// <reference lib="esnext" /> /// <reference lib="dom" /> /// <reference lib="dom.iterable" /> import { getLineDOM, takeInternalLines } from "jsr:@cosense/std@0.29/browser/dom"; import type { Scrapbox } from "jsr:@cosense/types@0.10/userscript"; import { parse } from "../../takker/takker99%2Ftakker-scheduler/deps.ts"; import { differenceInMinutes } from "npm:date-fns@4/differenceInMinutes"; declare const scrapbox: Scrapbox; const makeTomatoDom = (): HTMLDivElement => { const div = document.createElement("div"); div.style.position = "absolute"; div.style.top = "0"; div.style.right = "0"; div.style.textAlign = "right"; return div }; const tomatoDoms = new Map<string, HTMLDivElement>(); let timer: number | undefined; const updateTomato = ():void => { for (const tomatoDom of tomatoDoms.values()) { tomatoDom.remove(); } tomatoDoms.clear(); if (scrapbox.Layout !== "page" || scrapbox.Project.name !== "takker-memex") { scrapbox.removeListener("lines:changed", checkLines); if (!timer) return; clearInterval(timer); timer = undefined; return; } checkLines(); scrapbox.addListener("lines:changed", checkLines); timer = setInterval(checkLines, 60 * 1000); }; const checkLines = ():void => { const lines = takeInternalLines(); for (const line of lines) { const task = parse(line.text); if (!task?.record?.start) { const tomatoDom = tomatoDoms.get(line.id); tomatoDom?.remove?.(); tomatoDoms.delete(line.id); continue; } const duration = differenceInMinutes(task.record.end ?? new Date(), task.record.start); const tomatoCount = Math.round(duration / 30); const indicator = // maximum is 🍅x20 tomatoCount > 20 ? `🍅x${(duration / 30).toFixed(1)}` : "🍅".repeat(tomatoCount); const tomatoDom = tomatoDoms.get(line.id) ?? makeTomatoDom(); getLineDOM(line.id)?.append?.(tomatoDom); tomatoDoms.set(line.id, tomatoDom); tomatoDom.textContent = indicator; } }; updateTomato(); scrapbox.addListener("page:changed", updateTomato); scrapbox.addListener("lines:changed", updateTomato);

#2025-02-06 22:01:37