diff --git a/package.json b/package.json index beb5c14..909ddc5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frpilot", "private": true, - "version": "1.1.0", + "version": "1.2.0", "type": "module", "scripts": { "dev": "vite", diff --git a/src/assets/main.css b/src/assets/main.css index 1542499..a1d9060 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -13,6 +13,12 @@ body, /* 窗口背景色与渐变(供 html / #app 复用,避免重复定义) */ :root { + /* 全局文字颜色:普通 HTML 文本继承使用(Antd 组件由 CSS-in-JS 自行着色,不受影响) */ + --app-text-color: rgba(15, 23, 42, 0.88); + /* 磨砂玻璃透明度:由「外观设置」实时写入 ,默认值与初始外观保持一致 */ + --app-card-alpha: 0.45; + --app-card-alpha-hover: 0.62; + --app-modal-alpha: 0.62; --app-bg-color: #eef2ff; --app-bg-gradient: radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.28), transparent 60%), @@ -21,6 +27,7 @@ body, } html.dark { + --app-text-color: rgba(226, 232, 240, 0.92); --app-bg-color: #0b1220; --app-bg-gradient: radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.35), transparent 60%), @@ -85,6 +92,8 @@ body { overflow: hidden; font-family: 'Inter', 'HarmonyOS Sans SC', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif; -webkit-font-smoothing: antialiased; + /* 文字颜色跟随明暗主题,避免暗色下普通文本仍是浏览器默认黑色 */ + color: var(--app-text-color); /* 背景交由 (或 macOS 下的 #app)绘制,body 保持透明避免覆盖画布背景 */ background-color: transparent; } @@ -112,7 +121,7 @@ body { .glass-panel { border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.55); - background: rgba(255, 255, 255, 0.45); + background: rgba(255, 255, 255, var(--app-card-alpha)); backdrop-filter: blur(18px) saturate(160%); -webkit-backdrop-filter: blur(18px) saturate(160%); box-shadow: 0 8px 32px rgba(15, 23, 42, 0.12); @@ -120,7 +129,7 @@ body { .dark .glass-panel { border-color: rgba(255, 255, 255, 0.08); - background: rgba(15, 23, 42, 0.45); + background: rgba(15, 23, 42, var(--app-card-alpha)); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); } @@ -131,7 +140,7 @@ body { */ .glass-card.ant-card { border: 1px solid rgba(255, 255, 255, 0.5) !important; - background: rgba(255, 255, 255, 0.45) !important; + background: rgba(255, 255, 255, var(--app-card-alpha)) !important; 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; @@ -140,19 +149,19 @@ body { .glass-card.ant-card:hover { border-color: rgba(99, 102, 241, 0.45) !important; - background: rgba(255, 255, 255, 0.62) !important; + background: rgba(255, 255, 255, var(--app-card-alpha-hover)) !important; box-shadow: 0 10px 28px rgba(15, 23, 42, 0.14) !important; } .dark .glass-card.ant-card { border-color: rgba(255, 255, 255, 0.1) !important; - background: rgba(30, 41, 59, 0.5) !important; + background: rgba(30, 41, 59, var(--app-card-alpha)) !important; box-shadow: 0 6px 22px rgba(0, 0, 0, 0.35) !important; } .dark .glass-card.ant-card:hover { border-color: rgba(129, 140, 248, 0.5) !important; - background: rgba(30, 41, 59, 0.62) !important; + background: rgba(30, 41, 59, var(--app-card-alpha-hover)) !important; box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45) !important; } @@ -172,7 +181,7 @@ body { max-height: 80vh; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.55); - background: rgba(255, 255, 255, 0.62) !important; + background: rgba(255, 255, 255, var(--app-modal-alpha)) !important; backdrop-filter: blur(24px) saturate(170%); -webkit-backdrop-filter: blur(24px) saturate(170%); box-shadow: 0 16px 48px rgba(15, 23, 42, 0.18) !important; @@ -187,7 +196,7 @@ body { .dark .form-modal-wrap .ant-modal-content { border-color: rgba(255, 255, 255, 0.1); - background: rgba(30, 41, 59, 0.62) !important; + background: rgba(30, 41, 59, var(--app-modal-alpha)) !important; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5) !important; } @@ -217,7 +226,7 @@ body { max-height: 60vh; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.55); - background: rgba(255, 255, 255, 0.72) !important; + background: rgba(255, 255, 255, var(--app-modal-alpha)) !important; backdrop-filter: blur(24px) saturate(170%); -webkit-backdrop-filter: blur(24px) saturate(170%); box-shadow: 0 16px 48px rgba(15, 23, 42, 0.18) !important; @@ -232,7 +241,7 @@ body { .dark .update-modal-wrap .ant-modal-content { border-color: rgba(255, 255, 255, 0.1); - background: rgba(30, 41, 59, 0.72) !important; + background: rgba(30, 41, 59, var(--app-modal-alpha)) !important; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5) !important; } diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 7e7e69e..8245d97 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -94,7 +94,12 @@ "bg6": "Background 6", "bg7": "Background 7", "bg8": "Background 8", - "bg9": "Background 9" + "bg9": "Background 9", + "glass": "Glass transparency", + "glassTip": "Drag the sliders to adjust how transparent the cards and dialogs are. Higher values are more transparent.", + "cardTransparency": "Card transparency", + "modalTransparency": "Dialog transparency", + "previewTip": "Top preview shows cards, bottom shows dialogs — drag a slider to preview live." } }, "server": { diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 6f84a01..4be45c3 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -94,7 +94,12 @@ "bg6": "背景六", "bg7": "背景七", "bg8": "背景八", - "bg9": "背景九" + "bg9": "背景九", + "glass": "磨砂玻璃透明度", + "glassTip": "拖动滑块调整卡片与弹窗背景的透明程度,数值越大越透明", + "cardTransparency": "卡片透明度", + "modalTransparency": "弹窗透明度", + "previewTip": "上方为卡片效果,下方为弹窗效果,可拖动滑块实时预览" } }, "server": { diff --git a/src/stores/app.ts b/src/stores/app.ts index 156efdc..3c6e423 100644 --- a/src/stores/app.ts +++ b/src/stores/app.ts @@ -45,6 +45,27 @@ export const useAppStore = defineStore("app", () => { } }) + // 磨砂玻璃透明度(0 - 100,数值越大越透明,持久化) + const cardTransparency = useStorage("frpilot:card-transparency", 55) + const modalTransparency = useStorage("frpilot:modal-transparency", 38) + + /** 透明度百分比 → 背景 alpha(越大越透明,alpha 越小;并做范围兜底) */ + function alphaFromTransparency(value: number) { + const percent = Math.min(100, Math.max(0, Number(value) || 0)) + return (100 - percent) / 100 + } + + const cardAlpha = computed(() => alphaFromTransparency(cardTransparency.value)) + const modalAlpha = computed(() => alphaFromTransparency(modalTransparency.value)) + + // 把透明度实时写入 的 CSS 变量,供磨砂玻璃样式(卡片 / 弹窗)即时生效 + watchEffect(() => { + const root = document.documentElement + root.style.setProperty("--app-card-alpha", String(cardAlpha.value)) + root.style.setProperty("--app-card-alpha-hover", String(Math.min(cardAlpha.value + 0.15, 0.95))) + root.style.setProperty("--app-modal-alpha", String(modalAlpha.value)) + }) + // Frpc 运行状态(后续由后端驱动) const runStatus = ref("stopped") @@ -76,6 +97,8 @@ export const useAppStore = defineStore("app", () => { toggleDark, background, backgroundUrl, + cardTransparency, + modalTransparency, runStatus, antdLocale, setLanguage, diff --git a/src/types/components.d.ts b/src/types/components.d.ts index fe06106..192db3f 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -36,6 +36,7 @@ declare module 'vue' { ARow: typeof import('ant-design-vue/es')['Row'] ASegmented: typeof import('ant-design-vue/es')['Segmented'] ASelect: typeof import('ant-design-vue/es')['Select'] + ASlider: typeof import('ant-design-vue/es')['Slider'] ASpace: typeof import('ant-design-vue/es')['Space'] ASpin: typeof import('ant-design-vue/es')['Spin'] AStatistic: typeof import('ant-design-vue/es')['Statistic'] diff --git a/src/views/setting/Appearance.vue b/src/views/setting/Appearance.vue index 4386b22..f84e629 100644 --- a/src/views/setting/Appearance.vue +++ b/src/views/setting/Appearance.vue @@ -33,6 +33,37 @@ + + + + +
+
{{ t("settings.appearance.glass") }}
+

{{ t("settings.appearance.glassTip") }}

+ +
+
+ {{ t("settings.appearance.cardTransparency") }} + {{ appStore.cardTransparency }}% +
+ +
+ +
+
+ {{ t("settings.appearance.modalTransparency") }} + {{ appStore.modalTransparency }}% +
+ +
+ + + +

{{ t("settings.appearance.previewTip") }}

+
@@ -105,4 +136,45 @@ function selectBackground(key: BackgroundKey) { rgba(148, 163, 184, 0.25) 0 8px, transparent 8px 16px); } + +/* 透明度实时预览:纯色底图(暖调中性色,不用渐变)+ 卡片 / 弹窗两种磨砂效果 */ +.glass-preview { + display: flex; + flex-direction: column; + gap: 12px; + padding: 14px; + border-radius: 12px; + background-color: #a09adf; +} + +.dark .glass-preview { + background-color: #a09adf; +} + +.glass-preview-card, +.glass-preview-modal { + border: 1px solid rgba(255, 255, 255, 0.5); + backdrop-filter: blur(10px) saturate(160%); + -webkit-backdrop-filter: blur(10px) saturate(160%); +} + +.glass-preview-card { + height: 48px; + border-radius: 12px; + background: rgba(255, 255, 255, var(--app-card-alpha)); +} + +.glass-preview-modal { + height: 48px; + border-radius: 10px; + background: rgba(255, 255, 255, var(--app-modal-alpha)); +} + +.dark .glass-preview-card { + background: rgba(30, 41, 59, var(--app-card-alpha)); +} + +.dark .glass-preview-modal { + background: rgba(30, 41, 59, var(--app-modal-alpha)); +}