revspec 0.3.0 → 0.5.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/README.md +13 -0
- package/docs/superpowers/plans/2026-03-15-ui-refactor.md +1025 -0
- package/package.json +1 -1
- package/src/state/review-state.ts +5 -0
- package/src/tui/app.ts +189 -234
- package/src/tui/comment-input.ts +146 -144
- package/src/tui/confirm.ts +29 -43
- package/src/tui/help.ts +77 -76
- package/src/tui/pager.ts +54 -267
- package/src/tui/search.ts +6 -6
- package/src/tui/status-bar.ts +27 -24
- package/src/tui/thread-list.ts +29 -55
- package/src/tui/ui/dialog.ts +106 -0
- package/src/tui/ui/hint-bar.ts +20 -0
- package/src/tui/ui/keybinds.ts +106 -0
- package/src/tui/ui/markdown.ts +292 -0
- package/src/tui/ui/theme.ts +49 -0
- package/test/tui/ui/keybinds.test.ts +71 -0
- package/src/tui/theme.ts +0 -34
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const theme = {
|
|
2
|
+
// Surfaces
|
|
3
|
+
base: "#1e1e2e",
|
|
4
|
+
backgroundPanel: "#313244",
|
|
5
|
+
backgroundElement: "#45475a",
|
|
6
|
+
|
|
7
|
+
// Text hierarchy
|
|
8
|
+
text: "#cdd6f4",
|
|
9
|
+
textMuted: "#a6adc8",
|
|
10
|
+
textDim: "#6c7086",
|
|
11
|
+
|
|
12
|
+
// Semantic accents
|
|
13
|
+
blue: "#89b4fa",
|
|
14
|
+
green: "#a6e3a1",
|
|
15
|
+
red: "#f38ba8",
|
|
16
|
+
yellow: "#f9e2af",
|
|
17
|
+
mauve: "#cba6f7",
|
|
18
|
+
|
|
19
|
+
// Borders
|
|
20
|
+
border: "#45475a",
|
|
21
|
+
borderAccent: "#89b4fa",
|
|
22
|
+
|
|
23
|
+
// Status
|
|
24
|
+
success: "#a6e3a1",
|
|
25
|
+
warning: "#f9e2af",
|
|
26
|
+
error: "#f38ba8",
|
|
27
|
+
info: "#89b4fa",
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
export const STATUS_ICONS: Record<string, string> = {
|
|
31
|
+
open: "\u258c", // ▌ half block
|
|
32
|
+
pending: "\u25cb", // ○ circle
|
|
33
|
+
resolved: "\u2713", // ✓ checkmark
|
|
34
|
+
outdated: "\u223c", // ∼ tilde
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const SPLIT_BORDER = {
|
|
38
|
+
topLeft: " ",
|
|
39
|
+
topRight: " ",
|
|
40
|
+
bottomLeft: " ",
|
|
41
|
+
bottomRight: " ",
|
|
42
|
+
horizontal: " ",
|
|
43
|
+
vertical: "\u2503",
|
|
44
|
+
topT: " ",
|
|
45
|
+
bottomT: " ",
|
|
46
|
+
leftT: "\u2503",
|
|
47
|
+
rightT: " ",
|
|
48
|
+
cross: " ",
|
|
49
|
+
} as const;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { createKeybindRegistry } from "../../../src/tui/ui/keybinds";
|
|
3
|
+
|
|
4
|
+
function makeKey(name: string, opts: { ctrl?: boolean; shift?: boolean; sequence?: string } = {}): any {
|
|
5
|
+
return { name, ctrl: opts.ctrl ?? false, shift: opts.shift ?? false, sequence: opts.sequence ?? name };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
describe("createKeybindRegistry", () => {
|
|
9
|
+
it("matches single keys", () => {
|
|
10
|
+
const reg = createKeybindRegistry([
|
|
11
|
+
{ key: "j", action: "down" },
|
|
12
|
+
{ key: "k", action: "up" },
|
|
13
|
+
]);
|
|
14
|
+
expect(reg.match(makeKey("j"))).toBe("down");
|
|
15
|
+
expect(reg.match(makeKey("k"))).toBe("up");
|
|
16
|
+
expect(reg.match(makeKey("x"))).toBeNull();
|
|
17
|
+
reg.destroy();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("matches ctrl keys", () => {
|
|
21
|
+
const reg = createKeybindRegistry([
|
|
22
|
+
{ key: "C-d", action: "half-page-down" },
|
|
23
|
+
]);
|
|
24
|
+
expect(reg.match(makeKey("d", { ctrl: true }))).toBe("half-page-down");
|
|
25
|
+
expect(reg.match(makeKey("d"))).toBeNull();
|
|
26
|
+
reg.destroy();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("matches shift keys", () => {
|
|
30
|
+
const reg = createKeybindRegistry([
|
|
31
|
+
{ key: "G", action: "goto-bottom" },
|
|
32
|
+
{ key: "R", action: "resolve-all" },
|
|
33
|
+
]);
|
|
34
|
+
expect(reg.match(makeKey("g", { shift: true }))).toBe("goto-bottom");
|
|
35
|
+
expect(reg.match(makeKey("r", { shift: true }))).toBe("resolve-all");
|
|
36
|
+
reg.destroy();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("matches two-key sequences", () => {
|
|
40
|
+
const reg = createKeybindRegistry([
|
|
41
|
+
{ key: "gg", action: "goto-top" },
|
|
42
|
+
{ key: "dd", action: "delete" },
|
|
43
|
+
]);
|
|
44
|
+
expect(reg.match(makeKey("g"))).toBeNull();
|
|
45
|
+
expect(reg.pending()).toBe("g...");
|
|
46
|
+
expect(reg.match(makeKey("g"))).toBe("goto-top");
|
|
47
|
+
expect(reg.pending()).toBeNull();
|
|
48
|
+
reg.destroy();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("clears sequence on invalid second key", () => {
|
|
52
|
+
const reg = createKeybindRegistry([
|
|
53
|
+
{ key: "gg", action: "goto-top" },
|
|
54
|
+
{ key: "j", action: "down" },
|
|
55
|
+
]);
|
|
56
|
+
expect(reg.match(makeKey("g"))).toBeNull();
|
|
57
|
+
expect(reg.match(makeKey("x"))).toBeNull();
|
|
58
|
+
expect(reg.match(makeKey("j"))).toBe("down");
|
|
59
|
+
reg.destroy();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("handles bracket sequences", () => {
|
|
63
|
+
const reg = createKeybindRegistry([
|
|
64
|
+
{ key: "]t", action: "next-thread" },
|
|
65
|
+
{ key: "[t", action: "prev-thread" },
|
|
66
|
+
]);
|
|
67
|
+
expect(reg.match(makeKey("]", { sequence: "]" }))).toBeNull();
|
|
68
|
+
expect(reg.match(makeKey("t"))).toBe("next-thread");
|
|
69
|
+
reg.destroy();
|
|
70
|
+
});
|
|
71
|
+
});
|
package/src/tui/theme.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export const theme = {
|
|
2
|
-
// Base surfaces
|
|
3
|
-
base: "#1e1e2e",
|
|
4
|
-
surface0: "#313244",
|
|
5
|
-
surface1: "#45475a",
|
|
6
|
-
|
|
7
|
-
// Text hierarchy
|
|
8
|
-
text: "#cdd6f4",
|
|
9
|
-
subtext: "#a6adc8",
|
|
10
|
-
overlay: "#6c7086",
|
|
11
|
-
|
|
12
|
-
// Semantic accents
|
|
13
|
-
blue: "#89b4fa",
|
|
14
|
-
green: "#a6e3a1",
|
|
15
|
-
red: "#f38ba8",
|
|
16
|
-
yellow: "#f9e2af",
|
|
17
|
-
mauve: "#cba6f7",
|
|
18
|
-
|
|
19
|
-
// Derived roles
|
|
20
|
-
borderComment: "#89b4fa",
|
|
21
|
-
borderThread: "#f9e2af", // yellow for informational view
|
|
22
|
-
borderList: "#cba6f7",
|
|
23
|
-
borderConfirm: "#f38ba8",
|
|
24
|
-
borderSearch: "#89b4fa",
|
|
25
|
-
hintFg: "#6c7086",
|
|
26
|
-
hintBg: "#313244",
|
|
27
|
-
} as const;
|
|
28
|
-
|
|
29
|
-
export const STATUS_ICONS: Record<string, string> = {
|
|
30
|
-
open: "\u258c", // ▌ half block
|
|
31
|
-
pending: "\u258c", // ▌ half block
|
|
32
|
-
resolved: "\u2713", // ✓ checkmark
|
|
33
|
-
outdated: "\u258c", // ▌ half block
|
|
34
|
-
};
|