@shivaedev/work-board 0.2.1 → 0.4.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.
Files changed (420) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +208 -11
  3. package/dist/attention/overviewHtml.d.ts +3 -0
  4. package/dist/attention/overviewHtml.d.ts.map +1 -0
  5. package/dist/attention/overviewHtml.js +41 -0
  6. package/dist/attention/overviewHtml.js.map +1 -0
  7. package/dist/attention/requests.d.ts +24 -0
  8. package/dist/attention/requests.d.ts.map +1 -0
  9. package/dist/attention/requests.js +40 -0
  10. package/dist/attention/requests.js.map +1 -0
  11. package/dist/attention/style.d.ts +2 -0
  12. package/dist/attention/style.d.ts.map +1 -0
  13. package/dist/attention/style.js +10 -0
  14. package/dist/attention/style.js.map +1 -0
  15. package/dist/board.d.ts.map +1 -1
  16. package/dist/board.js +15 -2
  17. package/dist/board.js.map +1 -1
  18. package/dist/cli.js +1 -1
  19. package/dist/files/changes.d.ts +1 -0
  20. package/dist/files/changes.d.ts.map +1 -1
  21. package/dist/files/changes.js +5 -10
  22. package/dist/files/changes.js.map +1 -1
  23. package/dist/files/home.d.ts.map +1 -1
  24. package/dist/files/home.js +4 -0
  25. package/dist/files/home.js.map +1 -1
  26. package/dist/files/list.d.ts +7 -0
  27. package/dist/files/list.d.ts.map +1 -1
  28. package/dist/files/list.js +23 -13
  29. package/dist/files/list.js.map +1 -1
  30. package/dist/files/markdownPath.d.ts +3 -0
  31. package/dist/files/markdownPath.d.ts.map +1 -0
  32. package/dist/files/markdownPath.js +31 -0
  33. package/dist/files/markdownPath.js.map +1 -0
  34. package/dist/files/url.d.ts +2 -0
  35. package/dist/files/url.d.ts.map +1 -0
  36. package/dist/files/url.js +4 -0
  37. package/dist/files/url.js.map +1 -0
  38. package/dist/files/watchDirectories.d.ts +9 -0
  39. package/dist/files/watchDirectories.d.ts.map +1 -0
  40. package/dist/files/watchDirectories.js +33 -0
  41. package/dist/files/watchDirectories.js.map +1 -0
  42. package/dist/history/baseline.d.ts +19 -0
  43. package/dist/history/baseline.d.ts.map +1 -0
  44. package/dist/history/baseline.js +40 -0
  45. package/dist/history/baseline.js.map +1 -0
  46. package/dist/history/compare.d.ts +14 -0
  47. package/dist/history/compare.d.ts.map +1 -0
  48. package/dist/history/compare.js +47 -0
  49. package/dist/history/compare.js.map +1 -0
  50. package/dist/history/documents.d.ts +10 -0
  51. package/dist/history/documents.d.ts.map +1 -0
  52. package/dist/history/documents.js +15 -0
  53. package/dist/history/documents.js.map +1 -0
  54. package/dist/history/fields.d.ts +3 -0
  55. package/dist/history/fields.d.ts.map +1 -0
  56. package/dist/history/fields.js +27 -0
  57. package/dist/history/fields.js.map +1 -0
  58. package/dist/history/html.d.ts +4 -0
  59. package/dist/history/html.d.ts.map +1 -0
  60. package/dist/history/html.js +22 -0
  61. package/dist/history/html.js.map +1 -0
  62. package/dist/history/limits.d.ts +3 -0
  63. package/dist/history/limits.d.ts.map +1 -0
  64. package/dist/history/limits.js +3 -0
  65. package/dist/history/limits.js.map +1 -0
  66. package/dist/history/response.d.ts +4 -0
  67. package/dist/history/response.d.ts.map +1 -0
  68. package/dist/history/response.js +20 -0
  69. package/dist/history/response.js.map +1 -0
  70. package/dist/history/schema.d.ts +24 -0
  71. package/dist/history/schema.d.ts.map +1 -0
  72. package/dist/history/schema.js +19 -0
  73. package/dist/history/schema.js.map +1 -0
  74. package/dist/history/script.d.ts +2 -0
  75. package/dist/history/script.d.ts.map +1 -0
  76. package/dist/history/script.js +113 -0
  77. package/dist/history/script.js.map +1 -0
  78. package/dist/http/assets.d.ts.map +1 -1
  79. package/dist/http/assets.js +18 -1
  80. package/dist/http/assets.js.map +1 -1
  81. package/dist/http/history.d.ts +7 -0
  82. package/dist/http/history.d.ts.map +1 -0
  83. package/dist/http/history.js +45 -0
  84. package/dist/http/history.js.map +1 -0
  85. package/dist/http/identity.d.ts +7 -0
  86. package/dist/http/identity.d.ts.map +1 -0
  87. package/dist/http/identity.js +38 -0
  88. package/dist/http/identity.js.map +1 -0
  89. package/dist/http/overview.d.ts +5 -0
  90. package/dist/http/overview.d.ts.map +1 -0
  91. package/dist/http/overview.js +13 -0
  92. package/dist/http/overview.js.map +1 -0
  93. package/dist/http/page.d.ts +3 -2
  94. package/dist/http/page.d.ts.map +1 -1
  95. package/dist/http/page.js +34 -13
  96. package/dist/http/page.js.map +1 -1
  97. package/dist/http/search.d.ts +5 -0
  98. package/dist/http/search.d.ts.map +1 -0
  99. package/dist/http/search.js +11 -0
  100. package/dist/http/search.js.map +1 -0
  101. package/dist/http/work.d.ts +6 -0
  102. package/dist/http/work.d.ts.map +1 -0
  103. package/dist/http/work.js +22 -0
  104. package/dist/http/work.js.map +1 -0
  105. package/dist/metadata/attentionProblems.d.ts +4 -0
  106. package/dist/metadata/attentionProblems.d.ts.map +1 -0
  107. package/dist/metadata/attentionProblems.js +16 -0
  108. package/dist/metadata/attentionProblems.js.map +1 -0
  109. package/dist/metadata/backlinks.d.ts +8 -0
  110. package/dist/metadata/backlinks.d.ts.map +1 -0
  111. package/dist/metadata/backlinks.js +34 -0
  112. package/dist/metadata/backlinks.js.map +1 -0
  113. package/dist/metadata/fields.d.ts +37 -0
  114. package/dist/metadata/fields.d.ts.map +1 -0
  115. package/dist/metadata/fields.js +25 -0
  116. package/dist/metadata/fields.js.map +1 -0
  117. package/dist/metadata/links.d.ts +4 -0
  118. package/dist/metadata/links.d.ts.map +1 -0
  119. package/dist/metadata/links.js +18 -0
  120. package/dist/metadata/links.js.map +1 -0
  121. package/dist/metadata/locations.d.ts +3 -0
  122. package/dist/metadata/locations.d.ts.map +1 -0
  123. package/dist/metadata/locations.js +35 -0
  124. package/dist/metadata/locations.js.map +1 -0
  125. package/dist/metadata/model.d.ts +15 -0
  126. package/dist/metadata/model.d.ts.map +1 -0
  127. package/dist/metadata/model.js +13 -0
  128. package/dist/metadata/model.js.map +1 -0
  129. package/dist/metadata/parse.d.ts +16 -0
  130. package/dist/metadata/parse.d.ts.map +1 -0
  131. package/dist/metadata/parse.js +48 -0
  132. package/dist/metadata/parse.js.map +1 -0
  133. package/dist/metadata/problems.d.ts +4 -0
  134. package/dist/metadata/problems.d.ts.map +1 -0
  135. package/dist/metadata/problems.js +59 -0
  136. package/dist/metadata/problems.js.map +1 -0
  137. package/dist/metadata/relationshipLabel.d.ts +2 -0
  138. package/dist/metadata/relationshipLabel.d.ts.map +1 -0
  139. package/dist/metadata/relationshipLabel.js +14 -0
  140. package/dist/metadata/relationshipLabel.js.map +1 -0
  141. package/dist/metadata/schema.d.ts +44 -0
  142. package/dist/metadata/schema.d.ts.map +1 -0
  143. package/dist/metadata/schema.js +36 -0
  144. package/dist/metadata/schema.js.map +1 -0
  145. package/dist/metadata/sourceLinks.d.ts +5 -0
  146. package/dist/metadata/sourceLinks.d.ts.map +1 -0
  147. package/dist/metadata/sourceLinks.js +44 -0
  148. package/dist/metadata/sourceLinks.js.map +1 -0
  149. package/dist/page/attentionDetails.d.ts +4 -0
  150. package/dist/page/attentionDetails.d.ts.map +1 -0
  151. package/dist/page/attentionDetails.js +13 -0
  152. package/dist/page/attentionDetails.js.map +1 -0
  153. package/dist/page/backlinksHtml.d.ts +3 -0
  154. package/dist/page/backlinksHtml.d.ts.map +1 -0
  155. package/dist/page/backlinksHtml.js +16 -0
  156. package/dist/page/backlinksHtml.js.map +1 -0
  157. package/dist/page/board.d.ts +1 -1
  158. package/dist/page/board.d.ts.map +1 -1
  159. package/dist/page/board.js +14 -4
  160. package/dist/page/board.js.map +1 -1
  161. package/dist/page/client.d.ts +2 -1
  162. package/dist/page/client.d.ts.map +1 -1
  163. package/dist/page/client.js +66 -7
  164. package/dist/page/client.js.map +1 -1
  165. package/dist/page/criteriaEvidence.d.ts +4 -0
  166. package/dist/page/criteriaEvidence.d.ts.map +1 -0
  167. package/dist/page/criteriaEvidence.js +27 -0
  168. package/dist/page/criteriaEvidence.js.map +1 -0
  169. package/dist/page/diagrams.d.ts +1 -1
  170. package/dist/page/diagrams.d.ts.map +1 -1
  171. package/dist/page/diagrams.js +12 -4
  172. package/dist/page/diagrams.js.map +1 -1
  173. package/dist/page/document.d.ts +1 -1
  174. package/dist/page/document.d.ts.map +1 -1
  175. package/dist/page/document.js +6 -3
  176. package/dist/page/document.js.map +1 -1
  177. package/dist/page/libraryScript.d.ts +2 -0
  178. package/dist/page/libraryScript.d.ts.map +1 -0
  179. package/dist/page/libraryScript.js +73 -0
  180. package/dist/page/libraryScript.js.map +1 -0
  181. package/dist/page/metadata.d.ts +5 -0
  182. package/dist/page/metadata.d.ts.map +1 -0
  183. package/dist/page/metadata.js +34 -0
  184. package/dist/page/metadata.js.map +1 -0
  185. package/dist/page/metadataDetails.d.ts +4 -0
  186. package/dist/page/metadataDetails.d.ts.map +1 -0
  187. package/dist/page/metadataDetails.js +23 -0
  188. package/dist/page/metadataDetails.js.map +1 -0
  189. package/dist/page/metadataLinks.d.ts +6 -0
  190. package/dist/page/metadataLinks.d.ts.map +1 -0
  191. package/dist/page/metadataLinks.js +31 -0
  192. package/dist/page/metadataLinks.js.map +1 -0
  193. package/dist/page/nav.d.ts.map +1 -1
  194. package/dist/page/nav.js +3 -3
  195. package/dist/page/nav.js.map +1 -1
  196. package/dist/page/navigationScript.d.ts +2 -0
  197. package/dist/page/navigationScript.d.ts.map +1 -0
  198. package/dist/page/navigationScript.js +104 -0
  199. package/dist/page/navigationScript.js.map +1 -0
  200. package/dist/page/readingStateScript.d.ts +2 -0
  201. package/dist/page/readingStateScript.d.ts.map +1 -0
  202. package/dist/page/readingStateScript.js +62 -0
  203. package/dist/page/readingStateScript.js.map +1 -0
  204. package/dist/page/readingStyles.d.ts +2 -0
  205. package/dist/page/readingStyles.d.ts.map +1 -0
  206. package/dist/page/readingStyles.js +29 -0
  207. package/dist/page/readingStyles.js.map +1 -0
  208. package/dist/page/readingTools.d.ts +3 -0
  209. package/dist/page/readingTools.d.ts.map +1 -0
  210. package/dist/page/readingTools.js +10 -0
  211. package/dist/page/readingTools.js.map +1 -0
  212. package/dist/page/recordedEvidence.d.ts +4 -0
  213. package/dist/page/recordedEvidence.d.ts.map +1 -0
  214. package/dist/page/recordedEvidence.js +10 -0
  215. package/dist/page/recordedEvidence.js.map +1 -0
  216. package/dist/page/searchDialog.d.ts +3 -0
  217. package/dist/page/searchDialog.d.ts.map +1 -0
  218. package/dist/page/searchDialog.js +16 -0
  219. package/dist/page/searchDialog.js.map +1 -0
  220. package/dist/page/searchResultsScript.d.ts +2 -0
  221. package/dist/page/searchResultsScript.d.ts.map +1 -0
  222. package/dist/page/searchResultsScript.js +64 -0
  223. package/dist/page/searchResultsScript.js.map +1 -0
  224. package/dist/page/searchScript.d.ts +2 -0
  225. package/dist/page/searchScript.d.ts.map +1 -0
  226. package/dist/page/searchScript.js +73 -0
  227. package/dist/page/searchScript.js.map +1 -0
  228. package/dist/page/shell.d.ts +1 -1
  229. package/dist/page/shell.d.ts.map +1 -1
  230. package/dist/page/shell.js +23 -5
  231. package/dist/page/shell.js.map +1 -1
  232. package/dist/page/stateScript.d.ts +2 -0
  233. package/dist/page/stateScript.d.ts.map +1 -0
  234. package/dist/page/stateScript.js +55 -0
  235. package/dist/page/stateScript.js.map +1 -0
  236. package/dist/page/style.d.ts.map +1 -1
  237. package/dist/page/style.js +15 -34
  238. package/dist/page/style.js.map +1 -1
  239. package/dist/page/swap.d.ts +1 -1
  240. package/dist/page/swap.d.ts.map +1 -1
  241. package/dist/page/swap.js +4 -1
  242. package/dist/page/swap.js.map +1 -1
  243. package/dist/page/workspaceStyles.d.ts +3 -0
  244. package/dist/page/workspaceStyles.d.ts.map +1 -0
  245. package/dist/page/workspaceStyles.js +79 -0
  246. package/dist/page/workspaceStyles.js.map +1 -0
  247. package/dist/render/documentHeadings.d.ts +667 -0
  248. package/dist/render/documentHeadings.d.ts.map +1 -0
  249. package/dist/render/documentHeadings.js +45 -0
  250. package/dist/render/documentHeadings.js.map +1 -0
  251. package/dist/render/documentLinks.d.ts +659 -0
  252. package/dist/render/documentLinks.d.ts.map +1 -0
  253. package/dist/render/documentLinks.js +19 -0
  254. package/dist/render/documentLinks.js.map +1 -0
  255. package/dist/render/markdown.d.ts +7 -1
  256. package/dist/render/markdown.d.ts.map +1 -1
  257. package/dist/render/markdown.js +13 -2
  258. package/dist/render/markdown.js.map +1 -1
  259. package/dist/search/attentionEntries.d.ts +4 -0
  260. package/dist/search/attentionEntries.d.ts.map +1 -0
  261. package/dist/search/attentionEntries.js +20 -0
  262. package/dist/search/attentionEntries.js.map +1 -0
  263. package/dist/search/collector.d.ts +13 -0
  264. package/dist/search/collector.d.ts.map +1 -0
  265. package/dist/search/collector.js +40 -0
  266. package/dist/search/collector.js.map +1 -0
  267. package/dist/search/entries.d.ts +10 -0
  268. package/dist/search/entries.d.ts.map +1 -0
  269. package/dist/search/entries.js +37 -0
  270. package/dist/search/entries.js.map +1 -0
  271. package/dist/search/linkCollector.d.ts +8 -0
  272. package/dist/search/linkCollector.d.ts.map +1 -0
  273. package/dist/search/linkCollector.js +16 -0
  274. package/dist/search/linkCollector.js.map +1 -0
  275. package/dist/search/match.d.ts +14 -0
  276. package/dist/search/match.d.ts.map +1 -0
  277. package/dist/search/match.js +26 -0
  278. package/dist/search/match.js.map +1 -0
  279. package/dist/search/metadataEntries.d.ts +4 -0
  280. package/dist/search/metadataEntries.d.ts.map +1 -0
  281. package/dist/search/metadataEntries.js +42 -0
  282. package/dist/search/metadataEntries.js.map +1 -0
  283. package/dist/search/snapshot.d.ts +13 -0
  284. package/dist/search/snapshot.d.ts.map +1 -0
  285. package/dist/search/snapshot.js +49 -0
  286. package/dist/search/snapshot.js.map +1 -0
  287. package/dist/views/items.d.ts +11 -0
  288. package/dist/views/items.d.ts.map +1 -0
  289. package/dist/views/items.js +48 -0
  290. package/dist/views/items.js.map +1 -0
  291. package/dist/views/projection.d.ts +15 -0
  292. package/dist/views/projection.d.ts.map +1 -0
  293. package/dist/views/projection.js +47 -0
  294. package/dist/views/projection.js.map +1 -0
  295. package/dist/views/savedScript.d.ts +2 -0
  296. package/dist/views/savedScript.d.ts.map +1 -0
  297. package/dist/views/savedScript.js +89 -0
  298. package/dist/views/savedScript.js.map +1 -0
  299. package/dist/views/state.d.ts +15 -0
  300. package/dist/views/state.d.ts.map +1 -0
  301. package/dist/views/state.js +45 -0
  302. package/dist/views/state.js.map +1 -0
  303. package/dist/views/tools.d.ts +3 -0
  304. package/dist/views/tools.d.ts.map +1 -0
  305. package/dist/views/tools.js +11 -0
  306. package/dist/views/tools.js.map +1 -0
  307. package/dist/views/workCards.d.ts +4 -0
  308. package/dist/views/workCards.d.ts.map +1 -0
  309. package/dist/views/workCards.js +23 -0
  310. package/dist/views/workCards.js.map +1 -0
  311. package/dist/views/workControls.d.ts +4 -0
  312. package/dist/views/workControls.d.ts.map +1 -0
  313. package/dist/views/workControls.js +32 -0
  314. package/dist/views/workControls.js.map +1 -0
  315. package/dist/views/workDetail.d.ts +13 -0
  316. package/dist/views/workDetail.d.ts.map +1 -0
  317. package/dist/views/workDetail.js +26 -0
  318. package/dist/views/workDetail.js.map +1 -0
  319. package/dist/views/workHtml.d.ts +15 -0
  320. package/dist/views/workHtml.d.ts.map +1 -0
  321. package/dist/views/workHtml.js +35 -0
  322. package/dist/views/workHtml.js.map +1 -0
  323. package/dist/views/workStyle.d.ts +2 -0
  324. package/dist/views/workStyle.d.ts.map +1 -0
  325. package/dist/views/workStyle.js +18 -0
  326. package/dist/views/workStyle.js.map +1 -0
  327. package/dist/views/workTable.d.ts +4 -0
  328. package/dist/views/workTable.d.ts.map +1 -0
  329. package/dist/views/workTable.js +19 -0
  330. package/dist/views/workTable.js.map +1 -0
  331. package/package.json +14 -10
  332. package/src/attention/overviewHtml.ts +44 -0
  333. package/src/attention/requests.ts +64 -0
  334. package/src/attention/style.ts +9 -0
  335. package/src/board.ts +16 -3
  336. package/src/cli.ts +1 -1
  337. package/src/files/changes.ts +6 -17
  338. package/src/files/home.ts +4 -0
  339. package/src/files/list.ts +25 -14
  340. package/src/files/markdownPath.ts +31 -0
  341. package/src/files/url.ts +3 -0
  342. package/src/files/watchDirectories.ts +60 -0
  343. package/src/history/baseline.ts +43 -0
  344. package/src/history/compare.ts +54 -0
  345. package/src/history/documents.ts +21 -0
  346. package/src/history/fields.ts +32 -0
  347. package/src/history/html.ts +23 -0
  348. package/src/history/limits.ts +2 -0
  349. package/src/history/response.ts +23 -0
  350. package/src/history/schema.ts +36 -0
  351. package/src/history/script.ts +112 -0
  352. package/src/http/assets.ts +18 -1
  353. package/src/http/history.ts +50 -0
  354. package/src/http/identity.ts +62 -0
  355. package/src/http/overview.ts +19 -0
  356. package/src/http/page.ts +52 -15
  357. package/src/http/search.ts +13 -0
  358. package/src/http/work.ts +41 -0
  359. package/src/metadata/attentionProblems.ts +18 -0
  360. package/src/metadata/backlinks.ts +46 -0
  361. package/src/metadata/fields.ts +26 -0
  362. package/src/metadata/links.ts +19 -0
  363. package/src/metadata/locations.ts +34 -0
  364. package/src/metadata/model.ts +27 -0
  365. package/src/metadata/parse.ts +62 -0
  366. package/src/metadata/problems.ts +66 -0
  367. package/src/metadata/relationshipLabel.ts +14 -0
  368. package/src/metadata/schema.ts +45 -0
  369. package/src/metadata/sourceLinks.ts +46 -0
  370. package/src/page/attentionDetails.ts +18 -0
  371. package/src/page/backlinksHtml.ts +18 -0
  372. package/src/page/board.ts +14 -4
  373. package/src/page/client.ts +66 -7
  374. package/src/page/criteriaEvidence.ts +36 -0
  375. package/src/page/diagrams.ts +12 -4
  376. package/src/page/document.ts +6 -3
  377. package/src/page/libraryScript.ts +72 -0
  378. package/src/page/metadata.ts +40 -0
  379. package/src/page/metadataDetails.ts +26 -0
  380. package/src/page/metadataLinks.ts +35 -0
  381. package/src/page/nav.ts +5 -4
  382. package/src/page/navigationScript.ts +103 -0
  383. package/src/page/readingStateScript.ts +61 -0
  384. package/src/page/readingStyles.ts +28 -0
  385. package/src/page/readingTools.ts +12 -0
  386. package/src/page/recordedEvidence.ts +12 -0
  387. package/src/page/searchDialog.ts +16 -0
  388. package/src/page/searchResultsScript.ts +63 -0
  389. package/src/page/searchScript.ts +72 -0
  390. package/src/page/shell.ts +32 -5
  391. package/src/page/stateScript.ts +54 -0
  392. package/src/page/style.ts +15 -35
  393. package/src/page/swap.ts +4 -1
  394. package/src/page/workspaceStyles.ts +79 -0
  395. package/src/render/documentHeadings.ts +52 -0
  396. package/src/render/documentLinks.ts +19 -0
  397. package/src/render/markdown.ts +21 -4
  398. package/src/search/attentionEntries.ts +22 -0
  399. package/src/search/collector.ts +44 -0
  400. package/src/search/entries.ts +51 -0
  401. package/src/search/linkCollector.ts +16 -0
  402. package/src/search/match.ts +28 -0
  403. package/src/search/metadataEntries.ts +44 -0
  404. package/src/search/snapshot.ts +59 -0
  405. package/src/views/items.ts +55 -0
  406. package/src/views/projection.ts +59 -0
  407. package/src/views/savedScript.ts +88 -0
  408. package/src/views/state.ts +47 -0
  409. package/src/views/tools.ts +11 -0
  410. package/src/views/workCards.ts +26 -0
  411. package/src/views/workControls.ts +38 -0
  412. package/src/views/workDetail.ts +28 -0
  413. package/src/views/workHtml.ts +39 -0
  414. package/src/views/workStyle.ts +17 -0
  415. package/src/views/workTable.ts +21 -0
  416. package/dist/index.d.ts +0 -2
  417. package/dist/index.d.ts.map +0 -1
  418. package/dist/index.js +0 -2
  419. package/dist/index.js.map +0 -1
  420. package/src/index.ts +0 -1
@@ -0,0 +1,59 @@
1
+ import type { Snapshot } from "#search/snapshot.ts";
2
+ import { filterItems, type Item, itemsOf } from "./items.ts";
3
+ import type { State } from "./state.ts";
4
+
5
+ export interface Projection {
6
+ readonly boards: readonly Item[];
7
+ readonly issues: readonly string[];
8
+ readonly items: readonly Item[];
9
+ readonly rows: readonly Item[];
10
+ readonly selected: Item | undefined;
11
+ readonly selectedOutside: boolean;
12
+ readonly title: string;
13
+ readonly validBoard: boolean;
14
+ }
15
+ function boardItems(board: Item, items: readonly Item[], snapshot: Snapshot) {
16
+ const references = board.document.parsed.fields.items ?? [];
17
+ const byId = new Map(items.map((item) => [item.id, item]));
18
+ const issues: string[] = [];
19
+ const found: Item[] = [];
20
+ for (const id of new Set(references)) {
21
+ const item = byId.get(id);
22
+ if (item) {
23
+ found.push(item);
24
+ } else {
25
+ issues.push(`${id}: ${(snapshot.model.ids.get(id)?.length ?? 0) > 1 ? "ambiguous ID" : "missing or invalid ID"}`);
26
+ }
27
+ if (references.filter((reference) => reference === id).length > 1) {
28
+ issues.push(`${id}: repeated membership, shown once`);
29
+ }
30
+ }
31
+ return { found, issues };
32
+ }
33
+ export function projectItems(snapshot: Snapshot, state: State): Projection {
34
+ const known = itemsOf(snapshot);
35
+ const boards = known.filter((item) => item.document.parsed.fields.kind === "board");
36
+ const board = boards.find((item) => item.id === state.board);
37
+ const membership = board ? boardItems(board, known, snapshot) : undefined;
38
+ const items = membership?.found ?? known.filter((item) => item.document.parsed.fields.kind !== "board");
39
+ const rows = filterItems(items, state);
40
+ const selected = known.find((item) => item.id === state.item);
41
+ const issues =
42
+ membership?.issues
43
+ ?? [...snapshot.model.ids]
44
+ .filter(([, documents]) => documents.length > 1)
45
+ .map(([id]) => `${id}: ambiguous ID; open its source files to correct the declaration`);
46
+ const sourceIssues = board
47
+ ? (snapshot.model.diagnostics.get(board.document.file) ?? []).map((problem) => `${board.document.file}:${problem.line}: ${problem.message}`)
48
+ : [];
49
+ return {
50
+ boards,
51
+ issues: [...issues, ...sourceIssues],
52
+ items,
53
+ rows,
54
+ selected,
55
+ selectedOutside: selected !== undefined && !rows.some((item) => item.id === selected.id),
56
+ title: board?.title ?? "All work",
57
+ validBoard: !state.board || board !== undefined,
58
+ };
59
+ }
@@ -0,0 +1,88 @@
1
+ export function savedScript(): string {
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
+ }
@@ -0,0 +1,47 @@
1
+ import { Option, Schema } from "effect";
2
+
3
+ const View = Schema.Literals(["board", "table"]);
4
+ const Sort = Schema.Literals(["title", "owner", "status"]);
5
+ export const State = Schema.Struct({
6
+ board: Schema.String,
7
+ item: Schema.String,
8
+ owner: Schema.String,
9
+ query: Schema.String,
10
+ sort: Sort,
11
+ status: Schema.String,
12
+ view: View,
13
+ });
14
+ export type State = typeof State.Type;
15
+
16
+ export function stateOf(url: string): State {
17
+ const params = new URL(url, "http://127.0.0.1").searchParams;
18
+ return {
19
+ board: params.get("board") ?? "",
20
+ item: params.get("item") ?? "",
21
+ owner: params.get("owner") ?? "",
22
+ query: (params.get("q") ?? "").slice(0, 200),
23
+ sort: Option.getOrElse(Schema.decodeUnknownOption(Sort)(params.get("sort")), () => "title"),
24
+ status: params.get("status") ?? "",
25
+ view: Option.getOrElse(Schema.decodeUnknownOption(View)(params.get("view")), () => "board"),
26
+ };
27
+ }
28
+ export function viewUrl(state: State, changes: Partial<State> = {}, hash = ""): string {
29
+ const next = { ...state, ...changes };
30
+ const params = new URLSearchParams({ view: next.view });
31
+ for (const [key, value] of Object.entries({
32
+ board: next.board,
33
+ item: next.item,
34
+ owner: next.owner,
35
+ q: next.query,
36
+ sort: next.sort,
37
+ status: next.status,
38
+ })) {
39
+ if (value) {
40
+ params.set(key, value);
41
+ }
42
+ }
43
+ return `/_board/work?${params}${hash ? `#${hash}` : ""}`;
44
+ }
45
+ export function fieldFilter(value: string | undefined): string {
46
+ return value === undefined ? "missing" : `value:${value}`;
47
+ }
@@ -0,0 +1,11 @@
1
+ import { escapeHtml } from "#page/escape.ts";
2
+ import { type State, viewUrl } from "./state.ts";
3
+
4
+ export function viewTools(state: State): string {
5
+ const layouts = ["board", "table"] as const;
6
+ 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>
7
+ <section id="saved-work-views" class="saved-work-views" aria-label="Saved local views" data-url="${escapeHtml(viewUrl(state, { item: "" }))}">
8
+ <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>
9
+ <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>
10
+ <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>`;
11
+ }
@@ -0,0 +1,26 @@
1
+ import { escapeHtml } from "#page/escape.ts";
2
+ import type { Item } from "./items.ts";
3
+ import { type State, viewUrl } from "./state.ts";
4
+
5
+ function card(item: Item, state: State): string {
6
+ const fields = item.document.parsed.fields;
7
+ const selected = item.id === state.item;
8
+ return `<article class="work-card" data-key="item:${escapeHtml(item.id)}" data-item="${escapeHtml(item.id)}"${selected ? ' data-selected="true"' : ""}>
9
+ <p class="work-kind">${escapeHtml(fields.kind ?? "Kind not recorded")}</p>
10
+ <h3><a href="${escapeHtml(viewUrl(state, { item: item.id }, "work-detail"))}"${selected ? ' aria-current="true"' : ""}>${escapeHtml(item.title)}</a></h3>
11
+ <p class="work-id">${escapeHtml(item.id)}</p><p class="work-owner">Owner: ${escapeHtml(fields.owner ?? "Not recorded")}</p>
12
+ ${fields.nextAction ? `<p class="work-next">Next: ${escapeHtml(fields.nextAction)}</p>` : ""}</article>`;
13
+ }
14
+ export function workCards(items: readonly Item[], state: State): string {
15
+ if (items.length === 0) {
16
+ return '<p class="empty">No work matches these filters.</p>';
17
+ }
18
+ const columns = Map.groupBy(items, (item) => item.document.parsed.fields.status);
19
+ return `<div class="work-columns">${[...columns]
20
+ .map(
21
+ ([status, rows]) => `<section class="work-column" data-key="status:${escapeHtml(status ?? "")}"
22
+ aria-label="${escapeHtml(status ?? "Status not recorded")}"><h2>${escapeHtml(status ?? "Status not recorded")} <span class="work-count">${rows.length}</span></h2>
23
+ ${rows.map((item) => card(item, state)).join("")}</section>`,
24
+ )
25
+ .join("")}</div>`;
26
+ }
@@ -0,0 +1,38 @@
1
+ import { escapeHtml } from "#page/escape.ts";
2
+ import type { Item } from "./items.ts";
3
+ import type { Projection } from "./projection.ts";
4
+ import { fieldFilter, type State, viewUrl } from "./state.ts";
5
+
6
+ function option(value: string, title: string, current: string): string {
7
+ return `<option value="${escapeHtml(value)}"${value === current ? " selected" : ""}>${escapeHtml(title)}</option>`;
8
+ }
9
+ function fieldOptions(items: readonly Item[], field: "owner" | "status", current: string): string {
10
+ const values = new Map(
11
+ items.map((item) => {
12
+ const value = item.document.parsed.fields[field];
13
+ return [fieldFilter(value), value ?? `${field === "owner" ? "Owner" : "Status"} not recorded`];
14
+ }),
15
+ );
16
+ if (current && !values.has(current)) {
17
+ values.set(current, `${current.startsWith("value:") ? current.slice(6) : current} (no current matches)`);
18
+ }
19
+ return (
20
+ option("", `All ${field === "owner" ? "owners" : "statuses"}`, current)
21
+ + [...values]
22
+ .sort((a, b) => a[1].localeCompare(b[1], "en"))
23
+ .map(([value, label]) => option(value, label, current))
24
+ .join("")
25
+ );
26
+ }
27
+ export function workControls(projection: Projection, state: State): string {
28
+ const boards = option("", "All work", state.board) + projection.boards.map((board) => option(board.id, board.title, state.board)).join("");
29
+ const unavailable = state.board && !projection.validBoard ? option(state.board, `${state.board} (unavailable)`, state.board) : "";
30
+ return `<form id="work-filters" class="work-filters" action="/_board/work#work-results" method="get">
31
+ <input type="hidden" name="view" value="${state.view}"><input type="hidden" name="item" value="${escapeHtml(state.item)}">
32
+ <label><span>Board</span><select name="board" id="work-board">${boards}${unavailable}</select></label>
33
+ <label><span>Status</span><select name="status" id="work-status">${fieldOptions(projection.items, "status", state.status)}</select></label>
34
+ <label><span>Owner</span><select name="owner" id="work-owner">${fieldOptions(projection.items, "owner", state.owner)}</select></label>
35
+ <label><span>Find work</span><input name="q" id="work-query" type="search" value="${escapeHtml(state.query)}" maxlength="200"></label>
36
+ <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>
37
+ <button type="submit">Apply</button><a href="${escapeHtml(viewUrl(state, { owner: "", query: "", status: "" }, "work-results"))}">Clear filters</a></form>`;
38
+ }
@@ -0,0 +1,28 @@
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 type { Snapshot } from "#search/snapshot.ts";
8
+ import type { Projection } from "./projection.ts";
9
+ import { type State, viewUrl } from "./state.ts";
10
+
11
+ export const workDetail = Effect.fn("WorkBoard.workDetail")(function* (projection: Projection, state: State, snapshot: Snapshot) {
12
+ if (!state.item) {
13
+ return "";
14
+ }
15
+ const close = `<a class="detail-close" href="${escapeHtml(viewUrl(state, { item: "" }, "work-results"))}">Close detail</a>`;
16
+ const selected = projection.selected;
17
+ if (!selected) {
18
+ const ambiguous = (snapshot.model.ids.get(state.item)?.length ?? 0) > 1;
19
+ 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>`;
20
+ }
21
+ const { document } = selected;
22
+ const prose = yield* renderMarkdown(document.parsed.body, { file: document.file, headings: documentHeadings() });
23
+ return `<aside id="work-detail" class="work-detail" data-key="detail:${escapeHtml(selected.id)}" tabindex="-1" aria-label="Selected work">
24
+ <header>${close}<a href="${escapeHtml(identityUrl(selected.id))}">Open document</a></header>
25
+ ${projection.selectedOutside ? '<p class="detail-notice" role="status">This selected item is outside the current board or filters.</p>' : ""}
26
+ <p class="meta">Source: ${escapeHtml(document.file)}</p>${metadataHtml(document.parsed, document.file, snapshot.model)}
27
+ <article class="doc">${prose}</article></aside>`;
28
+ });
@@ -0,0 +1,39 @@
1
+ import { Effect } from "effect";
2
+ import { identityUrl } from "#metadata/links.ts";
3
+ import { escapeHtml } from "#page/escape.ts";
4
+ import type { Snapshot } from "#search/snapshot.ts";
5
+ import { projectItems } from "./projection.ts";
6
+ import type { State } from "./state.ts";
7
+ import { viewTools } from "./tools.ts";
8
+ import { workCards } from "./workCards.ts";
9
+ import { workControls } from "./workControls.ts";
10
+ import { workDetail } from "./workDetail.ts";
11
+ import { workTable } from "./workTable.ts";
12
+
13
+ export const workHtml = Effect.fn("WorkBoard.workHtml")(function* (snapshot: Snapshot, state: State) {
14
+ const projection = projectItems(snapshot, state);
15
+ const controls = workControls(projection, state);
16
+ const tools = viewTools(state);
17
+ if (!projection.validBoard) {
18
+ return {
19
+ 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>`,
20
+ status: 404,
21
+ };
22
+ }
23
+ const issues =
24
+ projection.issues.length > 0
25
+ ? `<details class="view-issues"><summary>Source issues (${projection.issues.length})</summary><ul>${projection.issues.map((issue) => `<li>${escapeHtml(issue)}</li>`).join("")}</ul></details>`
26
+ : "";
27
+ const source = state.board ? `<a href="${escapeHtml(identityUrl(state.board))}">Board source</a>` : "";
28
+ const empty =
29
+ projection.items.length === 0
30
+ ? '<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>'
31
+ : "";
32
+ const detail = yield* workDetail(projection, state, snapshot);
33
+ return {
34
+ 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>
35
+ ${tools}${controls}${issues}<p class="work-total" role="status">${projection.rows.length} shown · ${projection.items.length} items in this view</p>
36
+ <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>`,
37
+ status: 200,
38
+ };
39
+ });
@@ -0,0 +1,17 @@
1
+ export function workStyle(): string {
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
+ }
@@ -0,0 +1,21 @@
1
+ import { escapeHtml } from "#page/escape.ts";
2
+ import type { Item } from "./items.ts";
3
+ import { type State, viewUrl } from "./state.ts";
4
+
5
+ function row(item: Item, state: State): string {
6
+ const fields = item.document.parsed.fields;
7
+ const selected = item.id === state.item;
8
+ const values = [fields.kind, fields.status, fields.owner, fields.nextAction];
9
+ return `<tr data-item="${escapeHtml(item.id)}"${selected ? ' data-selected="true"' : ""}>
10
+ <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>
11
+ ${values.map((value) => `<td>${escapeHtml(value ?? "Not recorded")}</td>`).join("")}</tr>`;
12
+ }
13
+
14
+ export function workTable(items: readonly Item[], state: State): string {
15
+ if (items.length === 0) {
16
+ return '<p class="empty">No work matches these filters.</p>';
17
+ }
18
+ return `<div class="work-table-wrap"><table class="work-table"><caption class="sr-only">Identified work, sorted by ${escapeHtml(state.sort)}</caption>
19
+ <thead><tr>${["Work", "Kind", "Status", "Owner", "Next action"].map((title) => `<th scope="col">${title}</th>`).join("")}</tr></thead>
20
+ <tbody>${items.map((item) => row(item, state)).join("")}</tbody></table></div>`;
21
+ }
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export { type BoardOptions, boardLayer } from "./board.ts";
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js DELETED
@@ -1,2 +0,0 @@
1
- export { boardLayer } from "./board.js";
2
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,UAAU,EAAE,MAAM,YAAY,CAAC"}
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export { type BoardOptions, boardLayer } from "./board.ts";