@plannotator/ui 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/README.md +60 -0
  2. package/assets/diff-options.png +0 -0
  3. package/assets/icon-codex.png +0 -0
  4. package/assets/look-flat.png +0 -0
  5. package/assets/look-grid.png +0 -0
  6. package/assets/review-sections.png +0 -0
  7. package/assets/review-tree.png +0 -0
  8. package/assets/workspaces.webp +0 -0
  9. package/components/AISettingsTab.tsx +145 -0
  10. package/components/ActionMenu.tsx +101 -0
  11. package/components/AgentControls.tsx +216 -0
  12. package/components/AgentsTab.tsx +1294 -0
  13. package/components/AnnotationPanel.tsx +731 -0
  14. package/components/AnnotationSidebar.tsx +86 -0
  15. package/components/AnnotationToolbar.tsx +323 -0
  16. package/components/AnnotationToolstrip.tsx +355 -0
  17. package/components/ApproveDropdown.tsx +170 -0
  18. package/components/AttachmentsButton.tsx +410 -0
  19. package/components/BlockRenderer.tsx +163 -0
  20. package/components/BorderTrail.tsx +38 -0
  21. package/components/CodeFilePicker.tsx +64 -0
  22. package/components/CodeFilePopout.tsx +602 -0
  23. package/components/CodePathValidationContext.tsx +14 -0
  24. package/components/CommentPopover.tsx +512 -0
  25. package/components/CompletionOverlay.tsx +99 -0
  26. package/components/ConfirmDialog.tsx +128 -0
  27. package/components/DocBadges.tsx +231 -0
  28. package/components/EditorAnnotationCard.tsx +65 -0
  29. package/components/ExportModal.tsx +565 -0
  30. package/components/FloatingQuickLabelPicker.tsx +144 -0
  31. package/components/GitHubIcon.tsx +16 -0
  32. package/components/GitLabIcon.tsx +30 -0
  33. package/components/GraphvizBlock.tsx +511 -0
  34. package/components/ImageAnnotator/Canvas.tsx +118 -0
  35. package/components/ImageAnnotator/Toolbar.tsx +218 -0
  36. package/components/ImageAnnotator/index.tsx +272 -0
  37. package/components/ImageAnnotator/types.ts +39 -0
  38. package/components/ImageAnnotator/utils.ts +147 -0
  39. package/components/ImageThumbnail.tsx +126 -0
  40. package/components/ImportModal.tsx +146 -0
  41. package/components/InlineMarkdown.tsx +1094 -0
  42. package/components/KeyboardShortcuts.tsx +208 -0
  43. package/components/Landing.tsx +496 -0
  44. package/components/ListItemBody.tsx +62 -0
  45. package/components/ListMarker.tsx +73 -0
  46. package/components/LookAndFeelAnnouncementDialog.tsx +230 -0
  47. package/components/MarkdownEditor.tsx +44 -0
  48. package/components/MenuVersionSection.tsx +91 -0
  49. package/components/MermaidBlock.tsx +579 -0
  50. package/components/ModeToggle.tsx +68 -0
  51. package/components/OpenInAppButton.tsx +299 -0
  52. package/components/OverlayScrollArea.tsx +82 -0
  53. package/components/PermissionModeSetup.tsx +92 -0
  54. package/components/PinpointOverlay.tsx +99 -0
  55. package/components/PlanAIAnnouncementDialog.tsx +187 -0
  56. package/components/PlanHeaderMenu.tsx +299 -0
  57. package/components/PopoutDialog.tsx +91 -0
  58. package/components/Popover.tsx +27 -0
  59. package/components/ProviderIcons.tsx +51 -0
  60. package/components/PullRequestIcon.tsx +12 -0
  61. package/components/QuickLabelDropdown.tsx +63 -0
  62. package/components/RenderedMarkdown.tsx +54 -0
  63. package/components/RepoIcon.tsx +12 -0
  64. package/components/ResizeHandle.tsx +86 -0
  65. package/components/ReviewAgentsIcon.tsx +18 -0
  66. package/components/SearchableSelect.tsx +157 -0
  67. package/components/Settings.tsx +2220 -0
  68. package/components/SparklesIcon.tsx +45 -0
  69. package/components/StickyHeaderLane.tsx +260 -0
  70. package/components/TableOfContents.tsx +157 -0
  71. package/components/TaterSpritePullup.tsx +34 -0
  72. package/components/TaterSpriteRunning.tsx +54 -0
  73. package/components/TaterSpriteSitting.tsx +37 -0
  74. package/components/TextShimmer.tsx +57 -0
  75. package/components/ThemeProvider.tsx +162 -0
  76. package/components/ThemeTab.tsx +139 -0
  77. package/components/ToolbarButtons.tsx +116 -0
  78. package/components/Tooltip.tsx +45 -0
  79. package/components/Viewer.tsx +977 -0
  80. package/components/ai/AIProviderBar.tsx +95 -0
  81. package/components/ai/DocumentAIChatPanel.tsx +313 -0
  82. package/components/blocks/AlertBlock.tsx +58 -0
  83. package/components/blocks/Callout.tsx +60 -0
  84. package/components/blocks/CodeBlock.tsx +75 -0
  85. package/components/blocks/HtmlBlock.tsx +122 -0
  86. package/components/blocks/MathBlock.tsx +36 -0
  87. package/components/blocks/TableBlock.tsx +146 -0
  88. package/components/blocks/TablePopout.tsx +279 -0
  89. package/components/blocks/TableToolbar.tsx +153 -0
  90. package/components/blocks/proseBody.tsx +102 -0
  91. package/components/core/button.tsx +44 -0
  92. package/components/core/textarea.tsx +26 -0
  93. package/components/diagramLanguages.ts +14 -0
  94. package/components/goal-setup/GoalSetupSurface.tsx +1354 -0
  95. package/components/html-viewer/HtmlViewer.tsx +386 -0
  96. package/components/html-viewer/bridge-script.ts +505 -0
  97. package/components/html-viewer/index.ts +1 -0
  98. package/components/html-viewer/useHtmlAnnotation.ts +400 -0
  99. package/components/icons/AgentIcons.tsx +66 -0
  100. package/components/icons/AppIcon.tsx +56 -0
  101. package/components/icons/MessagesIcon.tsx +11 -0
  102. package/components/icons/ObsidianIcons.tsx +208 -0
  103. package/components/icons/app/android-studio.svg +369 -0
  104. package/components/icons/app/antigravity.svg +97 -0
  105. package/components/icons/app/cursor.svg +16 -0
  106. package/components/icons/app/file-explorer.svg +20 -0
  107. package/components/icons/app/finder.png +0 -0
  108. package/components/icons/app/ghostty.svg +13 -0
  109. package/components/icons/app/iterm2.svg +13 -0
  110. package/components/icons/app/powershell.svg +14 -0
  111. package/components/icons/app/sublime-text.svg +17 -0
  112. package/components/icons/app/terminal.png +0 -0
  113. package/components/icons/app/textmate.png +0 -0
  114. package/components/icons/app/vscode.svg +39 -0
  115. package/components/icons/app/warp.png +0 -0
  116. package/components/icons/app/xcode.png +0 -0
  117. package/components/icons/app/zed-dark.svg +15 -0
  118. package/components/icons/app/zed.svg +15 -0
  119. package/components/icons/themeIcons.tsx +47 -0
  120. package/components/mermaidSvg.ts +33 -0
  121. package/components/plan-diff/PlanCleanDiffView.tsx +884 -0
  122. package/components/plan-diff/PlanDiffBadge.tsx +48 -0
  123. package/components/plan-diff/PlanDiffModeSwitcher.tsx +103 -0
  124. package/components/plan-diff/PlanDiffViewer.tsx +214 -0
  125. package/components/plan-diff/PlanRawDiffView.tsx +102 -0
  126. package/components/plan-diff/VSCodeIcon.tsx +132 -0
  127. package/components/settings/HooksTab.tsx +208 -0
  128. package/components/sidebar/ArchiveBrowser.tsx +98 -0
  129. package/components/sidebar/CountBadge.tsx +12 -0
  130. package/components/sidebar/FileBrowser.tsx +498 -0
  131. package/components/sidebar/MessagesBrowser.tsx +109 -0
  132. package/components/sidebar/SidebarContainer.tsx +353 -0
  133. package/components/sidebar/SidebarTabs.tsx +155 -0
  134. package/components/sidebar/VersionBrowser.tsx +141 -0
  135. package/components/types.d.ts +7 -0
  136. package/components/ui/badge.tsx +44 -0
  137. package/components/ui/button.tsx +83 -0
  138. package/components/ui/card.tsx +58 -0
  139. package/components/ui/dialog.tsx +106 -0
  140. package/components/ui/dropdown-menu.tsx +240 -0
  141. package/components/ui/state-pill.tsx +45 -0
  142. package/components/ui/tabs.tsx +46 -0
  143. package/components/ui/textarea.tsx +25 -0
  144. package/config/configStore.ts +214 -0
  145. package/config/index.ts +4 -0
  146. package/config/reviewView.ts +42 -0
  147. package/config/settings.ts +310 -0
  148. package/config/useConfig.ts +20 -0
  149. package/configure.ts +69 -0
  150. package/globals.d.ts +14 -0
  151. package/hooks/pfm/useCodeFilePopout.ts +111 -0
  152. package/hooks/useAIChat.ts +532 -0
  153. package/hooks/useAIProviderConfig.ts +115 -0
  154. package/hooks/useActiveSection.ts +78 -0
  155. package/hooks/useAgentJobs.ts +306 -0
  156. package/hooks/useAgentSettings.ts +579 -0
  157. package/hooks/useAgents.ts +90 -0
  158. package/hooks/useAnnotationDraft.ts +523 -0
  159. package/hooks/useAnnotationHighlighter.ts +1170 -0
  160. package/hooks/useArchive.ts +171 -0
  161. package/hooks/useAutoClose.ts +104 -0
  162. package/hooks/useCodeAnnotationDraft.ts +194 -0
  163. package/hooks/useCodeFilePopout.ts +1 -0
  164. package/hooks/useDismissOnOutsideAndEscape.ts +50 -0
  165. package/hooks/useDraggable.ts +108 -0
  166. package/hooks/useEditorAnnotations.ts +64 -0
  167. package/hooks/useExternalAnnotationHighlights.ts +105 -0
  168. package/hooks/useExternalAnnotations.ts +268 -0
  169. package/hooks/useFileBrowser.ts +402 -0
  170. package/hooks/useInputMethodSwitch.ts +89 -0
  171. package/hooks/useIsMobile.ts +17 -0
  172. package/hooks/useLinkedDoc.ts +494 -0
  173. package/hooks/useOverlayViewport.ts +36 -0
  174. package/hooks/usePinpoint.ts +182 -0
  175. package/hooks/usePlanDiff.ts +176 -0
  176. package/hooks/usePrintMode.ts +27 -0
  177. package/hooks/useResizablePanel.ts +173 -0
  178. package/hooks/useScrollViewport.ts +38 -0
  179. package/hooks/useSharing.ts +441 -0
  180. package/hooks/useSidebar.ts +55 -0
  181. package/hooks/useUpdateCheck.ts +132 -0
  182. package/hooks/useValidatedCodePaths.ts +94 -0
  183. package/icons/GitUser.tsx +17 -0
  184. package/lib/utils.ts +11 -0
  185. package/package.json +117 -0
  186. package/plannotator.webp +0 -0
  187. package/print.css +427 -0
  188. package/shortcuts/code-review/ai.shortcuts.ts +25 -0
  189. package/shortcuts/code-review/allFilesDiff.shortcuts.ts +46 -0
  190. package/shortcuts/code-review/annotationToolbar.shortcuts.ts +30 -0
  191. package/shortcuts/code-review/fileTree.shortcuts.ts +35 -0
  192. package/shortcuts/code-review/prComments.shortcuts.ts +18 -0
  193. package/shortcuts/code-review/suggestionModal.shortcuts.ts +25 -0
  194. package/shortcuts/code-review/tourDialog.shortcuts.ts +18 -0
  195. package/shortcuts/core.ts +399 -0
  196. package/shortcuts/index.ts +21 -0
  197. package/shortcuts/plan-review/annotationPanel.shortcuts.ts +25 -0
  198. package/shortcuts/plan-review/annotationToolbar.shortcuts.ts +39 -0
  199. package/shortcuts/plan-review/commentPopover.shortcuts.ts +21 -0
  200. package/shortcuts/plan-review/goalSetup.shortcuts.ts +10 -0
  201. package/shortcuts/plan-review/imageAnnotator.shortcuts.ts +42 -0
  202. package/shortcuts/plan-review/inputMethod.shortcuts.ts +30 -0
  203. package/shortcuts/plan-review/sidebar.shortcuts.ts +34 -0
  204. package/shortcuts/plan-review/viewer.shortcuts.ts +24 -0
  205. package/shortcuts/runtime.ts +259 -0
  206. package/sprite_package_additional/index.html +34 -0
  207. package/sprite_package_additional/sprite.png +0 -0
  208. package/sprite_package_new/index.html +34 -0
  209. package/sprite_package_new/sprite.png +0 -0
  210. package/sprite_package_pulluphang/index.html +34 -0
  211. package/sprite_package_pulluphang/sprite.png +0 -0
  212. package/styles.css +1 -0
  213. package/theme.css +893 -0
  214. package/themes/adwaita.css +62 -0
  215. package/themes/andromeeda.css +66 -0
  216. package/themes/aurora-x.css +66 -0
  217. package/themes/ayu-dark.css +66 -0
  218. package/themes/caffeine.css +113 -0
  219. package/themes/catppuccin.css +62 -0
  220. package/themes/claude-plus.css +60 -0
  221. package/themes/cursor-hc.css +34 -0
  222. package/themes/cursor-midnight.css +34 -0
  223. package/themes/cursor.css +62 -0
  224. package/themes/dark-plus.css +66 -0
  225. package/themes/doom-64.css +109 -0
  226. package/themes/dracula.css +33 -0
  227. package/themes/everforest-hard.css +62 -0
  228. package/themes/everforest-soft.css +62 -0
  229. package/themes/everforest.css +62 -0
  230. package/themes/github.css +66 -0
  231. package/themes/gruvbox.css +62 -0
  232. package/themes/houston.css +66 -0
  233. package/themes/kanagawa-dragon.css +34 -0
  234. package/themes/kanagawa-lotus.css +34 -0
  235. package/themes/kanagawa-wave.css +34 -0
  236. package/themes/laserwave.css +66 -0
  237. package/themes/material.css +62 -0
  238. package/themes/min.css +66 -0
  239. package/themes/monokai-pro.css +34 -0
  240. package/themes/neutral.css +59 -0
  241. package/themes/night-owl.css +66 -0
  242. package/themes/nord.css +66 -0
  243. package/themes/one-dark-pro.css +66 -0
  244. package/themes/one-light.css +66 -0
  245. package/themes/paulmillr.css +34 -0
  246. package/themes/plannotator.css +60 -0
  247. package/themes/plastic.css +66 -0
  248. package/themes/poimandres.css +66 -0
  249. package/themes/quantum-rose.css +109 -0
  250. package/themes/red.css +66 -0
  251. package/themes/rose-pine.css +62 -0
  252. package/themes/simple.css +124 -0
  253. package/themes/slack.css +66 -0
  254. package/themes/snazzy-light.css +66 -0
  255. package/themes/soft-pop.css +60 -0
  256. package/themes/solar-dusk.css +109 -0
  257. package/themes/solarized.css +66 -0
  258. package/themes/synthwave-84.css +34 -0
  259. package/themes/terminal.css +62 -0
  260. package/themes/tinacious.css +57 -0
  261. package/themes/tokyo-night.css +62 -0
  262. package/themes/vesper.css +62 -0
  263. package/themes/vitesse-black.css +66 -0
  264. package/themes/vitesse.css +62 -0
  265. package/types.ts +264 -0
  266. package/utils/agentSwitch.ts +71 -0
  267. package/utils/aiChatFormat.ts +33 -0
  268. package/utils/aiPrompt.ts +29 -0
  269. package/utils/aiProvider.ts +217 -0
  270. package/utils/anchors.ts +11 -0
  271. package/utils/annotateAgentTerminal.ts +29 -0
  272. package/utils/annotationHelpers.ts +101 -0
  273. package/utils/bear.ts +59 -0
  274. package/utils/blockTargeting.ts +240 -0
  275. package/utils/callback.ts +99 -0
  276. package/utils/commentContent.ts +8 -0
  277. package/utils/defaultNotesApp.ts +20 -0
  278. package/utils/diffFonts.ts +33 -0
  279. package/utils/editorMode.ts +31 -0
  280. package/utils/fileBrowser.ts +40 -0
  281. package/utils/generateId.ts +7 -0
  282. package/utils/generateIdentity.ts +29 -0
  283. package/utils/identity.ts +112 -0
  284. package/utils/inlineTransforms.ts +41 -0
  285. package/utils/inputMethod.ts +17 -0
  286. package/utils/lookAndFeelAnnouncement.ts +18 -0
  287. package/utils/obsidian.ts +201 -0
  288. package/utils/octarine.ts +53 -0
  289. package/utils/parser.ts +991 -0
  290. package/utils/permissionMode.ts +77 -0
  291. package/utils/planAIAnnouncement.ts +17 -0
  292. package/utils/planAgentInstructions.ts +137 -0
  293. package/utils/planDiffEngine.ts +590 -0
  294. package/utils/planSave.ts +49 -0
  295. package/utils/platform.ts +11 -0
  296. package/utils/quickLabels.ts +77 -0
  297. package/utils/reviewAgentInstructions.ts +182 -0
  298. package/utils/sanitizeHtml.ts +45 -0
  299. package/utils/sharing.ts +350 -0
  300. package/utils/slugify.ts +37 -0
  301. package/utils/storage.ts +141 -0
  302. package/utils/themeRegistry.ts +567 -0
  303. package/utils/uiPreferences.ts +34 -0
  304. package/utils/upload.ts +56 -0
  305. package/utils/wideMode.ts +48 -0
@@ -0,0 +1,230 @@
1
+ /// <reference path="../globals.d.ts" />
2
+ import React, { useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { TextShimmer } from './TextShimmer';
5
+ import lookGridImg from '../assets/look-grid.png';
6
+ import lookFlatImg from '../assets/look-flat.png';
7
+ import workspacesImg from '../assets/workspaces.webp';
8
+
9
+ interface LookAndFeelAnnouncementDialogProps {
10
+ isOpen: boolean;
11
+ /** Current value of the singleton configStore 'gridEnabled' key. */
12
+ gridEnabled: boolean;
13
+ /** App owns this: it calls configStore.set('gridEnabled', value). */
14
+ onToggleGrid: (value: boolean) => void;
15
+ /** Marks the announcement seen and closes the dialog. */
16
+ onDismiss: () => void;
17
+ }
18
+
19
+ const WAITLIST_URL = 'https://plannotator.ai/workspaces';
20
+
21
+ const FEATURES: { title: string; desc: string }[] = [
22
+ {
23
+ title: 'Leaner install',
24
+ desc: 'Only the core skills ship by default. Extra skills install separately.',
25
+ },
26
+ { title: 'A fresh new look', desc: 'Refreshed UI 2.0 with new Simple and Neutral themes.' },
27
+ { title: 'Semantic code review', desc: 'Diffs grouped by what changed, not just which lines.' },
28
+ { title: 'Multi-repo reviews', desc: 'Review nested repositories together in one pass.' },
29
+ {
30
+ title: 'Full-page HTML',
31
+ desc: 'Render HTML reports and explainers full-screen, then annotate them in place.',
32
+ },
33
+ ];
34
+
35
+ const LOOK_OPTIONS: {
36
+ key: string;
37
+ /** gridEnabled value this option selects. */
38
+ value: boolean;
39
+ img: string;
40
+ title: string;
41
+ tag: string;
42
+ desc: string;
43
+ }[] = [
44
+ {
45
+ key: 'grid',
46
+ value: true,
47
+ img: lookGridImg,
48
+ title: 'Grid',
49
+ tag: 'Classic',
50
+ desc: 'Your plan as a floating card on grid paper.',
51
+ },
52
+ {
53
+ key: 'flat',
54
+ value: false,
55
+ img: lookFlatImg,
56
+ title: 'Clean',
57
+ tag: 'New',
58
+ desc: 'A simpler, edge-to-edge flat card.',
59
+ },
60
+ ];
61
+
62
+ export const LookAndFeelAnnouncementDialog: React.FC<LookAndFeelAnnouncementDialogProps> = ({
63
+ isOpen,
64
+ gridEnabled,
65
+ onToggleGrid,
66
+ onDismiss,
67
+ }) => {
68
+ const [page, setPage] = useState<1 | 2>(1);
69
+ const [hovered, setHovered] = useState<string | null>(null);
70
+ if (!isOpen) return null;
71
+
72
+ return createPortal(
73
+ <div className="fixed inset-0 z-[100] flex items-center justify-center bg-background/90 backdrop-blur-sm p-4">
74
+ {/* Fixed size across both pages; the dialog never resizes. */}
75
+ <div className="bg-card border border-border rounded-xl w-full max-w-5xl h-[760px] shadow-2xl flex flex-col">
76
+ {page === 1 ? (
77
+ <>
78
+ {/* Header */}
79
+ <div className="p-7 border-b border-border">
80
+ <div className="flex items-start justify-between gap-4">
81
+ <h3 className="font-semibold text-2xl mb-1.5">Plannotator 0.20.0 is here</h3>
82
+ <a
83
+ href="https://github.com/backnotprop/plannotator/releases/tag/v0.20.0"
84
+ target="_blank"
85
+ rel="noopener noreferrer"
86
+ className="shrink-0 mt-1.5 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors"
87
+ >
88
+ Full release notes &#8599;
89
+ </a>
90
+ </div>
91
+ <p className="text-sm text-muted-foreground">
92
+ A big release. Here&apos;s what&apos;s new, plus a choice of how your plans look.
93
+ </p>
94
+ </div>
95
+
96
+ {/* What's new */}
97
+ <div className="px-7 pt-6 grid grid-cols-5 gap-3">
98
+ {FEATURES.map((f) => (
99
+ <div key={f.title} className="rounded-lg border border-border bg-muted/40 p-3">
100
+ <div className="text-sm font-semibold">{f.title}</div>
101
+ <div className="text-xs text-muted-foreground mt-0.5 leading-snug">{f.desc}</div>
102
+ </div>
103
+ ))}
104
+ </div>
105
+
106
+ {/* Plan-look chooser */}
107
+ <div className="px-7 pt-6 flex-1 min-h-0">
108
+ <div className="text-sm font-medium mb-3">Choose your plan look</div>
109
+ <div className="flex gap-6">
110
+ {LOOK_OPTIONS.map((opt) => {
111
+ const selected = gridEnabled === opt.value;
112
+ const isHovered = hovered === opt.key;
113
+ return (
114
+ <button
115
+ key={opt.key}
116
+ type="button"
117
+ onClick={() => onToggleGrid(opt.value)}
118
+ onMouseEnter={() => setHovered(opt.key)}
119
+ onMouseLeave={() => setHovered((h) => (h === opt.key ? null : h))}
120
+ aria-pressed={selected}
121
+ className={`flex-1 min-w-0 flex flex-col items-stretch gap-2 rounded-lg border p-2 text-left transition-colors ${
122
+ selected
123
+ ? 'border-primary bg-primary/5'
124
+ : 'border-border hover:border-muted-foreground/40'
125
+ }`}
126
+ >
127
+ <div className="relative">
128
+ <img
129
+ src={opt.img}
130
+ alt={`${opt.title} plan look`}
131
+ className="w-full rounded-md select-none"
132
+ draggable={false}
133
+ style={{
134
+ border: `2px solid ${
135
+ selected
136
+ ? 'var(--primary)'
137
+ : 'color-mix(in srgb, var(--primary) 25%, transparent)'
138
+ }`,
139
+ transform: isHovered ? 'scale(1.22)' : 'scale(1)',
140
+ transformOrigin: 'center',
141
+ zIndex: isHovered ? 50 : 0,
142
+ position: 'relative',
143
+ boxShadow: isHovered ? '0 14px 36px rgba(0,0,0,0.4)' : 'none',
144
+ transition:
145
+ 'transform 0.25s cubic-bezier(0.34,1.56,0.64,1), border-color 0.2s ease, box-shadow 0.2s ease',
146
+ }}
147
+ />
148
+ </div>
149
+ <div className="flex items-center justify-between gap-2 px-0.5 mt-1">
150
+ <span className="text-base font-semibold">{opt.title}</span>
151
+ <span
152
+ className={`text-[11px] leading-none px-2 py-0.5 rounded-full ${
153
+ selected ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'
154
+ }`}
155
+ >
156
+ {selected ? 'Selected' : opt.tag}
157
+ </span>
158
+ </div>
159
+ <p className="text-sm text-muted-foreground px-0.5 leading-snug">{opt.desc}</p>
160
+ </button>
161
+ );
162
+ })}
163
+ </div>
164
+ </div>
165
+
166
+ {/* Footer */}
167
+ <div className="px-7 py-5 border-t border-border flex justify-end items-center gap-4">
168
+ <button
169
+ type="button"
170
+ onClick={() => setPage(2)}
171
+ className="px-4 py-2 rounded-lg border border-primary/35 hover:opacity-80 transition-opacity"
172
+ >
173
+ <TextShimmer className="text-sm font-medium" duration={2.5} spread={1.5}>
174
+ {'✨ Workspaces are coming 🎉 →'}
175
+ </TextShimmer>
176
+ </button>
177
+ <button
178
+ onClick={onDismiss}
179
+ className="px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm font-medium hover:opacity-90 transition-opacity"
180
+ >
181
+ Got it
182
+ </button>
183
+ </div>
184
+ </>
185
+ ) : (
186
+ <>
187
+ {/* Header */}
188
+ <div className="p-7 border-b border-border">
189
+ <h3 className="font-semibold text-2xl mb-1.5">Workspaces are coming 🎉</h3>
190
+ <p className="text-sm text-muted-foreground">
191
+ A shared context workspace for specs, reviews, and decisions your agents can build
192
+ on. Join the waitlist.
193
+ </p>
194
+ </div>
195
+
196
+ {/* The landscape teaser image, scaled to fit the fixed dialog. */}
197
+ <div className="flex-1 min-h-0 p-6 flex items-center justify-center">
198
+ <img
199
+ src={workspacesImg}
200
+ alt="Plannotator Workspaces, a shared context workspace across your agents"
201
+ className="max-h-full max-w-full w-auto object-contain rounded-lg border border-border select-none"
202
+ draggable={false}
203
+ />
204
+ </div>
205
+
206
+ {/* Footer */}
207
+ <div className="px-7 py-5 border-t border-border flex justify-end items-center gap-4">
208
+ <button
209
+ type="button"
210
+ onClick={() => setPage(1)}
211
+ className="text-sm text-muted-foreground hover:text-foreground transition-colors"
212
+ >
213
+ &larr; Back
214
+ </button>
215
+ <a
216
+ href={WAITLIST_URL}
217
+ target="_blank"
218
+ rel="noopener noreferrer"
219
+ className="px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm font-medium hover:opacity-90 transition-opacity"
220
+ >
221
+ Join the waitlist
222
+ </a>
223
+ </div>
224
+ </>
225
+ )}
226
+ </div>
227
+ </div>,
228
+ document.body
229
+ );
230
+ };
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import {
3
+ MarkdownEditor as PackagedMarkdownEditor,
4
+ type MarkdownEditorHandle,
5
+ } from '@plannotator/markdown-editor';
6
+ import '@plannotator/markdown-editor/themes/plannotator.css';
7
+ import { useTheme } from './ThemeProvider';
8
+
9
+ export type { MarkdownEditorHandle };
10
+
11
+ /* Grid-mode card utilities stay here (not in the package): they're Plannotator
12
+ design-system Tailwind classes, and this file is @source-scanned. */
13
+ const GRID_CARD_CLASSES = 'px-5 md:px-8 lg:px-10 xl:px-12 shadow-xl border border-border/50';
14
+
15
+ interface MarkdownEditorProps {
16
+ /** Initial markdown. Read at mount only — the editor owns the text after that.
17
+ Read the current text via editorHandleRef.current.getMarkdown(). */
18
+ markdown: string;
19
+ /** Identity key; change to remount with new content. */
20
+ documentId: string;
21
+ editorHandleRef: React.MutableRefObject<MarkdownEditorHandle | null>;
22
+ onMarkdownChange?: (markdown: string) => void;
23
+ onLinkClick?: (url: string) => void;
24
+ /** Mirrors the Viewer card's outer maxWidth so toggling view<->edit doesn't jump. */
25
+ maxWidth?: number | null;
26
+ gridEnabled?: boolean;
27
+ /** Theme color mode. Defaults to the ThemeProvider's resolved mode (Plannotator
28
+ passes nothing); a host without ThemeProvider can supply it directly. */
29
+ mode?: React.ComponentProps<typeof PackagedMarkdownEditor>['mode'];
30
+ }
31
+
32
+ /* Theme-bridging shim around @plannotator/markdown-editor. App.tsx renders its
33
+ ThemeProvider inside its own JSX, so the resolved color mode must be read
34
+ from a component beneath the provider — here — and passed down as a prop. */
35
+ export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({ gridEnabled, mode, ...props }) => {
36
+ const { resolvedMode } = useTheme();
37
+ return (
38
+ <PackagedMarkdownEditor
39
+ {...props}
40
+ mode={mode ?? resolvedMode}
41
+ cardClassName={gridEnabled ? GRID_CARD_CLASSES : undefined}
42
+ />
43
+ );
44
+ };
@@ -0,0 +1,91 @@
1
+ import React, { useState } from 'react';
2
+ import { TextShimmer } from './TextShimmer';
3
+ import type { UpdateInfo } from '../hooks/useUpdateCheck';
4
+ import type { Origin } from '@plannotator/core/agents';
5
+ import { isWindows } from '../utils/platform';
6
+
7
+ const PI_INSTALL_COMMAND = 'pi install npm:@plannotator/pi-extension';
8
+
9
+ function getInstallCommand(origin?: Origin | null, isWSL = false): string {
10
+ if (origin === 'pi') return PI_INSTALL_COMMAND;
11
+ return isWindows && !isWSL
12
+ ? 'powershell -c "irm https://plannotator.ai/install.ps1 | iex"'
13
+ : 'curl -fsSL https://plannotator.ai/install.sh | bash';
14
+ }
15
+
16
+ interface MenuVersionSectionProps {
17
+ appVersion: string;
18
+ updateInfo?: UpdateInfo | null;
19
+ origin?: Origin | null;
20
+ isWSL: boolean;
21
+ closeMenu: () => void;
22
+ }
23
+
24
+ export const MenuVersionSection: React.FC<MenuVersionSectionProps> = ({
25
+ appVersion,
26
+ updateInfo,
27
+ origin,
28
+ isWSL,
29
+ closeMenu,
30
+ }) => {
31
+ const [copied, setCopied] = useState(false);
32
+ const hasUpdate = !!updateInfo?.updateAvailable;
33
+
34
+ const handleCopy = async () => {
35
+ try {
36
+ await navigator.clipboard.writeText(getInstallCommand(origin, isWSL));
37
+ setCopied(true);
38
+ setTimeout(() => setCopied(false), 2000);
39
+ } catch (e) {
40
+ console.error('Failed to copy:', e);
41
+ }
42
+ };
43
+
44
+ return (
45
+ <div className="px-3 py-2 space-y-2">
46
+ <div className="flex items-center justify-between gap-3">
47
+ <a
48
+ href="https://github.com/backnotprop/plannotator"
49
+ target="_blank"
50
+ rel="noopener noreferrer"
51
+ onClick={closeMenu}
52
+ className="text-[10px] font-semibold tracking-wide text-muted-foreground hover:text-foreground transition-colors"
53
+ >
54
+ Plannotator
55
+ </a>
56
+ <span className="text-[10px] font-mono text-muted-foreground/70">
57
+ v{appVersion}
58
+ </span>
59
+ </div>
60
+ <div className="flex flex-col items-start gap-1 text-[11px]">
61
+ <span className="flex items-center gap-1.5">
62
+ <a
63
+ href={hasUpdate ? updateInfo!.releaseUrl : 'https://github.com/backnotprop/plannotator/releases'}
64
+ target="_blank"
65
+ rel="noopener noreferrer"
66
+ onClick={closeMenu}
67
+ className="text-muted-foreground hover:text-foreground transition-colors"
68
+ >
69
+ Release notes
70
+ </a>
71
+ {hasUpdate && (
72
+ <>
73
+ <span className="text-muted-foreground/40">·</span>
74
+ <TextShimmer className="text-[10px] font-medium" duration={2.5} spread={1.5}>
75
+ New update available!
76
+ </TextShimmer>
77
+ </>
78
+ )}
79
+ </span>
80
+ {hasUpdate && (
81
+ <button
82
+ onClick={handleCopy}
83
+ className="w-full mt-1 px-2.5 py-1.5 rounded-md text-[11px] font-medium bg-primary text-primary-foreground hover:opacity-90 transition-opacity"
84
+ >
85
+ {copied ? 'Copied!' : 'Copy update command'}
86
+ </button>
87
+ )}
88
+ </div>
89
+ </div>
90
+ );
91
+ };