11import "@/index.css"
2- import { ErrorBoundary , Show , type ParentProps } from "solid-js"
2+ import { createSignal , ErrorBoundary , onCleanup , onMount , Show , type ParentProps } from "solid-js"
33import { Router , Route , Navigate } from "@solidjs/router"
44import { MetaProvider } from "@solidjs/meta"
55import { Font } from "@opencode-ai/ui/font"
@@ -20,6 +20,7 @@ import { FileProvider } from "@/context/file"
2020import { NotificationProvider } from "@/context/notification"
2121import { DialogProvider } from "@opencode-ai/ui/context/dialog"
2222import { CommandProvider } from "@/context/command"
23+ import { Logo } from "@opencode-ai/ui/logo"
2324import Layout from "@/pages/layout"
2425import Home from "@/pages/home"
2526import DirectoryLayout from "@/pages/directory-layout"
@@ -29,7 +30,7 @@ import { iife } from "@opencode-ai/util/iife"
2930
3031declare global {
3132 interface Window {
32- __OPENCODE__ ?: { updaterEnabled ?: boolean ; port ?: number }
33+ __OPENCODE__ ?: { updaterEnabled ?: boolean ; port ?: number ; serverReady ?: boolean }
3334 }
3435}
3536
@@ -54,6 +55,44 @@ function ServerKey(props: ParentProps) {
5455 )
5556}
5657
58+ // Loading screen shown while desktop server is starting
59+ function LoadingScreen ( ) {
60+ return (
61+ < div class = "h-screen w-screen flex flex-col items-center justify-center bg-background-base" >
62+ < Logo class = "w-xl opacity-12 animate-pulse" />
63+ < div class = "mt-8 text-14-regular text-text-weak" > Starting server...</ div >
64+ </ div >
65+ )
66+ }
67+
68+ // Gate component that waits for the desktop server to be ready
69+ function DesktopServerGate ( props : ParentProps ) {
70+ // Check if we're running in desktop mode with serverReady flag
71+ const isDesktop = ( ) => typeof window . __OPENCODE__ !== "undefined" && "serverReady" in ( window . __OPENCODE__ ?? { } )
72+ const [ ready , setReady ] = createSignal ( window . __OPENCODE__ ?. serverReady ?? true )
73+
74+ onMount ( ( ) => {
75+ if ( ! isDesktop ( ) ) return
76+
77+ // If already ready, no need to wait
78+ if ( window . __OPENCODE__ ?. serverReady ) {
79+ setReady ( true )
80+ return
81+ }
82+
83+ // Listen for the server-ready event
84+ const handler = ( ) => setReady ( true )
85+ window . addEventListener ( "opencode:server-ready" , handler )
86+ onCleanup ( ( ) => window . removeEventListener ( "opencode:server-ready" , handler ) )
87+ } )
88+
89+ return (
90+ < Show when = { ready ( ) } fallback = { < LoadingScreen /> } >
91+ { props . children }
92+ </ Show >
93+ )
94+ }
95+
5796export function App ( ) {
5897 return (
5998 < MetaProvider >
@@ -64,46 +103,48 @@ export function App() {
64103 < MarkedProvider >
65104 < DiffComponentProvider component = { Diff } >
66105 < CodeComponentProvider component = { Code } >
67- < ServerProvider defaultUrl = { defaultServerUrl } >
68- < ServerKey >
69- < GlobalSDKProvider >
70- < GlobalSyncProvider >
71- < Router
72- root = { ( props ) => (
73- < PermissionProvider >
74- < LayoutProvider >
75- < NotificationProvider >
76- < CommandProvider >
77- < Layout > { props . children } </ Layout >
78- </ CommandProvider >
79- </ NotificationProvider >
80- </ LayoutProvider >
81- </ PermissionProvider >
82- ) }
83- >
84- < Route path = "/" component = { Home } />
85- < Route path = "/:dir" component = { DirectoryLayout } >
86- < Route path = "/" component = { ( ) => < Navigate href = "session" /> } />
87- < Route
88- path = "/session/:id?"
89- component = { ( p ) => (
90- < Show when = { p . params . id ?? "new" } keyed >
91- < TerminalProvider >
92- < FileProvider >
93- < PromptProvider >
94- < Session />
95- </ PromptProvider >
96- </ FileProvider >
97- </ TerminalProvider >
98- </ Show >
99- ) }
100- />
101- </ Route >
102- </ Router >
103- </ GlobalSyncProvider >
104- </ GlobalSDKProvider >
105- </ ServerKey >
106- </ ServerProvider >
106+ < DesktopServerGate >
107+ < ServerProvider defaultUrl = { defaultServerUrl } >
108+ < ServerKey >
109+ < GlobalSDKProvider >
110+ < GlobalSyncProvider >
111+ < Router
112+ root = { ( props ) => (
113+ < PermissionProvider >
114+ < LayoutProvider >
115+ < NotificationProvider >
116+ < CommandProvider >
117+ < Layout > { props . children } </ Layout >
118+ </ CommandProvider >
119+ </ NotificationProvider >
120+ </ LayoutProvider >
121+ </ PermissionProvider >
122+ ) }
123+ >
124+ < Route path = "/" component = { Home } />
125+ < Route path = "/:dir" component = { DirectoryLayout } >
126+ < Route path = "/" component = { ( ) => < Navigate href = "session" /> } />
127+ < Route
128+ path = "/session/:id?"
129+ component = { ( p ) => (
130+ < Show when = { p . params . id ?? "new" } keyed >
131+ < TerminalProvider >
132+ < FileProvider >
133+ < PromptProvider >
134+ < Session />
135+ </ PromptProvider >
136+ </ FileProvider >
137+ </ TerminalProvider >
138+ </ Show >
139+ ) }
140+ />
141+ </ Route >
142+ </ Router >
143+ </ GlobalSyncProvider >
144+ </ GlobalSDKProvider >
145+ </ ServerKey >
146+ </ ServerProvider >
147+ </ DesktopServerGate >
107148 </ CodeComponentProvider >
108149 </ DiffComponentProvider >
109150 </ MarkedProvider >
0 commit comments