feat: right side panel (#6952)

<img width="1183" height="809" alt="CleanShot 2025-11-26 at 16 01 15"
src="https://github.com/user-attachments/assets/c14dc5c3-a672-4dcd-917d-14f16310188e"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6952-feat-right-side-panel-2b76d73d36508112b121c283a479f42a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Rizumu Ayaka
2025-12-03 13:55:24 +08:00
committed by GitHub
parent fb54669dc3
commit 68274134c8
42 changed files with 1271 additions and 374 deletions

View File

@@ -14,10 +14,10 @@
</div>
<Splitter
key="main-splitter-stable"
:key="splitterRefreshKey"
class="splitter-overlay flex-1 overflow-hidden"
:pt:gutter="sidebarPanelVisible ? '' : 'hidden'"
:state-key="sidebarStateKey || 'main-splitter'"
:pt:gutter="getSplitterGutterClasses"
:state-key="sidebarStateKey"
state-storage="local"
>
<SplitterPanel
@@ -80,6 +80,16 @@
name="side-bar-panel"
/>
</SplitterPanel>
<!-- Right Side Panel - independent of sidebar -->
<SplitterPanel
v-if="rightSidePanelVisible"
class="right-side-panel pointer-events-auto"
:min-size="15"
:size="20"
>
<slot name="right-side-panel" />
</SplitterPanel>
</Splitter>
</div>
</div>
@@ -92,9 +102,11 @@ import { computed } from 'vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'
import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore'
import { useSidebarTabStore } from '@/stores/workspace/sidebarTabStore'
const settingStore = useSettingStore()
const rightSidePanelStore = useRightSidePanelStore()
const sidebarLocation = computed<'left' | 'right'>(() =>
settingStore.get('Comfy.Sidebar.Location')
)
@@ -109,6 +121,7 @@ const sidebarPanelVisible = computed(
const bottomPanelVisible = computed(
() => useBottomPanelStore().bottomPanelVisible
)
const rightSidePanelVisible = computed(() => rightSidePanelStore.isOpen)
const activeSidebarTabId = computed(
() => useSidebarTabStore().activeSidebarTabId
)
@@ -120,6 +133,21 @@ const sidebarStateKey = computed(() => {
// When no tab is active, use a default key to maintain state
return activeSidebarTabId.value ?? 'default-sidebar'
})
/**
* Force refresh the splitter when right panel visibility changes to recalculate the width
*/
const splitterRefreshKey = computed(() => {
return rightSidePanelVisible.value
? 'main-splitter-with-right-panel'
: 'main-splitter'
})
// Gutter visibility should be controlled by CSS targeting specific gutters
const getSplitterGutterClasses = computed(() => {
// Empty string - let individual gutter styles handle visibility
return ''
})
</script>
<style scoped>
@@ -135,10 +163,20 @@ const sidebarStateKey = computed(() => {
background-color: var(--p-primary-color);
}
/* Hide sidebar gutter when sidebar is not visible */
:deep(.side-bar-panel[style*='display: none'] + .p-splitter-gutter),
:deep(.p-splitter-gutter + .side-bar-panel[style*='display: none']) {
display: none;
}
.side-bar-panel {
background-color: var(--bg-color);
}
.right-side-panel {
background-color: var(--bg-color);
}
.bottom-panel {
background-color: var(--comfy-menu-bg);
border: 1px solid var(--p-panel-border-color);