feat: use monaco instead of vue-prism-editor and support switching color scheme for the editor
This commit is contained in:
@@ -4,42 +4,57 @@
|
||||
min-size="30"
|
||||
class="live-editor"
|
||||
>
|
||||
<v-live-editor
|
||||
:code="localCode"
|
||||
:editor-props="{
|
||||
lineNumbers: true
|
||||
<v-monaco-editor
|
||||
v-model="localCode"
|
||||
style="height: 100%"
|
||||
language="html"
|
||||
:theme="theme"
|
||||
:options="{
|
||||
automaticLayout: true,
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
}"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<div class="editor-toolbar">
|
||||
<veui-button
|
||||
v-tooltip="t('@onedemo.playInCodeSandbox')"
|
||||
ui="s translucent square"
|
||||
:ui="iconUi"
|
||||
@click="play('CodeSandbox')"
|
||||
>
|
||||
<veui-icon name="one-demo-codesandbox"/>
|
||||
</veui-button>
|
||||
<veui-button
|
||||
v-tooltip="t('@onedemo.playInStackBlitz')"
|
||||
ui="s translucent square"
|
||||
:ui="iconUi"
|
||||
@click="play('StackBlitz')"
|
||||
>
|
||||
<veui-icon name="one-demo-stackblitz"/>
|
||||
</veui-button>
|
||||
<veui-button
|
||||
v-tooltip="t('reset')"
|
||||
ui="s translucent square"
|
||||
:ui="iconUi"
|
||||
@click="reset"
|
||||
>
|
||||
<veui-icon name="anticlockwise"/>
|
||||
</veui-button>
|
||||
<veui-button
|
||||
v-tooltip="t('copyCode')"
|
||||
ui="s translucent square"
|
||||
:ui="iconUi"
|
||||
@click="copy"
|
||||
>
|
||||
<veui-icon name="copy"/>
|
||||
</veui-button>
|
||||
<veui-button
|
||||
v-tooltip="t(colorSchemeLabelKey)"
|
||||
:ui="iconUi"
|
||||
@click="switchColorScheme"
|
||||
>
|
||||
<veui-icon
|
||||
:name="colorSchemeIcon"
|
||||
scale="1.2"
|
||||
/>
|
||||
</veui-button>
|
||||
<div class="editor-live-badge">
|
||||
<span>Live</span>
|
||||
</div>
|
||||
@@ -74,9 +89,10 @@
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { VueLiveEditor, VueLivePreview } from 'vue-live'
|
||||
import 'vue-live/lib/vue-live.esm.css'
|
||||
import 'prism-theme-night-owl/build/no-italics.css'
|
||||
import { VueLivePreview } from 'vue-live'
|
||||
import MonacoEditor from 'vue-monaco'
|
||||
import { editor } from 'monaco-editor/esm/vs/editor/editor.api'
|
||||
import NightOwl from 'monaco-themes/themes/Night Owl.json'
|
||||
import { Button, Icon, Alert } from 'veui'
|
||||
import * as veui from 'veui'
|
||||
import lodash from 'lodash'
|
||||
@@ -91,12 +107,42 @@ import 'splitpanes/dist/splitpanes.css'
|
||||
import { getLocale } from '../common/i18n'
|
||||
import { play } from '../common/play'
|
||||
import { transformLessCode } from '../common/transform'
|
||||
import { loadPref, savePref } from '../common/util'
|
||||
|
||||
Vue.use(toast)
|
||||
|
||||
editor.defineTheme('night-owl', NightOwl)
|
||||
|
||||
Icon.register({
|
||||
'one-live-color-scheme-auto': {
|
||||
width: 24,
|
||||
height: 24,
|
||||
d:
|
||||
'M7.5 2c-1.79 1.15-3 3.18-3 5.5s1.21 4.35 3.03 5.5C4.46 13 2 10.54 2 7.5A5.5 5.5 0 0 1 7.5 2m11.57 1.5l1.43 1.43L4.93 20.5L3.5 19.07L19.07 3.5m-6.18 2.43L11.41 5L9.97 6l.42-1.7L9 3.24l1.75-.12l.58-1.65L12 3.1l1.73.03l-1.35 1.13l.51 1.67m-3.3 3.61l-1.16-.73l-1.12.78l.34-1.32l-1.09-.83l1.36-.09l.45-1.29l.51 1.27l1.36.03l-1.05.87l.4 1.31M19 13.5a5.5 5.5 0 0 1-5.5 5.5c-1.22 0-2.35-.4-3.26-1.07l7.69-7.69c.67.91 1.07 2.04 1.07 3.26m-4.4 6.58l2.77-1.15l-.24 3.35l-2.53-2.2m4.33-2.7l1.15-2.77l2.2 2.54l-3.35.23m1.15-4.96l-1.14-2.78l3.34.24l-2.2 2.54M9.63 18.93l2.77 1.15l-2.53 2.19l-.24-3.34z'
|
||||
},
|
||||
'one-live-color-scheme-light': {
|
||||
width: 24,
|
||||
height: 24,
|
||||
d:
|
||||
'M12 9c1.65 0 3 1.35 3 3s-1.35 3-3 3s-3-1.35-3-3s1.35-3 3-3m0-2c-2.76 0-5 2.24-5 5s2.24 5 5 5s5-2.24 5-5s-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58a.996.996 0 0 0-1.41 0a.996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37a.996.996 0 0 0-1.41 0a.996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41l-1.06-1.06zm1.06-10.96a.996.996 0 0 0 0-1.41a.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36a.996.996 0 0 0 0-1.41a.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z'
|
||||
},
|
||||
'one-live-color-scheme-dark': {
|
||||
width: 24,
|
||||
height: 24,
|
||||
d:
|
||||
'M9.37 5.51A7.35 7.35 0 0 0 9.1 7.5c0 4.08 3.32 7.4 7.4 7.4c.68 0 1.35-.09 1.99-.27A7.014 7.014 0 0 1 12 19c-3.86 0-7-3.14-7-7c0-2.93 1.81-5.45 4.37-6.49zM12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26a5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z'
|
||||
}
|
||||
})
|
||||
|
||||
const iconPackage = 'veui-theme-dls-icons'
|
||||
const iconNames = Object.keys(Icon.icons).filter(name => !name.startsWith('one-demo-') && Icon.icons[name])
|
||||
const iconModules = [iconPackage].concat(iconNames.map(name => `${iconPackage}/${name}`))
|
||||
const iconNames = Object.keys(Icon.icons).filter(
|
||||
name => !name.startsWith('one-demo-') && Icon.icons[name]
|
||||
)
|
||||
const iconModules = [iconPackage].concat(
|
||||
iconNames.map(name => `${iconPackage}/${name}`)
|
||||
)
|
||||
|
||||
const colorSchemeOptions = ['dark', 'light', 'auto']
|
||||
|
||||
export default {
|
||||
name: 'one-live',
|
||||
@@ -106,7 +152,7 @@ export default {
|
||||
'veui-alert': Alert,
|
||||
'v-splitpanes': Splitpanes,
|
||||
'v-pane': Pane,
|
||||
'v-live-editor': VueLiveEditor,
|
||||
'v-monaco-editor': MonacoEditor,
|
||||
'v-live-preview': VueLivePreview
|
||||
},
|
||||
directives: {
|
||||
@@ -132,7 +178,9 @@ export default {
|
||||
mocks[module] = true
|
||||
return mocks
|
||||
}, {})
|
||||
}
|
||||
},
|
||||
colorSchemeOption: loadPref('prefers-color-scheme'),
|
||||
colorSchemeSystemPref: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -144,6 +192,46 @@ export default {
|
||||
}
|
||||
|
||||
return error.name ? `${error.name}: ${error.message}` : error.message
|
||||
},
|
||||
colorScheme () {
|
||||
if (!this.colorSchemeOption || !this.mql) {
|
||||
return 'dark'
|
||||
}
|
||||
|
||||
if (this.colorSchemeOption === 'auto') {
|
||||
return this.colorSchemeSystemPref
|
||||
}
|
||||
|
||||
return this.colorSchemeOption
|
||||
},
|
||||
theme () {
|
||||
return this.colorScheme === 'dark' ? 'night-owl' : 'vs'
|
||||
},
|
||||
iconUi () {
|
||||
const ui = 's square icon'
|
||||
return this.colorScheme === 'dark' ? `${ui} reverse` : ui
|
||||
},
|
||||
colorSchemeIcon () {
|
||||
if (!this.colorSchemeOption) {
|
||||
return 'one-live-color-scheme-dark'
|
||||
}
|
||||
|
||||
return {
|
||||
light: 'one-live-color-scheme-light',
|
||||
dark: 'one-live-color-scheme-dark',
|
||||
auto: 'one-live-color-scheme-auto'
|
||||
}[this.colorSchemeOption]
|
||||
},
|
||||
colorSchemeLabelKey () {
|
||||
if (!this.colorSchemeOption) {
|
||||
return 'darkMode'
|
||||
}
|
||||
|
||||
return {
|
||||
light: 'lightMode',
|
||||
dark: 'darkMode',
|
||||
auto: 'followSystem'
|
||||
}[this.colorSchemeOption]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -162,6 +250,13 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.mql = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
this.mql.addEventListener('change', this.handleColorSchemeChange)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.mql.removeEventListener('change', this.handleColorSchemeChange)
|
||||
},
|
||||
methods: {
|
||||
play (vendor) {
|
||||
let locale = getLocale(this.$route.path)
|
||||
@@ -175,6 +270,21 @@ export default {
|
||||
this.$toast.error(this.t('copyFailed'))
|
||||
}
|
||||
},
|
||||
switchColorScheme () {
|
||||
if (!this.colorSchemeOption) {
|
||||
this.colorSchemeOption = 'light'
|
||||
} else {
|
||||
this.colorSchemeOption = colorSchemeOptions[
|
||||
(colorSchemeOptions.indexOf(this.colorSchemeOption) + 1) %
|
||||
colorSchemeOptions.length
|
||||
]
|
||||
}
|
||||
|
||||
savePref('prefers-color-scheme', this.colorSchemeOption)
|
||||
},
|
||||
handleColorSchemeChange () {
|
||||
this.colorSchemeSystemPref = this.mql.matches ? 'dark' : 'light'
|
||||
},
|
||||
reset () {
|
||||
this.localCode = this.code
|
||||
},
|
||||
@@ -208,7 +318,7 @@ export default {
|
||||
.editor-toolbar
|
||||
position absolute
|
||||
top 12px
|
||||
right 20px
|
||||
right 28px
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
@@ -224,10 +334,6 @@ export default {
|
||||
color #fff
|
||||
height 18px
|
||||
|
||||
span
|
||||
position relative
|
||||
top -1px
|
||||
|
||||
&::before
|
||||
content ""
|
||||
position absolute
|
||||
@@ -268,4 +374,14 @@ export default {
|
||||
100%
|
||||
transform scale(0.95)
|
||||
box-shadow 0 0 0 0 rgba(255, 255, 255, 0)
|
||||
|
||||
.veui-button[ui~="icon"][ui~="reverse"]
|
||||
color #ebedf5
|
||||
|
||||
&:hover
|
||||
&[data-focus-visible-added]
|
||||
color #f6f7fa
|
||||
|
||||
&:active
|
||||
color #fff
|
||||
</style>
|
||||
|
@@ -70,6 +70,7 @@ export default {
|
||||
padding 0 24px
|
||||
box-shadow 0 0 4px #0006
|
||||
position relative
|
||||
z-index 1
|
||||
|
||||
h1
|
||||
flex none
|
||||
@@ -86,30 +87,6 @@ export default {
|
||||
flex 1 1 auto
|
||||
height calc(100vh - 48px)
|
||||
|
||||
& >>> .prism-editor-wrapper
|
||||
padding 8px 12px
|
||||
font-size 12px
|
||||
color #eee
|
||||
background-color #0a0b0d
|
||||
line-height 1.5
|
||||
font-family Menlo, consolas, monospace
|
||||
-webkit-font-smoothing auto
|
||||
|
||||
&::-webkit-scrollbar
|
||||
width 8px
|
||||
background transparent
|
||||
transition all 0.3s
|
||||
|
||||
&-thumb
|
||||
border-radius 4px
|
||||
background-color #282c33
|
||||
|
||||
&:hover::-webkit-scrollbar-thumb
|
||||
background-color #545b66
|
||||
|
||||
textarea
|
||||
outline none
|
||||
|
||||
& >>> .live-preview
|
||||
padding 24px 36px
|
||||
|
||||
|
Reference in New Issue
Block a user