markupr 2.1.8 → 2.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.
Files changed (300) hide show
  1. package/README.md +292 -15
  2. package/dist/cli/index.mjs +3593 -0
  3. package/dist/main/index.mjs +743 -220
  4. package/dist/mcp/index.mjs +4053 -0
  5. package/package.json +32 -7
  6. package/.claude/commands/review-feedback.md +0 -47
  7. package/.eslintrc.json +0 -35
  8. package/.github/CODEOWNERS +0 -16
  9. package/.github/FUNDING.yml +0 -1
  10. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -56
  11. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -54
  12. package/.github/PULL_REQUEST_TEMPLATE.md +0 -89
  13. package/.github/dependabot.yml +0 -70
  14. package/.github/workflows/ci.yml +0 -184
  15. package/.github/workflows/deploy-landing.yml +0 -134
  16. package/.github/workflows/nightly.yml +0 -288
  17. package/.github/workflows/release.yml +0 -318
  18. package/CHANGELOG.md +0 -127
  19. package/CLAUDE.md +0 -137
  20. package/CODE_OF_CONDUCT.md +0 -9
  21. package/CONTRIBUTING.md +0 -390
  22. package/PRODUCT_VISION.md +0 -277
  23. package/SECURITY.md +0 -51
  24. package/SIGNING_INSTRUCTIONS.md +0 -284
  25. package/assets/DMG_BACKGROUND_INSTRUCTIONS.md +0 -130
  26. package/assets/svg-source/dmg-background.svg +0 -70
  27. package/assets/svg-source/icon.svg +0 -20
  28. package/assets/svg-source/tray-icon-processing.svg +0 -7
  29. package/assets/svg-source/tray-icon-recording.svg +0 -7
  30. package/assets/svg-source/tray-icon.svg +0 -6
  31. package/assets/tray-complete.png +0 -0
  32. package/assets/tray-complete@2x.png +0 -0
  33. package/assets/tray-completeTemplate.png +0 -0
  34. package/assets/tray-completeTemplate@2x.png +0 -0
  35. package/assets/tray-error.png +0 -0
  36. package/assets/tray-error@2x.png +0 -0
  37. package/assets/tray-errorTemplate.png +0 -0
  38. package/assets/tray-errorTemplate@2x.png +0 -0
  39. package/assets/tray-icon-processing.png +0 -0
  40. package/assets/tray-icon-processing@2x.png +0 -0
  41. package/assets/tray-icon-processingTemplate.png +0 -0
  42. package/assets/tray-icon-processingTemplate@2x.png +0 -0
  43. package/assets/tray-icon-recording.png +0 -0
  44. package/assets/tray-icon-recording@2x.png +0 -0
  45. package/assets/tray-icon-recordingTemplate.png +0 -0
  46. package/assets/tray-icon-recordingTemplate@2x.png +0 -0
  47. package/assets/tray-icon.png +0 -0
  48. package/assets/tray-icon@2x.png +0 -0
  49. package/assets/tray-iconTemplate.png +0 -0
  50. package/assets/tray-iconTemplate@2x.png +0 -0
  51. package/assets/tray-idle.png +0 -0
  52. package/assets/tray-idle@2x.png +0 -0
  53. package/assets/tray-idleTemplate.png +0 -0
  54. package/assets/tray-idleTemplate@2x.png +0 -0
  55. package/assets/tray-processing-0.png +0 -0
  56. package/assets/tray-processing-0@2x.png +0 -0
  57. package/assets/tray-processing-0Template.png +0 -0
  58. package/assets/tray-processing-0Template@2x.png +0 -0
  59. package/assets/tray-processing-1.png +0 -0
  60. package/assets/tray-processing-1@2x.png +0 -0
  61. package/assets/tray-processing-1Template.png +0 -0
  62. package/assets/tray-processing-1Template@2x.png +0 -0
  63. package/assets/tray-processing-2.png +0 -0
  64. package/assets/tray-processing-2@2x.png +0 -0
  65. package/assets/tray-processing-2Template.png +0 -0
  66. package/assets/tray-processing-2Template@2x.png +0 -0
  67. package/assets/tray-processing-3.png +0 -0
  68. package/assets/tray-processing-3@2x.png +0 -0
  69. package/assets/tray-processing-3Template.png +0 -0
  70. package/assets/tray-processing-3Template@2x.png +0 -0
  71. package/assets/tray-processing.png +0 -0
  72. package/assets/tray-processing@2x.png +0 -0
  73. package/assets/tray-processingTemplate.png +0 -0
  74. package/assets/tray-processingTemplate@2x.png +0 -0
  75. package/assets/tray-recording.png +0 -0
  76. package/assets/tray-recording@2x.png +0 -0
  77. package/assets/tray-recordingTemplate.png +0 -0
  78. package/assets/tray-recordingTemplate@2x.png +0 -0
  79. package/build/DMG_BACKGROUND_SPEC.md +0 -50
  80. package/build/dmg-background.png +0 -0
  81. package/build/dmg-background@2x.png +0 -0
  82. package/build/entitlements.mac.inherit.plist +0 -27
  83. package/build/entitlements.mac.plist +0 -41
  84. package/build/favicon-16.png +0 -0
  85. package/build/favicon-180.png +0 -0
  86. package/build/favicon-192.png +0 -0
  87. package/build/favicon-32.png +0 -0
  88. package/build/favicon-48.png +0 -0
  89. package/build/favicon-512.png +0 -0
  90. package/build/favicon-64.png +0 -0
  91. package/build/icon-128.png +0 -0
  92. package/build/icon-16.png +0 -0
  93. package/build/icon-24.png +0 -0
  94. package/build/icon-256.png +0 -0
  95. package/build/icon-32.png +0 -0
  96. package/build/icon-48.png +0 -0
  97. package/build/icon-64.png +0 -0
  98. package/build/icon.icns +0 -0
  99. package/build/icon.ico +0 -0
  100. package/build/icon.iconset/icon_128x128.png +0 -0
  101. package/build/icon.iconset/icon_128x128@2x.png +0 -0
  102. package/build/icon.iconset/icon_16x16.png +0 -0
  103. package/build/icon.iconset/icon_16x16@2x.png +0 -0
  104. package/build/icon.iconset/icon_256x256.png +0 -0
  105. package/build/icon.iconset/icon_256x256@2x.png +0 -0
  106. package/build/icon.iconset/icon_32x32.png +0 -0
  107. package/build/icon.iconset/icon_32x32@2x.png +0 -0
  108. package/build/icon.iconset/icon_512x512.png +0 -0
  109. package/build/icon.iconset/icon_512x512@2x.png +0 -0
  110. package/build/icon.png +0 -0
  111. package/build/installer-header.bmp +0 -0
  112. package/build/installer-header.png +0 -0
  113. package/build/installer-sidebar.bmp +0 -0
  114. package/build/installer-sidebar.png +0 -0
  115. package/build/installer.nsh +0 -45
  116. package/build/overlay-processing.png +0 -0
  117. package/build/overlay-recording.png +0 -0
  118. package/build/toolbar-record.png +0 -0
  119. package/build/toolbar-screenshot.png +0 -0
  120. package/build/toolbar-settings.png +0 -0
  121. package/build/toolbar-stop.png +0 -0
  122. package/dist/preload/index.mjs +0 -907
  123. package/dist/renderer/assets/index-CCmUjl9K.js +0 -19495
  124. package/dist/renderer/assets/index-CUqz_Gs6.css +0 -2270
  125. package/dist/renderer/index.html +0 -27
  126. package/docs/AI_AGENT_QUICKSTART.md +0 -42
  127. package/docs/AI_PIPELINE_DESIGN.md +0 -595
  128. package/docs/API.md +0 -514
  129. package/docs/ARCHITECTURE.md +0 -460
  130. package/docs/CONFIGURATION.md +0 -336
  131. package/docs/DEVELOPMENT.md +0 -508
  132. package/docs/EXPORT_FORMATS.md +0 -451
  133. package/docs/GETTING_STARTED.md +0 -236
  134. package/docs/KEYBOARD_SHORTCUTS.md +0 -334
  135. package/docs/TROUBLESHOOTING.md +0 -418
  136. package/docs/landing/index.html +0 -672
  137. package/docs/landing/script.js +0 -342
  138. package/docs/landing/styles.css +0 -1543
  139. package/electron-builder.yml +0 -140
  140. package/electron.vite.config.ts +0 -63
  141. package/railway.json +0 -12
  142. package/scripts/build.mjs +0 -51
  143. package/scripts/generate-icons.mjs +0 -314
  144. package/scripts/generate-installer-images.cjs +0 -253
  145. package/scripts/generate-tray-icons.mjs +0 -258
  146. package/scripts/notarize.cjs +0 -180
  147. package/scripts/one-click-clean-test.sh +0 -147
  148. package/scripts/postinstall.mjs +0 -36
  149. package/scripts/setup-markupr.sh +0 -55
  150. package/setup +0 -17
  151. package/site/index.html +0 -1835
  152. package/site/package.json +0 -11
  153. package/site/railway.json +0 -12
  154. package/site/server.js +0 -31
  155. package/src/main/AutoUpdater.ts +0 -392
  156. package/src/main/CrashRecovery.ts +0 -655
  157. package/src/main/ErrorHandler.ts +0 -703
  158. package/src/main/HotkeyManager.ts +0 -399
  159. package/src/main/MenuManager.ts +0 -529
  160. package/src/main/PermissionManager.ts +0 -420
  161. package/src/main/SessionController.ts +0 -1465
  162. package/src/main/TrayManager.ts +0 -540
  163. package/src/main/ai/AIPipelineManager.ts +0 -199
  164. package/src/main/ai/ClaudeAnalyzer.ts +0 -339
  165. package/src/main/ai/ImageOptimizer.ts +0 -176
  166. package/src/main/ai/StructuredMarkdownBuilder.ts +0 -379
  167. package/src/main/ai/index.ts +0 -16
  168. package/src/main/ai/types.ts +0 -258
  169. package/src/main/analysis/ClarificationGenerator.ts +0 -385
  170. package/src/main/analysis/FeedbackAnalyzer.ts +0 -531
  171. package/src/main/analysis/index.ts +0 -19
  172. package/src/main/audio/AudioCapture.ts +0 -978
  173. package/src/main/audio/audioUtils.ts +0 -100
  174. package/src/main/audio/index.ts +0 -20
  175. package/src/main/capture/index.ts +0 -1
  176. package/src/main/index.ts +0 -1693
  177. package/src/main/ipc/captureHandlers.ts +0 -272
  178. package/src/main/ipc/index.ts +0 -45
  179. package/src/main/ipc/outputHandlers.ts +0 -302
  180. package/src/main/ipc/sessionHandlers.ts +0 -56
  181. package/src/main/ipc/settingsHandlers.ts +0 -471
  182. package/src/main/ipc/types.ts +0 -56
  183. package/src/main/ipc/windowHandlers.ts +0 -277
  184. package/src/main/output/ClipboardService.ts +0 -369
  185. package/src/main/output/ExportService.ts +0 -539
  186. package/src/main/output/FileManager.ts +0 -416
  187. package/src/main/output/MarkdownGenerator.ts +0 -791
  188. package/src/main/output/MarkdownPatcher.ts +0 -299
  189. package/src/main/output/index.ts +0 -186
  190. package/src/main/output/sessionAdapter.ts +0 -207
  191. package/src/main/output/templates/html-template.ts +0 -553
  192. package/src/main/pipeline/FrameExtractor.ts +0 -330
  193. package/src/main/pipeline/PostProcessor.ts +0 -399
  194. package/src/main/pipeline/TranscriptAnalyzer.ts +0 -226
  195. package/src/main/pipeline/index.ts +0 -36
  196. package/src/main/platform/WindowsTaskbar.ts +0 -600
  197. package/src/main/platform/index.ts +0 -16
  198. package/src/main/settings/SettingsManager.ts +0 -730
  199. package/src/main/settings/index.ts +0 -19
  200. package/src/main/transcription/ModelDownloadManager.ts +0 -494
  201. package/src/main/transcription/TierManager.ts +0 -219
  202. package/src/main/transcription/TranscriptionRecoveryService.ts +0 -340
  203. package/src/main/transcription/WhisperService.ts +0 -748
  204. package/src/main/transcription/index.ts +0 -56
  205. package/src/main/transcription/types.ts +0 -135
  206. package/src/main/windows/PopoverManager.ts +0 -284
  207. package/src/main/windows/TaskbarIntegration.ts +0 -452
  208. package/src/main/windows/index.ts +0 -23
  209. package/src/preload/index.ts +0 -1047
  210. package/src/renderer/App.tsx +0 -515
  211. package/src/renderer/AppWrapper.tsx +0 -28
  212. package/src/renderer/assets/logo-dark.svg +0 -7
  213. package/src/renderer/assets/logo.svg +0 -7
  214. package/src/renderer/audio/AudioCaptureRenderer.ts +0 -454
  215. package/src/renderer/capture/ScreenRecordingRenderer.ts +0 -492
  216. package/src/renderer/components/AnnotationOverlay.tsx +0 -836
  217. package/src/renderer/components/AudioWaveform.tsx +0 -811
  218. package/src/renderer/components/ClarificationQuestions.tsx +0 -656
  219. package/src/renderer/components/CountdownTimer.tsx +0 -495
  220. package/src/renderer/components/CrashRecoveryDialog.tsx +0 -632
  221. package/src/renderer/components/DonateButton.tsx +0 -127
  222. package/src/renderer/components/ErrorBoundary.tsx +0 -308
  223. package/src/renderer/components/ExportDialog.tsx +0 -872
  224. package/src/renderer/components/HotkeyHint.tsx +0 -261
  225. package/src/renderer/components/KeyboardShortcuts.tsx +0 -787
  226. package/src/renderer/components/ModelDownloadDialog.tsx +0 -844
  227. package/src/renderer/components/Onboarding.tsx +0 -1830
  228. package/src/renderer/components/ProcessingOverlay.tsx +0 -157
  229. package/src/renderer/components/RecordingOverlay.tsx +0 -423
  230. package/src/renderer/components/SessionHistory.tsx +0 -1746
  231. package/src/renderer/components/SessionReview.tsx +0 -1321
  232. package/src/renderer/components/SettingsPanel.tsx +0 -217
  233. package/src/renderer/components/Skeleton.tsx +0 -347
  234. package/src/renderer/components/StatusIndicator.tsx +0 -86
  235. package/src/renderer/components/ThemeProvider.tsx +0 -429
  236. package/src/renderer/components/Tooltip.tsx +0 -370
  237. package/src/renderer/components/TranscriptionPreview.tsx +0 -183
  238. package/src/renderer/components/TranscriptionTierSelector.tsx +0 -640
  239. package/src/renderer/components/UpdateNotification.tsx +0 -377
  240. package/src/renderer/components/WindowSelector.tsx +0 -947
  241. package/src/renderer/components/index.ts +0 -99
  242. package/src/renderer/components/primitives/ApiKeyInput.tsx +0 -98
  243. package/src/renderer/components/primitives/ColorPicker.tsx +0 -65
  244. package/src/renderer/components/primitives/DangerButton.tsx +0 -45
  245. package/src/renderer/components/primitives/DirectoryPicker.tsx +0 -41
  246. package/src/renderer/components/primitives/Dropdown.tsx +0 -34
  247. package/src/renderer/components/primitives/KeyRecorder.tsx +0 -117
  248. package/src/renderer/components/primitives/SettingsSection.tsx +0 -32
  249. package/src/renderer/components/primitives/Slider.tsx +0 -43
  250. package/src/renderer/components/primitives/Toggle.tsx +0 -36
  251. package/src/renderer/components/primitives/index.ts +0 -10
  252. package/src/renderer/components/settings/AdvancedTab.tsx +0 -174
  253. package/src/renderer/components/settings/AppearanceTab.tsx +0 -77
  254. package/src/renderer/components/settings/GeneralTab.tsx +0 -40
  255. package/src/renderer/components/settings/HotkeysTab.tsx +0 -79
  256. package/src/renderer/components/settings/RecordingTab.tsx +0 -84
  257. package/src/renderer/components/settings/index.ts +0 -9
  258. package/src/renderer/components/settings/settingsStyles.ts +0 -673
  259. package/src/renderer/components/settings/tabConfig.tsx +0 -85
  260. package/src/renderer/components/settings/useSettingsPanel.ts +0 -447
  261. package/src/renderer/contexts/ProcessingContext.tsx +0 -227
  262. package/src/renderer/contexts/RecordingContext.tsx +0 -683
  263. package/src/renderer/contexts/UIContext.tsx +0 -326
  264. package/src/renderer/contexts/index.ts +0 -24
  265. package/src/renderer/donateMessages.ts +0 -69
  266. package/src/renderer/hooks/index.ts +0 -75
  267. package/src/renderer/hooks/useAnimation.tsx +0 -544
  268. package/src/renderer/hooks/useTheme.ts +0 -313
  269. package/src/renderer/index.html +0 -26
  270. package/src/renderer/main.tsx +0 -52
  271. package/src/renderer/styles/animations.css +0 -1093
  272. package/src/renderer/styles/app-shell.css +0 -662
  273. package/src/renderer/styles/globals.css +0 -515
  274. package/src/renderer/styles/theme.ts +0 -578
  275. package/src/renderer/types/electron.d.ts +0 -385
  276. package/src/shared/hotkeys.ts +0 -283
  277. package/src/shared/types.ts +0 -809
  278. package/tests/clipboard.test.ts +0 -228
  279. package/tests/e2e/criticalPaths.test.ts +0 -594
  280. package/tests/feedbackAnalyzer.test.ts +0 -303
  281. package/tests/integration/sessionFlow.test.ts +0 -583
  282. package/tests/markdownGenerator.test.ts +0 -418
  283. package/tests/output.test.ts +0 -96
  284. package/tests/setup.ts +0 -486
  285. package/tests/unit/appIntegration.test.ts +0 -676
  286. package/tests/unit/appViewState.test.ts +0 -281
  287. package/tests/unit/audioIpcChannels.test.ts +0 -17
  288. package/tests/unit/exportService.test.ts +0 -492
  289. package/tests/unit/hotkeys.test.ts +0 -92
  290. package/tests/unit/navigationPreload.test.ts +0 -94
  291. package/tests/unit/onboardingFlow.test.ts +0 -345
  292. package/tests/unit/permissionManager.test.ts +0 -175
  293. package/tests/unit/permissionManagerExpanded.test.ts +0 -296
  294. package/tests/unit/screenRecordingRenderer.test.ts +0 -368
  295. package/tests/unit/sessionController.test.ts +0 -515
  296. package/tests/unit/tierManager.test.ts +0 -61
  297. package/tests/unit/tierManagerExpanded.test.ts +0 -142
  298. package/tests/unit/transcriptAnalyzer.test.ts +0 -64
  299. package/tsconfig.json +0 -25
  300. package/vitest.config.ts +0 -46
@@ -1,600 +0,0 @@
1
- /**
2
- * WindowsTaskbar - Windows-specific taskbar integration for markupr
3
- *
4
- * Provides native Windows taskbar features:
5
- * - Jump lists with recent sessions and quick actions
6
- * - Taskbar progress bar during export/processing
7
- * - Overlay icons for recording/processing states
8
- * - Thumbnail toolbar buttons for quick actions
9
- * - Frame flashing for completion notifications
10
- * - Custom thumbnail clip regions
11
- *
12
- * All methods are no-ops on non-Windows platforms.
13
- */
14
-
15
- import { BrowserWindow, app, nativeImage } from 'electron';
16
- import { join } from 'path';
17
-
18
- export interface RecentSession {
19
- id: string;
20
- name: string;
21
- path: string;
22
- date: Date;
23
- }
24
-
25
- export interface TaskbarActionCallback {
26
- onRecord: () => void;
27
- onStop: () => void;
28
- onScreenshot: () => void;
29
- onSettings: () => void;
30
- }
31
-
32
- type OverlayState = 'recording' | 'processing' | 'none';
33
- type ProgressMode = 'none' | 'normal' | 'indeterminate' | 'error' | 'paused';
34
-
35
- // Local interface for ThumbarButton since Electron types may vary
36
- interface ThumbarButton {
37
- tooltip: string;
38
- icon: Electron.NativeImage;
39
- flags?: ('enabled' | 'disabled' | 'dismissonclick' | 'nobackground' | 'hidden' | 'noninteractive')[];
40
- click: () => void;
41
- }
42
-
43
- export class WindowsTaskbar {
44
- private mainWindow: BrowserWindow;
45
- private isWindows: boolean;
46
- private recentSessions: RecentSession[] = [];
47
- private currentOverlayState: OverlayState = 'none';
48
- private isRecording = false;
49
- private actionCallbacks: TaskbarActionCallback | null = null;
50
- private assetsPath: string;
51
-
52
- constructor(mainWindow: BrowserWindow) {
53
- this.mainWindow = mainWindow;
54
- this.isWindows = process.platform === 'win32';
55
-
56
- // Assets are in build/ directory during development, resources/ in production
57
- this.assetsPath = app.isPackaged
58
- ? join(process.resourcesPath, 'build')
59
- : join(app.getAppPath(), 'build');
60
-
61
- if (!this.isWindows) {
62
- console.log('[WindowsTaskbar] Not on Windows, taskbar features disabled');
63
- }
64
- }
65
-
66
- /**
67
- * Set action callbacks for thumbnail toolbar buttons
68
- */
69
- setActionCallbacks(callbacks: TaskbarActionCallback): void {
70
- this.actionCallbacks = callbacks;
71
- }
72
-
73
- /**
74
- * Initialize the taskbar with default state
75
- */
76
- initialize(): void {
77
- if (!this.isWindows) return;
78
-
79
- console.log('[WindowsTaskbar] Initializing Windows taskbar integration');
80
-
81
- this.setupJumpList();
82
- this.setupThumbnailToolbar();
83
- this.setOverlayIcon('none');
84
- }
85
-
86
- /**
87
- * Set up Windows jump list with recent sessions and tasks
88
- *
89
- * Jump list structure:
90
- * - Recent Sessions (user tasks)
91
- * - Tasks (standard actions)
92
- */
93
- setupJumpList(): void {
94
- if (!this.isWindows) return;
95
-
96
- try {
97
- const jumpListItems: Electron.JumpListCategory[] = [];
98
-
99
- // Recent Sessions category
100
- if (this.recentSessions.length > 0) {
101
- const recentItems: Electron.JumpListItem[] = this.recentSessions
102
- .slice(0, 10) // Max 10 recent items
103
- .map((session) => ({
104
- type: 'task' as const,
105
- title: session.name,
106
- description: `Opened ${session.date.toLocaleDateString()}`,
107
- program: process.execPath,
108
- args: `--open-session "${session.path}"`,
109
- iconPath: process.execPath,
110
- iconIndex: 0,
111
- }));
112
-
113
- jumpListItems.push({
114
- type: 'custom',
115
- name: 'Recent Sessions',
116
- items: recentItems,
117
- });
118
- }
119
-
120
- // Tasks category - quick actions
121
- const tasks: Electron.JumpListItem[] = [
122
- {
123
- type: 'task',
124
- title: 'New Recording',
125
- description: 'Start a new feedback recording session',
126
- program: process.execPath,
127
- args: '--new-recording',
128
- iconPath: process.execPath,
129
- iconIndex: 0,
130
- },
131
- {
132
- type: 'task',
133
- title: 'Open Settings',
134
- description: 'Configure markupr settings',
135
- program: process.execPath,
136
- args: '--settings',
137
- iconPath: process.execPath,
138
- iconIndex: 0,
139
- },
140
- {
141
- type: 'task',
142
- title: 'Check for Updates',
143
- description: 'Check for application updates',
144
- program: process.execPath,
145
- args: '--check-updates',
146
- iconPath: process.execPath,
147
- iconIndex: 0,
148
- },
149
- ];
150
-
151
- jumpListItems.push({
152
- type: 'tasks',
153
- items: tasks,
154
- });
155
-
156
- app.setJumpList(jumpListItems);
157
- console.log('[WindowsTaskbar] Jump list configured');
158
- } catch (error) {
159
- console.error('[WindowsTaskbar] Failed to set jump list:', error);
160
- }
161
- }
162
-
163
- /**
164
- * Update the list of recent sessions in the jump list
165
- */
166
- updateRecentSessions(sessions: RecentSession[]): void {
167
- this.recentSessions = sessions;
168
- this.setupJumpList();
169
- }
170
-
171
- /**
172
- * Set taskbar progress bar
173
- *
174
- * @param progress - Progress value:
175
- * - 0 to 1: Normal progress percentage
176
- * - -1: Indeterminate (spinning) progress
177
- * - 2: Clear/remove progress bar
178
- */
179
- setProgress(progress: number): void {
180
- if (!this.isWindows) return;
181
-
182
- try {
183
- if (progress === 2 || progress < 0 && progress !== -1) {
184
- // Clear progress bar
185
- this.mainWindow.setProgressBar(-1);
186
- } else if (progress === -1) {
187
- // Indeterminate progress
188
- this.mainWindow.setProgressBar(2, { mode: 'indeterminate' });
189
- } else {
190
- // Normal progress (0-1)
191
- const clampedProgress = Math.max(0, Math.min(1, progress));
192
- this.mainWindow.setProgressBar(clampedProgress, { mode: 'normal' });
193
- }
194
- } catch (error) {
195
- console.error('[WindowsTaskbar] Failed to set progress:', error);
196
- }
197
- }
198
-
199
- /**
200
- * Set progress bar with specific mode
201
- */
202
- setProgressWithMode(progress: number, mode: ProgressMode): void {
203
- if (!this.isWindows) return;
204
-
205
- try {
206
- if (mode === 'none') {
207
- this.mainWindow.setProgressBar(-1);
208
- } else {
209
- const clampedProgress = Math.max(0, Math.min(1, progress));
210
- this.mainWindow.setProgressBar(clampedProgress, { mode });
211
- }
212
- } catch (error) {
213
- console.error('[WindowsTaskbar] Failed to set progress with mode:', error);
214
- }
215
- }
216
-
217
- /**
218
- * Clear the progress bar
219
- */
220
- clearProgress(): void {
221
- this.setProgress(2);
222
- }
223
-
224
- /**
225
- * Set overlay icon on the taskbar icon
226
- * Used to indicate recording/processing state
227
- */
228
- setOverlayIcon(state: OverlayState): void {
229
- if (!this.isWindows) return;
230
-
231
- this.currentOverlayState = state;
232
-
233
- try {
234
- if (state === 'none') {
235
- this.mainWindow.setOverlayIcon(null, '');
236
- return;
237
- }
238
-
239
- const iconName = state === 'recording'
240
- ? 'overlay-recording.png'
241
- : 'overlay-processing.png';
242
-
243
- const iconPath = join(this.assetsPath, iconName);
244
-
245
- try {
246
- const icon = nativeImage.createFromPath(iconPath);
247
-
248
- if (icon.isEmpty()) {
249
- // Fallback: create a simple colored icon programmatically
250
- const fallbackIcon = this.createFallbackOverlayIcon(state);
251
- const description = state === 'recording' ? 'Recording' : 'Processing';
252
- this.mainWindow.setOverlayIcon(fallbackIcon, description);
253
- console.log(`[WindowsTaskbar] Using fallback overlay icon for ${state}`);
254
- } else {
255
- const description = state === 'recording' ? 'Recording' : 'Processing';
256
- this.mainWindow.setOverlayIcon(icon, description);
257
- }
258
- } catch {
259
- // If icon file doesn't exist, create fallback
260
- const fallbackIcon = this.createFallbackOverlayIcon(state);
261
- const description = state === 'recording' ? 'Recording' : 'Processing';
262
- this.mainWindow.setOverlayIcon(fallbackIcon, description);
263
- console.log(`[WindowsTaskbar] Icon not found, using fallback for ${state}`);
264
- }
265
- } catch (error) {
266
- console.error('[WindowsTaskbar] Failed to set overlay icon:', error);
267
- }
268
- }
269
-
270
- /**
271
- * Create a fallback overlay icon programmatically
272
- */
273
- private createFallbackOverlayIcon(state: OverlayState): Electron.NativeImage {
274
- // Create a 16x16 icon using data URL
275
- const size = 16;
276
- const color = state === 'recording' ? '#FF4444' : '#4488FF';
277
-
278
- // Simple SVG circle
279
- const svg = `
280
- <svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
281
- <circle cx="${size/2}" cy="${size/2}" r="${size/2 - 1}" fill="${color}" />
282
- </svg>
283
- `;
284
-
285
- const base64 = Buffer.from(svg).toString('base64');
286
- return nativeImage.createFromDataURL(`data:image/svg+xml;base64,${base64}`);
287
- }
288
-
289
- /**
290
- * Set up thumbnail toolbar buttons
291
- * These appear when hovering over the taskbar icon
292
- */
293
- setupThumbnailToolbar(): void {
294
- if (!this.isWindows) return;
295
-
296
- try {
297
- const buttons = this.createThumbnailButtons();
298
- this.mainWindow.setThumbarButtons(buttons);
299
- console.log('[WindowsTaskbar] Thumbnail toolbar configured');
300
- } catch (error) {
301
- console.error('[WindowsTaskbar] Failed to set thumbnail toolbar:', error);
302
- }
303
- }
304
-
305
- /**
306
- * Update thumbnail toolbar based on recording state
307
- */
308
- updateThumbnailToolbar(isRecording: boolean): void {
309
- if (!this.isWindows) return;
310
-
311
- this.isRecording = isRecording;
312
-
313
- try {
314
- const buttons = this.createThumbnailButtons();
315
- this.mainWindow.setThumbarButtons(buttons);
316
- } catch (error) {
317
- console.error('[WindowsTaskbar] Failed to update thumbnail toolbar:', error);
318
- }
319
- }
320
-
321
- /**
322
- * Create thumbnail toolbar buttons based on current state
323
- */
324
- private createThumbnailButtons(): ThumbarButton[] {
325
- const buttons: ThumbarButton[] = [];
326
-
327
- // Record/Stop button
328
- if (this.isRecording) {
329
- buttons.push({
330
- tooltip: 'Stop Recording',
331
- icon: this.loadToolbarIcon('toolbar-stop.png'),
332
- click: () => {
333
- console.log('[WindowsTaskbar] Stop button clicked');
334
- this.actionCallbacks?.onStop();
335
- },
336
- });
337
- } else {
338
- buttons.push({
339
- tooltip: 'Start Recording',
340
- icon: this.loadToolbarIcon('toolbar-record.png'),
341
- click: () => {
342
- console.log('[WindowsTaskbar] Record button clicked');
343
- this.actionCallbacks?.onRecord();
344
- },
345
- });
346
- }
347
-
348
- // Screenshot button (only enabled during recording)
349
- buttons.push({
350
- tooltip: 'Take Screenshot',
351
- icon: this.loadToolbarIcon('toolbar-screenshot.png'),
352
- flags: this.isRecording ? [] : ['disabled'],
353
- click: () => {
354
- console.log('[WindowsTaskbar] Screenshot button clicked');
355
- this.actionCallbacks?.onScreenshot();
356
- },
357
- });
358
-
359
- // Settings button
360
- buttons.push({
361
- tooltip: 'Settings',
362
- icon: this.loadToolbarIcon('toolbar-settings.png'),
363
- click: () => {
364
- console.log('[WindowsTaskbar] Settings button clicked');
365
- this.actionCallbacks?.onSettings();
366
- },
367
- });
368
-
369
- return buttons;
370
- }
371
-
372
- /**
373
- * Load a toolbar icon, with fallback to programmatic icon
374
- */
375
- private loadToolbarIcon(iconName: string): Electron.NativeImage {
376
- const iconPath = join(this.assetsPath, iconName);
377
-
378
- try {
379
- const icon = nativeImage.createFromPath(iconPath);
380
-
381
- if (!icon.isEmpty()) {
382
- return icon;
383
- }
384
- } catch {
385
- // Fall through to create fallback
386
- }
387
-
388
- // Create fallback icon
389
- return this.createFallbackToolbarIcon(iconName);
390
- }
391
-
392
- /**
393
- * Create a fallback toolbar icon programmatically
394
- */
395
- private createFallbackToolbarIcon(iconName: string): Electron.NativeImage {
396
- const size = 16;
397
- let svgContent: string;
398
-
399
- if (iconName.includes('record')) {
400
- // Red circle for record
401
- svgContent = `
402
- <svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
403
- <circle cx="${size/2}" cy="${size/2}" r="${size/2 - 2}" fill="#FF4444" />
404
- </svg>
405
- `;
406
- } else if (iconName.includes('stop')) {
407
- // White square for stop
408
- svgContent = `
409
- <svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
410
- <rect x="3" y="3" width="${size - 6}" height="${size - 6}" fill="#FFFFFF" />
411
- </svg>
412
- `;
413
- } else if (iconName.includes('screenshot')) {
414
- // Camera-like icon for screenshot
415
- svgContent = `
416
- <svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
417
- <rect x="2" y="4" width="12" height="9" rx="1" fill="none" stroke="#FFFFFF" stroke-width="1.5"/>
418
- <circle cx="8" cy="8" r="2" fill="#FFFFFF"/>
419
- </svg>
420
- `;
421
- } else if (iconName.includes('settings')) {
422
- // Gear-like icon for settings
423
- svgContent = `
424
- <svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
425
- <circle cx="${size/2}" cy="${size/2}" r="3" fill="none" stroke="#FFFFFF" stroke-width="1.5"/>
426
- <circle cx="${size/2}" cy="${size/2}" r="6" fill="none" stroke="#FFFFFF" stroke-width="1" stroke-dasharray="2 2"/>
427
- </svg>
428
- `;
429
- } else {
430
- // Default: simple white circle
431
- svgContent = `
432
- <svg width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg">
433
- <circle cx="${size/2}" cy="${size/2}" r="${size/2 - 2}" fill="#FFFFFF" />
434
- </svg>
435
- `;
436
- }
437
-
438
- const base64 = Buffer.from(svgContent).toString('base64');
439
- return nativeImage.createFromDataURL(`data:image/svg+xml;base64,${base64}`);
440
- }
441
-
442
- /**
443
- * Flash the taskbar button to get user attention
444
- *
445
- * @param count - Number of times to flash (0 for continuous until focused)
446
- */
447
- flashFrame(count?: number): void {
448
- if (!this.isWindows) return;
449
-
450
- try {
451
- if (count === 0 || count === undefined) {
452
- // Flash until the window is focused
453
- this.mainWindow.flashFrame(true);
454
-
455
- // Stop flashing when window gains focus
456
- const stopFlashing = (): void => {
457
- this.mainWindow.flashFrame(false);
458
- this.mainWindow.removeListener('focus', stopFlashing);
459
- };
460
- this.mainWindow.once('focus', stopFlashing);
461
- } else {
462
- // Flash a specific number of times
463
- let flashCount = 0;
464
- const interval = setInterval(() => {
465
- if (flashCount >= count * 2) {
466
- clearInterval(interval);
467
- this.mainWindow.flashFrame(false);
468
- return;
469
- }
470
-
471
- this.mainWindow.flashFrame(flashCount % 2 === 0);
472
- flashCount++;
473
- }, 500);
474
- }
475
- } catch (error) {
476
- console.error('[WindowsTaskbar] Failed to flash frame:', error);
477
- }
478
- }
479
-
480
- /**
481
- * Stop flashing the taskbar button
482
- */
483
- stopFlashing(): void {
484
- if (!this.isWindows) return;
485
-
486
- try {
487
- this.mainWindow.flashFrame(false);
488
- } catch (error) {
489
- console.error('[WindowsTaskbar] Failed to stop flashing:', error);
490
- }
491
- }
492
-
493
- /**
494
- * Set a custom thumbnail clip region
495
- * Used to show a specific part of the window in the thumbnail preview
496
- *
497
- * @param region - Rectangle defining the clip region, or undefined to reset
498
- */
499
- setThumbnailClip(region?: Electron.Rectangle): void {
500
- if (!this.isWindows) return;
501
-
502
- try {
503
- if (region) {
504
- this.mainWindow.setThumbnailClip(region);
505
- } else {
506
- // Reset to full window
507
- this.mainWindow.setThumbnailClip({ x: 0, y: 0, width: 0, height: 0 });
508
- }
509
- } catch (error) {
510
- console.error('[WindowsTaskbar] Failed to set thumbnail clip:', error);
511
- }
512
- }
513
-
514
- /**
515
- * Update the taskbar state based on session state.
516
- * Supports the bulletproof 7-state machine.
517
- */
518
- updateSessionState(
519
- state: 'idle' | 'starting' | 'recording' | 'stopping' | 'processing' | 'complete' | 'error'
520
- ): void {
521
- switch (state) {
522
- case 'idle':
523
- this.setOverlayIcon('none');
524
- this.clearProgress();
525
- this.updateThumbnailToolbar(false);
526
- break;
527
- case 'starting':
528
- this.setOverlayIcon('processing');
529
- this.setProgress(-1); // Indeterminate while starting
530
- this.updateThumbnailToolbar(false);
531
- break;
532
- case 'recording':
533
- this.setOverlayIcon('recording');
534
- this.clearProgress();
535
- this.updateThumbnailToolbar(true);
536
- break;
537
- case 'stopping':
538
- this.setOverlayIcon('processing');
539
- this.setProgress(-1); // Indeterminate while stopping
540
- this.updateThumbnailToolbar(false);
541
- break;
542
- case 'processing':
543
- this.setOverlayIcon('processing');
544
- this.setProgress(-1); // Indeterminate
545
- this.updateThumbnailToolbar(false);
546
- break;
547
- case 'complete':
548
- this.setOverlayIcon('none');
549
- this.clearProgress();
550
- this.updateThumbnailToolbar(false);
551
- this.flashFrame(3); // Flash 3 times on completion
552
- break;
553
- case 'error':
554
- this.setOverlayIcon('none');
555
- this.clearProgress();
556
- this.updateThumbnailToolbar(false);
557
- this.flashFrame(2); // Flash 2 times on error
558
- break;
559
- }
560
- }
561
-
562
- /**
563
- * Clean up taskbar resources
564
- */
565
- destroy(): void {
566
- if (!this.isWindows) return;
567
-
568
- try {
569
- // Clear overlay icon
570
- this.mainWindow.setOverlayIcon(null, '');
571
-
572
- // Clear progress
573
- this.mainWindow.setProgressBar(-1);
574
-
575
- // Clear thumbnail toolbar
576
- this.mainWindow.setThumbarButtons([]);
577
-
578
- // Stop any flashing
579
- this.mainWindow.flashFrame(false);
580
-
581
- console.log('[WindowsTaskbar] Cleaned up');
582
- } catch (error) {
583
- console.error('[WindowsTaskbar] Error during cleanup:', error);
584
- }
585
- }
586
- }
587
-
588
- // Export singleton factory
589
- let windowsTaskbarInstance: WindowsTaskbar | null = null;
590
-
591
- export function createWindowsTaskbar(mainWindow: BrowserWindow): WindowsTaskbar {
592
- windowsTaskbarInstance = new WindowsTaskbar(mainWindow);
593
- return windowsTaskbarInstance;
594
- }
595
-
596
- export function getWindowsTaskbar(): WindowsTaskbar | null {
597
- return windowsTaskbarInstance;
598
- }
599
-
600
- export default WindowsTaskbar;
@@ -1,16 +0,0 @@
1
- /**
2
- * Platform-specific integrations for markupr
3
- *
4
- * Provides native OS features:
5
- * - Windows: Taskbar integration (jump lists, progress, overlay icons, thumbnail toolbar)
6
- * - macOS: Dock integration (handled by TrayManager and MenuManager)
7
- * - Linux: Unity launcher (future)
8
- */
9
-
10
- export {
11
- WindowsTaskbar,
12
- createWindowsTaskbar,
13
- getWindowsTaskbar,
14
- type RecentSession,
15
- type TaskbarActionCallback,
16
- } from './WindowsTaskbar';