@shivaedev/work-board 0.17.0 → 0.18.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 +27 -0
- package/README.md +27 -25
- package/assets/react.css +1 -1
- package/assets/react.js +37 -36
- package/dist/browser/responses/cardContext.d.ts +8 -1
- package/dist/browser/responses/cardContext.d.ts.map +1 -1
- package/dist/browser/responses/cardContext.js +12 -7
- package/dist/browser/responses/cardContext.js.map +1 -1
- package/dist/browser/views/now.d.ts +5 -0
- package/dist/browser/views/now.d.ts.map +1 -1
- package/dist/browser/views/now.js +38 -2
- package/dist/browser/views/now.js.map +1 -1
- package/dist/browser/views/schema.d.ts +11 -0
- package/dist/browser/views/schema.d.ts.map +1 -1
- package/dist/browser/views/schema.js +1 -0
- package/dist/browser/views/schema.js.map +1 -1
- package/dist/client/document/View.js +1 -1
- package/dist/client/document/View.js.map +1 -1
- package/dist/client/formStatus.d.ts +2 -2
- package/dist/client/formStatus.d.ts.map +1 -1
- package/dist/client/formStatus.js +2 -2
- package/dist/client/formStatus.js.map +1 -1
- package/dist/client/react/AnswerContext.d.ts.map +1 -1
- package/dist/client/react/AnswerContext.js +5 -2
- package/dist/client/react/AnswerContext.js.map +1 -1
- package/dist/client/react/AnswerForm.d.ts.map +1 -1
- package/dist/client/react/AnswerForm.js +6 -2
- package/dist/client/react/AnswerForm.js.map +1 -1
- package/dist/client/react/AnswerMarkdown.d.ts +6 -0
- package/dist/client/react/AnswerMarkdown.d.ts.map +1 -0
- package/dist/client/react/AnswerMarkdown.js +7 -0
- package/dist/client/react/AnswerMarkdown.js.map +1 -0
- package/dist/client/react/AnswerMore.d.ts.map +1 -1
- package/dist/client/react/AnswerMore.js +2 -1
- package/dist/client/react/AnswerMore.js.map +1 -1
- package/dist/client/react/AnswerPanel.d.ts.map +1 -1
- package/dist/client/react/AnswerPanel.js +3 -2
- package/dist/client/react/AnswerPanel.js.map +1 -1
- package/dist/client/react/AnswerPrompts.d.ts.map +1 -1
- package/dist/client/react/AnswerPrompts.js +16 -10
- package/dist/client/react/AnswerPrompts.js.map +1 -1
- package/dist/client/react/BoardShell.js +2 -2
- package/dist/client/react/BoardShell.js.map +1 -1
- package/dist/client/react/DocumentMain.d.ts.map +1 -1
- package/dist/client/react/DocumentMain.js +2 -2
- package/dist/client/react/DocumentMain.js.map +1 -1
- package/dist/client/react/FleetMain.js +1 -1
- package/dist/client/react/FleetMain.js.map +1 -1
- package/dist/client/react/FormField.js +1 -1
- package/dist/client/react/FormField.js.map +1 -1
- package/dist/client/react/GoalPage.js +2 -2
- package/dist/client/react/GoalPage.js.map +1 -1
- package/dist/client/react/GoalProgressHeader.js +2 -2
- package/dist/client/react/GoalProgressHeader.js.map +1 -1
- package/dist/client/react/Header.d.ts.map +1 -1
- package/dist/client/react/Header.js +3 -2
- package/dist/client/react/Header.js.map +1 -1
- package/dist/client/react/LibraryContents.js +1 -1
- package/dist/client/react/LibraryContents.js.map +1 -1
- package/dist/client/react/LibraryMain.d.ts.map +1 -1
- package/dist/client/react/LibraryMain.js +1 -1
- package/dist/client/react/LibraryMain.js.map +1 -1
- package/dist/client/react/LibraryPage.js +2 -2
- package/dist/client/react/LibraryPage.js.map +1 -1
- package/dist/client/react/LiveControls.js +1 -1
- package/dist/client/react/LiveControls.js.map +1 -1
- package/dist/client/react/ProjectionMain.d.ts.map +1 -1
- package/dist/client/react/ProjectionMain.js +1 -1
- package/dist/client/react/ProjectionMain.js.map +1 -1
- package/dist/client/react/PromptOption.d.ts.map +1 -1
- package/dist/client/react/PromptOption.js +7 -5
- package/dist/client/react/PromptOption.js.map +1 -1
- package/dist/client/react/ReadingHistory.js +1 -1
- package/dist/client/react/ReadingHistory.js.map +1 -1
- package/dist/client/react/RemainingMain.d.ts.map +1 -1
- package/dist/client/react/RemainingMain.js +1 -1
- package/dist/client/react/RemainingMain.js.map +1 -1
- package/dist/client/react/ResponseHistory.d.ts.map +1 -1
- package/dist/client/react/ResponseHistory.js +11 -5
- package/dist/client/react/ResponseHistory.js.map +1 -1
- package/dist/client/react/SearchPalette.js +1 -1
- package/dist/client/react/SearchPalette.js.map +1 -1
- package/dist/client/react/Sidebar.d.ts.map +1 -1
- package/dist/client/react/Sidebar.js +9 -2
- package/dist/client/react/Sidebar.js.map +1 -1
- package/dist/client/react/SystemFleetLane.d.ts.map +1 -1
- package/dist/client/react/SystemFleetLane.js +2 -1
- package/dist/client/react/SystemFleetLane.js.map +1 -1
- package/dist/client/react/SystemHealth.d.ts +2 -1
- package/dist/client/react/SystemHealth.d.ts.map +1 -1
- package/dist/client/react/SystemHealth.js +3 -2
- package/dist/client/react/SystemHealth.js.map +1 -1
- package/dist/client/react/SystemMain.d.ts.map +1 -1
- package/dist/client/react/SystemMain.js +6 -2
- package/dist/client/react/SystemMain.js.map +1 -1
- package/dist/client/react/SystemPage.d.ts +2 -1
- package/dist/client/react/SystemPage.d.ts.map +1 -1
- package/dist/client/react/SystemPage.js +2 -2
- package/dist/client/react/SystemPage.js.map +1 -1
- package/dist/client/react/TodayNeeds.d.ts +5 -0
- package/dist/client/react/TodayNeeds.d.ts.map +1 -1
- package/dist/client/react/TodayNeeds.js +6 -3
- package/dist/client/react/TodayNeeds.js.map +1 -1
- package/dist/client/react/TodayOptionButton.d.ts +14 -0
- package/dist/client/react/TodayOptionButton.d.ts.map +1 -0
- package/dist/client/react/TodayOptionButton.js +10 -0
- package/dist/client/react/TodayOptionButton.js.map +1 -0
- package/dist/client/react/TodayOptions.d.ts.map +1 -1
- package/dist/client/react/TodayOptions.js +18 -14
- package/dist/client/react/TodayOptions.js.map +1 -1
- package/dist/client/react/TodayPage.d.ts.map +1 -1
- package/dist/client/react/TodayPage.js +20 -5
- package/dist/client/react/TodayPage.js.map +1 -1
- package/dist/client/react/WorkCard.d.ts.map +1 -1
- package/dist/client/react/WorkCard.js +7 -2
- package/dist/client/react/WorkCard.js.map +1 -1
- package/dist/client/react/WorkLane.d.ts.map +1 -1
- package/dist/client/react/WorkLane.js +1 -1
- package/dist/client/react/WorkLane.js.map +1 -1
- package/dist/client/react/WorkNow.js +1 -1
- package/dist/client/react/WorkNow.js.map +1 -1
- package/dist/client/react/activeRead.js +1 -1
- package/dist/client/react/activeRead.js.map +1 -1
- package/dist/client/react/destinationName.d.ts +2 -0
- package/dist/client/react/destinationName.d.ts.map +1 -0
- package/dist/client/react/destinationName.js +4 -0
- package/dist/client/react/destinationName.js.map +1 -0
- package/dist/client/react/loadBoardPage.d.ts.map +1 -1
- package/dist/client/react/loadBoardPage.js +2 -2
- package/dist/client/react/loadBoardPage.js.map +1 -1
- package/dist/client/react/loadProjection.d.ts +135 -135
- package/dist/client/react/loadProjection.d.ts.map +1 -1
- package/dist/client/react/loadProjection.js +2 -2
- package/dist/client/react/loadProjection.js.map +1 -1
- package/dist/client/react/loadRemaining.d.ts +184 -184
- package/dist/client/react/loadRemaining.d.ts.map +1 -1
- package/dist/client/react/loadRemaining.js +2 -2
- package/dist/client/react/loadRemaining.js.map +1 -1
- package/dist/client/react/pageQueries.js +1 -1
- package/dist/client/react/pageQueries.js.map +1 -1
- package/dist/client/react/resolvedDocumentFailure.d.ts.map +1 -0
- package/dist/client/react/resolvedDocumentFailure.js.map +1 -0
- package/dist/client/react/routeQuery.d.ts.map +1 -0
- package/dist/client/react/routeQuery.js.map +1 -0
- package/dist/client/react/useHandoffForm.js +1 -1
- package/dist/client/react/useHandoffForm.js.map +1 -1
- package/dist/client/react/useProjectionData.d.ts +1 -1
- package/dist/client/react/useProjectionData.js +1 -1
- package/dist/client/react/useProjectionData.js.map +1 -1
- package/dist/client/react/useResponseForm.d.ts.map +1 -1
- package/dist/client/react/useResponseForm.js +3 -3
- package/dist/client/react/useResponseForm.js.map +1 -1
- package/dist/client/responses/summary.d.ts +1 -0
- package/dist/client/responses/summary.d.ts.map +1 -1
- package/dist/client/responses/summary.js +12 -1
- package/dist/client/responses/summary.js.map +1 -1
- package/dist/diagnostics/source.js +1 -1
- package/dist/diagnostics/source.js.map +1 -1
- package/dist/rpc/contract.d.ts +1951 -1918
- package/dist/rpc/contract.d.ts.map +1 -1
- package/dist/server/Responses.js +2 -2
- package/dist/server/Responses.js.map +1 -1
- package/dist/server/attention/inbox.d.ts +13 -2
- package/dist/server/attention/inbox.d.ts.map +1 -1
- package/dist/server/attention/inbox.js +44 -27
- package/dist/server/attention/inbox.js.map +1 -1
- package/dist/server/attention/managedRequestReceipt.d.ts +10 -0
- package/dist/server/attention/managedRequestReceipt.d.ts.map +1 -1
- package/dist/server/attention/managedRequestReceipt.js +29 -10
- package/dist/server/attention/managedRequestReceipt.js.map +1 -1
- package/dist/server/attention/projection.d.ts.map +1 -1
- package/dist/server/attention/projection.js +2 -1
- package/dist/server/attention/projection.js.map +1 -1
- package/dist/server/attention/requestInbox.d.ts +3 -3
- package/dist/server/attention/requestInbox.js +2 -2
- package/dist/server/attention/requestInbox.js.map +1 -1
- package/dist/server/attention/requests.d.ts +1 -0
- package/dist/server/attention/requests.d.ts.map +1 -1
- package/dist/server/attention/requests.js +7 -3
- package/dist/server/attention/requests.js.map +1 -1
- package/dist/server/board.js +1 -1
- package/dist/server/board.js.map +1 -1
- package/dist/server/document/answerBody.d.ts.map +1 -1
- package/dist/server/document/answerBody.js +9 -1
- package/dist/server/document/answerBody.js.map +1 -1
- package/dist/server/document/reviewedWork.d.ts +3 -0
- package/dist/server/document/reviewedWork.d.ts.map +1 -0
- package/dist/server/document/reviewedWork.js +23 -0
- package/dist/server/document/reviewedWork.js.map +1 -0
- package/dist/server/files/changes.d.ts.map +1 -1
- package/dist/server/files/changes.js +1 -1
- package/dist/server/files/changes.js.map +1 -1
- package/dist/server/files/watchDirectories.d.ts +1 -1
- package/dist/server/files/watchDirectories.d.ts.map +1 -1
- package/dist/server/files/watchDirectories.js +71 -12
- package/dist/server/files/watchDirectories.js.map +1 -1
- package/dist/server/handoffs/Service.js +2 -2
- package/dist/server/handoffs/Service.js.map +1 -1
- package/dist/server/handoffs/source.js +1 -1
- package/dist/server/handoffs/source.js.map +1 -1
- package/dist/server/http/boardRoutes.js +1 -1
- package/dist/server/http/boardRoutes.js.map +1 -1
- package/dist/server/mcp/client.d.ts +11 -0
- package/dist/server/mcp/client.d.ts.map +1 -1
- package/dist/server/mcp/queries.d.ts +2851 -2818
- package/dist/server/mcp/queries.d.ts.map +1 -1
- package/dist/server/packageInfo.d.ts +1 -1
- package/dist/server/packageInfo.js +1 -1
- package/dist/server/render/Highlighter.js +1 -1
- package/dist/server/render/Highlighter.js.map +1 -1
- package/dist/server/responses/locate.js +1 -1
- package/dist/server/responses/locate.js.map +1 -1
- package/dist/server/rpc/handlers.js +2 -2
- package/dist/server/rpc/handlers.js.map +1 -1
- package/dist/server/serve.js +1 -1
- package/dist/server/serve.js.map +1 -1
- package/dist/server/views/projectionQueries.d.ts +11 -0
- package/dist/server/views/projectionQueries.d.ts.map +1 -1
- package/dist/server/workspace.js +1 -1
- package/dist/server/workspace.js.map +1 -1
- package/docs/delivery/README.md +2 -2
- package/package.json +18 -362
- package/src/browser/responses/cardContext.ts +13 -7
- package/src/browser/views/now.ts +42 -2
- package/src/browser/views/schema.ts +1 -0
- package/src/client/document/View.ts +1 -1
- package/src/client/formStatus.ts +3 -3
- package/src/client/react/AnswerContext.tsx +9 -4
- package/src/client/react/AnswerForm.tsx +25 -6
- package/src/client/react/AnswerMarkdown.tsx +15 -0
- package/src/client/react/AnswerMore.tsx +58 -46
- package/src/client/react/AnswerPanel.tsx +14 -8
- package/src/client/react/AnswerPrompts.tsx +33 -18
- package/src/client/react/BoardShell.tsx +2 -2
- package/src/client/react/DocumentMain.tsx +2 -2
- package/src/client/react/FleetMain.tsx +1 -1
- package/src/client/react/FormField.tsx +1 -1
- package/src/client/react/GoalPage.tsx +2 -2
- package/src/client/react/GoalProgressHeader.tsx +2 -2
- package/src/client/react/Header.tsx +3 -2
- package/src/client/react/LibraryContents.tsx +1 -1
- package/src/client/react/LibraryMain.tsx +1 -1
- package/src/client/react/LibraryPage.tsx +2 -2
- package/src/client/react/LiveControls.tsx +1 -1
- package/src/client/react/ProjectionMain.tsx +1 -1
- package/src/client/react/PromptOption.tsx +39 -24
- package/src/client/react/ReadingHistory.tsx +1 -1
- package/src/client/react/RemainingMain.tsx +1 -1
- package/src/client/react/ResponseHistory.tsx +53 -14
- package/src/client/react/SearchPalette.tsx +1 -1
- package/src/client/react/Sidebar.tsx +10 -2
- package/src/client/react/SystemFleetLane.tsx +2 -1
- package/src/client/react/SystemHealth.tsx +24 -4
- package/src/client/react/SystemMain.tsx +6 -2
- package/src/client/react/SystemPage.tsx +8 -2
- package/src/client/react/TodayNeeds.tsx +21 -6
- package/src/client/react/TodayOptionButton.tsx +35 -0
- package/src/client/react/TodayOptions.tsx +42 -33
- package/src/client/react/TodayPage.tsx +36 -7
- package/src/client/react/WorkCard.tsx +16 -8
- package/src/client/react/WorkLane.tsx +8 -2
- package/src/client/react/WorkNow.tsx +1 -1
- package/src/client/react/activeRead.ts +1 -1
- package/src/client/react/destinationName.ts +3 -0
- package/src/client/react/entry.css +0 -6
- package/src/client/react/loadBoardPage.ts +2 -2
- package/src/client/react/loadProjection.ts +2 -2
- package/src/client/react/loadRemaining.ts +2 -2
- package/src/client/react/pageQueries.ts +1 -1
- package/src/client/react/useHandoffForm.ts +1 -1
- package/src/client/react/useProjectionData.ts +1 -1
- package/src/client/react/useResponseForm.ts +5 -3
- package/src/client/responses/summary.ts +13 -1
- package/src/diagnostics/source.ts +1 -1
- package/src/server/Responses.ts +2 -2
- package/src/server/attention/inbox.ts +51 -27
- package/src/server/attention/managedRequestReceipt.ts +41 -10
- package/src/server/attention/projection.ts +5 -2
- package/src/server/attention/requestInbox.ts +2 -2
- package/src/server/attention/requests.ts +7 -2
- package/src/server/board.ts +1 -1
- package/src/server/document/answerBody.ts +10 -1
- package/src/server/document/reviewedWork.ts +24 -0
- package/src/server/files/changes.ts +1 -0
- package/src/server/files/watchDirectories.ts +90 -27
- package/src/server/handoffs/Service.ts +2 -2
- package/src/server/handoffs/source.ts +1 -1
- package/src/server/http/boardRoutes.ts +1 -1
- package/src/server/packageInfo.ts +1 -1
- package/src/server/render/Highlighter.ts +1 -1
- package/src/server/responses/locate.ts +1 -1
- package/src/server/rpc/handlers.ts +2 -2
- package/src/server/serve.ts +1 -1
- package/src/server/workspace.ts +1 -1
- package/dist/client/page/resolvedDocumentFailure.d.ts.map +0 -1
- package/dist/client/page/resolvedDocumentFailure.js.map +0 -1
- package/dist/client/page/routeQuery.d.ts.map +0 -1
- package/dist/client/page/routeQuery.js.map +0 -1
- /package/dist/client/{page → react}/resolvedDocumentFailure.d.ts +0 -0
- /package/dist/client/{page → react}/resolvedDocumentFailure.js +0 -0
- /package/dist/client/{page → react}/routeQuery.d.ts +0 -0
- /package/dist/client/{page → react}/routeQuery.js +0 -0
- /package/src/client/{page → react}/resolvedDocumentFailure.ts +0 -0
- /package/src/client/{page → react}/routeQuery.ts +0 -0
|
@@ -10,15 +10,16 @@ export function cardContext(source: string) {
|
|
|
10
10
|
return { links, recommendation };
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function
|
|
14
|
-
const heading =
|
|
15
|
-
if (heading) {
|
|
16
|
-
return heading;
|
|
13
|
+
export function optionText(id: string, source: string) {
|
|
14
|
+
const heading = promptHeading(source);
|
|
15
|
+
if (heading.title) {
|
|
16
|
+
return { description: heading.rest, label: heading.title };
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const lead = /^\*\*(?<label>[^*]+)\*\*\s*(?:[—–:-]\s*)?/u.exec(source.trim());
|
|
19
|
+
if (lead?.groups?.label) {
|
|
20
|
+
return { description: source.trim().slice(lead[0].length).trim(), label: lead.groups.label.trim() };
|
|
20
21
|
}
|
|
21
|
-
return id.charAt(0).toUpperCase() + id.slice(1).replaceAll("-", " ");
|
|
22
|
+
return { description: source.trim(), label: id.charAt(0).toUpperCase() + id.slice(1).replaceAll("-", " ") };
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
function section(source: string, title: string) {
|
|
@@ -48,3 +49,8 @@ function section(source: string, title: string) {
|
|
|
48
49
|
function nextFence(current: string | undefined, marker: string) {
|
|
49
50
|
return current?.startsWith(marker.charAt(0)) && marker.length >= current.length ? undefined : marker;
|
|
50
51
|
}
|
|
52
|
+
|
|
53
|
+
export function promptHeading(source: string) {
|
|
54
|
+
const heading = /^#{1,6}\s+(?<title>.+)$/mu.exec(source);
|
|
55
|
+
return { rest: heading ? source.replace(heading[0], "").trim() : source.trim(), title: heading?.groups?.title?.trim() };
|
|
56
|
+
}
|
package/src/browser/views/now.ts
CHANGED
|
@@ -51,11 +51,51 @@ function authoredLane(status: string | undefined, approved: boolean): NowLane |
|
|
|
51
51
|
return Object.entries(stages).find(([stage]) => stage === status)?.[1];
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
const fleetHolders: Record<FleetWork["stage"], string> = {
|
|
55
|
+
adopting: "Fleet is working on this",
|
|
56
|
+
completed: "Fleet finished this",
|
|
57
|
+
delivering: "Fleet is working on this",
|
|
58
|
+
executing: "Fleet is working on this",
|
|
59
|
+
"needs-human": "Waiting on a person",
|
|
60
|
+
prepared: "Queued for Fleet",
|
|
61
|
+
released: "Fleet handed this back",
|
|
62
|
+
repairing: "Fleet is working on this",
|
|
63
|
+
reviewing: "Fleet is working on this",
|
|
64
|
+
validating: "Fleet is working on this",
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export function fleetHolder(fleet: FleetWork): string {
|
|
68
|
+
if (fleet.attentionOwner === "maintainer") {
|
|
69
|
+
return "Needs you";
|
|
70
|
+
}
|
|
71
|
+
return fleet.attentionOwner === "orchestrator" ? "Waiting on the orchestrator" : fleetHolders[fleet.stage];
|
|
72
|
+
}
|
|
73
|
+
|
|
54
74
|
export function holderOf(metadata: Metadata, fleet: FleetWork | undefined): string | undefined {
|
|
55
75
|
if (fleet) {
|
|
56
|
-
return fleet
|
|
76
|
+
return fleetHolder(fleet);
|
|
57
77
|
}
|
|
58
|
-
|
|
78
|
+
if (metadata.owner === "maintainer") {
|
|
79
|
+
return "Assigned to you";
|
|
80
|
+
}
|
|
81
|
+
return metadata.owner === "orchestrator" ? "Assigned to the orchestrator" : undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const stageNames: Record<FleetWork["stage"], string> = {
|
|
85
|
+
adopting: "Adopting",
|
|
86
|
+
completed: "Done",
|
|
87
|
+
delivering: "Delivering",
|
|
88
|
+
executing: "Executing",
|
|
89
|
+
"needs-human": "Waiting",
|
|
90
|
+
prepared: "Queued",
|
|
91
|
+
released: "Handed back",
|
|
92
|
+
repairing: "Repairing",
|
|
93
|
+
reviewing: "Reviewing",
|
|
94
|
+
validating: "Validating",
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export function stageTime(stage: FleetWork["stage"]): { readonly ended: boolean; readonly label: string } {
|
|
98
|
+
return { ended: stage === "completed" || stage === "released", label: stageNames[stage] };
|
|
59
99
|
}
|
|
60
100
|
|
|
61
101
|
export function cardStatus(metadata: Metadata, fleet: FleetWork | undefined, waiting: string | undefined): string | undefined {
|
|
@@ -40,6 +40,7 @@ export const InboxProjection = Schema.Struct({
|
|
|
40
40
|
complete: Schema.Boolean,
|
|
41
41
|
issues: Schema.Array(Schema.Struct({ file: Schema.String, line: Schema.Number, message: Schema.String })),
|
|
42
42
|
items: Schema.Array(InboxItem),
|
|
43
|
+
later: Schema.Array(InboxItem),
|
|
43
44
|
parked: Schema.Array(InboxItem),
|
|
44
45
|
resolved: Schema.Array(InboxItem),
|
|
45
46
|
sourceIssues: Schema.Boolean,
|
|
@@ -3,7 +3,7 @@ import { type Components, MarkdownHooks } from "react-markdown";
|
|
|
3
3
|
import rehypeRaw from "rehype-raw";
|
|
4
4
|
import type { PluggableList } from "unified";
|
|
5
5
|
import type { Document } from "#browser/document/schema.ts";
|
|
6
|
-
import { Age } from "#client/react/Age";
|
|
6
|
+
import { Age } from "#client/react/Age.tsx";
|
|
7
7
|
import { documentHeadings } from "#render/documentHeadings.ts";
|
|
8
8
|
import { documentLinks } from "#render/documentLinks.ts";
|
|
9
9
|
import { documentPlugins } from "#render/documentPlugins.ts";
|
package/src/client/formStatus.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
|
-
import type { SaveState } from "@shivaedev/effect-react/
|
|
2
|
+
import type { SaveState } from "@shivaedev/effect-react/client/saveState.ts";
|
|
3
3
|
import { type SaveFailure, saveFailure } from "./saveFailure.ts";
|
|
4
4
|
|
|
5
5
|
export type DraftInteraction = "draft" | "cleared" | "submitted";
|
|
@@ -30,6 +30,6 @@ export function formStatus<A>(
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export function responseSaved(id: string, dirty: boolean) {
|
|
34
|
-
return `Saved: responses/${id}.md. This records
|
|
33
|
+
export function responseSaved(id: string, dirty: boolean, choice = "") {
|
|
34
|
+
return `Saved: your answer${choice ? ` “${choice}”` : ""} is recorded. The agent reads it from responses/${id}.md the next time it checks. This records your answer, not acceptance of the work.${dirty ? " Your current draft remains unsaved." : ""}`;
|
|
35
35
|
}
|
|
@@ -1,25 +1,30 @@
|
|
|
1
|
+
import { ExternalLink } from "lucide-react";
|
|
1
2
|
import { cardContext } from "#browser/responses/cardContext.ts";
|
|
2
3
|
import type { QuestionPreview } from "#browser/responses/schema.ts";
|
|
3
|
-
import {
|
|
4
|
+
import { buttonVariants } from "#client/react/components/ui/buttonVariants.ts";
|
|
5
|
+
import { cn } from "#client/react/lib/cn.ts";
|
|
6
|
+
import { AnswerMarkdown } from "./AnswerMarkdown.tsx";
|
|
4
7
|
|
|
5
8
|
export function AnswerContext({ preview }: { readonly preview: QuestionPreview }) {
|
|
6
9
|
const context = cardContext(preview.context);
|
|
7
10
|
return (
|
|
8
11
|
<>
|
|
9
12
|
{Boolean(context.recommendation) && (
|
|
10
|
-
<div className="
|
|
11
|
-
<
|
|
13
|
+
<div className="rounded-lg bg-muted/60 px-4 py-3 text-sm">
|
|
14
|
+
<p className="mb-1 font-medium text-muted-foreground text-xs uppercase tracking-wide">Recommendation</p>
|
|
15
|
+
<AnswerMarkdown className="answer-recommendation" file={preview.source} source={context.recommendation} />
|
|
12
16
|
</div>
|
|
13
17
|
)}
|
|
14
18
|
{context.links.length > 0 && (
|
|
15
19
|
<div className="answer-links flex flex-wrap gap-2">
|
|
16
20
|
{context.links.map((link) => (
|
|
17
21
|
<a
|
|
18
|
-
className={
|
|
22
|
+
className={cn(buttonVariants({ size: "sm", variant: link.primary ? "default" : "outline" }), "answer-link")}
|
|
19
23
|
href={link.url}
|
|
20
24
|
key={link.url}
|
|
21
25
|
>
|
|
22
26
|
{link.label}
|
|
27
|
+
<ExternalLink aria-hidden="true" />
|
|
23
28
|
</a>
|
|
24
29
|
))}
|
|
25
30
|
</div>
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { CheckCircle2 } from "lucide-react";
|
|
1
2
|
import type { Document, DocumentRequest } from "#browser/document/schema.ts";
|
|
2
3
|
import type { QuestionPreview } from "#browser/responses/schema.ts";
|
|
4
|
+
import { Button } from "#client/react/components/ui/Button.tsx";
|
|
5
|
+
import { cn } from "#client/react/lib/cn.ts";
|
|
3
6
|
import { AnswerMore } from "./AnswerMore.tsx";
|
|
4
7
|
import { AnswerPrompts } from "./AnswerPrompts.tsx";
|
|
5
8
|
import { FormField } from "./FormField.tsx";
|
|
@@ -7,6 +10,8 @@ import { shellIds } from "./shellIds.ts";
|
|
|
7
10
|
import { useFormFocus } from "./useFormFocus.ts";
|
|
8
11
|
import { useResponseForm } from "./useResponseForm.ts";
|
|
9
12
|
|
|
13
|
+
const READ_ONLY = "This Board is read-only. Start it with --responses to record answers.";
|
|
14
|
+
|
|
10
15
|
interface AnswerProps {
|
|
11
16
|
readonly document: Document;
|
|
12
17
|
readonly preview: QuestionPreview;
|
|
@@ -38,6 +43,7 @@ function AnswerSession({ document: data, request, preview }: AnswerProps) {
|
|
|
38
43
|
return (
|
|
39
44
|
<form
|
|
40
45
|
{...focus}
|
|
46
|
+
className="space-y-4"
|
|
41
47
|
data-item={preview.item}
|
|
42
48
|
data-question={preview.id}
|
|
43
49
|
data-request={preview.request}
|
|
@@ -76,13 +82,26 @@ function AnswerSession({ document: data, request, preview }: AnswerProps) {
|
|
|
76
82
|
showErrors={state.attempted}
|
|
77
83
|
/>
|
|
78
84
|
{prompts.length === 0 && body}
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
86
|
+
<Button disabled={!data.writable || state.created.saving} id={id(shellIds.responseSubmit)} type="submit">
|
|
87
|
+
Record answer
|
|
88
|
+
</Button>
|
|
89
|
+
</div>
|
|
90
|
+
<p
|
|
91
|
+
className={cn(
|
|
92
|
+
"flex items-start gap-2 text-sm empty:hidden",
|
|
93
|
+
!data.writable && "text-muted-foreground",
|
|
94
|
+
state.outcome === "saved" && "rounded-md border border-done/40 bg-done/10 px-3 py-2",
|
|
95
|
+
(state.outcome === "rejected" || state.outcome === "uncertain") && "rounded-md border border-destructive/40 px-3 py-2 text-destructive",
|
|
96
|
+
)}
|
|
97
|
+
data-outcome={state.outcome}
|
|
98
|
+
id={id(shellIds.responseStatus)}
|
|
99
|
+
role="status"
|
|
100
|
+
>
|
|
101
|
+
{state.outcome === "saved" && <CheckCircle2 aria-hidden="true" className="mt-0.5 size-4 shrink-0 text-done" />}
|
|
102
|
+
{data.writable ? writableStatus : `${state.status} ${READ_ONLY}`.trim()}
|
|
85
103
|
</p>
|
|
104
|
+
<AnswerMore body={prompts.length > 0 ? body : undefined} id={id} request={request} state={state} />
|
|
86
105
|
</form>
|
|
87
106
|
);
|
|
88
107
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cn } from "#client/react/lib/cn.ts";
|
|
2
|
+
import { ResponseMarkdown } from "./ResponseMarkdown.tsx";
|
|
3
|
+
|
|
4
|
+
export function AnswerMarkdown({ className, file, source }: { readonly className?: string; readonly file: string; readonly source: string }) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
className={cn(
|
|
8
|
+
"[&_a]:underline [&_a]:underline-offset-4 [&_code]:font-mono [&_code]:text-[0.9em] [&_li]:my-1 [&_ol]:list-decimal [&_ol]:pl-5 [&_p+p]:mt-2 [&_ul]:list-disc [&_ul]:pl-5",
|
|
9
|
+
className,
|
|
10
|
+
)}
|
|
11
|
+
>
|
|
12
|
+
<ResponseMarkdown file={file} source={source} />
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { DocumentRequest } from "#browser/document/schema.ts";
|
|
3
|
+
import { Button } from "#client/react/components/ui/Button.tsx";
|
|
3
4
|
import { FormField } from "./FormField.tsx";
|
|
4
5
|
import { shellIds } from "./shellIds.ts";
|
|
5
6
|
import type { useResponseForm } from "./useResponseForm.ts";
|
|
@@ -16,52 +17,63 @@ export function AnswerMore({
|
|
|
16
17
|
readonly state: ReturnType<typeof useResponseForm>;
|
|
17
18
|
}) {
|
|
18
19
|
return (
|
|
19
|
-
<details data-key="response-details">
|
|
20
|
-
<summary>More</summary>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{record.id}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{state.recovery}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
20
|
+
<details className="group rounded-lg border px-4 py-2 text-sm [&[open]]:pb-4" data-key="response-details">
|
|
21
|
+
<summary className="cursor-pointer select-none py-1 text-muted-foreground hover:text-foreground">More options</summary>
|
|
22
|
+
<div className="mt-3 grid gap-4">
|
|
23
|
+
<FormField
|
|
24
|
+
autoComplete="nickname"
|
|
25
|
+
form={state.form}
|
|
26
|
+
label="Local author label"
|
|
27
|
+
maxLength={200}
|
|
28
|
+
name="author"
|
|
29
|
+
required
|
|
30
|
+
showErrors={state.attempted}
|
|
31
|
+
/>
|
|
32
|
+
<FormField form={state.form} label="Response kind" name="type">
|
|
33
|
+
<option value="answer">Answer (including no)</option>
|
|
34
|
+
<option value="clarify">Ask back / clarify</option>
|
|
35
|
+
<option value="not_now">Not now</option>
|
|
36
|
+
</FormField>
|
|
37
|
+
{body}
|
|
38
|
+
<FormField form={state.form} label="Supersedes an earlier response (optional)" name="supersedes">
|
|
39
|
+
<option value="">Adds feedback; does not supersede</option>
|
|
40
|
+
{request.responses?.map((record) => (
|
|
41
|
+
<option key={record.id} value={record.id}>
|
|
42
|
+
{record.id} · {record.response.author} · {record.response.reviewedRevision.slice(0, 12)}
|
|
43
|
+
</option>
|
|
44
|
+
))}
|
|
45
|
+
</FormField>
|
|
46
|
+
<pre className="whitespace-pre-wrap rounded-md bg-muted p-3 text-xs" hidden={!state.recovery} id={id(shellIds.responseDraftRecovery)}>
|
|
47
|
+
{state.recovery}
|
|
48
|
+
</pre>
|
|
49
|
+
<p className="text-muted-foreground text-xs">
|
|
50
|
+
Drafts stay in this browser for seven days after the last edit, with a 256 KiB limit per draft. Saved responses are Markdown files in
|
|
51
|
+
responses/.
|
|
52
|
+
</p>
|
|
53
|
+
<div className="flex flex-wrap gap-2">
|
|
54
|
+
<Button
|
|
55
|
+
disabled={typeof window === "undefined" || state.created.saving}
|
|
56
|
+
id={id(shellIds.responsePreview)}
|
|
57
|
+
onClick={state.showPreview}
|
|
58
|
+
size="sm"
|
|
59
|
+
variant="outline"
|
|
60
|
+
>
|
|
61
|
+
Preview Markdown
|
|
62
|
+
</Button>
|
|
63
|
+
<Button
|
|
64
|
+
disabled={typeof window === "undefined" || state.created.saving}
|
|
65
|
+
id={id(shellIds.responseClear)}
|
|
66
|
+
onClick={state.clear}
|
|
67
|
+
size="sm"
|
|
68
|
+
variant="ghost"
|
|
69
|
+
>
|
|
70
|
+
Clear draft
|
|
71
|
+
</Button>
|
|
72
|
+
</div>
|
|
73
|
+
<pre className="whitespace-pre-wrap rounded-md bg-muted p-3 text-xs" hidden={!state.preview} id={id(shellIds.responsePreviewContent)}>
|
|
74
|
+
{state.preview}
|
|
75
|
+
</pre>
|
|
76
|
+
</div>
|
|
65
77
|
</details>
|
|
66
78
|
);
|
|
67
79
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { MessageCircleQuestion } from "lucide-react";
|
|
1
2
|
import type { Document, DocumentRequest } from "#browser/document/schema.ts";
|
|
2
3
|
import { reasonMarkdown } from "#browser/responses/reasonMarkdown.ts";
|
|
3
4
|
import { AnswerContext } from "./AnswerContext.tsx";
|
|
4
5
|
import { AnswerForm } from "./AnswerForm.tsx";
|
|
6
|
+
import { AnswerMarkdown } from "./AnswerMarkdown.tsx";
|
|
5
7
|
import { ResponseHistory } from "./ResponseHistory.tsx";
|
|
6
|
-
import { ResponseMarkdown } from "./ResponseMarkdown.tsx";
|
|
7
8
|
|
|
8
9
|
export function AnswerPanel({ document: data }: { readonly document: Document }) {
|
|
9
10
|
const requests = data.requests.filter(
|
|
@@ -30,23 +31,28 @@ function AnswerCard({ document: data, request }: { readonly document: Document;
|
|
|
30
31
|
return (
|
|
31
32
|
<section
|
|
32
33
|
aria-labelledby={`answer-title-${request.id}`}
|
|
33
|
-
className="response-panel
|
|
34
|
+
className="response-panel max-w-[72ch] space-y-5 rounded-xl border bg-card p-5 text-card-foreground shadow-sm"
|
|
34
35
|
id={`answer-card-${request.id}`}
|
|
35
36
|
tabIndex={-1}
|
|
36
37
|
>
|
|
37
|
-
<h2 id={`answer-title-${request.id}`}>
|
|
38
|
+
<h2 className="flex items-center gap-2 font-medium text-muted-foreground text-sm" id={`answer-title-${request.id}`}>
|
|
39
|
+
{request.open ? <MessageCircleQuestion aria-hidden="true" className="size-4 text-needs-you" /> : null}
|
|
40
|
+
{cardTitle(request, closed)}
|
|
41
|
+
</h2>
|
|
38
42
|
{!(request.open || unavailable) && (
|
|
39
|
-
<p role="status">
|
|
43
|
+
<p className="text-muted-foreground text-sm" role="status">
|
|
40
44
|
{closed ? "This question is closed. Recorded answers remain below." : "Answer unavailable. Check the source diagnostics."}
|
|
41
45
|
</p>
|
|
42
46
|
)}
|
|
43
|
-
{Boolean(unavailable) &&
|
|
47
|
+
{Boolean(unavailable) && (
|
|
48
|
+
<p className="rounded-md border border-destructive/40 px-3 py-2 text-sm" role="status">
|
|
49
|
+
{unavailable}
|
|
50
|
+
</p>
|
|
51
|
+
)}
|
|
44
52
|
{request.open && preview !== undefined && (
|
|
45
53
|
<>
|
|
54
|
+
<AnswerMarkdown className="answer-reason font-medium text-base" file={source.file} source={reasonMarkdown(preview.reason)} />
|
|
46
55
|
<AnswerContext preview={preview} />
|
|
47
|
-
<div className="answer-reason">
|
|
48
|
-
<ResponseMarkdown file={source.file} source={reasonMarkdown(preview.reason)} />
|
|
49
|
-
</div>
|
|
50
56
|
</>
|
|
51
57
|
)}
|
|
52
58
|
{request.open && preview && !unavailable && <AnswerForm document={source} preview={preview} request={request} />}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { useAtomValue } from "@effect/atom-react";
|
|
2
2
|
import { useId, useLayoutEffect, useRef } from "react";
|
|
3
3
|
import type { Document } from "#browser/document/schema.ts";
|
|
4
|
+
import { promptHeading } from "#browser/responses/cardContext.ts";
|
|
4
5
|
import type { Prompt } from "#browser/responses/Prompt.ts";
|
|
5
6
|
import type { PromptAnswer } from "#browser/responses/schema.ts";
|
|
7
|
+
import { AnswerMarkdown } from "./AnswerMarkdown.tsx";
|
|
6
8
|
import { PromptOption } from "./PromptOption.tsx";
|
|
7
|
-
import { ResponseMarkdown } from "./ResponseMarkdown.tsx";
|
|
8
9
|
import type { useResponseForm } from "./useResponseForm.ts";
|
|
9
10
|
|
|
10
11
|
type Model = ReturnType<typeof useResponseForm>["form"];
|
|
@@ -36,12 +37,9 @@ function PromptField({
|
|
|
36
37
|
useLayoutEffect(() => ref.current?.setCustomValidity(error ?? ""), [error]);
|
|
37
38
|
const choices = document.metadata.options;
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
} else if (prompt.mode !== "text") {
|
|
43
|
-
guidance = `${prompt.mode === "one" ? "Choose one option" : "Choose any combination"}, or answer in your own words.`;
|
|
44
|
-
}
|
|
40
|
+
const guidance = promptGuidance(prompt.mode, choices !== undefined);
|
|
41
|
+
const heading = promptHeading(prompt.source);
|
|
42
|
+
const title = heading.title ?? `Question ${index + 1}`;
|
|
45
43
|
function change(next: PromptAnswer) {
|
|
46
44
|
onEdit(index, next);
|
|
47
45
|
}
|
|
@@ -57,14 +55,14 @@ function PromptField({
|
|
|
57
55
|
}
|
|
58
56
|
let message = error;
|
|
59
57
|
if (error && answer.selected.length === 0 && !answer.text.trim()) {
|
|
60
|
-
message = `Unanswered:
|
|
58
|
+
message = `Unanswered: “${title}”. Choose an option or answer in your own words.`;
|
|
61
59
|
}
|
|
62
60
|
return (
|
|
63
|
-
<fieldset data-mode={prompt.mode} data-prompt={prompt.id} data-source={prompt.source}>
|
|
64
|
-
<legend>{choices ? "Your answer"
|
|
65
|
-
{choices === undefined && <
|
|
66
|
-
<p>{guidance}
|
|
67
|
-
<div className={choices ? "question-choices" :
|
|
61
|
+
<fieldset className="m-0 min-w-0 space-y-3 border-0 p-0" data-mode={prompt.mode} data-prompt={prompt.id} data-source={prompt.source}>
|
|
62
|
+
<legend className="mb-1 p-0 font-semibold text-base">{choices === undefined ? title : "Your answer"}</legend>
|
|
63
|
+
{choices === undefined && heading.rest ? <AnswerMarkdown className="text-sm" file={document.file} source={heading.rest} /> : null}
|
|
64
|
+
<p className="text-muted-foreground text-sm">{guidance}</p>
|
|
65
|
+
<div className={`grid gap-2 ${choices ? "question-choices" : ""}`}>
|
|
68
66
|
{prompt.options.map((option, choice) => (
|
|
69
67
|
<PromptOption
|
|
70
68
|
checked={answer.selected.includes(option.id)}
|
|
@@ -78,26 +76,43 @@ function PromptField({
|
|
|
78
76
|
))}
|
|
79
77
|
</div>
|
|
80
78
|
{prompt.mode !== "text" && (
|
|
81
|
-
<button
|
|
79
|
+
<button
|
|
80
|
+
className="text-muted-foreground text-xs underline-offset-4 hover:underline disabled:opacity-50"
|
|
81
|
+
data-clear-choices
|
|
82
|
+
disabled={answer.selected.length === 0}
|
|
83
|
+
onClick={() => change({ ...answer, selected: [] })}
|
|
84
|
+
type="button"
|
|
85
|
+
>
|
|
82
86
|
Clear selections
|
|
83
87
|
</button>
|
|
84
88
|
)}
|
|
85
|
-
<label>
|
|
86
|
-
{
|
|
89
|
+
<label className="grid gap-2 text-sm">
|
|
90
|
+
<span>{prompt.mode === "text" ? "Your answer" : "Add a note or answer in your own words (optional)"}</span>
|
|
87
91
|
<textarea
|
|
88
92
|
aria-describedby={`${errorId}-error`}
|
|
89
93
|
aria-invalid={Boolean(error)}
|
|
94
|
+
className="w-full rounded-md border bg-background px-3 py-2 text-sm aria-invalid:border-destructive"
|
|
90
95
|
data-answer-text
|
|
91
96
|
maxLength={8192}
|
|
92
97
|
onInput={(event) => change({ ...answer, text: event.currentTarget.value })}
|
|
93
98
|
ref={ref}
|
|
94
|
-
rows={choices ? 4 :
|
|
99
|
+
rows={choices || prompt.mode === "text" ? 4 : 2}
|
|
95
100
|
value={answer.text}
|
|
96
101
|
/>
|
|
97
|
-
<span className="response-field-error" hidden={!error} id={`${errorId}-error`}>
|
|
102
|
+
<span className="response-field-error text-destructive text-xs" hidden={!error} id={`${errorId}-error`}>
|
|
98
103
|
{message}
|
|
99
104
|
</span>
|
|
100
105
|
</label>
|
|
101
106
|
</fieldset>
|
|
102
107
|
);
|
|
103
108
|
}
|
|
109
|
+
|
|
110
|
+
function promptGuidance(mode: Prompt["mode"], authored: boolean) {
|
|
111
|
+
if (authored) {
|
|
112
|
+
return "Choose an option or write another answer. Nothing is selected for you.";
|
|
113
|
+
}
|
|
114
|
+
if (mode === "text") {
|
|
115
|
+
return "Answer in your own words.";
|
|
116
|
+
}
|
|
117
|
+
return `${mode === "one" ? "Choose one option" : "Choose any combination"}, or answer in your own words. Nothing is selected for you.`;
|
|
118
|
+
}
|
|
@@ -2,9 +2,8 @@ import { useRouterState } from "@tanstack/react-router";
|
|
|
2
2
|
import { Option } from "effect";
|
|
3
3
|
import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
|
|
4
4
|
import { useCallback, useContext, useEffect, useState } from "react";
|
|
5
|
-
import { useQuery } from "@shivaedev/effect-react/
|
|
5
|
+
import { useQuery } from "@shivaedev/effect-react/client/resultState.ts";
|
|
6
6
|
import type { BrowserClient } from "#client/client.ts";
|
|
7
|
-
import { navigationQuery } from "#client/page/routeQuery.ts";
|
|
8
7
|
import { AgeTicker } from "./Age.tsx";
|
|
9
8
|
import { FleetMain } from "./FleetMain.tsx";
|
|
10
9
|
import { FormContext } from "./FormContext.ts";
|
|
@@ -15,6 +14,7 @@ import { emptyMainLocation, type MainLocation } from "./mainLocation.ts";
|
|
|
15
14
|
import { PhoneNavigation } from "./PhoneNavigation.tsx";
|
|
16
15
|
import { ReadingLibrary } from "./ReadingLibrary.tsx";
|
|
17
16
|
import { ReadingReadyContext, readingReady } from "./ReadingReadyContext.ts";
|
|
17
|
+
import { navigationQuery } from "./routeQuery.ts";
|
|
18
18
|
import { SearchDialog } from "./SearchDialog.tsx";
|
|
19
19
|
import { SessionContext } from "./SessionContext.ts";
|
|
20
20
|
import type { ShellApi } from "./ShellApi.ts";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Cause, Option } from "effect";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
-
import { useQuery } from "@shivaedev/effect-react/
|
|
3
|
+
import { useQuery } from "@shivaedev/effect-react/client/resultState.ts";
|
|
4
4
|
import type { Document } from "#browser/document/schema.ts";
|
|
5
|
-
import { documentQuery } from "#client/page/routeQuery.ts";
|
|
6
5
|
import { DocumentPage } from "./DocumentPage.tsx";
|
|
7
6
|
import type { MainLocation } from "./mainLocation.ts";
|
|
8
7
|
import { ProjectionMain } from "./ProjectionMain.tsx";
|
|
9
8
|
import { RemainingMain } from "./RemainingMain.tsx";
|
|
9
|
+
import { documentQuery } from "./routeQuery.ts";
|
|
10
10
|
import type { ShellApi } from "./ShellApi.ts";
|
|
11
11
|
import { shellIds } from "./shellIds.ts";
|
|
12
12
|
import { useDocumentPage } from "./useDocumentPage.ts";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
2
|
import type { ComponentProps } from "react";
|
|
3
|
-
import { useQuery } from "@shivaedev/effect-react/
|
|
3
|
+
import { useQuery } from "@shivaedev/effect-react/client/resultState.ts";
|
|
4
4
|
import { BoardMain } from "./BoardMain.tsx";
|
|
5
5
|
import { FleetItemsContext } from "./FleetItemsContext.ts";
|
|
6
6
|
export function FleetMain(props: ComponentProps<typeof BoardMain>) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactNode, useId, useLayoutEffect, useRef } from "react";
|
|
2
|
-
import { useField } from "@shivaedev/effect-form/react.ts";
|
|
2
|
+
import { useField } from "@shivaedev/effect-form/client/react.ts";
|
|
3
3
|
import type { Fields, Form, Name } from "@shivaedev/effect-form/shape.ts";
|
|
4
4
|
|
|
5
5
|
type Control = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
|
-
import { useQuery } from "@shivaedev/effect-react/
|
|
2
|
+
import { useQuery } from "@shivaedev/effect-react/client/resultState.ts";
|
|
3
3
|
import type { Document } from "#browser/document/schema.ts";
|
|
4
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
5
4
|
import { GoalCriteria } from "./GoalCriteria.tsx";
|
|
6
5
|
import { GoalWorkTable } from "./GoalWorkTable.tsx";
|
|
7
6
|
import { targetsGoal } from "./goalWork.ts";
|
|
7
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
8
8
|
import type { ShellApi } from "./ShellApi.ts";
|
|
9
9
|
|
|
10
10
|
export function GoalPage({ api, document }: { readonly api: ShellApi; readonly document: Document }) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
2
|
import { useId } from "react";
|
|
3
|
-
import { useQuery } from "@shivaedev/effect-react/
|
|
3
|
+
import { useQuery } from "@shivaedev/effect-react/client/resultState.ts";
|
|
4
4
|
import type { Document } from "#browser/document/schema.ts";
|
|
5
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
6
5
|
import { GoalProgressSummary } from "./GoalProgressSummary.tsx";
|
|
6
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
7
7
|
import type { ShellApi } from "./ShellApi.ts";
|
|
8
8
|
|
|
9
9
|
export function GoalProgressHeader({ api, document }: { readonly api: ShellApi; readonly document: Document }) {
|
|
@@ -3,6 +3,7 @@ import type { ReactNode } from "react";
|
|
|
3
3
|
import { Badge } from "#client/react/components/ui/Badge.tsx";
|
|
4
4
|
import { Button } from "#client/react/components/ui/Button.tsx";
|
|
5
5
|
import { buttonVariants } from "#client/react/components/ui/buttonVariants.ts";
|
|
6
|
+
import { destinationName } from "#client/react/destinationName.ts";
|
|
6
7
|
import { cn } from "#client/react/lib/cn.ts";
|
|
7
8
|
import { KeyboardHints } from "./KeyboardHints.tsx";
|
|
8
9
|
import type { MainLocation } from "./mainLocation.ts";
|
|
@@ -12,7 +13,7 @@ import type { AppearanceControls } from "./useAppearance.ts";
|
|
|
12
13
|
import type { SidebarControls } from "./useSidebar.ts";
|
|
13
14
|
export function InboxCount({ count, id }: { readonly count: number | null; readonly id: string }) {
|
|
14
15
|
return (
|
|
15
|
-
<Badge aria-label={
|
|
16
|
+
<Badge aria-label={count === null ? "Needs you unavailable" : `${count} need you`} id={id} role="status">
|
|
16
17
|
{count ?? "?"}
|
|
17
18
|
</Badge>
|
|
18
19
|
);
|
|
@@ -57,7 +58,7 @@ export function Header({
|
|
|
57
58
|
<Breadcrumbs file={main.title ?? main.file} />
|
|
58
59
|
<a
|
|
59
60
|
aria-current={main.view === "today" ? "page" : undefined}
|
|
60
|
-
aria-label="Today"
|
|
61
|
+
aria-label={destinationName("Today", count, "need you")}
|
|
61
62
|
className={cn(buttonVariants({ size: "sm", variant: "ghost" }), "hidden md:inline-flex")}
|
|
62
63
|
href="/"
|
|
63
64
|
id={shellIds.inboxTopbar}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Option } from "effect";
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import { useQuery } from "@shivaedev/effect-react/
|
|
3
|
+
import { useQuery } from "@shivaedev/effect-react/client/resultState.ts";
|
|
4
4
|
import type { Library, LibraryFile } from "#browser/navigation/library.ts";
|
|
5
5
|
import { Age } from "./Age.tsx";
|
|
6
6
|
import type { ShellApi } from "./ShellApi.ts";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { routeQueryOptions } from "#client/page/routeQuery.ts";
|
|
2
1
|
import { LibraryPage } from "./LibraryPage.tsx";
|
|
3
2
|
import type { MainLocation } from "./mainLocation.ts";
|
|
4
3
|
import { ProjectionFrame } from "./ProjectionFrame.tsx";
|
|
4
|
+
import { routeQueryOptions } from "./routeQuery.ts";
|
|
5
5
|
import type { ShellApi } from "./ShellApi.ts";
|
|
6
6
|
export function LibraryMain({
|
|
7
7
|
api,
|