feat: 为 macOS 适配无边框窗口圆角效果
新增 macOS 平台配置文件,修改平台检测逻辑,在 macOS 时给 html 加标记,调整 CSS 让 #app 绘制背景并裁切 8px 圆角,避免首帧方角闪烁,同时适配弹窗遮罩圆角。
This commit is contained in:
@@ -230,6 +230,11 @@ const { t } = useI18n()
|
|||||||
|
|
||||||
- 前端封装:`src/utils/window.ts`(`minimizeWindow` / `toggleMaximizeWindow` / `closeWindow` / `startDragging` 等),在非 Tauri 环境(浏览器)下自动空转。
|
- 前端封装:`src/utils/window.ts`(`minimizeWindow` / `toggleMaximizeWindow` / `closeWindow` / `startDragging` 等),在非 Tauri 环境(浏览器)下自动空转。
|
||||||
- 自定义标题栏依赖无边框窗口(`src-tauri/tauri.conf.json` 中 `decorations: false`),拖拽区域通过 `data-tauri-drag-region` 实现。
|
- 自定义标题栏依赖无边框窗口(`src-tauri/tauri.conf.json` 中 `decorations: false`),拖拽区域通过 `data-tauri-drag-region` 实现。
|
||||||
|
- **窗口圆角(8px)**:Windows 11 由系统 DWM 自动裁切;macOS 的无边框窗口系统不会裁圆角,因此:
|
||||||
|
- `src-tauri/tauri.macos.conf.json` 中把窗口设为 `transparent: true`(**Tauri 2.12.1+ 无需再开启 `macOSPrivateApi`**);
|
||||||
|
- `src/assets/main.css` 中在 `html.is-macos` 下把背景从 `<html>` 移到 `#app`,由 `#app` 裁出 8px 圆角,并让 `html`/`body` 透明以透出桌面;
|
||||||
|
- `src/main.ts` 在挂载前根据 UA 给 `<html>` 打上 `is-macos` 标记。
|
||||||
|
- ⚠️ 平台配置文件按 **JSON Merge Patch** 合并,且**数组整体替换**,因此 `tauri.macos.conf.json` 里必须完整重复 `app.windows` 的字段;**修改基础配置的窗口参数时,记得同步这份文件**。
|
||||||
- 相关权限在 `src-tauri/capabilities/default.json` 中声明(`core:window:*`、`updater:default`、`process:default` 等)。**新增窗口 / 插件 API 调用时需同步补充对应权限**,否则会报 `not allowed` 错误。
|
- 相关权限在 `src-tauri/capabilities/default.json` 中声明(`core:window:*`、`updater:default`、`process:default` 等)。**新增窗口 / 插件 API 调用时需同步补充对应权限**,否则会报 `not allowed` 错误。
|
||||||
|
|
||||||
### 发布与自动更新
|
### 发布与自动更新
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
|
"app": {
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"title": "Frpilot",
|
||||||
|
"width": 1100,
|
||||||
|
"height": 720,
|
||||||
|
"minWidth": 900,
|
||||||
|
"minHeight": 600,
|
||||||
|
"decorations": false,
|
||||||
|
"transparent": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
-12
@@ -11,28 +11,35 @@ body,
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* 窗口背景色与渐变(供 html / #app 复用,避免重复定义) */
|
||||||
* 背景统一绘制在 <html> 上:
|
:root {
|
||||||
* 根元素的背景会被绘制到整个画布(canvas)上,铺满窗口的每一个像素,
|
--app-bg-color: #eef2ff;
|
||||||
* 不会出现“元素高度(100vh) 与实际窗口差几个像素”导致的上下留白。
|
--app-bg-gradient:
|
||||||
*/
|
|
||||||
html {
|
|
||||||
background-color: #eef2ff;
|
|
||||||
background-image:
|
|
||||||
radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.28), transparent 60%),
|
radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.28), transparent 60%),
|
||||||
radial-gradient(1000px 500px at 110% 10%, rgba(34, 211, 238, 0.28), transparent 55%),
|
radial-gradient(1000px 500px at 110% 10%, rgba(34, 211, 238, 0.28), transparent 55%),
|
||||||
linear-gradient(160deg, #eef2ff 0%, #f8fafc 45%, #eef7ff 100%);
|
linear-gradient(160deg, #eef2ff 0%, #f8fafc 45%, #eef7ff 100%);
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
background-color: #0b1220;
|
--app-bg-color: #0b1220;
|
||||||
background-image:
|
--app-bg-gradient:
|
||||||
radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.35), transparent 60%),
|
radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.35), transparent 60%),
|
||||||
radial-gradient(1000px 500px at 110% 10%, rgba(14, 165, 233, 0.28), transparent 55%),
|
radial-gradient(1000px 500px at 110% 10%, rgba(14, 165, 233, 0.28), transparent 55%),
|
||||||
linear-gradient(160deg, #0b1220 0%, #0f172a 45%, #111827 100%);
|
linear-gradient(160deg, #0b1220 0%, #0f172a 45%, #111827 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 默认(Windows / Linux):背景绘制在 <html> 上。
|
||||||
|
* 根元素的背景会被绘制到整个画布(canvas)上,铺满窗口的每一个像素,
|
||||||
|
* 不会出现“元素高度(100vh) 与实际窗口差几个像素”导致的上下留白;
|
||||||
|
* 窗口圆角交给系统裁切(Windows 11 的 DWM 默认就是 8px 圆角)。
|
||||||
|
*/
|
||||||
|
html {
|
||||||
|
background-color: var(--app-bg-color);
|
||||||
|
background-image: var(--app-bg-gradient);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
/* 选中自定义背景图时替换为图片:等比缩放铺满,不拉伸变形 */
|
/* 选中自定义背景图时替换为图片:等比缩放铺满,不拉伸变形 */
|
||||||
html.has-bg-image {
|
html.has-bg-image {
|
||||||
background-image: var(--app-bg-image, none);
|
background-image: var(--app-bg-image, none);
|
||||||
@@ -41,11 +48,44 @@ html.has-bg-image {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* macOS:无边框窗口系统不会自动裁圆角(不像 Windows 11 的 DWM),
|
||||||
|
* 因此通过 tauri.macos.conf.json 开启 transparent 窗口,
|
||||||
|
* 再把背景从 <html> 移到 #app 上并由 #app 裁出 8px 圆角,
|
||||||
|
* html/body 保持完全透明,让圆角之外的区域透出桌面壁纸。
|
||||||
|
*/
|
||||||
|
html.is-macos,
|
||||||
|
html.is-macos body {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.is-macos #app {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--app-bg-color);
|
||||||
|
background-image: var(--app-bg-gradient);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.is-macos.has-bg-image #app {
|
||||||
|
background-image: var(--app-bg-image, none);
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全屏遮罩跟随窗口圆角,避免弹窗打开时遮罩把圆角「填方」 */
|
||||||
|
html.is-macos .ant-modal-mask {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-family: 'Inter', 'HarmonyOS Sans SC', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif;
|
font-family: 'Inter', 'HarmonyOS Sans SC', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
/* 背景交由 <html> 绘制,body 保持透明避免覆盖画布背景 */
|
/* 背景交由 <html>(或 macOS 下的 #app)绘制,body 保持透明避免覆盖画布背景 */
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,17 @@ export type Platform = "windows" | "macos" | "linux" | "unknown"
|
|||||||
* 判断当前运行的操作系统类型。
|
* 判断当前运行的操作系统类型。
|
||||||
* 通过 navigator.userAgent 推断,避免额外引入 @tauri-apps/plugin-os。
|
* 通过 navigator.userAgent 推断,避免额外引入 @tauri-apps/plugin-os。
|
||||||
*/
|
*/
|
||||||
export function usePlatform() {
|
export function detectPlatform(): Platform {
|
||||||
const ua = (navigator.userAgent || "").toLowerCase()
|
const ua = (navigator.userAgent || "").toLowerCase()
|
||||||
|
if (ua.includes("mac") || ua.includes("darwin")) return "macos"
|
||||||
|
if (ua.includes("win")) return "windows"
|
||||||
|
if (ua.includes("linux") || ua.includes("x11")) return "linux"
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
const platform = computed<Platform>(() => {
|
/** 在组件中响应式地获取当前平台 */
|
||||||
if (ua.includes("mac") || ua.includes("darwin")) return "macos"
|
export function usePlatform() {
|
||||||
if (ua.includes("win")) return "windows"
|
const platform = ref<Platform>(detectPlatform())
|
||||||
if (ua.includes("linux") || ua.includes("x11")) return "linux"
|
|
||||||
return "unknown"
|
|
||||||
})
|
|
||||||
|
|
||||||
const isMac = computed(() => platform.value === "macos")
|
const isMac = computed(() => platform.value === "macos")
|
||||||
const isWindows = computed(() => platform.value === "windows")
|
const isWindows = computed(() => platform.value === "windows")
|
||||||
|
|||||||
+10
@@ -9,6 +9,16 @@ import "ant-design-vue/dist/reset.css"
|
|||||||
import router from "@/router/router"
|
import router from "@/router/router"
|
||||||
// 引入国际化
|
// 引入国际化
|
||||||
import i18n from "@/i18n"
|
import i18n from "@/i18n"
|
||||||
|
import { detectPlatform } from "@/composables/usePlatform"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* macOS 的无边框窗口系统不会自动裁圆角,需要配合 transparent 窗口,
|
||||||
|
* 由 #app 自身裁出 8px 圆角(见 assets/main.css)。这里在挂载前打上平台标记,
|
||||||
|
* 避免首帧出现方角闪烁。
|
||||||
|
*/
|
||||||
|
if (detectPlatform() === "macos") {
|
||||||
|
document.documentElement.classList.add("is-macos")
|
||||||
|
}
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.use(createPinia())
|
app.use(createPinia())
|
||||||
|
|||||||
Reference in New Issue
Block a user