@shivaedev/work-board 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/README.md +141 -3
- package/dist/board.d.ts.map +1 -1
- package/dist/board.js +9 -1
- package/dist/board.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/files/changes.d.ts +1 -0
- package/dist/files/changes.d.ts.map +1 -1
- package/dist/files/changes.js +1 -1
- package/dist/files/changes.js.map +1 -1
- package/dist/files/url.d.ts +2 -0
- package/dist/files/url.d.ts.map +1 -0
- package/dist/files/url.js +4 -0
- package/dist/files/url.js.map +1 -0
- package/dist/http/assets.d.ts.map +1 -1
- package/dist/http/assets.js +16 -1
- package/dist/http/assets.js.map +1 -1
- package/dist/http/identity.d.ts +7 -0
- package/dist/http/identity.d.ts.map +1 -0
- package/dist/http/identity.js +38 -0
- package/dist/http/identity.js.map +1 -0
- package/dist/http/page.d.ts +2 -1
- package/dist/http/page.d.ts.map +1 -1
- package/dist/http/page.js +29 -7
- package/dist/http/page.js.map +1 -1
- package/dist/http/search.d.ts +5 -0
- package/dist/http/search.d.ts.map +1 -0
- package/dist/http/search.js +11 -0
- package/dist/http/search.js.map +1 -0
- package/dist/http/work.d.ts +6 -0
- package/dist/http/work.d.ts.map +1 -0
- package/dist/http/work.js +22 -0
- package/dist/http/work.js.map +1 -0
- package/dist/metadata/backlinks.d.ts +8 -0
- package/dist/metadata/backlinks.d.ts.map +1 -0
- package/dist/metadata/backlinks.js +29 -0
- package/dist/metadata/backlinks.js.map +1 -0
- package/dist/metadata/fields.d.ts +29 -0
- package/dist/metadata/fields.d.ts.map +1 -0
- package/dist/metadata/fields.js +25 -0
- package/dist/metadata/fields.js.map +1 -0
- package/dist/metadata/links.d.ts +4 -0
- package/dist/metadata/links.d.ts.map +1 -0
- package/dist/metadata/links.js +18 -0
- package/dist/metadata/links.js.map +1 -0
- package/dist/metadata/locations.d.ts +3 -0
- package/dist/metadata/locations.d.ts.map +1 -0
- package/dist/metadata/locations.js +35 -0
- package/dist/metadata/locations.js.map +1 -0
- package/dist/metadata/model.d.ts +15 -0
- package/dist/metadata/model.d.ts.map +1 -0
- package/dist/metadata/model.js +13 -0
- package/dist/metadata/model.js.map +1 -0
- package/dist/metadata/parse.d.ts +16 -0
- package/dist/metadata/parse.d.ts.map +1 -0
- package/dist/metadata/parse.js +48 -0
- package/dist/metadata/parse.js.map +1 -0
- package/dist/metadata/problems.d.ts +4 -0
- package/dist/metadata/problems.d.ts.map +1 -0
- package/dist/metadata/problems.js +57 -0
- package/dist/metadata/problems.js.map +1 -0
- package/dist/metadata/relationshipLabel.d.ts +2 -0
- package/dist/metadata/relationshipLabel.d.ts.map +1 -0
- package/dist/metadata/relationshipLabel.js +13 -0
- package/dist/metadata/relationshipLabel.js.map +1 -0
- package/dist/metadata/schema.d.ts +34 -0
- package/dist/metadata/schema.d.ts.map +1 -0
- package/dist/metadata/schema.js +27 -0
- package/dist/metadata/schema.js.map +1 -0
- package/dist/metadata/sourceLinks.d.ts +5 -0
- package/dist/metadata/sourceLinks.d.ts.map +1 -0
- package/dist/metadata/sourceLinks.js +44 -0
- package/dist/metadata/sourceLinks.js.map +1 -0
- package/dist/page/backlinksHtml.d.ts +3 -0
- package/dist/page/backlinksHtml.d.ts.map +1 -0
- package/dist/page/backlinksHtml.js +16 -0
- package/dist/page/backlinksHtml.js.map +1 -0
- package/dist/page/board.d.ts +1 -1
- package/dist/page/board.d.ts.map +1 -1
- package/dist/page/board.js +14 -4
- package/dist/page/board.js.map +1 -1
- package/dist/page/client.d.ts +2 -1
- package/dist/page/client.d.ts.map +1 -1
- package/dist/page/client.js +65 -7
- package/dist/page/client.js.map +1 -1
- package/dist/page/criteriaEvidence.d.ts +4 -0
- package/dist/page/criteriaEvidence.d.ts.map +1 -0
- package/dist/page/criteriaEvidence.js +27 -0
- package/dist/page/criteriaEvidence.js.map +1 -0
- package/dist/page/diagrams.d.ts +1 -1
- package/dist/page/diagrams.d.ts.map +1 -1
- package/dist/page/diagrams.js +12 -4
- package/dist/page/diagrams.js.map +1 -1
- package/dist/page/document.d.ts +1 -1
- package/dist/page/document.d.ts.map +1 -1
- package/dist/page/document.js +6 -3
- package/dist/page/document.js.map +1 -1
- package/dist/page/libraryScript.d.ts +2 -0
- package/dist/page/libraryScript.d.ts.map +1 -0
- package/dist/page/libraryScript.js +73 -0
- package/dist/page/libraryScript.js.map +1 -0
- package/dist/page/metadata.d.ts +5 -0
- package/dist/page/metadata.d.ts.map +1 -0
- package/dist/page/metadata.js +34 -0
- package/dist/page/metadata.js.map +1 -0
- package/dist/page/metadataDetails.d.ts +4 -0
- package/dist/page/metadataDetails.d.ts.map +1 -0
- package/dist/page/metadataDetails.js +21 -0
- package/dist/page/metadataDetails.js.map +1 -0
- package/dist/page/metadataLinks.d.ts +6 -0
- package/dist/page/metadataLinks.d.ts.map +1 -0
- package/dist/page/metadataLinks.js +31 -0
- package/dist/page/metadataLinks.js.map +1 -0
- package/dist/page/nav.d.ts.map +1 -1
- package/dist/page/nav.js +3 -3
- package/dist/page/nav.js.map +1 -1
- package/dist/page/navigationScript.d.ts +2 -0
- package/dist/page/navigationScript.d.ts.map +1 -0
- package/dist/page/navigationScript.js +104 -0
- package/dist/page/navigationScript.js.map +1 -0
- package/dist/page/readingStateScript.d.ts +2 -0
- package/dist/page/readingStateScript.d.ts.map +1 -0
- package/dist/page/readingStateScript.js +62 -0
- package/dist/page/readingStateScript.js.map +1 -0
- package/dist/page/readingStyles.d.ts +2 -0
- package/dist/page/readingStyles.d.ts.map +1 -0
- package/dist/page/readingStyles.js +29 -0
- package/dist/page/readingStyles.js.map +1 -0
- package/dist/page/readingTools.d.ts +3 -0
- package/dist/page/readingTools.d.ts.map +1 -0
- package/dist/page/readingTools.js +10 -0
- package/dist/page/readingTools.js.map +1 -0
- package/dist/page/recordedEvidence.d.ts +4 -0
- package/dist/page/recordedEvidence.d.ts.map +1 -0
- package/dist/page/recordedEvidence.js +10 -0
- package/dist/page/recordedEvidence.js.map +1 -0
- package/dist/page/searchDialog.d.ts +3 -0
- package/dist/page/searchDialog.d.ts.map +1 -0
- package/dist/page/searchDialog.js +16 -0
- package/dist/page/searchDialog.js.map +1 -0
- package/dist/page/searchResultsScript.d.ts +2 -0
- package/dist/page/searchResultsScript.d.ts.map +1 -0
- package/dist/page/searchResultsScript.js +64 -0
- package/dist/page/searchResultsScript.js.map +1 -0
- package/dist/page/searchScript.d.ts +2 -0
- package/dist/page/searchScript.d.ts.map +1 -0
- package/dist/page/searchScript.js +73 -0
- package/dist/page/searchScript.js.map +1 -0
- package/dist/page/shell.d.ts +1 -1
- package/dist/page/shell.d.ts.map +1 -1
- package/dist/page/shell.js +23 -5
- package/dist/page/shell.js.map +1 -1
- package/dist/page/stateScript.d.ts +2 -0
- package/dist/page/stateScript.d.ts.map +1 -0
- package/dist/page/stateScript.js +49 -0
- package/dist/page/stateScript.js.map +1 -0
- package/dist/page/style.d.ts.map +1 -1
- package/dist/page/style.js +14 -34
- package/dist/page/style.js.map +1 -1
- package/dist/page/swap.d.ts +1 -1
- package/dist/page/swap.d.ts.map +1 -1
- package/dist/page/swap.js +4 -1
- package/dist/page/swap.js.map +1 -1
- package/dist/page/workspaceStyles.d.ts +3 -0
- package/dist/page/workspaceStyles.d.ts.map +1 -0
- package/dist/page/workspaceStyles.js +79 -0
- package/dist/page/workspaceStyles.js.map +1 -0
- package/dist/render/documentHeadings.d.ts +667 -0
- package/dist/render/documentHeadings.d.ts.map +1 -0
- package/dist/render/documentHeadings.js +45 -0
- package/dist/render/documentHeadings.js.map +1 -0
- package/dist/render/documentLinks.d.ts +659 -0
- package/dist/render/documentLinks.d.ts.map +1 -0
- package/dist/render/documentLinks.js +19 -0
- package/dist/render/documentLinks.js.map +1 -0
- package/dist/render/markdown.d.ts +7 -1
- package/dist/render/markdown.d.ts.map +1 -1
- package/dist/render/markdown.js +13 -2
- package/dist/render/markdown.js.map +1 -1
- package/dist/search/collector.d.ts +13 -0
- package/dist/search/collector.d.ts.map +1 -0
- package/dist/search/collector.js +40 -0
- package/dist/search/collector.js.map +1 -0
- package/dist/search/entries.d.ts +10 -0
- package/dist/search/entries.d.ts.map +1 -0
- package/dist/search/entries.js +37 -0
- package/dist/search/entries.js.map +1 -0
- package/dist/search/linkCollector.d.ts +8 -0
- package/dist/search/linkCollector.d.ts.map +1 -0
- package/dist/search/linkCollector.js +16 -0
- package/dist/search/linkCollector.js.map +1 -0
- package/dist/search/match.d.ts +14 -0
- package/dist/search/match.d.ts.map +1 -0
- package/dist/search/match.js +26 -0
- package/dist/search/match.js.map +1 -0
- package/dist/search/metadataEntries.d.ts +4 -0
- package/dist/search/metadataEntries.d.ts.map +1 -0
- package/dist/search/metadataEntries.js +40 -0
- package/dist/search/metadataEntries.js.map +1 -0
- package/dist/search/snapshot.d.ts +13 -0
- package/dist/search/snapshot.d.ts.map +1 -0
- package/dist/search/snapshot.js +50 -0
- package/dist/search/snapshot.js.map +1 -0
- package/dist/views/items.d.ts +11 -0
- package/dist/views/items.d.ts.map +1 -0
- package/dist/views/items.js +48 -0
- package/dist/views/items.js.map +1 -0
- package/dist/views/projection.d.ts +15 -0
- package/dist/views/projection.d.ts.map +1 -0
- package/dist/views/projection.js +47 -0
- package/dist/views/projection.js.map +1 -0
- package/dist/views/savedScript.d.ts +2 -0
- package/dist/views/savedScript.d.ts.map +1 -0
- package/dist/views/savedScript.js +89 -0
- package/dist/views/savedScript.js.map +1 -0
- package/dist/views/state.d.ts +15 -0
- package/dist/views/state.d.ts.map +1 -0
- package/dist/views/state.js +45 -0
- package/dist/views/state.js.map +1 -0
- package/dist/views/tools.d.ts +3 -0
- package/dist/views/tools.d.ts.map +1 -0
- package/dist/views/tools.js +11 -0
- package/dist/views/tools.js.map +1 -0
- package/dist/views/workCards.d.ts +4 -0
- package/dist/views/workCards.d.ts.map +1 -0
- package/dist/views/workCards.js +23 -0
- package/dist/views/workCards.js.map +1 -0
- package/dist/views/workControls.d.ts +4 -0
- package/dist/views/workControls.d.ts.map +1 -0
- package/dist/views/workControls.js +32 -0
- package/dist/views/workControls.js.map +1 -0
- package/dist/views/workDetail.d.ts +13 -0
- package/dist/views/workDetail.d.ts.map +1 -0
- package/dist/views/workDetail.js +26 -0
- package/dist/views/workDetail.js.map +1 -0
- package/dist/views/workHtml.d.ts +15 -0
- package/dist/views/workHtml.d.ts.map +1 -0
- package/dist/views/workHtml.js +35 -0
- package/dist/views/workHtml.js.map +1 -0
- package/dist/views/workStyle.d.ts +2 -0
- package/dist/views/workStyle.d.ts.map +1 -0
- package/dist/views/workStyle.js +18 -0
- package/dist/views/workStyle.js.map +1 -0
- package/dist/views/workTable.d.ts +4 -0
- package/dist/views/workTable.d.ts.map +1 -0
- package/dist/views/workTable.js +19 -0
- package/dist/views/workTable.js.map +1 -0
- package/package.json +11 -8
- package/src/board.ts +9 -1
- package/src/cli.ts +1 -1
- package/src/files/changes.ts +2 -1
- package/src/files/url.ts +3 -0
- package/src/http/assets.ts +16 -1
- package/src/http/identity.ts +62 -0
- package/src/http/page.ts +46 -9
- package/src/http/search.ts +13 -0
- package/src/http/work.ts +41 -0
- package/src/metadata/backlinks.ts +39 -0
- package/src/metadata/fields.ts +26 -0
- package/src/metadata/links.ts +19 -0
- package/src/metadata/locations.ts +34 -0
- package/src/metadata/model.ts +27 -0
- package/src/metadata/parse.ts +62 -0
- package/src/metadata/problems.ts +62 -0
- package/src/metadata/relationshipLabel.ts +13 -0
- package/src/metadata/schema.ts +36 -0
- package/src/metadata/sourceLinks.ts +46 -0
- package/src/page/backlinksHtml.ts +18 -0
- package/src/page/board.ts +14 -4
- package/src/page/client.ts +65 -7
- package/src/page/criteriaEvidence.ts +36 -0
- package/src/page/diagrams.ts +12 -4
- package/src/page/document.ts +6 -3
- package/src/page/libraryScript.ts +72 -0
- package/src/page/metadata.ts +40 -0
- package/src/page/metadataDetails.ts +24 -0
- package/src/page/metadataLinks.ts +35 -0
- package/src/page/nav.ts +5 -4
- package/src/page/navigationScript.ts +103 -0
- package/src/page/readingStateScript.ts +61 -0
- package/src/page/readingStyles.ts +28 -0
- package/src/page/readingTools.ts +12 -0
- package/src/page/recordedEvidence.ts +12 -0
- package/src/page/searchDialog.ts +16 -0
- package/src/page/searchResultsScript.ts +63 -0
- package/src/page/searchScript.ts +72 -0
- package/src/page/shell.ts +24 -5
- package/src/page/stateScript.ts +48 -0
- package/src/page/style.ts +14 -35
- package/src/page/swap.ts +4 -1
- package/src/page/workspaceStyles.ts +79 -0
- package/src/render/documentHeadings.ts +52 -0
- package/src/render/documentLinks.ts +19 -0
- package/src/render/markdown.ts +21 -4
- package/src/search/collector.ts +44 -0
- package/src/search/entries.ts +51 -0
- package/src/search/linkCollector.ts +16 -0
- package/src/search/match.ts +28 -0
- package/src/search/metadataEntries.ts +42 -0
- package/src/search/snapshot.ts +60 -0
- package/src/views/items.ts +55 -0
- package/src/views/projection.ts +59 -0
- package/src/views/savedScript.ts +88 -0
- package/src/views/state.ts +47 -0
- package/src/views/tools.ts +11 -0
- package/src/views/workCards.ts +26 -0
- package/src/views/workControls.ts +38 -0
- package/src/views/workDetail.ts +28 -0
- package/src/views/workHtml.ts +39 -0
- package/src/views/workStyle.ts +17 -0
- package/src/views/workTable.ts +21 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/src/index.ts +0 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export function savedScript() {
|
|
2
|
+
return `
|
|
3
|
+
const key = "work-board:views:" + document.documentElement.dataset.workspace;
|
|
4
|
+
let views = [];
|
|
5
|
+
let notice = "";
|
|
6
|
+
let selectedName = "";
|
|
7
|
+
const localUrl = (value) => {
|
|
8
|
+
if (typeof value !== "string" || value.length > 8192) return null;
|
|
9
|
+
try {
|
|
10
|
+
const url = new URL(value, location.href);
|
|
11
|
+
if (url.origin !== location.origin || url.pathname !== "/_board/work") return null;
|
|
12
|
+
for (const name of [...url.searchParams.keys()]) {
|
|
13
|
+
if (!["view", "board", "owner", "status", "q", "sort"].includes(name)) url.searchParams.delete(name);
|
|
14
|
+
}
|
|
15
|
+
return url.pathname + url.search;
|
|
16
|
+
} catch { return null; }
|
|
17
|
+
};
|
|
18
|
+
try {
|
|
19
|
+
const saved = JSON.parse(localStorage.getItem(key) ?? "[]");
|
|
20
|
+
if (Array.isArray(saved)) {
|
|
21
|
+
for (const entry of saved) {
|
|
22
|
+
const url = localUrl(entry?.url);
|
|
23
|
+
if (!url || typeof entry.name !== "string" || !entry.name.trim() || entry.name.length > 60 || views.some((view) => view.name === entry.name)) continue;
|
|
24
|
+
views.push({ name: entry.name, url });
|
|
25
|
+
if (views.length === 10) break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
} catch { notice = "Saved views could not be restored; new views apply to this page until saved."; }
|
|
29
|
+
const persist = () => {
|
|
30
|
+
try { localStorage.setItem(key, JSON.stringify(views)); notice = ""; }
|
|
31
|
+
catch { notice = "Saved views apply to this page only; browser storage is unavailable."; }
|
|
32
|
+
};
|
|
33
|
+
const selectedView = () => views.find((view) => view.name === document.getElementById("saved-view")?.value);
|
|
34
|
+
const showSelection = () => {
|
|
35
|
+
const open = document.getElementById("open-saved-view");
|
|
36
|
+
if (!open) return;
|
|
37
|
+
const selected = selectedView();
|
|
38
|
+
open.hidden = !selected;
|
|
39
|
+
if (selected) open.href = selected.url; else open.removeAttribute("href");
|
|
40
|
+
document.getElementById("remove-saved-view").disabled = !selected;
|
|
41
|
+
};
|
|
42
|
+
const option = (label, value) => {
|
|
43
|
+
const node = document.createElement("option");
|
|
44
|
+
node.textContent = label; node.value = value;
|
|
45
|
+
return node;
|
|
46
|
+
};
|
|
47
|
+
const refresh = (chosen) => {
|
|
48
|
+
const tools = document.getElementById("saved-work-views");
|
|
49
|
+
if (!tools) return;
|
|
50
|
+
const picker = document.getElementById("saved-view");
|
|
51
|
+
const previous = chosen ?? selectedName;
|
|
52
|
+
const labels = views.map((view) => view.name);
|
|
53
|
+
if (JSON.stringify([...picker.options].slice(1).map((option) => option.value)) !== JSON.stringify(labels)) {
|
|
54
|
+
picker.replaceChildren(option(views.length ? "Choose a saved view" : "No saved views", ""), ...views.map((view) => option(view.name, view.name)));
|
|
55
|
+
}
|
|
56
|
+
picker.value = views.some((view) => view.name === previous) ? previous : "";
|
|
57
|
+
selectedName = picker.value;
|
|
58
|
+
picker.disabled = views.length === 0;
|
|
59
|
+
tools.querySelector('#save-work-view button').disabled = false;
|
|
60
|
+
document.getElementById("clear-saved-views").disabled = views.length === 0;
|
|
61
|
+
document.getElementById("saved-view-status").textContent = notice || "Save board, filters, sort, and layout locally. Up to 10 named views; saving the same name updates it. Item selection stays in the URL.";
|
|
62
|
+
showSelection();
|
|
63
|
+
};
|
|
64
|
+
document.addEventListener("submit", (event) => {
|
|
65
|
+
if (!event.target.matches?.("#save-work-view")) return;
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
const name = document.getElementById("view-name").value.trim().slice(0, 60);
|
|
68
|
+
const url = localUrl(document.getElementById("saved-work-views").dataset.url);
|
|
69
|
+
if (!name || !url) return;
|
|
70
|
+
if (views.length === 10 && !views.some((view) => view.name === name)) {
|
|
71
|
+
notice = "You have 10 saved views. Remove one or update an existing name."; refresh(); return;
|
|
72
|
+
}
|
|
73
|
+
views = [{ name, url }, ...views.filter((view) => view.name !== name)];
|
|
74
|
+
persist(); refresh(name);
|
|
75
|
+
});
|
|
76
|
+
document.addEventListener("change", (event) => {
|
|
77
|
+
if (event.target.id === "saved-view") { selectedName = event.target.value; showSelection(); }
|
|
78
|
+
});
|
|
79
|
+
document.addEventListener("click", (event) => {
|
|
80
|
+
if (event.target.id === "remove-saved-view") views = views.filter((view) => view.name !== selectedView()?.name);
|
|
81
|
+
else if (event.target.id === "clear-saved-views") views = [];
|
|
82
|
+
else return;
|
|
83
|
+
persist(); refresh();
|
|
84
|
+
});
|
|
85
|
+
document.addEventListener("board-page", () => refresh());
|
|
86
|
+
refresh();
|
|
87
|
+
`;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=savedScript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"savedScript.js","sourceRoot":"","sources":["../../src/views/savedScript.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW;IAC1B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFP,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const State: Schema.Struct<{
|
|
3
|
+
readonly board: Schema.String;
|
|
4
|
+
readonly item: Schema.String;
|
|
5
|
+
readonly owner: Schema.String;
|
|
6
|
+
readonly query: Schema.String;
|
|
7
|
+
readonly sort: Schema.Literals<readonly ["title", "owner", "status"]>;
|
|
8
|
+
readonly status: Schema.String;
|
|
9
|
+
readonly view: Schema.Literals<readonly ["board", "table"]>;
|
|
10
|
+
}>;
|
|
11
|
+
export type State = typeof State.Type;
|
|
12
|
+
export declare function stateOf(url: string): State;
|
|
13
|
+
export declare function viewUrl(state: State, changes?: Partial<State>, hash?: string): string;
|
|
14
|
+
export declare function fieldFilter(value: string | undefined): string;
|
|
15
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/views/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIxC,eAAO,MAAM,KAAK;;;;;;;;EAQhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC;AAEtC,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAW1C;AACD,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE,OAAO,CAAC,KAAK,CAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAgBrF;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Option, Schema } from "effect";
|
|
2
|
+
const View = Schema.Literals(["board", "table"]);
|
|
3
|
+
const Sort = Schema.Literals(["title", "owner", "status"]);
|
|
4
|
+
export const State = Schema.Struct({
|
|
5
|
+
board: Schema.String,
|
|
6
|
+
item: Schema.String,
|
|
7
|
+
owner: Schema.String,
|
|
8
|
+
query: Schema.String,
|
|
9
|
+
sort: Sort,
|
|
10
|
+
status: Schema.String,
|
|
11
|
+
view: View,
|
|
12
|
+
});
|
|
13
|
+
export function stateOf(url) {
|
|
14
|
+
const params = new URL(url, "http://127.0.0.1").searchParams;
|
|
15
|
+
return {
|
|
16
|
+
board: params.get("board") ?? "",
|
|
17
|
+
item: params.get("item") ?? "",
|
|
18
|
+
owner: params.get("owner") ?? "",
|
|
19
|
+
query: (params.get("q") ?? "").slice(0, 200),
|
|
20
|
+
sort: Option.getOrElse(Schema.decodeUnknownOption(Sort)(params.get("sort")), () => "title"),
|
|
21
|
+
status: params.get("status") ?? "",
|
|
22
|
+
view: Option.getOrElse(Schema.decodeUnknownOption(View)(params.get("view")), () => "board"),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function viewUrl(state, changes = {}, hash = "") {
|
|
26
|
+
const next = { ...state, ...changes };
|
|
27
|
+
const params = new URLSearchParams({ view: next.view });
|
|
28
|
+
for (const [key, value] of Object.entries({
|
|
29
|
+
board: next.board,
|
|
30
|
+
item: next.item,
|
|
31
|
+
owner: next.owner,
|
|
32
|
+
q: next.query,
|
|
33
|
+
sort: next.sort,
|
|
34
|
+
status: next.status,
|
|
35
|
+
})) {
|
|
36
|
+
if (value) {
|
|
37
|
+
params.set(key, value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return `/_board/work?${params}${hash ? `#${hash}` : ""}`;
|
|
41
|
+
}
|
|
42
|
+
export function fieldFilter(value) {
|
|
43
|
+
return value === undefined ? "missing" : `value:${value}`;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/views/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/views/tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,YAAY,CAAC;AAEjD,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAO9C"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { escapeHtml } from "#page/escape.ts";
|
|
2
|
+
import { viewUrl } from "./state.js";
|
|
3
|
+
export function viewTools(state) {
|
|
4
|
+
const layouts = ["board", "table"];
|
|
5
|
+
return `<nav class="view-layouts" aria-label="Work layout">${layouts.map((view) => `<a href="${escapeHtml(viewUrl(state, { view }, "work-results"))}"${state.view === view ? ' aria-current="page"' : ""}>${view === "board" ? "Board" : "Table"}</a>`).join("")}</nav>
|
|
6
|
+
<section id="saved-work-views" class="saved-work-views" aria-label="Saved local views" data-url="${escapeHtml(viewUrl(state, { item: "" }))}">
|
|
7
|
+
<form id="save-work-view"><label for="view-name">View name</label><input id="view-name" maxlength="60" placeholder="Name this view" required><button type="submit" disabled>Save view</button></form>
|
|
8
|
+
<div class="view-picker"><label for="saved-view">Saved views</label><select id="saved-view" disabled><option value="">No saved views</option></select><a id="open-saved-view" hidden>Open</a><button id="remove-saved-view" type="button" disabled>Remove</button><button id="clear-saved-views" type="button" disabled>Clear all</button></div>
|
|
9
|
+
<p id="saved-view-status" role="status">Save board, filters, sort, and layout locally. Item selection stays in the URL. Saving requires JavaScript.</p></section>`;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/views/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,UAAU,SAAS,CAAC,KAAY;IACrC,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAC;IAC5C,OAAO,sDAAsD,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,cAAc,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;oGAC7J,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;;;mKAGuB,CAAC;AACpK,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workCards.d.ts","sourceRoot":"","sources":["../../src/views/workCards.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,YAAY,CAAC;AAWjD,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAYtE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { escapeHtml } from "#page/escape.ts";
|
|
2
|
+
import { viewUrl } from "./state.js";
|
|
3
|
+
function card(item, state) {
|
|
4
|
+
const fields = item.document.parsed.fields;
|
|
5
|
+
const selected = item.id === state.item;
|
|
6
|
+
return `<article class="work-card" data-key="item:${escapeHtml(item.id)}" data-item="${escapeHtml(item.id)}"${selected ? ' data-selected="true"' : ""}>
|
|
7
|
+
<p class="work-kind">${escapeHtml(fields.kind ?? "Kind not recorded")}</p>
|
|
8
|
+
<h3><a href="${escapeHtml(viewUrl(state, { item: item.id }, "work-detail"))}"${selected ? ' aria-current="true"' : ""}>${escapeHtml(item.title)}</a></h3>
|
|
9
|
+
<p class="work-id">${escapeHtml(item.id)}</p><p class="work-owner">Owner: ${escapeHtml(fields.owner ?? "Not recorded")}</p>
|
|
10
|
+
${fields.nextAction ? `<p class="work-next">Next: ${escapeHtml(fields.nextAction)}</p>` : ""}</article>`;
|
|
11
|
+
}
|
|
12
|
+
export function workCards(items, state) {
|
|
13
|
+
if (items.length === 0) {
|
|
14
|
+
return '<p class="empty">No work matches these filters.</p>';
|
|
15
|
+
}
|
|
16
|
+
const columns = Map.groupBy(items, (item) => item.document.parsed.fields.status);
|
|
17
|
+
return `<div class="work-columns">${[...columns]
|
|
18
|
+
.map(([status, rows]) => `<section class="work-column" data-key="status:${escapeHtml(status ?? "")}"
|
|
19
|
+
aria-label="${escapeHtml(status ?? "Status not recorded")}"><h2>${escapeHtml(status ?? "Status not recorded")} <span class="work-count">${rows.length}</span></h2>
|
|
20
|
+
${rows.map((item) => card(item, state)).join("")}</section>`)
|
|
21
|
+
.join("")}</div>`;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=workCards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workCards.js","sourceRoot":"","sources":["../../src/views/workCards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD,SAAS,IAAI,CAAC,IAAU,EAAE,KAAY;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC;IACxC,OAAO,6CAA6C,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE;wBAC9H,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,mBAAmB,CAAC;gBACtD,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;sBAC1H,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,oCAAoC,UAAU,CAAC,MAAM,CAAC,KAAK,IAAI,cAAc,CAAC;GACpH,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,8BAA8B,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;AAC1G,CAAC;AACD,MAAM,UAAU,SAAS,CAAC,KAAsB,EAAE,KAAY;IAC7D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,qDAAqD,CAAC;IAC9D,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACjF,OAAO,6BAA6B,CAAC,GAAG,OAAO,CAAC;SAC9C,GAAG,CACH,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,iDAAiD,UAAU,CAAC,MAAM,IAAI,EAAE,CAAC;eACjF,UAAU,CAAC,MAAM,IAAI,qBAAqB,CAAC,SAAS,UAAU,CAAC,MAAM,IAAI,qBAAqB,CAAC,6BAA6B,IAAI,CAAC,MAAM;GACnJ,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAC1D;SACA,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workControls.d.ts","sourceRoot":"","sources":["../../src/views/workControls.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAe,KAAK,KAAK,EAAW,MAAM,YAAY,CAAC;AAuB9D,wBAAgB,YAAY,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAWzE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { escapeHtml } from "#page/escape.ts";
|
|
2
|
+
import { fieldFilter, viewUrl } from "./state.js";
|
|
3
|
+
function option(value, title, current) {
|
|
4
|
+
return `<option value="${escapeHtml(value)}"${value === current ? " selected" : ""}>${escapeHtml(title)}</option>`;
|
|
5
|
+
}
|
|
6
|
+
function fieldOptions(items, field, current) {
|
|
7
|
+
const values = new Map(items.map((item) => {
|
|
8
|
+
const value = item.document.parsed.fields[field];
|
|
9
|
+
return [fieldFilter(value), value ?? `${field === "owner" ? "Owner" : "Status"} not recorded`];
|
|
10
|
+
}));
|
|
11
|
+
if (current && !values.has(current)) {
|
|
12
|
+
values.set(current, `${current.startsWith("value:") ? current.slice(6) : current} (no current matches)`);
|
|
13
|
+
}
|
|
14
|
+
return (option("", `All ${field === "owner" ? "owners" : "statuses"}`, current)
|
|
15
|
+
+ [...values]
|
|
16
|
+
.sort((a, b) => a[1].localeCompare(b[1], "en"))
|
|
17
|
+
.map(([value, label]) => option(value, label, current))
|
|
18
|
+
.join(""));
|
|
19
|
+
}
|
|
20
|
+
export function workControls(projection, state) {
|
|
21
|
+
const boards = option("", "All work", state.board) + projection.boards.map((board) => option(board.id, board.title, state.board)).join("");
|
|
22
|
+
const unavailable = state.board && !projection.validBoard ? option(state.board, `${state.board} (unavailable)`, state.board) : "";
|
|
23
|
+
return `<form id="work-filters" class="work-filters" action="/_board/work#work-results" method="get">
|
|
24
|
+
<input type="hidden" name="view" value="${state.view}"><input type="hidden" name="item" value="${escapeHtml(state.item)}">
|
|
25
|
+
<label><span>Board</span><select name="board" id="work-board">${boards}${unavailable}</select></label>
|
|
26
|
+
<label><span>Status</span><select name="status" id="work-status">${fieldOptions(projection.items, "status", state.status)}</select></label>
|
|
27
|
+
<label><span>Owner</span><select name="owner" id="work-owner">${fieldOptions(projection.items, "owner", state.owner)}</select></label>
|
|
28
|
+
<label><span>Find work</span><input name="q" id="work-query" type="search" value="${escapeHtml(state.query)}" maxlength="200"></label>
|
|
29
|
+
<label><span>Sort by</span><select name="sort" id="work-sort">${["title", "owner", "status"].map((sort) => option(sort, sort.charAt(0).toUpperCase() + sort.slice(1), state.sort)).join("")}</select></label>
|
|
30
|
+
<button type="submit">Apply</button><a href="${escapeHtml(viewUrl(state, { owner: "", query: "", status: "" }, "work-results"))}">Clear filters</a></form>`;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=workControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workControls.js","sourceRoot":"","sources":["../../src/views/workControls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,WAAW,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAE9D,SAAS,MAAM,CAAC,KAAa,EAAE,KAAa,EAAE,OAAe;IAC5D,OAAO,kBAAkB,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC;AACpH,CAAC;AACD,SAAS,YAAY,CAAC,KAAsB,EAAE,KAAyB,EAAE,OAAe;IACvF,MAAM,MAAM,GAAG,IAAI,GAAG,CACrB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjD,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,GAAG,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,eAAe,CAAC,CAAC;IAChG,CAAC,CAAC,CACF,CAAC;IACF,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,CACN,MAAM,CAAC,EAAE,EAAE,OAAO,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC;UACrE,CAAC,GAAG,MAAM,CAAC;aACX,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;aAC9C,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;aACtD,IAAI,CAAC,EAAE,CAAC,CACV,CAAC;AACH,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,UAAsB,EAAE,KAAY;IAChE,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3I,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,gBAAgB,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClI,OAAO;2CACmC,KAAK,CAAC,IAAI,6CAA6C,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;iEACvD,MAAM,GAAG,WAAW;oEACjB,YAAY,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;iEACzD,YAAY,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC;qFAChC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC;iEAC3C,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gDAC5I,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC,4BAA4B,CAAC;AAC7J,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { Snapshot } from "#search/snapshot.ts";
|
|
3
|
+
import type { Projection } from "./projection.ts";
|
|
4
|
+
export declare const workDetail: (projection: Projection, state: {
|
|
5
|
+
readonly board: string;
|
|
6
|
+
readonly item: string;
|
|
7
|
+
readonly owner: string;
|
|
8
|
+
readonly query: string;
|
|
9
|
+
readonly sort: "owner" | "status" | "title";
|
|
10
|
+
readonly status: string;
|
|
11
|
+
readonly view: "board" | "table";
|
|
12
|
+
}, snapshot: Snapshot) => Effect.Effect<string, import("../render/failed.ts").RenderFailed, import("../render/highlighter.ts").Highlighter>;
|
|
13
|
+
//# sourceMappingURL=workDetail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workDetail.d.ts","sourceRoot":"","sources":["../../src/views/workDetail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMhC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,eAAO,MAAM,UAAU;;;;;;;;2IAiBrB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { identityUrl } from "#metadata/links.ts";
|
|
3
|
+
import { escapeHtml } from "#page/escape.ts";
|
|
4
|
+
import { metadataHtml } from "#page/metadata.ts";
|
|
5
|
+
import { documentHeadings } from "#render/documentHeadings.ts";
|
|
6
|
+
import { renderMarkdown } from "#render/markdown.ts";
|
|
7
|
+
import { viewUrl } from "./state.js";
|
|
8
|
+
export const workDetail = Effect.fn("WorkBoard.workDetail")(function* (projection, state, snapshot) {
|
|
9
|
+
if (!state.item) {
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
const close = `<a class="detail-close" href="${escapeHtml(viewUrl(state, { item: "" }, "work-results"))}">Close detail</a>`;
|
|
13
|
+
const selected = projection.selected;
|
|
14
|
+
if (!selected) {
|
|
15
|
+
const ambiguous = (snapshot.model.ids.get(state.item)?.length ?? 0) > 1;
|
|
16
|
+
return `<aside id="work-detail" class="work-detail" tabindex="-1" aria-label="Selected work">${close}<h2>Item unavailable</h2><p>${escapeHtml(state.item)} ${ambiguous ? "has a duplicate ID" : "is missing or its identity changed"}. No source was selected.</p><a href="${escapeHtml(identityUrl(state.item))}">Inspect item identity</a></aside>`;
|
|
17
|
+
}
|
|
18
|
+
const { document } = selected;
|
|
19
|
+
const prose = yield* renderMarkdown(document.parsed.body, { file: document.file, headings: documentHeadings() });
|
|
20
|
+
return `<aside id="work-detail" class="work-detail" data-key="detail:${escapeHtml(selected.id)}" tabindex="-1" aria-label="Selected work">
|
|
21
|
+
<header>${close}<a href="${escapeHtml(identityUrl(selected.id))}">Open document</a></header>
|
|
22
|
+
${projection.selectedOutside ? '<p class="detail-notice" role="status">This selected item is outside the current board or filters.</p>' : ""}
|
|
23
|
+
<p class="meta">Source: ${escapeHtml(document.file)}</p>${metadataHtml(document.parsed, document.file, snapshot.model)}
|
|
24
|
+
<article class="doc">${prose}</article></aside>`;
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=workDetail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workDetail.js","sourceRoot":"","sources":["../../src/views/workDetail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,QAAQ,CAAC,EAAE,UAAsB,EAAE,KAAY,EAAE,QAAkB;IAC9H,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACX,CAAC;IACD,MAAM,KAAK,GAAG,iCAAiC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC,oBAAoB,CAAC;IAC5H,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;IACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACxE,OAAO,wFAAwF,KAAK,+BAA+B,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,oCAAoC,yCAAyC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,qCAAqC,CAAC;IACvV,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACjH,OAAO,gEAAgE,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;WACpF,KAAK,YAAY,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;GAC7D,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,wGAAwG,CAAC,CAAC,CAAC,EAAE;2BAClH,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC;wBAC/F,KAAK,oBAAoB,CAAC;AAClD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { Snapshot } from "#search/snapshot.ts";
|
|
3
|
+
export declare const workHtml: (snapshot: Snapshot, state: {
|
|
4
|
+
readonly board: string;
|
|
5
|
+
readonly item: string;
|
|
6
|
+
readonly owner: string;
|
|
7
|
+
readonly query: string;
|
|
8
|
+
readonly sort: "owner" | "status" | "title";
|
|
9
|
+
readonly status: string;
|
|
10
|
+
readonly view: "board" | "table";
|
|
11
|
+
}) => Effect.Effect<{
|
|
12
|
+
html: string;
|
|
13
|
+
status: number;
|
|
14
|
+
}, import("../render/failed.ts").RenderFailed, import("../render/highlighter.ts").Highlighter>;
|
|
15
|
+
//# sourceMappingURL=workHtml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workHtml.d.ts","sourceRoot":"","sources":["../../src/views/workHtml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AASpD,eAAO,MAAM,QAAQ;;;;;;;;;;;8FA0BnB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { identityUrl } from "#metadata/links.ts";
|
|
3
|
+
import { escapeHtml } from "#page/escape.ts";
|
|
4
|
+
import { projectItems } from "./projection.js";
|
|
5
|
+
import { viewTools } from "./tools.js";
|
|
6
|
+
import { workCards } from "./workCards.js";
|
|
7
|
+
import { workControls } from "./workControls.js";
|
|
8
|
+
import { workDetail } from "./workDetail.js";
|
|
9
|
+
import { workTable } from "./workTable.js";
|
|
10
|
+
export const workHtml = Effect.fn("WorkBoard.workHtml")(function* (snapshot, state) {
|
|
11
|
+
const projection = projectItems(snapshot, state);
|
|
12
|
+
const controls = workControls(projection, state);
|
|
13
|
+
const tools = viewTools(state);
|
|
14
|
+
if (!projection.validBoard) {
|
|
15
|
+
return {
|
|
16
|
+
html: `<h1>Board unavailable</h1>${tools}${controls}<p class="empty">${escapeHtml(state.board)} is missing, has a duplicate ID, or is not a declared board. Choose another board or open its <a href="${escapeHtml(identityUrl(state.board))}">source identity</a>.</p>`,
|
|
17
|
+
status: 404,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const issues = projection.issues.length > 0
|
|
21
|
+
? `<details class="view-issues"><summary>Source issues (${projection.issues.length})</summary><ul>${projection.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("")}</ul></details>`
|
|
22
|
+
: "";
|
|
23
|
+
const source = state.board ? `<a href="${escapeHtml(identityUrl(state.board))}">Board source</a>` : "";
|
|
24
|
+
const empty = projection.items.length === 0
|
|
25
|
+
? '<p class="empty">No identified work is declared here. Keep reading ordinary files, or add item IDs and explicit board membership in their Markdown sources.</p>'
|
|
26
|
+
: "";
|
|
27
|
+
const detail = yield* workDetail(projection, state, snapshot);
|
|
28
|
+
return {
|
|
29
|
+
html: `<header class="work-head"><p class="work-eyebrow">WORK · ${state.view.toUpperCase()} VIEW</p><h1>${escapeHtml(projection.title)}</h1><p>Views use recorded fields. A section heading does not set an item's status.</p>${source}</header>
|
|
30
|
+
${tools}${controls}${issues}<p class="work-total" role="status">${projection.rows.length} shown · ${projection.items.length} items in this view</p>
|
|
31
|
+
<div class="work-layout${state.item ? " has-detail" : ""}"><section id="work-results" tabindex="-1" aria-label="Work items">${empty}${state.view === "table" ? workTable(projection.rows, state) : workCards(projection.rows, state)}</section>${detail}</div>`,
|
|
32
|
+
status: 200,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=workHtml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workHtml.js","sourceRoot":"","sources":["../../src/views/workHtml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAkB,EAAE,KAAY;IAClG,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;QAC5B,OAAO;YACN,IAAI,EAAE,6BAA6B,KAAK,GAAG,QAAQ,oBAAoB,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,0GAA0G,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,4BAA4B;YACxQ,MAAM,EAAE,GAAG;SACX,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GACX,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAC3B,CAAC,CAAC,wDAAwD,UAAU,CAAC,MAAM,CAAC,MAAM,kBAAkB,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,iBAAiB;QAC/L,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;IACvG,MAAM,KAAK,GACV,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAC5B,CAAC,CAAC,iKAAiK;QACnK,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC9D,OAAO;QACN,IAAI,EAAE,4DAA4D,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,0FAA0F,MAAM;GACrO,KAAK,GAAG,QAAQ,GAAG,MAAM,uCAAuC,UAAU,CAAC,IAAI,CAAC,MAAM,YAAY,UAAU,CAAC,KAAK,CAAC,MAAM;0BAClG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,sEAAsE,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,MAAM,QAAQ;QAC9P,MAAM,EAAE,GAAG;KACX,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workStyle.d.ts","sourceRoot":"","sources":["../../src/views/workStyle.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,IAAI,MAAM,CAgBlC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function workStyle() {
|
|
2
|
+
return `
|
|
3
|
+
.work-head h1{margin:0 0 8px}.work-eyebrow{font:11px var(--mono);letter-spacing:.12em;color:var(--muted);margin:0 0 12px}.work-head>p:not(.work-eyebrow){color:var(--muted);font-size:.9rem;margin:0 0 12px}
|
|
4
|
+
.work-filters{display:flex;flex-wrap:wrap;gap:12px;align-items:end;margin:24px 0 16px;padding:16px;border:1px solid var(--border);border-radius:10px;background:var(--surface)}
|
|
5
|
+
.work-filters label{display:grid;gap:5px;font-size:12px;color:var(--muted);flex:1 1 130px;min-width:0}.work-filters input,.work-filters select{width:100%;min-width:0;font:inherit;font-size:14px;color:var(--text);background:var(--card);border:1px solid var(--border);border-radius:5px;padding:8px}
|
|
6
|
+
.work-filters button{font:inherit;color:var(--text);background:var(--card);border:1px solid var(--border);border-radius:5px;padding:8px 12px}.work-filters>a{font-size:13px;padding:8px 0}.work-total{font-size:13px;color:var(--muted);margin:0 0 20px}
|
|
7
|
+
.work-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:24px;align-items:start}.work-layout.has-detail{grid-template-columns:minmax(0,1fr) minmax(300px,420px)}
|
|
8
|
+
.work-columns{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:16px}.work-column{min-width:0}.work-column>h2{display:flex;justify-content:space-between;gap:12px;margin:0 0 12px;font-size:14px;overflow-wrap:anywhere}.work-count{font:12px var(--mono);color:var(--muted)}
|
|
9
|
+
.work-card{padding:var(--card-space);margin-bottom:12px;border:1px solid var(--border);border-radius:10px;background:var(--card);overflow-wrap:anywhere}.work-card[data-selected="true"]{border-color:var(--link);box-shadow:0 0 0 1px var(--link)}.work-card h3{font-size:1rem;margin:6px 0}.work-card h3 a{text-decoration:none}.work-kind{font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:0}.work-id{font:11px var(--mono);color:var(--muted);margin:0 0 12px}.work-owner,.work-next{font-size:13px;margin:0 0 8px}.work-card>:last-child{margin-bottom:0}
|
|
10
|
+
.work-detail{position:sticky;top:24px;max-height:calc(100vh - 48px);overflow:auto;min-width:0;padding:20px;border:1px solid var(--border);border-radius:12px;background:var(--card);scroll-margin-top:20px}.work-detail>header{display:flex;justify-content:space-between;gap:16px;font-size:13px;margin:0 0 16px}.work-detail .work-meta{padding:12px;font-size:13px}.work-detail .doc{font-size:.9rem}.work-detail .doc h1{font-size:1.5rem}.detail-notice{padding:10px;background:var(--surface);font-size:13px}.view-issues{margin:0 0 16px;padding:12px;background:var(--surface);border-radius:8px;font-size:13px;overflow-wrap:anywhere}
|
|
11
|
+
.work-open{font-size:13px;white-space:nowrap}.work-open[aria-current="page"]{font-weight:700;text-decoration:underline}#work-results{scroll-margin-top:20px}
|
|
12
|
+
.view-layouts{display:flex;gap:6px;margin:20px 0 12px}.view-layouts a{padding:5px 14px;border:1px solid var(--border);border-radius:6px;text-decoration:none;font-size:13px}.view-layouts a[aria-current="page"]{background:var(--surface);font-weight:600}
|
|
13
|
+
.saved-work-views{display:flex;flex-wrap:wrap;gap:12px 24px;align-items:center;font-size:12px}.saved-work-views form,.view-picker{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-width:0}.saved-work-views input,.saved-work-views select{min-width:0;max-width:100%;padding:6px 10px;font:inherit;border:1px solid var(--border);border-radius:6px;background:var(--card);color:var(--text)}.saved-work-views>p{flex-basis:100%;margin:0;color:var(--muted)}
|
|
14
|
+
.work-table-wrap{max-width:100%;overflow:auto}.work-table{display:table;width:100%;margin:0;font-size:13px;background:var(--card)}.work-table th,.work-table td{padding:calc(var(--card-space)/2);overflow-wrap:anywhere;min-width:100px}.work-table th{font-weight:500}.work-table tbody th{min-width:160px}.work-table .work-id{display:block;margin:6px 0 0}.work-table tr[data-selected="true"]>*{background:var(--surface);box-shadow:inset 0 -2px var(--link)}
|
|
15
|
+
@media(max-width:1000px){.work-layout.has-detail{grid-template-columns:minmax(0,1fr)}.work-detail{position:static;max-height:none;grid-row:1}.work-filters{padding:12px;gap:10px}}
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=workStyle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workStyle.js","sourceRoot":"","sources":["../../src/views/workStyle.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS;IACxB,OAAO;;;;;;;;;;;;;;CAcP,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workTable.d.ts","sourceRoot":"","sources":["../../src/views/workTable.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,YAAY,CAAC;AAWjD,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAOtE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { escapeHtml } from "#page/escape.ts";
|
|
2
|
+
import { viewUrl } from "./state.js";
|
|
3
|
+
function row(item, state) {
|
|
4
|
+
const fields = item.document.parsed.fields;
|
|
5
|
+
const selected = item.id === state.item;
|
|
6
|
+
const values = [fields.kind, fields.status, fields.owner, fields.nextAction];
|
|
7
|
+
return `<tr data-item="${escapeHtml(item.id)}"${selected ? ' data-selected="true"' : ""}>
|
|
8
|
+
<th scope="row"><a href="${escapeHtml(viewUrl(state, { item: item.id }, "work-detail"))}"${selected ? ' aria-current="true"' : ""}>${escapeHtml(item.title)}</a><span class="work-id">${escapeHtml(item.id)}</span></th>
|
|
9
|
+
${values.map((value) => `<td>${escapeHtml(value ?? "Not recorded")}</td>`).join("")}</tr>`;
|
|
10
|
+
}
|
|
11
|
+
export function workTable(items, state) {
|
|
12
|
+
if (items.length === 0) {
|
|
13
|
+
return '<p class="empty">No work matches these filters.</p>';
|
|
14
|
+
}
|
|
15
|
+
return `<div class="work-table-wrap"><table class="work-table"><caption class="sr-only">Identified work, sorted by ${escapeHtml(state.sort)}</caption>
|
|
16
|
+
<thead><tr>${["Work", "Kind", "Status", "Owner", "Next action"].map((title) => `<th scope="col">${title}</th>`).join("")}</tr></thead>
|
|
17
|
+
<tbody>${items.map((item) => row(item, state)).join("")}</tbody></table></div>`;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=workTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workTable.js","sourceRoot":"","sources":["../../src/views/workTable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAc,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD,SAAS,GAAG,CAAC,IAAU,EAAE,KAAY;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7E,OAAO,kBAAkB,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE;4BAC5D,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,aAAa,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,6BAA6B,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;GACzM,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;AAC5F,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAsB,EAAE,KAAY;IAC7D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,qDAAqD,CAAC;IAC9D,CAAC;IACD,OAAO,8GAA8G,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;cAC9H,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,mBAAmB,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;UAC/G,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,wBAAwB,CAAC;AACjF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/work-board",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Serve a folder of markdown files as a live local page that updates in place when a file changes",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/work-board#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"exports": {
|
|
26
|
-
"
|
|
27
|
-
"types": "./dist
|
|
28
|
-
"source": "./src
|
|
29
|
-
"import": "./dist
|
|
30
|
-
"default": "./dist
|
|
26
|
+
"./*.ts": {
|
|
27
|
+
"types": "./dist/*.d.ts",
|
|
28
|
+
"source": "./src/*.ts",
|
|
29
|
+
"import": "./dist/*.js",
|
|
30
|
+
"default": "./dist/*.js"
|
|
31
31
|
},
|
|
32
32
|
"./package.json": "./package.json"
|
|
33
33
|
},
|
|
@@ -37,18 +37,21 @@
|
|
|
37
37
|
"files": [
|
|
38
38
|
"dist",
|
|
39
39
|
"src",
|
|
40
|
+
"!src/**/*.test.ts",
|
|
41
|
+
"!src/**/*.spec.ts",
|
|
40
42
|
"CHANGELOG.md",
|
|
41
43
|
"README.md"
|
|
42
44
|
],
|
|
43
45
|
"dependencies": {
|
|
44
46
|
"mermaid": "11.16.1",
|
|
45
47
|
"satteri": "0.9.5",
|
|
46
|
-
"shiki": "4.4.2"
|
|
48
|
+
"shiki": "4.4.2",
|
|
49
|
+
"yaml": "2.9.0"
|
|
47
50
|
},
|
|
48
51
|
"devDependencies": {
|
|
49
52
|
"@effect/platform-node": "4.0.0-rc.112",
|
|
50
53
|
"@effect/platform-node-shared": "4.0.0-rc.112",
|
|
51
|
-
"@shivaedev/quality": "0.
|
|
54
|
+
"@shivaedev/quality": "0.9.0",
|
|
52
55
|
"@types/hast": "3.0.5",
|
|
53
56
|
"@types/mdast": "4.0.4",
|
|
54
57
|
"@types/node": "24.10.1",
|
package/src/board.ts
CHANGED
|
@@ -4,11 +4,15 @@ import { watchChanges } from "#files/changes.ts";
|
|
|
4
4
|
import { type HomeMissing, homeIn } from "#files/home.ts";
|
|
5
5
|
import { ASSETS, MERMAID_ROUTE, type MermaidMissing, mermaidFile, mermaidRoot } from "#http/assets.ts";
|
|
6
6
|
import { events } from "#http/events.ts";
|
|
7
|
+
import { identity } from "#http/identity.ts";
|
|
7
8
|
import { loopbackOnly } from "#http/loopback.ts";
|
|
8
9
|
import { page } from "#http/page.ts";
|
|
9
10
|
import { respond } from "#http/respond.ts";
|
|
11
|
+
import { search } from "#http/search.ts";
|
|
12
|
+
import { work } from "#http/work.ts";
|
|
10
13
|
import type { RenderFailed } from "#render/failed.ts";
|
|
11
14
|
import { Highlighter } from "#render/highlighter.ts";
|
|
15
|
+
import { searchSnapshot } from "#search/snapshot.ts";
|
|
12
16
|
|
|
13
17
|
export interface BoardOptions {
|
|
14
18
|
readonly home?: string | undefined;
|
|
@@ -32,11 +36,15 @@ const routes = (options: BoardOptions) =>
|
|
|
32
36
|
loopbackOnly((request) => Effect.provideContext(handler(request), context)),
|
|
33
37
|
);
|
|
34
38
|
yield* serve("/events", events(changes));
|
|
39
|
+
const index = yield* searchSnapshot(options.root, home, changes);
|
|
40
|
+
yield* serve("/_board/search", search(index));
|
|
41
|
+
yield* serve("/_board/work", work(index, changes, home));
|
|
35
42
|
for (const [route, body, contentType] of ASSETS) {
|
|
36
43
|
yield* serve(route, () => Effect.succeed(respond(body, contentType)));
|
|
37
44
|
}
|
|
38
45
|
yield* serve(MERMAID_ROUTE, mermaidFile(mermaid));
|
|
39
|
-
const pages = page({ home, root: options.root }, changes);
|
|
46
|
+
const pages = page({ home, root: options.root }, changes, index);
|
|
47
|
+
yield* serve("/_board/item/*", identity(index, pages, changes, home));
|
|
40
48
|
yield* serve("/", pages);
|
|
41
49
|
yield* serve("/*", pages);
|
|
42
50
|
}),
|
package/src/cli.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Effect, Layer, Option, Path } from "effect";
|
|
|
4
4
|
import { Argument, Command, Flag } from "effect/unstable/cli";
|
|
5
5
|
import { HOST, serveBoard } from "./serve.ts";
|
|
6
6
|
|
|
7
|
-
const VERSION = "0.
|
|
7
|
+
const VERSION = "0.3.0";
|
|
8
8
|
|
|
9
9
|
const serve = Effect.fn("WorkBoard.serve")(function* (input: { readonly dir: string; readonly port: number; readonly home: Option.Option<string> }) {
|
|
10
10
|
const path = yield* Path.Path;
|
package/src/files/changes.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface Changes {
|
|
|
7
7
|
readonly events: PubSub.PubSub<Change>;
|
|
8
8
|
readonly files: Effect.Effect<readonly MarkdownFile[], PlatformError.PlatformError>;
|
|
9
9
|
readonly realRoot: string;
|
|
10
|
+
readonly revision: Effect.Effect<number>;
|
|
10
11
|
readonly watching: Ref.Ref<boolean>;
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -66,6 +67,6 @@ export const watchChanges = Effect.fn("WorkBoard.watchChanges")(function* (root:
|
|
|
66
67
|
yield* Ref.set(cached, Option.some({ files: listed, generation: now }));
|
|
67
68
|
return listed;
|
|
68
69
|
});
|
|
69
|
-
const changes: Changes = { events, files, realRoot, watching };
|
|
70
|
+
const changes: Changes = { events, files, realRoot, revision: Ref.get(generation), watching };
|
|
70
71
|
return changes;
|
|
71
72
|
});
|
package/src/files/url.ts
ADDED