Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cross-env": "^10.1.0",
"dayjs": "^1.11.18",
"electron": "^37.6.1",
"electron-builder": "26.0.12",
"electron-vite": "^4.0.0",
Expand Down Expand Up @@ -173,7 +174,6 @@
"vue-virtual-scroller": "^2.0.0-beta.8",
"vuedraggable": "^4.1.0",
"yaml": "^2.8.1",
"dayjs": "^1.11.18",
"zod-to-json-schema": "^3.24.6"
},
"simple-git-hooks": {
Expand Down
2 changes: 1 addition & 1 deletion src/main/presenter/tabPresenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ export class TabPresenter implements ITabPresenter {
x: 0,
y: TAB_BAR_HEIGHT,
width: width,
height: height - TAB_BAR_HEIGHT - 4
height: height - TAB_BAR_HEIGHT
})
}

Expand Down
11 changes: 8 additions & 3 deletions src/main/presenter/windowPresenter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,12 +653,12 @@ export class WindowPresenter implements IWindowPresenter {
icon: iconFile, // 设置图标
titleBarStyle: 'hiddenInset', // macOS 风格标题栏
transparent: process.platform === 'darwin', // macOS 标题栏透明
vibrancy: process.platform === 'darwin' ? 'under-window' : undefined, // macOS 磨砂效果
backgroundColor: '#00000000', // 透明背景色
vibrancy: process.platform === 'darwin' ? 'hud' : undefined, // macOS 磨砂效果
backgroundColor: '#00ffffff', // 透明背景色
maximizable: true, // 允许最大化
frame: process.platform === 'darwin', // macOS 无边框
hasShadow: true, // macOS 阴影
trafficLightPosition: process.platform === 'darwin' ? { x: 12, y: 12 } : undefined, // macOS 红绿灯按钮位置
trafficLightPosition: process.platform === 'darwin' ? { x: 12, y: 10 } : undefined, // macOS 红绿灯按钮位置
webPreferences: {
preload: join(__dirname, '../preload/index.mjs'), // Preload 脚本路径
sandbox: false, // 禁用沙箱,允许 preload 访问 Node.js API
Expand Down Expand Up @@ -728,6 +728,7 @@ export class WindowPresenter implements IWindowPresenter {
shellWindow.on('maximize', () => {
console.log(`Window ${windowId} maximized.`)
if (!shellWindow.isDestroyed()) {
shellWindow.webContents.send(WINDOW_EVENTS.WINDOW_MAXIMIZED)
eventBus.sendToMain(WINDOW_EVENTS.WINDOW_MAXIMIZED, windowId)
// 触发恢复逻辑更新标签页 bounds
this.handleWindowRestore(windowId).catch((error) => {
Expand All @@ -740,6 +741,7 @@ export class WindowPresenter implements IWindowPresenter {
shellWindow.on('unmaximize', () => {
console.log(`Window ${windowId} unmaximized.`)
if (!shellWindow.isDestroyed()) {
shellWindow.webContents.send(WINDOW_EVENTS.WINDOW_UNMAXIMIZED)
eventBus.sendToMain(WINDOW_EVENTS.WINDOW_UNMAXIMIZED, windowId)
// 触发恢复逻辑更新标签页 bounds
this.handleWindowRestore(windowId).catch((error) => {
Expand All @@ -758,6 +760,7 @@ export class WindowPresenter implements IWindowPresenter {
console.error(`Error handling restore logic for window ${windowId}:`, error)
})
this.focusActiveTab(windowId, 'restore')
shellWindow.webContents.send(WINDOW_EVENTS.WINDOW_UNMAXIMIZED)
eventBus.sendToMain(WINDOW_EVENTS.WINDOW_RESTORED, windowId)
}
shellWindow.on('restore', handleRestore)
Expand All @@ -766,6 +769,7 @@ export class WindowPresenter implements IWindowPresenter {
shellWindow.on('enter-full-screen', () => {
console.log(`Window ${windowId} entered fullscreen.`)
if (!shellWindow.isDestroyed()) {
shellWindow.webContents.send(WINDOW_EVENTS.WINDOW_ENTER_FULL_SCREEN)
eventBus.sendToMain(WINDOW_EVENTS.WINDOW_ENTER_FULL_SCREEN, windowId)
// 触发恢复逻辑更新标签页 bounds
this.handleWindowRestore(windowId).catch((error) => {
Expand All @@ -781,6 +785,7 @@ export class WindowPresenter implements IWindowPresenter {
shellWindow.on('leave-full-screen', () => {
console.log(`Window ${windowId} left fullscreen.`)
if (!shellWindow.isDestroyed()) {
shellWindow.webContents.send(WINDOW_EVENTS.WINDOW_LEAVE_FULL_SCREEN)
eventBus.sendToMain(WINDOW_EVENTS.WINDOW_LEAVE_FULL_SCREEN, windowId)
// 触发恢复逻辑更新标签页 bounds
this.handleWindowRestore(windowId).catch((error) => {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/shell/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="w-screen h-screen" :class="[isMacOS ? 'bg-transparent' : 'bg-card/50']">
<div class="w-screen h-screen">
<AppBar />
<main class="content-container">
<!-- WebContentsView will be rendered here by the main process -->
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/shell/assets/ChromeClose.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/renderer/shell/assets/ChromeMaximize-1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/renderer/shell/assets/ChromeMaximize.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/renderer/shell/assets/ChromeMinimize.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
105 changes: 51 additions & 54 deletions src/renderer/shell/components/AppBar.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
<template>
<div class="flex flex-row h-9" :dir="langStore.dir">
<div
class="flex flex-row h-9 min-h-9 bg-window-background border border-b-0 border-window-inner-border box-border rounded-t-[10px] relative overflow-hidden"
:class="[!isFullscreened && isMacOS ? '' : ' rounded-t-none']"
:dir="langStore.dir"
>
<div class="absolute bottom-0 left-0 w-full h-[1px] bg-border"></div>
<div
class="h-9 shrink-0 w-0 flex-1 flex select-none text-center text-sm font-medium flex-row items-center justify-start window-drag-region"
:class="['', isMacOS ? (isFullscreened ? 'pr-2' : 'pl-20 pr-2') : '']"
class="h-full shrink-0 w-0 flex-1 flex select-none text-center text-sm font-medium flex-row items-center justify-start window-drag-region"
>
<div v-if="!isFullscreened && isMacOS" class="shrink-0 w-20 h-full window-drag-region"></div>
<!-- App title/content in center -->
<Button
v-if="isTabContainerOverflowingLeft"
variant="ghost"
class="shrink-0 text-xs font-medium px-2 h-6 mt-0.5 bg-transparent rounded-md flex items-center justify-center hover:bg-zinc-500/20 mr-1"
class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group border-r border-border"
@click="scrollTabContainer('left')"
>
<Icon icon="lucide:chevron-left" class="w-4 h-4" />
</Button>
<Button
v-if="isTabContainerOverflowingRight"
variant="ghost"
class="shrink-0 text-xs font-medium px-2 h-6 mt-0.5 bg-transparent rounded-md flex items-center justify-center hover:bg-zinc-500/20 mr-1"
class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group border-border"
@click="scrollTabContainer('right')"
>
<Icon icon="lucide:chevron-right" class="w-4 h-4" />
Expand Down Expand Up @@ -58,37 +63,51 @@
</div>

<Button
variant="ghost"
class="shrink-0 text-xs ml-1 font-medium px-2 h-6 bg-transparent rounded-md flex items-center justify-center hover:bg-zinc-500/20"
size="icon"
class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group"
@click="onNewTabClick"
>
<Icon icon="lucide:plus" class="w-4 h-4" />
</Button>
<div class="flex-1"></div>

<Button
variant="ghost"
class="text-xs font-medium px-2 h-7 bg-transparent rounded-md flex items-center justify-center hover:bg-zinc-500/20"
@click="onThemeClick"
size="icon"
class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group border-l"
@click="onHistoryClick"
>
<Icon v-if="themeStore.themeMode === 'dark'" icon="lucide:moon" class="w-4 h-4" />
<Icon v-else-if="themeStore.themeMode === 'light'" icon="lucide:sun" class="w-4 h-4" />
<Icon v-else icon="lucide:monitor" class="w-4 h-4" />
<Icon icon="lucide:history" class="w-4 h-4" />
</Button>
<Button
variant="ghost"
class="text-xs font-medium px-2 h-7 bg-transparent rounded-md flex items-center justify-center hover:bg-zinc-500/20"
@click="toggleThreadView"
class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group border-l"
@click="openSettings"
>
<Icon icon="lucide:history" class="w-4 h-4" />
<Icon icon="lucide:ellipsis" class="w-4 h-4" />
</Button>
<Button
variant="ghost"
class="text-xs font-medium px-2 h-7 bg-transparent rounded-md flex items-center justify-center hover:bg-zinc-500/20"
@click="openSettings"
v-if="!isMacOS"
class="window-no-drag-region shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group border-l"
@click="minimizeWindow"
>
<Icon icon="lucide:settings" class="w-4 h-4" />
<MinimizeIcon class="h-3! w-3!" />
</Button>
<Button
v-if="!isMacOS"
class="window-no-drag-region shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group"
@click="toggleMaximize"
>
<MaximizeIcon v-if="!isMaximized" class="h-3! w-3!" />
<RestoreIcon v-else class="h-3! w-3!" />
</Button>
<Button
v-if="!isMacOS"
class="window-no-drag-region shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group"
@click="closeWindow"
>
<CloseIcon class="h-3! w-3!" />
</Button>

<!-- <Button
class="text-xs font-medium px-2 h-7 bg-transparent rounded-md flex items-center justify-center"
@click="openNewWindow"
Expand All @@ -97,45 +116,24 @@
<Icon v-else icon="lucide:app-window" class="w-4 h-4" />
</Button> -->
</div>

<div v-if="!isMacOS" class="flex h-9">
<button
class="inline-flex items-center justify-center h-full w-12 hover:bg-zinc-500/20"
@click="minimizeWindow"
>
<MinusIcon class="h-4 w-4" />
</button>
<button
class="inline-flex items-center justify-center h-full w-12 hover:bg-zinc-500/20"
@click="toggleMaximize"
>
<MaximizeIcon v-if="!isMaximized" class="h-4 w-4" />
<RestoreIcon v-else class="h-4 w-4" />
</button>
<button
class="inline-flex items-center justify-center h-full w-12 hover:bg-destructive hover:text-destructive-foreground"
@click="closeWindow"
>
<XIcon class="h-4 w-4" />
</button>
</div>
</div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, computed } from 'vue'
import { MinusIcon, XIcon } from 'lucide-vue-next'
import MaximizeIcon from './icons/MaximizeIcon.vue'
import RestoreIcon from './icons/RestoreIcon.vue'
import { usePresenter } from '@/composables/usePresenter'
import { Button } from '@shadcn/components/ui/button'
import { Icon } from '@iconify/vue'
import AppBarTabItem from './app-bar/AppBarTabItem.vue'
import { useTabStore } from '@shell/stores/tab'
import { useThemeStore } from '@/stores/theme'
import { useElementSize } from '@vueuse/core'
import { useLanguageStore } from '@/stores/language'
import { useI18n } from 'vue-i18n'
import { WINDOW_EVENTS } from '../lib/events'
import CloseIcon from './icons/CloseIcon.vue'
import MinimizeIcon from './icons/MinimizeIcon.vue'
import { THREAD_VIEW_EVENTS } from '@/events'
const tabStore = useTabStore()
const langStore = useLanguageStore()
Expand All @@ -152,7 +150,6 @@ const isFullscreened = ref(false)

const { ipcRenderer } = window.electron

const themeStore = useThemeStore()
const tabContainerWrapper = ref<HTMLElement | null>(null)
const tabContainer = ref<HTMLElement | null>(null)

Expand All @@ -170,7 +167,7 @@ const onTabContainerWrapperScroll = () => {
})
}

const toggleThreadView = async () => {
const onHistoryClick = async () => {
try {
const windowId = window.api.getWindowId()
if (windowId == null) {
Expand Down Expand Up @@ -460,27 +457,27 @@ const handleDragEnd = async (event: DragEvent) => {
draggedTabId = null
}

const onThemeClick = () => {
console.log('onThemeClick')
themeStore.cycleTheme()
}
// const onThemeClick = () => {
// console.log('onThemeClick')
// themeStore.cycleTheme()
// }

onMounted(() => {
console.log('onMounted', tabStore.tabs)
// Listen for window maximize/unmaximize events
devicePresenter.getDeviceInfo().then((deviceInfo) => {
isMacOS.value = deviceInfo.platform === 'darwin'
})
ipcRenderer?.on('window:maximized', () => {
ipcRenderer?.on(WINDOW_EVENTS.WINDOW_MAXIMIZED, () => {
isMaximized.value = true
})
ipcRenderer?.on('window-fullscreened', () => {
ipcRenderer?.on(WINDOW_EVENTS.WINDOW_ENTER_FULL_SCREEN, () => {
isFullscreened.value = true
})
ipcRenderer?.on('window:unmaximized', () => {
ipcRenderer?.on(WINDOW_EVENTS.WINDOW_UNMAXIMIZED, () => {
isMaximized.value = false
})
ipcRenderer?.on('window-unfullscreened', () => {
ipcRenderer?.on(WINDOW_EVENTS.WINDOW_LEAVE_FULL_SCREEN, () => {
isFullscreened.value = false
})

Expand Down
Loading