@cueloop/client 0.1.0-alpha.9 → 0.1.0-alpha.91

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 (316) hide show
  1. package/native/build-pty.sh +51 -0
  2. package/native/build.sh +82 -0
  3. package/native/darwin-arm64/libcuelooppty.dylib +0 -0
  4. package/native/darwin-arm64/libcueloopvt.dylib +0 -0
  5. package/native/src/pty.zig +193 -0
  6. package/native/src/shim.zig +114 -0
  7. package/package.json +42 -34
  8. package/src/App.appearance.test.tsx +53 -0
  9. package/src/App.autoclose.test.tsx +77 -51
  10. package/src/App.diff.test.tsx +259 -45
  11. package/src/App.export.test.tsx +58 -41
  12. package/src/App.focus.test.ts +89 -0
  13. package/src/App.identity.test.tsx +78 -0
  14. package/src/App.plan-render.test.tsx +209 -0
  15. package/src/App.plan-review.test.tsx +330 -161
  16. package/src/App.prototype-markdown.test.tsx +128 -0
  17. package/src/App.prototype.test.tsx +176 -0
  18. package/src/App.readonly.test.tsx +129 -67
  19. package/src/App.regression.test.tsx +94 -0
  20. package/src/App.rendering.test.tsx +61 -35
  21. package/src/App.share-dialog.test.tsx +172 -0
  22. package/src/App.submit-confirm.test.tsx +264 -0
  23. package/src/App.test.tsx +402 -126
  24. package/src/App.toast.test.tsx +98 -0
  25. package/src/App.tsx +1406 -1060
  26. package/src/App.visual.test.tsx +57 -0
  27. package/src/App.walk.test.tsx +299 -0
  28. package/src/App.workbench.test.tsx +787 -0
  29. package/src/__snapshots__/view-plan.regression.test.ts.snap +100 -0
  30. package/src/annotation-palette.ts +62 -0
  31. package/src/ansi-screen.test.ts +28 -0
  32. package/src/ansi-screen.ts +72 -0
  33. package/src/app-key-state.ts +61 -0
  34. package/src/app-screens.tsx +577 -0
  35. package/src/app-view-model.ts +168 -0
  36. package/src/attribution.test.ts +31 -0
  37. package/src/attribution.ts +42 -0
  38. package/src/client-extension-registry.test.tsx +61 -0
  39. package/src/client-extension-registry.ts +159 -0
  40. package/src/clipboard.test.ts +23 -0
  41. package/src/clipboard.ts +33 -0
  42. package/src/components/AnnotatableFileView.stories.tsx +42 -0
  43. package/src/components/AnnotatableFileView.test.tsx +102 -0
  44. package/src/components/AnnotatableFileView.tsx +134 -0
  45. package/src/components/AnnotationCards.stories.tsx +86 -0
  46. package/src/components/AnnotationCards.tsx +341 -0
  47. package/src/components/AnsiScreen.stories.tsx +12 -0
  48. package/src/components/AnsiScreen.tsx +28 -0
  49. package/src/components/AppHeader.stories.tsx +50 -0
  50. package/src/components/AppHeader.tsx +83 -0
  51. package/src/components/AppShell.brand.test.tsx +58 -0
  52. package/src/components/AppShell.extensions.test.tsx +191 -0
  53. package/src/components/AppShell.stories.tsx +89 -0
  54. package/src/components/AppShell.tsx +362 -0
  55. package/src/components/AppShell.zoom.test.tsx +135 -0
  56. package/src/components/BareWorkbenchFileView.stories.tsx +27 -0
  57. package/src/components/BareWorkbenchFileView.tsx +64 -0
  58. package/src/components/Breadcrumb.stories.tsx +19 -0
  59. package/src/components/Breadcrumb.tsx +45 -0
  60. package/src/components/ChangesColumn.stories.tsx +44 -0
  61. package/src/components/ChangesColumn.tsx +199 -0
  62. package/src/components/ChangesFileTree.test.tsx +61 -0
  63. package/src/components/CodeBlock.stories.tsx +42 -0
  64. package/src/components/CodeBlock.tsx +84 -0
  65. package/src/components/CompletionOverlay.stories.tsx +37 -0
  66. package/src/components/CompletionOverlay.tsx +77 -0
  67. package/src/components/ConfirmCard.stories.tsx +37 -0
  68. package/src/components/ConfirmCard.tsx +150 -0
  69. package/src/components/ConfirmDialog.stories.tsx +21 -0
  70. package/src/components/ConfirmDialog.tsx +72 -0
  71. package/src/components/DiffContentView.scroll.test.tsx +149 -0
  72. package/src/components/DiffContentView.split.test.tsx +140 -0
  73. package/src/components/DiffContentView.stories.tsx +80 -0
  74. package/src/components/DiffContentView.syntax.test.tsx +82 -0
  75. package/src/components/DiffContentView.tsx +906 -0
  76. package/src/components/DiscussionMarkerRail.stories.tsx +54 -0
  77. package/src/components/DiscussionMarkerRail.tsx +186 -0
  78. package/src/components/EditorGrid.stories.tsx +59 -0
  79. package/src/components/EditorGrid.tabs.test.tsx +118 -0
  80. package/src/components/EditorGrid.tsx +426 -0
  81. package/src/components/EditorGrid.zoom.test.tsx +68 -0
  82. package/src/components/ExtensionZone.stories.tsx +28 -0
  83. package/src/components/ExtensionZone.tsx +145 -0
  84. package/src/components/FileContentsView.stories.tsx +16 -0
  85. package/src/components/FileContentsView.test.tsx +29 -0
  86. package/src/components/FileContentsView.tsx +98 -0
  87. package/src/components/GridTabContent.stories.tsx +59 -0
  88. package/src/components/GridTabContent.tsx +182 -0
  89. package/src/components/HandleChipsInput.stories.tsx +24 -0
  90. package/src/components/HandleChipsInput.test.tsx +35 -0
  91. package/src/components/HandleChipsInput.tsx +145 -0
  92. package/src/components/KeybindsDialog.stories.tsx +31 -0
  93. package/src/components/KeybindsDialog.tsx +103 -0
  94. package/src/components/MarkdownGridBlock.stories.tsx +33 -0
  95. package/src/components/MarkdownGridBlock.tsx +72 -0
  96. package/src/components/MarkdownThreadEditor.stories.tsx +15 -0
  97. package/src/components/MarkdownThreadEditor.test.tsx +98 -0
  98. package/src/components/MarkdownThreadEditor.tsx +162 -0
  99. package/src/components/MenuBar.stories.tsx +28 -0
  100. package/src/components/MenuBar.tsx +44 -0
  101. package/src/components/NavModeHint.stories.tsx +40 -0
  102. package/src/components/NavModeHint.tsx +31 -0
  103. package/src/components/OverlayScrollbar.stories.tsx +33 -0
  104. package/src/components/OverlayScrollbar.test.tsx +139 -0
  105. package/src/components/OverlayScrollbar.tsx +129 -0
  106. package/src/components/PaneGrid.stories.tsx +84 -0
  107. package/src/components/PaneGrid.tsx +128 -0
  108. package/src/components/PanelColumn.stories.tsx +25 -0
  109. package/src/components/PanelColumn.tsx +98 -0
  110. package/src/components/ProjectTreeView.stories.tsx +25 -0
  111. package/src/components/ProjectTreeView.test.tsx +75 -0
  112. package/src/components/ProjectTreeView.tsx +125 -0
  113. package/src/components/PromptDialog.stories.tsx +36 -0
  114. package/src/components/PromptDialog.test.tsx +61 -0
  115. package/src/components/PromptDialog.tsx +99 -0
  116. package/src/components/PrototypeContentView.stories.tsx +19 -0
  117. package/src/components/PrototypeContentView.tsx +446 -0
  118. package/src/components/RootOverlay.stories.tsx +45 -0
  119. package/src/components/RootOverlay.tsx +48 -0
  120. package/src/components/ScrollArea.stories.tsx +20 -0
  121. package/src/components/ScrollArea.tsx +44 -0
  122. package/src/components/SettingsDialog.stories.tsx +117 -0
  123. package/src/components/SettingsDialog.tsx +186 -0
  124. package/src/components/SettingsRows.stories.tsx +18 -0
  125. package/src/components/SettingsRows.tsx +112 -0
  126. package/src/components/ShareDialog.stories.tsx +121 -0
  127. package/src/components/ShareDialog.tsx +552 -0
  128. package/src/components/ShellHeader.stories.tsx +50 -0
  129. package/src/components/ShellHeader.tsx +137 -0
  130. package/src/components/SlashComposer.stories.tsx +37 -0
  131. package/src/components/SlashComposer.tsx +87 -0
  132. package/src/components/ThreadFooter.stories.tsx +30 -0
  133. package/src/components/ThreadFooter.test.tsx +47 -0
  134. package/src/components/ThreadFooter.tsx +76 -0
  135. package/src/components/ThreadTree.stories.tsx +46 -0
  136. package/src/components/ThreadTree.tsx +255 -0
  137. package/src/components/ThreadView.selection.test.tsx +951 -0
  138. package/src/components/ThreadView.slash.test.tsx +146 -0
  139. package/src/components/ThreadView.stories.tsx +26 -0
  140. package/src/components/ThreadView.tsx +525 -0
  141. package/src/components/Toast.stories.tsx +19 -0
  142. package/src/components/Toast.tsx +52 -0
  143. package/src/components/Tooltip.stories.tsx +26 -0
  144. package/src/components/Tooltip.tsx +72 -0
  145. package/src/components/TreePane.stories.tsx +106 -0
  146. package/src/components/TreePane.tsx +157 -0
  147. package/src/components/WalkWizard.stories.tsx +100 -0
  148. package/src/components/WalkWizard.tsx +150 -0
  149. package/src/components/WelcomePlayground.stories.tsx +12 -0
  150. package/src/components/WelcomePlayground.test.tsx +49 -0
  151. package/src/components/WelcomePlayground.tsx +139 -0
  152. package/src/components/WorkspacePanels.stories.tsx +36 -0
  153. package/src/components/WorkspacePanels.tsx +116 -0
  154. package/src/components/__snapshots__/stories.test.tsx.snap +2264 -0
  155. package/src/components/diff-content-view-layout.test.ts +198 -0
  156. package/src/components/diff-content-view-layout.ts +84 -0
  157. package/src/components/editor-grid.test.ts +86 -0
  158. package/src/components/editor-grid.ts +138 -0
  159. package/src/components/file-tree.test.ts +60 -0
  160. package/src/components/file-tree.ts +112 -0
  161. package/src/components/menu-control.stories.tsx +35 -0
  162. package/src/components/menu-control.tsx +43 -0
  163. package/src/components/pages/Workspace.stories.tsx +181 -0
  164. package/src/components/primitives/Button.stories.tsx +32 -0
  165. package/src/components/primitives/Button.tsx +59 -0
  166. package/src/components/primitives/Card.stories.tsx +25 -0
  167. package/src/components/primitives/Card.tsx +63 -0
  168. package/src/components/primitives/Dialog.stories.tsx +24 -0
  169. package/src/components/primitives/Dialog.test.tsx +37 -0
  170. package/src/components/primitives/Dialog.tsx +71 -0
  171. package/src/components/primitives/DialogActions.stories.tsx +20 -0
  172. package/src/components/primitives/DialogActions.tsx +39 -0
  173. package/src/components/primitives/IconButton.stories.tsx +36 -0
  174. package/src/components/primitives/IconButton.tsx +62 -0
  175. package/src/components/primitives/StatusBar.stories.tsx +11 -0
  176. package/src/components/primitives/StatusBar.tsx +23 -0
  177. package/src/components/primitives/Switch.stories.tsx +17 -0
  178. package/src/components/primitives/Switch.tsx +32 -0
  179. package/src/components/primitives/Tabs.stories.tsx +29 -0
  180. package/src/components/primitives/Tabs.tsx +102 -0
  181. package/src/components/primitives/Toolbar.stories.tsx +17 -0
  182. package/src/components/primitives/Toolbar.tsx +14 -0
  183. package/src/components/primitives/Tree.stories.tsx +124 -0
  184. package/src/components/primitives/Tree.tsx +100 -0
  185. package/src/components/primitives/frame.test.ts +12 -0
  186. package/src/components/primitives/frame.ts +17 -0
  187. package/src/components/primitives/icons.ts +61 -0
  188. package/src/components/primitives/tree-model.test.ts +99 -0
  189. package/src/components/primitives/tree-model.ts +137 -0
  190. package/src/components/quick-actions-editor.stories.tsx +58 -0
  191. package/src/components/quick-actions-editor.test.tsx +117 -0
  192. package/src/components/quick-actions-editor.tsx +226 -0
  193. package/src/components/share-dialog-store.ts +58 -0
  194. package/src/components/stories-app.tsx +193 -0
  195. package/src/components/stories.test.tsx +74 -0
  196. package/src/components/story-fixtures.ts +102 -0
  197. package/src/components/story-tree.test.ts +108 -0
  198. package/src/components/story.ts +159 -0
  199. package/src/components/syntax-highlight.ts +133 -0
  200. package/src/components/terminal-pane.test.tsx +40 -0
  201. package/src/components/terminal-pane.ts +199 -0
  202. package/src/components/theme-context.stories.tsx +46 -0
  203. package/src/components/theme-context.tsx +37 -0
  204. package/src/components/thread-tree.test.ts +134 -0
  205. package/src/components/thread-tree.ts +109 -0
  206. package/src/components/truncate-text.ts +7 -0
  207. package/src/components/truncate-title.test.ts +31 -0
  208. package/src/components/truncate-title.ts +15 -0
  209. package/src/config-identity.test.ts +78 -0
  210. package/src/config.test.ts +579 -34
  211. package/src/config.ts +533 -57
  212. package/src/diff-fold.test.ts +78 -0
  213. package/src/diff-fold.ts +126 -0
  214. package/src/diff-hunk-curate.test.ts +315 -0
  215. package/src/diff-hunk-curate.ts +153 -0
  216. package/src/diff-intraline.test.ts +238 -0
  217. package/src/diff-intraline.ts +236 -0
  218. package/src/diff-syntax.test.ts +112 -0
  219. package/src/diff-syntax.ts +179 -0
  220. package/src/discussions.ts +79 -0
  221. package/src/editor.test.ts +149 -0
  222. package/src/editor.ts +139 -9
  223. package/src/ghostty-terminal.test.ts +85 -0
  224. package/src/ghostty-terminal.ts +199 -0
  225. package/src/github-identity.test.ts +58 -0
  226. package/src/github-identity.ts +41 -0
  227. package/src/herdr.test.ts +9 -34
  228. package/src/herdr.ts +25 -21
  229. package/src/index.ts +29 -0
  230. package/src/integrations.test.ts +41 -0
  231. package/src/integrations.ts +32 -0
  232. package/src/intent-dispatch.test.ts +724 -0
  233. package/src/intent-dispatch.ts +690 -0
  234. package/src/key-bindings.test.ts +156 -0
  235. package/src/key-bindings.ts +459 -0
  236. package/src/keymap.test.ts +456 -115
  237. package/src/keymap.ts +315 -81
  238. package/src/kitty-image.test.ts +66 -0
  239. package/src/kitty-image.ts +138 -0
  240. package/src/launch-layout.test.ts +78 -0
  241. package/src/launch-layout.ts +62 -0
  242. package/src/mark-runs.ts +121 -0
  243. package/src/markdown-editor-syntax-style.ts +50 -0
  244. package/src/markdown-grid.test.ts +101 -0
  245. package/src/markdown-grid.ts +203 -0
  246. package/src/markdown-highlight.test.ts +61 -0
  247. package/src/markdown-highlight.ts +122 -0
  248. package/src/pasted-image.test.ts +67 -0
  249. package/src/pasted-image.ts +60 -0
  250. package/src/perf/otlp-trace.test.ts +116 -0
  251. package/src/perf/otlp-trace.ts +130 -0
  252. package/src/perf/perf-report.ts +17 -0
  253. package/src/perf/perf-timings.test.ts +18 -0
  254. package/src/perf/perf-timings.ts +38 -0
  255. package/src/prototype-browser.test.ts +81 -0
  256. package/src/prototype-browser.ts +329 -0
  257. package/src/prototype-pixels.tsx +35 -0
  258. package/src/pty.test.ts +81 -0
  259. package/src/pty.ts +245 -0
  260. package/src/ready-signal.test.ts +85 -0
  261. package/src/ready-signal.ts +52 -0
  262. package/src/run.ts +85 -12
  263. package/src/serve.test.ts +24 -12
  264. package/src/serve.ts +52 -10
  265. package/src/share.ts +237 -0
  266. package/src/skills.test.ts +74 -0
  267. package/src/skills.ts +75 -0
  268. package/src/slash-palette.test.ts +103 -0
  269. package/src/slash-palette.ts +129 -0
  270. package/src/split-diff.test.ts +110 -0
  271. package/src/split-diff.ts +149 -0
  272. package/src/test-support.test.ts +264 -0
  273. package/src/test-support.ts +369 -0
  274. package/src/theme-presets.test.ts +51 -0
  275. package/src/theme-presets.ts +219 -0
  276. package/src/theme.ts +88 -19
  277. package/src/thread-chords.test.ts +79 -0
  278. package/src/thread-chords.ts +163 -0
  279. package/src/thread-code-syntax.ts +45 -0
  280. package/src/thread-controller.curate.test.ts +476 -0
  281. package/src/thread-controller.derivation.test.ts +62 -0
  282. package/src/thread-controller.live-diff.test.ts +322 -0
  283. package/src/thread-controller.optimistic.test.ts +69 -0
  284. package/src/thread-controller.share.test.ts +561 -0
  285. package/src/thread-controller.switch-cache.test.ts +176 -0
  286. package/src/thread-controller.tree.test.ts +261 -0
  287. package/src/thread-controller.ts +2050 -0
  288. package/src/thread-selection.test.ts +210 -0
  289. package/src/thread-selection.ts +243 -0
  290. package/src/tree-view.test.ts +128 -0
  291. package/src/tree-view.ts +153 -0
  292. package/src/use-annotation-surface.tsx +975 -0
  293. package/src/use-changes-workbench.ts +190 -0
  294. package/src/use-frame-measure.ts +41 -0
  295. package/src/use-remember-layout.ts +31 -0
  296. package/src/use-repo-changes.ts +87 -0
  297. package/src/use-settings-dialog.tsx +364 -0
  298. package/src/use-terminal-virtualizer.ts +259 -0
  299. package/src/use-thread-body-editing.tsx +58 -0
  300. package/src/version.ts +5 -0
  301. package/src/view-diff.test.ts +279 -9
  302. package/src/view-diff.ts +460 -24
  303. package/src/view-plan.regression.test.ts +60 -0
  304. package/src/view-plan.test.ts +545 -0
  305. package/src/view-plan.ts +1019 -0
  306. package/src/visual/contrast.test.ts +35 -0
  307. package/src/visual/contrast.ts +33 -0
  308. package/src/walk.test.ts +121 -0
  309. package/src/walk.ts +74 -0
  310. package/src/workbench-snapshot.test.ts +99 -0
  311. package/src/workbench-snapshot.ts +59 -0
  312. package/src/session-controller.ts +0 -398
  313. package/src/syntax.test.ts +0 -41
  314. package/src/syntax.ts +0 -88
  315. package/src/view.test.ts +0 -157
  316. package/src/view.ts +0 -364
@@ -0,0 +1,117 @@
1
+ import React from "react";
2
+ import { DARK } from "../theme";
3
+ import { THEME_PRESETS } from "../theme-presets";
4
+ import type { Story, StoryMeta } from "./story";
5
+ import { SettingsDialog, type SettingsCategory } from "./SettingsDialog";
6
+
7
+ export const meta: StoryMeta = { title: "Overlays/SettingsDialog" };
8
+
9
+ const CATEGORIES: SettingsCategory[] = [
10
+ {
11
+ id: "general",
12
+ name: "General",
13
+ rows: [
14
+ { key: "displayName", label: "Display name", kind: "text" },
15
+ {
16
+ key: "autoClose",
17
+ label: "Auto-close on submit",
18
+ kind: "cycle",
19
+ options: ["off", "3s", "on"],
20
+ },
21
+ ],
22
+ },
23
+ {
24
+ id: "display",
25
+ name: "Display",
26
+ rows: [
27
+ {
28
+ key: "planWidth",
29
+ label: "Plan width",
30
+ kind: "cycle",
31
+ options: ["default", "wide", "full"],
32
+ },
33
+ { key: "showLineNumbers", label: "Line numbers", kind: "toggle" },
34
+ ],
35
+ },
36
+ {
37
+ id: "appearance",
38
+ name: "Appearance",
39
+ rows: [
40
+ {
41
+ key: "theme",
42
+ label: "Theme",
43
+ kind: "cycle",
44
+ options: ["cueloop", "Rosé Pine Moon", "Nord"],
45
+ },
46
+ ],
47
+ },
48
+ ];
49
+
50
+ const VALUES = {
51
+ displayName: "amber-heron",
52
+ autoClose: "3s",
53
+ planWidth: "default",
54
+ showLineNumbers: true,
55
+ theme: "Rosé Pine Moon",
56
+ };
57
+
58
+ export const NavZone: Story = {
59
+ render: () => (
60
+ <SettingsDialog
61
+ isOpen
62
+ version="0.1.0-alpha.32"
63
+ keybindsSections={[]}
64
+ categories={CATEGORIES}
65
+ values={VALUES}
66
+ activeCategoryId="general"
67
+ activeRowIndex={0}
68
+ activeZone="nav"
69
+ onCategorySelect={() => {}}
70
+ onRowActivate={() => {}}
71
+ onClose={() => {}}
72
+ />
73
+ ),
74
+ expectedColors: [DARK.accent],
75
+ size: { width: 100, height: 30 },
76
+ };
77
+
78
+ export const BodyZone: Story = {
79
+ render: () => (
80
+ <SettingsDialog
81
+ isOpen
82
+ version="0.1.0-alpha.32"
83
+ keybindsSections={[]}
84
+ categories={CATEGORIES}
85
+ values={VALUES}
86
+ activeCategoryId="display"
87
+ activeRowIndex={1}
88
+ activeZone="body"
89
+ onCategorySelect={() => {}}
90
+ onRowActivate={() => {}}
91
+ onClose={() => {}}
92
+ />
93
+ ),
94
+ expectedColors: [DARK.green],
95
+ size: { width: 100, height: 30 },
96
+ };
97
+
98
+ export const AppearanceThemed: Story = {
99
+ render: () => (
100
+ <SettingsDialog
101
+ isOpen
102
+ version="0.1.0-alpha.32"
103
+ keybindsSections={[]}
104
+ categories={CATEGORIES}
105
+ values={VALUES}
106
+ activeCategoryId="appearance"
107
+ activeRowIndex={0}
108
+ activeZone="body"
109
+ onCategorySelect={() => {}}
110
+ onRowActivate={() => {}}
111
+ onClose={() => {}}
112
+ theme={THEME_PRESETS["rose-pine-moon"]}
113
+ />
114
+ ),
115
+ expectedColors: [THEME_PRESETS["rose-pine-moon"].accent],
116
+ size: { width: 100, height: 30 },
117
+ };
@@ -0,0 +1,186 @@
1
+ /**
2
+ * The settings overlay: a centered Dialog whose left nav lists the categories as
3
+ * first-level leaves (General, Appearance, Actions, Keybinds), and whose right
4
+ * body shows the active category's typed rows or the keybinds cheatsheet. The
5
+ * component is controlled: the caller owns the open flag, the active
6
+ * category/row/zone, and value changes, so the app's keyboard grammar (and the
7
+ * stories catalog) drive it without a second key handler inside.
8
+ */
9
+
10
+ import { ScrollArea } from "./ScrollArea";
11
+ import React from "react";
12
+ import { useTerminalDimensions } from "@opentui/react";
13
+ import type { Theme } from "../theme";
14
+ import type { CheatsheetSection } from "../key-bindings";
15
+ import { useComponentTheme } from "./theme-context";
16
+ import { Dialog } from "./primitives/Dialog";
17
+ import { Tree } from "./primitives/Tree";
18
+ import type { TreeNode } from "./primitives/tree-model";
19
+ import { CycleRow, TextRow, ToggleRow, type SettingsRowDescriptor } from "./SettingsRows";
20
+
21
+ export interface SettingsCategory {
22
+ id: string;
23
+ name: string;
24
+ rows: SettingsRowDescriptor[];
25
+ /** A bespoke body (e.g. the quick-actions editor) rendered instead of typed rows. */
26
+ customBody?: React.ReactNode;
27
+ }
28
+
29
+ export type SettingsValues = Record<string, string | boolean>;
30
+
31
+ /** The category id whose right pane shows the keybinds cheatsheet rather than rows. */
32
+ const KEYBINDS_CATEGORY_ID = "keybinds";
33
+
34
+ export interface SettingsDialogProps {
35
+ isOpen: boolean;
36
+ /** The client version, shown in the dialog footer (its home now the menu bar is gone). */
37
+ version: string;
38
+ categories: SettingsCategory[];
39
+ values: SettingsValues;
40
+ /** The keybinds cheatsheet, shown when the Keybinds leaf is active. */
41
+ keybindsSections: CheatsheetSection[];
42
+ activeCategoryId: string;
43
+ activeRowIndex: number;
44
+ activeZone: "nav" | "body";
45
+ onCategorySelect: (categoryId: string) => void;
46
+ onRowActivate: (row: SettingsRowDescriptor) => void;
47
+ onClose: () => void;
48
+ theme?: Theme;
49
+ }
50
+
51
+ function navTree(categories: SettingsCategory[]): TreeNode[] {
52
+ return categories.map((category) => ({ id: category.id, label: category.name }));
53
+ }
54
+
55
+ function KeybindsBody({
56
+ sections,
57
+ tokens,
58
+ }: {
59
+ sections: CheatsheetSection[];
60
+ tokens: Theme;
61
+ }): React.ReactNode {
62
+ return (
63
+ <ScrollArea>
64
+ {sections.map((section) => (
65
+ <box key={section.title} style={{ flexDirection: "column" }}>
66
+ <text fg={tokens.accent}>{section.title}</text>
67
+ {section.entries.map((entry, index) => (
68
+ <text key={`${section.title}-${index}`}>
69
+ <span fg={tokens.text}>{entry.keys.padEnd(12)}</span>
70
+ <span fg={tokens.textMuted}>{entry.label}</span>
71
+ </text>
72
+ ))}
73
+ <text> </text>
74
+ </box>
75
+ ))}
76
+ </ScrollArea>
77
+ );
78
+ }
79
+
80
+ export function SettingsDialog({
81
+ isOpen,
82
+ version,
83
+ categories,
84
+ values,
85
+ keybindsSections,
86
+ activeCategoryId,
87
+ activeRowIndex,
88
+ activeZone,
89
+ onCategorySelect,
90
+ onRowActivate,
91
+ onClose,
92
+ theme,
93
+ }: SettingsDialogProps): React.ReactNode {
94
+ const tokens = useComponentTheme(theme);
95
+ const { width: terminalWidth, height: terminalHeight } = useTerminalDimensions();
96
+
97
+ if (!isOpen) return null;
98
+ const category =
99
+ categories.find((candidate) => candidate.id === activeCategoryId) ?? categories[0];
100
+
101
+ if (!category) return null;
102
+ const onKeybinds = category.id === KEYBINDS_CATEGORY_ID;
103
+
104
+ return (
105
+ <Dialog
106
+ isOpen
107
+ title=" Settings "
108
+ width={Math.min(76, terminalWidth - 6)}
109
+ height={Math.min(22, terminalHeight - 4)}
110
+ background={tokens.elevated}
111
+ onDismiss={onClose}
112
+ theme={theme}
113
+ >
114
+ <box style={{ flexDirection: "row", flexGrow: 1 }}>
115
+ <box style={{ flexDirection: "column", width: 20, paddingLeft: 1, paddingRight: 1 }}>
116
+ <Tree
117
+ nodes={navTree(categories)}
118
+ expandedIds={new Set<string>()}
119
+ selectedId={category.id}
120
+ hideIcons
121
+ selectedBackground={tokens.border}
122
+ onSelect={onCategorySelect}
123
+ onToggle={onCategorySelect}
124
+ theme={theme}
125
+ />
126
+ </box>
127
+ <box style={{ borderStyle: "single", border: ["left"], borderColor: tokens.border }} />
128
+ <box style={{ flexDirection: "column", flexGrow: 1, paddingLeft: 2, paddingRight: 1 }}>
129
+ {onKeybinds ? <KeybindsBody sections={keybindsSections} tokens={tokens} /> : null}
130
+ {onKeybinds ? null : category.customBody}
131
+ {onKeybinds
132
+ ? null
133
+ : category.rows.map((row, rowIndex) => {
134
+ const isActive = activeZone === "body" && rowIndex === activeRowIndex;
135
+ const value = values[row.key];
136
+
137
+ if (row.kind === "toggle") {
138
+ return (
139
+ <ToggleRow
140
+ key={row.key}
141
+ label={row.label}
142
+ value={value === true}
143
+ isActive={isActive}
144
+ onPress={() => onRowActivate(row)}
145
+ theme={theme}
146
+ />
147
+ );
148
+ }
149
+ if (row.kind === "cycle") {
150
+ return (
151
+ <CycleRow
152
+ key={row.key}
153
+ label={row.label}
154
+ value={String(value ?? "")}
155
+ isActive={isActive}
156
+ onPress={() => onRowActivate(row)}
157
+ theme={theme}
158
+ />
159
+ );
160
+ }
161
+
162
+ return (
163
+ <TextRow
164
+ key={row.key}
165
+ label={row.label}
166
+ value={String(value ?? "")}
167
+ isActive={isActive}
168
+ onPress={() => onRowActivate(row)}
169
+ theme={theme}
170
+ />
171
+ );
172
+ })}
173
+ </box>
174
+ </box>
175
+ <box style={{ flexDirection: "row", height: 1, paddingLeft: 1, paddingRight: 1 }}>
176
+ <text fg={tokens.textDim}>
177
+ {activeZone === "nav"
178
+ ? "j/k nav · l/tab open · esc close"
179
+ : "j/k row · l/space change · h back · esc close"}
180
+ </text>
181
+ <box style={{ flexGrow: 1 }} />
182
+ <text fg={tokens.textDim}>{`cueloop v${version}`}</text>
183
+ </box>
184
+ </Dialog>
185
+ );
186
+ }
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+ import { DARK } from "../theme";
3
+ import type { Story, StoryMeta } from "./story";
4
+ import { CycleRow, TextRow, ToggleRow } from "./SettingsRows";
5
+
6
+ export const meta: StoryMeta = { title: "Chrome/SettingsRows" };
7
+
8
+ export const AllKinds: Story = {
9
+ render: () => (
10
+ <box style={{ flexDirection: "column", width: 50 }}>
11
+ <ToggleRow label="Line numbers" value={true} isActive={false} onPress={() => {}} />
12
+ <ToggleRow label="Hide whitespace" value={false} isActive={true} onPress={() => {}} />
13
+ <CycleRow label="Palette" value="dark" isActive={false} onPress={() => {}} />
14
+ <TextRow label="Vault path" value="~/vaults/notes" isActive={false} onPress={() => {}} />
15
+ </box>
16
+ ),
17
+ expectedColors: [DARK.green, DARK.accent, DARK.border],
18
+ };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Typed settings rows for the settings dialog: toggle (on/off), cycle
3
+ * (enumerated options), and text (freeform value). Every row is one line -
4
+ * label column left, value right - and presses go through `onPress` so mouse
5
+ * and keyboard activation share one path.
6
+ */
7
+
8
+ import React from "react";
9
+ import type { Theme } from "../theme";
10
+ import { useComponentTheme } from "./theme-context";
11
+
12
+ export interface SettingsRowDescriptor {
13
+ key: string;
14
+ label: string;
15
+ kind: "toggle" | "cycle" | "text";
16
+ options?: string[];
17
+ hint?: string;
18
+ }
19
+
20
+ interface RowShellProps {
21
+ label: string;
22
+ isActive: boolean;
23
+ onPress: () => void;
24
+ theme?: Theme;
25
+ children: React.ReactNode;
26
+ }
27
+
28
+ function RowShell({ label, isActive, onPress, theme, children }: RowShellProps): React.ReactNode {
29
+ const tokens = useComponentTheme(theme);
30
+
31
+ return (
32
+ <box
33
+ style={{
34
+ flexDirection: "row",
35
+ height: 1,
36
+ backgroundColor: isActive ? tokens.border : undefined,
37
+ }}
38
+ onMouseUp={onPress}
39
+ >
40
+ <box style={{ width: 26, paddingLeft: 1 }}>
41
+ <text fg={isActive ? tokens.text : tokens.textMuted}>{label}</text>
42
+ </box>
43
+ {children}
44
+ </box>
45
+ );
46
+ }
47
+
48
+ export interface ToggleRowProps {
49
+ label: string;
50
+ value: boolean;
51
+ isActive: boolean;
52
+ onPress: () => void;
53
+ theme?: Theme;
54
+ }
55
+
56
+ export function ToggleRow({
57
+ label,
58
+ value,
59
+ isActive,
60
+ onPress,
61
+ theme,
62
+ }: ToggleRowProps): React.ReactNode {
63
+ const tokens = useComponentTheme(theme);
64
+
65
+ return (
66
+ <RowShell label={label} isActive={isActive} onPress={onPress} theme={theme}>
67
+ <text fg={value ? tokens.green : tokens.accent}>{value ? "on" : "off"}</text>
68
+ </RowShell>
69
+ );
70
+ }
71
+
72
+ export interface CycleRowProps {
73
+ label: string;
74
+ value: string;
75
+ isActive: boolean;
76
+ onPress: () => void;
77
+ theme?: Theme;
78
+ }
79
+
80
+ export function CycleRow({
81
+ label,
82
+ value,
83
+ isActive,
84
+ onPress,
85
+ theme,
86
+ }: CycleRowProps): React.ReactNode {
87
+ const tokens = useComponentTheme(theme);
88
+
89
+ return (
90
+ <RowShell label={label} isActive={isActive} onPress={onPress} theme={theme}>
91
+ <text fg={tokens.accent}>{value}</text>
92
+ </RowShell>
93
+ );
94
+ }
95
+
96
+ export interface TextRowProps {
97
+ label: string;
98
+ value: string;
99
+ isActive: boolean;
100
+ onPress: () => void;
101
+ theme?: Theme;
102
+ }
103
+
104
+ export function TextRow({ label, value, isActive, onPress, theme }: TextRowProps): React.ReactNode {
105
+ const tokens = useComponentTheme(theme);
106
+
107
+ return (
108
+ <RowShell label={label} isActive={isActive} onPress={onPress} theme={theme}>
109
+ <text fg={tokens.accent}>{value}</text>
110
+ </RowShell>
111
+ );
112
+ }
@@ -0,0 +1,121 @@
1
+ import React from "react";
2
+ import type { ShareLink } from "@cueloop/schema";
3
+ import { DARK } from "../theme";
4
+ import type { Story, StoryMeta } from "./story";
5
+ import { ShareDialog } from "./ShareDialog";
6
+ import { newWizardDraft, shareDialogStore } from "./share-dialog-store";
7
+
8
+ export const meta: StoryMeta = { title: "Dialogs/Share" };
9
+
10
+ const LINKS: ShareLink[] = [
11
+ { id: "p_ab12cd", name: "reviewers", requireAuth: true, allowlist: ["octocat"] },
12
+ { id: "p_ef34gh", requireAuth: false, allowlist: [] },
13
+ ];
14
+
15
+ const NOOP = {
16
+ onCreateLink: () => {},
17
+ onUpdateLink: () => {},
18
+ onDeleteLink: () => {},
19
+ onCopyLink: () => {},
20
+ onClose: () => {},
21
+ };
22
+
23
+ const SIZE = { width: 80, height: 24 };
24
+
25
+ export const EmptyList: Story = {
26
+ render: () => {
27
+ shareDialogStore.getState().reset();
28
+
29
+ return (
30
+ <ShareDialog
31
+ isOpen
32
+ threadName="Improve retry logic"
33
+ links={[]}
34
+ isOwner
35
+ {...NOOP}
36
+ theme={DARK}
37
+ />
38
+ );
39
+ },
40
+ size: SIZE,
41
+ };
42
+
43
+ export const WithLinks: Story = {
44
+ render: () => {
45
+ shareDialogStore.getState().reset();
46
+
47
+ return (
48
+ <ShareDialog
49
+ isOpen
50
+ threadName="Improve retry logic"
51
+ links={LINKS}
52
+ isOwner
53
+ {...NOOP}
54
+ theme={DARK}
55
+ />
56
+ );
57
+ },
58
+ size: SIZE,
59
+ };
60
+
61
+ export const ExportComingSoon: Story = {
62
+ render: () => {
63
+ shareDialogStore.getState().reset();
64
+ shareDialogStore.getState().setCategory("export");
65
+
66
+ return (
67
+ <ShareDialog
68
+ isOpen
69
+ threadName="Improve retry logic"
70
+ links={LINKS}
71
+ isOwner
72
+ {...NOOP}
73
+ theme={DARK}
74
+ />
75
+ );
76
+ },
77
+ size: SIZE,
78
+ };
79
+
80
+ export const NewLinkWizard: Story = {
81
+ render: () => {
82
+ shareDialogStore.getState().reset();
83
+ shareDialogStore.getState().openWizard(newWizardDraft("Improve retry logic"));
84
+
85
+ return (
86
+ <ShareDialog
87
+ isOpen
88
+ threadName="Improve retry logic"
89
+ links={[]}
90
+ isOwner
91
+ {...NOOP}
92
+ theme={DARK}
93
+ />
94
+ );
95
+ },
96
+ size: SIZE,
97
+ };
98
+
99
+ export const AuthWizard: Story = {
100
+ render: () => {
101
+ shareDialogStore.getState().reset();
102
+ shareDialogStore.getState().openWizard({
103
+ editingId: null,
104
+ name: "reviewers",
105
+ requireAuth: true,
106
+ allowlist: ["octocat", "hubot"],
107
+ });
108
+
109
+ return (
110
+ <ShareDialog
111
+ isOpen
112
+ threadName="Improve retry logic"
113
+ links={[]}
114
+ isOwner
115
+ {...NOOP}
116
+ theme={DARK}
117
+ />
118
+ );
119
+ },
120
+ size: SIZE,
121
+ };