-
Notifications
You must be signed in to change notification settings - Fork 426
feat: right side panel #6952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: right side panel #6952
Changes from 13 commits
9056052
2f2f65a
cd3e809
c1bbb7b
fd6defc
1677667
7e9ece2
ff1b9ad
2c33757
464c9b2
828c836
d47af09
56f8f29
8370166
f2fcdd5
e10a0b9
0159622
4be493c
aa429ee
3774b6c
d7fa9a9
cc34422
952f4a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -44,6 +44,20 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </IconButton> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CurrentUserButton v-if="isLoggedIn" class="shrink-0" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <LoginButton v-else-if="isDesktop" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <IconButton | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-if="!isRightSidePanelOpen" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-tooltip.bottom="rightSidePanelTooltipConfig" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="transparent" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size="sm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="mr-2 transition-colors duration-200 ease-in-out hover:bg-secondary-background-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-background" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :aria-pressed="isRightSidePanelOpen" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :aria-label="t('rightSidePanel.togglePanel')" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @click="toggleRightSidePanel" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <i | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class="icon-[lucide--panel-right] block size-4 text-muted-foreground" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </IconButton> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+47
to
+60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove The button is only rendered when the panel is closed ( Consider one of these approaches:
Apply this diff to remove the unnecessary <IconButton
v-if="!isRightSidePanelOpen"
v-tooltip.bottom="rightSidePanelTooltipConfig"
type="transparent"
size="sm"
class="mr-2 transition-colors duration-200 ease-in-out hover:bg-secondary-background-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-background"
- :aria-pressed="isRightSidePanelOpen"
:aria-label="t('rightSidePanel.togglePanel')"
@click="toggleRightSidePanel"
>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <QueueProgressOverlay | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| v-model:expanded="isQueueOverlayExpanded" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -68,10 +82,12 @@ import { useCurrentUser } from '@/composables/auth/useCurrentUser' | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { buildTooltipConfig } from '@/composables/useTooltipConfig' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { app } from '@/scripts/app' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useQueueStore } from '@/stores/queueStore' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useWorkspaceStore } from '@/stores/workspaceStore' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { isElectron } from '@/utils/envUtil' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const workspaceStore = useWorkspaceStore() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rightSidePanelStore = useRightSidePanelStore() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { isLoggedIn } = useCurrentUser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isDesktop = isElectron() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { t } = useI18n() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -88,6 +104,16 @@ const queueHistoryButtonBackgroundClass = computed(() => | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : 'bg-secondary-background' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Right side panel toggle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isRightSidePanelOpen = computed(() => rightSidePanelStore.isOpen) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rightSidePanelTooltipConfig = computed(() => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| buildTooltipConfig(t('rightSidePanel.togglePanel')) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const toggleRightSidePanel = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rightSidePanelStore.togglePanel() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Maintain support for legacy topbar elements attached by custom scripts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const legacyCommandsContainerRef = ref<HTMLElement>() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onMounted(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,230 @@ | ||
| <template> | ||
| <div class="node-help-content mx-auto w-full"> | ||
| <ProgressSpinner | ||
| v-if="isLoading" | ||
| class="m-auto" | ||
| :aria-label="$t('g.loading')" | ||
| /> | ||
| <!-- Markdown fetched successfully --> | ||
| <div | ||
| v-else-if="!error" | ||
| class="markdown-content" | ||
| v-html="renderedHelpHtml" | ||
| /> | ||
| <!-- Fallback: markdown not found or fetch error --> | ||
| <div v-else class="fallback-content space-y-6 text-sm"> | ||
| <p v-if="node.description"> | ||
| <strong>{{ $t('g.description') }}:</strong> {{ node.description }} | ||
| </p> | ||
|
|
||
| <div v-if="inputList.length"> | ||
| <p> | ||
| <strong>{{ $t('nodeHelpPage.inputs') }}:</strong> | ||
| </p> | ||
| <!-- Using plain HTML table instead of DataTable for consistent styling with markdown content --> | ||
| <table class="overflow-x-auto"> | ||
| <thead> | ||
| <tr> | ||
| <th>{{ $t('g.name') }}</th> | ||
| <th>{{ $t('nodeHelpPage.type') }}</th> | ||
| <th>{{ $t('g.description') }}</th> | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| <tr v-for="input in inputList" :key="input.name"> | ||
| <td> | ||
| <code>{{ input.name }}</code> | ||
| </td> | ||
| <td>{{ input.type }}</td> | ||
| <td>{{ input.tooltip || '-' }}</td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </div> | ||
|
|
||
| <div v-if="outputList.length"> | ||
| <p> | ||
| <strong>{{ $t('nodeHelpPage.outputs') }}:</strong> | ||
| </p> | ||
| <table class="overflow-x-auto"> | ||
| <thead> | ||
| <tr> | ||
| <th>{{ $t('g.name') }}</th> | ||
| <th>{{ $t('nodeHelpPage.type') }}</th> | ||
| <th>{{ $t('g.description') }}</th> | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| <tr v-for="output in outputList" :key="output.name"> | ||
| <td> | ||
| <code>{{ output.name }}</code> | ||
| </td> | ||
| <td>{{ output.type }}</td> | ||
| <td>{{ output.tooltip || '-' }}</td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </template> | ||
|
|
||
| <script setup lang="ts"> | ||
| import { storeToRefs } from 'pinia' | ||
| import ProgressSpinner from 'primevue/progressspinner' | ||
| import { computed } from 'vue' | ||
|
|
||
| import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore' | ||
| import { useNodeHelpStore } from '@/stores/workspace/nodeHelpStore' | ||
|
|
||
| const { node } = defineProps<{ node: ComfyNodeDefImpl }>() | ||
|
|
||
| const nodeHelpStore = useNodeHelpStore() | ||
| const { renderedHelpHtml, isLoading, error } = storeToRefs(nodeHelpStore) | ||
|
|
||
| const inputList = computed(() => | ||
| Object.values(node.inputs).map((spec) => ({ | ||
| name: spec.name, | ||
| type: spec.type, | ||
| tooltip: spec.tooltip || '' | ||
| })) | ||
| ) | ||
|
|
||
| const outputList = computed(() => | ||
| node.outputs.map((spec) => ({ | ||
| name: spec.name, | ||
| type: spec.type, | ||
| tooltip: spec.tooltip || '' | ||
| })) | ||
| ) | ||
| </script> | ||
|
|
||
| <style scoped> | ||
| @reference './../../assets/css/style.css'; | ||
|
|
||
| .node-help-content :deep(:is(img, video)) { | ||
| @apply max-w-full h-auto block mb-4; | ||
| } | ||
|
|
||
| .markdown-content, | ||
| .fallback-content { | ||
| @apply text-sm overflow-visible; | ||
| } | ||
|
|
||
| .markdown-content :deep(h1), | ||
| .fallback-content h1 { | ||
| @apply text-[22px] font-bold mt-8 mb-4 first:mt-0; | ||
| } | ||
|
|
||
| .markdown-content :deep(h2), | ||
| .fallback-content h2 { | ||
| @apply text-[18px] font-bold mt-8 mb-4 first:mt-0; | ||
| } | ||
|
|
||
| .markdown-content :deep(h3), | ||
| .fallback-content h3 { | ||
| @apply text-[16px] font-bold mt-8 mb-4 first:mt-0; | ||
| } | ||
|
|
||
| .markdown-content :deep(h4), | ||
| .markdown-content :deep(h5), | ||
| .markdown-content :deep(h6), | ||
| .fallback-content h4, | ||
| .fallback-content h5, | ||
| .fallback-content h6 { | ||
| @apply mt-8 mb-4 first:mt-0; | ||
| } | ||
|
|
||
| .markdown-content :deep(td), | ||
| .fallback-content td { | ||
| color: var(--drag-text); | ||
| } | ||
|
|
||
| .markdown-content :deep(a), | ||
| .fallback-content a { | ||
| color: var(--drag-text); | ||
| text-decoration: underline; | ||
| } | ||
|
|
||
| .markdown-content :deep(th), | ||
| .fallback-content th { | ||
| color: var(--fg-color); | ||
| } | ||
|
|
||
| .markdown-content :deep(ul), | ||
| .markdown-content :deep(ol), | ||
| .fallback-content ul, | ||
| .fallback-content ol { | ||
| @apply pl-8 my-2; | ||
| } | ||
|
|
||
| .markdown-content :deep(ul ul), | ||
| .markdown-content :deep(ol ol), | ||
| .markdown-content :deep(ul ol), | ||
| .markdown-content :deep(ol ul), | ||
| .fallback-content ul ul, | ||
| .fallback-content ol ol, | ||
| .fallback-content ul ol, | ||
| .fallback-content ol ul { | ||
| @apply pl-6 my-2; | ||
| } | ||
|
|
||
| .markdown-content :deep(li), | ||
| .fallback-content li { | ||
| @apply my-2; | ||
| } | ||
|
|
||
| .markdown-content :deep(*:first-child), | ||
| .fallback-content > *:first-child { | ||
| @apply mt-0; | ||
| } | ||
|
|
||
| .markdown-content :deep(code), | ||
| .fallback-content code { | ||
| color: var(--code-text-color); | ||
| background-color: var(--code-bg-color); | ||
| @apply rounded px-1.5 py-0.5; | ||
| } | ||
|
|
||
| .markdown-content :deep(table), | ||
| .fallback-content table { | ||
| @apply w-full border-collapse; | ||
| } | ||
|
|
||
| .markdown-content :deep(th), | ||
| .markdown-content :deep(td), | ||
| .fallback-content th, | ||
| .fallback-content td { | ||
| @apply px-2 py-2; | ||
| } | ||
|
|
||
| .markdown-content :deep(tr), | ||
| .fallback-content tr { | ||
| border-bottom: 1px solid var(--content-bg); | ||
| } | ||
|
|
||
| .markdown-content :deep(tr:last-child), | ||
| .fallback-content tr:last-child { | ||
| border-bottom: none; | ||
| } | ||
|
|
||
| .markdown-content :deep(thead), | ||
| .fallback-content thead { | ||
| border-bottom: 1px solid var(--p-text-color); | ||
| } | ||
|
|
||
| .markdown-content :deep(pre), | ||
| .fallback-content pre { | ||
| @apply rounded p-4 my-4 overflow-x-auto; | ||
| background-color: var(--code-block-bg-color); | ||
|
|
||
| code { | ||
| @apply bg-transparent p-0; | ||
| color: var(--p-text-color); | ||
| } | ||
| } | ||
|
|
||
| .markdown-content :deep(table) { | ||
| @apply overflow-x-auto; | ||
| } | ||
| </style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find src -name "LiteGraphCanvasSplitterOverlay.vue" -type fRepository: Comfy-Org/ComfyUI_frontend
Length of output: 119
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 123
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 7416
🏁 Script executed:
head -n 220 src/components/LiteGraphCanvasSplitterOverlay.vue | cat -nRepository: Comfy-Org/ComfyUI_frontend
Length of output: 7416
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 5988
🏁 Script executed:
sed -n '170,185p' src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 338
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 4310
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 1545
🏁 Script executed:
grep -n "sidebarLocation" src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 613
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2581
🏁 Script executed:
grep -n "topPositionedSidebar\|leftPositionedSidebar\|rightPositionedSidebar" src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 52
🏁 Script executed:
grep -rn "sidebarLocation.*right\|right.*sidebar" src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 377
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2581
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2293
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 52
🏁 Script executed:
sed -n '20,45p' src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 886
🏁 Script executed:
sed -n '15,50p' src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 1206
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 377
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 156
🏁 Script executed:
ast-grep --pattern 'defineProps<$_>()'Repository: Comfy-Org/ComfyUI_frontend
Length of output: 52
🏁 Script executed:
grep -n "computed" src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 553
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 1878
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 1420
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 52
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 96
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 52
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 52
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 920
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2309
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 1502
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 534
🏁 Script executed:
ls -la src/components/ | grep -i sidebarRepository: Comfy-Org/ComfyUI_frontend
Length of output: 127
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 240
🏁 Script executed:
Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2044
🏁 Script executed:
grep -n "rightPositionedSidebar\|const.*sidebar\|computed.*sidebar" src/components/LiteGraphCanvasSplitterOverlay.vueRepository: Comfy-Org/ComfyUI_frontend
Length of output: 217
Right-side panel can coexist with right-positioned sidebar, creating layout constraints
When
sidebarLocation === 'right'andrightSidePanelVisible === true, both panels appear in the same horizontal splitter:Test this layout on smaller viewports to verify the main canvas remains usable and gutter handles discoverable when both right-side panels are visible. Consider whether adaptive sizing or constraints are needed when both panels are enabled.
🤖 Prompt for AI Agents