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,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* markupr - Update Notification Component
|
|
3
|
+
*
|
|
4
|
+
* Shows update status notifications to the user with:
|
|
5
|
+
* - Update available banner with release notes
|
|
6
|
+
* - Download progress indicator
|
|
7
|
+
* - Ready to install prompt
|
|
8
|
+
*
|
|
9
|
+
* User controls when to download and when to restart.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
13
|
+
import type { UpdateStatusPayload, UpdateStatusType } from '../../shared/types';
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
interface UpdateState {
|
|
20
|
+
status: UpdateStatusType;
|
|
21
|
+
version?: string;
|
|
22
|
+
releaseNotes?: string | null;
|
|
23
|
+
percent?: number;
|
|
24
|
+
message?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Component
|
|
29
|
+
// =============================================================================
|
|
30
|
+
|
|
31
|
+
export function UpdateNotification(): React.ReactElement | null {
|
|
32
|
+
const [update, setUpdate] = useState<UpdateState>({ status: 'idle' });
|
|
33
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
34
|
+
const [isDismissed, setIsDismissed] = useState(false);
|
|
35
|
+
|
|
36
|
+
// Subscribe to update status events
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
let isMounted = true;
|
|
39
|
+
let unsubscribe: (() => void) | undefined;
|
|
40
|
+
|
|
41
|
+
const init = async (): Promise<void> => {
|
|
42
|
+
try {
|
|
43
|
+
const checkForUpdates = await window.markupr.settings.get('checkForUpdates');
|
|
44
|
+
if (!checkForUpdates || !isMounted) {
|
|
45
|
+
setIsDismissed(true);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
// If settings can't be read, keep default behavior.
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
unsubscribe = window.markupr.updates.onStatus((status: UpdateStatusPayload) => {
|
|
53
|
+
// Local/manual builds may not ship updater metadata; suppress that noisy non-actionable state.
|
|
54
|
+
if (
|
|
55
|
+
status.status === 'error' &&
|
|
56
|
+
typeof status.message === 'string' &&
|
|
57
|
+
/(app-update\.yml|latest\.yml|enoent)/i.test(status.message)
|
|
58
|
+
) {
|
|
59
|
+
setUpdate({ status: 'not-available' });
|
|
60
|
+
setIsDismissed(true);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setUpdate({
|
|
65
|
+
status: status.status,
|
|
66
|
+
version: status.version,
|
|
67
|
+
releaseNotes: status.releaseNotes,
|
|
68
|
+
percent: status.percent,
|
|
69
|
+
message: status.message,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Auto-expand for important states
|
|
73
|
+
if (status.status === 'available' || status.status === 'ready') {
|
|
74
|
+
setIsExpanded(true);
|
|
75
|
+
setIsDismissed(false);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
window.markupr.updates.check();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
void init();
|
|
83
|
+
|
|
84
|
+
return () => {
|
|
85
|
+
isMounted = false;
|
|
86
|
+
unsubscribe?.();
|
|
87
|
+
};
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
// Handle download button click
|
|
91
|
+
const handleDownload = useCallback(() => {
|
|
92
|
+
window.markupr.updates.download();
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
95
|
+
// Handle install/restart button click
|
|
96
|
+
const handleInstall = useCallback(() => {
|
|
97
|
+
window.markupr.updates.install();
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
// Handle dismiss (Later button)
|
|
101
|
+
const handleDismiss = useCallback(() => {
|
|
102
|
+
setIsDismissed(true);
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
// Handle toggle expand/collapse
|
|
106
|
+
const handleToggleExpand = useCallback(() => {
|
|
107
|
+
setIsExpanded((prev) => !prev);
|
|
108
|
+
}, []);
|
|
109
|
+
|
|
110
|
+
// Don't render if idle, checking, not-available, or dismissed
|
|
111
|
+
if (
|
|
112
|
+
update.status === 'idle' ||
|
|
113
|
+
update.status === 'checking' ||
|
|
114
|
+
update.status === 'not-available' ||
|
|
115
|
+
(update.status === 'error' && !update.message) ||
|
|
116
|
+
isDismissed
|
|
117
|
+
) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div className="fixed bottom-4 right-4 max-w-sm z-50 animate-slide-up">
|
|
123
|
+
{/* Update Available State */}
|
|
124
|
+
{update.status === 'available' && (
|
|
125
|
+
<div className="bg-gradient-to-br from-blue-600 to-blue-700 text-white p-4 rounded-xl shadow-2xl border border-blue-500/30">
|
|
126
|
+
{/* Header */}
|
|
127
|
+
<div className="flex items-start justify-between gap-3">
|
|
128
|
+
<div className="flex items-center gap-2">
|
|
129
|
+
<div className="w-8 h-8 bg-white/20 rounded-lg flex items-center justify-center">
|
|
130
|
+
<svg
|
|
131
|
+
className="w-5 h-5"
|
|
132
|
+
fill="none"
|
|
133
|
+
stroke="currentColor"
|
|
134
|
+
viewBox="0 0 24 24"
|
|
135
|
+
>
|
|
136
|
+
<path
|
|
137
|
+
strokeLinecap="round"
|
|
138
|
+
strokeLinejoin="round"
|
|
139
|
+
strokeWidth={2}
|
|
140
|
+
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
|
141
|
+
/>
|
|
142
|
+
</svg>
|
|
143
|
+
</div>
|
|
144
|
+
<div>
|
|
145
|
+
<h4 className="font-semibold text-sm">Update Available</h4>
|
|
146
|
+
<p className="text-xs text-white/80">Version {update.version}</p>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
<button
|
|
150
|
+
onClick={handleToggleExpand}
|
|
151
|
+
className="p-1 hover:bg-white/10 rounded transition-colors"
|
|
152
|
+
aria-label={isExpanded ? 'Collapse' : 'Expand'}
|
|
153
|
+
>
|
|
154
|
+
<svg
|
|
155
|
+
className={`w-4 h-4 transition-transform ${isExpanded ? 'rotate-180' : ''}`}
|
|
156
|
+
fill="none"
|
|
157
|
+
stroke="currentColor"
|
|
158
|
+
viewBox="0 0 24 24"
|
|
159
|
+
>
|
|
160
|
+
<path
|
|
161
|
+
strokeLinecap="round"
|
|
162
|
+
strokeLinejoin="round"
|
|
163
|
+
strokeWidth={2}
|
|
164
|
+
d="M19 9l-7 7-7-7"
|
|
165
|
+
/>
|
|
166
|
+
</svg>
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
{/* Release Notes (Expandable) */}
|
|
171
|
+
{isExpanded && update.releaseNotes && (
|
|
172
|
+
<div className="mt-3 p-3 bg-black/20 rounded-lg text-sm max-h-32 overflow-y-auto">
|
|
173
|
+
<h5 className="font-medium text-xs text-white/70 uppercase tracking-wide mb-2">
|
|
174
|
+
{"What's New"}
|
|
175
|
+
</h5>
|
|
176
|
+
<div
|
|
177
|
+
className="prose prose-sm prose-invert max-w-none text-white/90"
|
|
178
|
+
dangerouslySetInnerHTML={{ __html: formatReleaseNotes(update.releaseNotes) }}
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
182
|
+
|
|
183
|
+
{/* Actions */}
|
|
184
|
+
<div className="mt-4 flex gap-2">
|
|
185
|
+
<button
|
|
186
|
+
onClick={handleDownload}
|
|
187
|
+
className="flex-1 bg-white text-blue-600 px-4 py-2 rounded-lg font-medium text-sm hover:bg-blue-50 transition-colors"
|
|
188
|
+
>
|
|
189
|
+
Download Now
|
|
190
|
+
</button>
|
|
191
|
+
<button
|
|
192
|
+
onClick={handleDismiss}
|
|
193
|
+
className="px-4 py-2 text-white/70 hover:text-white text-sm transition-colors"
|
|
194
|
+
>
|
|
195
|
+
Later
|
|
196
|
+
</button>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
)}
|
|
200
|
+
|
|
201
|
+
{/* Downloading State */}
|
|
202
|
+
{update.status === 'downloading' && (
|
|
203
|
+
<div className="bg-gradient-to-br from-slate-800 to-slate-900 text-white p-4 rounded-xl shadow-2xl border border-slate-700/50">
|
|
204
|
+
<div className="flex items-center gap-3 mb-3">
|
|
205
|
+
<div className="w-8 h-8 bg-blue-500/20 rounded-lg flex items-center justify-center">
|
|
206
|
+
<svg
|
|
207
|
+
className="w-5 h-5 text-blue-400 animate-pulse"
|
|
208
|
+
fill="none"
|
|
209
|
+
stroke="currentColor"
|
|
210
|
+
viewBox="0 0 24 24"
|
|
211
|
+
>
|
|
212
|
+
<path
|
|
213
|
+
strokeLinecap="round"
|
|
214
|
+
strokeLinejoin="round"
|
|
215
|
+
strokeWidth={2}
|
|
216
|
+
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
|
217
|
+
/>
|
|
218
|
+
</svg>
|
|
219
|
+
</div>
|
|
220
|
+
<div>
|
|
221
|
+
<h4 className="font-semibold text-sm">Downloading Update...</h4>
|
|
222
|
+
<p className="text-xs text-slate-400">Please wait</p>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
{/* Progress Bar */}
|
|
227
|
+
<div className="h-2 bg-slate-700 rounded-full overflow-hidden">
|
|
228
|
+
<div
|
|
229
|
+
className="h-full bg-gradient-to-r from-blue-500 to-cyan-400 transition-all duration-300 ease-out"
|
|
230
|
+
style={{ width: `${update.percent || 0}%` }}
|
|
231
|
+
/>
|
|
232
|
+
</div>
|
|
233
|
+
<p className="text-xs text-slate-400 mt-2 text-right">
|
|
234
|
+
{Math.round(update.percent || 0)}% complete
|
|
235
|
+
</p>
|
|
236
|
+
</div>
|
|
237
|
+
)}
|
|
238
|
+
|
|
239
|
+
{/* Ready to Install State */}
|
|
240
|
+
{update.status === 'ready' && (
|
|
241
|
+
<div className="bg-gradient-to-br from-green-600 to-emerald-700 text-white p-4 rounded-xl shadow-2xl border border-green-500/30">
|
|
242
|
+
<div className="flex items-center gap-3 mb-3">
|
|
243
|
+
<div className="w-8 h-8 bg-white/20 rounded-lg flex items-center justify-center">
|
|
244
|
+
<svg
|
|
245
|
+
className="w-5 h-5"
|
|
246
|
+
fill="none"
|
|
247
|
+
stroke="currentColor"
|
|
248
|
+
viewBox="0 0 24 24"
|
|
249
|
+
>
|
|
250
|
+
<path
|
|
251
|
+
strokeLinecap="round"
|
|
252
|
+
strokeLinejoin="round"
|
|
253
|
+
strokeWidth={2}
|
|
254
|
+
d="M5 13l4 4L19 7"
|
|
255
|
+
/>
|
|
256
|
+
</svg>
|
|
257
|
+
</div>
|
|
258
|
+
<div>
|
|
259
|
+
<h4 className="font-semibold text-sm">Update Ready!</h4>
|
|
260
|
+
<p className="text-xs text-white/80">Version {update.version} is ready to install</p>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<p className="text-sm text-white/90 mb-4">
|
|
265
|
+
Restart markupr to apply the update. Your work will be saved.
|
|
266
|
+
</p>
|
|
267
|
+
|
|
268
|
+
<button
|
|
269
|
+
onClick={handleInstall}
|
|
270
|
+
className="w-full bg-white text-green-600 px-4 py-2.5 rounded-lg font-medium text-sm hover:bg-green-50 transition-colors flex items-center justify-center gap-2"
|
|
271
|
+
>
|
|
272
|
+
<svg
|
|
273
|
+
className="w-4 h-4"
|
|
274
|
+
fill="none"
|
|
275
|
+
stroke="currentColor"
|
|
276
|
+
viewBox="0 0 24 24"
|
|
277
|
+
>
|
|
278
|
+
<path
|
|
279
|
+
strokeLinecap="round"
|
|
280
|
+
strokeLinejoin="round"
|
|
281
|
+
strokeWidth={2}
|
|
282
|
+
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
|
283
|
+
/>
|
|
284
|
+
</svg>
|
|
285
|
+
Restart Now
|
|
286
|
+
</button>
|
|
287
|
+
</div>
|
|
288
|
+
)}
|
|
289
|
+
|
|
290
|
+
{/* Error State */}
|
|
291
|
+
{update.status === 'error' && update.message && (
|
|
292
|
+
<div className="bg-gradient-to-br from-red-600 to-red-700 text-white p-4 rounded-xl shadow-2xl border border-red-500/30">
|
|
293
|
+
<div className="flex items-center gap-3 mb-2">
|
|
294
|
+
<div className="w-8 h-8 bg-white/20 rounded-lg flex items-center justify-center">
|
|
295
|
+
<svg
|
|
296
|
+
className="w-5 h-5"
|
|
297
|
+
fill="none"
|
|
298
|
+
stroke="currentColor"
|
|
299
|
+
viewBox="0 0 24 24"
|
|
300
|
+
>
|
|
301
|
+
<path
|
|
302
|
+
strokeLinecap="round"
|
|
303
|
+
strokeLinejoin="round"
|
|
304
|
+
strokeWidth={2}
|
|
305
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
|
306
|
+
/>
|
|
307
|
+
</svg>
|
|
308
|
+
</div>
|
|
309
|
+
<div>
|
|
310
|
+
<h4 className="font-semibold text-sm">Update Failed</h4>
|
|
311
|
+
<p className="text-xs text-white/80">{update.message}</p>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<div className="flex gap-2 mt-3">
|
|
316
|
+
<button
|
|
317
|
+
onClick={() => window.markupr.updates.check()}
|
|
318
|
+
className="flex-1 bg-white/20 hover:bg-white/30 px-4 py-2 rounded-lg font-medium text-sm transition-colors"
|
|
319
|
+
>
|
|
320
|
+
Try Again
|
|
321
|
+
</button>
|
|
322
|
+
<button
|
|
323
|
+
onClick={handleDismiss}
|
|
324
|
+
className="px-4 py-2 text-white/70 hover:text-white text-sm transition-colors"
|
|
325
|
+
>
|
|
326
|
+
Dismiss
|
|
327
|
+
</button>
|
|
328
|
+
</div>
|
|
329
|
+
</div>
|
|
330
|
+
)}
|
|
331
|
+
</div>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// =============================================================================
|
|
336
|
+
// Helper Functions
|
|
337
|
+
// =============================================================================
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Format release notes for display
|
|
341
|
+
* Handles markdown-like formatting and converts to safe HTML
|
|
342
|
+
*/
|
|
343
|
+
function formatReleaseNotes(notes: string): string {
|
|
344
|
+
// Simple markdown-like formatting
|
|
345
|
+
return notes
|
|
346
|
+
// Escape HTML
|
|
347
|
+
.replace(/&/g, '&')
|
|
348
|
+
.replace(/</g, '<')
|
|
349
|
+
.replace(/>/g, '>')
|
|
350
|
+
// Convert markdown headers
|
|
351
|
+
.replace(/^### (.+)$/gm, '<h3 class="font-semibold mt-2">$1</h3>')
|
|
352
|
+
.replace(/^## (.+)$/gm, '<h2 class="font-semibold mt-2 text-base">$1</h2>')
|
|
353
|
+
.replace(/^# (.+)$/gm, '<h1 class="font-bold mt-2 text-lg">$1</h1>')
|
|
354
|
+
// Convert bold
|
|
355
|
+
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
|
356
|
+
// Convert italic
|
|
357
|
+
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
|
358
|
+
// Convert bullet points
|
|
359
|
+
.replace(/^[-*] (.+)$/gm, '<li class="ml-4">$1</li>')
|
|
360
|
+
// Convert newlines to breaks
|
|
361
|
+
.replace(/\n/g, '<br />');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// =============================================================================
|
|
365
|
+
// CSS Animation (add to your global styles or Tailwind config)
|
|
366
|
+
// =============================================================================
|
|
367
|
+
|
|
368
|
+
// Add this to your CSS or tailwind.config.js:
|
|
369
|
+
// .animate-slide-up {
|
|
370
|
+
// animation: slideUp 0.3s ease-out;
|
|
371
|
+
// }
|
|
372
|
+
// @keyframes slideUp {
|
|
373
|
+
// from { opacity: 0; transform: translateY(20px); }
|
|
374
|
+
// to { opacity: 1; transform: translateY(0); }
|
|
375
|
+
// }
|
|
376
|
+
|
|
377
|
+
export default UpdateNotification;
|