171 lines
3.7 KiB
Vue
171 lines
3.7 KiB
Vue
<script setup lang="ts">
|
||
import { ref, onMounted, watch } from 'vue'
|
||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||
import { Minus, Square, Maximize2, X } from 'lucide-vue-next'
|
||
|
||
const appWindow = getCurrentWindow()
|
||
const isMaximized = ref(false)
|
||
const isDark = ref(false)
|
||
|
||
// 检查主题
|
||
const checkTheme = () => {
|
||
isDark.value = document.documentElement.classList.contains('dark')
|
||
}
|
||
|
||
// 检查窗口是否最大化
|
||
const checkMaximized = async () => {
|
||
try {
|
||
isMaximized.value = await appWindow.isMaximized()
|
||
} catch (error) {
|
||
console.error('Failed to check maximized state:', error)
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
checkMaximized()
|
||
checkTheme()
|
||
|
||
// 监听主题变化
|
||
const observer = new MutationObserver(() => {
|
||
checkTheme()
|
||
})
|
||
|
||
observer.observe(document.documentElement, {
|
||
attributes: true,
|
||
attributeFilter: ['class']
|
||
})
|
||
})
|
||
|
||
// 最小化窗口
|
||
const minimize = async () => {
|
||
try {
|
||
await appWindow.minimize()
|
||
} catch (error) {
|
||
console.error('Failed to minimize:', error)
|
||
}
|
||
}
|
||
|
||
// 最大化/还原窗口
|
||
const toggleMaximize = async () => {
|
||
try {
|
||
await appWindow.toggleMaximize()
|
||
await checkMaximized()
|
||
} catch (error) {
|
||
console.error('Failed to toggle maximize:', error)
|
||
}
|
||
}
|
||
|
||
// 关闭窗口
|
||
const close = async () => {
|
||
try {
|
||
await appWindow.close()
|
||
} catch (error) {
|
||
console.error('Failed to close:', error)
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<!-- data-tauri-drag-region: Tauri 自动处理窗口拖拽 -->
|
||
<div
|
||
data-tauri-drag-region
|
||
class="titlebar h-10 flex items-center justify-between px-3 select-none fixed top-0 left-0 right-0 z-50"
|
||
:class="{ 'titlebar-dark': isDark }"
|
||
>
|
||
<!-- 左侧:标题 -->
|
||
<div data-tauri-drag-region class="flex items-center gap-2 pointer-events-none">
|
||
<div class="titlebar-icon" :class="{ 'titlebar-icon-dark': isDark }" />
|
||
<span class="titlebar-text">News Classifier</span>
|
||
</div>
|
||
|
||
<!-- 右侧:窗口控制按钮 -->
|
||
<div class="flex items-center">
|
||
<!-- 最小化按钮 -->
|
||
<button
|
||
@click="minimize"
|
||
class="titlebar-btn"
|
||
title="最小化"
|
||
>
|
||
<Minus :size="14" />
|
||
</button>
|
||
|
||
<!-- 最大化/还原按钮 -->
|
||
<button
|
||
@click="toggleMaximize"
|
||
class="titlebar-btn"
|
||
:title="isMaximized ? '还原' : '最大化'"
|
||
>
|
||
<Square v-if="isMaximized" :size="12" />
|
||
<Maximize2 v-else :size="14" />
|
||
</button>
|
||
|
||
<!-- 关闭按钮 -->
|
||
<button
|
||
@click="close"
|
||
class="titlebar-btn titlebar-btn-close"
|
||
title="关闭"
|
||
>
|
||
<X :size="14" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.titlebar {
|
||
background: hsl(var(--card));
|
||
border-bottom: 1px solid hsl(var(--border));
|
||
}
|
||
|
||
.titlebar-dark {
|
||
background: hsl(var(--sidebar));
|
||
border-bottom: 1px solid hsl(var(--sidebar-border));
|
||
}
|
||
|
||
.titlebar-icon {
|
||
width: 12px;
|
||
height: 12px;
|
||
background: hsl(var(--primary));
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.titlebar-icon-dark {
|
||
background: hsl(var(--sidebar-primary));
|
||
}
|
||
|
||
.titlebar-text {
|
||
font-size: 0.8125rem;
|
||
font-weight: 500;
|
||
color: hsl(var(--foreground));
|
||
}
|
||
|
||
.titlebar-btn {
|
||
padding: 0.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: hsl(var(--muted-foreground));
|
||
background: transparent;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
transition: background 0.15s ease, color 0.15s ease;
|
||
}
|
||
|
||
.titlebar-btn:hover {
|
||
background: hsl(var(--accent));
|
||
color: hsl(var(--foreground));
|
||
}
|
||
|
||
.titlebar-btn-close:hover {
|
||
background: hsl(var(--destructive));
|
||
color: hsl(var(--destructive-foreground));
|
||
}
|
||
|
||
/* 防止拖拽时选中文本 */
|
||
.titlebar * {
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
}
|
||
</style>
|