feat: 添加应用图标并实现更新提示徽标

- 新增应用图标资源
- 调整玻璃面板背景色优化视觉效果
- 重构标题栏布局,替换品牌Logo为应用图标
- 为检查更新按钮添加徽标,有更新时显示提示点
- 修改更新逻辑,保留已检测更新状态避免重复检查
- 简化模板代码格式,提升可读性
- 版本号从1.0.0更新为0.9.0
This commit is contained in:
Yuhang Wu
2026-10-14 14:09:41 +08:00
parent 4adde51bef
commit 827075bdef
9 changed files with 67 additions and 101 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "frpilot", "name": "frpilot",
"private": true, "private": true,
"version": "1.0.0", "version": "0.9.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

+3 -3
View File
@@ -112,7 +112,7 @@ body {
.glass-panel { .glass-panel {
border-radius: 16px; border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.55); border: 1px solid rgba(255, 255, 255, 0.55);
background: rgba(255, 255, 255, 0.35); background: rgba(255, 255, 255, 0.45);
backdrop-filter: blur(18px) saturate(160%); backdrop-filter: blur(18px) saturate(160%);
-webkit-backdrop-filter: blur(18px) saturate(160%); -webkit-backdrop-filter: blur(18px) saturate(160%);
box-shadow: 0 8px 32px rgba(15, 23, 42, 0.12); box-shadow: 0 8px 32px rgba(15, 23, 42, 0.12);
@@ -120,7 +120,7 @@ body {
.dark .glass-panel { .dark .glass-panel {
border-color: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.08);
background: rgba(15, 23, 42, 0.55); background: rgba(15, 23, 42, 0.45);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
} }
@@ -131,7 +131,7 @@ body {
*/ */
.glass-card.ant-card { .glass-card.ant-card {
border: 1px solid rgba(255, 255, 255, 0.5) !important; border: 1px solid rgba(255, 255, 255, 0.5) !important;
background: rgba(255, 255, 255, 0.5) !important; background: rgba(255, 255, 255, 0.45) !important;
backdrop-filter: blur(16px) saturate(160%); backdrop-filter: blur(16px) saturate(160%);
-webkit-backdrop-filter: blur(16px) saturate(160%); -webkit-backdrop-filter: blur(16px) saturate(160%);
box-shadow: 0 6px 22px rgba(15, 23, 42, 0.08) !important; box-shadow: 0 6px 22px rgba(15, 23, 42, 0.08) !important;
+33 -60
View File
@@ -2,22 +2,14 @@
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<!-- 语言切换 --> <!-- 语言切换 -->
<a-dropdown placement="bottomRight" trigger="click"> <a-dropdown placement="bottomRight" trigger="click">
<a-button <a-button type="text" class="tb-btn" :title="t('titlebar.language')">
type="text" <template #icon>
class="tb-btn" <TranslationOutlined />
:title="t('titlebar.language')" </template>
>
<template #icon><TranslationOutlined /></template>
</a-button> </a-button>
<template #overlay> <template #overlay>
<a-menu <a-menu :selected-keys="[appStore.language]" @click="onLanguageClick">
:selected-keys="[appStore.language]" <a-menu-item v-for="item in languageOptions" :key="item.key">
@click="onLanguageClick"
>
<a-menu-item
v-for="item in languageOptions"
:key="item.key"
>
{{ item.label }} {{ item.label }}
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@@ -25,69 +17,50 @@
</a-dropdown> </a-dropdown>
<!-- 明暗切换 --> <!-- 明暗切换 -->
<a-button <a-button type="text" class="tb-btn" :title="appStore.isDark ? t('titlebar.lightMode') : t('titlebar.darkMode')"
type="text" @click="appStore.toggleDark()">
class="tb-btn"
:title="appStore.isDark ? t('titlebar.lightMode') : t('titlebar.darkMode')"
@click="appStore.toggleDark()"
>
<template #icon> <template #icon>
<BulbFilled v-if="appStore.isDark" /> <BulbFilled v-if="appStore.isDark" />
<BulbOutlined v-else /> <BulbOutlined v-else />
</template> </template>
</a-button> </a-button>
<!-- 检查更新 --> <!-- 检查更新(有新版本时显示圆点徽标) -->
<a-button <a-badge :dot="updateStore.hasUpdate">
type="text" <a-button type="text" class="tb-btn" :title="t('titlebar.checkUpdate')" :loading="updateStore.checking"
class="tb-btn" @click="onCheckUpdate">
:title="t('titlebar.checkUpdate')" <template #icon>
:loading="updateStore.checking" <CloudSyncOutlined />
@click="onCheckUpdate" </template>
> </a-button>
<template #icon><CloudSyncOutlined /></template> </a-badge>
</a-button>
<!-- GitHub --> <!-- GitHub -->
<a-button <a-button type="text" class="tb-btn" :title="t('titlebar.github')" @click="onOpenGithub">
type="text" <template #icon>
class="tb-btn" <GithubOutlined />
:title="t('titlebar.github')" </template>
@click="onOpenGithub"
>
<template #icon><GithubOutlined /></template>
</a-button> </a-button>
<!-- 设置 --> <!-- 设置 -->
<a-button <a-button type="text" class="tb-btn" :title="t('titlebar.settings')" @click="emit('settings')">
type="text" <template #icon>
class="tb-btn" <SettingOutlined />
:title="t('titlebar.settings')" </template>
@click="emit('settings')"
>
<template #icon><SettingOutlined /></template>
</a-button> </a-button>
<!-- 最小化(macOS 由左侧红绿灯负责,此处隐藏) --> <!-- 最小化(macOS 由左侧红绿灯负责,此处隐藏) -->
<a-button <a-button v-if="!isMac" type="text" class="tb-btn" :title="t('titlebar.minimize')" @click="minimizeWindow()">
v-if="!isMac" <template #icon>
type="text" <MinusOutlined />
class="tb-btn" </template>
:title="t('titlebar.minimize')"
@click="minimizeWindow()"
>
<template #icon><MinusOutlined /></template>
</a-button> </a-button>
<!-- 关闭(macOS 由左侧红绿灯负责,此处隐藏) --> <!-- 关闭(macOS 由左侧红绿灯负责,此处隐藏) -->
<a-button <a-button v-if="!isMac" type="text" class="tb-btn tb-btn-close" :title="t('titlebar.close')" @click="closeWindow()">
v-if="!isMac" <template #icon>
type="text" <CloseOutlined />
class="tb-btn tb-btn-close" </template>
:title="t('titlebar.close')"
@click="closeWindow()"
>
<template #icon><CloseOutlined /></template>
</a-button> </a-button>
</div> </div>
</template> </template>
+2 -11
View File
@@ -1,15 +1,6 @@
<template> <template>
<a-modal <a-modal :open="store.modalOpen" :title="modalTitle" :closable="!store.installing" :mask-closable="false"
:open="store.modalOpen" :keyboard="!store.installing" :width="520" centered wrap-class-name="update-modal-wrap" @cancel="onCancel">
:title="modalTitle"
:closable="!store.installing"
:mask-closable="false"
:keyboard="!store.installing"
:width="520"
centered
wrap-class-name="update-modal-wrap"
@cancel="onCancel"
>
<!-- 俏皮的问候 + 版本变化 --> <!-- 俏皮的问候 + 版本变化 -->
<div class="update-hero"> <div class="update-hero">
<span class="update-hero-emoji">🎉</span> <span class="update-hero-emoji">🎉</span>
+9 -21
View File
@@ -1,12 +1,14 @@
<template> <template>
<!-- Windows 自定义标题栏 --> <!-- Windows 自定义标题栏 -->
<div <div class="titlebar flex h-12 shrink-0 items-center justify-between pl-4 pr-2 select-none" data-tauri-drag-region>
class="titlebar flex h-12 shrink-0 items-center justify-between pl-4 pr-2 select-none" <!-- 左侧:图标 + 标题 -->
data-tauri-drag-region
>
<!-- 左侧:标题 -->
<div class="flex items-center gap-2" data-tauri-drag-region> <div class="flex items-center gap-2" data-tauri-drag-region>
<span class="brand-logo">F</span> <img
class="h-[22px] w-[22px] shrink-0 object-contain"
:src="appIcon"
alt=""
draggable="false"
/>
<span class="text-sm font-semibold tracking-wide">Frpilot</span> <span class="text-sm font-semibold tracking-wide">Frpilot</span>
</div> </div>
@@ -17,21 +19,7 @@
<script setup lang="ts"> <script setup lang="ts">
import TitleBarActions from "./TitleBarActions.vue" import TitleBarActions from "./TitleBarActions.vue"
import appIcon from "@/assets/images/app-icon.webp"
const emit = defineEmits<{ settings: [] }>() const emit = defineEmits<{ settings: [] }>()
</script> </script>
<style scoped lang="scss">
.brand-logo {
display: inline-flex;
height: 22px;
width: 22px;
align-items: center;
justify-content: center;
border-radius: 6px;
background: linear-gradient(135deg, #6366f1, #22d3ee);
color: #fff;
font-size: 12px;
font-weight: 700;
}
</style>
+13 -2
View File
@@ -60,11 +60,19 @@ export const useUpdateStore = defineStore("update", () => {
return return
} }
// 已检测到可用更新(例如用户点过「取消」关掉了弹窗):直接重新打开,
// 避免重复联网检查、重复创建后端资源;徽标也因此能持续提示。
if (pending) {
modalOpen.value = true
return
}
checking.value = true checking.value = true
try { try {
const update = await checkForAppUpdate() const update = await checkForAppUpdate()
if (!update) { if (!update) {
info.value = null
if (!silent) message.success(translate("update.upToDate")) if (!silent) message.success(translate("update.upToDate"))
return return
} }
@@ -107,9 +115,12 @@ export const useUpdateStore = defineStore("update", () => {
} }
} }
/** 取消(本次不更新,下次启动仍会提示) */ /**
* 取消:仅关闭弹窗,保留已检测到的可用更新。
* 顶部栏 / 关于页的圆点徽标会继续提示,再次点击「检查更新」可重新打开弹窗。
*/
function cancel() { function cancel() {
void discard() modalOpen.value = false
} }
/** 忽略该版本(持久化,静默检查不再提示) */ /** 忽略该版本(持久化,静默检查不再提示) */
+1
View File
@@ -11,6 +11,7 @@ export {}
/* prettier-ignore */ /* prettier-ignore */
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
ABadge: typeof import('ant-design-vue/es')['Badge']
AButton: typeof import('ant-design-vue/es')['Button'] AButton: typeof import('ant-design-vue/es')['Button']
ACard: typeof import('ant-design-vue/es')['Card'] ACard: typeof import('ant-design-vue/es')['Card']
ACol: typeof import('ant-design-vue/es')['Col'] ACol: typeof import('ant-design-vue/es')['Col']
+5 -3
View File
@@ -48,9 +48,11 @@
<div class="flex flex-wrap items-center gap-3"> <div class="flex flex-wrap items-center gap-3">
<span class="text-xs opacity-60">{{ t("about.currentVersion") }}</span> <span class="text-xs opacity-60">{{ t("about.currentVersion") }}</span>
<a-tag color="purple" class="!me-0">v{{ version }}</a-tag> <a-tag color="purple" class="!me-0">v{{ version }}</a-tag>
<a-button size="small" :loading="updateStore.checking" @click="onCheckUpdate"> <a-badge :dot="updateStore.hasUpdate">
{{ t("about.checkUpdate") }} <a-button size="small" :loading="updateStore.checking" @click="onCheckUpdate">
</a-button> {{ t("about.checkUpdate") }}
</a-button>
</a-badge>
<span v-if="updateStore.hasUpdate" class="text-xs text-[#6366f1]"> <span v-if="updateStore.hasUpdate" class="text-xs text-[#6366f1]">
{{ t("about.newVersion", { version: updateStore.info?.version }) }} {{ t("about.newVersion", { version: updateStore.info?.version }) }}
</span> </span>