@@ -11,17 +11,21 @@ import {
11
11
watch ,
12
12
watchEffect ,
13
13
} from ' vue'
14
+ import LunaConsole from ' luna-console'
14
15
import srcdoc from ' ./srcdoc.html?raw'
15
16
import { PreviewProxy } from ' ./PreviewProxy'
17
+ import SplitPane from ' ../SplitPane.vue'
16
18
import { compileModulesForPreview } from ' ./moduleCompiler'
17
- import type { Store } from ' ../store'
18
19
import { injectKeyProps } from ' ../types'
19
20
21
+ import type { Store } from ' ../store'
22
+
20
23
export interface SandboxProps {
21
24
store: Store
22
25
show? : boolean
23
26
ssr? : boolean
24
27
clearConsole? : boolean
28
+ showConsole? : boolean
25
29
theme? : ' dark' | ' light'
26
30
previewOptions? : {
27
31
headHTML? : string
@@ -42,6 +46,7 @@ const props = withDefaults(defineProps<SandboxProps>(), {
42
46
show: true ,
43
47
ssr: false ,
44
48
theme: ' light' ,
49
+ showConsole: false ,
45
50
clearConsole: true ,
46
51
previewOptions : () => ({}),
47
52
autoStoreInit: true ,
@@ -54,15 +59,26 @@ if (keyProps === undefined && props.autoStoreInit) {
54
59
}
55
60
56
61
const containerRef = useTemplateRef (' container' )
62
+ const consoleContainerRef = useTemplateRef (' console-container' )
57
63
const runtimeError = ref <string >()
58
64
const runtimeWarning = ref <string >()
59
65
60
66
let sandbox: HTMLIFrameElement
67
+ let lunaConsole: LunaConsole
61
68
let proxy: PreviewProxy
62
69
let stopUpdateWatcher: WatchStopHandle | undefined
63
70
64
71
// create sandbox on mount
65
- onMounted (createSandbox )
72
+ onMounted (() => {
73
+ createSandbox ()
74
+ if (! consoleContainerRef .value ) return
75
+ if (props .showConsole ) {
76
+ lunaConsole = new LunaConsole (consoleContainerRef .value , {
77
+ theme: keyProps ?.theme .value || ' light' ,
78
+ })
79
+ watch (() => store .value .activeFile .code , clearLunaConsole )
80
+ }
81
+ })
66
82
67
83
// reset sandbox when import map changes
68
84
watch (
@@ -157,32 +173,33 @@ function createSandbox() {
157
173
runtimeError .value = ' Uncaught (in promise): ' + error .message
158
174
},
159
175
on_console : (log : any ) => {
160
- if (log .duplicate ) {
161
- return
162
- }
163
176
if (log .level === ' error' ) {
164
177
if (log .args [0 ] instanceof Error ) {
165
178
runtimeError .value = log .args [0 ].message
166
179
} else {
167
180
runtimeError .value = log .args [0 ]
168
181
}
182
+ lunaConsole .error (... log .args )
169
183
} else if (log .level === ' warn' ) {
170
184
if (log .args [0 ].toString ().includes (' [Vue warn]' )) {
171
185
runtimeWarning .value = log .args
172
186
.join (' ' )
173
187
.replace (/ \[ Vue warn\] :/ , ' ' )
174
188
.trim ()
175
189
}
190
+ lunaConsole .warn (... log .args )
191
+ } else {
192
+ lunaConsole .log (... log .args )
176
193
}
177
194
},
178
195
on_console_group : (action : any ) => {
179
- // group_logs (action.label, false);
196
+ lunaConsole . group (action .label )
180
197
},
181
198
on_console_group_end : () => {
182
- // ungroup_logs();
199
+ lunaConsole . groupEnd ()
183
200
},
184
201
on_console_group_collapsed : (action : any ) => {
185
- // group_logs (action.label, true);
202
+ lunaConsole . groupCollapsed (action .label )
186
203
},
187
204
})
188
205
@@ -301,18 +318,33 @@ async function updatePreview() {
301
318
}
302
319
}
303
320
321
+ function clearLunaConsole() {
322
+ lunaConsole ?.clear (true )
323
+ }
324
+
304
325
/**
305
326
* Reload the preview iframe
306
327
*/
307
328
function reload() {
308
329
sandbox .contentWindow ?.location .reload ()
330
+ clearLunaConsole ()
309
331
}
310
332
311
333
defineExpose ({ reload , container: containerRef })
312
334
</script >
313
335
314
336
<template >
337
+ <SplitPane v-if =" show && showConsole" layout =" vertical" >
338
+ <template #left >
339
+ <div ref =" container" class =" iframe-container" :class =" theme" />
340
+ </template >
341
+ <template #right >
342
+ <div ref =" console-container" />
343
+ <button class =" clear-btn" @click =" clearLunaConsole" >clear</button >
344
+ </template >
345
+ </SplitPane >
315
346
<div
347
+ v-if =" !showConsole"
316
348
v-show =" props.show"
317
349
ref =" container"
318
350
class =" iframe-container"
@@ -336,4 +368,23 @@ defineExpose({ reload, container: containerRef })
336
368
.iframe-container.dark :deep(iframe ) {
337
369
background-color : #1e1e1e ;
338
370
}
371
+ .luna-console-theme-dark {
372
+ background-color : var (--bg ) !important ;
373
+ }
374
+ .clear-btn {
375
+ position : absolute ;
376
+ font-size : 18px ;
377
+ font-family : var (--font-code );
378
+ color : #999 ;
379
+ top : 10px ;
380
+ right : 10px ;
381
+ z-index : 99 ;
382
+ padding : 8px 10px 6px ;
383
+ background-color : var (--bg );
384
+ border-radius : 4px ;
385
+ border : 1px solid var (--border );
386
+ &:hover {
387
+ color : var (--color-branding );
388
+ }
389
+ }
339
390
</style >
0 commit comments