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,174 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AppSettings } from '../../../shared/types';
|
|
3
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
4
|
+
import { SettingsSection, ToggleSetting, ApiKeyInput, DangerButton } from '../primitives';
|
|
5
|
+
import type { ApiKeyState } from '../primitives';
|
|
6
|
+
import { styles } from './settingsStyles';
|
|
7
|
+
|
|
8
|
+
export const AdvancedTab: React.FC<{
|
|
9
|
+
settings: AppSettings;
|
|
10
|
+
openAiApiKey: ApiKeyState;
|
|
11
|
+
anthropicApiKey: ApiKeyState;
|
|
12
|
+
onSettingChange: <K extends keyof AppSettings>(key: K, value: AppSettings[K]) => void;
|
|
13
|
+
onOpenAiApiKeyChange: (value: string) => void;
|
|
14
|
+
onToggleOpenAiApiKeyVisibility: () => void;
|
|
15
|
+
onTestOpenAiApiKey: () => void;
|
|
16
|
+
onAnthropicApiKeyChange: (value: string) => void;
|
|
17
|
+
onToggleAnthropicApiKeyVisibility: () => void;
|
|
18
|
+
onTestAnthropicApiKey: () => void;
|
|
19
|
+
onClearAllData: () => void;
|
|
20
|
+
onExportSettings: () => void;
|
|
21
|
+
onImportSettings: () => void;
|
|
22
|
+
onResetSection: () => void;
|
|
23
|
+
}> = ({
|
|
24
|
+
settings,
|
|
25
|
+
openAiApiKey,
|
|
26
|
+
anthropicApiKey,
|
|
27
|
+
onSettingChange,
|
|
28
|
+
onOpenAiApiKeyChange,
|
|
29
|
+
onToggleOpenAiApiKeyVisibility,
|
|
30
|
+
onTestOpenAiApiKey,
|
|
31
|
+
onAnthropicApiKeyChange,
|
|
32
|
+
onToggleAnthropicApiKeyVisibility,
|
|
33
|
+
onTestAnthropicApiKey,
|
|
34
|
+
onClearAllData,
|
|
35
|
+
onExportSettings,
|
|
36
|
+
onImportSettings,
|
|
37
|
+
onResetSection,
|
|
38
|
+
}) => {
|
|
39
|
+
const { colors } = useTheme();
|
|
40
|
+
return (
|
|
41
|
+
<div style={styles.tabContent}>
|
|
42
|
+
{/* Transcription workflow */}
|
|
43
|
+
<SettingsSection
|
|
44
|
+
title="Transcription Workflow"
|
|
45
|
+
description="Simple and reliable capture pipeline"
|
|
46
|
+
onReset={onResetSection}
|
|
47
|
+
>
|
|
48
|
+
<div style={styles.settingDescription}>
|
|
49
|
+
markupr records screen + microphone first, then runs transcription after you stop.
|
|
50
|
+
OpenAI is the primary cloud path. Local Whisper is optional fallback when available.
|
|
51
|
+
</div>
|
|
52
|
+
</SettingsSection>
|
|
53
|
+
|
|
54
|
+
<SettingsSection
|
|
55
|
+
title="BYOK Mode"
|
|
56
|
+
description="This open-source build uses your own keys for both transcription and AI analysis."
|
|
57
|
+
>
|
|
58
|
+
<div style={styles.settingDescription}>
|
|
59
|
+
Set both the OpenAI key (transcription) and Anthropic key (analysis) below for full end-to-end reports.
|
|
60
|
+
</div>
|
|
61
|
+
</SettingsSection>
|
|
62
|
+
|
|
63
|
+
{/* OpenAI API Key (BYOK primary transcription fallback) */}
|
|
64
|
+
<SettingsSection
|
|
65
|
+
title="OpenAI API Key"
|
|
66
|
+
description="Required for BYOK post-session transcription"
|
|
67
|
+
>
|
|
68
|
+
<div style={styles.serviceInfo}>
|
|
69
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
70
|
+
<path
|
|
71
|
+
d="M12 3l2.4 1.4 2.8-.3 1.2 2.6 2.3 1.6-.8 2.7.8 2.7-2.3 1.6-1.2 2.6-2.8-.3L12 21l-2.4-1.4-2.8.3-1.2-2.6-2.3-1.6.8-2.7-.8-2.7 2.3-1.6 1.2-2.6 2.8.3L12 3z"
|
|
72
|
+
stroke={colors.status.success}
|
|
73
|
+
strokeWidth="1.5"
|
|
74
|
+
strokeLinecap="round"
|
|
75
|
+
strokeLinejoin="round"
|
|
76
|
+
/>
|
|
77
|
+
<path d="M9.5 12h5M12 9.5v5" stroke={colors.status.success} strokeWidth="1.5" strokeLinecap="round" />
|
|
78
|
+
</svg>
|
|
79
|
+
<div>
|
|
80
|
+
<span style={styles.serviceName}>OpenAI Audio Transcription</span>
|
|
81
|
+
<span style={styles.serviceDescription}>
|
|
82
|
+
Used for reliable post-session narration transcription when local models are unavailable.
|
|
83
|
+
</span>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
<ApiKeyInput
|
|
87
|
+
label="API Key"
|
|
88
|
+
description="Required for BYOK transcription"
|
|
89
|
+
serviceName="OpenAI"
|
|
90
|
+
apiKey={openAiApiKey}
|
|
91
|
+
onApiKeyChange={onOpenAiApiKeyChange}
|
|
92
|
+
onToggleVisibility={onToggleOpenAiApiKeyVisibility}
|
|
93
|
+
onTest={onTestOpenAiApiKey}
|
|
94
|
+
/>
|
|
95
|
+
</SettingsSection>
|
|
96
|
+
|
|
97
|
+
{/* Anthropic API Key (BYOK AI analysis) */}
|
|
98
|
+
<SettingsSection
|
|
99
|
+
title="Anthropic API Key"
|
|
100
|
+
description="Required for BYOK AI analysis in this version"
|
|
101
|
+
>
|
|
102
|
+
<div style={styles.serviceInfo}>
|
|
103
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
104
|
+
<path
|
|
105
|
+
d="M4 20L10.5 4h3L20 20h-3.5l-1.3-3.3H8.8L7.5 20H4zM9.9 13.9h4.2L12 8.4l-2.1 5.5z"
|
|
106
|
+
fill={colors.status.warning}
|
|
107
|
+
/>
|
|
108
|
+
</svg>
|
|
109
|
+
<div>
|
|
110
|
+
<span style={styles.serviceName}>Anthropic Analysis</span>
|
|
111
|
+
<span style={styles.serviceDescription}>
|
|
112
|
+
Used to generate structured, agent-ready markdown insights from your capture session.
|
|
113
|
+
</span>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
<ApiKeyInput
|
|
117
|
+
label="API Key"
|
|
118
|
+
description="Required for BYOK AI analysis"
|
|
119
|
+
serviceName="Anthropic"
|
|
120
|
+
apiKey={anthropicApiKey}
|
|
121
|
+
onApiKeyChange={onAnthropicApiKeyChange}
|
|
122
|
+
onToggleVisibility={onToggleAnthropicApiKeyVisibility}
|
|
123
|
+
onTest={onTestAnthropicApiKey}
|
|
124
|
+
/>
|
|
125
|
+
</SettingsSection>
|
|
126
|
+
|
|
127
|
+
<SettingsSection title="Debug & Backup">
|
|
128
|
+
<ToggleSetting
|
|
129
|
+
label="Debug Mode"
|
|
130
|
+
description="Enable verbose logging for troubleshooting"
|
|
131
|
+
value={settings.debugMode}
|
|
132
|
+
onChange={(value) => onSettingChange('debugMode', value)}
|
|
133
|
+
/>
|
|
134
|
+
<ToggleSetting
|
|
135
|
+
label="Keep Audio Backups"
|
|
136
|
+
description="Save audio recordings alongside transcriptions"
|
|
137
|
+
value={settings.keepAudioBackups}
|
|
138
|
+
onChange={(value) => onSettingChange('keepAudioBackups', value)}
|
|
139
|
+
/>
|
|
140
|
+
</SettingsSection>
|
|
141
|
+
|
|
142
|
+
<SettingsSection title="Settings Management">
|
|
143
|
+
<div style={styles.settingRow}>
|
|
144
|
+
<div style={styles.settingInfo}>
|
|
145
|
+
<span style={styles.settingLabel}>Export Settings</span>
|
|
146
|
+
<span style={styles.settingDescription}>Save your settings to a file</span>
|
|
147
|
+
</div>
|
|
148
|
+
<button style={styles.secondaryButton} onClick={onExportSettings}>
|
|
149
|
+
Export
|
|
150
|
+
</button>
|
|
151
|
+
</div>
|
|
152
|
+
<div style={styles.settingRow}>
|
|
153
|
+
<div style={styles.settingInfo}>
|
|
154
|
+
<span style={styles.settingLabel}>Import Settings</span>
|
|
155
|
+
<span style={styles.settingDescription}>Load settings from a file</span>
|
|
156
|
+
</div>
|
|
157
|
+
<button style={styles.secondaryButton} onClick={onImportSettings}>
|
|
158
|
+
Import
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
</SettingsSection>
|
|
162
|
+
|
|
163
|
+
<SettingsSection title="Danger Zone">
|
|
164
|
+
<DangerButton
|
|
165
|
+
label="Clear All Data"
|
|
166
|
+
description="Delete all sessions, screenshots, and reset settings"
|
|
167
|
+
buttonText="Clear All Data"
|
|
168
|
+
confirmText="Click to confirm deletion"
|
|
169
|
+
onConfirm={onClearAllData}
|
|
170
|
+
/>
|
|
171
|
+
</SettingsSection>
|
|
172
|
+
</div>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AppSettings } from '../../../shared/types';
|
|
3
|
+
// useTheme available for future theme-aware styling
|
|
4
|
+
import { darkTheme, lightTheme } from '../../styles/theme';
|
|
5
|
+
import { SettingsSection, DropdownSetting, ColorPicker } from '../primitives';
|
|
6
|
+
import { styles } from './settingsStyles';
|
|
7
|
+
|
|
8
|
+
export const AppearanceTab: React.FC<{
|
|
9
|
+
settings: AppSettings;
|
|
10
|
+
onSettingChange: <K extends keyof AppSettings>(key: K, value: AppSettings[K]) => void;
|
|
11
|
+
onResetSection: () => void;
|
|
12
|
+
}> = ({ settings, onSettingChange, onResetSection }) => {
|
|
13
|
+
const previewColors = settings.theme === 'light' ? lightTheme : darkTheme;
|
|
14
|
+
return (
|
|
15
|
+
<div style={styles.tabContent}>
|
|
16
|
+
<SettingsSection
|
|
17
|
+
title="Theme"
|
|
18
|
+
description="Choose how markupr looks"
|
|
19
|
+
onReset={onResetSection}
|
|
20
|
+
>
|
|
21
|
+
<DropdownSetting
|
|
22
|
+
label="Theme Mode"
|
|
23
|
+
description="Match your system or choose a specific theme"
|
|
24
|
+
value={settings.theme}
|
|
25
|
+
options={[
|
|
26
|
+
{ value: 'system', label: 'System' },
|
|
27
|
+
{ value: 'dark', label: 'Dark' },
|
|
28
|
+
{ value: 'light', label: 'Light' },
|
|
29
|
+
]}
|
|
30
|
+
onChange={(value) => onSettingChange('theme', value as 'system' | 'dark' | 'light')}
|
|
31
|
+
/>
|
|
32
|
+
</SettingsSection>
|
|
33
|
+
|
|
34
|
+
<SettingsSection title="Accent Color">
|
|
35
|
+
<ColorPicker
|
|
36
|
+
label="Accent Color"
|
|
37
|
+
description="Used for buttons, links, and highlights"
|
|
38
|
+
value={settings.accentColor}
|
|
39
|
+
onChange={(value) => onSettingChange('accentColor', value)}
|
|
40
|
+
/>
|
|
41
|
+
</SettingsSection>
|
|
42
|
+
|
|
43
|
+
{/* Live Preview */}
|
|
44
|
+
<SettingsSection title="Preview">
|
|
45
|
+
<div style={styles.themePreview}>
|
|
46
|
+
<div
|
|
47
|
+
style={{
|
|
48
|
+
...styles.previewCard,
|
|
49
|
+
backgroundColor: previewColors.bg.primary,
|
|
50
|
+
borderColor: previewColors.border.default,
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<div style={styles.previewHeader}>
|
|
54
|
+
<div style={{ ...styles.previewDot, backgroundColor: settings.accentColor }} />
|
|
55
|
+
<span
|
|
56
|
+
style={{
|
|
57
|
+
...styles.previewTitle,
|
|
58
|
+
color: previewColors.text.primary,
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
Recording Session
|
|
62
|
+
</span>
|
|
63
|
+
</div>
|
|
64
|
+
<button
|
|
65
|
+
style={{
|
|
66
|
+
...styles.previewButton,
|
|
67
|
+
backgroundColor: settings.accentColor,
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
Start Recording
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</SettingsSection>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AppSettings } from '../../../shared/types';
|
|
3
|
+
import { SettingsSection, ToggleSetting, DirectoryPicker } from '../primitives';
|
|
4
|
+
import { styles } from './settingsStyles';
|
|
5
|
+
|
|
6
|
+
export const GeneralTab: React.FC<{
|
|
7
|
+
settings: AppSettings;
|
|
8
|
+
onSettingChange: <K extends keyof AppSettings>(key: K, value: AppSettings[K]) => void;
|
|
9
|
+
onResetSection: () => void;
|
|
10
|
+
}> = ({ settings, onSettingChange, onResetSection }) => (
|
|
11
|
+
<div style={styles.tabContent}>
|
|
12
|
+
<SettingsSection
|
|
13
|
+
title="Output"
|
|
14
|
+
description="Where your feedback sessions are saved"
|
|
15
|
+
onReset={onResetSection}
|
|
16
|
+
>
|
|
17
|
+
<DirectoryPicker
|
|
18
|
+
label="Output Directory"
|
|
19
|
+
description="Screenshots and markdown files will be saved here"
|
|
20
|
+
value={settings.outputDirectory}
|
|
21
|
+
onChange={(value) => onSettingChange('outputDirectory', value)}
|
|
22
|
+
/>
|
|
23
|
+
</SettingsSection>
|
|
24
|
+
|
|
25
|
+
<SettingsSection title="Startup">
|
|
26
|
+
<ToggleSetting
|
|
27
|
+
label="Launch at Login"
|
|
28
|
+
description="Start markupr automatically when you log in"
|
|
29
|
+
value={settings.launchAtLogin}
|
|
30
|
+
onChange={(value) => onSettingChange('launchAtLogin', value)}
|
|
31
|
+
/>
|
|
32
|
+
<ToggleSetting
|
|
33
|
+
label="Check for Updates"
|
|
34
|
+
description="Automatically check on launch and while the app is running"
|
|
35
|
+
value={settings.checkForUpdates}
|
|
36
|
+
onChange={(value) => onSettingChange('checkForUpdates', value)}
|
|
37
|
+
/>
|
|
38
|
+
</SettingsSection>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import type { AppSettings, HotkeyConfig } from '../../../shared/types';
|
|
3
|
+
import { SettingsSection, KeyRecorder } from '../primitives';
|
|
4
|
+
import { HotkeyHint } from '../HotkeyHint';
|
|
5
|
+
import { styles } from './settingsStyles';
|
|
6
|
+
|
|
7
|
+
export const HotkeysTab: React.FC<{
|
|
8
|
+
settings: AppSettings;
|
|
9
|
+
onHotkeyChange: (key: keyof HotkeyConfig, value: string) => void;
|
|
10
|
+
onResetSection: () => void;
|
|
11
|
+
}> = ({ settings, onHotkeyChange, onResetSection }) => {
|
|
12
|
+
// Detect conflicts
|
|
13
|
+
const findConflict = useCallback(
|
|
14
|
+
(currentKey: keyof HotkeyConfig, value: string): string | null => {
|
|
15
|
+
const entries = Object.entries(settings.hotkeys) as [keyof HotkeyConfig, string][];
|
|
16
|
+
for (const [key, hotkey] of entries) {
|
|
17
|
+
if (key !== currentKey && hotkey === value) {
|
|
18
|
+
const labels: Record<keyof HotkeyConfig, string> = {
|
|
19
|
+
toggleRecording: 'Start/Stop Recording',
|
|
20
|
+
manualScreenshot: 'Manual Screenshot',
|
|
21
|
+
pauseResume: 'Pause/Resume',
|
|
22
|
+
};
|
|
23
|
+
return labels[key];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
},
|
|
28
|
+
[settings.hotkeys]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div style={styles.tabContent}>
|
|
33
|
+
<SettingsSection
|
|
34
|
+
title="Keyboard Shortcuts"
|
|
35
|
+
description="Customize global hotkeys for markupr"
|
|
36
|
+
onReset={onResetSection}
|
|
37
|
+
>
|
|
38
|
+
<KeyRecorder
|
|
39
|
+
label="Start/Stop Recording"
|
|
40
|
+
description="Toggle recording on and off"
|
|
41
|
+
value={settings.hotkeys.toggleRecording}
|
|
42
|
+
onChange={(value) => onHotkeyChange('toggleRecording', value)}
|
|
43
|
+
conflict={findConflict('toggleRecording', settings.hotkeys.toggleRecording)}
|
|
44
|
+
/>
|
|
45
|
+
<KeyRecorder
|
|
46
|
+
label="Manual Screenshot"
|
|
47
|
+
description="Capture a screenshot immediately"
|
|
48
|
+
value={settings.hotkeys.manualScreenshot}
|
|
49
|
+
onChange={(value) => onHotkeyChange('manualScreenshot', value)}
|
|
50
|
+
conflict={findConflict('manualScreenshot', settings.hotkeys.manualScreenshot)}
|
|
51
|
+
/>
|
|
52
|
+
<KeyRecorder
|
|
53
|
+
label="Pause/Resume"
|
|
54
|
+
description="Temporarily pause active capture"
|
|
55
|
+
value={settings.hotkeys.pauseResume}
|
|
56
|
+
onChange={(value) => onHotkeyChange('pauseResume', value)}
|
|
57
|
+
conflict={findConflict('pauseResume', settings.hotkeys.pauseResume)}
|
|
58
|
+
/>
|
|
59
|
+
</SettingsSection>
|
|
60
|
+
|
|
61
|
+
<SettingsSection title="Quick Reference">
|
|
62
|
+
<div style={styles.hotkeyReference}>
|
|
63
|
+
<div style={styles.hotkeyRefItem}>
|
|
64
|
+
<span style={styles.hotkeyRefLabel}>Start/Stop Recording</span>
|
|
65
|
+
<HotkeyHint keys={settings.hotkeys.toggleRecording} size="medium" />
|
|
66
|
+
</div>
|
|
67
|
+
<div style={styles.hotkeyRefItem}>
|
|
68
|
+
<span style={styles.hotkeyRefLabel}>Manual Screenshot</span>
|
|
69
|
+
<HotkeyHint keys={settings.hotkeys.manualScreenshot} size="medium" />
|
|
70
|
+
</div>
|
|
71
|
+
<div style={styles.hotkeyRefItem}>
|
|
72
|
+
<span style={styles.hotkeyRefLabel}>Pause/Resume</span>
|
|
73
|
+
<HotkeyHint keys={settings.hotkeys.pauseResume} size="medium" />
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</SettingsSection>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AppSettings, AudioDevice } from '../../../shared/types';
|
|
3
|
+
import { SettingsSection, ToggleSetting, DropdownSetting, SliderSetting } from '../primitives';
|
|
4
|
+
import { styles } from './settingsStyles';
|
|
5
|
+
|
|
6
|
+
export const RecordingTab: React.FC<{
|
|
7
|
+
settings: AppSettings;
|
|
8
|
+
audioDevices: AudioDevice[];
|
|
9
|
+
onSettingChange: <K extends keyof AppSettings>(key: K, value: AppSettings[K]) => void;
|
|
10
|
+
onResetSection: () => void;
|
|
11
|
+
}> = ({ settings, audioDevices, onSettingChange, onResetSection }) => (
|
|
12
|
+
<div style={styles.tabContent}>
|
|
13
|
+
<SettingsSection
|
|
14
|
+
title="Recording Behavior"
|
|
15
|
+
description="Customize how recording sessions work"
|
|
16
|
+
onReset={onResetSection}
|
|
17
|
+
>
|
|
18
|
+
<DropdownSetting
|
|
19
|
+
label="Countdown Before Recording"
|
|
20
|
+
description="Give yourself time to prepare"
|
|
21
|
+
value={settings.defaultCountdown}
|
|
22
|
+
options={[
|
|
23
|
+
{ value: 0, label: 'No countdown' },
|
|
24
|
+
{ value: 3, label: '3 seconds' },
|
|
25
|
+
{ value: 5, label: '5 seconds' },
|
|
26
|
+
]}
|
|
27
|
+
onChange={(value) => onSettingChange('defaultCountdown', Number(value) as 0 | 3 | 5)}
|
|
28
|
+
/>
|
|
29
|
+
<ToggleSetting
|
|
30
|
+
label="Show Recording HUD"
|
|
31
|
+
description="Display mic activity and shortcut hints while recording"
|
|
32
|
+
value={settings.showTranscriptionPreview}
|
|
33
|
+
onChange={(value) => onSettingChange('showTranscriptionPreview', value)}
|
|
34
|
+
/>
|
|
35
|
+
<ToggleSetting
|
|
36
|
+
label="Show Audio Waveform"
|
|
37
|
+
description="Visual feedback of your voice levels"
|
|
38
|
+
value={settings.showAudioWaveform}
|
|
39
|
+
onChange={(value) => onSettingChange('showAudioWaveform', value)}
|
|
40
|
+
/>
|
|
41
|
+
</SettingsSection>
|
|
42
|
+
|
|
43
|
+
<SettingsSection title="Audio Input">
|
|
44
|
+
<DropdownSetting
|
|
45
|
+
label="Microphone"
|
|
46
|
+
description="Select which microphone to use for voice capture"
|
|
47
|
+
value={settings.audioDeviceId || 'default'}
|
|
48
|
+
options={[
|
|
49
|
+
{ value: 'default', label: 'System Default' },
|
|
50
|
+
...audioDevices.map((device) => ({
|
|
51
|
+
value: device.id,
|
|
52
|
+
label: device.name + (device.isDefault ? ' (Default)' : ''),
|
|
53
|
+
})),
|
|
54
|
+
]}
|
|
55
|
+
onChange={(value) => onSettingChange('audioDeviceId', value === 'default' ? null : String(value))}
|
|
56
|
+
/>
|
|
57
|
+
</SettingsSection>
|
|
58
|
+
|
|
59
|
+
<SettingsSection title="Screenshot Timing">
|
|
60
|
+
<SliderSetting
|
|
61
|
+
label="Pause Threshold"
|
|
62
|
+
description="How long to pause before capturing a screenshot"
|
|
63
|
+
value={settings.pauseThreshold}
|
|
64
|
+
min={500}
|
|
65
|
+
max={3000}
|
|
66
|
+
step={100}
|
|
67
|
+
unit="ms"
|
|
68
|
+
formatValue={(v) => `${(v / 1000).toFixed(1)}s`}
|
|
69
|
+
onChange={(value) => onSettingChange('pauseThreshold', value)}
|
|
70
|
+
/>
|
|
71
|
+
<SliderSetting
|
|
72
|
+
label="Minimum Time Between Captures"
|
|
73
|
+
description="Prevent too many screenshots in quick succession"
|
|
74
|
+
value={settings.minTimeBetweenCaptures}
|
|
75
|
+
min={300}
|
|
76
|
+
max={2000}
|
|
77
|
+
step={100}
|
|
78
|
+
unit="ms"
|
|
79
|
+
formatValue={(v) => `${(v / 1000).toFixed(1)}s`}
|
|
80
|
+
onChange={(value) => onSettingChange('minTimeBetweenCaptures', value)}
|
|
81
|
+
/>
|
|
82
|
+
</SettingsSection>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { GeneralTab } from './GeneralTab';
|
|
2
|
+
export { RecordingTab } from './RecordingTab';
|
|
3
|
+
export { AppearanceTab } from './AppearanceTab';
|
|
4
|
+
export { HotkeysTab } from './HotkeysTab';
|
|
5
|
+
export { AdvancedTab } from './AdvancedTab';
|
|
6
|
+
export { TABS } from './tabConfig';
|
|
7
|
+
export type { SettingsTab } from './tabConfig';
|
|
8
|
+
export { styles as settingsStyles } from './settingsStyles';
|
|
9
|
+
export { useSettingsPanel } from './useSettingsPanel';
|