Progressbar on mobile improvement

This commit is contained in:
space-nuko
2023-05-31 14:28:56 -05:00
parent c537cb71bf
commit 5474687041
10 changed files with 333 additions and 153 deletions

View File

@@ -30,7 +30,7 @@
"prettier-plugin-svelte": "^2.10.0", "prettier-plugin-svelte": "^2.10.0",
"rollup-plugin-visualizer": "^5.9.0", "rollup-plugin-visualizer": "^5.9.0",
"sass": "^1.61.0", "sass": "^1.61.0",
"svelte": "^3.58.0", "svelte": "^3.59.0",
"svelte-check": "^3.2.0", "svelte-check": "^3.2.0",
"svelte-dnd-action": "^0.9.22", "svelte-dnd-action": "^0.9.22",
"typescript": "^5.0.3", "typescript": "^5.0.3",

81
pnpm-lock.yaml generated
View File

@@ -27,7 +27,7 @@ importers:
version: 6.11.0 version: 6.11.0
'@dogagenc/svelte-markdown': '@dogagenc/svelte-markdown':
specifier: ^0.2.4 specifier: ^0.2.4
version: 0.2.4(svelte@3.58.0) version: 0.2.4(svelte@3.59.1)
'@gradio/accordion': '@gradio/accordion':
specifier: workspace:* specifier: workspace:*
version: link:gradio/js/accordion version: link:gradio/js/accordion
@@ -93,7 +93,7 @@ importers:
version: link:litegraph/packages/tsconfig version: link:litegraph/packages/tsconfig
'@sveltejs/vite-plugin-svelte': '@sveltejs/vite-plugin-svelte':
specifier: ^2.1.1 specifier: ^2.1.1
version: 2.1.1(svelte@3.58.0)(vite@4.3.8) version: 2.1.1(svelte@3.59.1)(vite@4.3.8)
'@tsconfig/svelte': '@tsconfig/svelte':
specifier: ^4.0.1 specifier: ^4.0.1
version: 4.0.1 version: 4.0.1
@@ -156,13 +156,13 @@ importers:
version: 1.5.2 version: 1.5.2
svelte-preprocess: svelte-preprocess:
specifier: ^5.0.3 specifier: ^5.0.3
version: 5.0.3(sass@1.61.0)(svelte@3.58.0)(typescript@5.0.3) version: 5.0.3(sass@1.61.0)(svelte@3.59.1)(typescript@5.0.3)
svelte-select: svelte-select:
specifier: ^5.5.3 specifier: ^5.5.3
version: 5.5.3 version: 5.5.3
svelte-splitpanes: svelte-splitpanes:
specifier: ^0.7.13 specifier: ^0.7.13
version: 0.7.13(svelte@3.58.0) version: 0.7.13(svelte@3.59.1)
svelte-tiny-virtual-list: svelte-tiny-virtual-list:
specifier: ^2.0.5 specifier: ^2.0.5
version: 2.0.5 version: 2.0.5
@@ -190,7 +190,7 @@ importers:
version: 1.2.8 version: 1.2.8
'@zerodevx/svelte-toast': '@zerodevx/svelte-toast':
specifier: ^0.9.3 specifier: ^0.9.3
version: 0.9.3(svelte@3.58.0) version: 0.9.3(svelte@3.59.1)
eslint: eslint:
specifier: ^8.37.0 specifier: ^8.37.0
version: 8.37.0 version: 8.37.0
@@ -199,7 +199,7 @@ importers:
version: 8.8.0(eslint@8.37.0) version: 8.8.0(eslint@8.37.0)
eslint-plugin-svelte3: eslint-plugin-svelte3:
specifier: ^4.0.0 specifier: ^4.0.0
version: 4.0.0(eslint@8.37.0)(svelte@3.58.0) version: 4.0.0(eslint@8.37.0)(svelte@3.59.1)
happy-dom: happy-dom:
specifier: ^9.18.3 specifier: ^9.18.3
version: 9.18.3 version: 9.18.3
@@ -211,7 +211,7 @@ importers:
version: 2.8.7 version: 2.8.7
prettier-plugin-svelte: prettier-plugin-svelte:
specifier: ^2.10.0 specifier: ^2.10.0
version: 2.10.0(prettier@2.8.7)(svelte@3.58.0) version: 2.10.0(prettier@2.8.7)(svelte@3.59.1)
rollup-plugin-visualizer: rollup-plugin-visualizer:
specifier: ^5.9.0 specifier: ^5.9.0
version: 5.9.0 version: 5.9.0
@@ -219,14 +219,14 @@ importers:
specifier: ^1.61.0 specifier: ^1.61.0
version: 1.61.0 version: 1.61.0
svelte: svelte:
specifier: ^3.58.0 specifier: ^3.59.0
version: 3.58.0 version: 3.59.1
svelte-check: svelte-check:
specifier: ^3.2.0 specifier: ^3.2.0
version: 3.2.0(sass@1.61.0)(svelte@3.58.0) version: 3.2.0(sass@1.61.0)(svelte@3.59.1)
svelte-dnd-action: svelte-dnd-action:
specifier: ^0.9.22 specifier: ^0.9.22
version: 0.9.22(svelte@3.58.0) version: 0.9.22(svelte@3.59.1)
typescript: typescript:
specifier: ^5.0.3 specifier: ^5.0.3
version: 5.0.3 version: 5.0.3
@@ -1363,6 +1363,7 @@ packages:
'@codemirror/language': ^6.0.0 '@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0 '@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0 '@codemirror/view': ^6.0.0
'@lezer/common': ^1.0.0
dependencies: dependencies:
'@codemirror/language': 6.6.0 '@codemirror/language': 6.6.0
'@codemirror/state': 6.2.0 '@codemirror/state': 6.2.0
@@ -1506,14 +1507,14 @@ packages:
w3c-keyname: 2.2.6 w3c-keyname: 2.2.6
dev: false dev: false
/@dogagenc/svelte-markdown@0.2.4(svelte@3.58.0): /@dogagenc/svelte-markdown@0.2.4(svelte@3.59.1):
resolution: {integrity: sha512-UmmHHZ7rilAbBYiNsxuL5d8Ac79EhFXrhjsUNr30BPzn+T7ohJR8kHMFjDYDQc0tOQOfKbICvkPAQ6cprqS3Eg==} resolution: {integrity: sha512-UmmHHZ7rilAbBYiNsxuL5d8Ac79EhFXrhjsUNr30BPzn+T7ohJR8kHMFjDYDQc0tOQOfKbICvkPAQ6cprqS3Eg==}
peerDependencies: peerDependencies:
svelte: ^3.0.0 svelte: ^3.0.0
dependencies: dependencies:
'@types/marked': 4.3.1 '@types/marked': 4.3.1
marked: 4.3.0 marked: 4.3.0
svelte: 3.58.0 svelte: 3.59.1
dev: false dev: false
/@esbuild/android-arm64@0.17.18: /@esbuild/android-arm64@0.17.18:
@@ -2275,7 +2276,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@sveltejs/vite-plugin-svelte@2.1.1(svelte@3.58.0)(vite@4.3.8): /@sveltejs/vite-plugin-svelte@2.1.1(svelte@3.59.1)(vite@4.3.8):
resolution: {integrity: sha512-7YeBDt4us0FiIMNsVXxyaP4Hwyn2/v9x3oqStkHU3ZdIc5O22pGwUwH33wUqYo+7Itdmo8zxJ45Qvfm3H7UUjQ==} resolution: {integrity: sha512-7YeBDt4us0FiIMNsVXxyaP4Hwyn2/v9x3oqStkHU3ZdIc5O22pGwUwH33wUqYo+7Itdmo8zxJ45Qvfm3H7UUjQ==}
engines: {node: ^14.18.0 || >= 16} engines: {node: ^14.18.0 || >= 16}
peerDependencies: peerDependencies:
@@ -2286,8 +2287,8 @@ packages:
deepmerge: 4.3.1 deepmerge: 4.3.1
kleur: 4.1.5 kleur: 4.1.5
magic-string: 0.30.0 magic-string: 0.30.0
svelte: 3.58.0 svelte: 3.59.1
svelte-hmr: 0.15.1(svelte@3.58.0) svelte-hmr: 0.15.1(svelte@3.59.1)
vite: 4.3.8(sass@1.61.0) vite: 4.3.8(sass@1.61.0)
vitefu: 0.2.4(vite@4.3.8) vitefu: 0.2.4(vite@4.3.8)
transitivePeerDependencies: transitivePeerDependencies:
@@ -2604,12 +2605,12 @@ packages:
pretty-format: 27.5.1 pretty-format: 27.5.1
dev: false dev: false
/@zerodevx/svelte-toast@0.9.3(svelte@3.58.0): /@zerodevx/svelte-toast@0.9.3(svelte@3.59.1):
resolution: {integrity: sha512-VPKWR4A9y01fyXRscu9HiTj7tV2hFrpRKZvGwMmaPXfHIXR1D9+NNsz0HXcQ7qZ0C5UaHS3n9uNtPtIcAXT7RQ==} resolution: {integrity: sha512-VPKWR4A9y01fyXRscu9HiTj7tV2hFrpRKZvGwMmaPXfHIXR1D9+NNsz0HXcQ7qZ0C5UaHS3n9uNtPtIcAXT7RQ==}
peerDependencies: peerDependencies:
svelte: ^3.57.0 svelte: ^3.57.0
dependencies: dependencies:
svelte: 3.58.0 svelte: 3.59.1
dev: true dev: true
/abab@2.0.6: /abab@2.0.6:
@@ -3117,6 +3118,8 @@ packages:
'@codemirror/search': 6.4.0 '@codemirror/search': 6.4.0
'@codemirror/state': 6.2.0 '@codemirror/state': 6.2.0
'@codemirror/view': 6.11.0 '@codemirror/view': 6.11.0
transitivePeerDependencies:
- '@lezer/common'
dev: false dev: false
/codemirror@6.0.1(@lezer/common@1.0.2): /codemirror@6.0.1(@lezer/common@1.0.2):
@@ -3941,14 +3944,14 @@ packages:
- typescript - typescript
dev: true dev: true
/eslint-plugin-svelte3@4.0.0(eslint@8.37.0)(svelte@3.58.0): /eslint-plugin-svelte3@4.0.0(eslint@8.37.0)(svelte@3.59.1):
resolution: {integrity: sha512-OIx9lgaNzD02+MDFNLw0GEUbuovNcglg+wnd/UY0fbZmlQSz7GlQiQ1f+yX0XvC07XPcDOnFcichqI3xCwp71g==} resolution: {integrity: sha512-OIx9lgaNzD02+MDFNLw0GEUbuovNcglg+wnd/UY0fbZmlQSz7GlQiQ1f+yX0XvC07XPcDOnFcichqI3xCwp71g==}
peerDependencies: peerDependencies:
eslint: '>=8.0.0' eslint: '>=8.0.0'
svelte: ^3.2.0 svelte: ^3.2.0
dependencies: dependencies:
eslint: 8.37.0 eslint: 8.37.0
svelte: 3.58.0 svelte: 3.59.1
dev: true dev: true
/eslint-scope@5.1.1: /eslint-scope@5.1.1:
@@ -5988,14 +5991,14 @@ packages:
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
dev: true dev: true
/prettier-plugin-svelte@2.10.0(prettier@2.8.7)(svelte@3.58.0): /prettier-plugin-svelte@2.10.0(prettier@2.8.7)(svelte@3.59.1):
resolution: {integrity: sha512-GXMY6t86thctyCvQq+jqElO+MKdB09BkL3hexyGP3Oi8XLKRFaJP1ud/xlWCZ9ZIa2BxHka32zhHfcuU+XsRQg==} resolution: {integrity: sha512-GXMY6t86thctyCvQq+jqElO+MKdB09BkL3hexyGP3Oi8XLKRFaJP1ud/xlWCZ9ZIa2BxHka32zhHfcuU+XsRQg==}
peerDependencies: peerDependencies:
prettier: ^1.16.4 || ^2.0.0 prettier: ^1.16.4 || ^2.0.0
svelte: ^3.2.0 svelte: ^3.2.0
dependencies: dependencies:
prettier: 2.8.7 prettier: 2.8.7
svelte: 3.58.0 svelte: 3.59.1
dev: true dev: true
/prettier@2.8.7: /prettier@2.8.7:
@@ -6656,7 +6659,7 @@ packages:
- sugarss - sugarss
dev: true dev: true
/svelte-check@3.2.0(sass@1.61.0)(svelte@3.58.0): /svelte-check@3.2.0(sass@1.61.0)(svelte@3.59.1):
resolution: {integrity: sha512-6ZnscN8dHEN5Eq5LgIzjj07W9nc9myyBH+diXsUAuiY/3rt0l65/LCIQYlIuoFEjp2F1NhXqZiJwV9omPj9tMw==} resolution: {integrity: sha512-6ZnscN8dHEN5Eq5LgIzjj07W9nc9myyBH+diXsUAuiY/3rt0l65/LCIQYlIuoFEjp2F1NhXqZiJwV9omPj9tMw==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -6668,8 +6671,8 @@ packages:
import-fresh: 3.3.0 import-fresh: 3.3.0
picocolors: 1.0.0 picocolors: 1.0.0
sade: 1.8.1 sade: 1.8.1
svelte: 3.58.0 svelte: 3.59.1
svelte-preprocess: 5.0.3(sass@1.61.0)(svelte@3.58.0)(typescript@5.0.3) svelte-preprocess: 5.0.3(sass@1.61.0)(svelte@3.59.1)(typescript@5.0.3)
typescript: 5.0.3 typescript: 5.0.3
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'
@@ -6683,18 +6686,18 @@ packages:
- sugarss - sugarss
dev: true dev: true
/svelte-dnd-action@0.9.22(svelte@3.58.0): /svelte-dnd-action@0.9.22(svelte@3.59.1):
resolution: {integrity: sha512-lOQJsNLM1QWv5mdxIkCVtk6k4lHCtLgfE59y8rs7iOM6erchbLC9hMEFYSveZz7biJV0mpg7yDSs4bj/RT/YkA==} resolution: {integrity: sha512-lOQJsNLM1QWv5mdxIkCVtk6k4lHCtLgfE59y8rs7iOM6erchbLC9hMEFYSveZz7biJV0mpg7yDSs4bj/RT/YkA==}
peerDependencies: peerDependencies:
svelte: '>=3.23.0' svelte: '>=3.23.0'
dependencies: dependencies:
svelte: 3.58.0 svelte: 3.59.1
dev: true dev: true
/svelte-feather-icons@4.0.0: /svelte-feather-icons@4.0.0:
resolution: {integrity: sha512-4ieUsjp+VYa1r6y80jDt9zRiRUZyJNbESpRdHdJJhiBubyuXX96A7f1UZSK4olxzP6Qsg5ZAuyZlnmvD+/swAA==} resolution: {integrity: sha512-4ieUsjp+VYa1r6y80jDt9zRiRUZyJNbESpRdHdJJhiBubyuXX96A7f1UZSK4olxzP6Qsg5ZAuyZlnmvD+/swAA==}
dependencies: dependencies:
svelte: 3.58.0 svelte: 3.59.1
dev: false dev: false
/svelte-floating-ui@1.2.8: /svelte-floating-ui@1.2.8:
@@ -6718,6 +6721,16 @@ packages:
svelte: '>=3.19.0' svelte: '>=3.19.0'
dependencies: dependencies:
svelte: 3.58.0 svelte: 3.58.0
dev: true
/svelte-hmr@0.15.1(svelte@3.59.1):
resolution: {integrity: sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==}
engines: {node: ^12.20 || ^14.13.1 || >= 16}
peerDependencies:
svelte: '>=3.19.0'
dependencies:
svelte: 3.59.1
dev: false
/svelte-preprocess@4.10.1(postcss-load-config@3.1.4)(postcss@8.4.21)(svelte@3.58.0)(typescript@4.5.4): /svelte-preprocess@4.10.1(postcss-load-config@3.1.4)(postcss@8.4.21)(svelte@3.58.0)(typescript@4.5.4):
resolution: {integrity: sha512-NSNloaylf+o9UeyUR2KvpdxrAyMdHl3U7rMnoP06/sG0iwJvlUM4TpMno13RaNqovh4AAoGsx1jeYcIyuGUXMw==} resolution: {integrity: sha512-NSNloaylf+o9UeyUR2KvpdxrAyMdHl3U7rMnoP06/sG0iwJvlUM4TpMno13RaNqovh4AAoGsx1jeYcIyuGUXMw==}
@@ -6825,7 +6838,7 @@ packages:
typescript: 5.0.3 typescript: 5.0.3
dev: true dev: true
/svelte-preprocess@5.0.3(sass@1.61.0)(svelte@3.58.0)(typescript@5.0.3): /svelte-preprocess@5.0.3(sass@1.61.0)(svelte@3.59.1)(typescript@5.0.3):
resolution: {integrity: sha512-GrHF1rusdJVbOZOwgPWtpqmaexkydznKzy5qIC2FabgpFyKN57bjMUUUqPRfbBXK5igiEWn1uO/DXsa2vJ5VHA==} resolution: {integrity: sha512-GrHF1rusdJVbOZOwgPWtpqmaexkydznKzy5qIC2FabgpFyKN57bjMUUUqPRfbBXK5igiEWn1uO/DXsa2vJ5VHA==}
engines: {node: '>= 14.10.0'} engines: {node: '>= 14.10.0'}
requiresBuild: true requiresBuild: true
@@ -6869,7 +6882,7 @@ packages:
sass: 1.61.0 sass: 1.61.0
sorcery: 0.11.0 sorcery: 0.11.0
strip-indent: 3.0.0 strip-indent: 3.0.0
svelte: 3.58.0 svelte: 3.59.1
typescript: 5.0.3 typescript: 5.0.3
/svelte-range-slider-pips@2.0.1: /svelte-range-slider-pips@2.0.1:
@@ -6883,13 +6896,13 @@ packages:
svelte-floating-ui: 1.2.8 svelte-floating-ui: 1.2.8
dev: false dev: false
/svelte-splitpanes@0.7.13(svelte@3.58.0): /svelte-splitpanes@0.7.13(svelte@3.59.1):
resolution: {integrity: sha512-LiAf4OEZqRJanoax9mextXtQ0JzrdCqX2tOgVO+yJu2XNyGz5j5fGbw8+5AXgOasPi/m1nv8n2Lt+XYFRfvIGg==} resolution: {integrity: sha512-LiAf4OEZqRJanoax9mextXtQ0JzrdCqX2tOgVO+yJu2XNyGz5j5fGbw8+5AXgOasPi/m1nv8n2Lt+XYFRfvIGg==}
peerDependencies: peerDependencies:
svelte: ^3.54.0 svelte: ^3.54.0
dependencies: dependencies:
esm-env-robust: 0.0.3 esm-env-robust: 0.0.3
svelte: 3.58.0 svelte: 3.59.1
dev: false dev: false
/svelte-tiny-virtual-list@2.0.5: /svelte-tiny-virtual-list@2.0.5:
@@ -6912,6 +6925,10 @@ packages:
resolution: {integrity: sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==} resolution: {integrity: sha512-brIBNNB76mXFmU/Kerm4wFnkskBbluBDCjx/8TcpYRb298Yh2dztS2kQ6bhtjMcvUhd5ynClfwpz5h2gnzdQ1A==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
/svelte@3.59.1:
resolution: {integrity: sha512-pKj8fEBmqf6mq3/NfrB9SLtcJcUvjYSWyePlfCqN9gujLB25RitWK8PvFzlwim6hD/We35KbPlRteuA6rnPGcQ==}
engines: {node: '>= 8'}
/swiper@9.2.4: /swiper@9.2.4:
resolution: {integrity: sha512-L7y3K/iiMXNYQ94FbfcJn7jex4QPnS4+voXGupTdC+UHW4XrR40QDdm4c9hXJ+Br0Il7PP0vP1W3goM9/Ly6Sg==} resolution: {integrity: sha512-L7y3K/iiMXNYQ94FbfcJn7jex4QPnS4+voXGupTdC+UHW4XrR40QDdm4c9hXJ+Br0Il7PP0vP1W3goM9/Ly6Sg==}
engines: {node: '>= 4.7.0'} engines: {node: '>= 4.7.0'}

View File

@@ -2,7 +2,7 @@
import { onMount } from "svelte"; import { onMount } from "svelte";
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp"; import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
import { App, View } from "framework7-svelte" import { App, View, Preloader } from "framework7-svelte"
import { f7, f7ready } from 'framework7-svelte'; import { f7, f7ready } from 'framework7-svelte';
@@ -15,8 +15,7 @@
import AboutPage from './mobile/routes/about.svelte'; import AboutPage from './mobile/routes/about.svelte';
import LoginPage from './mobile/routes/login.svelte'; import LoginPage from './mobile/routes/login.svelte';
import GraphPage from './mobile/routes/graph.svelte'; import GraphPage from './mobile/routes/graph.svelte';
import ListSubWorkflowsPage from './mobile/routes/list-subworkflows.svelte'; import WorkflowPage from './mobile/routes/workflow.svelte';
import SubWorkflowPage from './mobile/routes/subworkflow.svelte';
import type { Framework7Parameters, Modal } from "framework7/types"; import type { Framework7Parameters, Modal } from "framework7/types";
export let app: ComfyApp; export let app: ComfyApp;
@@ -51,18 +50,35 @@
} }
} }
let appSetupPromise: Promise<void> = null;
let loading = true;
let lastSize = Number.POSITIVE_INFINITY;
onMount(async () => { onMount(async () => {
await app.setup(); appSetupPromise = app.setup().then(() => {
loading = false
});
window.addEventListener("backbutton", onBackKeyDown, false); window.addEventListener("backbutton", onBackKeyDown, false);
window.addEventListener("popstate", onBackKeyDown, false); window.addEventListener("popstate", onBackKeyDown, false);
});
/* // Blur any input elements when the virtual keyboard closes
Now we need to map components to routes. // Otherwise tapping on other input events can refocus the input from way
We need to pass them along with the F7 app parameters to <App> component // off the screen
*/ window.visualViewport.addEventListener("resize", function(e) {
if (e.target.height > lastSize) {
// Assume keyboard was hidden
(document.activeElement as HTMLElement)?.blur();
}
lastSize = e.target.height
})
})
let f7params: Framework7Parameters = { /*
Now we need to map components to routes.
We need to pass them along with the F7 app parameters to <App> component
*/
let f7params: Framework7Parameters = {
routes: [ routes: [
{ {
path: '/', path: '/',
@@ -79,23 +95,16 @@
path: '/login/', path: '/login/',
component: LoginPage, component: LoginPage,
}, },
// {
// path: '/graph/',
// component: GraphPage,
// options: {
// props: { app }
// }
// },
{ {
path: '/graph/', path: '/workflows/:workflowID/',
component: GraphPage, component: WorkflowPage,
options: {
props: { app }
}
},
{
path: '/subworkflows/',
component: ListSubWorkflowsPage,
options: {
props: { app }
}
},
{
path: '/subworkflows/:subworkflowID/',
component: SubWorkflowPage,
options: { options: {
props: { app } props: { app }
} }
@@ -113,23 +122,72 @@
actions: { actions: {
closeOnEscape: true, closeOnEscape: true,
}, },
touch: {
tapHold: true
}
} }
</script> </script>
{#if app} <App theme="auto" name="ComfyBox" {...f7params}>
<App theme="auto" name="ComfyBox" {...f7params}> {#if appSetupPromise}
<View {#await appSetupPromise}
url="/" <div class="comfy-app-loading">
main={true} <div>
class="safe-areas" <Preloader color="blue" size={100} />
masterDetailBreakpoint={768}, </div>
browserHistory=true, </div>
browserHistoryRoot="/mobile/" {:then}
> <View
<GenToolbar {app} /> url="/"
</View> main={true}
</App> class="safe-areas"
<div class="canvas-wrapper pane-wrapper" style="display: none"> masterDetailBreakpoint={768},
<canvas id="graph-canvas" /> browserHistory=true,
</div> browserHistoryRoot="/mobile/"
{/if} >
<GenToolbar {app} />
</View>
{:catch error}
<div class="comfy-loading-error">
<div>
Error loading app
</div>
<div>{error}</div>
{#if error != null && error.stack}
{@const lines = error.stack.split("\n")}
{#each lines as line}
<div style:font-size="16px">{line}</div>
{/each}
{/if}
</div>
{/await}
{/if}
</App>
<div class="canvas-wrapper pane-wrapper" style="display: none">
<canvas id="graph-canvas" />
</div>
<style lang="scss">
.comfy-app-loading, .comfy-loading-error {
font-size: 40px;
color: var(--body-text-color);
justify-content: center;
margin: auto;
width: 100%;
height: 100%;
text-align: center;
flex-direction: column;
display: flex;
position: absolute;
z-index: 100000000;
pointer-events: none;
user-select: none;
top: 0px;
}
.comfy-app-loading > span {
display: flex;
flex-direction: row;
justify-content: center;
}
</style>

View File

@@ -0,0 +1,58 @@
<!--
Fix a framework7 issue
https://github.com/framework7io/framework7/issues/4183
-->
<script>
let className = undefined;
export { className as class };
export let progress = 0;
export let infinite = false;
function colorClasses(props) {
const { color, textColor, bgColor, borderColor, rippleColor, dark } = props;
return {
dark,
[`color-${color}`]: color,
[`text-color-${textColor}`]: textColor,
[`bg-color-${bgColor}`]: bgColor,
[`border-color-${borderColor}`]: borderColor,
[`ripple-color-${rippleColor}`]: rippleColor,
};
}
function classNames(...args) {
const classes = [];
args.forEach((arg) => {
if (typeof arg === 'object' && arg.constructor === Object) {
Object.keys(arg).forEach((key) => {
if (arg[key]) classes.push(key);
});
} else if (arg) classes.push(arg);
});
const uniqueClasses = [];
classes.forEach((c) => {
if (uniqueClasses.indexOf(c) < 0) uniqueClasses.push(c);
});
return uniqueClasses.join(' ');
}
let classes
$: classes = classNames(
className,
'progressbar',
{
'progressbar-infinite': infinite,
},
colorClasses($$props),
);
let transformStyle = ""
$: transformStyle = progress ? `translate3d(${-100 + progress}%, 0, 0)` : '';
</script>
<span class={classes}
data-progress={progress} >
<span style:transform={transformStyle} />
</span>

View File

@@ -42,6 +42,7 @@ export default class ComfyMarkdownNode extends ComfyWidgetNode<string> {
}, },
{ {
multiline: true, multiline: true,
inputStyle: { fontFamily: "monospace" } inputStyle: { fontFamily: "monospace" }
} }
) )

View File

@@ -8,7 +8,7 @@
import { type WidgetLayout } from "$lib/stores/layoutStates"; import { type WidgetLayout } from "$lib/stores/layoutStates";
import { get, writable, type Writable } from "svelte/store"; import { get, writable, type Writable } from "svelte/store";
import { isDisabled } from "./utils" import { isDisabled } from "./utils"
import { getSafetensorsMetadata } from '$lib/utils'; import { getSafetensorsMetadata } from '$lib/utils';
export let widget: WidgetLayout | null = null; export let widget: WidgetLayout | null = null;
export let isMobile: boolean = false; export let isMobile: boolean = false;
let node: ComfyComboNode | null = null; let node: ComfyComboNode | null = null;
@@ -74,26 +74,10 @@
} }
} }
function onSelect(e: CustomEvent<any>) {
if (input)
input.blur();
navigator.vibrate(20)
const item = e.detail
console.debug("[ComboWidget] SELECT", item, item.index)
$nodeValue = item.value;
activeIndex = item.index;
listOpen = false;
}
let activeIndex = null; let activeIndex = null;
let hoverItemIndex = null; let hoverItemIndex = null;
let filterText = ""; let filterText = "";
let listOpen = null; let listOpen = null;
let scrollToIndex = null;
let start = 0;
let end = 0;
function handleHover(index: number) { function handleHover(index: number) {
// console.warn("HOV", index) // console.warn("HOV", index)
@@ -108,7 +92,9 @@
$nodeValue = item.value $nodeValue = item.value
listOpen = false; listOpen = false;
filterText = "" filterText = ""
input?.blur() setTimeout(() => {
input?.blur();
}, 100)
} }
function onFilter() { function onFilter() {
@@ -174,7 +160,10 @@
on:select={(e) => handleSelect(e.detail.index)} on:select={(e) => handleSelect(e.detail.index)}
on:blur on:blur
on:filter={onFilter}> on:filter={onFilter}>
<div class="comfy-select-list" slot="list" let:filteredItems style:--maxLabelWidth={node.maxLabelWidthChars || 100}> <div class="comfy-select-list" slot="list"
class:mobile={isMobile}
let:filteredItems
style:--maxLabelWidth={node.maxLabelWidthChars || 100}>
{#if filteredItems.length > 0} {#if filteredItems.length > 0}
{@const itemSize = isMobile ? 50 : 25} {@const itemSize = isMobile ? 50 : 25}
{@const itemsToShow = isMobile ? 10 : 30} {@const itemsToShow = isMobile ? 10 : 30}
@@ -292,9 +281,14 @@
.comfy-select-list { .comfy-select-list {
--maxLabelWidth: 100; --maxLabelWidth: 100;
--maxListWidth: 50vw;
&.mobile {
--maxListWidth: 80vw;
}
font-size: 14px; font-size: 14px;
width: min(calc((var(--maxLabelWidth) + 10) * 1ch), 50vw);
color: var(--item-color); color: var(--item-color);
width: min(calc((var(--maxLabelWidth) + 10) * 1ch), var(--maxListWidth));
> :global(.virtual-list-wrapper) { > :global(.virtual-list-wrapper) {
box-shadow: var(--block-shadow); box-shadow: var(--block-shadow);

View File

@@ -5,7 +5,7 @@
import type { ComfyMarkdownNode } from "$lib/nodes/widgets"; import type { ComfyMarkdownNode } from "$lib/nodes/widgets";
import SvelteMarkdown from "@dogagenc/svelte-markdown" import SvelteMarkdown from "@dogagenc/svelte-markdown"
import NullMarkdownRenderer from "./markdown/NullMarkdownRenderer.svelte" import NullMarkdownRenderer from "./markdown/NullMarkdownRenderer.svelte"
import { SvelteComponentDev } from "svelte/internal"; import { SvelteComponentDev } from "svelte/internal";
export let widget: WidgetLayout | null = null; export let widget: WidgetLayout | null = null;
export let isMobile: boolean = false; export let isMobile: boolean = false;
@@ -69,7 +69,7 @@
} }
/* headings /* headings
*/ */
.prose h1, .prose h1,
.prose h2, .prose h2,
@@ -107,7 +107,7 @@
} }
/* lists /* lists
*/ */
.prose ul { .prose ul {
list-style: circle inside; list-style: circle inside;
} }
@@ -136,7 +136,7 @@
} }
/* code /* code
*/ */
.prose code { .prose code {
border: 1px solid var(--border-color-primary); border: 1px solid var(--border-color-primary);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
@@ -153,7 +153,7 @@
} }
/* tables /* tables
*/ */
.prose th, .prose th,
.prose td { .prose td {
border-bottom: 1px solid #e1e1e1; border-bottom: 1px solid #e1e1e1;
@@ -170,7 +170,7 @@
} }
/* spacing /* spacing
*/ */
.prose button, .prose button,
.prose .button { .prose .button {
margin-bottom: var(--spacing-sm); margin-bottom: var(--spacing-sm);
@@ -194,7 +194,7 @@
} }
/* links /* links
*/ */
.prose a { .prose a {
color: var(--link-text-color); color: var(--link-text-color);
text-decoration: underline; text-decoration: underline;
@@ -212,7 +212,7 @@
} }
/* misc /* misc
*/ */
.prose hr { .prose hr {
margin-top: 3em; margin-top: 3em;

View File

@@ -6,6 +6,7 @@
import { Link, Toolbar } from "framework7-svelte" import { Link, Toolbar } from "framework7-svelte"
import ProgressBar from "$lib/components/ProgressBar.svelte"; import ProgressBar from "$lib/components/ProgressBar.svelte";
import Progressbar from "$lib/components/f7/progressbar.svelte";
import Indicator from "./Indicator.svelte"; import Indicator from "./Indicator.svelte";
import interfaceState from "$lib/stores/interfaceState"; import interfaceState from "$lib/stores/interfaceState";
import type { WritableLayoutStateStore } from "$lib/stores/layoutStates"; import type { WritableLayoutStateStore } from "$lib/stores/layoutStates";
@@ -53,29 +54,50 @@
navigator.vibrate(20) navigator.vibrate(20)
app.saveStateToLocalStorage(); app.saveStateToLocalStorage();
} }
let queued: false;
$: queued = Boolean($queueState.runningNodeID || $queueState.progress)
let running = false;
$: running = typeof $queueState.queueRemaining === "number" && $queueState.queueRemaining > 0;
let progress;
$: progress = $queueState.progress
let progressPercent = 0
let progressText = ""
$: if (progress) {
progressPercent = (progress.value / progress.max) * 100;
progressText = progressPercent.toFixed(1) + "%";
} else {
progressPercent = 0
progressText = "??.?%"
}
</script> </script>
<div class="bottom"> <div class="bottom">
{#if $queueState.runningNodeID || $queueState.progress} <div class="bars">
<div class="node-name"> {#if queued}
<span>Node: {getNodeInfo($queueState.runningNodeID)}</span> <div class="node-name">
</div> <span>Node: {getNodeInfo($queueState.runningNodeID)} ({progressText})</span>
<div class="progress-bar">
<ProgressBar value={$queueState.progress?.value} max={$queueState.progress?.max} />
</div>
{/if}
{#if typeof $queueState.queueRemaining === "number" && $queueState.queueRemaining > 0}
<div class="queue-remaining in-progress">
<div>
Queued prompts: {$queueState.queueRemaining}.
</div> </div>
</div> {/if}
{/if} </div>
<div class="wrapper">
{#if queued}
{#if progress}
<Progressbar color="blue" progress={progressPercent} />
{:else if running}
<Progressbar color="blue" infinite />
{/if}
{/if}
</div>
</div> </div>
<Toolbar bottom> <Toolbar bottom>
{#if workflow != null && workflow.attrs.queuePromptButtonName != ""} {#if workflow != null && workflow.attrs.queuePromptButtonName != ""}
<Link on:click={queuePrompt}> <Link on:click={queuePrompt}>
{workflow.attrs.queuePromptButtonName} {workflow.attrs.queuePromptButtonName}
</Link> </Link>
{/if} {/if}
<Link on:click={refreshCombos}>🔄</Link> <Link on:click={refreshCombos}>🔄</Link>
@@ -94,19 +116,26 @@
} }
.bottom { .bottom {
display: flex;
flex-direction: row;
position: absolute; position: absolute;
text-align: center; text-align: center;
width: 100%; width: 100%;
height: 2rem; font-size: 13pt;
bottom: calc(var(--f7-toolbar-height) + var(--f7-safe-area-bottom)); bottom: calc(var(--f7-toolbar-height));
z-index: var(--layer-top); z-index: var(--layer-top);
background-color: grey; }
.bars {
display: flex;
flex-direction: row;
.bars {
display: flex;
flex-direction: row;
}
.node-name { .node-name {
flex-grow: 1; flex-grow: 1;
background-color: var(--color-red-300); background-color: var(--secondary-300);
padding: 0.2em; padding: 0.2em;
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@@ -1,34 +1,44 @@
<script lang="ts"> <script lang="ts">
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp"; import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
import workflowState, { ComfyBoxWorkflow, type WorkflowInstID } from "$lib/stores/workflowState";
import { f7 } from 'framework7-svelte';
import { XCircle } from 'svelte-bootstrap-icons';
import { Page, Navbar, Button, BlockTitle, Block, List, ListItem } from "framework7-svelte" import { Page, Navbar, Button, BlockTitle, Block, List, ListItem } from "framework7-svelte"
export let app: ComfyApp | null = null; export let app: ComfyApp | null = null;
async function doLoadDefault() { async function doLoadDefault() {
var confirmed = confirm("Would you like to load the default workflow in a new tab?"); f7.dialog.confirm("Would you like to load the default workflow in a new tab?", async () => {
if (confirmed) {
await app.initDefaultWorkflow(); await app.initDefaultWorkflow();
} })
} }
function onClickDelete(workflow: ComfyBoxWorkflow, e: Event) {
e.preventDefault();
e.stopImmediatePropagation();
f7.dialog.confirm("Are you sure you want to delete this workflow?", workflow.attrs.title || `Workflow: ${workflow.id}`,
() => { app.closeWorkflow(workflow.id); })}
</script> </script>
<Page name="home"> <Page name="home">
<Navbar title="Home Page" /> <Navbar title="Home Page" />
<BlockTitle>Yo</BlockTitle> {#if $workflowState.openedWorkflows}
<Block> <List strong inset dividersIos class="components-list searchbar-found">
<div>{app} Nodes</div> {#each $workflowState.openedWorkflows as workflow}
</Block> <ListItem link="/workflows/{workflow.id}/" title={workflow.attrs.title || `Workflow: ${workflow.id}`}>
<svelte:fragment slot="media">
<List strong inset dividersIos class="components-list searchbar-found"> <div on:pointerdown={(e) => onClickDelete(workflow, e)}>
<ListItem link="/subworkflows/" title="Workflows"> <XCircle width="1.5em" height="1.5em" />
<i class="icon icon-f7" slot="media" /> </div>
</ListItem> </svelte:fragment>
<ListItem link="/graph/" title="Show Node Graph"> </ListItem>
<i class="icon icon-f7" slot="media" /> {/each}
</ListItem> </List>
</List> {:else}
(No workflows opened.)
{/if}
<Block strong outlineIos> <Block strong outlineIos>
<Button fill={true} onClick={doLoadDefault}>Load Default Graph</Button> <Button fill={true} onClick={doLoadDefault}>Load Default Graph</Button>
</Block> </Block>

View File

@@ -4,25 +4,38 @@
import type ComfyApp from "$lib/components/ComfyApp"; import type ComfyApp from "$lib/components/ComfyApp";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import type { WritableLayoutStateStore } from "$lib/stores/layoutStates"; import type { WritableLayoutStateStore } from "$lib/stores/layoutStates";
import workflowState, { type ComfyBoxWorkflow } from "$lib/stores/workflowState"; import workflowState, { type ComfyBoxWorkflow, type WorkflowInstID } from "$lib/stores/workflowState";
export let subworkflowID: number = -1; export let workflowID: WorkflowInstID;
export let app: ComfyApp export let app: ComfyApp
// TODO move let workflow: ComfyBoxWorkflow;
let workflow: ComfyBoxWorkflow | null = null let root: IDragItem | null;
let layoutState: WritableLayoutStateStore | null = null; let title = ""
$: workflow = $workflowState.activeWorkflow; $: workflow = workflowState.getWorkflow(workflowID);
$: layoutState = workflow ? workflow.layout : null; $: layoutState = workflow?.layout;
$: title = workflow?.attrs?.title || `Workflow: ${workflowID}`;
$: if (layoutState && $layoutState.root) {
root = $layoutState.root
} else {
root = null;
}
</script> </script>
<Page name="subworkflow"> <Page name="workflow">
<Navbar title="Workflow {subworkflowID}" backLink="Back" /> <Navbar title="{title}" backLink="Back" />
{#if layoutState} {#if workflow}
<div class="container"> {#if root}
<WidgetContainer bind:dragItem={$layoutState.root} {layoutState} isMobile={true} classes={["root-container", "mobile"]} /> <div class="container">
<WidgetContainer bind:dragItem={root} isMobile={true} classes={["root-container"]} {layoutState} />
</div>
{/if}
{:else}
<div>
Workflow not found.
</div> </div>
{/if} {/if}
</Page> </Page>