From 4dc1a1d7fe20606b28902b6ac3f895ff3dba62ad Mon Sep 17 00:00:00 2001
From: xiyidaiwa
Date: Mon, 17 Aug 2026 23:00:14 +0800
Subject: [PATCH 1/6] =?UTF-8?q?feat(settings):=20=E6=96=B0=E5=A2=9E?=
=?UTF-8?q?=E5=AD=97=E4=BD=93=E5=A4=A7=E5=B0=8F=E8=AE=BE=E7=BD=AE=EF=BC=88?=
=?UTF-8?q?=E4=BB=85=E5=AD=97=E5=8F=B7=E6=A1=A3=E4=BD=8D=EF=BC=8C=E4=B8=8D?=
=?UTF-8?q?=E5=90=AB=E6=95=B4=E4=BD=93=E7=BC=A9=E6=94=BE/=E5=AD=97?=
=?UTF-8?q?=E4=BD=93=E6=97=8F=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 src/global/displaySettings.ts:small/medium/large/xlarge 四档 → html 15/16/17/18px,
localStorage(spark-store-font-size) 持久化,applyFontSize 写 html font-size 全局联动 rem 字号类
- App.vue onMounted 最前 initFontSize()(与 initTagPriorityStrategy 同级,防字号闪烁)
- SettingsModal.vue 新增「字体大小」卡片(4 档分段按钮 + 预览),selectFontSize 即时应用+持久化
- 用户确认范围:仅字号档位,整体缩放与字体族切换本期不做
- vue-tsc/lint/打包均通过
---
debian/changelog | 2 +-
src/App.vue | 3 ++
src/components/SettingsModal.vue | 73 +++++++++++++++++++++++++++++++
src/global/displaySettings.ts | 75 ++++++++++++++++++++++++++++++++
4 files changed, 152 insertions(+), 1 deletion(-)
create mode 100644 src/global/displaySettings.ts
diff --git a/debian/changelog b/debian/changelog
index 8fb4c320..b78193f9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-spark-store (5.3.0.1) UNRELEASED; urgency=medium
+spark-store (5.3.0.2-test) UNRELEASED; urgency=medium
* Initial release.
diff --git a/src/App.vue b/src/App.vue
index abd3b205..e9ed680b 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -344,6 +344,7 @@ import ReviewUserProfileModal from "./components/ReviewUserProfileModal.vue";
import WindowTitleBar from "./components/WindowTitleBar.vue";
import SubmitterWindow from "./components/SubmitterWindow.vue";
import { initTagPriorityStrategy } from "./global/tagPriority";
+import { initFontSize } from "./global/displaySettings";
import {
FLARUM_BASE_URL,
FLARUM_REGISTER_URL,
@@ -1052,6 +1053,8 @@ onMounted(async () => {
// 应用启动即锁定标签优先显示策略的真实持久化值,避免依赖详情页挂载顺序
// 导致先读到内存默认值 "auto" 再懒加载的竞态窗口。
initTagPriorityStrategy();
+ // 恢复并应用持久化的字体大小档位(仅字号),避免渲染瞬间默认字号闪烁。
+ initFontSize();
initTheme();
updateCenterStore.bind();
diff --git a/src/components/SettingsModal.vue b/src/components/SettingsModal.vue
index 7cc55d35..f14110c8 100644
--- a/src/components/SettingsModal.vue
+++ b/src/components/SettingsModal.vue
@@ -163,6 +163,56 @@
+
+
+
+
+
+
+
+
+
+ 字体大小
+
+
+ 调整全局界面字体大小(仅字号)
+
+
+
+
+
+ 预览:星火应用商店 Spark Store 123
+
+
+
+
@@ -185,6 +235,12 @@ import {
setTagPriorityStrategy,
type TagPriorityStrategy,
} from "../global/tagPriority";
+import {
+ getFontSize,
+ setFontSize,
+ FONT_SIZE_OPTIONS,
+ type FontSizeOption,
+} from "../global/displaySettings";
const props = defineProps<{
show: boolean;
@@ -206,6 +262,9 @@ const strategyOptions: Array<{ value: TagPriorityStrategy; label: string }> = [
{ value: "apm", label: "APM 优先" },
];
+// 字体大小档位选项(小 / 标准 / 大 / 特大)
+const fontSizeOptions = FONT_SIZE_OPTIONS;
+
const tagPriorityStrategy = ref("auto");
// 加载标签优先显示策略(从持久化读取)
@@ -219,6 +278,19 @@ const selectStrategy = (value: TagPriorityStrategy) => {
setTagPriorityStrategy(value);
};
+// 字体大小档位(仅字号,不含整体缩放/字体族)
+const fontSize = ref("medium");
+
+const loadFontSize = () => {
+ fontSize.value = getFontSize();
+};
+
+// 选择并保存字号档位(立即应用到 html,全局 rem 字号类联动)
+const selectFontSize = (value: FontSizeOption) => {
+ fontSize.value = value;
+ setFontSize(value);
+};
+
const settings = ref({
enableUpdateCheck: true,
enableCreateDesktop: true,
@@ -279,6 +351,7 @@ watch(
if (newVal) {
loadSettings();
loadTagPriority();
+ loadFontSize();
}
},
);
diff --git a/src/global/displaySettings.ts b/src/global/displaySettings.ts
new file mode 100644
index 00000000..e34bcc71
--- /dev/null
+++ b/src/global/displaySettings.ts
@@ -0,0 +1,75 @@
+/**
+ * 显示设置:全局字体大小档位(仅字号,不含整体缩放/字体族)。
+ *
+ * 实现原理:Tailwind 4 的 `text-*` 字号类均为 rem 单位(如 text-sm = 0.875rem),
+ * 因此修改根元素 `html` 的 font-size 即可让全部 rem 字号类联动缩放。
+ * 取值范围:14px(小) ~ 18px(特大),默认 16px(标准)。
+ *
+ * 持久化:localStorage key = "spark-store-font-size",存档位枚举字符串。
+ */
+export type FontSizeOption = "small" | "medium" | "large" | "xlarge";
+
+interface FontSizeMeta {
+ /** 应用到 html 的 font-size(px) */
+ px: number;
+ label: string;
+}
+
+export const FONT_SIZE_OPTIONS: Array<{
+ value: FontSizeOption;
+ label: string;
+}> = [
+ { value: "small", label: "小" },
+ { value: "medium", label: "标准" },
+ { value: "large", label: "大" },
+ { value: "xlarge", label: "特大" },
+];
+
+// 各档位对应的根字号。medium 保持现状 16px,向上放大、向下略缩。
+const FONT_SIZE_MAP: Record = {
+ small: { px: 15, label: "小" },
+ medium: { px: 16, label: "标准" },
+ large: { px: 17, label: "大" },
+ xlarge: { px: 18, label: "特大" },
+};
+
+const FONT_SIZE_STORAGE_KEY = "spark-store-font-size";
+const DEFAULT_FONT_SIZE: FontSizeOption = "medium";
+
+const isValidFontSize = (v: unknown): v is FontSizeOption =>
+ typeof v === "string" && v in FONT_SIZE_MAP;
+
+/** 读取持久化的字号档位(无/非法时回退默认「标准」) */
+export const getFontSize = (): FontSizeOption => {
+ try {
+ const raw = localStorage.getItem(FONT_SIZE_STORAGE_KEY);
+ if (isValidFontSize(raw)) return raw;
+ } catch {
+ // localStorage 不可用时忽略,使用默认
+ }
+ return DEFAULT_FONT_SIZE;
+};
+
+/** 将字号档位应用到根元素 html(写入 inline font-size) */
+export const applyFontSize = (option: FontSizeOption): void => {
+ const meta = FONT_SIZE_MAP[option] ?? FONT_SIZE_MAP[DEFAULT_FONT_SIZE];
+ document.documentElement.style.fontSize = `${meta.px}px`;
+};
+
+/** 选择并持久化字号档位,同时立即应用 */
+export const setFontSize = (option: FontSizeOption): void => {
+ applyFontSize(option);
+ try {
+ localStorage.setItem(FONT_SIZE_STORAGE_KEY, option);
+ } catch {
+ // 持久化失败时仍已应用当前会话,忽略写入错误
+ }
+};
+
+/**
+ * 应用启动时初始化:从持久化恢复并使用,避免渲染瞬间闪烁。
+ * 应在 App.vue 的 onMounted 最前调用(与 initTagPriorityStrategy 同级)。
+ */
+export const initFontSize = (): void => {
+ applyFontSize(getFontSize());
+};
From 7b658e9dd1d2844f4b5b8dad87d111d2fd5503e3 Mon Sep 17 00:00:00 2001
From: xiyidaiwa
Date: Mon, 17 Aug 2026 23:15:18 +0800
Subject: [PATCH 2/6] =?UTF-8?q?fix(ui):=20=E5=B0=86=E5=9B=BA=E5=AE=9A=20px?=
=?UTF-8?q?=20=E5=AD=97=E5=8F=B7=E6=94=B9=E4=B8=BA=20rem=EF=BC=8C=E8=AE=A9?=
=?UTF-8?q?=E5=85=A8=E5=B1=80=E5=AD=97=E4=BD=93=E5=A4=A7=E5=B0=8F=E6=A1=A3?=
=?UTF-8?q?=E4=BD=8D=E7=94=9F=E6=95=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
用户反馈首页红框区域(横幅标题/副标题)没随字号档位变大。
原因是多处使用了 Tailwind 固定 px 任意值(text-[10px]/[11px]/[12px]/[13px]/[15px]),
它们不随 html font-size 缩放。统一替换为等效 rem 任意值:
10px → 0.625rem, 11px → 0.6875rem, 12px → 0.75rem, 13px → 0.8125rem, 15px → 0.9375rem
涉及 8 个 Vue 组件,保证字号档位全局联动(仍保持 16px 基准下的原视觉大小)。
vue-tsc 通过,打包成功;HomeView.vue 原有 emit 未使用 lint 错误未动。
---
debian/changelog | 2 +-
src/components/AppCard.vue | 16 +++++-----
src/components/HomeView.vue | 6 ++--
src/components/InstalledAppsModal.vue | 22 ++++++-------
src/components/RankingAppRow.vue | 9 +++---
src/components/SettingsModal.vue | 2 +-
src/components/SourceLabel.vue | 2 +-
src/components/WindowTitleBar.vue | 2 +-
.../update-center/UpdateCenterItem.vue | 31 +++++++++----------
9 files changed, 45 insertions(+), 47 deletions(-)
diff --git a/debian/changelog b/debian/changelog
index b78193f9..c79d5081 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-spark-store (5.3.0.2-test) UNRELEASED; urgency=medium
+spark-store (5.3.0.3-test) UNRELEASED; urgency=medium
* Initial release.
diff --git a/src/components/AppCard.vue b/src/components/AppCard.vue
index 82de7541..f5fdb567 100644
--- a/src/components/AppCard.vue
+++ b/src/components/AppCard.vue
@@ -39,20 +39,20 @@
SPARK/APM
Spark
APM
@@ -60,7 +60,7 @@
{{ formatDownloads(downloadCount) }}
@@ -72,7 +72,7 @@
{{ description || "\u00A0" }}
@@ -153,12 +153,10 @@ const formatDownloads = (n?: number): string => {
// 排名徽标配色(前 3 名金/银/铜,其余灰色)
const rankClass = computed(() => {
- if (props.rank === 1)
- return "bg-amber-400 text-white shadow-amber-400/40";
+ if (props.rank === 1) return "bg-amber-400 text-white shadow-amber-400/40";
if (props.rank === 2)
return "bg-slate-300 text-slate-700 shadow-slate-400/40";
- if (props.rank === 3)
- return "bg-amber-600 text-white shadow-amber-600/40";
+ if (props.rank === 3) return "bg-amber-600 text-white shadow-amber-600/40";
return "bg-slate-500/90 text-white shadow-slate-500/30";
});
diff --git a/src/components/HomeView.vue b/src/components/HomeView.vue
index 73f67d98..4909ce3c 100644
--- a/src/components/HomeView.vue
+++ b/src/components/HomeView.vue
@@ -62,7 +62,7 @@
storeFilter === "apm" ? "星火应用商店 (Amber PM)" : "星火应用商店"
}}
-
+
探索丰富的应用,发现更多精彩内容
@@ -108,12 +108,12 @@
{{ link.name }}
{{ link.more }}
diff --git a/src/components/InstalledAppsModal.vue b/src/components/InstalledAppsModal.vue
index ee3c6b41..4ce65a22 100644
--- a/src/components/InstalledAppsModal.vue
+++ b/src/components/InstalledAppsModal.vue
@@ -48,15 +48,15 @@
-
+
{{ apmCount }}
APM
@@ -80,15 +80,15 @@
-
+
{{ sparkCount }}
Spark
@@ -112,15 +112,15 @@
-
+
{{ totalCount }}
总数
@@ -259,7 +259,7 @@
:data-testid="
o === 'apm' ? 'origin-tag-apm' : 'origin-tag-spark'
"
- class="rounded-md px-2 py-0.5 text-[11px] font-semibold"
+ class="rounded-md px-2 py-0.5 text-[0.6875rem] font-semibold"
:class="
o === 'apm'
? 'bg-amber-100 text-amber-700 dark:bg-amber-500/20 dark:text-amber-400'
@@ -271,7 +271,7 @@
依赖项
diff --git a/src/components/RankingAppRow.vue b/src/components/RankingAppRow.vue
index 812dc5bf..c9fd378e 100644
--- a/src/components/RankingAppRow.vue
+++ b/src/components/RankingAppRow.vue
@@ -34,17 +34,17 @@
Spark
APM
{{ formatDownloads(downloadCount) }}
@@ -77,7 +77,8 @@ const iconFailed = ref(false);
const iconPath = computed(() => {
const arch = window.apm_store.arch || "amd64";
- const finalArch = props.app.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
+ const finalArch =
+ props.app.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
return `${APM_STORE_BASE_URL}/${finalArch}/${props.app.category}/${props.app.pkgname}/icon.png`;
});
diff --git a/src/components/SettingsModal.vue b/src/components/SettingsModal.vue
index f14110c8..c47219bf 100644
--- a/src/components/SettingsModal.vue
+++ b/src/components/SettingsModal.vue
@@ -206,7 +206,7 @@
预览:星火应用商店 Spark Store 123
diff --git a/src/components/SourceLabel.vue b/src/components/SourceLabel.vue
index bbbc060d..98c67018 100644
--- a/src/components/SourceLabel.vue
+++ b/src/components/SourceLabel.vue
@@ -8,7 +8,7 @@
"
>
星火应用商店
社区版
diff --git a/src/components/update-center/UpdateCenterItem.vue b/src/components/update-center/UpdateCenterItem.vue
index d7b81018..73bf4175 100644
--- a/src/components/update-center/UpdateCenterItem.vue
+++ b/src/components/update-center/UpdateCenterItem.vue
@@ -42,25 +42,25 @@
{{ item.displayName }}
{{ sourceLabel }}
已忽略
已锁定
将强制
@@ -83,19 +83,17 @@
v-if="item.ignored !== true && !task"
class="flex shrink-0 flex-col items-end gap-0.5"
>
- {{
- timeLabel
- }}
- {{ sizeLabel }}
+ {{ timeLabel }}
+ {{ sizeLabel }}
-
-
{{
+
+ {{
timeLabel
}}
- {{ sizeLabel }}
+ {{ sizeLabel }}
@@ -118,7 +116,7 @@
:class="forced ? 'translate-x-[16px]' : 'translate-x-[2px]'"
>
-
强制
+
强制
- 强制
+ 强制
= [
- { value: "small", label: "小" },
- { value: "medium", label: "标准" },
- { value: "large", label: "大" },
- { value: "xlarge", label: "特大" },
- { value: "xxlarge", label: "超大" },
-];
-
-// 各档位对应的根字号。medium 保持现状 16px,向上放大、向下略缩。
-const FONT_SIZE_MAP: Record = {
- small: { px: 15, label: "小" },
- medium: { px: 16, label: "标准" },
- large: { px: 17, label: "大" },
- xlarge: { px: 18, label: "特大" },
- xxlarge: { px: 20, label: "超大" },
-};
-
-const FONT_SIZE_STORAGE_KEY = "spark-store-font-size";
-const DEFAULT_FONT_SIZE: FontSizeOption = "medium";
-
-const isValidFontSize = (v: unknown): v is FontSizeOption =>
- typeof v === "string" && v in FONT_SIZE_MAP;
-
-/** 读取持久化的字号档位(无/非法时回退默认「标准」) */
-export const getFontSize = (): FontSizeOption => {
- try {
- const raw = localStorage.getItem(FONT_SIZE_STORAGE_KEY);
- if (isValidFontSize(raw)) return raw;
- } catch {
- // localStorage 不可用时忽略,使用默认
- }
- return DEFAULT_FONT_SIZE;
-};
-
-/** 将字号档位应用到根元素 html(写入 inline font-size) */
-export const applyFontSize = (option: FontSizeOption): void => {
- const meta = FONT_SIZE_MAP[option] ?? FONT_SIZE_MAP[DEFAULT_FONT_SIZE];
- document.documentElement.style.fontSize = `${meta.px}px`;
-};
-
-/** 选择并持久化字号档位,同时立即应用 */
-export const setFontSize = (option: FontSizeOption): void => {
- applyFontSize(option);
- try {
- localStorage.setItem(FONT_SIZE_STORAGE_KEY, option);
- } catch {
- // 持久化失败时仍已应用当前会话,忽略写入错误
- }
-};
-
-/**
- * 应用启动时初始化:从持久化恢复并使用,避免渲染瞬间闪烁。
- * 应在 App.vue 的 onMounted 最前调用(与 initTagPriorityStrategy 同级)。
- */
-export const initFontSize = (): void => {
- applyFontSize(getFontSize());
-};
-
-/* ------------------------------------------------------------------ *
- * 界面整体缩放(Electron webContents.setZoomFactor)
- *
- * 与「字体大小」正交:字号只改 html font-size(rem 字号类),
- * 而界面缩放会连图标、间距、布局一起等比放大/缩小(逻辑分辨率变化)。
* 实际缩放由主进程 setZoomFactor 执行;渲染端仅负责持久化档位偏好,
* 并在启动时把档位换算的系数通过 IPC 告知主进程。
- * ------------------------------------------------------------------ */
+ */
export type UiScaleOption = "90" | "100" | "110" | "125" | "150";
@@ -139,8 +63,8 @@ export const setUiScale = (option: UiScaleOption): void => {
/**
* 应用启动时初始化:从持久化恢复档位,并经 IPC 告知主进程应用缩放。
- * 需在 App.vue onMounted 调用(initFontSize 之后或同级均可),
- * 主进程 createWindow 阶段已自有兜底(默认 1),此处确保渲染端偏好生效。
+ * 需在 App.vue onMounted 调用,主进程 createWindow 阶段已自有兜底(默认 1),
+ * 此处确保渲染端偏好生效。
*/
export const initUiScale = async (): Promise => {
const factor = uiScaleToFactor(getUiScale());
From d0e6dc1b79136ac445671e765f7e821c11bb370b Mon Sep 17 00:00:00 2001
From: xiyidaiwa
Date: Tue, 18 Aug 2026 09:09:52 +0800
Subject: [PATCH 6/6] =?UTF-8?q?feat(build):=20=E6=9B=B4=E6=96=B0=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=E6=9E=84=E5=BB=BA=E8=84=9A=E6=9C=AC=E4=BB=A5=E5=90=8C?=
=?UTF-8?q?=E6=AD=A5=E5=BA=94=E7=94=A8=E5=86=85=E7=89=88=E6=9C=AC=E5=8F=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 为 electron-builder.yml 添加 extraMetadata.version 临时配置
- 实现打包完成后自动恢复 electron-builder.yml 文件
- 添加 trap 机制确保异常退出时也能正确恢复配置
- 清理旧的 electron-builder 产物避免内容污染
- 完善脚本注释说明版本同步机制和使用注意事项
---
scripts/test-build.sh | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/scripts/test-build.sh b/scripts/test-build.sh
index 8346bafe..2730ad1d 100755
--- a/scripts/test-build.sh
+++ b/scripts/test-build.sh
@@ -11,7 +11,12 @@
# 再运行一次 -> 5.2.1.2-test
#
# 注意:
-# - 此脚本仅用于本地测试,不会修改 package.json(electron-builder 的 dir 产物版本)。
+# - 此脚本仅用于本地测试,不会修改 package.json(其 version 为 semver 格式,
+# 而 deb 测试版本如 5.3.0.8-test 会被 electron-builder 拒绝)。
+# - 为保证打包后「关于」页面显示版本与 deb 版本一致,脚本会临时向
+# electron-builder.yml 追加 extraMetadata.version(electron-builder 会将其写入
+# app.asar 内的 package.json,Electron 的 app.getVersion() 即从中读取),
+# 打包完成后自动恢复,异常退出时由 trap 兜底恢复。
# - 每次运行都会改写 debian/changelog,属于未跟踪的工作区改动,按需自行还原。
# - 如需恢复正式版本,将 debian/changelog 顶部版本改回即可。
@@ -71,7 +76,33 @@ sed -i -E "1s/\\(${old_ver_esc}\\)/(${new_ver})/" "$CHANGELOG"
# Electron 二进制下载镜像(本机到 GitHub 不通,使用 npmmirror 镜像)
export ELECTRON_MIRROR="${ELECTRON_MIRROR:-https://registry.npmmirror.com/-/binary/electron/}"
+# 同步应用内版本号:临时向 electron-builder.yml 追加 extraMetadata.version。
+# electron-builder 会把它合并进 app.asar 内的 package.json,
+# 「关于」页面经 IPC 调用的 app.getVersion() 即读取该值。
+EB_YML="electron-builder.yml"
+EB_YML_BAK="${EB_YML}.bak-test-build"
+
+# 清理上次异常中断可能残留的 extraMetadata 块(追加内容始终位于文件末尾)
+if grep -q "^extraMetadata:" "$EB_YML"; then
+ echo "清理 $EB_YML 中残留的 extraMetadata 块"
+ sed -i '/^extraMetadata:/,$d' "$EB_YML"
+fi
+cp "$EB_YML" "$EB_YML_BAK"
+restore_eb_yml() {
+ mv -f "$EB_YML_BAK" "$EB_YML" 2>/dev/null || true
+}
+trap restore_eb_yml EXIT
+printf 'extraMetadata:\n version: "%s"\n' "$new_ver" >> "$EB_YML"
+
+# 清理旧的 electron-builder 产物,避免 release/ 下多个版本目录被 make install
+# 的 release/*/linux*-unpacked/* 通配一并拷入 deb,造成内容污染
+rm -rf release/
+
echo "开始测试打包(版本 ${new_ver})..."
dpkg-buildpackage -us -uc -b
+# 打包成功,立即恢复 electron-builder.yml 并解除 trap
+restore_eb_yml
+trap - EXIT
+
echo "完成。产物: ../spark-store_${new_ver}_amd64.deb"