markupr 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/review-feedback.md +47 -0
- package/.eslintrc.json +35 -0
- package/.github/CODEOWNERS +16 -0
- package/.github/FUNDING.yml +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +56 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +54 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +89 -0
- package/.github/dependabot.yml +70 -0
- package/.github/workflows/ci.yml +184 -0
- package/.github/workflows/deploy-landing.yml +134 -0
- package/.github/workflows/nightly.yml +288 -0
- package/.github/workflows/release.yml +318 -0
- package/CHANGELOG.md +127 -0
- package/CLAUDE.md +137 -0
- package/CODE_OF_CONDUCT.md +9 -0
- package/CONTRIBUTING.md +390 -0
- package/LICENSE +21 -0
- package/PRODUCT_VISION.md +277 -0
- package/README.md +517 -0
- package/SECURITY.md +51 -0
- package/SIGNING_INSTRUCTIONS.md +284 -0
- package/assets/DMG_BACKGROUND_INSTRUCTIONS.md +130 -0
- package/assets/svg-source/dmg-background.svg +70 -0
- package/assets/svg-source/icon.svg +20 -0
- package/assets/svg-source/tray-icon-processing.svg +7 -0
- package/assets/svg-source/tray-icon-recording.svg +7 -0
- package/assets/svg-source/tray-icon.svg +6 -0
- package/assets/tray-complete.png +0 -0
- package/assets/tray-complete@2x.png +0 -0
- package/assets/tray-completeTemplate.png +0 -0
- package/assets/tray-completeTemplate@2x.png +0 -0
- package/assets/tray-error.png +0 -0
- package/assets/tray-error@2x.png +0 -0
- package/assets/tray-errorTemplate.png +0 -0
- package/assets/tray-errorTemplate@2x.png +0 -0
- package/assets/tray-icon-processing.png +0 -0
- package/assets/tray-icon-processing@2x.png +0 -0
- package/assets/tray-icon-processingTemplate.png +0 -0
- package/assets/tray-icon-processingTemplate@2x.png +0 -0
- package/assets/tray-icon-recording.png +0 -0
- package/assets/tray-icon-recording@2x.png +0 -0
- package/assets/tray-icon-recordingTemplate.png +0 -0
- package/assets/tray-icon-recordingTemplate@2x.png +0 -0
- package/assets/tray-icon.png +0 -0
- package/assets/tray-icon@2x.png +0 -0
- package/assets/tray-iconTemplate.png +0 -0
- package/assets/tray-iconTemplate@2x.png +0 -0
- package/assets/tray-idle.png +0 -0
- package/assets/tray-idle@2x.png +0 -0
- package/assets/tray-idleTemplate.png +0 -0
- package/assets/tray-idleTemplate@2x.png +0 -0
- package/assets/tray-processing-0.png +0 -0
- package/assets/tray-processing-0@2x.png +0 -0
- package/assets/tray-processing-0Template.png +0 -0
- package/assets/tray-processing-0Template@2x.png +0 -0
- package/assets/tray-processing-1.png +0 -0
- package/assets/tray-processing-1@2x.png +0 -0
- package/assets/tray-processing-1Template.png +0 -0
- package/assets/tray-processing-1Template@2x.png +0 -0
- package/assets/tray-processing-2.png +0 -0
- package/assets/tray-processing-2@2x.png +0 -0
- package/assets/tray-processing-2Template.png +0 -0
- package/assets/tray-processing-2Template@2x.png +0 -0
- package/assets/tray-processing-3.png +0 -0
- package/assets/tray-processing-3@2x.png +0 -0
- package/assets/tray-processing-3Template.png +0 -0
- package/assets/tray-processing-3Template@2x.png +0 -0
- package/assets/tray-processing.png +0 -0
- package/assets/tray-processing@2x.png +0 -0
- package/assets/tray-processingTemplate.png +0 -0
- package/assets/tray-processingTemplate@2x.png +0 -0
- package/assets/tray-recording.png +0 -0
- package/assets/tray-recording@2x.png +0 -0
- package/assets/tray-recordingTemplate.png +0 -0
- package/assets/tray-recordingTemplate@2x.png +0 -0
- package/build/DMG_BACKGROUND_SPEC.md +50 -0
- package/build/dmg-background.png +0 -0
- package/build/dmg-background@2x.png +0 -0
- package/build/entitlements.mac.inherit.plist +27 -0
- package/build/entitlements.mac.plist +41 -0
- package/build/favicon-16.png +0 -0
- package/build/favicon-180.png +0 -0
- package/build/favicon-192.png +0 -0
- package/build/favicon-32.png +0 -0
- package/build/favicon-48.png +0 -0
- package/build/favicon-512.png +0 -0
- package/build/favicon-64.png +0 -0
- package/build/icon-128.png +0 -0
- package/build/icon-16.png +0 -0
- package/build/icon-24.png +0 -0
- package/build/icon-256.png +0 -0
- package/build/icon-32.png +0 -0
- package/build/icon-48.png +0 -0
- package/build/icon-64.png +0 -0
- package/build/icon.icns +0 -0
- package/build/icon.ico +0 -0
- package/build/icon.iconset/icon_128x128.png +0 -0
- package/build/icon.iconset/icon_128x128@2x.png +0 -0
- package/build/icon.iconset/icon_16x16.png +0 -0
- package/build/icon.iconset/icon_16x16@2x.png +0 -0
- package/build/icon.iconset/icon_256x256.png +0 -0
- package/build/icon.iconset/icon_256x256@2x.png +0 -0
- package/build/icon.iconset/icon_32x32.png +0 -0
- package/build/icon.iconset/icon_32x32@2x.png +0 -0
- package/build/icon.iconset/icon_512x512.png +0 -0
- package/build/icon.iconset/icon_512x512@2x.png +0 -0
- package/build/icon.png +0 -0
- package/build/installer-header.bmp +0 -0
- package/build/installer-header.png +0 -0
- package/build/installer-sidebar.bmp +0 -0
- package/build/installer-sidebar.png +0 -0
- package/build/installer.nsh +45 -0
- package/build/overlay-processing.png +0 -0
- package/build/overlay-recording.png +0 -0
- package/build/toolbar-record.png +0 -0
- package/build/toolbar-screenshot.png +0 -0
- package/build/toolbar-settings.png +0 -0
- package/build/toolbar-stop.png +0 -0
- package/dist/main/index.mjs +12612 -0
- package/dist/preload/index.mjs +907 -0
- package/dist/renderer/assets/index-CCmUjl9K.js +19495 -0
- package/dist/renderer/assets/index-CUqz_Gs6.css +2270 -0
- package/dist/renderer/index.html +27 -0
- package/docs/AI_AGENT_QUICKSTART.md +42 -0
- package/docs/AI_PIPELINE_DESIGN.md +595 -0
- package/docs/API.md +514 -0
- package/docs/ARCHITECTURE.md +460 -0
- package/docs/CONFIGURATION.md +336 -0
- package/docs/DEVELOPMENT.md +508 -0
- package/docs/EXPORT_FORMATS.md +451 -0
- package/docs/GETTING_STARTED.md +236 -0
- package/docs/KEYBOARD_SHORTCUTS.md +334 -0
- package/docs/TROUBLESHOOTING.md +418 -0
- package/docs/landing/index.html +672 -0
- package/docs/landing/script.js +342 -0
- package/docs/landing/styles.css +1543 -0
- package/electron-builder.yml +140 -0
- package/electron.vite.config.ts +63 -0
- package/package.json +108 -0
- package/railway.json +12 -0
- package/scripts/build.mjs +51 -0
- package/scripts/generate-icons.mjs +314 -0
- package/scripts/generate-installer-images.cjs +253 -0
- package/scripts/generate-tray-icons.mjs +258 -0
- package/scripts/notarize.cjs +180 -0
- package/scripts/one-click-clean-test.sh +147 -0
- package/scripts/postinstall.mjs +36 -0
- package/scripts/setup-markupr.sh +55 -0
- package/setup +17 -0
- package/site/index.html +1835 -0
- package/site/package.json +11 -0
- package/site/railway.json +12 -0
- package/site/server.js +31 -0
- package/src/main/AutoUpdater.ts +392 -0
- package/src/main/CrashRecovery.ts +655 -0
- package/src/main/ErrorHandler.ts +703 -0
- package/src/main/HotkeyManager.ts +399 -0
- package/src/main/MenuManager.ts +529 -0
- package/src/main/PermissionManager.ts +420 -0
- package/src/main/SessionController.ts +1465 -0
- package/src/main/TrayManager.ts +540 -0
- package/src/main/ai/AIPipelineManager.ts +199 -0
- package/src/main/ai/ClaudeAnalyzer.ts +339 -0
- package/src/main/ai/ImageOptimizer.ts +176 -0
- package/src/main/ai/StructuredMarkdownBuilder.ts +379 -0
- package/src/main/ai/index.ts +16 -0
- package/src/main/ai/types.ts +258 -0
- package/src/main/analysis/ClarificationGenerator.ts +385 -0
- package/src/main/analysis/FeedbackAnalyzer.ts +531 -0
- package/src/main/analysis/index.ts +19 -0
- package/src/main/audio/AudioCapture.ts +978 -0
- package/src/main/audio/audioUtils.ts +100 -0
- package/src/main/audio/index.ts +20 -0
- package/src/main/capture/index.ts +1 -0
- package/src/main/index.ts +1693 -0
- package/src/main/ipc/captureHandlers.ts +272 -0
- package/src/main/ipc/index.ts +45 -0
- package/src/main/ipc/outputHandlers.ts +302 -0
- package/src/main/ipc/sessionHandlers.ts +56 -0
- package/src/main/ipc/settingsHandlers.ts +471 -0
- package/src/main/ipc/types.ts +56 -0
- package/src/main/ipc/windowHandlers.ts +277 -0
- package/src/main/output/ClipboardService.ts +369 -0
- package/src/main/output/ExportService.ts +539 -0
- package/src/main/output/FileManager.ts +416 -0
- package/src/main/output/MarkdownGenerator.ts +791 -0
- package/src/main/output/MarkdownPatcher.ts +299 -0
- package/src/main/output/index.ts +186 -0
- package/src/main/output/sessionAdapter.ts +207 -0
- package/src/main/output/templates/html-template.ts +553 -0
- package/src/main/pipeline/FrameExtractor.ts +330 -0
- package/src/main/pipeline/PostProcessor.ts +399 -0
- package/src/main/pipeline/TranscriptAnalyzer.ts +226 -0
- package/src/main/pipeline/index.ts +36 -0
- package/src/main/platform/WindowsTaskbar.ts +600 -0
- package/src/main/platform/index.ts +16 -0
- package/src/main/settings/SettingsManager.ts +730 -0
- package/src/main/settings/index.ts +19 -0
- package/src/main/transcription/ModelDownloadManager.ts +494 -0
- package/src/main/transcription/TierManager.ts +219 -0
- package/src/main/transcription/TranscriptionRecoveryService.ts +340 -0
- package/src/main/transcription/WhisperService.ts +748 -0
- package/src/main/transcription/index.ts +56 -0
- package/src/main/transcription/types.ts +135 -0
- package/src/main/windows/PopoverManager.ts +284 -0
- package/src/main/windows/TaskbarIntegration.ts +452 -0
- package/src/main/windows/index.ts +23 -0
- package/src/preload/index.ts +1047 -0
- package/src/renderer/App.tsx +515 -0
- package/src/renderer/AppWrapper.tsx +28 -0
- package/src/renderer/assets/logo-dark.svg +7 -0
- package/src/renderer/assets/logo.svg +7 -0
- package/src/renderer/audio/AudioCaptureRenderer.ts +454 -0
- package/src/renderer/capture/ScreenRecordingRenderer.ts +492 -0
- package/src/renderer/components/AnnotationOverlay.tsx +836 -0
- package/src/renderer/components/AudioWaveform.tsx +811 -0
- package/src/renderer/components/ClarificationQuestions.tsx +656 -0
- package/src/renderer/components/CountdownTimer.tsx +495 -0
- package/src/renderer/components/CrashRecoveryDialog.tsx +632 -0
- package/src/renderer/components/DonateButton.tsx +127 -0
- package/src/renderer/components/ErrorBoundary.tsx +308 -0
- package/src/renderer/components/ExportDialog.tsx +872 -0
- package/src/renderer/components/HotkeyHint.tsx +261 -0
- package/src/renderer/components/KeyboardShortcuts.tsx +787 -0
- package/src/renderer/components/ModelDownloadDialog.tsx +844 -0
- package/src/renderer/components/Onboarding.tsx +1830 -0
- package/src/renderer/components/ProcessingOverlay.tsx +157 -0
- package/src/renderer/components/RecordingOverlay.tsx +423 -0
- package/src/renderer/components/SessionHistory.tsx +1746 -0
- package/src/renderer/components/SessionReview.tsx +1321 -0
- package/src/renderer/components/SettingsPanel.tsx +217 -0
- package/src/renderer/components/Skeleton.tsx +347 -0
- package/src/renderer/components/StatusIndicator.tsx +86 -0
- package/src/renderer/components/ThemeProvider.tsx +429 -0
- package/src/renderer/components/Tooltip.tsx +370 -0
- package/src/renderer/components/TranscriptionPreview.tsx +183 -0
- package/src/renderer/components/TranscriptionTierSelector.tsx +640 -0
- package/src/renderer/components/UpdateNotification.tsx +377 -0
- package/src/renderer/components/WindowSelector.tsx +947 -0
- package/src/renderer/components/index.ts +99 -0
- package/src/renderer/components/primitives/ApiKeyInput.tsx +98 -0
- package/src/renderer/components/primitives/ColorPicker.tsx +65 -0
- package/src/renderer/components/primitives/DangerButton.tsx +45 -0
- package/src/renderer/components/primitives/DirectoryPicker.tsx +41 -0
- package/src/renderer/components/primitives/Dropdown.tsx +34 -0
- package/src/renderer/components/primitives/KeyRecorder.tsx +117 -0
- package/src/renderer/components/primitives/SettingsSection.tsx +32 -0
- package/src/renderer/components/primitives/Slider.tsx +43 -0
- package/src/renderer/components/primitives/Toggle.tsx +36 -0
- package/src/renderer/components/primitives/index.ts +10 -0
- package/src/renderer/components/settings/AdvancedTab.tsx +174 -0
- package/src/renderer/components/settings/AppearanceTab.tsx +77 -0
- package/src/renderer/components/settings/GeneralTab.tsx +40 -0
- package/src/renderer/components/settings/HotkeysTab.tsx +79 -0
- package/src/renderer/components/settings/RecordingTab.tsx +84 -0
- package/src/renderer/components/settings/index.ts +9 -0
- package/src/renderer/components/settings/settingsStyles.ts +673 -0
- package/src/renderer/components/settings/tabConfig.tsx +85 -0
- package/src/renderer/components/settings/useSettingsPanel.ts +447 -0
- package/src/renderer/contexts/ProcessingContext.tsx +227 -0
- package/src/renderer/contexts/RecordingContext.tsx +683 -0
- package/src/renderer/contexts/UIContext.tsx +326 -0
- package/src/renderer/contexts/index.ts +24 -0
- package/src/renderer/donateMessages.ts +69 -0
- package/src/renderer/hooks/index.ts +75 -0
- package/src/renderer/hooks/useAnimation.tsx +544 -0
- package/src/renderer/hooks/useTheme.ts +313 -0
- package/src/renderer/index.html +26 -0
- package/src/renderer/main.tsx +52 -0
- package/src/renderer/styles/animations.css +1093 -0
- package/src/renderer/styles/app-shell.css +662 -0
- package/src/renderer/styles/globals.css +515 -0
- package/src/renderer/styles/theme.ts +578 -0
- package/src/renderer/types/electron.d.ts +385 -0
- package/src/shared/hotkeys.ts +283 -0
- package/src/shared/types.ts +809 -0
- package/tests/clipboard.test.ts +228 -0
- package/tests/e2e/criticalPaths.test.ts +594 -0
- package/tests/feedbackAnalyzer.test.ts +303 -0
- package/tests/integration/sessionFlow.test.ts +583 -0
- package/tests/markdownGenerator.test.ts +418 -0
- package/tests/output.test.ts +96 -0
- package/tests/setup.ts +486 -0
- package/tests/unit/appIntegration.test.ts +676 -0
- package/tests/unit/appViewState.test.ts +281 -0
- package/tests/unit/audioIpcChannels.test.ts +17 -0
- package/tests/unit/exportService.test.ts +492 -0
- package/tests/unit/hotkeys.test.ts +92 -0
- package/tests/unit/navigationPreload.test.ts +94 -0
- package/tests/unit/onboardingFlow.test.ts +345 -0
- package/tests/unit/permissionManager.test.ts +175 -0
- package/tests/unit/permissionManagerExpanded.test.ts +296 -0
- package/tests/unit/screenRecordingRenderer.test.ts +368 -0
- package/tests/unit/sessionController.test.ts +515 -0
- package/tests/unit/tierManager.test.ts +61 -0
- package/tests/unit/tierManagerExpanded.test.ts +142 -0
- package/tests/unit/transcriptAnalyzer.test.ts +64 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +46 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows Taskbar Integration for markupr
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Jump list with recent sessions
|
|
6
|
+
* - Taskbar progress indicator during processing
|
|
7
|
+
* - Thumbnail toolbar buttons (Record, Pause, Stop)
|
|
8
|
+
* - Windows toast notifications
|
|
9
|
+
*
|
|
10
|
+
* @module windows/TaskbarIntegration
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { app, BrowserWindow, nativeImage, Notification, shell } from 'electron';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import electronLog from 'electron-log';
|
|
16
|
+
const log = electronLog.default ?? electronLog;
|
|
17
|
+
|
|
18
|
+
// Types for Windows taskbar integration
|
|
19
|
+
interface ThumbnailToolbarButton {
|
|
20
|
+
tooltip: string;
|
|
21
|
+
icon: Electron.NativeImage;
|
|
22
|
+
click: () => void;
|
|
23
|
+
flags?: ('enabled' | 'disabled' | 'dismissonclick' | 'nobackground' | 'hidden' | 'noninteractive')[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface SessionInfo {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
path: string;
|
|
30
|
+
timestamp: Date;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type RecordingState = 'idle' | 'recording' | 'paused' | 'processing';
|
|
34
|
+
|
|
35
|
+
export class TaskbarIntegration {
|
|
36
|
+
private mainWindow: BrowserWindow | null = null;
|
|
37
|
+
private recentSessions: SessionInfo[] = [];
|
|
38
|
+
private currentState: RecordingState = 'idle';
|
|
39
|
+
private assetsPath: string;
|
|
40
|
+
|
|
41
|
+
constructor() {
|
|
42
|
+
this.assetsPath = app.isPackaged
|
|
43
|
+
? path.join(process.resourcesPath, 'assets')
|
|
44
|
+
: path.join(__dirname, '../../../assets');
|
|
45
|
+
|
|
46
|
+
log.info('[TaskbarIntegration] Initialized');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Initialize taskbar integration with the main window
|
|
51
|
+
*/
|
|
52
|
+
public initialize(mainWindow: BrowserWindow): void {
|
|
53
|
+
this.mainWindow = mainWindow;
|
|
54
|
+
|
|
55
|
+
if (process.platform !== 'win32') {
|
|
56
|
+
log.info('[TaskbarIntegration] Not on Windows, skipping initialization');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.setupJumpList();
|
|
61
|
+
this.setupThumbnailToolbar();
|
|
62
|
+
log.info('[TaskbarIntegration] Windows taskbar features enabled');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ===========================================================================
|
|
66
|
+
// Jump List Management
|
|
67
|
+
// ===========================================================================
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Set up the Windows Jump List with recent sessions and quick actions
|
|
71
|
+
*/
|
|
72
|
+
private setupJumpList(): void {
|
|
73
|
+
try {
|
|
74
|
+
app.setJumpList([
|
|
75
|
+
{
|
|
76
|
+
type: 'custom',
|
|
77
|
+
name: 'Quick Actions',
|
|
78
|
+
items: [
|
|
79
|
+
{
|
|
80
|
+
type: 'task',
|
|
81
|
+
title: 'New Recording',
|
|
82
|
+
description: 'Start a new feedback recording session',
|
|
83
|
+
program: process.execPath,
|
|
84
|
+
args: '--new-recording',
|
|
85
|
+
iconPath: process.execPath,
|
|
86
|
+
iconIndex: 0
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
type: 'task',
|
|
90
|
+
title: 'Quick Screenshot',
|
|
91
|
+
description: 'Take a quick annotated screenshot',
|
|
92
|
+
program: process.execPath,
|
|
93
|
+
args: '--quick-screenshot',
|
|
94
|
+
iconPath: process.execPath,
|
|
95
|
+
iconIndex: 0
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
type: 'recent'
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
type: 'tasks',
|
|
104
|
+
items: [
|
|
105
|
+
{
|
|
106
|
+
type: 'task',
|
|
107
|
+
title: 'Open Settings',
|
|
108
|
+
description: 'Configure markupr settings',
|
|
109
|
+
program: process.execPath,
|
|
110
|
+
args: '--settings',
|
|
111
|
+
iconPath: process.execPath,
|
|
112
|
+
iconIndex: 0
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
]);
|
|
117
|
+
log.info('[TaskbarIntegration] Jump list configured');
|
|
118
|
+
} catch (error) {
|
|
119
|
+
log.error('[TaskbarIntegration] Failed to set jump list:', error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Update recent sessions in the jump list
|
|
125
|
+
*/
|
|
126
|
+
public updateRecentSessions(sessions: SessionInfo[]): void {
|
|
127
|
+
this.recentSessions = sessions.slice(0, 10); // Keep last 10
|
|
128
|
+
|
|
129
|
+
if (process.platform !== 'win32') return;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
// Add sessions to Windows recent documents
|
|
133
|
+
for (const session of this.recentSessions) {
|
|
134
|
+
app.addRecentDocument(session.path);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Rebuild jump list with updated recent sessions
|
|
138
|
+
this.setupJumpList();
|
|
139
|
+
log.info(`[TaskbarIntegration] Updated ${sessions.length} recent sessions`);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
log.error('[TaskbarIntegration] Failed to update recent sessions:', error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Clear recent sessions from jump list
|
|
147
|
+
*/
|
|
148
|
+
public clearRecentSessions(): void {
|
|
149
|
+
this.recentSessions = [];
|
|
150
|
+
|
|
151
|
+
if (process.platform === 'win32') {
|
|
152
|
+
app.clearRecentDocuments();
|
|
153
|
+
this.setupJumpList();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ===========================================================================
|
|
158
|
+
// Taskbar Progress Indicator
|
|
159
|
+
// ===========================================================================
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Set taskbar progress bar (0-1 range, or -1 for indeterminate)
|
|
163
|
+
*/
|
|
164
|
+
public setProgress(progress: number): void {
|
|
165
|
+
if (!this.mainWindow || process.platform !== 'win32') return;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
if (progress < 0) {
|
|
169
|
+
// Indeterminate progress
|
|
170
|
+
this.mainWindow.setProgressBar(2, { mode: 'indeterminate' });
|
|
171
|
+
} else if (progress >= 1) {
|
|
172
|
+
// Complete - briefly show green, then hide
|
|
173
|
+
this.mainWindow.setProgressBar(1, { mode: 'normal' });
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
this.mainWindow?.setProgressBar(-1); // Hide
|
|
176
|
+
}, 2000);
|
|
177
|
+
} else {
|
|
178
|
+
// Normal progress
|
|
179
|
+
this.mainWindow.setProgressBar(progress, { mode: 'normal' });
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
log.error('[TaskbarIntegration] Failed to set progress:', error);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Show error state in taskbar progress
|
|
188
|
+
*/
|
|
189
|
+
public setProgressError(): void {
|
|
190
|
+
if (!this.mainWindow || process.platform !== 'win32') return;
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
this.mainWindow.setProgressBar(1, { mode: 'error' });
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
this.mainWindow?.setProgressBar(-1);
|
|
196
|
+
}, 5000);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
log.error('[TaskbarIntegration] Failed to set error progress:', error);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Clear taskbar progress
|
|
204
|
+
*/
|
|
205
|
+
public clearProgress(): void {
|
|
206
|
+
if (!this.mainWindow || process.platform !== 'win32') return;
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
this.mainWindow.setProgressBar(-1);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
log.error('[TaskbarIntegration] Failed to clear progress:', error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ===========================================================================
|
|
216
|
+
// Thumbnail Toolbar (Recording Controls)
|
|
217
|
+
// ===========================================================================
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Set up thumbnail toolbar with recording controls
|
|
221
|
+
*/
|
|
222
|
+
private setupThumbnailToolbar(): void {
|
|
223
|
+
if (!this.mainWindow) return;
|
|
224
|
+
|
|
225
|
+
this.updateThumbnailToolbar('idle');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Update thumbnail toolbar based on recording state
|
|
230
|
+
*/
|
|
231
|
+
public updateThumbnailToolbar(state: RecordingState): void {
|
|
232
|
+
if (!this.mainWindow || process.platform !== 'win32') return;
|
|
233
|
+
|
|
234
|
+
this.currentState = state;
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const buttons = this.getToolbarButtons(state);
|
|
238
|
+
this.mainWindow.setThumbarButtons(buttons);
|
|
239
|
+
log.debug(`[TaskbarIntegration] Toolbar updated for state: ${state}`);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
log.error('[TaskbarIntegration] Failed to update toolbar:', error);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get toolbar buttons for current state
|
|
247
|
+
*/
|
|
248
|
+
private getToolbarButtons(state: RecordingState): ThumbnailToolbarButton[] {
|
|
249
|
+
const recordIcon = this.loadIcon('tray-recording.png');
|
|
250
|
+
const pauseIcon = this.loadIcon('tray-idle.png');
|
|
251
|
+
const stopIcon = this.loadIcon('tray-error.png');
|
|
252
|
+
const processingIcon = this.loadIcon('tray-processing.png');
|
|
253
|
+
|
|
254
|
+
switch (state) {
|
|
255
|
+
case 'idle':
|
|
256
|
+
return [
|
|
257
|
+
{
|
|
258
|
+
tooltip: 'Start Recording',
|
|
259
|
+
icon: recordIcon,
|
|
260
|
+
click: () => this.emitAction('start-recording'),
|
|
261
|
+
flags: ['enabled']
|
|
262
|
+
}
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
case 'recording':
|
|
266
|
+
return [
|
|
267
|
+
{
|
|
268
|
+
tooltip: 'Pause Recording',
|
|
269
|
+
icon: pauseIcon,
|
|
270
|
+
click: () => this.emitAction('pause-recording'),
|
|
271
|
+
flags: ['enabled']
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
tooltip: 'Stop Recording',
|
|
275
|
+
icon: stopIcon,
|
|
276
|
+
click: () => this.emitAction('stop-recording'),
|
|
277
|
+
flags: ['enabled']
|
|
278
|
+
}
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
case 'paused':
|
|
282
|
+
return [
|
|
283
|
+
{
|
|
284
|
+
tooltip: 'Resume Recording',
|
|
285
|
+
icon: recordIcon,
|
|
286
|
+
click: () => this.emitAction('resume-recording'),
|
|
287
|
+
flags: ['enabled']
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
tooltip: 'Stop Recording',
|
|
291
|
+
icon: stopIcon,
|
|
292
|
+
click: () => this.emitAction('stop-recording'),
|
|
293
|
+
flags: ['enabled']
|
|
294
|
+
}
|
|
295
|
+
];
|
|
296
|
+
|
|
297
|
+
case 'processing':
|
|
298
|
+
return [
|
|
299
|
+
{
|
|
300
|
+
tooltip: 'Processing...',
|
|
301
|
+
icon: processingIcon,
|
|
302
|
+
click: () => {},
|
|
303
|
+
flags: ['disabled', 'nobackground']
|
|
304
|
+
}
|
|
305
|
+
];
|
|
306
|
+
|
|
307
|
+
default:
|
|
308
|
+
return [];
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Load icon from assets
|
|
314
|
+
*/
|
|
315
|
+
private loadIcon(filename: string): Electron.NativeImage {
|
|
316
|
+
try {
|
|
317
|
+
const iconPath = path.join(this.assetsPath, filename);
|
|
318
|
+
return nativeImage.createFromPath(iconPath);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
log.error(`[TaskbarIntegration] Failed to load icon ${filename}:`, error);
|
|
321
|
+
return nativeImage.createEmpty();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Emit action to main window
|
|
327
|
+
*/
|
|
328
|
+
private emitAction(action: string): void {
|
|
329
|
+
if (!this.mainWindow) return;
|
|
330
|
+
this.mainWindow.webContents.send('taskbar-action', action);
|
|
331
|
+
log.info(`[TaskbarIntegration] Action emitted: ${action}`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ===========================================================================
|
|
335
|
+
// Windows Toast Notifications
|
|
336
|
+
// ===========================================================================
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Show a Windows toast notification
|
|
340
|
+
*/
|
|
341
|
+
public showNotification(options: {
|
|
342
|
+
title: string;
|
|
343
|
+
body: string;
|
|
344
|
+
silent?: boolean;
|
|
345
|
+
urgency?: 'normal' | 'critical' | 'low';
|
|
346
|
+
actions?: { type: 'button'; text: string; }[];
|
|
347
|
+
onClick?: () => void;
|
|
348
|
+
}): void {
|
|
349
|
+
if (!Notification.isSupported()) {
|
|
350
|
+
log.warn('[TaskbarIntegration] Notifications not supported');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
const notification = new Notification({
|
|
356
|
+
title: options.title,
|
|
357
|
+
body: options.body,
|
|
358
|
+
silent: options.silent ?? false,
|
|
359
|
+
urgency: options.urgency ?? 'normal',
|
|
360
|
+
icon: path.join(this.assetsPath, 'tray-idle.png'),
|
|
361
|
+
timeoutType: options.urgency === 'critical' ? 'never' : 'default'
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
if (options.onClick) {
|
|
365
|
+
notification.on('click', options.onClick);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
notification.show();
|
|
369
|
+
log.debug(`[TaskbarIntegration] Notification shown: ${options.title}`);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
log.error('[TaskbarIntegration] Failed to show notification:', error);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Show recording started notification
|
|
377
|
+
*/
|
|
378
|
+
public notifyRecordingStarted(): void {
|
|
379
|
+
this.showNotification({
|
|
380
|
+
title: 'Recording Started',
|
|
381
|
+
body: 'markupr is now capturing your feedback',
|
|
382
|
+
silent: true,
|
|
383
|
+
urgency: 'low'
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Show recording completed notification
|
|
389
|
+
*/
|
|
390
|
+
public notifyRecordingComplete(sessionName: string, outputPath: string): void {
|
|
391
|
+
this.showNotification({
|
|
392
|
+
title: 'Recording Complete',
|
|
393
|
+
body: `Session "${sessionName}" saved successfully`,
|
|
394
|
+
onClick: () => {
|
|
395
|
+
// Open the output folder
|
|
396
|
+
shell.showItemInFolder(outputPath);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Show export progress notification
|
|
403
|
+
*/
|
|
404
|
+
public notifyExportProgress(format: string): void {
|
|
405
|
+
this.showNotification({
|
|
406
|
+
title: 'Exporting...',
|
|
407
|
+
body: `Exporting session to ${format} format`,
|
|
408
|
+
silent: true,
|
|
409
|
+
urgency: 'low'
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Show export complete notification
|
|
415
|
+
*/
|
|
416
|
+
public notifyExportComplete(outputPath: string): void {
|
|
417
|
+
this.showNotification({
|
|
418
|
+
title: 'Export Complete',
|
|
419
|
+
body: 'Your feedback session has been exported',
|
|
420
|
+
onClick: () => {
|
|
421
|
+
shell.showItemInFolder(outputPath);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Show error notification
|
|
428
|
+
*/
|
|
429
|
+
public notifyError(title: string, message: string): void {
|
|
430
|
+
this.showNotification({
|
|
431
|
+
title,
|
|
432
|
+
body: message,
|
|
433
|
+
urgency: 'critical'
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ===========================================================================
|
|
438
|
+
// Cleanup
|
|
439
|
+
// ===========================================================================
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Clean up resources
|
|
443
|
+
*/
|
|
444
|
+
public destroy(): void {
|
|
445
|
+
this.mainWindow = null;
|
|
446
|
+
this.recentSessions = [];
|
|
447
|
+
log.info('[TaskbarIntegration] Destroyed');
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Export singleton instance
|
|
452
|
+
export const taskbarIntegration = new TaskbarIntegration();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window management for markupr
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - PopoverManager: NSPopover-like menu bar window
|
|
6
|
+
* - TaskbarIntegration: Jump lists, progress bar, thumbnail toolbar (Windows)
|
|
7
|
+
*
|
|
8
|
+
* @module windows
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
PopoverManager,
|
|
13
|
+
POPOVER_SIZES,
|
|
14
|
+
type PopoverConfig,
|
|
15
|
+
type PopoverState
|
|
16
|
+
} from './PopoverManager';
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
TaskbarIntegration,
|
|
20
|
+
taskbarIntegration,
|
|
21
|
+
type SessionInfo,
|
|
22
|
+
type RecordingState
|
|
23
|
+
} from './TaskbarIntegration';
|