feat: add play in codesandbox
This commit is contained in:
@@ -20,6 +20,25 @@
|
||||
>
|
||||
<slot name="desc"/>
|
||||
</section>
|
||||
<section class="actions">
|
||||
<veui-button
|
||||
v-tooltip="t('playInCsb')"
|
||||
ui="icon"
|
||||
@click="play"
|
||||
>
|
||||
<veui-icon
|
||||
scale="0.8"
|
||||
name="csb"
|
||||
/>
|
||||
</veui-button>
|
||||
<veui-button
|
||||
v-tooltip="t(localExpanded ? 'hideCode' : 'showCode')"
|
||||
ui="icon"
|
||||
@click="localExpanded = !localExpanded"
|
||||
>
|
||||
<veui-icon :name="localExpanded ? 'code-off' : 'code'"/>
|
||||
</veui-button>
|
||||
</section>
|
||||
<section
|
||||
v-if="$slots.source"
|
||||
ref="source"
|
||||
@@ -28,27 +47,23 @@
|
||||
>
|
||||
<slot name="source"/>
|
||||
</section>
|
||||
<button
|
||||
class="toggle"
|
||||
@click="localExpanded = !localExpanded"
|
||||
>
|
||||
<veui-icon
|
||||
class="arrow"
|
||||
name="chevron-down"
|
||||
/> {{ t(localExpanded ? 'hideCode' : 'showCode') }}
|
||||
</button>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Icon } from 'veui'
|
||||
import { Button, Icon } from 'veui'
|
||||
import tooltip from 'veui/directives/tooltip'
|
||||
import i18n from 'veui/mixins/i18n'
|
||||
import { BrowserWindow } from 'vue-windows'
|
||||
import 'veui-theme-dls-icons/chevron-down'
|
||||
import { createCodeSandbox } from './play'
|
||||
|
||||
export default {
|
||||
name: 'one-demo',
|
||||
directives: {
|
||||
tooltip
|
||||
},
|
||||
components: {
|
||||
'veui-button': Button,
|
||||
'veui-icon': Icon,
|
||||
BrowserWindow
|
||||
},
|
||||
@@ -78,8 +93,31 @@ export default {
|
||||
style.height = source.offsetHeight
|
||||
this.sourceHeight = source.offsetHeight
|
||||
style.height = '0'
|
||||
},
|
||||
methods: {
|
||||
play () {
|
||||
createCodeSandbox(this.$refs.source.textContent.replace(/from 'veui'/g, 'from \'veui/dist/veui.esm\''))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Icon.register({
|
||||
'code': {
|
||||
width: 24,
|
||||
height: 24,
|
||||
d: 'M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6l6 6l1.4-1.4zm5.2 0l4.6-4.6l-4.6-4.6L16 6l6 6l-6 6l-1.4-1.4z'
|
||||
},
|
||||
'code-off': {
|
||||
width: 24,
|
||||
height: 24,
|
||||
d: 'M19.17 12l-4.58-4.59L16 6l6 6l-3.59 3.59L17 14.17L19.17 12zM1.39 4.22l4.19 4.19L2 12l6 6l1.41-1.41L4.83 12L7 9.83l12.78 12.78l1.41-1.41L2.81 2.81L1.39 4.22z'
|
||||
},
|
||||
'csb': {
|
||||
width: 32,
|
||||
height: 32,
|
||||
d: 'M2.667 8l13.938-8l13.943 8l.12 15.932L16.605 32L2.667 24zm2.786 3.307v6.344l4.458 2.479v4.688l5.297 3.063V16.85zm22.318 0l-9.755 5.542V27.88l5.292-3.063v-4.682l4.464-2.484zM6.844 8.802l9.74 5.526l9.76-5.573l-5.161-2.932l-4.547 2.594l-4.573-2.625z'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style src="vue-windows/dist/vue-windows.css"></style>
|
||||
@@ -88,14 +126,6 @@ export default {
|
||||
.one-demo
|
||||
overflow hidden
|
||||
|
||||
.arrow
|
||||
transition transform 0.3s
|
||||
height 1.2em
|
||||
margin-right 4px
|
||||
|
||||
.one-demo.expanded &
|
||||
transform rotateZ(180deg)
|
||||
|
||||
.demo
|
||||
border 1px solid #eee
|
||||
border-top-left-radius 4px
|
||||
@@ -120,26 +150,27 @@ export default {
|
||||
|
||||
.desc
|
||||
.source >>> pre
|
||||
.toggle
|
||||
.actions
|
||||
margin-top -1px
|
||||
|
||||
.toggle
|
||||
.actions
|
||||
position relative
|
||||
display flex
|
||||
justify-content center
|
||||
align-items center
|
||||
line-height 2
|
||||
width 100%
|
||||
height 40px
|
||||
height 48px
|
||||
border 1px solid #eee
|
||||
border-bottom-left-radius 4px
|
||||
border-bottom-right-radius 4px
|
||||
background-color #fff
|
||||
transition background-color 0.3s
|
||||
outline none
|
||||
cursor pointer
|
||||
|
||||
&:hover
|
||||
&.focus-visible
|
||||
background-color #fafafa
|
||||
.veui-button
|
||||
font-size 18px
|
||||
|
||||
.veui-button + .veui-button
|
||||
margin-left 8px
|
||||
</style>
|
||||
|
||||
161
components/play.js
Normal file
161
components/play.js
Normal file
@@ -0,0 +1,161 @@
|
||||
import { loading } from 'dls-graphics'
|
||||
|
||||
const API_CSB = 'https://codesandbox.io/api/v1/sandboxes/define'
|
||||
|
||||
export function createCodeSandbox (sfc) {
|
||||
const win = window.open()
|
||||
win.document.write(landing)
|
||||
fetch(`${API_CSB}?json=1`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
files: {
|
||||
...templateFiles,
|
||||
'src/Demo.vue': {
|
||||
content: sfc
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
win.location = `https://codesandbox.io/s/${data.sandbox_id}?file=/src/Demo.vue`
|
||||
})
|
||||
}
|
||||
|
||||
const meta = `{
|
||||
"dependencies": {
|
||||
"veui": "2.1.1",
|
||||
"veui-theme-dls": "2.1.1",
|
||||
"vue": "2.6.14"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const prettier = `{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"jsxBracketSameLine": false,
|
||||
"fluid": false
|
||||
}
|
||||
`
|
||||
|
||||
const index = `<!DOCTYPE html>
|
||||
<html lang="zh-Hans">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<title>VEUI Playground</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
const main = `import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import 'veui-theme-dls/dist/dls.esm'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
render: (h) => h(App)
|
||||
}).$mount('#app')
|
||||
`
|
||||
|
||||
const app = `<template>
|
||||
<main>
|
||||
<demo/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Demo from './Demo'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Demo
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
main {
|
||||
padding: 24px;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
|
||||
const templateFiles = {
|
||||
'package.json': {
|
||||
content: meta
|
||||
},
|
||||
'.prettierrc': {
|
||||
content: prettier
|
||||
},
|
||||
'public/index.html': {
|
||||
content: index
|
||||
},
|
||||
'src/main.js': {
|
||||
content: main
|
||||
},
|
||||
'src/App.vue': {
|
||||
content: app
|
||||
}
|
||||
}
|
||||
|
||||
const landing = `<!DOCTYPE html>
|
||||
<html lang="zh-Hans">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||
<title>VEUI Playground</title>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
background-color: #040404;
|
||||
}
|
||||
.loading {
|
||||
position: absolute;
|
||||
top: 38.4%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -38.4%);
|
||||
height: 48px;
|
||||
font-weight: 400;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${genLoading()}
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
function genLoading () {
|
||||
const { contents, attrs } = loading
|
||||
const attrsStr = Object.entries({
|
||||
...attrs,
|
||||
class: `loading ${attrs.class}`
|
||||
})
|
||||
.map(([key, value]) => `${key}="${value}"`)
|
||||
.join(' ')
|
||||
return `<svg ${attrsStr}>${contents}</svg>`
|
||||
}
|
||||
Reference in New Issue
Block a user