App mode - landing/arrange screens - 4 (#9026)

## Summary

Updates messaging on app mode welcome pages and adds arrange view

## Screenshots (if applicable)

Build app view
<img width="628" height="470" alt="image"
src="https://github.com/user-attachments/assets/7f648769-1380-4093-8de9-414d05303b87"
/>

Run view
<img width="593" height="471" alt="image"
src="https://github.com/user-attachments/assets/cc81cfd0-fa89-4402-82f4-6bbdd0e7e2f9"
/>

Arrange view
<img width="1071" height="829" alt="image"
src="https://github.com/user-attachments/assets/ae8666ef-dff1-4fde-929e-89479c891261"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9026-App-mode-landing-arrange-screens-4-30d6d73d365081f4b209f34834a2ce5e)
by [Unito](https://www.unito.io)
This commit is contained in:
pythongosssss
2026-02-23 18:16:22 +00:00
committed by GitHub
parent 0f4bceafdd
commit b29dbec916
5 changed files with 125 additions and 20 deletions

View File

@@ -0,0 +1,59 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { useAppModeStore } from '@/stores/appModeStore'
import Button from '@/components/ui/button/Button.vue'
const { t } = useI18n()
const appModeStore = useAppModeStore()
</script>
<template>
<div
v-if="appModeStore.hasOutputs"
role="article"
data-testid="arrange-preview"
class="flex flex-col items-center justify-center h-full w-3/4 gap-6 p-8 mx-auto"
>
<div
class="border-warning-background border-2 border-dashed rounded-2xl w-full h-4/5 flex items-center justify-center flex-col p-12"
>
<p class="text-base-foreground font-bold mb-0">
{{ t('linearMode.arrange.outputs') }}
</p>
<p>{{ t('linearMode.arrange.resultsLabel') }}</p>
</div>
</div>
<div
v-else
role="article"
data-testid="arrange-no-outputs"
class="flex flex-col items-center justify-center h-full gap-6 p-8 w-lg mx-auto text-center"
>
<p class="m-0 text-base-foreground">
{{ t('linearMode.arrange.noOutputs') }}
</p>
<div class="flex flex-col gap-1 text-muted-foreground w-lg text-[14px]">
<p class="mt-0 p-0">{{ t('linearMode.arrange.switchToSelect') }}</p>
<i18n-t keypath="linearMode.arrange.connectAtLeastOne" tag="div">
<template #atLeastOne>
<span class="italic font-bold">
{{ t('linearMode.arrange.atLeastOne') }}
</span>
</template>
</i18n-t>
<p class="mt-0 p-0">{{ t('linearMode.arrange.outputExamples') }}</p>
</div>
<div class="flex flex-row gap-2">
<Button
variant="primary"
size="lg"
@click="appModeStore.setMode('builder:select')"
>
{{ t('linearMode.arrange.switchToSelectButton') }}
</Button>
</div>
</div>
</template>

View File

@@ -147,7 +147,7 @@ defineExpose({ runButtonClick })
</script>
<template>
<div
v-if="!appModeStore.isBuilderMode"
v-if="!appModeStore.isBuilderMode && appModeStore.hasOutputs"
class="flex flex-col min-w-80 md:h-full"
>
<section

View File

@@ -13,6 +13,7 @@ import { useWorkflowStore } from '@/platform/workflow/management/stores/workflow
import { extractWorkflowFromAsset } from '@/platform/workflow/utils/workflowExtractionUtil'
import ImagePreview from '@/renderer/extensions/linearMode/ImagePreview.vue'
import LinearWelcome from '@/renderer/extensions/linearMode/LinearWelcome.vue'
import LinearArrange from '@/renderer/extensions/linearMode/LinearArrange.vue'
import OutputHistory from '@/renderer/extensions/linearMode/OutputHistory.vue'
// Lazy-loaded to avoid pulling THREE.js into the main bundle
const Preview3d = () => import('@/renderer/extensions/linearMode/Preview3d.vue')
@@ -28,11 +29,11 @@ import type { ResultItemImpl } from '@/stores/queueStore'
import { formatDuration } from '@/utils/dateTimeUtil'
import { collectAllNodes } from '@/utils/graphTraversalUtil'
import { executeWidgetsCallback } from '@/utils/litegraphUtil'
import { useAppModeStore } from '@/stores/appModeStore'
const { t, d } = useI18n()
const mediaActions = useMediaAssetActions()
const nodeOutputStore = useNodeOutputStore()
const appModeStore = useAppModeStore()
const { runButtonClick } = defineProps<{
runButtonClick?: (e: Event) => void
mobile?: boolean
@@ -190,6 +191,7 @@ async function rerun(e: Event) {
v-else-if="getMediaType(selectedOutput) === '3d'"
:model-url="selectedOutput!.url"
/>
<LinearArrange v-else-if="appModeStore.mode === 'builder:arrange'" />
<LinearWelcome v-else />
<OutputHistory
@update-selection="

View File

@@ -1,7 +1,10 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { useAppModeStore } from '@/stores/appModeStore'
import Button from '@/components/ui/button/Button.vue'
const { t } = useI18n()
const appModeStore = useAppModeStore()
</script>
<template>
@@ -11,21 +14,50 @@ const { t } = useI18n()
class="flex flex-col items-center justify-center h-full gap-6 p-8 max-w-lg mx-auto text-center"
>
<div class="flex flex-col gap-2">
<h2 class="text-xl font-semibold text-base-foreground">
{{ t('linearMode.welcome.title')
}}<sup class="ml-1 text-xs font-normal text-muted-foreground">{{
t('g.experimental')
}}</sup>
<h2 class="text-3xl font-semibold text-muted-foreground">
{{ t('linearMode.welcome.title') }}
</h2>
<p class="text-base text-muted-foreground">
{{ t('linearMode.welcome.intro') }}
</p>
</div>
<div class="flex flex-col gap-3 text-xs text-muted-foreground/70 max-w-md">
<p>{{ t('linearMode.welcome.layout') }}</p>
<p>{{ t('linearMode.welcome.sharing') }}</p>
<p>{{ t('linearMode.welcome.widget') }}</p>
<div class="flex flex-col gap-3 text-muted-foreground max-w-md text-[14px]">
<p class="mt-0">{{ t('linearMode.welcome.message') }}</p>
<p class="mt-0">{{ t('linearMode.welcome.controls') }}</p>
<p class="mt-0">{{ t('linearMode.welcome.sharing') }}</p>
</div>
<div v-if="appModeStore.hasOutputs" class="flex flex-row gap-2 text-[14px]">
<p class="mt-0 text-base-foreground">
<i18n-t keypath="linearMode.welcome.getStarted" tag="span">
<template #runButton>
<span
class="inline-flex items-center px-3.5 py-0.5 mx-0.5 transform -translate-y-0.5 rounded bg-primary-background text-base-foreground text-xxs font-medium cursor-default"
>
{{ t('menu.run') }}
</span>
</template>
</i18n-t>
</p>
</div>
<div v-else class="flex flex-row gap-2">
<Button
variant="textonly"
size="lg"
@click="appModeStore.setMode('graph')"
>
{{ t('linearMode.welcome.backToWorkflow') }}
</Button>
<Button
variant="primary"
size="lg"
@click="appModeStore.setMode('builder:select')"
>
<i class="icon-[lucide--hammer]" />
{{ t('linearMode.welcome.buildApp') }}
<div
class="bg-base-foreground text-base-background text-xxs rounded-full absolute -top-2 -right-2 px-1"
>
{{ t('g.experimental') }}
</div>
</Button>
</div>
</div>
</template>