@cueloop/client 0.1.0-alpha.33 → 0.1.0-alpha.35
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/package.json +27 -26
- package/src/App.autoclose.test.tsx +7 -4
- package/src/App.diff.test.tsx +130 -4
- package/src/App.export.test.tsx +22 -4
- package/src/App.plan-review.test.tsx +127 -27
- package/src/App.readonly.test.tsx +31 -8
- package/src/App.rendering.test.tsx +12 -3
- package/src/App.review-panel.test.tsx +11 -3
- package/src/App.submit-confirm.test.tsx +12 -7
- package/src/App.test.tsx +46 -9
- package/src/App.toast.test.tsx +10 -3
- package/src/App.tsx +400 -100
- package/src/App.walk.test.tsx +30 -10
- package/src/attribution.ts +8 -2
- package/src/clipboard.ts +5 -1
- package/src/components/AnnotationCard.stories.tsx +28 -9
- package/src/components/AnnotationCard.tsx +53 -38
- package/src/components/Breadcrumb.tsx +7 -1
- package/src/components/CodeBlock.stories.tsx +19 -2
- package/src/components/CodeBlock.tsx +24 -9
- package/src/components/CompletionOverlay.tsx +13 -3
- package/src/components/ConfirmCard.stories.tsx +22 -3
- package/src/components/ConfirmCard.tsx +22 -5
- package/src/components/ConfirmDialog.tsx +9 -1
- package/src/components/DiffSheet.scroll.test.tsx +123 -0
- package/src/components/DiffSheet.stories.tsx +18 -2
- package/src/components/DiffSheet.syntax.test.tsx +62 -0
- package/src/components/DiffSheet.tsx +184 -98
- package/src/components/InboxList.stories.tsx +16 -3
- package/src/components/InboxList.tsx +17 -10
- package/src/components/KeybindsDialog.tsx +19 -3
- package/src/components/MarkerPopover.stories.tsx +58 -0
- package/src/components/MarkerPopover.tsx +102 -0
- package/src/components/MenuBar.stories.tsx +5 -1
- package/src/components/MenuBar.tsx +18 -2
- package/src/components/PlanSheet.stories.tsx +34 -2
- package/src/components/PlanSheet.tsx +141 -32
- package/src/components/PromptDialog.tsx +18 -2
- package/src/components/ReviewPanel.stories.tsx +13 -3
- package/src/components/ReviewPanel.tsx +8 -4
- package/src/components/ReviewRail.stories.tsx +145 -72
- package/src/components/ReviewRail.tsx +177 -38
- package/src/components/SettingsDialog.stories.tsx +51 -3
- package/src/components/SettingsDialog.tsx +8 -3
- package/src/components/SettingsRows.tsx +19 -3
- package/src/components/Toast.tsx +17 -2
- package/src/components/WalkWizard.stories.tsx +13 -2
- package/src/components/WalkWizard.tsx +9 -3
- package/src/components/__snapshots__/stories.test.tsx.snap +281 -83
- package/src/components/diff-sheet-layout.test.ts +127 -0
- package/src/components/diff-sheet-layout.ts +167 -0
- package/src/components/primitives/Button.tsx +5 -1
- package/src/components/primitives/Dialog.tsx +9 -1
- package/src/components/primitives/Tabs.tsx +24 -4
- package/src/components/stories-app.tsx +34 -6
- package/src/components/story-fixtures.ts +11 -3
- package/src/components/story.ts +3 -1
- package/src/components/syntax-highlight.ts +47 -12
- package/src/components/theme-context.stories.tsx +6 -1
- package/src/components/theme-context.tsx +7 -1
- package/src/config.test.ts +178 -2
- package/src/config.ts +121 -23
- package/src/diff-hunk-curate.test.ts +315 -0
- package/src/diff-hunk-curate.ts +233 -0
- package/src/diff-intraline.test.ts +164 -0
- package/src/diff-intraline.ts +132 -0
- package/src/diff-syntax.test.ts +96 -0
- package/src/diff-syntax.ts +154 -0
- package/src/editor.test.ts +13 -4
- package/src/editor.ts +31 -5
- package/src/herdr.ts +8 -2
- package/src/index.ts +9 -1
- package/src/integrations.ts +3 -1
- package/src/intent-dispatch.test.ts +193 -9
- package/src/intent-dispatch.ts +151 -18
- package/src/key-bindings.test.ts +19 -9
- package/src/key-bindings.ts +36 -14
- package/src/keymap.test.ts +171 -26
- package/src/keymap.ts +83 -16
- package/src/review-panel.test.ts +3 -1
- package/src/review-panel.ts +9 -2
- package/src/serve.test.ts +11 -3
- package/src/session-controller.curate.test.ts +253 -0
- package/src/session-controller.share.test.ts +65 -17
- package/src/session-controller.ts +301 -26
- package/src/share.ts +41 -8
- package/src/test-support.ts +16 -6
- package/src/theme-presets.ts +168 -0
- package/src/theme.ts +1 -3
- package/src/view-diff.ts +15 -4
- package/src/view-plan.test.ts +40 -6
- package/src/view-plan.ts +71 -28
- package/src/walk.test.ts +7 -2
- package/src/walk.ts +7 -2
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* which keeps quote anchors char-precise.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import React, { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
|
|
11
|
+
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
12
12
|
import { useRenderer } from "@opentui/react";
|
|
13
|
-
import type
|
|
13
|
+
import { createTextAttributes, type ScrollBoxRenderable, type TextRenderable } from "@opentui/core";
|
|
14
14
|
import type { ReviewSession } from "@cueloop/schema";
|
|
15
15
|
import {
|
|
16
16
|
blockRuns,
|
|
@@ -27,8 +27,12 @@ import type { Theme } from "../theme";
|
|
|
27
27
|
import { useComponentTheme } from "./theme-context";
|
|
28
28
|
import { CodeBlock } from "./CodeBlock";
|
|
29
29
|
import { AnnotationCard, type AnnotationDraft } from "./AnnotationCard";
|
|
30
|
+
import { MarkerPopover, type MarkerPopoverProps } from "./MarkerPopover";
|
|
30
31
|
import { FRAME_BORDER_STYLE } from "./primitives/frame";
|
|
31
32
|
|
|
33
|
+
/** A cut block reads as removed: struck through and grayed, never red. */
|
|
34
|
+
const CUT_ATTRIBUTES = createTextAttributes({ strikethrough: true, dim: true });
|
|
35
|
+
|
|
32
36
|
export interface PlanSelection {
|
|
33
37
|
displayIndex: number;
|
|
34
38
|
start: number;
|
|
@@ -37,7 +41,8 @@ export interface PlanSelection {
|
|
|
37
41
|
|
|
38
42
|
export interface PlanSheetHandle {
|
|
39
43
|
/** Work-text range of the current native (mouse) selection, if any. */
|
|
40
|
-
|
|
44
|
+
/** The current native selection; `preferredIndex` (the mouse-up block) re-anchors a fresh drag. */
|
|
45
|
+
readSelection(preferredIndex?: number): PlanSelection | null;
|
|
41
46
|
/** Anchor/extend the renderer's native selection from keyboard span offsets. */
|
|
42
47
|
driveSpanSelection(span: SpanState): void;
|
|
43
48
|
clearSelection(): void;
|
|
@@ -45,12 +50,17 @@ export interface PlanSheetHandle {
|
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
export interface PlanComposeState {
|
|
48
|
-
kind: "comment"
|
|
53
|
+
kind: "comment";
|
|
49
54
|
displayIndex: number;
|
|
50
55
|
quote: string;
|
|
51
56
|
draft: AnnotationDraft;
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
/** The marker-actions popover, rendered inline at its block while span mode is live. */
|
|
60
|
+
export interface PlanPopoverState extends MarkerPopoverProps {
|
|
61
|
+
displayIndex: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
54
64
|
export interface PlanSheetProps {
|
|
55
65
|
session: ReviewSession;
|
|
56
66
|
display: DisplayBlock[];
|
|
@@ -59,6 +69,8 @@ export interface PlanSheetProps {
|
|
|
59
69
|
/** Extra selection-style paint on one block (keyboard span or compose anchor). */
|
|
60
70
|
activeSpan: { displayIndex: number; start: number; end: number } | null;
|
|
61
71
|
compose: PlanComposeState | null;
|
|
72
|
+
/** The marker-actions popover for the span's block; null when not in span mode. */
|
|
73
|
+
popover: PlanPopoverState | null;
|
|
62
74
|
editOrphanCount: number;
|
|
63
75
|
onLineActivate: (displayIndex: number) => void;
|
|
64
76
|
theme?: Theme;
|
|
@@ -70,7 +82,10 @@ interface BlockRef {
|
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
/** Screen position of a rendered-text offset inside a wrapped text. */
|
|
73
|
-
function positionOfRenderedOffset(
|
|
85
|
+
function positionOfRenderedOffset(
|
|
86
|
+
renderable: TextRenderable,
|
|
87
|
+
renderedOffset: number,
|
|
88
|
+
): { x: number; y: number } {
|
|
74
89
|
const info = renderable.lineInfo;
|
|
75
90
|
let lineIndex = 0;
|
|
76
91
|
for (let index = 0; index < info.lineStartCols.length; index++) {
|
|
@@ -85,12 +100,12 @@ function positionOfRenderedOffset(renderable: TextRenderable, renderedOffset: nu
|
|
|
85
100
|
|
|
86
101
|
export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function PlanSheet(
|
|
87
102
|
{
|
|
88
|
-
session,
|
|
89
103
|
display,
|
|
90
104
|
marks,
|
|
91
105
|
cursor,
|
|
92
106
|
activeSpan,
|
|
93
107
|
compose,
|
|
108
|
+
popover,
|
|
94
109
|
editOrphanCount,
|
|
95
110
|
onLineActivate,
|
|
96
111
|
theme,
|
|
@@ -103,14 +118,27 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
103
118
|
const scrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
104
119
|
|
|
105
120
|
useImperativeHandle(handleRef, () => ({
|
|
106
|
-
readSelection: (): PlanSelection | null => {
|
|
121
|
+
readSelection: (preferredIndex?: number): PlanSelection | null => {
|
|
107
122
|
if (!renderer?.hasSelection) return null;
|
|
108
|
-
const
|
|
109
|
-
|
|
123
|
+
const readBlock = (displayIndex: number): PlanSelection | null => {
|
|
124
|
+
const blockRef = blockRefs.current.get(displayIndex);
|
|
125
|
+
if (!blockRef) return null;
|
|
110
126
|
const selection = blockRef.renderable.getSelection();
|
|
111
|
-
if (!selection || selection.end <= selection.start)
|
|
127
|
+
if (!selection || selection.end <= selection.start) return null;
|
|
112
128
|
const range = workRangeForRendered(blockRef.runs, selection.start, selection.end);
|
|
113
|
-
|
|
129
|
+
return range ? { displayIndex, ...range } : null;
|
|
130
|
+
};
|
|
131
|
+
// the block the mouse released on wins, so a fresh drag re-anchors the span
|
|
132
|
+
// (one marker at a time) instead of sticking to the topmost prior selection
|
|
133
|
+
if (preferredIndex !== undefined) {
|
|
134
|
+
const preferred = readBlock(preferredIndex);
|
|
135
|
+
if (preferred) return preferred;
|
|
136
|
+
}
|
|
137
|
+
for (const displayIndex of [...blockRefs.current.keys()].sort(
|
|
138
|
+
(left, right) => left - right,
|
|
139
|
+
)) {
|
|
140
|
+
const found = readBlock(displayIndex);
|
|
141
|
+
if (found) return found;
|
|
114
142
|
}
|
|
115
143
|
return null;
|
|
116
144
|
},
|
|
@@ -138,7 +166,30 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
138
166
|
},
|
|
139
167
|
}));
|
|
140
168
|
|
|
141
|
-
|
|
169
|
+
// the popover floats above its block, anchored to the selection start; flip
|
|
170
|
+
// below when the block sits too near the viewport top to fit above it
|
|
171
|
+
const [popoverFlipBelow, setPopoverFlipBelow] = useState(false);
|
|
172
|
+
const [popoverLeft, setPopoverLeft] = useState(2);
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
if (!popover) return;
|
|
175
|
+
const blockRef = blockRefs.current.get(popover.displayIndex);
|
|
176
|
+
const scrollbox = scrollRef.current;
|
|
177
|
+
if (!blockRef || !scrollbox) return;
|
|
178
|
+
// only the toolbar (3 rows) + gap must fit above; the dropdown flows down
|
|
179
|
+
setPopoverFlipBelow(blockRef.renderable.y - scrollbox.y < 4);
|
|
180
|
+
// left-anchor to the start of the selection: gutter width + its column
|
|
181
|
+
const startColumn =
|
|
182
|
+
activeSpan && activeSpan.displayIndex === popover.displayIndex
|
|
183
|
+
? (renderedOffsetFor(blockRef.runs, activeSpan.start) ?? 0)
|
|
184
|
+
: 0;
|
|
185
|
+
setPopoverLeft(2 + startColumn);
|
|
186
|
+
}, [popover, activeSpan, display, cursor]);
|
|
187
|
+
|
|
188
|
+
const registerBlock = (
|
|
189
|
+
displayIndex: number,
|
|
190
|
+
renderable: TextRenderable | null,
|
|
191
|
+
runs: StyleRun[],
|
|
192
|
+
): void => {
|
|
142
193
|
if (renderable) blockRefs.current.set(displayIndex, { renderable, runs });
|
|
143
194
|
else blockRefs.current.delete(displayIndex);
|
|
144
195
|
};
|
|
@@ -164,7 +215,8 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
164
215
|
isCursor={isCursor}
|
|
165
216
|
marginTop={gap}
|
|
166
217
|
isAnnotated={(marks.get(displayIndex) ?? []).length > 0}
|
|
167
|
-
changeTag={block
|
|
218
|
+
changeTag={showsChangeTag(block) ? tagLabel(block) : undefined}
|
|
219
|
+
cut={block.type === "del"}
|
|
168
220
|
theme={theme}
|
|
169
221
|
/>,
|
|
170
222
|
);
|
|
@@ -174,11 +226,23 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
174
226
|
blockMarks.push({ start: activeSpan.start, end: activeSpan.end, role: "kspan" });
|
|
175
227
|
}
|
|
176
228
|
const runs = overlayMarks(blockRuns(block, true), blockMarks);
|
|
177
|
-
// the change tag participates in the rendered text but carries no offsets
|
|
178
|
-
|
|
179
|
-
|
|
229
|
+
// the change tag participates in the rendered text but carries no offsets;
|
|
230
|
+
// a cut block shows no tag (its strikethrough already reads as removed)
|
|
231
|
+
const mappedRuns: StyleRun[] = showsChangeTag(block)
|
|
232
|
+
? [...runs, { text: ` [${tagLabel(block)}]`, role: "plain", start: null }]
|
|
233
|
+
: runs;
|
|
180
234
|
children.push(
|
|
181
|
-
<box
|
|
235
|
+
<box
|
|
236
|
+
key={displayIndex}
|
|
237
|
+
id={`plan-block-${displayIndex}`}
|
|
238
|
+
// raise the block holding the popover so its overlay paints over the
|
|
239
|
+
// later blocks it floats across (siblings paint in z-index order)
|
|
240
|
+
style={{
|
|
241
|
+
flexDirection: "row",
|
|
242
|
+
marginTop: gap,
|
|
243
|
+
zIndex: popover?.displayIndex === displayIndex ? 10 : undefined,
|
|
244
|
+
}}
|
|
245
|
+
>
|
|
182
246
|
<text selectable={false}>
|
|
183
247
|
<span fg={isCursor ? tokens.accent : tokens.textDim}>{isCursor ? "▎ " : " "}</span>
|
|
184
248
|
<span fg={tokens.textDim}>{marker(block)}</span>
|
|
@@ -189,7 +253,9 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
189
253
|
selectionBg={tokens.accent}
|
|
190
254
|
selectionFg={tokens.accentInk}
|
|
191
255
|
style={{ wrapMode: "word", flexGrow: 1, flexShrink: 1 }}
|
|
192
|
-
ref={(renderable: TextRenderable | null) =>
|
|
256
|
+
ref={(renderable: TextRenderable | null) =>
|
|
257
|
+
registerBlock(displayIndex, renderable, mappedRuns)
|
|
258
|
+
}
|
|
193
259
|
onMouseUp={() => onLineActivate(displayIndex)}
|
|
194
260
|
>
|
|
195
261
|
{runs.map((run, runIndex) => (
|
|
@@ -197,14 +263,38 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
197
263
|
{run.text}
|
|
198
264
|
</span>
|
|
199
265
|
))}
|
|
200
|
-
{block
|
|
266
|
+
{showsChangeTag(block) ? (
|
|
267
|
+
<span fg={tagColor(block, tokens)}> [{tagLabel(block)}]</span>
|
|
268
|
+
) : null}
|
|
201
269
|
</text>
|
|
270
|
+
{popover && popover.displayIndex === displayIndex ? (
|
|
271
|
+
// float the card over the block, centered, with a one-row gap; flip
|
|
272
|
+
// below only when there is no room above (near the viewport top)
|
|
273
|
+
<box
|
|
274
|
+
style={{
|
|
275
|
+
position: "absolute",
|
|
276
|
+
left: popoverLeft,
|
|
277
|
+
// fixed offset: the toolbar sits one row above the selection and
|
|
278
|
+
// stays put; the dropdown flows down from it, over the selection
|
|
279
|
+
top: popoverFlipBelow ? 1 : -4,
|
|
280
|
+
flexDirection: "column",
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
<MarkerPopover {...popover} theme={theme} />
|
|
284
|
+
</box>
|
|
285
|
+
) : null}
|
|
202
286
|
</box>,
|
|
203
287
|
);
|
|
204
288
|
}
|
|
205
289
|
if (compose && compose.displayIndex === displayIndex) {
|
|
206
290
|
children.push(
|
|
207
|
-
<AnnotationCard
|
|
291
|
+
<AnnotationCard
|
|
292
|
+
key={`compose-${displayIndex}`}
|
|
293
|
+
kind={compose.kind}
|
|
294
|
+
quote={compose.quote}
|
|
295
|
+
draft={compose.draft}
|
|
296
|
+
theme={theme}
|
|
297
|
+
/>,
|
|
208
298
|
);
|
|
209
299
|
}
|
|
210
300
|
}
|
|
@@ -223,11 +313,16 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
223
313
|
{editOrphanCount > 0 ? (
|
|
224
314
|
<box style={{ height: 1, backgroundColor: tokens.markCommentBackground, paddingLeft: 1 }}>
|
|
225
315
|
<text fg={tokens.red}>
|
|
226
|
-
{editOrphanCount} annotation{editOrphanCount === 1 ? "" : "s"} no longer match - the
|
|
316
|
+
{editOrphanCount} annotation{editOrphanCount === 1 ? "" : "s"} no longer match - the
|
|
317
|
+
passage was removed.
|
|
227
318
|
</text>
|
|
228
319
|
</box>
|
|
229
320
|
) : null}
|
|
230
|
-
<scrollbox
|
|
321
|
+
<scrollbox
|
|
322
|
+
ref={scrollRef}
|
|
323
|
+
style={{ flexGrow: 1, paddingLeft: 1, paddingTop: 0 }}
|
|
324
|
+
focused={false}
|
|
325
|
+
>
|
|
231
326
|
{children}
|
|
232
327
|
</scrollbox>
|
|
233
328
|
</box>
|
|
@@ -239,7 +334,8 @@ export const PlanSheet = forwardRef<PlanSheetHandle, PlanSheetProps>(function Pl
|
|
|
239
334
|
function topGap(previous: DisplayBlock | undefined, current: DisplayBlock): number {
|
|
240
335
|
if (!previous) return 0;
|
|
241
336
|
const tightPair =
|
|
242
|
-
(current.kind === "li" && previous.kind === "li") ||
|
|
337
|
+
(current.kind === "li" && previous.kind === "li") ||
|
|
338
|
+
(current.kind === "oli" && previous.kind === "oli");
|
|
243
339
|
return tightPair ? 0 : 1;
|
|
244
340
|
}
|
|
245
341
|
|
|
@@ -250,17 +346,32 @@ function marker(block: DisplayBlock): string {
|
|
|
250
346
|
return "";
|
|
251
347
|
}
|
|
252
348
|
|
|
253
|
-
|
|
254
|
-
|
|
349
|
+
/** An added or edited block earns a tag; a cut block relies on its strikethrough. */
|
|
350
|
+
function showsChangeTag(block: DisplayBlock): boolean {
|
|
351
|
+
return block.type === "add" || block.type === "mod";
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function tagLabel(block: DisplayBlock): "new" | "edited" {
|
|
355
|
+
return block.type === "add" ? "new" : "edited";
|
|
255
356
|
}
|
|
256
357
|
|
|
257
358
|
function tagColor(block: DisplayBlock, tokens: Theme): string {
|
|
258
|
-
return block.type === "
|
|
359
|
+
return block.type === "add" ? tokens.green : tokens.accent;
|
|
259
360
|
}
|
|
260
361
|
|
|
261
|
-
function runStyle(
|
|
262
|
-
|
|
263
|
-
|
|
362
|
+
function runStyle(
|
|
363
|
+
run: StyleRun,
|
|
364
|
+
block: DisplayBlock,
|
|
365
|
+
tokens: Theme,
|
|
366
|
+
): { fg?: string; bg?: string; attributes?: number } {
|
|
367
|
+
// a cut block reads as removed: every run struck through and grayed, never red
|
|
368
|
+
if (block.type === "del") return { fg: tokens.textDim, attributes: CUT_ATTRIBUTES };
|
|
369
|
+
const headingFg =
|
|
370
|
+
block.kind === "h1"
|
|
371
|
+
? tokens.text
|
|
372
|
+
: block.kind === "h2" || block.kind === "h3"
|
|
373
|
+
? tokens.accent
|
|
374
|
+
: undefined;
|
|
264
375
|
switch (run.role) {
|
|
265
376
|
case "ins":
|
|
266
377
|
return { fg: tokens.insertedForeground };
|
|
@@ -268,13 +379,11 @@ function runStyle(run: StyleRun, block: DisplayBlock, tokens: Theme): { fg?: str
|
|
|
268
379
|
return { fg: tokens.deletedForeground };
|
|
269
380
|
case "mark-comment":
|
|
270
381
|
return { fg: tokens.text, bg: tokens.markCommentBackground };
|
|
271
|
-
case "mark-suggestion":
|
|
272
|
-
return { fg: tokens.text, bg: tokens.markSuggestionBackground };
|
|
273
382
|
case "mark-focus":
|
|
274
383
|
return { fg: tokens.accentInk, bg: tokens.accent };
|
|
275
384
|
case "kspan":
|
|
276
385
|
return { fg: tokens.accentInk, bg: tokens.accent };
|
|
277
386
|
default:
|
|
278
|
-
return { fg:
|
|
387
|
+
return { fg: headingFg ?? tokens.text };
|
|
279
388
|
}
|
|
280
389
|
}
|
|
@@ -25,7 +25,15 @@ export interface PromptDialogProps {
|
|
|
25
25
|
theme?: Theme;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function PromptDialog({
|
|
28
|
+
export function PromptDialog({
|
|
29
|
+
isOpen,
|
|
30
|
+
title,
|
|
31
|
+
label,
|
|
32
|
+
value,
|
|
33
|
+
placeholder,
|
|
34
|
+
onInput,
|
|
35
|
+
theme,
|
|
36
|
+
}: PromptDialogProps): React.ReactNode {
|
|
29
37
|
const tokens = useComponentTheme(theme);
|
|
30
38
|
const { width: terminalWidth } = useTerminalDimensions();
|
|
31
39
|
const inputRef = useRef<TextareaRenderable | null>(null);
|
|
@@ -37,7 +45,15 @@ export function PromptDialog({ isOpen, title, label, value, placeholder, onInput
|
|
|
37
45
|
if (!isOpen) return null;
|
|
38
46
|
return (
|
|
39
47
|
<Dialog isOpen title={title} width={Math.min(54, terminalWidth - 6)} height={7} theme={theme}>
|
|
40
|
-
<box
|
|
48
|
+
<box
|
|
49
|
+
style={{
|
|
50
|
+
flexDirection: "column",
|
|
51
|
+
flexGrow: 1,
|
|
52
|
+
paddingLeft: 1,
|
|
53
|
+
paddingRight: 1,
|
|
54
|
+
paddingTop: 1,
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
41
57
|
<text fg={tokens.textDim}>{label}</text>
|
|
42
58
|
<textarea
|
|
43
59
|
ref={inputRef}
|
|
@@ -12,6 +12,7 @@ const rail = {
|
|
|
12
12
|
authorNames: {},
|
|
13
13
|
selectedId: FIXTURE_ANNOTATIONS[0]!.id,
|
|
14
14
|
resolvedIds: new Set(FIXTURE_ANNOTATIONS.map((annotation) => annotation.id)),
|
|
15
|
+
curationItems: [],
|
|
15
16
|
railTab: "review" as const,
|
|
16
17
|
pendingCount: 2,
|
|
17
18
|
cardEdit: null,
|
|
@@ -19,6 +20,8 @@ const rail = {
|
|
|
19
20
|
onTabChange: () => {},
|
|
20
21
|
onSelectCard: () => {},
|
|
21
22
|
onActivateCard: () => {},
|
|
23
|
+
onSelectCuration: () => {},
|
|
24
|
+
onUndoCuration: () => {},
|
|
22
25
|
onSubmitRequest: () => {},
|
|
23
26
|
};
|
|
24
27
|
|
|
@@ -27,7 +30,14 @@ const panelCallbacks = { onDividerGrab: () => {}, onToggle: () => {} };
|
|
|
27
30
|
/** The plan area to the left of the divider, so the layout reads in context. */
|
|
28
31
|
function PanelFrame({ children }: { children: React.ReactNode }): React.ReactNode {
|
|
29
32
|
return (
|
|
30
|
-
<box
|
|
33
|
+
<box
|
|
34
|
+
style={{
|
|
35
|
+
flexDirection: "row",
|
|
36
|
+
width: "100%",
|
|
37
|
+
height: "100%",
|
|
38
|
+
backgroundColor: DARK.background,
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
31
41
|
<box style={{ flexGrow: 1, paddingLeft: 1 }}>
|
|
32
42
|
<text fg={DARK.textMuted}>The plan takes the width the panel hands back.</text>
|
|
33
43
|
</box>
|
|
@@ -51,7 +61,7 @@ export const ExpandedWide: Story = {
|
|
|
51
61
|
<ReviewPanel mode="expanded" width={REVIEW_MAX_WIDTH} rail={rail} {...panelCallbacks} />
|
|
52
62
|
</PanelFrame>
|
|
53
63
|
),
|
|
54
|
-
expectedColors: [DARK.
|
|
64
|
+
expectedColors: [DARK.accent],
|
|
55
65
|
size: { width: 90, height: 24 },
|
|
56
66
|
};
|
|
57
67
|
|
|
@@ -61,7 +71,7 @@ export const Compact: Story = {
|
|
|
61
71
|
<ReviewPanel mode="compact" width={34} rail={rail} {...panelCallbacks} />
|
|
62
72
|
</PanelFrame>
|
|
63
73
|
),
|
|
64
|
-
expectedColors: [DARK.accent
|
|
74
|
+
expectedColors: [DARK.accent],
|
|
65
75
|
size: { width: 60, height: 24 },
|
|
66
76
|
};
|
|
67
77
|
|
|
@@ -49,11 +49,15 @@ function CompactRail({
|
|
|
49
49
|
theme?: Theme;
|
|
50
50
|
}): React.ReactNode {
|
|
51
51
|
const tokens = useComponentTheme(theme);
|
|
52
|
-
const dotColor = (annotation: Annotation): string =>
|
|
53
|
-
annotation.kind === "suggestion" ? tokens.green : tokens.accent;
|
|
54
52
|
return (
|
|
55
53
|
<box
|
|
56
|
-
style={{
|
|
54
|
+
style={{
|
|
55
|
+
width: REVIEW_COMPACT_WIDTH,
|
|
56
|
+
backgroundColor: tokens.panel,
|
|
57
|
+
flexDirection: "column",
|
|
58
|
+
paddingTop: 1,
|
|
59
|
+
paddingBottom: 1,
|
|
60
|
+
}}
|
|
57
61
|
>
|
|
58
62
|
<box style={{ alignItems: "center" }}>
|
|
59
63
|
<text fg={tokens.accent}>{String(annotations.length)}</text>
|
|
@@ -61,7 +65,7 @@ function CompactRail({
|
|
|
61
65
|
<box style={{ height: 1 }} />
|
|
62
66
|
<box style={{ flexDirection: "column", alignItems: "center" }}>
|
|
63
67
|
{annotations.map((annotation) => (
|
|
64
|
-
<text key={annotation.id} fg={
|
|
68
|
+
<text key={annotation.id} fg={tokens.accent}>
|
|
65
69
|
●
|
|
66
70
|
</text>
|
|
67
71
|
))}
|