diff --git a/src/renderer/shell/components/AppBar.vue b/src/renderer/shell/components/AppBar.vue index 293c2ec75..9d1fe18fc 100644 --- a/src/renderer/shell/components/AppBar.vue +++ b/src/renderer/shell/components/AppBar.vue @@ -75,6 +75,13 @@ + + + { }) } +const toggleThreadView = async () => { + try { + const windowId = window.api.getWindowId() + if (windowId == null) { + console.warn('Failed to toggle thread view: unable to determine window id.') + return + } + const success = await windowPresenter.sendToActiveTab(windowId, THREAD_VIEW_EVENTS.TOGGLE) + if (!success) { + console.warn('Failed to toggle thread view: no active tab found.') + } + } catch (error) { + console.warn('Failed to toggle thread view via windowPresenter.', error) + } +} + const isTabContainerOverflowingLeft = computed(() => { return ( tabContainerWrapperSize.width.value < tabContainerSize.width.value && diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index ed81f4bee..9cbe9c7a0 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -6,7 +6,7 @@ import { usePresenter } from './composables/usePresenter' import SelectedTextContextMenu from './components/message/SelectedTextContextMenu.vue' import { useArtifactStore } from './stores/artifact' import { useChatStore } from '@/stores/chat' -import { NOTIFICATION_EVENTS, SHORTCUT_EVENTS } from './events' +import { NOTIFICATION_EVENTS, SHORTCUT_EVENTS, THREAD_VIEW_EVENTS } from './events' import { Toaster } from '@shadcn/components/ui/sonner' import { useToast } from '@/components/use-toast' import { useSettingsStore } from '@/stores/settings' @@ -14,6 +14,7 @@ import { useThemeStore } from '@/stores/theme' import { useLanguageStore } from '@/stores/language' import { useI18n } from 'vue-i18n' import TranslatePopup from '@/components/popup/TranslatePopup.vue' +import ThreadView from '@/components/ThreadView.vue' import ModelCheckDialog from '@/components/settings/ModelCheckDialog.vue' import { useModelCheckStore } from '@/stores/modelCheck' import MessageDialog from './components/ui/MessageDialog.vue' @@ -165,6 +166,15 @@ const handleCreateNewConversation = () => { } } +const handleThreadViewToggle = () => { + if (router.currentRoute.value.name !== 'chat') { + void router.push({ name: 'chat' }) + chatStore.isSidebarOpen = true + return + } + chatStore.isSidebarOpen = !chatStore.isSidebarOpen +} + // Removed GO_SETTINGS handler; now handled in main via tab logic // Handle ESC key - close floating chat window @@ -224,6 +234,8 @@ onMounted(() => { }) }) + window.electron.ipcRenderer.on(THREAD_VIEW_EVENTS.TOGGLE, handleThreadViewToggle) + window.electron.ipcRenderer.on(NOTIFICATION_EVENTS.SYS_NOTIFY_CLICKED, (_, msg) => { let threadId: string | null = null @@ -265,6 +277,9 @@ onMounted(() => { } // Close artifacts page when route changes artifactStore.hideArtifact() + if (route.name !== 'chat') { + chatStore.isSidebarOpen = false + } } ) @@ -302,6 +317,7 @@ onBeforeUnmount(() => { // GO_SETTINGS listener removed; handled in main window.electron.ipcRenderer.removeAllListeners(NOTIFICATION_EVENTS.SYS_NOTIFY_CLICKED) window.electron.ipcRenderer.removeAllListeners(NOTIFICATION_EVENTS.DATA_RESET_COMPLETE_DEV) + window.electron.ipcRenderer.removeListener(THREAD_VIEW_EVENTS.TOGGLE, handleThreadViewToggle) }) @@ -320,6 +336,7 @@ onBeforeUnmount(() => { + + + + + + + + + + + + + + + + + + diff --git a/src/renderer/src/components/ThreadsView.vue b/src/renderer/src/components/ThreadsView.vue index af6f214c2..9748f6129 100644 --- a/src/renderer/src/components/ThreadsView.vue +++ b/src/renderer/src/components/ThreadsView.vue @@ -5,7 +5,6 @@ - - - - - - - - - - - - - + + + + @@ -35,10 +21,6 @@ const emit = defineEmits(['messageNavigationToggle']) const chatStore = useChatStore() -const onSidebarButtonClick = () => { - chatStore.isSidebarOpen = !chatStore.isSidebarOpen -} - // 新增的事件处理函数 const onMessageNavigationButtonClick = () => { emit('messageNavigationToggle') diff --git a/src/renderer/src/events.ts b/src/renderer/src/events.ts index 59a93eae6..ab01adb7f 100644 --- a/src/renderer/src/events.ts +++ b/src/renderer/src/events.ts @@ -124,6 +124,11 @@ export const SHORTCUT_EVENTS = { DELETE_CONVERSATION: 'shortcut:delete-conversation' } +// Thread view related events +export const THREAD_VIEW_EVENTS = { + TOGGLE: 'thread-view:toggle' +} + // 标签页相关事件 export const TAB_EVENTS = { TITLE_UPDATED: 'tab:title-updated', // 标签页标题更新 diff --git a/src/renderer/src/views/ChatTabView.vue b/src/renderer/src/views/ChatTabView.vue index 738c6fbcb..0760b4418 100644 --- a/src/renderer/src/views/ChatTabView.vue +++ b/src/renderer/src/views/ChatTabView.vue @@ -8,30 +8,6 @@ ]" > - - - - - - - @@ -73,7 +49,7 @@ - + import('@/components/ThreadsView.vue')) const TitleView = defineAsyncComponent(() => import('@/components/TitleView.vue')) const ChatView = defineAsyncComponent(() => import('@/components/ChatView.vue')) const NewThread = defineAsyncComponent(() => import('@/components/NewThread.vue')) @@ -108,7 +82,6 @@ const artifactStore = useArtifactStore() const route = useRoute() const chatStore = useChatStore() const title = useTitle() -const langStore = useLanguageStore() const chatViewRef = ref() // 添加标题更新逻辑 const updateTitle = () => { @@ -141,21 +114,8 @@ watch( ) // 点击外部区域关闭侧边栏 -const sidebarRef = ref() -const messageNavigationRef = ref() const isLargeScreen = useMediaQuery('(min-width: 1024px)') -onClickOutside(sidebarRef, (event) => { - const isClickInMessageNavigation = messageNavigationRef.value?.contains(event.target as Node) - - if (chatStore.isSidebarOpen && !isLargeScreen.value) { - chatStore.isSidebarOpen = false - } - if (chatStore.isMessageNavigationOpen && !isLargeScreen.value && !isClickInMessageNavigation) { - chatStore.isMessageNavigationOpen = false - } -}) - const handleMessageNavigationToggle = () => { if (artifactStore.isOpen) { artifactStore.isOpen = false