今日やるリストを表示するPageMenu
今日やるリストだけを表示するようにして、使い勝手を上げてみる
interfaceのアイデア
Page Menuを使う
Page Menuを押したらリストが出る
Page Menuを押したら「今日やるリストを出す」「1週間以内にやることを出す」などのいくつかのボタンがある それらを押すと、その範囲に絞った結果が表示される
どこに表示すればいいだろうか?
これ実装したいtakker.icon
いろんな期間のタスクを見れるとよい
とりあえず今日やるリストまでは作れたので、これをしばらく使ってから様子見かな
Reloadの下にCopy Allボタンをつける
これを押すと、今日やることがリスト形式でコピーされる
code:format.txt
やり残していること
今日やること
明日やること
今週やること
独自のUIを組み立てる
こっちでやりたくなってきた
以下、「Page Menuを使う」案を採用して作成したUserScriptとなる
実装したいこと
↑のUIにする
projectごとに区切り線で分けるのをやめる
全然使わなった
2022-03-25
22:16:37 group()のテストを書く
これをやったら終わり
23:02:29 終了
結構間違えていた
22:15:29 コピペ機能もできた
期間を細かく分け過ぎな気もするが
とりあえずこれで使ってみる
21:52:53 readLinksBulkにバグが有ったので直す
13:36:47 函数を切り出した
2022-03-15
05:48:05 いいかんじ!
https://gyazo.com/368c4d5a0ea6c8d666135a0e7bc34aa2
完了したやつを外すの忘れてた
05:48:55 直した
05:42:59 script.tsの型チェック終了
05:25:00 E2Eテストやる
実際にuserscriptを動かしてみることをかっこよく言ってみただけtakker.icon
05:19:07 締切 & いつ頃やるかの両方があったときのテストもいれた
05:12:48 parserのテスト終了
2022-03-14
18:49:42 parserを作っていたが、単に探して羅列するだけならそんな必要ないことに気づいた
たとえば2022-03-14にやるタスクを表示するなら、@2022-03-14と~2022-03-14と@2022-w12のいずれかの文字列を含むリンクを表示すればいい
あ、だめだ。それだと期限切れのタスクを表示できない……
一旦期限切れは無視するか?
過去1週間分の日付を列挙して力業で検索するという手段もある
バグ
[⬜️@2022-03-18 ~を!に置き換える]がタスクとして認識されない
これをテストケースに加えて、テストが通るようにコードを修正しよう
09:22:13 今やったら認識された
serverのDB更新にラグがあっただけだろうか?
まあいいや
code:script.ts
import { setup } from "./mod.ts";
code:type_check.sh
code:mod.ts
/// <reference no-default-lib="true" />
/// <reference lib="esnext" />
/// <reference lib="dom" />
import { classify, Category, list, Task } from "../takker99%2Ftakker-scheduler/workflow.ts";
import {
useStatusBar,
openInTheSameTab,
encodeTitleURI,
toTitleLc,
} from "../scrapbox-userscript-std/dom.ts";
import type { Scrapbox } from "../scrapbox-jp%2Ftypes/mod.ts";
declare const scrapbox: Scrapbox;
const id = "today-next-action";
let loading = false;
let initialized: Promise<void>;
const dummyImage = "/assets/img/favicon/apple-touch-icon.png";
entory point
code:mod.ts
export function setup(projects: string[]) {
code:mod.ts
const selector = head style[data-userscript-name="${id}"];
document.querySelector(selector)?.remove?.();
const style = document.createElement("style");
style.dataset.userscriptName = id;
style.textContent = `a#${id}.tool-btn:hover {
text-decoration: none;
}
a#${id}.tool-btn::before {
position: absolute;
content: "\\f0ae";
font: 900 20px/46px "Font Awesome 5 Free";
}
a#${id}.tool-btn img {
opacity: 0;
}
a#${id}.tool-btn ~ ul a::before {
position: absolute;
font-family: "Font Awesome 5 Free";
font-weight: 900;
}
a#${id}.tool-btn ~ ul img {
opacity: 0;
margin-right: 0;
}`;
document.head.append(style);
Page Menuを入れる
code:mod.ts
if (!document.getElementById(id)) {
scrapbox.PageMenu.addMenu({
title: id,
image: dummyImage,
onClick: async () => {
initialized ??= load(projects);
await initialized;
},
});
}
}
code:mod.ts
/** 一度取得したTaskを貯めておく場所
*
* reloadでresetされる
*/
const tasks: {
project: string;
title: string;
task: Task;
}[] = [];
async function load(projects: string[]) {
scrapbox.PageMenu(id).removeAllItems();
loading = true;
// 再読み込み用
scrapbox.PageMenu(id).addItem({
title: "Reload",
onClick: () => {
if (loading) return;
load(projects);
},
});
// コピペ用
scrapbox.PageMenu(id).addItem({
title: "Copy missed and today actions",
onClick: async () => {
const today = new Date();
const titles = tasks.map(({ task, title }) => {
const category = classify(task, today);
return { category, title };
});
const text = [
"今日やること",
...titles.flatMap(
({ category, title }) => category === "today" ? [ [${title}]] : []
),
"",
"やり残していること",
...titles.flatMap(
({ category, title }) => category === "missed" ? [ [${title}]] : []
),
"",
].join("\n");
try {
await navigator.clipboard.writeText(text);
} catch(e: unknown) {
if (!(e instanceof Error)) throw e;
console.error(e);
alert(${e.name} ${e.message});
}
},
});
]
scrapbox.PageMenu(id).addItem({
title: button,
onClick: async () => {
const today = new Date();
const titles = tasks.map(({ task, title }) => {
const category = classify(task, today);
return { category, title };
});
const text = [
section,
...titles.flatMap(
({ category, title }) => category === cat ? [ [${title}]] : []
),
"",
].join("\n");
try {
await navigator.clipboard.writeText(text);
} catch(e: unknown) {
if (!(e instanceof Error)) throw e;
console.error(e);
alert(${e.name} ${e.message});
}
},
});
}
const { render, dispose } = useStatusBar();
try {
const titleLcs = new Set<string>(); // 重複除外用
const today = new Date();
for (const project of projects) {
render(
{ type: "spinner" },
{ type: "text", text: Searching "/${project}" for next actions...},
);
for await (const { task, title } of list(project)) {
const titleLc = toTitleLc(title);
if (titleLcs.has(titleLc)) continue;
titleLcs.add(titleLc);
if (task.status === "✅") continue;
if (task.status === "❌") continue;
tasks.push({ project, title, task });
const category = classify(task, today);
if (
category !== "missed" &&
category !== "today"
) continue;
scrapbox.PageMenu(id).addItem({
title,
onClick: () => {
if (project !== scrapbox.Project.name) {
project
}/${encodeTitleURI(title)}`;
window.open(path);
return;
}
openInTheSameTab(project, title);
},
});
}
scrapbox.PageMenu(id).addSeparator();
}
render(
{ type: "check-circle" },
{ type: "text", text: Found actions.},
);
} catch(e: unknown) {
render(
{ type: "exclamation-triangle" },
{ type: "text", text: e instanceof Error ?
${e.name} ${e.message} :
Unknown error! (see developper console),
},
);
console.error(e);
} finally {
loading = false;
setTimeout(() => dispose(), 1000);
}
}
タスクをstartAtに応じて振り分ける
タスクの書式解析など
別ページに切り出したほうがいいかも
Githubに入れる……までしなくてもいいか
2022-03-18 13:51:14 切り出した