Skip to content

Commit 629d3f5

Browse files
feat: workflow UX improvements — browser support, embedded config, sidebar collapse, viewport-centered nodes
- Add browser workflow adapter (localStorage + static node defs) so workflow works without Electron - Embed NodeConfigPanel and ResultsPanel inside selected node cards on canvas (remove right sidebar) - Sidebar always visible with responsive collapse (1024px breakpoint) and bottom toggle button - New nodes placed at center of current viewport instead of hardcoded coordinates - Allow closing the last workflow tab (resets to clean blank state) - Default theme to 'auto' (follow system preference) - Grid lines background on workflow canvas - Fix Capacitor module resolution, .npmrc ELECTRON_MIRROR warning, useFreeToolListener crash in browser - Update workflow guide to reflect in-node config/results instead of right panel Co-authored-by: Cursor <[email protected]>
1 parent 3aebeaf commit 629d3f5

21 files changed

Lines changed: 771 additions & 176 deletions

.npmrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
1+
# npm registry (optional: use npmmirror for China)
22
registry=https://registry.npmmirror.com/
3+
4+
# ELECTRON_MIRROR is not an npm config — set it in your environment if you need an Electron mirror, e.g.:
5+
# export ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "wavespeed-desktop",
3-
"version": "2.0.1",
3+
"version": "2.0.2",
44
"description": "WaveSpeedAI Desktop Application - A playground for AI models",
55
"main": "./out/main/index.js",
66
"author": {

src/components/layout/Layout.tsx

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { apiClient } from '@/api/client'
1212
import { Button } from '@/components/ui/button'
1313
import { Input } from '@/components/ui/input'
1414
import { Label } from '@/components/ui/label'
15-
import { KeyRound, Eye, EyeOff, Loader2, Zap, ExternalLink, Menu } from 'lucide-react'
15+
import { KeyRound, Eye, EyeOff, Loader2, Zap, ExternalLink } from 'lucide-react'
1616
import { VideoEnhancerPage } from '@/pages/VideoEnhancerPage'
1717
import { ImageEnhancerPage } from '@/pages/ImageEnhancerPage'
1818
import { BackgroundRemoverPage } from '@/pages/BackgroundRemoverPage'
@@ -33,30 +33,27 @@ import { useFreeToolListener } from '@/workflow/hooks/useFreeToolListener'
3333
let keyCounter = 0
3434
const nextKey = () => ++keyCounter
3535

36+
const SIDEBAR_EXPAND_BREAKPOINT = 1024 // px: below = collapsed, >= = expanded; sync on resize
37+
3638
export function Layout() {
3739
const { t } = useTranslation()
38-
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
39-
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
40+
const [sidebarCollapsed, setSidebarCollapsed] = useState(() =>
41+
typeof window !== 'undefined' ? window.innerWidth < SIDEBAR_EXPAND_BREAKPOINT : false
42+
)
43+
// Sync sidebar collapsed state to window width on resize (and initial layout)
44+
useEffect(() => {
45+
const onResize = () => setSidebarCollapsed(window.innerWidth < SIDEBAR_EXPAND_BREAKPOINT)
46+
window.addEventListener('resize', onResize)
47+
onResize()
48+
return () => window.removeEventListener('resize', onResize)
49+
}, [])
4050
const navigate = useNavigate()
4151
const location = useLocation()
4252
const hasShownUpdateToast = useRef(false)
4353

4454
// Register free-tool IPC listener globally (must be always mounted for workflow execution)
4555
useFreeToolListener()
4656

47-
// Close mobile menu when route changes; auto-collapse sidebar for workflow
48-
const prevPathRef = useRef(location.pathname)
49-
useEffect(() => {
50-
setMobileMenuOpen(false)
51-
// Auto-collapse when entering workflow, auto-expand when leaving
52-
if (location.pathname === '/workflow' && prevPathRef.current !== '/workflow') {
53-
setSidebarCollapsed(true)
54-
} else if (location.pathname !== '/workflow' && prevPathRef.current === '/workflow') {
55-
setSidebarCollapsed(false)
56-
}
57-
prevPathRef.current = location.pathname
58-
}, [location.pathname])
59-
6057
// Track which persistent pages have been visited (to delay initial mount)
6158
const [visitedPages, setVisitedPages] = useState<Set<string>>(new Set())
6259
// Track the last visited free-tools sub-page for navigation
@@ -280,29 +277,12 @@ export function Layout() {
280277
<PageResetContext.Provider value={{ resetPage }}>
281278
<TooltipProvider>
282279
<div className="flex h-screen overflow-hidden relative">
283-
{/* Mobile menu button */}
284-
<button
285-
className="fixed left-3 top-3 z-50 rounded-lg border border-border/70 bg-background/85 p-2 shadow-lg backdrop-blur md:hidden"
286-
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
287-
aria-label="Toggle menu"
288-
>
289-
<Menu className="h-5 w-5" />
290-
</button>
291-
292-
{/* Mobile overlay */}
293-
{mobileMenuOpen && (
294-
<div
295-
className="fixed inset-0 bg-black/50 z-40 md:hidden"
296-
onClick={() => setMobileMenuOpen(false)}
297-
/>
298-
)}
299-
300280
<Sidebar
301281
collapsed={sidebarCollapsed}
302-
onToggle={() => setSidebarCollapsed(!sidebarCollapsed)}
282+
onToggle={() => setSidebarCollapsed(prev => !prev)}
303283
lastFreeToolsPage={lastFreeToolsPage}
304-
isMobileOpen={mobileMenuOpen}
305-
onMobileClose={() => setMobileMenuOpen(false)}
284+
isMobileOpen={false}
285+
onMobileClose={() => {}}
306286
/>
307287
<main className="relative flex-1 overflow-hidden md:pl-0">
308288
{requiresLogin ? loginContent : (

src/components/layout/Sidebar.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,10 @@ export function Sidebar({ collapsed, onToggle, lastFreeToolsPage, isMobileOpen,
146146
return (
147147
<div
148148
className={cn(
149-
"flex h-full flex-col border-r border-border/70 bg-background/95 backdrop-blur transition-all duration-300",
150-
// Desktop styles
151-
"hidden md:flex",
149+
"flex h-full flex-col border-r border-border/70 bg-background/95 backdrop-blur transition-all duration-300 shrink-0",
152150
collapsed ? "w-16" : "w-52",
153-
// Mobile styles - fixed positioned drawer
154-
isMobileOpen && "!flex fixed inset-y-0 left-0 z-50 w-72 shadow-2xl"
151+
// Mobile overlay when hamburger opens
152+
isMobileOpen && "!fixed inset-y-0 left-0 z-50 w-72 shadow-2xl"
155153
)}
156154
>
157155
{/* Mobile close button */}
@@ -299,7 +297,7 @@ export function Sidebar({ collapsed, onToggle, lastFreeToolsPage, isMobileOpen,
299297
})}
300298
</nav>
301299

302-
{/* Toggle Button - hidden on mobile */}
300+
{/* Collapse/expand: bottom button toggles; state also syncs to window width on resize */}
303301
{!isMobileOpen && (
304302
<Tooltip delayDuration={0} open={collapsed && tooltipReady ? undefined : false}>
305303
<TooltipTrigger asChild>
@@ -308,7 +306,7 @@ export function Sidebar({ collapsed, onToggle, lastFreeToolsPage, isMobileOpen,
308306
size="sm"
309307
onClick={onToggle}
310308
className={cn(
311-
"mt-2 hidden h-9 w-full rounded-xl text-muted-foreground hover:bg-muted hover:text-foreground md:flex",
309+
"mt-2 h-9 w-full rounded-xl text-muted-foreground hover:bg-muted hover:text-foreground",
312310
collapsed ? "justify-center px-2" : "justify-start gap-3 px-3"
313311
)}
314312
>

src/i18n/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,7 @@
10451045
"workflows": "Workflows",
10461046
"newWorkflow": "New Workflow",
10471047
"untitled": "Untitled Workflow",
1048+
"modelSyncDesktopOnly": "Model sync is available in the WaveSpeed Desktop app.",
10481049
"save": "Save",
10491050
"saved": "Saved",
10501051
"saving": "Saving...",
@@ -1398,7 +1399,7 @@
13981399
},
13991400
"config": {
14001401
"title": "Configure & View Results",
1401-
"desc": "Click any node to select it. The right panel shows two tabs:\n• Config — Set model parameters, upload files, enter prompts\n• Results — View execution outputs (images, videos, 3D models)\n\nParameters update dynamically based on the node type and selected model. Results support fullscreen preview and download."
1402+
"desc": "Click any node to select it. Config and Results appear inside the node card:\n• Config — Set model parameters, upload files, enter prompts\n• Results — View execution outputs (images, videos, 3D models)\n\nParameters update dynamically based on the node type and selected model. Results support fullscreen preview and download."
14021403
},
14031404
"run": {
14041405
"title": "Run Your Workflow",

src/stores/themeStore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ export type Theme = 'auto' | 'dark' | 'light'
55
const THEME_STORAGE_KEY = 'wavespeed_theme'
66

77
function getStoredTheme(): Theme {
8-
if (typeof window === 'undefined') return 'dark'
8+
if (typeof window === 'undefined') return 'auto'
99
const stored = localStorage.getItem(THEME_STORAGE_KEY)
1010
if (stored === 'dark' || stored === 'light' || stored === 'auto') {
1111
return stored
1212
}
13-
return 'dark' // Default to dark theme
13+
return 'auto'
1414
}
1515

1616
function applyTheme(theme: Theme) {

0 commit comments

Comments
 (0)