@shivaedev/work-board 0.15.0 → 0.16.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 (119) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/assets/react.css +1 -1
  3. package/assets/react.js +17 -17
  4. package/dist/client/document/Mermaid.d.ts.map +1 -1
  5. package/dist/client/document/Mermaid.js +4 -10
  6. package/dist/client/document/Mermaid.js.map +1 -1
  7. package/dist/client/document/View.js +1 -1
  8. package/dist/client/document/View.js.map +1 -1
  9. package/dist/client/react/BoardShell.d.ts.map +1 -1
  10. package/dist/client/react/BoardShell.js +28 -23
  11. package/dist/client/react/BoardShell.js.map +1 -1
  12. package/dist/client/react/DocumentContext.d.ts.map +1 -1
  13. package/dist/client/react/DocumentContext.js +6 -4
  14. package/dist/client/react/DocumentContext.js.map +1 -1
  15. package/dist/client/react/LiveControls.d.ts.map +1 -1
  16. package/dist/client/react/LiveControls.js +1 -6
  17. package/dist/client/react/LiveControls.js.map +1 -1
  18. package/dist/client/react/PhoneNavigation.d.ts +3 -1
  19. package/dist/client/react/PhoneNavigation.d.ts.map +1 -1
  20. package/dist/client/react/PhoneNavigation.js +8 -13
  21. package/dist/client/react/PhoneNavigation.js.map +1 -1
  22. package/dist/client/react/ReadingLibrary.d.ts.map +1 -1
  23. package/dist/client/react/ReadingLibrary.js +2 -6
  24. package/dist/client/react/ReadingLibrary.js.map +1 -1
  25. package/dist/client/react/ReadingReadyContext.d.ts +6 -0
  26. package/dist/client/react/ReadingReadyContext.d.ts.map +1 -0
  27. package/dist/client/react/ReadingReadyContext.js +7 -0
  28. package/dist/client/react/ReadingReadyContext.js.map +1 -0
  29. package/dist/client/react/SessionContext.d.ts +3 -0
  30. package/dist/client/react/SessionContext.d.ts.map +1 -0
  31. package/dist/client/react/SessionContext.js +3 -0
  32. package/dist/client/react/SessionContext.js.map +1 -0
  33. package/dist/client/react/SystemMain.d.ts.map +1 -1
  34. package/dist/client/react/SystemMain.js +3 -1
  35. package/dist/client/react/SystemMain.js.map +1 -1
  36. package/dist/client/react/ThemeContext.d.ts +2 -0
  37. package/dist/client/react/ThemeContext.d.ts.map +1 -0
  38. package/dist/client/react/ThemeContext.js +3 -0
  39. package/dist/client/react/ThemeContext.js.map +1 -0
  40. package/dist/client/react/loadRemaining.d.ts +17 -17
  41. package/dist/client/react/navigationLocation.d.ts +2 -0
  42. package/dist/client/react/navigationLocation.d.ts.map +1 -1
  43. package/dist/client/react/navigationLocation.js +10 -0
  44. package/dist/client/react/navigationLocation.js.map +1 -1
  45. package/dist/client/react/scheduleReading.d.ts.map +1 -1
  46. package/dist/client/react/scheduleReading.js +1 -10
  47. package/dist/client/react/scheduleReading.js.map +1 -1
  48. package/dist/client/react/useAppearance.d.ts +2 -1
  49. package/dist/client/react/useAppearance.d.ts.map +1 -1
  50. package/dist/client/react/useAppearance.js +1 -2
  51. package/dist/client/react/useAppearance.js.map +1 -1
  52. package/dist/client/react/useBoardNavigation.d.ts +1 -1
  53. package/dist/client/react/useBoardNavigation.d.ts.map +1 -1
  54. package/dist/client/react/useBoardNavigation.js +13 -17
  55. package/dist/client/react/useBoardNavigation.js.map +1 -1
  56. package/dist/client/react/useDiagnosticsPolling.d.ts +4 -1
  57. package/dist/client/react/useDiagnosticsPolling.d.ts.map +1 -1
  58. package/dist/client/react/useDiagnosticsPolling.js +9 -7
  59. package/dist/client/react/useDiagnosticsPolling.js.map +1 -1
  60. package/dist/client/react/useSidebar.d.ts.map +1 -1
  61. package/dist/client/react/useSidebar.js +5 -3
  62. package/dist/client/react/useSidebar.js.map +1 -1
  63. package/dist/render/{failed.d.ts → Failed.d.ts} +1 -1
  64. package/dist/render/Failed.d.ts.map +1 -0
  65. package/dist/render/{failed.js → Failed.js} +1 -1
  66. package/dist/render/Failed.js.map +1 -0
  67. package/dist/render/code.d.ts +2 -2
  68. package/dist/render/code.d.ts.map +1 -1
  69. package/dist/render/code.js +15 -13
  70. package/dist/render/code.js.map +1 -1
  71. package/dist/render/footnoteIds.d.ts +3 -0
  72. package/dist/render/footnoteIds.d.ts.map +1 -0
  73. package/dist/render/{footnotes.js → footnoteIds.js} +11 -9
  74. package/dist/render/footnoteIds.js.map +1 -0
  75. package/dist/rpc/contract.d.ts +2401 -2401
  76. package/dist/rpc/contract.d.ts.map +1 -1
  77. package/dist/rpc/handoffContract.d.ts +33 -33
  78. package/dist/rpc/responseContract.d.ts +56 -56
  79. package/dist/server/board.d.ts +1 -1
  80. package/dist/server/mcp/client.d.ts +1265 -1265
  81. package/dist/server/mcp/client.d.ts.map +1 -1
  82. package/dist/server/packageInfo.d.ts +1 -1
  83. package/dist/server/packageInfo.js +1 -1
  84. package/dist/server/render/Highlighter.d.ts +1 -1
  85. package/dist/server/render/Highlighter.js +1 -1
  86. package/dist/server/render/markdown.d.ts +1 -1
  87. package/dist/server/render/markdown.js +2 -2
  88. package/dist/server/render/markdown.js.map +1 -1
  89. package/dist/server/serve.d.ts +1 -1
  90. package/package.json +5 -36
  91. package/src/client/document/Mermaid.ts +4 -10
  92. package/src/client/document/View.ts +1 -1
  93. package/src/client/react/BoardShell.tsx +37 -24
  94. package/src/client/react/DocumentContext.tsx +6 -4
  95. package/src/client/react/LiveControls.tsx +1 -14
  96. package/src/client/react/PhoneNavigation.tsx +20 -15
  97. package/src/client/react/ReadingLibrary.tsx +2 -6
  98. package/src/client/react/ReadingReadyContext.ts +11 -0
  99. package/src/client/react/SessionContext.ts +4 -0
  100. package/src/client/react/SystemMain.tsx +3 -1
  101. package/src/client/react/ThemeContext.ts +3 -0
  102. package/src/client/react/navigationLocation.ts +12 -0
  103. package/src/client/react/scheduleReading.ts +1 -10
  104. package/src/client/react/useAppearance.ts +2 -3
  105. package/src/client/react/useBoardNavigation.ts +13 -18
  106. package/src/client/react/useDiagnosticsPolling.ts +14 -7
  107. package/src/client/react/useSidebar.ts +5 -3
  108. package/src/render/code.ts +3 -4
  109. package/src/render/{footnotes.ts → footnoteIds.ts} +12 -10
  110. package/src/server/board.ts +1 -1
  111. package/src/server/packageInfo.ts +1 -1
  112. package/src/server/render/Highlighter.ts +1 -1
  113. package/src/server/render/markdown.ts +2 -2
  114. package/dist/render/failed.d.ts.map +0 -1
  115. package/dist/render/failed.js.map +0 -1
  116. package/dist/render/footnotes.d.ts +0 -3
  117. package/dist/render/footnotes.d.ts.map +0 -1
  118. package/dist/render/footnotes.js.map +0 -1
  119. /package/src/render/{failed.ts → Failed.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/server/mcp/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/server/mcp/client.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  export declare const NAME = "work-board";
2
- export declare const VERSION = "0.15.0";
2
+ export declare const VERSION = "0.16.0";
3
3
  //# sourceMappingURL=packageInfo.d.ts.map
@@ -1,3 +1,3 @@
1
1
  export const NAME = "work-board";
2
- export const VERSION = "0.15.0";
2
+ export const VERSION = "0.16.0";
3
3
  //# sourceMappingURL=packageInfo.js.map
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect";
2
- import { RenderFailed } from "#render/failed.ts";
2
+ import { RenderFailed } from "#render/Failed.ts";
3
3
  export declare const Highlighter: import("effect/Context").Service<"WorkBoard/Highlighter", Readonly<{
4
4
  readonly codeBlocks: () => Effect.Effect<() => (tree: import("hast").Root) => Promise<void>, never, never>;
5
5
  }>> & {
@@ -2,7 +2,7 @@ import { Effect } from "effect";
2
2
  import { createHighlighter } from "shiki";
3
3
  import { defineService } from "@shivaedev/effect-service/define-service.ts";
4
4
  import { codeBlocks, THEMES } from "#render/code.ts";
5
- import { RenderFailed } from "#render/failed.ts";
5
+ import { RenderFailed } from "#render/Failed.ts";
6
6
  export const Highlighter = defineService({
7
7
  id: "WorkBoard/Highlighter",
8
8
  initialize: Effect.acquireRelease(Effect.tryPromise({
@@ -1,6 +1,6 @@
1
1
  import { Effect } from "effect";
2
2
  import type { documentHeadings } from "#render/documentHeadings.ts";
3
- import { RenderFailed } from "#render/failed.ts";
3
+ import { RenderFailed } from "#render/Failed.ts";
4
4
  export interface RenderOptions {
5
5
  readonly file?: string;
6
6
  readonly headings?: ReturnType<typeof documentHeadings>;
@@ -5,8 +5,8 @@ import { MarkdownAsync } from "react-markdown";
5
5
  import rehypeRaw from "rehype-raw";
6
6
  import { documentLinks } from "#render/documentLinks.ts";
7
7
  import { documentPlugins } from "#render/documentPlugins.ts";
8
- import { RenderFailed } from "#render/failed.ts";
9
- import { footnoteIds } from "#render/footnotes.ts";
8
+ import { RenderFailed } from "#render/Failed.ts";
9
+ import { footnoteIds } from "#render/footnoteIds.ts";
10
10
  import { Highlighter } from "./Highlighter.js";
11
11
  export const renderMarkdown = Effect.fn("WorkBoard.renderMarkdown")(function* (source, options = {}) {
12
12
  const highlighter = yield* Highlighter;
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/server/render/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,SAAS,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAU/C,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,0BAA0B,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAc,EAAE,OAAO,GAAkB,EAAE;IACzH,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC;IACvC,MAAM,OAAO,GAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC;IACvG,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QACrC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC;QAC7C,GAAG,EAAE,KAAK,IAAI,EAAE,CACf,oBAAoB,CACnB,MAAM,aAAa,CAAC;YACnB,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE;YACvG,aAAa,EAAE,OAAO;YACtB,aAAa,EAAE,eAAe,CAAC,OAAO,CAAC,eAAe,CAAC;YACvD,QAAQ,EAAE,OAAO,CAAC,IAAI;SACtB,CAAC,CACF;KACF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/server/render/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,SAAS,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAU/C,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,0BAA0B,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAc,EAAE,OAAO,GAAkB,EAAE;IACzH,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC;IACvC,MAAM,OAAO,GAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,CAAC;IACvG,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QACrC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC;QAC7C,GAAG,EAAE,KAAK,IAAI,EAAE,CACf,oBAAoB,CACnB,MAAM,aAAa,CAAC;YACnB,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE;YACvG,aAAa,EAAE,OAAO;YACtB,aAAa,EAAE,eAAe,CAAC,OAAO,CAAC,eAAe,CAAC;YACvD,QAAQ,EAAE,OAAO,CAAC,IAAI;SACtB,CAAC,CACF;KACF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACb,CAAC,CAAC,CAAC"}
@@ -5,5 +5,5 @@ export declare const HOST = "127.0.0.1";
5
5
  export interface ServeOptions extends BoardOptions {
6
6
  readonly port: number;
7
7
  }
8
- export declare function serveBoard(options: ServeOptions): Layer.Layer<import("effect/http/Etag").Generator | import("effect/http/HttpPlatform").HttpPlatform | HttpServer.HttpServer | import("@effect/platform-node/NodeServices").NodeServices, import("effect/Config").ConfigError | Error | import("./http/assets.ts").MermaidMissing | import("effect/PlatformError").PlatformError | import("../render/failed.ts").RenderFailed, import("effect/FileSystem").FileSystem | Path.Path>;
8
+ export declare function serveBoard(options: ServeOptions): Layer.Layer<import("effect/http/Etag").Generator | import("effect/http/HttpPlatform").HttpPlatform | HttpServer.HttpServer | import("@effect/platform-node/NodeServices").NodeServices, import("effect/Config").ConfigError | Error | import("./http/assets.ts").MermaidMissing | import("effect/PlatformError").PlatformError | import("../render/Failed.ts").RenderFailed, import("effect/FileSystem").FileSystem | Path.Path>;
9
9
  //# sourceMappingURL=serve.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/work-board",
3
- "version": "0.15.0",
3
+ "version": "0.16.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": {
@@ -77,13 +77,7 @@
77
77
  "default": "./dist/integration/metadata.js"
78
78
  },
79
79
  "./package.json": "./package.json",
80
- "./browser/react/*": null,
81
80
  "./browser/views/now.ts": null,
82
- "./browser/entry.ts": null,
83
- "./browser/fieldFeedback.ts": null,
84
- "./browser/reconcile/*": null,
85
- "./browser/legacyRuntime.ts": null,
86
- "./browser/session.ts": null,
87
81
  "./browser/handoffs/*": null,
88
82
  "./browser/responses/*": null,
89
83
  "./browser/handoffs/schema.ts": {
@@ -378,9 +372,7 @@
378
372
  "import": "./dist/client/document/*.js",
379
373
  "default": "./dist/client/document/*.js"
380
374
  },
381
- "./rpc/server.ts": null,
382
375
  "./rpc/HandlerOptions.ts": null,
383
- "./rpc/PageUrl.ts": null,
384
376
  "./http/boardRoutes.ts": null,
385
377
  "./http/rpcPolicy.ts": null,
386
378
  "./page/escape.ts": {
@@ -389,9 +381,6 @@
389
381
  "import": "./dist/browser/escapeHtml.js",
390
382
  "default": "./dist/browser/escapeHtml.js"
391
383
  },
392
- "./page/boardHtml.ts": null,
393
- "./page/documentHtml.ts": null,
394
- "./rpc/transport.ts": null,
395
384
  "./browser/document/layout.ts": null,
396
385
  "./browser/document/Details.ts": null,
397
386
  "./browser/document/ReadingContext.ts": {
@@ -400,28 +389,8 @@
400
389
  "import": "./dist/browser/document/ReadingContext.js",
401
390
  "default": "./dist/browser/document/ReadingContext.js"
402
391
  },
403
- "./diagnostics/script.ts": null,
404
- "./history/script.ts": null,
405
- "./page/sidebarScript.ts": null,
406
- "./page/searchResultsScript.ts": null,
407
- "./page/swap.ts": null,
408
- "./page/visualViewport.ts": null,
409
- "./page/stateScript.ts": null,
410
- "./page/searchScript.ts": null,
411
- "./page/visualScript.ts": null,
412
- "./page/itemContextScript.ts": null,
413
- "./page/libraryScript.ts": null,
414
- "./page/ageScript.ts": null,
415
- "./page/navigationScript.ts": null,
416
- "./page/readingStateScript.ts": null,
417
- "./page/formReadingScript.ts": null,
418
- "./page/diagrams.ts": null,
419
- "./page/client.ts": null,
420
- "./views/savedScript.ts": null,
421
392
  "./document/answerBody.ts": null,
422
- "./document/answerCardsHtml.ts": null,
423
- "./document/requestTitle.ts": null,
424
- "./browser/document/sourceGroups.ts": null
393
+ "./document/requestTitle.ts": null
425
394
  },
426
395
  "bin": {
427
396
  "work-board": "./dist/server/cli.js"
@@ -442,7 +411,7 @@
442
411
  "dependencies": {
443
412
  "@shivaedev/effect-contract": "0.5.1",
444
413
  "@shivaedev/effect-service": "0.3.0",
445
- "@shivaedev/platform": "0.14.2",
414
+ "@shivaedev/platform": "0.14.3",
446
415
  "mdast-util-directive": "3.1.1",
447
416
  "mermaid": "12.1.0",
448
417
  "react": "19.3.0",
@@ -465,9 +434,9 @@
465
434
  "@shivaedev/effect-react": "0.4.1",
466
435
  "@shivaedev/effect-test": "0.5.0",
467
436
  "@shivaedev/quality": "0.23.0",
468
- "@shivaedev/test-story": "0.5.0",
437
+ "@shivaedev/test-story": "0.6.0",
469
438
  "@tailwindcss/vite": "4.3.3",
470
- "@tanstack/react-router": "1.170.41",
439
+ "@tanstack/react-router": "1.170.42",
471
440
  "@types/hast": "3.0.5",
472
441
  "@types/mdast": "4.0.4",
473
442
  "@types/node": "24.19.2",
@@ -1,4 +1,5 @@
1
- import { createElement, useCallback, useEffect, useId, useRef, useState } from "react";
1
+ import { createElement, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
2
+ import { ThemeContext } from "#client/react/ThemeContext.ts";
2
3
  import { mermaidColor } from "./mermaidColor.ts";
3
4
 
4
5
  const drawings = new Map<string, { readonly source: string; readonly svg: string }>();
@@ -8,17 +9,10 @@ const MAX_DRAWINGS = 30;
8
9
  type Drawing = { readonly source: string; readonly svg: string } | { readonly source: string; readonly error: string };
9
10
 
10
11
  export function Mermaid({ source }: { readonly source: string }) {
12
+ const theme = useContext(ThemeContext);
11
13
  const id = useId().replace(/[^a-z\d_-]/giu, "");
12
- const [drawing, setDrawing] = useState<Drawing | undefined>(() => drawings.get(`${document.documentElement.dataset.scheme ?? "light"}:${source}`));
14
+ const [drawing, setDrawing] = useState<Drawing | undefined>(() => drawings.get(`${theme}:${source}`));
13
15
  const previousSourceRef = useRef(source);
14
- const [theme, setTheme] = useState(() => document.documentElement.dataset.scheme ?? "light");
15
- useEffect(() => {
16
- function sync() {
17
- setTheme(document.documentElement.dataset.scheme ?? "light");
18
- }
19
- document.addEventListener("board-theme", sync);
20
- return () => document.removeEventListener("board-theme", sync);
21
- }, []);
22
16
  useEffect(() => {
23
17
  if (previousSourceRef.current !== source) {
24
18
  for (const [key, value] of drawings) {
@@ -7,7 +7,7 @@ import { Age } from "#client/react/Age";
7
7
  import { documentHeadings } from "#render/documentHeadings.ts";
8
8
  import { documentLinks } from "#render/documentLinks.ts";
9
9
  import { documentPlugins } from "#render/documentPlugins.ts";
10
- import { footnoteIds } from "#render/footnotes.ts";
10
+ import { footnoteIds } from "#render/footnoteIds.ts";
11
11
  import { boardLayout } from "./boardLayout.ts";
12
12
  import { DetailStatesContext, DocumentDetails } from "./Details.ts";
13
13
  import { highlightDocument } from "./highlight.ts";
@@ -1,7 +1,7 @@
1
1
  import { useRouterState } from "@tanstack/react-router";
2
2
  import { Option } from "effect";
3
3
  import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
4
- import { useEffect, useState } from "react";
4
+ import { useCallback, useContext, useEffect, useState } from "react";
5
5
  import { useQuery } from "@shivaedev/effect-react/result-state.ts";
6
6
  import type { BrowserClient } from "#client/client.ts";
7
7
  import { navigationQuery } from "#client/page/routeQuery.ts";
@@ -14,10 +14,13 @@ import { MainLocationContext, useMainLocation } from "./MainLocationContext.ts";
14
14
  import { emptyMainLocation, type MainLocation } from "./mainLocation.ts";
15
15
  import { PhoneNavigation } from "./PhoneNavigation.tsx";
16
16
  import { ReadingLibrary } from "./ReadingLibrary.tsx";
17
+ import { ReadingReadyContext, readingReady } from "./ReadingReadyContext.ts";
17
18
  import { SearchDialog } from "./SearchDialog.tsx";
19
+ import { SessionContext } from "./SessionContext.ts";
18
20
  import type { ShellApi } from "./ShellApi.ts";
19
21
  import { Sidebar } from "./Sidebar.tsx";
20
22
  import { shellIds } from "./shellIds.ts";
23
+ import { ThemeContext } from "./ThemeContext.ts";
21
24
  import { UpdatesToggle } from "./UpdatesToggle.tsx";
22
25
  import { useAppearance } from "./useAppearance.ts";
23
26
  import { useBoardNavigation } from "./useBoardNavigation.ts";
@@ -33,42 +36,52 @@ export interface ShellOptions {
33
36
  }
34
37
  export function BoardShell(options: ShellOptions) {
35
38
  const [main, onPage] = useState(emptyMainLocation);
39
+ const appearance = useAppearance();
40
+ const [element, setElement] = useState<HTMLElement | null>(null);
41
+ const report = useCallback((next: HTMLElement, ready: boolean) => {
42
+ setElement((current) => {
43
+ if (ready) {
44
+ return next;
45
+ }
46
+ return current === next ? null : current;
47
+ });
48
+ }, []);
36
49
  return (
37
50
  <MainLocationContext.Provider value={main}>
38
- <BoardWorkspace {...options} onPage={onPage} />
51
+ <ReadingReadyContext.Provider value={{ element, report }}>
52
+ <SessionContext.Provider value={options.client}>
53
+ <ThemeContext.Provider value={appearance.scheme}>
54
+ <BoardWorkspace {...options} appearance={appearance} onPage={onPage} />
55
+ </ThemeContext.Provider>
56
+ </SessionContext.Provider>
57
+ </ReadingReadyContext.Provider>
39
58
  </MainLocationContext.Provider>
40
59
  );
41
60
  }
42
- function BoardWorkspace(options: ShellOptions & { readonly onPage: (location: MainLocation) => void }) {
43
- const { api, ready, client, onPage } = options;
61
+ function BoardWorkspace(
62
+ options: ShellOptions & { readonly appearance: ReturnType<typeof useAppearance>; readonly onPage: (location: MainLocation) => void },
63
+ ) {
64
+ const { api, ready, client, onPage, appearance } = options;
44
65
  const main = useMainLocation();
45
- const appearance = useAppearance();
46
66
  const sidebar = useSidebar(appearance);
47
- const status = useBoardNavigation(options);
67
+ const [phoneOpen, setPhoneOpen] = useState(false);
68
+ const closeCurrentDestination = useCallback(() => {
69
+ sidebar.close();
70
+ setPhoneOpen(false);
71
+ }, [sidebar.close]);
72
+ const status = useBoardNavigation(options, closeCurrentDestination);
48
73
  const search = useSearchDialog();
49
74
  const [libraryOpen, setLibraryOpen] = useState(false);
50
75
  const location = useRouterState({ select: (state) => state.location });
51
76
  const query = useQuery(navigationQuery(api), { keepPreviousData: true });
52
77
  const data = Option.getOrUndefined(query.data);
78
+ const { element } = useContext(ReadingReadyContext);
53
79
  useEffect(() => {
54
- function start() {
55
- const doc = document.getElementById("doc");
56
- const context = doc?.querySelector<HTMLElement>(".item-context");
57
- if (data && main.route && (!context || context.dataset.readingReady === "true")) {
58
- ready?.();
59
- }
60
- }
61
- start();
62
- document.addEventListener("board-reading-ready", start);
63
- return () => {
64
- document.removeEventListener("board-reading-ready", start);
65
- };
66
- }, [ready, data, main]);
67
- useEffect(() => {
68
- if (data) {
69
- document.dispatchEvent(new Event("board-index-change"));
80
+ const doc = document.getElementById("doc");
81
+ if (data && main.route && doc && readingReady(doc, element)) {
82
+ ready?.();
70
83
  }
71
- }, [data]);
84
+ }, [ready, data, main, element]);
72
85
  const live = client ? (
73
86
  <LiveControls client={client} navigationFailed={Option.isSome(query.cause)} navigationPending={query.pending} />
74
87
  ) : (
@@ -109,7 +122,7 @@ function BoardWorkspace(options: ShellOptions & { readonly onPage: (location: Ma
109
122
  updates={client ? <UpdatesToggle client={client} /> : null}
110
123
  />
111
124
  <FleetMain api={api} home={data?.home} onPage={onPage} url={location.pathname + location.searchStr} />
112
- <PhoneNavigation main={main} openSearch={search.show} />
125
+ <PhoneNavigation main={main} more={phoneOpen} onMoreChange={setPhoneOpen} openSearch={search.show} />
113
126
  </div>
114
127
  </div>
115
128
  {Option.isSome(query.cause) && <p role="status">Navigation refresh failed. Your displayed files are retained.</p>}
@@ -1,13 +1,15 @@
1
- import { useEffect, useLayoutEffect, useRef, useState } from "react";
1
+ import { useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
2
2
  import type { Document } from "#browser/document/schema.ts";
3
3
  import { Tabs } from "#client/react/components/ui/Tabs.tsx";
4
4
  import { Age } from "./Age.tsx";
5
5
  import { DocumentMetadata } from "./DocumentMetadata.tsx";
6
6
  import { DocumentSource } from "./DocumentSource.tsx";
7
7
  import { useMainLocation } from "./MainLocationContext.ts";
8
+ import { ReadingReadyContext } from "./ReadingReadyContext.ts";
8
9
 
9
10
  export function DocumentContext({ document: data }: { readonly document: Document }) {
10
11
  const page = useMainLocation();
12
+ const { report } = useContext(ReadingReadyContext);
11
13
  const [headings, setHeadings] = useState<readonly { readonly id: string; readonly title: string; readonly depth: number }[]>([]);
12
14
  const contextRef = useRef<HTMLElement>(null);
13
15
  const [tab, setTab] = useState("details");
@@ -42,9 +44,9 @@ export function DocumentContext({ document: data }: { readonly document: Documen
42
44
  if (count !== headings.length) {
43
45
  return;
44
46
  }
45
- context.dataset.readingReady = "true";
46
- document.dispatchEvent(new Event("board-reading-ready"));
47
- }, [headings]);
47
+ report(context, true);
48
+ return () => report(context, false);
49
+ }, [headings, report]);
48
50
  const tabs = [
49
51
  { content: <Outline headings={headings} />, label: "Details", value: "details" },
50
52
  { content: <SourcePanel document={data} />, label: "Source", value: "source" },
@@ -1,7 +1,7 @@
1
1
  import { useAtomValue } from "@effect/atom-react";
2
2
  import { Option } from "effect";
3
3
  import * as Atom from "effect/reactivity/Atom";
4
- import { useEffect, useMemo } from "react";
4
+ import { useMemo } from "react";
5
5
  import { useQuery } from "@shivaedev/effect-react/result-state.ts";
6
6
  import type { BrowserClient } from "#client/client.ts";
7
7
  import { activeRead } from "./activeRead.ts";
@@ -35,19 +35,6 @@ export function LiveControls({
35
35
  waiting: navigationPending || reading.pending,
36
36
  watching,
37
37
  });
38
- useEffect(
39
- () =>
40
- client.registry.subscribe(
41
- client.updates.paused,
42
- (value) => {
43
- if (!value) {
44
- document.dispatchEvent(new Event("board-updates-resumed"));
45
- }
46
- },
47
- { immediate: true },
48
- ),
49
- [client],
50
- );
51
38
  return (
52
39
  <span
53
40
  className="font-mono text-muted-foreground text-xs data-[state=down]:text-destructive data-[state=stale]:text-destructive"
@@ -1,5 +1,6 @@
1
+ import { useRouter } from "@tanstack/react-router";
1
2
  import { CalendarDays, Ellipsis, Flag, Search, Zap } from "lucide-react";
2
- import { useEffect, useState } from "react";
3
+ import { useEffect } from "react";
3
4
  import { Button } from "#client/react/components/ui/Button.tsx";
4
5
  import { Modal } from "./Modal.tsx";
5
6
  import type { MainLocation } from "./mainLocation.ts";
@@ -11,21 +12,25 @@ const icons = [CalendarDays, Flag, Zap];
11
12
  const TAB_CLASS =
12
13
  "flex min-h-12 min-w-0 flex-col items-center justify-center gap-1 rounded-md border-0 bg-transparent p-0 text-foreground text-xs no-underline aria-[current=page]:bg-accent aria-[current=page]:text-primary";
13
14
 
14
- export function PhoneNavigation({ main, openSearch }: { readonly main: MainLocation; readonly openSearch: () => void }) {
15
- const [more, setMore] = useState(false);
15
+ export function PhoneNavigation({
16
+ main,
17
+ more,
18
+ onMoreChange,
19
+ openSearch,
20
+ }: {
21
+ readonly main: MainLocation;
22
+ readonly more: boolean;
23
+ readonly onMoreChange: (open: boolean) => void;
24
+ readonly openSearch: () => void;
25
+ }) {
26
+ const router = useRouter();
16
27
  const narrow = useMedia("(max-width: 767px)");
17
28
  useEffect(() => {
18
29
  if (!narrow) {
19
- setMore(false);
30
+ onMoreChange(false);
20
31
  }
21
- }, [narrow]);
22
- useEffect(() => {
23
- function close() {
24
- setMore(false);
25
- }
26
- document.addEventListener("board-navigate", close);
27
- return () => document.removeEventListener("board-navigate", close);
28
- }, []);
32
+ }, [narrow, onMoreChange]);
33
+ useEffect(() => router.subscribe("onBeforeNavigate", () => onMoreChange(false)), [router, onMoreChange]);
29
34
  return (
30
35
  <>
31
36
  <nav
@@ -50,19 +55,19 @@ export function PhoneNavigation({ main, openSearch }: { readonly main: MainLocat
50
55
  aria-expanded={more}
51
56
  aria-haspopup="dialog"
52
57
  className={TAB_CLASS}
53
- onClick={() => setMore(true)}
58
+ onClick={() => onMoreChange(true)}
54
59
  type="button"
55
60
  >
56
61
  <Ellipsis aria-hidden="true" className="size-5" />
57
62
  More
58
63
  </button>
59
64
  </nav>
60
- <Modal className="phone-more" close={() => setMore(false)} id={shellIds.phoneMore} open={more} title={shellIds.phoneMoreTitle}>
65
+ <Modal className="phone-more" close={() => onMoreChange(false)} id={shellIds.phoneMore} open={more} title={shellIds.phoneMoreTitle}>
61
66
  <div className="mb-3 flex items-center justify-between">
62
67
  <h2 className="font-semibold" id={shellIds.phoneMoreTitle}>
63
68
  More
64
69
  </h2>
65
- <Button onClick={() => setMore(false)} variant="ghost">
70
+ <Button onClick={() => onMoreChange(false)} variant="ghost">
66
71
  Close
67
72
  </Button>
68
73
  </div>
@@ -1,4 +1,4 @@
1
- import { type ReactNode, useCallback, useEffect, useRef, useState } from "react";
1
+ import { type ReactNode, useCallback, useLayoutEffect, useRef, useState } from "react";
2
2
  import { LibraryContext, restoreLibrary } from "#client/react/LibraryContext.ts";
3
3
  import { useMainLocation } from "./MainLocationContext.ts";
4
4
  import { Modal } from "./Modal.tsx";
@@ -36,7 +36,7 @@ export function ReadingLibrary({
36
36
  },
37
37
  [key],
38
38
  );
39
- useEffect(() => {
39
+ useLayoutEffect(() => {
40
40
  function sync() {
41
41
  if (!page.route) {
42
42
  return;
@@ -55,10 +55,6 @@ export function ReadingLibrary({
55
55
  }
56
56
  }
57
57
  sync();
58
- document.addEventListener("board-index-change", sync);
59
- return () => {
60
- document.removeEventListener("board-index-change", sync);
61
- };
62
58
  }, [save, page]);
63
59
 
64
60
  return (
@@ -0,0 +1,11 @@
1
+ import { createContext } from "react";
2
+
3
+ export const ReadingReadyContext = createContext<{
4
+ readonly element: HTMLElement | null;
5
+ readonly report: (element: HTMLElement, ready: boolean) => void;
6
+ }>({ element: null, report: () => undefined });
7
+
8
+ export function readingReady(doc: HTMLElement, element: HTMLElement | null) {
9
+ const context = doc.querySelector(".item-context");
10
+ return !context || context === element;
11
+ }
@@ -0,0 +1,4 @@
1
+ import { createContext } from "react";
2
+ import type { BrowserClient } from "#client/client.ts";
3
+
4
+ export const SessionContext = createContext<BrowserClient | undefined>(undefined);
@@ -1,6 +1,8 @@
1
+ import { useContext } from "react";
1
2
  import { routeQueryOptions } from "#client/page/routeQuery.ts";
2
3
  import type { MainLocation } from "./mainLocation.ts";
3
4
  import { ProjectionFrame } from "./ProjectionFrame.tsx";
5
+ import { SessionContext } from "./SessionContext.ts";
4
6
  import type { ShellApi } from "./ShellApi.ts";
5
7
  import { SystemPage } from "./SystemPage.tsx";
6
8
  import { useDiagnosticsPolling } from "./useDiagnosticsPolling.ts";
@@ -15,7 +17,7 @@ export function SystemMain({
15
17
  readonly url: string;
16
18
  }) {
17
19
  const atom = api.diagnostics.query(undefined, routeQueryOptions);
18
- useDiagnosticsPolling(atom, api.fleetItems.query(undefined, routeQueryOptions));
20
+ useDiagnosticsPolling(useContext(SessionContext), atom, api.fleetItems.query(undefined, routeQueryOptions));
19
21
  return (
20
22
  <ProjectionFrame
21
23
  atom={atom}
@@ -0,0 +1,3 @@
1
+ import { createContext } from "react";
2
+
3
+ export const ThemeContext = createContext("light");
@@ -1,3 +1,4 @@
1
+ import type { AnyRouter } from "@tanstack/react-router";
1
2
  import { readingEntry } from "#client/react/storedReadings.ts";
2
3
 
3
4
  export function navigationFailure(status: number) {
@@ -25,3 +26,14 @@ export function sameReadingLocation(
25
26
  ) {
26
27
  return previous.route === next.route && previous.id === next.id && previous.hash === next.hash;
27
28
  }
29
+
30
+ export function recordEntry(router: AnyRouter, route: string, id: string, native: boolean) {
31
+ if (!native) {
32
+ return;
33
+ }
34
+ router.history.flush?.();
35
+ if (window.location.pathname + window.location.search !== route || window.history.state?.workBoard?.id === id) {
36
+ return;
37
+ }
38
+ window.history.replaceState({ ...window.history.state, workBoard: { id } }, "");
39
+ }
@@ -9,18 +9,10 @@ export function scheduleReading(
9
9
  setStatus: (status: string) => void,
10
10
  focus: boolean,
11
11
  ) {
12
- let restored = false;
13
12
  function restore() {
14
- if (restored || !active()) {
15
- document.removeEventListener("board-reading-ready", restore);
13
+ if (!active()) {
16
14
  return;
17
15
  }
18
- const context = doc.querySelector<HTMLElement>(".item-context");
19
- if (context && context.dataset.readingReady !== "true") {
20
- return;
21
- }
22
- restored = true;
23
- document.removeEventListener("board-reading-ready", restore);
24
16
  if (focus && !document.activeElement?.closest("[data-response-form], #response-form, #handoff-form")) {
25
17
  doc.focus({ preventScroll: true });
26
18
  }
@@ -41,6 +33,5 @@ export function scheduleReading(
41
33
  }
42
34
  });
43
35
  }
44
- document.addEventListener("board-reading-ready", restore);
45
36
  requestAnimationFrame(restore);
46
37
  }
@@ -37,7 +37,6 @@ export function useAppearance() {
37
37
  if (doc) {
38
38
  doc.dataset.scheme = scheme;
39
39
  }
40
- document.dispatchEvent(new Event("board-theme"));
41
40
  }, [value.theme, value.density, scheme]);
42
41
  function change(next: Partial<Pick<typeof value, "closed" | "density" | "theme">>) {
43
42
  const appearance = { closed: valueRef.current.closed, density: valueRef.current.density, theme: valueRef.current.theme, ...next };
@@ -50,6 +49,6 @@ export function useAppearance() {
50
49
  valueRef.current = { ...appearance, notice };
51
50
  setValue(valueRef.current);
52
51
  }
53
- return { ...value, change };
52
+ return { ...value, change, scheme };
54
53
  }
55
- export type AppearanceControls = ReturnType<typeof useAppearance>;
54
+ export type AppearanceControls = Omit<ReturnType<typeof useAppearance>, "scheme">;