Skip to content
File

Blob: src/client/main.tsx

typescript57 lines
1import { useState, useEffect } from "react";
2import { createRoot } from "react-dom/client";
3import { App } from "./app";
4import "./styles/app.css";
5 
6// ghostty-web requires WASM initialisation before any Terminal is created.
7// Instead of blocking the React tree on init(), we render immediately and
8// show a loading screen until the WASM module is ready.
9import { init } from "ghostty-web";
10 
11function Root() {
12 const [wasmReady, setWasmReady] = useState(false);
13 const [wasmError, setWasmError] = useState<string | null>(null);
14 
15 useEffect(() => {
16 init()
17 .then(() => setWasmReady(true))
18 .catch((err: unknown) => {
19 const msg = err instanceof Error ? err.message : String(err);
20 setWasmError(msg);
21 });
22 }, []);
23 
24 if (wasmError) {
25 return (
26 <div className="flex flex-col h-full">
27 <div className="flex items-center justify-center w-full h-full bg-canvas">
28 <div className="flex flex-col items-center gap-4">
29 <div className="text-red-400 text-sm text-center max-w-[400px] leading-relaxed">
30 Failed to initialize terminal: {wasmError}
31 </div>
32 </div>
33 </div>
34 </div>
35 );
36 }
37 
38 if (!wasmReady) {
39 return (
40 <div className="flex flex-col h-full">
41 <div className="flex items-center justify-center w-full h-full bg-canvas" role="status" aria-live="polite">
42 <div className="flex flex-col items-center gap-4">
43 <div className="size-8 rounded-full border-3 border-zinc-700 border-t-zinc-100 animate-spinner" />
44 <div className="text-zinc-100 text-sm">Initializing terminal&hellip;</div>
45 </div>
46 </div>
47 </div>
48 );
49 }
50 
51 return <App />;
52}
53 
54const el = document.getElementById("root");
55if (!el) throw new Error("Missing #root element");
56createRoot(el).render(<Root />);