refactor(App): 移除窗口控制按钮并重构标题栏结构
- 移除 src-tauri/capabilities/default.json 中的 core🪟allow-toggle-maximize 权限
- 从 App.vue 中移除自定义标题栏实现,包括拖拽区域和窗口控制按钮
- 移除与窗口控制相关的函数(minimizeWindow、toggleMaximizeWindow、closeWindow 等)
- 移除标题栏相关样式和 CSS 类
- 新增独立的 WindowTitlebar 组件来处理窗口控制功能
- 在 MainLayout.vue 中集成新的 WindowTitlebar 组件
- 调整布局结构以支持新的标题栏组件
- 更新全局样式变量,添加 --playerbar-height 变量
- 移除 DiscoverView.vue 中未使用的分类头部元素
- 在 SettingsView.vue 中导入 computed 函数
此重构简化了主应用组件,并将窗口控制功能分离到专用组件中,
提高了代码的模块化程度和可维护性。
This commit is contained in:
parent
5bed7cd4cb
commit
cc2fdfa04f
|
|
@ -9,7 +9,6 @@
|
|||
"core:window:allow-start-dragging",
|
||||
"core:window:allow-close",
|
||||
"core:window:allow-minimize",
|
||||
"core:window:allow-toggle-maximize",
|
||||
"opener:default",
|
||||
"store:default"
|
||||
]
|
||||
|
|
|
|||
205
src/App.vue
205
src/App.vue
|
|
@ -1,36 +1,15 @@
|
|||
<template>
|
||||
<div class="app-root">
|
||||
<div class="titlebar" :class="{ 'titlebar-macos': isMacos }">
|
||||
<div class="titlebar-drag" data-tauri-drag-region @mousedown="handleTitlebarMouseDown">
|
||||
<span class="titlebar-dot"></span>
|
||||
<span class="titlebar-title">YwYMusic</span>
|
||||
</div>
|
||||
|
||||
<div class="titlebar-controls">
|
||||
<button type="button" aria-label="最小化" @click="minimizeWindow">
|
||||
<span class="window-icon window-icon-minimize"></span>
|
||||
</button>
|
||||
<button type="button" aria-label="最大化或还原" @click="toggleMaximizeWindow">
|
||||
<span class="window-icon window-icon-maximize"></span>
|
||||
</button>
|
||||
<button type="button" class="titlebar-close" aria-label="关闭" @click="closeWindow">
|
||||
<span class="window-icon window-icon-close"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<n-config-provider :theme-overrides="themeOverrides">
|
||||
<n-message-provider>
|
||||
<n-notification-provider>
|
||||
<n-dialog-provider>
|
||||
<div class="app-content">
|
||||
<RouterView />
|
||||
</div>
|
||||
</n-dialog-provider>
|
||||
</n-notification-provider>
|
||||
</n-message-provider>
|
||||
</n-config-provider>
|
||||
</div>
|
||||
<n-config-provider :theme-overrides="themeOverrides">
|
||||
<n-message-provider>
|
||||
<n-notification-provider>
|
||||
<n-dialog-provider>
|
||||
<div class="app-root">
|
||||
<RouterView />
|
||||
</div>
|
||||
</n-dialog-provider>
|
||||
</n-notification-provider>
|
||||
</n-message-provider>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
@ -41,12 +20,8 @@ import {
|
|||
NNotificationProvider,
|
||||
type GlobalThemeOverrides,
|
||||
} from "naive-ui";
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import { RouterView } from "vue-router";
|
||||
|
||||
const appWindow = getCurrentWindow();
|
||||
const isMacos = navigator.userAgent.includes("Mac OS X");
|
||||
|
||||
const themeOverrides: GlobalThemeOverrides = {
|
||||
common: {
|
||||
primaryColor: "#b4532a",
|
||||
|
|
@ -75,168 +50,12 @@ const themeOverrides: GlobalThemeOverrides = {
|
|||
"'Inter','HarmonyOS Sans SC','PingFang SC','Microsoft YaHei',system-ui,-apple-system,sans-serif",
|
||||
},
|
||||
};
|
||||
|
||||
function minimizeWindow() {
|
||||
void appWindow.minimize();
|
||||
}
|
||||
|
||||
function toggleMaximizeWindow() {
|
||||
void appWindow.toggleMaximize();
|
||||
}
|
||||
|
||||
function closeWindow() {
|
||||
void appWindow.close();
|
||||
}
|
||||
|
||||
function handleTitlebarMouseDown(event: MouseEvent) {
|
||||
if (event.detail === 2) {
|
||||
void appWindow.toggleMaximize();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-root {
|
||||
height: 100%;
|
||||
padding-top: var(--titlebar-height);
|
||||
min-height: 0;
|
||||
background: var(--app-bg);
|
||||
}
|
||||
|
||||
.titlebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
height: var(--titlebar-height);
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
background: rgba(234, 220, 200, 0.86);
|
||||
border-bottom: 1px solid rgba(180, 83, 42, 0.12);
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.titlebar-drag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
gap: 8px;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.titlebar-macos {
|
||||
background: rgba(244, 237, 223, 0.72);
|
||||
}
|
||||
|
||||
.titlebar-macos .titlebar-drag {
|
||||
padding-left: 78px;
|
||||
}
|
||||
|
||||
.titlebar-macos .titlebar-controls,
|
||||
.titlebar-macos .titlebar-dot {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.titlebar-macos .titlebar-title {
|
||||
color: var(--app-text-muted);
|
||||
}
|
||||
|
||||
.titlebar-dot {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(135deg, #d98b5f 0%, var(--app-primary) 100%);
|
||||
box-shadow: 0 0 0 3px rgba(180, 83, 42, 0.12);
|
||||
}
|
||||
|
||||
.titlebar-title {
|
||||
color: var(--app-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.titlebar-controls {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.titlebar-controls button {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 46px;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
color: var(--app-text-secondary);
|
||||
background: transparent;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
color 0.15s ease,
|
||||
background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.titlebar-controls button:hover {
|
||||
color: var(--app-text);
|
||||
background: rgba(180, 83, 42, 0.1);
|
||||
}
|
||||
|
||||
.titlebar-controls .titlebar-close:hover {
|
||||
color: #fffaf0;
|
||||
background: #d83b32;
|
||||
}
|
||||
|
||||
.window-icon {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.window-icon-minimize::before,
|
||||
.window-icon-maximize::before,
|
||||
.window-icon-close::before,
|
||||
.window-icon-close::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.window-icon-minimize::before {
|
||||
right: 1px;
|
||||
bottom: 3px;
|
||||
left: 1px;
|
||||
height: 1.5px;
|
||||
background: currentColor;
|
||||
}
|
||||
|
||||
.window-icon-maximize::before {
|
||||
inset: 1px;
|
||||
border: 1.5px solid currentColor;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.window-icon-close::before,
|
||||
.window-icon-close::after {
|
||||
top: 5px;
|
||||
left: 0;
|
||||
width: 12px;
|
||||
height: 1.5px;
|
||||
background: currentColor;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.window-icon-close::before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.window-icon-close::after {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.app-content {
|
||||
height: calc(100vh - var(--titlebar-height));
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ onUnmounted(() => {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: clamp(12px, 2vw, 20px);
|
||||
height: clamp(72px, 9vh, 88px);
|
||||
height: 100%;
|
||||
padding: 0 clamp(14px, 2vw, 22px);
|
||||
flex-shrink: 0;
|
||||
background: rgba(255, 250, 240, 0.94);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
<template>
|
||||
<header class="window-titlebar" :class="{ 'window-titlebar--macos': isMacos }">
|
||||
<div class="window-titlebar__drag" data-tauri-drag-region>
|
||||
<!-- <span class="window-titlebar__dot"></span> -->
|
||||
<span class="window-titlebar__title">YwYMusic</span>
|
||||
</div>
|
||||
|
||||
<div class="window-titlebar__controls">
|
||||
<n-button
|
||||
class="window-titlebar__control"
|
||||
quaternary
|
||||
:bordered="false"
|
||||
aria-label="最小化"
|
||||
@click.stop="minimizeWindow"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="MinimizeOutlined" :size="18" />
|
||||
</template>
|
||||
</n-button>
|
||||
|
||||
<n-button
|
||||
class="window-titlebar__control window-titlebar__control--close"
|
||||
quaternary
|
||||
:bordered="false"
|
||||
aria-label="关闭"
|
||||
@click.stop="closeWindow"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="CloseOutlined" :size="18" />
|
||||
</template>
|
||||
</n-button>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window"
|
||||
import { NButton, NIcon } from "naive-ui"
|
||||
import { CloseOutlined, MinimizeOutlined } from "@vicons/material"
|
||||
|
||||
const appWindow = getCurrentWindow()
|
||||
const isMacos = navigator.userAgent.includes("Mac OS X")
|
||||
|
||||
function minimizeWindow() {
|
||||
void appWindow.minimize()
|
||||
}
|
||||
|
||||
function closeWindow() {
|
||||
void appWindow.close()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.window-titlebar {
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
height: var(--titlebar-height);
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
background: rgba(234, 220, 200, 0.86);
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.window-titlebar__drag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
gap: 8px;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.window-titlebar__dot {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(135deg, #d98b5f 0%, var(--app-primary) 100%);
|
||||
box-shadow: 0 0 0 3px rgba(180, 83, 42, 0.12);
|
||||
}
|
||||
|
||||
.window-titlebar__title {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: var(--app-text-secondary);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.window-titlebar__controls {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.window-titlebar__control {
|
||||
width: 46px;
|
||||
height: var(--titlebar-height);
|
||||
--n-border-radius: 0 !important;
|
||||
--n-color-hover: rgba(180, 83, 42, 0.1) !important;
|
||||
--n-color-pressed: rgba(180, 83, 42, 0.16) !important;
|
||||
--n-text-color: var(--app-text-secondary) !important;
|
||||
--n-text-color-hover: var(--app-text) !important;
|
||||
--n-text-color-pressed: var(--app-text) !important;
|
||||
}
|
||||
|
||||
.window-titlebar__control--close {
|
||||
--n-color-hover: #d83b32 !important;
|
||||
--n-color-pressed: #c43129 !important;
|
||||
--n-text-color-hover: #fffaf0 !important;
|
||||
--n-text-color-pressed: #fffaf0 !important;
|
||||
}
|
||||
|
||||
.window-titlebar--macos {
|
||||
background: rgba(244, 237, 223, 0.72);
|
||||
}
|
||||
|
||||
.window-titlebar--macos .window-titlebar__drag {
|
||||
padding-left: 78px;
|
||||
}
|
||||
|
||||
.window-titlebar--macos .window-titlebar__controls,
|
||||
.window-titlebar--macos .window-titlebar__dot {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.window-titlebar--macos .window-titlebar__title {
|
||||
color: var(--app-text-muted);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -38,11 +38,15 @@
|
|||
</div>
|
||||
</n-layout-sider>
|
||||
|
||||
<n-layout-content ref="contentRef" class="content-layout" :native-scrollbar="false">
|
||||
<main class="content">
|
||||
<RouterView />
|
||||
</main>
|
||||
</n-layout-content>
|
||||
<div class="content-pane">
|
||||
<WindowTitlebar />
|
||||
|
||||
<n-layout-content ref="contentRef" class="content-layout" :native-scrollbar="false">
|
||||
<main class="content">
|
||||
<RouterView />
|
||||
</main>
|
||||
</n-layout-content>
|
||||
</div>
|
||||
</n-layout>
|
||||
|
||||
<n-layout-footer class="playerbar-footer">
|
||||
|
|
@ -61,6 +65,7 @@ import { NIcon } from "naive-ui"
|
|||
import { MusicalNotesOutline, SearchOutline, SettingsOutline, TrophyOutline } from "@vicons/ionicons5"
|
||||
import { Playlist } from "@vicons/tabler"
|
||||
import PlayerBar from "@/components/PlayerBar.vue"
|
||||
import WindowTitlebar from "@/components/WindowTitlebar.vue"
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -135,19 +140,35 @@ watch(
|
|||
<style scoped>
|
||||
.app-shell {
|
||||
display: grid;
|
||||
grid-template-rows: minmax(0, 1fr) auto;
|
||||
height: 100%;
|
||||
grid-template-rows: minmax(0, 1fr) var(--playerbar-height);
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
max-height: 100vh;
|
||||
max-height: 100dvh;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
background: var(--app-bg);
|
||||
}
|
||||
|
||||
.workspace {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content-pane {
|
||||
display: grid;
|
||||
flex: 1;
|
||||
grid-template-rows: var(--titlebar-height) minmax(0, 1fr);
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
background: var(--app-bg);
|
||||
}
|
||||
|
||||
.sidebar-sider {
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
|
|
@ -259,7 +280,9 @@ watch(
|
|||
|
||||
.content-layout {
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content {
|
||||
|
|
@ -269,6 +292,9 @@ watch(
|
|||
}
|
||||
|
||||
.playerbar-footer {
|
||||
height: var(--playerbar-height);
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
:root {
|
||||
--titlebar-height: 34px;
|
||||
--playerbar-height: clamp(72px, 9vh, 88px);
|
||||
--app-bg: #f4eddf;
|
||||
--app-bg-elevated: #eee2d1;
|
||||
--app-card: #fffaf0;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div class="page">
|
||||
<section class="section">
|
||||
<div class="section-head">
|
||||
<section>
|
||||
<!-- <div class="section-head">
|
||||
<h3>分类</h3>
|
||||
<span class="section-sub">歌单分类</span>
|
||||
</div>
|
||||
</div> -->
|
||||
<n-tabs v-model:value="activeCategory" type="line" animated @update:value="playList">
|
||||
<n-tab-pane v-for="category in categories" :key="category.id" :name="category.id" :tab="category.name" />
|
||||
</n-tabs>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue"
|
||||
import { RouterView, useRoute, useRouter } from "vue-router"
|
||||
import type { MenuOption } from "naive-ui"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue