feat: Update workflow menu to allow quick toggling modes (#9436)
## Summary Adds a quick toggle mode button to the workflow menu for users to easier discover & change modes ## Changes - **What**: - remove specific app mode rendering - increase spacing around breadcrumbs menu - add current mode text to menu - add base button variant ## Screenshots (if applicable) <img width="258" height="137" alt="image" src="https://github.com/user-attachments/assets/2ed7b276-c52c-44cd-b107-399f769574af" /> <img width="233" height="172" alt="image" src="https://github.com/user-attachments/assets/2639d30c-2150-4434-a86b-732649c4b142" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9436-feat-Update-workflow-menu-to-allow-quick-toggling-modes-31a6d73d365081b589eee0e03cd6f1de) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 108 KiB |
@@ -43,28 +43,7 @@ function openTemplates() {
|
||||
|
||||
<template>
|
||||
<div class="pointer-events-auto flex flex-col gap-2">
|
||||
<WorkflowActionsDropdown source="app_mode_toolbar">
|
||||
<template #button="{ hasUnseenItems }">
|
||||
<Button
|
||||
v-tooltip.right="{
|
||||
value: t('sideToolbar.labels.menu'),
|
||||
...tooltipOptions
|
||||
}"
|
||||
variant="secondary"
|
||||
size="unset"
|
||||
:aria-label="t('sideToolbar.labels.menu')"
|
||||
class="relative h-10 gap-1 rounded-lg pr-2 pl-3 data-[state=open]:bg-secondary-background-hover data-[state=open]:shadow-interface"
|
||||
>
|
||||
<i class="icon-[lucide--panels-top-left] size-4" />
|
||||
<i class="icon-[lucide--chevron-down] size-4 text-muted-foreground" />
|
||||
<span
|
||||
v-if="hasUnseenItems"
|
||||
aria-hidden="true"
|
||||
class="absolute -top-0.5 -right-0.5 size-2 rounded-full bg-primary-background"
|
||||
/>
|
||||
</Button>
|
||||
</template>
|
||||
</WorkflowActionsDropdown>
|
||||
<WorkflowActionsDropdown source="app_mode_toolbar" />
|
||||
|
||||
<Button
|
||||
v-if="enableAppBuilder"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
data-testid="subgraph-breadcrumb"
|
||||
class="subgraph-breadcrumb -mt-4 flex w-auto items-center pt-4 drop-shadow-(--interface-panel-drop-shadow)"
|
||||
class="subgraph-breadcrumb -mt-3 flex w-auto items-center pt-4 pl-1 drop-shadow-(--interface-panel-drop-shadow)"
|
||||
:class="{
|
||||
'subgraph-breadcrumb-collapse': collapseTabs,
|
||||
'subgraph-breadcrumb-overflow': overflowingTabs
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
DropdownMenuRoot,
|
||||
DropdownMenuTrigger
|
||||
} from 'reka-ui'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import WorkflowActionsList from '@/components/common/WorkflowActionsList.vue'
|
||||
@@ -22,6 +23,7 @@ const { source, align = 'start' } = defineProps<{
|
||||
|
||||
const { t } = useI18n()
|
||||
const canvasStore = useCanvasStore()
|
||||
const dropdownOpen = ref(false)
|
||||
|
||||
const { menuItems } = useWorkflowActionsMenu(
|
||||
() => useCommandStore().execute('Comfy.RenameWorkflow'),
|
||||
@@ -40,22 +42,38 @@ function handleOpen(open: boolean) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function toggleLinearMode() {
|
||||
dropdownOpen.value = false
|
||||
void useCommandStore().execute('Comfy.ToggleLinear', {
|
||||
metadata: { source }
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuRoot @update:open="handleOpen">
|
||||
<DropdownMenuTrigger as-child>
|
||||
<slot name="button" :has-unseen-items="hasUnseenItems">
|
||||
<DropdownMenuRoot v-model:open="dropdownOpen" @update:open="handleOpen">
|
||||
<slot name="button" :has-unseen-items="hasUnseenItems">
|
||||
<div
|
||||
class="pointer-events-auto inline-flex items-center rounded-lg bg-secondary-background"
|
||||
>
|
||||
<Button
|
||||
v-tooltip="{
|
||||
value: t('breadcrumbsMenu.workflowActions'),
|
||||
value: canvasStore.linearMode
|
||||
? t('breadcrumbsMenu.enterNodeGraph')
|
||||
: t('breadcrumbsMenu.enterAppMode'),
|
||||
showDelay: 300,
|
||||
hideDelay: 300
|
||||
}"
|
||||
variant="secondary"
|
||||
size="unset"
|
||||
:aria-label="t('breadcrumbsMenu.workflowActions')"
|
||||
class="pointer-events-auto relative h-10 gap-1 rounded-lg pr-2 pl-3 data-[state=open]:bg-secondary-background-hover data-[state=open]:shadow-interface"
|
||||
:aria-label="
|
||||
canvasStore.linearMode
|
||||
? t('breadcrumbsMenu.enterNodeGraph')
|
||||
: t('breadcrumbsMenu.enterAppMode')
|
||||
"
|
||||
variant="base"
|
||||
class="m-1"
|
||||
@pointerdown.stop
|
||||
@click="toggleLinearMode"
|
||||
>
|
||||
<i
|
||||
class="size-4"
|
||||
@@ -65,15 +83,36 @@ function handleOpen(open: boolean) {
|
||||
: 'icon-[comfy--workflow]'
|
||||
"
|
||||
/>
|
||||
<i class="icon-[lucide--chevron-down] size-4 text-muted-foreground" />
|
||||
<span
|
||||
v-if="hasUnseenItems"
|
||||
aria-hidden="true"
|
||||
class="absolute -top-0.5 -right-0.5 size-2 rounded-full bg-primary-background"
|
||||
/>
|
||||
</Button>
|
||||
</slot>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button
|
||||
v-tooltip="{
|
||||
value: t('breadcrumbsMenu.workflowActions'),
|
||||
showDelay: 300,
|
||||
hideDelay: 300
|
||||
}"
|
||||
variant="secondary"
|
||||
size="unset"
|
||||
:aria-label="t('breadcrumbsMenu.workflowActions')"
|
||||
class="relative h-10 gap-1 rounded-lg pr-2 pl-2.5 text-center data-[state=open]:bg-secondary-background-hover data-[state=open]:shadow-interface"
|
||||
>
|
||||
<span>{{
|
||||
canvasStore.linearMode
|
||||
? t('breadcrumbsMenu.app')
|
||||
: t('breadcrumbsMenu.graph')
|
||||
}}</span>
|
||||
<i
|
||||
class="icon-[lucide--chevron-down] size-4 text-muted-foreground"
|
||||
/>
|
||||
<span
|
||||
v-if="hasUnseenItems"
|
||||
aria-hidden="true"
|
||||
class="absolute -top-0.5 -right-0.5 size-2 rounded-full bg-primary-background"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
</div>
|
||||
</slot>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuContent
|
||||
:align
|
||||
|
||||
@@ -20,6 +20,7 @@ export const buttonVariants = cva({
|
||||
'destructive-textonly':
|
||||
'bg-transparent text-destructive-background hover:bg-destructive-background/10',
|
||||
'overlay-white': 'bg-white text-gray-600 hover:bg-white/90',
|
||||
base: 'bg-base-background text-base-foreground hover:bg-secondary-background-hover',
|
||||
gradient:
|
||||
'border-transparent bg-(image:--subscription-button-gradient) text-white hover:opacity-90'
|
||||
},
|
||||
@@ -49,6 +50,7 @@ const variants = [
|
||||
'textonly',
|
||||
'muted-textonly',
|
||||
'destructive-textonly',
|
||||
'base',
|
||||
'overlay-white',
|
||||
'gradient'
|
||||
] as const satisfies Array<ButtonVariants['variant']>
|
||||
|
||||
@@ -2605,6 +2605,9 @@
|
||||
"deleteBlueprint": "Delete Blueprint",
|
||||
"enterNewName": "Enter new name",
|
||||
"missingNodesWarning": "Workflow contains unsupported nodes (highlighted red).",
|
||||
"graph": "Graph",
|
||||
"app": "App",
|
||||
"enterNodeGraph": "Enter node graph",
|
||||
"share": "Share"
|
||||
},
|
||||
"shortcuts": {
|
||||
|
||||