feat(desktop,ci): GitHub Releases 分发 + 桌面端检查更新

让桌面端像开源项目一样用 GitHub Releases 分发,旧版用户自动获知更新:
- CD:.github/workflows/release.yml —— 打 vX.Y.Z 标签触发,macOS(universal)/
  Windows(amd64) 用 wails build 出安装包,softprops/action-gh-release 发布到
  GitHub Release(GOWORK=off,因 desktop 不在工作区)。
- 桌面端检查更新:lib/version.ts(APP_VERSION + 查 GitHub /releases/latest +
  语义版本比较 + openExternal 走 Wails BrowserOpenURL);UpdateBanner 启动时
  检查,有新版顶部横幅「前往下载」。404/限流/离线均静默不打扰。

注:未签名/公证(macOS Gatekeeper / Win SmartScreen 需后续证书);release
workflow 需真实 tag push 才能验证(GitHub 侧运行)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-06-23 16:26:02 +08:00
parent 9fc3597317
commit 8c980d2b37
4 changed files with 150 additions and 0 deletions
@@ -0,0 +1,38 @@
import { useEffect, useState } from "react";
import { Download, X } from "lucide-react";
import { checkUpdate, openExternal, type ReleaseInfo } from "../lib/version";
// 启动时查 GitHub Releases,有新版则在顶部显示一条可关闭的横幅,点击去下载页。
export function UpdateBanner() {
const [rel, setRel] = useState<ReleaseInfo | null>(null);
const [dismissed, setDismissed] = useState(false);
useEffect(() => {
let alive = true;
void checkUpdate().then((r) => {
if (alive) setRel(r);
});
return () => {
alive = false;
};
}, []);
if (!rel || dismissed) return null;
return (
<div className="flex shrink-0 items-center gap-3 border-b border-brand/30 bg-brand/10 px-4 py-1.5 text-[12px] text-brand-200">
<Download className="h-3.5 w-3.5 text-brand-400" />
<span>
<span className="font-semibold">v{rel.version}</span>
</span>
<button
onClick={() => openExternal(rel.url)}
className="rounded bg-brand/20 px-2 py-0.5 text-brand-200 hover:bg-brand/30"
>
</button>
<button onClick={() => setDismissed(true)} className="ml-auto text-slate-500 hover:text-slate-300" title="忽略">
<X className="h-3.5 w-3.5" />
</button>
</div>
);
}