@@ -2,8 +2,61 @@ import { ResizableHandle, ResizablePanelGroup } from "@/components/Resizable";
2
2
import { Editor } from "./Editor" ;
3
3
import { Logo } from "./components/Logo" ;
4
4
import { Preview } from "./Preview" ;
5
+ import { useStore } from "@/store" ;
6
+ import { useEffect , type FC } from "react" ;
7
+
8
+ // Glue code required to be able to run wasm compiled Go code.
9
+ import "@/utils/wasm_exec.js" ;
10
+ import { LoaderIcon } from "lucide-react" ;
11
+
12
+ type GoPreviewDef = ( v : unknown ) => Promise < string > ;
13
+
14
+ // Extend the Window object to include the Go related code that is added from
15
+ // wasm_exec.js and our loaded Go code.
16
+ declare global {
17
+ interface Window {
18
+ // Loaded from wasm
19
+ go_preview ?: GoPreviewDef ;
20
+ Go : { new ( ) : Go } ;
21
+ }
22
+ }
23
+
24
+ declare class Go {
25
+ argv : string [ ] ;
26
+ env : { [ envKey : string ] : string } ;
27
+ exit : ( code : number ) => void ;
28
+ importObject : WebAssembly . Imports ;
29
+ exited : boolean ;
30
+ mem : DataView ;
31
+ run ( instance : WebAssembly . Instance ) : Promise < void > ;
32
+ }
5
33
6
34
export const App = ( ) => {
35
+ const $isWasmLoaded = useStore ( ( state ) => state . isWasmLoaded ) ;
36
+ const $setIsWasmLoaded = useStore ( ( state ) => state . setIsWasmLoaded ) ;
37
+
38
+ // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
39
+ useEffect ( ( ) => {
40
+ const initWasm = async ( ) => {
41
+ try {
42
+ const goWasm = new window . Go ( ) ;
43
+ const result = await WebAssembly . instantiateStreaming (
44
+ fetch ( "build/preview.wasm" ) ,
45
+ goWasm . importObject ,
46
+ ) ;
47
+
48
+ goWasm . run ( result . instance ) ;
49
+ $setIsWasmLoaded ( true ) ;
50
+ } catch ( e ) {
51
+ console . error ( e ) ;
52
+ }
53
+ } ;
54
+
55
+ if ( ! $isWasmLoaded ) {
56
+ initWasm ( ) ;
57
+ }
58
+ } , [ ] ) ;
59
+
7
60
return (
8
61
< main className = "flex h-dvh w-screen flex-col items-center bg-surface-primary" >
9
62
{ /* NAV BAR */ }
@@ -43,16 +96,42 @@ export const App = () => {
43
96
</ div >
44
97
</ nav >
45
98
46
- { /* CONTENT */ }
47
- < ResizablePanelGroup direction = { "horizontal" } >
48
- { /* EDITOR */ }
49
- < Editor />
99
+ < div className = "relative h-full w-full" >
100
+ { ! $isWasmLoaded ? (
101
+ < div className = "absolute top-0 left-0 z-30 flex h-full w-full items-center justify-center backdrop-blur-sm" >
102
+ < WasmLoading />
103
+ </ div >
104
+ ) : null }
105
+
106
+ < ResizablePanelGroup
107
+ aria-hidden = { ! $isWasmLoaded }
108
+ direction = { "horizontal" }
109
+ >
110
+ { /* EDITOR */ }
111
+ < Editor />
50
112
51
- < ResizableHandle className = "bg-surface-quaternary" />
113
+ < ResizableHandle className = "bg-surface-quaternary" />
52
114
53
- { /* PREVIEW */ }
54
- < Preview />
55
- </ ResizablePanelGroup >
115
+ { /* PREVIEW */ }
116
+ < Preview />
117
+ </ ResizablePanelGroup >
118
+ </ div >
56
119
</ main >
57
120
) ;
58
121
} ;
122
+
123
+ const WasmLoading : FC = ( ) => {
124
+ return (
125
+ < div className = "flex w-full max-w-xs flex-col items-center justify-center gap-2 rounded-xl border border-[#38BDF8] bg-surface-tertiary p-4" >
126
+ < LoaderIcon className = "animate-spin text-content-primary" />
127
+ < div className = "text-center" >
128
+ < p className = "font-semibold text-content-primary text-xl" >
129
+ Loading Assets
130
+ </ p >
131
+ < p className = "text-content-secondary text-sm" >
132
+ Add some copy here to explain that this will only take a few moments
133
+ </ p >
134
+ </ div >
135
+ </ div >
136
+ ) ;
137
+ } ;
0 commit comments