@@ -11,17 +11,21 @@ import {
1111 watch ,
1212 watchEffect ,
1313} from ' vue'
14+ import LunaConsole from ' luna-console'
1415import srcdoc from ' ./srcdoc.html?raw'
1516import { PreviewProxy } from ' ./PreviewProxy'
17+ import SplitPane from ' ../SplitPane.vue'
1618import { compileModulesForPreview } from ' ./moduleCompiler'
17- import type { Store } from ' ../store'
1819import { injectKeyProps } from ' ../types'
1920
21+ import type { Store } from ' ../store'
22+
2023export interface SandboxProps {
2124 store: Store
2225 show? : boolean
2326 ssr? : boolean
2427 clearConsole? : boolean
28+ showConsole? : boolean
2529 theme? : ' dark' | ' light'
2630 previewOptions? : {
2731 headHTML? : string
@@ -42,6 +46,7 @@ const props = withDefaults(defineProps<SandboxProps>(), {
4246 show: true ,
4347 ssr: false ,
4448 theme: ' light' ,
49+ showConsole: false ,
4550 clearConsole: true ,
4651 previewOptions : () => ({}),
4752 autoStoreInit: true ,
@@ -54,15 +59,26 @@ if (keyProps === undefined && props.autoStoreInit) {
5459}
5560
5661const containerRef = useTemplateRef (' container' )
62+ const consoleContainerRef = useTemplateRef (' console-container' )
5763const runtimeError = ref <string >()
5864const runtimeWarning = ref <string >()
5965
6066let sandbox: HTMLIFrameElement
67+ let lunaConsole: LunaConsole
6168let proxy: PreviewProxy
6269let stopUpdateWatcher: WatchStopHandle | undefined
6370
6471// 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+ })
6682
6783// reset sandbox when import map changes
6884watch (
@@ -157,32 +173,33 @@ function createSandbox() {
157173 runtimeError .value = ' Uncaught (in promise): ' + error .message
158174 },
159175 on_console : (log : any ) => {
160- if (log .duplicate ) {
161- return
162- }
163176 if (log .level === ' error' ) {
164177 if (log .args [0 ] instanceof Error ) {
165178 runtimeError .value = log .args [0 ].message
166179 } else {
167180 runtimeError .value = log .args [0 ]
168181 }
182+ lunaConsole .error (... log .args )
169183 } else if (log .level === ' warn' ) {
170184 if (log .args [0 ].toString ().includes (' [Vue warn]' )) {
171185 runtimeWarning .value = log .args
172186 .join (' ' )
173187 .replace (/ \[ Vue warn\] :/ , ' ' )
174188 .trim ()
175189 }
190+ lunaConsole .warn (... log .args )
191+ } else {
192+ lunaConsole .log (... log .args )
176193 }
177194 },
178195 on_console_group : (action : any ) => {
179- // group_logs (action.label, false);
196+ lunaConsole . group (action .label )
180197 },
181198 on_console_group_end : () => {
182- // ungroup_logs();
199+ lunaConsole . groupEnd ()
183200 },
184201 on_console_group_collapsed : (action : any ) => {
185- // group_logs (action.label, true);
202+ lunaConsole . groupCollapsed (action .label )
186203 },
187204 })
188205
@@ -301,18 +318,33 @@ async function updatePreview() {
301318 }
302319}
303320
321+ function clearLunaConsole() {
322+ lunaConsole ?.clear (true )
323+ }
324+
304325/**
305326 * Reload the preview iframe
306327 */
307328function reload() {
308329 sandbox .contentWindow ?.location .reload ()
330+ clearLunaConsole ()
309331}
310332
311333defineExpose ({ reload , container: containerRef })
312334 </script >
313335
314336<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 >
315346 <div
347+ v-if =" !showConsole"
316348 v-show =" props.show"
317349 ref =" container"
318350 class =" iframe-container"
@@ -336,4 +368,23 @@ defineExpose({ reload, container: containerRef })
336368.iframe-container.dark :deep(iframe ) {
337369 background-color : #1e1e1e ;
338370}
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+ }
339390 </style >
0 commit comments