WIP mobile layout for linear

This commit is contained in:
Austin Mroz
2026-01-08 09:22:55 -08:00
parent d0cc44d962
commit 4b9909701c
4 changed files with 72 additions and 11 deletions

View File

@@ -23,6 +23,7 @@ import { collectAllNodes } from '@/utils/graphTraversalUtil'
import { executeWidgetsCallback } from '@/utils/litegraphUtil'
const mediaActions = useMediaAssetActions()
const mobile = true
const { runButtonClick, selectedItem, selectedOutput } = defineProps<{
latentPreview?: string
@@ -153,8 +154,14 @@ async function rerun(e: Event) {
]"
/>
</linear-output-info>
<div
v-if="getMediaType(selectedOutput) === 'images' && mobile"
class="aspect-square w-full flex"
>
<img :src="latentPreview ?? selectedOutput!.url" />
</div>
<ImagePreview
v-if="getMediaType(selectedOutput) === 'images'"
v-else-if="getMediaType(selectedOutput) === 'images'"
:src="latentPreview ?? selectedOutput!.url"
/>
<VideoPreview

View File

@@ -136,7 +136,7 @@ async function runButtonClick(e: Event) {
defineExpose({ runButtonClick })
</script>
<template>
<div class="flex flex-col min-w-80 h-full">
<div>
<linear-workflow-info
class="h-12 border-x border-border-subtle py-2 px-4 gap-2 bg-comfy-menu-bg flex items-center"
>
@@ -155,9 +155,9 @@ defineExpose({ runButtonClick })
<Button v-if="false"> {{ t('menuLabels.publish') }} </Button>
</linear-workflow-info>
<div
class="border gap-2 h-full border-[var(--interface-stroke)] bg-comfy-menu-bg flex flex-col px-2"
class="border gap-2 border-[var(--interface-stroke)] bg-comfy-menu-bg px-2"
>
<linear-widgets class="grow-1 overflow-y-auto contain-size">
<linear-widgets>
<template v-for="(nodeData, index) of nodeDatas" :key="nodeData.id">
<div
v-if="index !== 0"

View File

@@ -33,6 +33,7 @@ void outputs.fetchMediaList()
defineProps<{
scrollResetButtonTo: string | HTMLElement
horizontal?: boolean
}>()
const emit = defineEmits<{
(
@@ -179,12 +180,14 @@ useEventListener(document.body, 'keydown', (e: KeyboardEvent) => {
cn(
'min-w-38 flex bg-comfy-menu-bg h-full',
settingStore.get('Comfy.Sidebar.Location') === 'right' &&
'flex-row-reverse'
'flex-row-reverse',
horizontal && 'h-30'
)
"
v-bind="$attrs"
>
<div
v-if="!horizontal"
class="h-full flex flex-col w-14 shrink-0 overflow-hidden items-center p-2 border-r border-node-component-border"
>
<SidebarIcon
@@ -217,18 +220,23 @@ useEventListener(document.body, 'keydown', (e: KeyboardEvent) => {
<linear-outputs
v-else
ref="outputsRef"
class="h-full min-w-24 grow-1 p-3 overflow-y-auto border-r-1 border-node-component-border flex flex-col items-center contain-size"
:class="
cn(
'min-w-24 grow-1 p-3 border-r-1 border-node-component-border flex items-center contain-size',
horizontal ? 'overflow-x-auto' : 'flex-col overflow-y-auto w-full'
)
"
>
<linear-job
v-if="queueStore.runningTasks.length > 0"
class="py-3 w-full aspect-square px-1 relative"
class="py-3 aspect-square px-1 relative"
>
<ProgressSpinner class="size-full" />
<div
v-if="
queueStore.runningTasks.length + queueStore.pendingTasks.length > 1
"
class="absolute top-0 right-0 p-1 min-w-5 h-5 flex justify-center items-center rounded-full bg-primary-background text-text-primary"
class="absolute top-0 right-0 p-1 min-w-5 h-5 justify-center items-center rounded-full bg-primary-background text-text-primary"
v-text="
queueStore.runningTasks.length + queueStore.pendingTasks.length
"
@@ -237,7 +245,14 @@ useEventListener(document.body, 'keydown', (e: KeyboardEvent) => {
<linear-job
v-for="(item, index) in filteredOutputs"
:key="index"
class="py-3 border-border-subtle flex flex-col w-full px-1 first:border-t-0 border-t-2"
:class="
cn(
'border-border-subtle flex',
horizontal
? 'h-full px-3 py-1 first:border-l-0 border-l-2'
: 'flex-col w-full py-3 px-1 first:border-t-0 border-t-2'
)
"
>
<template v-for="(output, key) in allOutputs(item)" :key>
<img
@@ -274,7 +289,10 @@ useEventListener(document.body, 'keydown', (e: KeyboardEvent) => {
</linear-job>
</linear-outputs>
</div>
<teleport v-if="outputScrollState" :to="scrollResetButtonTo">
<teleport
v-if="outputScrollState && scrollResetButtonTo"
:to="scrollResetButtonTo"
>
<Button
:class="
cn(

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { whenever } from '@vueuse/core'
import { breakpointsTailwind, useBreakpoints, whenever } from '@vueuse/core'
import Splitter from 'primevue/splitter'
import SplitterPanel from 'primevue/splitterpanel'
import { ref, useTemplateRef } from 'vue'
@@ -17,6 +17,8 @@ import type { ResultItemImpl } from '@/stores/queueStore'
const nodeOutputStore = useNodeOutputStore()
const settingStore = useSettingStore()
const mobileDisplay = useBreakpoints(breakpointsTailwind).smaller('md')
const hasPreview = ref(false)
whenever(
() => nodeOutputStore.latestPreview[0],
@@ -38,7 +40,41 @@ const linearWorkflowRef = useTemplateRef('linearWorkflowRef')
<TopbarBadges />
</div>
</div>
<div
v-if="mobileDisplay"
class="overflow-y-auto contain-size w-full h-full"
>
<OutputHistory
ref="outputHistoryRef"
scroll-reset-button-to="#linearDockBottomLeft"
horizontal
@update-selection="
(e) => {
;[selectedItem, selectedOutput, selectedIndex] = e
hasPreview = false
}
"
/>
<LinearPreview
:latent-preview="
selectedIndex[0] === 0 && selectedIndex[1] === 0 && hasPreview
? nodeOutputStore.latestPreview[0]
: undefined
"
:run-button-click="linearWorkflowRef?.runButtonClick"
:selected-item
:selected-output
/>
<div id="linearDockMobileNotes" class="sticky top-4 z-20" />
<LinearWorkflow
ref="linearWorkflowRef"
toast-to="#linearDockMobileToast"
notes-to="linearDockMobileNotes"
/>
<div id="linearDockMobileToast" class="absolute bottom-20 z-20" />
</div>
<Splitter
v-else
class="h-[calc(100%-38px)] w-full bg-comfy-menu-secondary-bg"
:pt="{ gutter: { class: 'bg-transparent w-4 -mx-3' } }"
@resizestart="({ originalEvent }) => originalEvent.preventDefault()"