blob: b8162f79236670f12391f67e68f568bd4bd6a470 [file] [log] [blame]
<template>
<div id="main-container">
<div
id="editor-left-container"
:style="{ width: leftContainerSize + '%' }"
v-if="!shared.isMobile"
>
<el-tabs v-model="currentTab" type="border-card">
<el-tab-pane name="code-editor">
<span slot="label">{{ $t('editor.tabEditor') }}</span>
<el-container>
<el-header id="editor-control-panel">
<div class="editor-controls">
<a
href="javascript:;"
class="btn btn-default btn-sm"
@click="disposeAndRun"
>{{ $t('editor.run') }}</a
>
</div>
</el-header>
<el-main>
<CodeMonaco
v-if="shared.typeCheck"
id="code-panel"
:initialCode="initialCode"
></CodeMonaco>
<CodeAce
v-else
id="code-panel"
:initialCode="initialCode"
></CodeAce>
</el-main>
</el-container>
</el-tab-pane>
<el-tab-pane
:label="$t('editor.tabFullCodePreview')"
name="full-code"
:lazy="true"
>
<el-container style="width: 100%; height: 100%">
<el-header id="full-code-generate-config">
<span class="full-code-generate-config-label">
<!-- <i class="el-icon-setting"></i> 配置 -->
</span>
<el-switch
v-model="fullCodeConfig.minimal"
:active-text="$t('editor.minimalBundle')"
:inactive-text="''"
>
</el-switch>
<el-switch
v-model="fullCodeConfig.esm"
active-text="ES Modules"
:inactive-text="''"
>
</el-switch>
</el-header>
<el-main>
<FullCodePreview :code="fullCode"></FullCodePreview>
</el-main>
</el-container>
</el-tab-pane>
<el-tab-pane :label="$t('editor.tabOptionPreview')" name="full-option">
<div id="option-outline"></div>
</el-tab-pane>
</el-tabs>
</div>
<div
class="handler"
id="h-handler"
@mousedown="onSplitterDragStart"
:style="{ left: leftContainerSize + '%' }"
v-if="!shared.isMobile"
></div>
<Preview
:inEditor="true"
class="right-container"
ref="preview"
:style="{
width: 100 - leftContainerSize + '%',
left: leftContainerSize + '%'
}"
></Preview>
</div>
</template>
<script>
import CodeAce from './CodeAce.vue';
import CodeMonaco from './CodeMonaco.vue';
import FullCodePreview from './FullCodePreview.vue';
import Preview from './Preview.vue';
import { store, loadExampleCode, parseSourceCode } from '../common/store';
import { collectDeps, buildExampleCode } from '../../common/buildCode';
import { mount } from '@lang/object-visualizer';
import './object-visualizer.css';
export default {
components: {
CodeAce,
CodeMonaco,
FullCodePreview,
Preview
},
data() {
return {
mousedown: false,
leftContainerSize: 40,
mobileMode: false,
shared: store,
initialCode: '',
currentTab: 'code-editor',
fullCode: '',
fullCodeConfig: {
mimimal: false,
esm: true,
node: false // If is in node
}
};
},
computed: {
currentTime() {
// Update time when message updated.
const message = this.shared.message;
const time = new Date();
const digits = [time.getHours(), time.getMinutes(), time.getSeconds()];
let timeStr = '';
for (let i = 0, len = digits.length; i < len; ++i) {
timeStr += (digits[i] < 10 ? '0' : '') + digits[i];
if (i < len - 1) {
timeStr += ':';
}
}
return timeStr;
}
},
mounted() {
if (store.isMobile) {
this.leftContainerSize = 0;
loadExampleCode().then((code) => {
// No editor available. Set to runCode directly.
store.runCode = parseSourceCode(code);
});
} else {
loadExampleCode().then((code) => {
// Only set the code in editor. editor will sync to the store.
this.initialCode = parseSourceCode(code);
});
window.addEventListener('mousemove', (e) => {
if (this.mousedown) {
let percentage = e.clientX / window.innerWidth;
percentage = Math.min(0.9, Math.max(0.1, percentage));
this.leftContainerSize = percentage * 100;
}
});
window.addEventListener('mouseup', (e) => {
this.mousedown = false;
});
}
},
methods: {
onSplitterDragStart() {
this.mousedown = true;
},
disposeAndRun() {
this.$refs.preview.refreshAll();
},
updateFullCode() {
const option = this.$refs.preview.getOption();
if (!option) {
return;
}
const deps = collectDeps(option);
deps.push(store.renderer === 'svg' ? 'SVGRenderer' : 'CanvasRenderer');
this.fullCode = buildExampleCode(store.sourceCode, deps, {
minimal: this.fullCodeConfig.minimal,
ts: store.typeCheck,
esm: this.fullCodeConfig.esm,
// legacy: true,
theme: store.darkMode ? 'dark' : '',
ROOT_PATH: store.cdnRoot
});
},
updateOptionOutline() {
const option = Object.freeze(this.$refs.preview.getOption());
if (!option) {
return;
}
mount(option, this.$el.querySelector('#option-outline'), {
getKeys(object, path) {
return Object.keys(object).filter((key) => {
if (Array.isArray(object[key]) && !object[key].length) {
return false;
}
return true;
});
},
expandOnCreatedAndUpdated(path) {
return (
path.length === 0 || (path[0] === 'series' && path.length <= 1)
);
}
});
},
updateTabContent(tab) {
if (tab === 'full-code') {
this.updateFullCode();
} else if (tab === 'full-option') {
this.updateOptionOutline();
}
}
},
watch: {
'shared.typeCheck'(enableTypeCheck) {
// Update initialCode to avoid code changed when switching editor
this.initialCode = store.sourceCode;
this.updateFullCode();
},
currentTab(tab) {
this.updateTabContent(tab);
},
'shared.runHash'() {
this.updateTabContent(this.currentTab);
},
fullCodeConfig: {
deep: true,
handler() {
this.updateFullCode();
}
}
}
};
</script>
<style lang="scss">
@import '../style/color.scss';
$control-panel-height: 30px;
$pd-basic: 10px;
$handler-width: 5px;
#main-container {
.handler {
position: absolute;
left: 50%;
top: 0;
bottom: 0;
width: $handler-width;
cursor: col-resize;
z-index: 100;
background-color: transparent;
border-left: 1px solid #ececec;
// border-right: 1px solid $clr-border;
}
}
#editor-left-container {
position: absolute;
left: 0;
bottom: 0;
top: 0;
width: 50%;
.el-tab-pane {
height: 100%;
.el-container {
width: 100%;
height: 100%;
}
.el-header {
height: $control-panel-height !important;
position: relative;
z-index: 10;
padding: 0;
}
.el-main {
padding: 0;
position: relative;
::-webkit-scrollbar {
height: 8px;
width: 8px;
transition: all 0.3s ease-in-out;
border-radius: 2px;
}
::-webkit-scrollbar-button {
display: none;
}
::-webkit-scrollbar-thumb {
width: 8px;
min-height: 15px;
background: rgba(50, 50, 50, 0.6) !important;
transition: all 0.3s ease-in-out;
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.5) !important;
}
}
}
.el-tabs {
box-shadow: none;
}
.el-tabs--border-card > .el-tabs__header {
border-bottom: none;
}
.el-tabs__content {
position: absolute;
top: 34px;
left: 0;
right: 0;
bottom: 0;
padding: 0;
}
.el-tabs__item {
height: 34px;
line-height: 34px;
}
}
#editor-control-panel,
#full-code-generate-config {
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
#option-outline {
// height: 100%;
// Fix safari
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
font-size: 13px;
font-family: 'Source Code Pro', 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas',
monospace;
}
#full-code-generate-config {
.full-code-generate-config-label {
height: $control-panel-height;
line-height: $control-panel-height;
vertical-align: middle;
margin: 0 0 0 20px;
}
.el-switch {
margin-right: 10px;
}
.el-switch__label {
margin-left: 8px;
margin-top: -2px;
}
.el-switch__label * {
font-size: 12px;
}
}
#editor-control-panel {
.setting-panel {
display: inline-block;
.btn-group + .btn-group {
margin-left: $pd-basic;
}
}
.editor-controls {
float: right;
.el-switch__label {
margin-top: -3px;
}
.el-switch__label * {
font-size: 12px;
}
.btn {
color: #fff;
border-radius: 0;
background-color: #409eff;
margin-left: $pd-basic;
border: none;
height: 30px;
width: 50px;
}
.btn:hover {
background-color: lighten($color: #409eff, $amount: 5);
}
}
}
.right-container {
position: absolute;
right: 0;
width: 50%;
height: 100%;
padding: 0;
padding-left: $handler-width;
border: none;
z-index: 30;
background: $clr-bg;
}
</style>