Skip to content

Commit ef6a4b3

Browse files
committed
v0.2.3: 修复 Windows 焦点问题、托盘图标、自动更新模块
Bug 修复: - 修复 Windows 删除 Prompt 后输入框无法输入的问题(原生 confirm 对话框焦点丢失) - 修复 Windows 托盘图标显示为透明的问题 - 修复打包后关于页面图标不显示的问题 - 修复自动更新模块加载失败的问题(改为静态导入) 优化: - 使用自定义 ConfirmDialog 替代原生 confirm,提升 Windows 兼容性 - 优化托盘图标加载逻辑,添加备用路径
1 parent b8e9f65 commit ef6a4b3

10 files changed

Lines changed: 207 additions & 64 deletions

File tree

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<p>
88
<a href="https://github.com/legeling/PromptHub/stargazers"><img src="https://img.shields.io/github/stars/legeling/PromptHub?style=flat-square&color=yellow" alt="GitHub Stars"/></a>
99
<a href="https://github.com/legeling/PromptHub/network/members"><img src="https://img.shields.io/github/forks/legeling/PromptHub?style=flat-square" alt="GitHub Forks"/></a>
10-
<a href="https://github.com/legeling/PromptHub/releases"><img src="https://img.shields.io/badge/version-v0.2.2-green?style=flat-square" alt="Version"/></a>
10+
<a href="https://github.com/legeling/PromptHub/releases"><img src="https://img.shields.io/badge/version-v0.2.3-green?style=flat-square" alt="Version"/></a>
1111
<a href="https://github.com/legeling/PromptHub/releases"><img src="https://img.shields.io/github/downloads/legeling/PromptHub/total?style=flat-square&color=blue" alt="Downloads"/></a>
1212
<img src="https://img.shields.io/badge/license-AGPL--3.0-blue?style=flat-square" alt="License: AGPL-3.0"/>
1313
</p>
@@ -247,6 +247,17 @@ PromptHub/
247247

248248
## 📝 更新日志
249249

250+
### v0.2.3 (2025-12-08)
251+
**修复**
252+
- 🐛 修复 Windows 删除 Prompt 后输入框无法输入的问题(原生 confirm 对话框焦点丢失)
253+
- 🐛 修复 Windows 托盘图标显示为透明的问题
254+
- 🐛 修复打包后关于页面图标不显示的问题
255+
- 🐛 修复自动更新模块加载失败的问题(改为静态导入)
256+
257+
**优化**
258+
- 🎨 使用自定义确认对话框替代原生 confirm,提升 Windows 兼容性
259+
- 🎨 优化托盘图标加载逻辑,添加备用路径
260+
250261
### v0.2.2 (2025-12-08)
251262
**修复**
252263
- 🐛 修复关于页面版本号硬编码问题(现在动态获取)

docs/README.en.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<p>
88
<a href="https://github.com/legeling/PromptHub/stargazers"><img src="https://img.shields.io/github/stars/legeling/PromptHub?style=flat-square&color=yellow" alt="GitHub Stars"/></a>
99
<a href="https://github.com/legeling/PromptHub/network/members"><img src="https://img.shields.io/github/forks/legeling/PromptHub?style=flat-square" alt="GitHub Forks"/></a>
10-
<a href="https://github.com/legeling/PromptHub/releases"><img src="https://img.shields.io/badge/version-v0.2.2-green?style=flat-square" alt="Version"/></a>
10+
<a href="https://github.com/legeling/PromptHub/releases"><img src="https://img.shields.io/badge/version-v0.2.3-green?style=flat-square" alt="Version"/></a>
1111
<a href="https://github.com/legeling/PromptHub/releases"><img src="https://img.shields.io/github/downloads/legeling/PromptHub/total?style=flat-square&color=blue" alt="Downloads"/></a>
1212
<img src="https://img.shields.io/badge/license-AGPL--3.0-blue?style=flat-square" alt="License: AGPL-3.0"/>
1313
</p>
@@ -230,6 +230,17 @@ PromptHub/
230230

231231
## 📝 Changelog
232232

233+
### v0.2.3 (2025-12-08)
234+
**Bug Fixes**
235+
- 🐛 Fixed Windows input fields becoming unresponsive after deleting a Prompt (native confirm dialog focus issue)
236+
- 🐛 Fixed Windows tray icon appearing transparent
237+
- 🐛 Fixed About page icon not showing in packaged app
238+
- 🐛 Fixed auto-updater module failing to load (switched to static import)
239+
240+
**Improvements**
241+
- 🎨 Replaced native confirm dialog with custom ConfirmDialog for better Windows compatibility
242+
- 🎨 Improved tray icon loading logic with fallback paths
243+
233244
### v0.2.2 (2025-12-08)
234245
**Bug Fixes**
235246
- 🐛 Fixed hardcoded version number in About page (now fetched dynamically)

electron-builder.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,24 @@
99
"files": [
1010
"out/**/*"
1111
],
12+
"extraResources": [
13+
{
14+
"from": "resources/icon.ico",
15+
"to": "icon.ico"
16+
},
17+
{
18+
"from": "resources/icon.icns",
19+
"to": "icon.icns"
20+
},
21+
{
22+
"from": "resources/icon.iconset",
23+
"to": "icon.iconset"
24+
},
25+
{
26+
"from": "docs/imgs/icon.png",
27+
"to": "icon.png"
28+
}
29+
],
1230
"asarUnpack": [
1331
"**/*.node"
1432
],

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "prompthub",
3-
"version": "0.2.2",
3+
"version": "0.2.3",
44
"description": "一款开源、本地优先的 AI Prompt 管理工具,帮助你高效管理、版本控制和复用",
55
"main": "out/main/index.js",
66
"author": {
File renamed without changes.

src/main/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,17 @@ function createTray() {
180180
} else {
181181
iconPath = path.join(process.resourcesPath, 'icon.ico');
182182
}
183+
console.log('Loading tray icon from:', iconPath);
183184
icon = nativeImage.createFromPath(iconPath);
184-
icon = icon.resize({ width: 16, height: 16 });
185+
if (icon.isEmpty()) {
186+
console.error('Tray icon is empty, trying alternative path');
187+
// 尝试备用路径
188+
const altPath = path.join(process.resourcesPath, 'app.asar.unpacked', 'resources', 'icon.ico');
189+
icon = nativeImage.createFromPath(altPath);
190+
}
191+
if (!icon.isEmpty()) {
192+
icon = icon.resize({ width: 16, height: 16 });
193+
}
185194
}
186195

187196
tray = new Tray(icon);

src/main/updater.ts

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BrowserWindow, ipcMain, app } from 'electron';
2-
import type { UpdateInfo as ElectronUpdateInfo, AppUpdater } from 'electron-updater';
2+
import type { UpdateInfo as ElectronUpdateInfo } from 'electron-updater';
3+
import { autoUpdater } from 'electron-updater';
34

45
// 简化的更新信息类型(用于 IPC 传输)
56
interface SimpleUpdateInfo {
@@ -51,7 +52,6 @@ function toSimpleInfo(info: ElectronUpdateInfo): SimpleUpdateInfo {
5152
}
5253

5354
let mainWindow: BrowserWindow | null = null;
54-
let autoUpdater: AppUpdater | null = null;
5555

5656
export interface UpdateStatus {
5757
status: 'checking' | 'available' | 'not-available' | 'downloading' | 'downloaded' | 'error';
@@ -60,37 +60,15 @@ export interface UpdateStatus {
6060
error?: string;
6161
}
6262

63-
async function getAutoUpdater(): Promise<AppUpdater | null> {
64-
if (autoUpdater) return autoUpdater;
65-
66-
try {
67-
const module = await import('electron-updater');
68-
autoUpdater = module.autoUpdater;
69-
70-
// 禁用自动下载,让用户选择
71-
if (autoUpdater) {
72-
autoUpdater.autoDownload = false;
73-
autoUpdater.autoInstallOnAppQuit = true;
74-
}
75-
76-
return autoUpdater;
77-
} catch (error) {
78-
console.error('Failed to load electron-updater:', error);
79-
return null;
80-
}
81-
}
82-
83-
export async function initUpdater(win: BrowserWindow) {
63+
export function initUpdater(win: BrowserWindow) {
8464
mainWindow = win;
85-
const updater = await getAutoUpdater();
8665

87-
if (!updater) {
88-
console.warn('Auto updater not available');
89-
return;
90-
}
66+
// 禁用自动下载,让用户选择
67+
autoUpdater.autoDownload = false;
68+
autoUpdater.autoInstallOnAppQuit = true;
9169

9270
// 检查更新出错
93-
updater.on('error', (error) => {
71+
autoUpdater.on('error', (error) => {
9472
console.error('Update error:', error);
9573
let message = (error && (error as Error).message) || String(error);
9674
if (message.includes('ZIP file not provided')) {
@@ -104,13 +82,13 @@ export async function initUpdater(win: BrowserWindow) {
10482
});
10583

10684
// 检查更新中
107-
updater.on('checking-for-update', () => {
85+
autoUpdater.on('checking-for-update', () => {
10886
console.info('Checking for update...');
10987
sendStatusToWindow({ status: 'checking' });
11088
});
11189

11290
// 有可用更新
113-
updater.on('update-available', (info) => {
91+
autoUpdater.on('update-available', (info) => {
11492
console.info('Update available:', info.version);
11593
sendStatusToWindow({
11694
status: 'available',
@@ -119,7 +97,7 @@ export async function initUpdater(win: BrowserWindow) {
11997
});
12098

12199
// 没有可用更新
122-
updater.on('update-not-available', (info) => {
100+
autoUpdater.on('update-not-available', (info) => {
123101
console.info('Update not available, current version is latest');
124102
sendStatusToWindow({
125103
status: 'not-available',
@@ -128,7 +106,7 @@ export async function initUpdater(win: BrowserWindow) {
128106
});
129107

130108
// 下载进度
131-
updater.on('download-progress', (progress: ProgressInfo) => {
109+
autoUpdater.on('download-progress', (progress: ProgressInfo) => {
132110
console.info(`Download progress: ${progress.percent.toFixed(2)}%`);
133111
sendStatusToWindow({
134112
status: 'downloading',
@@ -137,7 +115,7 @@ export async function initUpdater(win: BrowserWindow) {
137115
});
138116

139117
// 下载完成
140-
updater.on('update-downloaded', (info) => {
118+
autoUpdater.on('update-downloaded', (info) => {
141119
console.info('Update downloaded:', info.version);
142120
sendStatusToWindow({
143121
status: 'downloaded',
@@ -167,11 +145,7 @@ export function registerUpdaterIPC() {
167145
return { success: false, error: 'Update check disabled in development mode' };
168146
}
169147
try {
170-
const updater = await getAutoUpdater();
171-
if (!updater) {
172-
return { success: false, error: '自动更新模块加载失败,请前往 GitHub Releases 手动下载:https://github.com/legeling/PromptHub/releases' };
173-
}
174-
const result = await updater.checkForUpdates();
148+
const result = await autoUpdater.checkForUpdates();
175149
return { success: true, result };
176150
} catch (error) {
177151
const errMsg = (error as Error).message || String(error);
@@ -185,11 +159,7 @@ export function registerUpdaterIPC() {
185159
return { success: false, error: 'Download disabled in development mode' };
186160
}
187161
try {
188-
const updater = await getAutoUpdater();
189-
if (!updater) {
190-
return { success: false, error: '自动更新模块不可用,请前往 GitHub Releases 手动下载:https://github.com/legeling/PromptHub/releases' };
191-
}
192-
await updater.downloadUpdate();
162+
await autoUpdater.downloadUpdate();
193163
return { success: true };
194164
} catch (error) {
195165
const errMsg = (error as Error).message || String(error);
@@ -200,10 +170,7 @@ export function registerUpdaterIPC() {
200170
// 安装更新并重启
201171
ipcMain.handle('updater:install', async () => {
202172
if (!isDev) {
203-
const updater = await getAutoUpdater();
204-
if (updater) {
205-
updater.quitAndInstall(false, true);
206-
}
173+
autoUpdater.quitAndInstall(false, true);
207174
}
208175
});
209176
}

src/renderer/components/layout/MainContent.tsx

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { useState, useEffect, useMemo } from 'react';
1+
import { useState, useEffect, useMemo, useCallback } from 'react';
22
import { usePromptStore } from '../../stores/prompt.store';
33
import { useFolderStore } from '../../stores/folder.store';
44
import { useSettingsStore } from '../../stores/settings.store';
55
import { StarIcon, CopyIcon, HistoryIcon, HashIcon, SparklesIcon, EditIcon, TrashIcon, CheckIcon, PlayIcon, LoaderIcon, XIcon, GitCompareIcon, ClockIcon } from 'lucide-react';
66
import { EditPromptModal, VersionHistoryModal, VariableInputModal, PromptListHeader, PromptListView, PromptTableView, AiTestModal, PromptDetailModal, PromptGalleryView } from '../prompt';
77
import { ContextMenu, ContextMenuItem } from '../ui/ContextMenu';
88
import { ImagePreviewModal } from '../ui/ImagePreviewModal';
9+
import { ConfirmDialog } from '../ui/ConfirmDialog';
910
import { useToast } from '../ui/Toast';
1011
import { chatCompletion, buildMessagesFromPrompt, multiModelCompare, AITestResult } from '../../services/ai';
1112
import { useTranslation } from 'react-i18next';
@@ -85,6 +86,7 @@ export function MainContent() {
8586
const [isCompareVariableModalOpen, setIsCompareVariableModalOpen] = useState(false);
8687
const [previewImage, setPreviewImage] = useState<string | null>(null);
8788
const [contextMenu, setContextMenu] = useState<{ x: number; y: number; prompt: Prompt } | null>(null);
89+
const [deleteConfirm, setDeleteConfirm] = useState<{ isOpen: boolean; prompt: Prompt | null }>({ isOpen: false, prompt: null });
8890
const renderMarkdownPref = useSettingsStore((state) => state.renderMarkdown);
8991
const setRenderMarkdownPref = useSettingsStore((state) => state.setRenderMarkdown);
9092
const [renderMarkdownEnabled, setRenderMarkdownEnabled] = useState(renderMarkdownPref);
@@ -397,12 +399,18 @@ export function MainContent() {
397399
};
398400

399401
// 处理删除 Prompt(表格视图用)
400-
const handleDeletePrompt = async (prompt: Prompt) => {
401-
if (confirm(t('prompt.confirmDeletePrompt'))) {
402-
await deletePrompt(prompt.id);
402+
const handleDeletePrompt = useCallback((prompt: Prompt) => {
403+
setDeleteConfirm({ isOpen: true, prompt });
404+
}, []);
405+
406+
// 确认删除
407+
const confirmDelete = useCallback(async () => {
408+
if (deleteConfirm.prompt) {
409+
await deletePrompt(deleteConfirm.prompt.id);
403410
showToast(t('prompt.promptDeleted'), 'success');
404411
}
405-
};
412+
setDeleteConfirm({ isOpen: false, prompt: null });
413+
}, [deleteConfirm.prompt, deletePrompt, showToast, t]);
406414

407415
// 处理 AI 测试(表格视图用 - 弹窗模式)
408416
const handleAiTestFromTable = (prompt: Prompt) => {
@@ -1054,12 +1062,7 @@ export function MainContent() {
10541062
<span>{t('prompt.history')}</span>
10551063
</button>
10561064
<button
1057-
onClick={async () => {
1058-
if (confirm(t('prompt.confirmDeletePrompt'))) {
1059-
await deletePrompt(selectedPrompt.id);
1060-
showToast(t('prompt.promptDeleted'), 'success');
1061-
}
1062-
}}
1065+
onClick={() => handleDeletePrompt(selectedPrompt)}
10631066
className="flex items-center gap-2 h-9 px-4 rounded-lg bg-destructive/10 border border-destructive/30 text-destructive text-sm font-medium hover:bg-destructive/20 transition-colors"
10641067
>
10651068
<TrashIcon className="w-4 h-4" />
@@ -1162,6 +1165,18 @@ export function MainContent() {
11621165
onClose={() => setPreviewImage(null)}
11631166
imageSrc={previewImage}
11641167
/>
1168+
1169+
{/* 删除确认对话框 */}
1170+
<ConfirmDialog
1171+
isOpen={deleteConfirm.isOpen}
1172+
onClose={() => setDeleteConfirm({ isOpen: false, prompt: null })}
1173+
onConfirm={confirmDelete}
1174+
title={t('prompt.delete')}
1175+
message={t('prompt.confirmDeletePrompt')}
1176+
confirmText={t('common.confirm')}
1177+
cancelText={t('common.cancel')}
1178+
variant="destructive"
1179+
/>
11651180
</main>
11661181
);
11671182
}

src/renderer/components/settings/SettingsPage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useState, useEffect } from 'react';
2+
import appIconUrl from '../../../assets/icon.png';
23
import {
34
SettingsIcon,
45
PaletteIcon,
@@ -1801,7 +1802,7 @@ export function SettingsPage({ onBack }: SettingsPageProps) {
18011802
{/* 应用信息卡片 */}
18021803
<div className="text-center py-6">
18031804
<div className="w-16 h-16 mx-auto mb-3 rounded-2xl overflow-hidden shadow-lg">
1804-
<img src="/icon.png" alt="PromptHub" className="w-full h-full object-cover" />
1805+
<img src={appIconUrl} alt="PromptHub" className="w-full h-full object-cover" />
18051806
</div>
18061807
<h2 className="text-lg font-semibold">PromptHub</h2>
18071808
<p className="text-sm text-muted-foreground mt-1">{t('settings.version')} {appVersion || '...'}</p>

0 commit comments

Comments
 (0)