mirror of
https://github.com/lobehub/lobehub.git
synced 2026-09-20 04:56:13 +08:00
82ba3706a7
* feat: add screen capture functionality with overlay support - Implemented ScreenCaptureManager to handle screen capture sessions. - Added ScreenCaptureCtr for IPC methods related to screen capture. - Created overlay.html and ScreenCaptureOverlay component for user interaction. - Integrated window enumeration and capture logic using node-screenshots and get-windows. - Updated menu options to include screen capture actions. - Enhanced RendererUrlManager to support overlay routing. - Introduced drag selection for capturing specific screen areas. - Added necessary types and events for screen capture in electron-client-ipc. Signed-off-by: Innei <tukon479@gmail.com> * ✨ feat(desktop): refine screen capture overlay flow * ✨ feat(desktop): refine screen capture overlay flow * ⚡ feat(desktop): optimize screen capture overlay flow * Delete apps/desktop/mockup/screen-capture-overlay.html * ✨ feat(desktop): open mini toolbar via double Option * 🐛 fix(desktop): separate quick composer hotkey * 💄 fix(desktop): remove stale quick composer accelerator * 🐛 fix(desktop): stabilize double option monitor * 🐛 fix(desktop): read hardware option key state * 🐛 fix(desktop): standardize path imports and improve error handling - Replaced `join` imports with `path` imports for consistency across files. - Enhanced error handling in various modules to include error causes for better debugging. - Updated test files to reflect changes in variable naming and mock implementations. Signed-off-by: Innei <tukon479@gmail.com> * 🔥 chore(hotkey): drop orphan renderer quickComposer i18n entries The `quickComposer` hotkey is registered only on the Electron side (DESKTOP_GLOBAL_SHORTCUT_DEFAULTS + BrowserWindowsCtr.openQuickComposer); the renderer never referenced these i18n keys, so the entries were dead. `desktop.quickComposer` covers the app-level trigger. * ⚡️ perf(screen-capture): parallelize overlay upload with route navigation Overlay submit used to await screenshot upload before router.push, blocking the main window for several seconds when the user was on an unrelated page (e.g. /settings). Now we navigate immediately and run upload in a background IIFE; MessageFromUrl waits on a new `uploadStatus` field before calling sendMessage, so the chat page mount and the upload proceed in parallel. - Add `uploadStatus: 'uploading' | 'ready' | 'failed'` to PendingOverlayDispatch; canConsumePendingOverlayDispatch blocks while `'uploading'`. - Store gains `markDispatchUploadComplete`; on failure it clears screenshotFileNames so the prompt still delivers. - Dispatcher drops stale prev search params on push to prevent MessageFromUrl's message-param effect from double-firing. * ⚡️ perf(screen-capture): pre-upload captures in overlay preview + per-thumbnail status Move uploads from post-submit to preview time, bypassing dataUrl round-trips: - Main process assigns captureId at preview time and ships the PNG bytes as ArrayBuffer to the main renderer via `overlayUploadRequest`. - Main renderer uploads through a dedicated pool (uploadWithProgress, no chatUploadFileList pollution); reports status back to the overlay through `overlayCaptureUploadStatus`. - Overlay thumbnails render a spinner / error badge based on status; the send button stays grey until every capture resolves to `ready`. - Submit now carries only captureIds; MessageFromUrl awaits the pool promises before sendMessage, removing the second upload pass. - Carry overlay-selected modelId/provider into the agent config so the first message actually uses the user-chosen model (fixes the bug where switching the model on the overlay had no effect). * update * ✨ feat(popup): add Quick Chat tray entry backed by Inbox agent Tray menu now exposes a "Quick Chat" action that opens (or focuses) a single-instance popup window at `/popup/agent/inbox`. Each fresh open starts with no active topic; the first message creates one through the normal agent flow. - New `PopupAgentQuickPage` resolves the inbox slug via `builtinAgentSelectors.inboxAgentId` so `activeAgentId` points at the real entity in `agentMap` (fixes the stuck-loading / skeleton state from using the literal `'inbox'` slug). - `BrowserManager.openQuickChatPopup` wraps `createMultiInstanceWindow` with a fixed `topicPopup_quick_inbox` uniqueId so repeat clicks focus rather than spawn. - Wire the action into macOS / Windows / Linux tray menus and add the `tray.quickChat` i18n key. * Add quick chat shortcut and desktop hotkey support * ✨ feat(screen-capture): enhance window enumeration with scale factor support - Updated `enumerateWindows` to accept an optional `displayScaleFactor` parameter for improved window geometry normalization on high-DPI displays. - Refactored `normalizeWindowBounds` to handle scaling based on the provided scale factor, ensuring accurate window dimensions across different platforms. - Adjusted tests in `WindowSourceService.test.ts` to validate the new scaling behavior for both Windows and macOS environments. - Minor adjustments in `ScreenCaptureManager` to accommodate the updated window enumeration logic. --------- Signed-off-by: Innei <tukon479@gmail.com>
52 lines
2.6 KiB
JavaScript
52 lines
2.6 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Generate the macOS tray template icon set (black + alpha).
|
|
*
|
|
* Template images must contain only black pixels and an alpha channel;
|
|
* macOS then recolors them automatically based on the menu bar theme.
|
|
*
|
|
* Renders two files in apps/desktop/resources:
|
|
* - trayTemplate.png (@1x, 18x18)
|
|
* - trayTemplate@2x.png (@2x, 36x36)
|
|
*
|
|
* Run: bun run apps/desktop/scripts/generate-tray-template.mjs
|
|
*/
|
|
import { mkdir } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
import sharp from 'sharp';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const outDir = path.resolve(__dirname, '..', 'resources');
|
|
|
|
// Silhouette derived from the LobeHub logo. Eyes and mouth are cut as
|
|
// transparent holes via fill-rule=evenodd so they remain visible when
|
|
// macOS tints the entire shape in a single color.
|
|
const svg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 320">
|
|
<path fill="#000" d="M172.997 19.016c-14.027 0-19.5-11.5-41-11-23.394 0-34 13-45.5 23-1.958 1.702-11.5 7-16 9-19.683 8.748-34.5 21.5-34.5 40.5 0 20.711 17.461 37.5 39 37.5 3.536 0 6.963-.453 10.22-1.301 8.7 10.539 22.179 16.658 37.28 17.301 23.5 1 31-15.25 44.5-8.5 9.259 4.629 13.83 8.5 28.5 8.5 17.108 0 25.057-5.233 30-11 9-10.5 22.879-4 31.5-4 18.778 0 34-14.551 34-32.5 0-17.95-15.222-32.5-34-32.5-5.15 0-14.856 1.27-17-7-3.5-13.5-20.148-29-44-29-9.318 0-17.691 1-23 1z"/>
|
|
<path fill="#000" fill-rule="evenodd" d="M294 172.519c0 75.655-59.442 128.5-134 128.5-74.558 0-134-53.845-134-129.5 0-22.5 5-32.141 31.5-35.671 47.5-6.329 72.542-3.829 102.5-3.829 29.959 0 72.556-1.27 102.5 3.829 24.5 4.171 30 8.671 31.5 36.671zM101 221.012c15.464 0 28-12.536 28-28s-12.536-28-28-28-28 12.536-28 28 12.536 28 28 28zM219 221.012c15.464 0 28-12.536 28-28s-12.536-28-28-28-28 12.536-28 28 12.536 28 28 28zM159.75 242.51c-28.25 0-35.75 3.5-35.75 3.5s3.5 27 35.75 27 35.75-27 35.75-27-7.5-3.5-35.75-3.5z"/>
|
|
</svg>
|
|
`;
|
|
|
|
async function render(size, outFile) {
|
|
const buf = Buffer.from(svg);
|
|
await sharp(buf, { density: Math.max(72, size * 12) })
|
|
.resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
|
.png()
|
|
.toFile(outFile);
|
|
console.log(`wrote ${path.relative(process.cwd(), outFile)} (${size}x${size})`);
|
|
}
|
|
|
|
async function main() {
|
|
await mkdir(outDir, { recursive: true });
|
|
await render(18, path.join(outDir, 'trayTemplate.png'));
|
|
await render(36, path.join(outDir, 'trayTemplate@2x.png'));
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|