diff --git a/package.json b/package.json index 11b5a00..80d63b4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "yehyecoa-vue", "type": "module", - "version": "0.1.0-beta", + "version": "0.2.0-beta", "private": true, "packageManager": "pnpm@10.17.0", "engines": { diff --git a/packages/vue-repl/package.json b/packages/vue-repl/package.json index ee24e9e..3275090 100644 --- a/packages/vue-repl/package.json +++ b/packages/vue-repl/package.json @@ -26,6 +26,11 @@ "import": "./dist/codemirror-editor.js", "require": null }, + "./luna-console": { + "types": "./dist/luna-console.d.ts", + "import": "./dist/luna-console.js", + "require": null + }, "./core": { "types": "./dist/core.d.ts", "import": "./dist/core.js", @@ -103,7 +108,12 @@ "eslint-plugin-vue": "^10.4.0", "fflate": "^0.8.2", "hash-sum": "^2.0.0", + "licia": "^1.48.0", "lint-staged": "^16.1.4", + "luna-console": "^1.3.5", + "luna-data-grid": "^1.3.0", + "luna-dom-viewer": "^1.8.3", + "luna-object-viewer": "^0.3.1", "monaco-editor-core": "0.52.2", "prettier": "^3.6.2", "shiki": "^3.9.2", diff --git a/packages/vue-repl/src/OutputSplitPane.vue b/packages/vue-repl/src/OutputSplitPane.vue new file mode 100644 index 0000000..9ad4753 --- /dev/null +++ b/packages/vue-repl/src/OutputSplitPane.vue @@ -0,0 +1,189 @@ + + + + + diff --git a/packages/vue-repl/src/Repl.vue b/packages/vue-repl/src/Repl.vue index a290c96..aebabf9 100644 --- a/packages/vue-repl/src/Repl.vue +++ b/packages/vue-repl/src/Repl.vue @@ -4,17 +4,22 @@ import Output from './output/Output.vue' import { type Store, useStore } from './store' import { computed, provide, toRefs, useTemplateRef } from 'vue' import { + type ConsoleComponentType, + + type EditorComponentType, injectKeyPreviewRef, injectKeyProps, } from './types' import EditorContainer from './editor/EditorContainer.vue' import type * as monaco from 'monaco-editor-core' +import LunaConsole from './output/luna-console.vue' export interface Props { theme?: 'dark' | 'light' previewTheme?: boolean editor: EditorComponentType + console?: ConsoleComponentType store?: Store autoResize?: boolean showCompileOutput?: boolean @@ -22,8 +27,11 @@ export interface Props { showImportMap?: boolean showSsrOutput?: boolean showTsConfig?: boolean + showConsole?: boolean clearConsole?: boolean + showOutput?: boolean layout?: 'horizontal' | 'vertical' + outputLayout?: 'horizontal' | 'vertical' layoutReverse?: boolean ssr?: boolean previewOptions?: { @@ -53,16 +61,20 @@ const props = withDefaults(defineProps(), { theme: 'light', previewTheme: false, store: () => useStore(), + console: LunaConsole, autoResize: true, showCompileOutput: true, showOpenSourceMap: false, showImportMap: true, showSsrOutput: false, showTsConfig: true, + showOutput: true, + showConsole: false, clearConsole: true, layoutReverse: false, ssr: false, layout: 'horizontal', + outputLayout: 'vertical', previewOptions: () => ({}), editorOptions: () => ({}), splitPaneOptions: () => ({}), @@ -72,6 +84,10 @@ if (!props.editor) { throw new Error('The "editor" prop is now required.') } +const consoleWrapper = computed( + () => props.console ?? (() => ({})), +) + const outputRef = useTemplateRef('output') props.store.init() @@ -81,6 +97,9 @@ const outputSlotName = computed(() => (props.layoutReverse ? 'left' : 'right')) provide(injectKeyProps, { ...toRefs(props), + console: consoleWrapper, + + autoSave, }) provide( @@ -100,7 +119,7 @@ defineExpose({ reload }) + + diff --git a/packages/vue-repl/src/SplitPane.vue b/packages/vue-repl/src/SplitPane.vue index 8985631..71ae492 100644 --- a/packages/vue-repl/src/SplitPane.vue +++ b/packages/vue-repl/src/SplitPane.vue @@ -125,6 +125,9 @@ function changeViewSize() { font-size: 12px; color: var(--text-light); z-index: 100; + background-color: var(--bg-soft); + padding: 0.5rem; + border-radius: 4px; } .left { border-right: 1px solid var(--border); diff --git a/packages/vue-repl/src/editor/EditorContainer.vue b/packages/vue-repl/src/editor/EditorContainer.vue index 76e543a..05cbe5a 100644 --- a/packages/vue-repl/src/editor/EditorContainer.vue +++ b/packages/vue-repl/src/editor/EditorContainer.vue @@ -43,7 +43,10 @@ watch(showMessage, () => { /> -
+
() -const { store } = inject(injectKeyProps)! +const { store, showConsole } = inject(injectKeyProps)! const previewRef = useTemplateRef('preview') const modes = computed(() => { const outputModes: OutputModes[] = ['preview'] @@ -51,6 +57,9 @@ function openSourceMap() { function reload() { previewRef.value?.reload() + store.value.clearConsole?.() + + } defineExpose({ reload, previewRef }) @@ -69,7 +78,15 @@ defineExpose({ reload, previewRef })
- + + + + + diff --git a/packages/vue-repl/src/output/Sandbox.vue b/packages/vue-repl/src/output/Sandbox.vue index c62f480..8c969f0 100644 --- a/packages/vue-repl/src/output/Sandbox.vue +++ b/packages/vue-repl/src/output/Sandbox.vue @@ -15,7 +15,7 @@ import srcdoc from './srcdoc.html?raw' import { PreviewProxy } from './PreviewProxy' import { compileModulesForPreview } from './moduleCompiler' import type { Store } from '../store' -import { injectKeyProps } from '../types' +import { type LogLevel, type SandboxEmits, injectKeyProps } from '../types' import { getVersions, isVaporSupported } from '../import-map' export interface SandboxProps { @@ -47,6 +47,10 @@ const props = withDefaults(defineProps(), { previewOptions: () => ({}), autoStoreInit: true, }) + +const emit = defineEmits() + + const { store, theme, clearConsole, previewOptions } = toRefs(props) const keyProps = inject(injectKeyProps) @@ -132,6 +136,9 @@ function createSandbox() { sandbox.srcdoc = sandboxSrc containerRef.value?.appendChild(sandbox) + const doLog = (logLevel: LogLevel, data?: any) => + emit('log', { logLevel, data }) + proxy = new PreviewProxy(sandbox, { on_fetch_progress: (progress: any) => { // pending_imports = progress; @@ -157,33 +164,33 @@ function createSandbox() { } runtimeError.value = 'Uncaught (in promise): ' + error.message }, - on_console: (log: any) => { - if (log.duplicate) { - return - } + on_console: (log: any) => { + const maybeMsg = log.args[0] if (log.level === 'error') { - if (log.args[0] instanceof Error) { - runtimeError.value = log.args[0].message - } else { - runtimeError.value = log.args[0] - } - } else if (log.level === 'warn') { - if (log.args[0].toString().includes('[Vue warn]')) { - runtimeWarning.value = log.args - .join('') - .replace(/\[Vue warn\]:/, '') - .trim() + if (maybeMsg instanceof Error) { + runtimeError.value = maybeMsg.message + } else if (!maybeMsg?.startsWith('[vue-repl]')) { + runtimeError.value = maybeMsg } + } else if ( + log.level === 'warn' && + maybeMsg.toString().includes('[Vue warn]') + ) { + runtimeWarning.value = log.args + .join('') + .replace(/\[Vue warn\]:/, '') + .trim() } + doLog(log.level || 'log', log.args) }, on_console_group: (action: any) => { - // group_logs(action.label, false); + doLog('group', action.label) }, on_console_group_end: () => { - // ungroup_logs(); + doLog('groupEnd') }, on_console_group_collapsed: (action: any) => { - // group_logs(action.label, true); + doLog('groupCollapsed', action.label) }, }) @@ -348,12 +355,7 @@ defineExpose({ reload, container: containerRef })