mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-09-20 21:50:11 +08:00
feat(settings): 新增字体大小设置(仅字号档位,不含整体缩放/字体族)
- 新增 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/打包均通过
This commit is contained in:
Vendored
+1
-1
@@ -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.
|
* Initial release.
|
||||||
|
|
||||||
|
|||||||
@@ -344,6 +344,7 @@ import ReviewUserProfileModal from "./components/ReviewUserProfileModal.vue";
|
|||||||
import WindowTitleBar from "./components/WindowTitleBar.vue";
|
import WindowTitleBar from "./components/WindowTitleBar.vue";
|
||||||
import SubmitterWindow from "./components/SubmitterWindow.vue";
|
import SubmitterWindow from "./components/SubmitterWindow.vue";
|
||||||
import { initTagPriorityStrategy } from "./global/tagPriority";
|
import { initTagPriorityStrategy } from "./global/tagPriority";
|
||||||
|
import { initFontSize } from "./global/displaySettings";
|
||||||
import {
|
import {
|
||||||
FLARUM_BASE_URL,
|
FLARUM_BASE_URL,
|
||||||
FLARUM_REGISTER_URL,
|
FLARUM_REGISTER_URL,
|
||||||
@@ -1052,6 +1053,8 @@ onMounted(async () => {
|
|||||||
// 应用启动即锁定标签优先显示策略的真实持久化值,避免依赖详情页挂载顺序
|
// 应用启动即锁定标签优先显示策略的真实持久化值,避免依赖详情页挂载顺序
|
||||||
// 导致先读到内存默认值 "auto" 再懒加载的竞态窗口。
|
// 导致先读到内存默认值 "auto" 再懒加载的竞态窗口。
|
||||||
initTagPriorityStrategy();
|
initTagPriorityStrategy();
|
||||||
|
// 恢复并应用持久化的字体大小档位(仅字号),避免渲染瞬间默认字号闪烁。
|
||||||
|
initFontSize();
|
||||||
initTheme();
|
initTheme();
|
||||||
updateCenterStore.bind();
|
updateCenterStore.bind();
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,56 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 字体大小(字号档位:小 / 标准 / 大 / 特大) -->
|
||||||
|
<div
|
||||||
|
class="rounded-2xl border border-slate-200/60 bg-slate-50/50 px-4 py-4 dark:border-slate-800/60 dark:bg-slate-800/50"
|
||||||
|
>
|
||||||
|
<div class="flex items-start gap-3">
|
||||||
|
<div
|
||||||
|
class="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl bg-pink-100 text-pink-600 dark:bg-pink-900/30 dark:text-pink-400"
|
||||||
|
>
|
||||||
|
<i class="fas fa-font"></i>
|
||||||
|
</div>
|
||||||
|
<div class="min-w-0 flex-1">
|
||||||
|
<p
|
||||||
|
class="text-sm font-medium text-slate-800 dark:text-slate-200"
|
||||||
|
>
|
||||||
|
字体大小
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-slate-500 dark:text-slate-400">
|
||||||
|
调整全局界面字体大小(仅字号)
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="mt-3 inline-flex w-full overflow-hidden rounded-lg border border-slate-200 dark:border-slate-700"
|
||||||
|
role="radiogroup"
|
||||||
|
aria-label="字体大小"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-for="opt in fontSizeOptions"
|
||||||
|
:key="opt.value"
|
||||||
|
type="button"
|
||||||
|
role="radio"
|
||||||
|
:aria-checked="fontSize === opt.value"
|
||||||
|
class="flex-1 px-2 py-1.5 text-xs font-medium transition-colors"
|
||||||
|
:class="
|
||||||
|
fontSize === opt.value
|
||||||
|
? 'bg-brand text-white'
|
||||||
|
: 'bg-white text-slate-500 hover:bg-slate-100 dark:bg-slate-700 dark:text-slate-400 dark:hover:bg-slate-600'
|
||||||
|
"
|
||||||
|
@click="selectFontSize(opt.value)"
|
||||||
|
>
|
||||||
|
{{ opt.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="mt-2 text-[11px] text-slate-400 dark:text-slate-500"
|
||||||
|
>
|
||||||
|
预览:星火应用商店 Spark Store 123
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部提示 -->
|
<!-- 底部提示 -->
|
||||||
@@ -185,6 +235,12 @@ import {
|
|||||||
setTagPriorityStrategy,
|
setTagPriorityStrategy,
|
||||||
type TagPriorityStrategy,
|
type TagPriorityStrategy,
|
||||||
} from "../global/tagPriority";
|
} from "../global/tagPriority";
|
||||||
|
import {
|
||||||
|
getFontSize,
|
||||||
|
setFontSize,
|
||||||
|
FONT_SIZE_OPTIONS,
|
||||||
|
type FontSizeOption,
|
||||||
|
} from "../global/displaySettings";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
show: boolean;
|
show: boolean;
|
||||||
@@ -206,6 +262,9 @@ const strategyOptions: Array<{ value: TagPriorityStrategy; label: string }> = [
|
|||||||
{ value: "apm", label: "APM 优先" },
|
{ value: "apm", label: "APM 优先" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 字体大小档位选项(小 / 标准 / 大 / 特大)
|
||||||
|
const fontSizeOptions = FONT_SIZE_OPTIONS;
|
||||||
|
|
||||||
const tagPriorityStrategy = ref<TagPriorityStrategy>("auto");
|
const tagPriorityStrategy = ref<TagPriorityStrategy>("auto");
|
||||||
|
|
||||||
// 加载标签优先显示策略(从持久化读取)
|
// 加载标签优先显示策略(从持久化读取)
|
||||||
@@ -219,6 +278,19 @@ const selectStrategy = (value: TagPriorityStrategy) => {
|
|||||||
setTagPriorityStrategy(value);
|
setTagPriorityStrategy(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 字体大小档位(仅字号,不含整体缩放/字体族)
|
||||||
|
const fontSize = ref<FontSizeOption>("medium");
|
||||||
|
|
||||||
|
const loadFontSize = () => {
|
||||||
|
fontSize.value = getFontSize();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择并保存字号档位(立即应用到 html,全局 rem 字号类联动)
|
||||||
|
const selectFontSize = (value: FontSizeOption) => {
|
||||||
|
fontSize.value = value;
|
||||||
|
setFontSize(value);
|
||||||
|
};
|
||||||
|
|
||||||
const settings = ref<Settings>({
|
const settings = ref<Settings>({
|
||||||
enableUpdateCheck: true,
|
enableUpdateCheck: true,
|
||||||
enableCreateDesktop: true,
|
enableCreateDesktop: true,
|
||||||
@@ -279,6 +351,7 @@ watch(
|
|||||||
if (newVal) {
|
if (newVal) {
|
||||||
loadSettings();
|
loadSettings();
|
||||||
loadTagPriority();
|
loadTagPriority();
|
||||||
|
loadFontSize();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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<FontSizeOption, FontSizeMeta> = {
|
||||||
|
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());
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user