feat: move live demo into iframes
This commit is contained in:
parent
f3d12243b9
commit
c64a77286e
@ -10,7 +10,9 @@
|
||||
width="calc(100% - 40px)"
|
||||
height="400px"
|
||||
>
|
||||
<slot/>
|
||||
<one-iframe global-style="body { margin: 0 !important; } .veui-layout { min-width: auto !important; }">
|
||||
<slot/>
|
||||
</one-iframe>
|
||||
</browser-window>
|
||||
<slot v-else/>
|
||||
</section>
|
||||
@ -104,6 +106,7 @@ import toast from 'veui/plugins/toast'
|
||||
import { BrowserWindow } from 'vue-windows'
|
||||
import { getLocale } from '../common/i18n'
|
||||
import { play } from '../common/play'
|
||||
import OneIframe from './OneIframe'
|
||||
import OneEditLink from './OneEditLink'
|
||||
import OneRepl from './OneRepl'
|
||||
import 'veui-theme-dls-icons/copy'
|
||||
@ -119,6 +122,7 @@ export default {
|
||||
'veui-button': Button,
|
||||
'veui-icon': Icon,
|
||||
BrowserWindow,
|
||||
OneIframe,
|
||||
OneEditLink,
|
||||
OneRepl
|
||||
},
|
||||
@ -223,12 +227,10 @@ Icon.register({
|
||||
padding 30px
|
||||
|
||||
& >>> .style-module_body__14MV-
|
||||
overflow hidden
|
||||
transform translate(0, 0)
|
||||
padding 0
|
||||
|
||||
& >>> .veui-layout
|
||||
min-width auto
|
||||
|
||||
.desc
|
||||
border 1px solid #eee
|
||||
padding 18px 20px
|
||||
|
98
components/OneIframe.vue
Normal file
98
components/OneIframe.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<fragment>
|
||||
<iframe
|
||||
ref="iframe"
|
||||
class="one-iframe"
|
||||
/>
|
||||
<slot/>
|
||||
</fragment>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Fragment } from 'vue-frag'
|
||||
|
||||
export default {
|
||||
name: 'one-iframe',
|
||||
components: {
|
||||
Fragment
|
||||
},
|
||||
props: {
|
||||
globalStyle: String
|
||||
},
|
||||
watch: {
|
||||
globalStyle (value) {
|
||||
if (this.style) {
|
||||
this.style.textContent = value
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
if (this.contents) {
|
||||
this.contents.forEach(node => {
|
||||
this.$refs.iframe.parentNode.appendChild(node)
|
||||
})
|
||||
}
|
||||
|
||||
if (this.mo) {
|
||||
this.mo.disconnect()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const links = document.querySelectorAll('link[rel=stylesheet]')
|
||||
const styles = document.querySelectorAll('style')
|
||||
const { iframe } = this.$refs
|
||||
const { body, head } = iframe.contentDocument
|
||||
this.contents = this.$el.frag.filter(node => node !== iframe);
|
||||
[...links, ...styles].forEach(node => {
|
||||
const clone = node.cloneNode(true)
|
||||
head.appendChild(clone)
|
||||
})
|
||||
|
||||
this.contents.forEach(node => {
|
||||
body.appendChild(node)
|
||||
})
|
||||
|
||||
if (this.globalStyle) {
|
||||
const style = document.createElement('style')
|
||||
style.textContent = this.globalStyle
|
||||
head.appendChild(style)
|
||||
this.style = style
|
||||
}
|
||||
|
||||
this.watchLiveStyle(head)
|
||||
},
|
||||
methods: {
|
||||
watchLiveStyle (head) {
|
||||
this.liveStyle = document.createComment('')
|
||||
head.appendChild(this.liveStyle)
|
||||
|
||||
this.mo = new MutationObserver(mutations => {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.target === document.head) {
|
||||
const style = (this.liveSource = [...mutation.addedNodes].find(
|
||||
node => node.nodeName === 'STYLE' && node.dataset.cssscoper
|
||||
))
|
||||
if (style) {
|
||||
const liveStyle = style.cloneNode(true)
|
||||
head.replaceChild(liveStyle, this.liveStyle)
|
||||
this.liveStyle = liveStyle
|
||||
}
|
||||
} else if (mutation.target === this.liveSource) {
|
||||
this.liveStyle.textContent = this.liveSource.textContent
|
||||
}
|
||||
}
|
||||
})
|
||||
this.mo.observe(document.head, { childList: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.one-iframe
|
||||
display block
|
||||
width 100%
|
||||
height 100%
|
||||
border none
|
||||
overflow auto
|
||||
</style>
|
@ -68,14 +68,16 @@
|
||||
'live-preview-browser': browser
|
||||
}"
|
||||
>
|
||||
<v-live-preview
|
||||
class="editor-preview"
|
||||
:code="transformedCode"
|
||||
:requires="imports"
|
||||
:check-variable-availability="false"
|
||||
@success="dismissError"
|
||||
@error="handleError"
|
||||
/>
|
||||
<one-iframe global-style="body { margin: 0 !important; } body > article { margin: 24px 36px; } .veui-layout { min-width: auto !important; }">
|
||||
<v-live-preview
|
||||
class="editor-preview"
|
||||
:code="transformedCode"
|
||||
:requires="imports"
|
||||
:check-variable-availability="false"
|
||||
@success="dismissError"
|
||||
@error="handleError"
|
||||
/>
|
||||
</one-iframe>
|
||||
<transition name="editor-error">
|
||||
<veui-alert
|
||||
v-if="error"
|
||||
@ -113,6 +115,7 @@ import { getLocale } from '../common/i18n'
|
||||
import { play } from '../common/play'
|
||||
import { transformLessCode } from '../common/transform'
|
||||
import { loadPref, savePref } from '../common/util'
|
||||
import OneIframe from './OneIframe'
|
||||
|
||||
Vue.use(toast)
|
||||
|
||||
@ -158,7 +161,8 @@ export default {
|
||||
'v-splitpanes': Splitpanes,
|
||||
'v-pane': Pane,
|
||||
'v-monaco-editor': MonacoEditor,
|
||||
'v-live-preview': VueLivePreview
|
||||
'v-live-preview': VueLivePreview,
|
||||
OneIframe
|
||||
},
|
||||
directives: {
|
||||
tooltip
|
||||
|
@ -4,50 +4,48 @@
|
||||
class="one-nav"
|
||||
:class="{ expanded }"
|
||||
>
|
||||
<header>
|
||||
<h2>VEUI</h2>
|
||||
<section class="desc">
|
||||
<a href="https://github.com/ecomfe/veui">
|
||||
<img
|
||||
alt="VEUI on GitHub"
|
||||
src="https://img.shields.io/github/stars/ecomfe/veui?label=stars&logo=github"
|
||||
height="20"
|
||||
>
|
||||
</a>
|
||||
<nuxt-link
|
||||
:class="{
|
||||
'locale-swith': true,
|
||||
disabled: altLocale.disabled,
|
||||
}"
|
||||
:to="altLocale.disabled ? '' : altLocale.to"
|
||||
>
|
||||
{{ altLocale.label }}
|
||||
</nuxt-link>
|
||||
</section>
|
||||
<section class="search">
|
||||
<one-search/>
|
||||
</section>
|
||||
<div
|
||||
class="toggle"
|
||||
@click="toggleMenu"
|
||||
>
|
||||
<veui-icon
|
||||
class="expanded-icon"
|
||||
name="chevron-left"
|
||||
/>
|
||||
<veui-icon
|
||||
class="collapsed-icon"
|
||||
name="hamburger"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
<veui-menu
|
||||
class="one-menu"
|
||||
:items="menuItems"
|
||||
:expanded.sync="menuExpanded"
|
||||
>
|
||||
<template #before>
|
||||
<header>
|
||||
<h2>VEUI</h2>
|
||||
<section class="desc">
|
||||
<a href="https://github.com/ecomfe/veui">
|
||||
<img
|
||||
alt="VEUI on GitHub"
|
||||
src="https://img.shields.io/github/stars/ecomfe/veui?label=stars&logo=github"
|
||||
height="20"
|
||||
>
|
||||
</a>
|
||||
<nuxt-link
|
||||
:class="{
|
||||
'locale-swith': true,
|
||||
disabled: altLocale.disabled,
|
||||
}"
|
||||
:to="altLocale.disabled ? '' : altLocale.to"
|
||||
>
|
||||
{{ altLocale.label }}
|
||||
</nuxt-link>
|
||||
</section>
|
||||
<section class="search">
|
||||
<one-search/>
|
||||
</section>
|
||||
<div
|
||||
class="toggle"
|
||||
@click="toggleMenu"
|
||||
>
|
||||
<veui-icon
|
||||
class="expanded-icon"
|
||||
name="chevron-left"
|
||||
/>
|
||||
<veui-icon
|
||||
class="collapsed-icon"
|
||||
name="hamburger"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
<template #item-label="{ label, sub }">
|
||||
{{ label }}<small>{{ sub }}</small>
|
||||
</template>
|
||||
@ -147,31 +145,14 @@ export default {
|
||||
top 0
|
||||
bottom 0
|
||||
left 0
|
||||
display flex
|
||||
flex-direction column
|
||||
width 280px
|
||||
z-index 1
|
||||
|
||||
.one-menu
|
||||
width 100%
|
||||
height 100%
|
||||
background-color #fff
|
||||
|
||||
& >>> .veui-menu-tree-wrapper
|
||||
display flex
|
||||
flex-direction column
|
||||
flex-grow 1
|
||||
height 100%
|
||||
overflow visible
|
||||
|
||||
.veui-menu-tree
|
||||
overflow auto
|
||||
|
||||
& >>> .DocSearch
|
||||
margin 0
|
||||
border-radius 6px
|
||||
font inherit
|
||||
|
||||
header
|
||||
padding 32px 20px 20px
|
||||
flex none
|
||||
|
||||
h2
|
||||
display flex
|
||||
@ -191,10 +172,6 @@ export default {
|
||||
img
|
||||
display block
|
||||
|
||||
small
|
||||
margin-left 8px
|
||||
opacity 0.7
|
||||
|
||||
.locale-swith
|
||||
display block
|
||||
margin-left 12px
|
||||
@ -215,6 +192,21 @@ export default {
|
||||
margin-right 12px
|
||||
flex-shrink 0
|
||||
|
||||
.one-menu
|
||||
flex 1 1 auto
|
||||
width 100%
|
||||
overflow auto
|
||||
background-color #fff
|
||||
|
||||
& >>> .DocSearch
|
||||
margin 0
|
||||
border-radius 6px
|
||||
font inherit
|
||||
|
||||
small
|
||||
margin-left 8px
|
||||
opacity 0.7
|
||||
|
||||
.toggle
|
||||
display none
|
||||
|
||||
|
@ -121,9 +121,6 @@ Icon.register({
|
||||
flex 1 1 auto
|
||||
height calc(100% - 48px)
|
||||
|
||||
& >>> .live-preview
|
||||
padding 24px 36px
|
||||
|
||||
& >>> .VueLive-error
|
||||
display none
|
||||
|
||||
|
@ -4,10 +4,7 @@
|
||||
Header
|
||||
</veui-header>
|
||||
<veui-layout>
|
||||
<veui-sidebar
|
||||
sticky
|
||||
style="max-height: 320px;"
|
||||
>
|
||||
<veui-sidebar sticky>
|
||||
<div class="center full">
|
||||
Sidebar
|
||||
</div>
|
||||
|
20
package-lock.json
generated
20
package-lock.json
generated
@ -82,6 +82,7 @@
|
||||
"veui-theme-dls": "^2.6.4",
|
||||
"veui-theme-dls-icons": "^2.6.4",
|
||||
"vue-awesome": "^4.5.0",
|
||||
"vue-frag": "^1.4.0",
|
||||
"vue-i18n": "^8.16.0",
|
||||
"vue-live": "^1.17.2",
|
||||
"vue-windows": "^0.2.4"
|
||||
@ -22221,6 +22222,18 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-frag": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-frag/-/vue-frag-1.4.0.tgz",
|
||||
"integrity": "sha512-S3LfATqRwSMR6O8mf92wKF3y2E/Gs/3MFJXW4CozMOLUeOopNUlkcYuhVLagw7fkNmn/Pyb1zfRY5UCwU+X6Gw==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/vue-frag?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-hot-reload-api": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
||||
@ -41338,6 +41351,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-frag": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-frag/-/vue-frag-1.4.0.tgz",
|
||||
"integrity": "sha512-S3LfATqRwSMR6O8mf92wKF3y2E/Gs/3MFJXW4CozMOLUeOopNUlkcYuhVLagw7fkNmn/Pyb1zfRY5UCwU+X6Gw==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"vue-hot-reload-api": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
|
||||
|
@ -91,6 +91,7 @@
|
||||
"veui-theme-dls": "^2.6.4",
|
||||
"veui-theme-dls-icons": "^2.6.4",
|
||||
"vue-awesome": "^4.5.0",
|
||||
"vue-frag": "^1.4.0",
|
||||
"vue-i18n": "^8.16.0",
|
||||
"vue-live": "^1.17.2",
|
||||
"vue-windows": "^0.2.4"
|
||||
|
Loading…
Reference in New Issue
Block a user