mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-24 08:19:51 +00:00
Linear mode arrangement tweaks (#8853)
Planning to keep updates smaller and more contained in the interest of collaboration and velocity - The breadcrumb hamburger menu that provides workflow options is now displayed in linear mode - As part of this change, the reka-ui popover component now accepts primvevue format MenuItems - I prefer the format I had, but this makes transitioning stuff easier. - The simplified linear history is moved to always be horizontal and shown beneath previews. - The label has been removed from the "Give Feedback" button on desktop so it does not overlap - The full side toolbar is displayed in linear mode - This is temporary, but it gets the dead code pruned out now. - Lays some groundwork for selecting an asset from the assets panel to also select the item in the main linear panel - The api `promptQueued` event can now optionally include a promptIds, which list the ids for all jobs that were queued together as part of that batch - Update the max for the `number of generations` field to respect the recently updated cloud limits | Before | After | | ------ | ----- | | <img width="360" alt="before" src="https://github.com/user-attachments/assets/e632679c-d727-4882-841b-09e99a2f81a4" /> | <img width="360" alt="after" src="https://github.com/user-attachments/assets/a9bcd809-c314-49bd-a479-2448d1a88456"/>| ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8853-Linear-mode-arrangement-tweaks-3066d73d365081589355ef753513900b) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -1,44 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
breakpointsTailwind,
|
||||
unrefElement,
|
||||
useBreakpoints,
|
||||
whenever
|
||||
} from '@vueuse/core'
|
||||
import { breakpointsTailwind, unrefElement, useBreakpoints } from '@vueuse/core'
|
||||
import Splitter from 'primevue/splitter'
|
||||
import SplitterPanel from 'primevue/splitterpanel'
|
||||
import { ref, useTemplateRef } from 'vue'
|
||||
import { computed, useTemplateRef } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import ExtensionSlot from '@/components/common/ExtensionSlot.vue'
|
||||
import ModeToggle from '@/components/sidebar/ModeToggle.vue'
|
||||
import SideToolbar from '@/components/sidebar/SideToolbar.vue'
|
||||
import TopbarBadges from '@/components/topbar/TopbarBadges.vue'
|
||||
import WorkflowTabs from '@/components/topbar/WorkflowTabs.vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import Popover from '@/components/ui/Popover.vue'
|
||||
import TypeformPopoverButton from '@/components/ui/TypeformPopoverButton.vue'
|
||||
import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
|
||||
import { useWorkflowActionsMenu } from '@/composables/useWorkflowActionsMenu'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import LinearControls from '@/renderer/extensions/linearMode/LinearControls.vue'
|
||||
import LinearPreview from '@/renderer/extensions/linearMode/LinearPreview.vue'
|
||||
import MobileMenu from '@/renderer/extensions/linearMode/MobileMenu.vue'
|
||||
import OutputHistory from '@/renderer/extensions/linearMode/OutputHistory.vue'
|
||||
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
|
||||
import type { ResultItemImpl } from '@/stores/queueStore'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
|
||||
const { t } = useI18n()
|
||||
const nodeOutputStore = useNodeOutputStore()
|
||||
const settingStore = useSettingStore()
|
||||
const workspaceStore = useWorkspaceStore()
|
||||
|
||||
const mobileDisplay = useBreakpoints(breakpointsTailwind).smaller('md')
|
||||
|
||||
const hasPreview = ref(false)
|
||||
whenever(
|
||||
() => nodeOutputStore.latestPreview[0],
|
||||
() => (hasPreview.value = true)
|
||||
)
|
||||
const activeTab = computed(() => workspaceStore.sidebarTab.activeSidebarTab)
|
||||
|
||||
const selectedItem = ref<AssetItem>()
|
||||
const selectedOutput = ref<ResultItemImpl>()
|
||||
const canShowPreview = ref(true)
|
||||
const outputHistoryRef = useTemplateRef('outputHistoryRef')
|
||||
const { menuItems } = useWorkflowActionsMenu(
|
||||
() => useCommandStore().execute('Comfy.RenameWorkflow'),
|
||||
{ isRoot: true }
|
||||
)
|
||||
|
||||
const topLeftRef = useTemplateRef('topLeftRef')
|
||||
const topRightRef = useTemplateRef('topRightRef')
|
||||
@@ -47,10 +41,7 @@ const bottomRightRef = useTemplateRef('bottomRightRef')
|
||||
const linearWorkflowRef = useTemplateRef('linearWorkflowRef')
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="absolute w-full h-full"
|
||||
@wheel.capture="(e: WheelEvent) => outputHistoryRef?.onWheel(e)"
|
||||
>
|
||||
<div class="absolute w-full h-full">
|
||||
<div class="workflow-tabs-container pointer-events-auto h-9.5 w-full">
|
||||
<div class="flex h-full items-center">
|
||||
<WorkflowTabs />
|
||||
@@ -64,29 +55,10 @@ const linearWorkflowRef = useTemplateRef('linearWorkflowRef')
|
||||
<MobileMenu />
|
||||
<div class="flex flex-col text-muted-foreground">
|
||||
<LinearPreview
|
||||
:latent-preview="
|
||||
canShowPreview && hasPreview
|
||||
? nodeOutputStore.latestPreview[0]
|
||||
: undefined
|
||||
"
|
||||
:run-button-click="linearWorkflowRef?.runButtonClick"
|
||||
:selected-item
|
||||
:selected-output
|
||||
mobile
|
||||
/>
|
||||
</div>
|
||||
<OutputHistory
|
||||
ref="outputHistoryRef"
|
||||
mobile
|
||||
@update-selection="
|
||||
([item, output, canShow]) => {
|
||||
selectedItem = item
|
||||
selectedOutput = output
|
||||
canShowPreview = canShow
|
||||
hasPreview = false
|
||||
}
|
||||
"
|
||||
/>
|
||||
<LinearControls ref="linearWorkflowRef" mobile />
|
||||
<div class="text-base-foreground flex items-center gap-4">
|
||||
<div class="border-r border-border-subtle mr-auto">
|
||||
@@ -99,7 +71,7 @@ const linearWorkflowRef = useTemplateRef('linearWorkflowRef')
|
||||
<Splitter
|
||||
v-else
|
||||
class="h-[calc(100%-38px)] w-full bg-comfy-menu-secondary-bg"
|
||||
:pt="{ gutter: { class: 'bg-transparent w-4 -mx-3' } }"
|
||||
:pt="{ gutter: { class: 'bg-transparent w-4 -mx-1' } }"
|
||||
@resizestart="({ originalEvent }) => originalEvent.preventDefault()"
|
||||
>
|
||||
<SplitterPanel
|
||||
@@ -107,50 +79,41 @@ const linearWorkflowRef = useTemplateRef('linearWorkflowRef')
|
||||
:size="1"
|
||||
class="min-w-min outline-none"
|
||||
>
|
||||
<OutputHistory
|
||||
<div
|
||||
v-if="settingStore.get('Comfy.Sidebar.Location') === 'left'"
|
||||
ref="outputHistoryRef"
|
||||
:scroll-reset-button-to="unrefElement(bottomLeftRef) ?? undefined"
|
||||
@update-selection="
|
||||
([item, output, canShow]) => {
|
||||
selectedItem = item
|
||||
selectedOutput = output
|
||||
canShowPreview = canShow
|
||||
hasPreview = false
|
||||
}
|
||||
"
|
||||
/>
|
||||
class="flex h-full border-border-subtle border-r"
|
||||
>
|
||||
<SideToolbar />
|
||||
<ExtensionSlot v-if="activeTab" :extension="activeTab" />
|
||||
</div>
|
||||
<LinearControls
|
||||
v-else
|
||||
ref="linearWorkflowRef"
|
||||
:toast-to="unrefElement(bottomLeftRef) ?? undefined"
|
||||
:notes-to="unrefElement(topLeftRef) ?? undefined"
|
||||
/>
|
||||
<div />
|
||||
</SplitterPanel>
|
||||
<SplitterPanel
|
||||
id="linearCenterPanel"
|
||||
:size="98"
|
||||
class="flex flex-col min-w-min gap-4 mx-2 px-10 pt-8 pb-4 relative text-muted-foreground outline-none"
|
||||
>
|
||||
<LinearPreview
|
||||
:latent-preview="
|
||||
canShowPreview && hasPreview
|
||||
? nodeOutputStore.latestPreview[0]
|
||||
: undefined
|
||||
"
|
||||
:run-button-click="linearWorkflowRef?.runButtonClick"
|
||||
:selected-item
|
||||
:selected-output
|
||||
/>
|
||||
<div ref="topLeftRef" class="absolute z-21 top-4 left-4" />
|
||||
<LinearPreview :run-button-click="linearWorkflowRef?.runButtonClick" />
|
||||
<div ref="topLeftRef" class="absolute z-21 top-4 left-4">
|
||||
<Popover :entries="menuItems" align="start">
|
||||
<template #button>
|
||||
<Button size="icon" variant="textonly">
|
||||
<i class="icon-[lucide--menu]" />
|
||||
</Button>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
<div ref="topRightRef" class="absolute z-21 top-4 right-4" />
|
||||
<div ref="bottomLeftRef" class="absolute z-20 bottom-4 left-4" />
|
||||
<div ref="bottomRightRef" class="absolute z-20 bottom-24 right-4" />
|
||||
<div
|
||||
class="absolute z-20 bottom-4 right-4 text-base-foreground flex items-center gap-4"
|
||||
>
|
||||
<div v-text="t('linearMode.beta')" />
|
||||
<TypeformPopoverButton
|
||||
data-tf-widget="gmVqFi8l"
|
||||
:align="
|
||||
@@ -172,20 +135,10 @@ const linearWorkflowRef = useTemplateRef('linearWorkflowRef')
|
||||
:toast-to="unrefElement(bottomRightRef) ?? undefined"
|
||||
:notes-to="unrefElement(topRightRef) ?? undefined"
|
||||
/>
|
||||
<OutputHistory
|
||||
v-else
|
||||
ref="outputHistoryRef"
|
||||
:scroll-reset-button-to="unrefElement(bottomRightRef) ?? undefined"
|
||||
@update-selection="
|
||||
([item, output, canShow]) => {
|
||||
selectedItem = item
|
||||
selectedOutput = output
|
||||
canShowPreview = canShow
|
||||
hasPreview = false
|
||||
}
|
||||
"
|
||||
/>
|
||||
<div />
|
||||
<div v-else class="flex h-full border-border-subtle border-l">
|
||||
<ExtensionSlot v-if="activeTab" :extension="activeTab" />
|
||||
<SideToolbar class="border-border-subtle border-l" />
|
||||
</div>
|
||||
</SplitterPanel>
|
||||
</Splitter>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user