doc: support CodeSandbox (#4861)

This commit is contained in:
John 2021-11-08 19:10:20 +08:00 committed by GitHub
parent c3400115dd
commit 45c0583426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 125 additions and 2 deletions

View File

@ -127,6 +127,7 @@
"chalk": "^4.1.1", "chalk": "^4.1.1",
"cheerio": "^1.0.0-rc.2", "cheerio": "^1.0.0-rc.2",
"codecov": "^3.0.0", "codecov": "^3.0.0",
"codesandbox": "^2.2.3",
"colorful": "^2.1.0", "colorful": "^2.1.0",
"commander": "^7.2.0", "commander": "^7.2.0",
"compare-versions": "^3.3.0", "compare-versions": "^3.3.0",

View File

@ -19,6 +19,12 @@
</div> </div>
<div class="code-box-description" v-html="docHtml"></div> <div class="code-box-description" v-html="docHtml"></div>
<div class="code-box-actions"> <div class="code-box-actions">
<a-tooltip :title="$t('app.demo.codesandbox')">
<CodeSandboxOutlined
class="code-box-code-copy code-box-code-action"
@click="handleCodeSandbox"
/>
</a-tooltip>
<a-tooltip :title="$t(`app.demo.type.${type === 'JS' ? 'js' : 'ts'}`)"> <a-tooltip :title="$t(`app.demo.type.${type === 'JS' ? 'js' : 'ts'}`)">
<span <span
class="code-expand-icon code-box-code-action" class="code-expand-icon code-box-code-action"
@ -72,7 +78,7 @@
</div> </div>
</section> </section>
<section :class="highlightClass"> <section :class="highlightClass">
<div class="highlight"> <div class="highlight" ref="codeRef">
<slot v-if="type === 'TS'" name="htmlCode" /> <slot v-if="type === 'TS'" name="htmlCode" />
<slot v-else name="jsVersionHtml" /> <slot v-else name="jsVersionHtml" />
</div> </div>
@ -84,13 +90,17 @@
import type { GlobalConfig } from '../App.vue'; import type { GlobalConfig } from '../App.vue';
import { GLOBAL_CONFIG } from '../SymbolKey'; import { GLOBAL_CONFIG } from '../SymbolKey';
import { computed, defineComponent, inject, onMounted, ref } from 'vue'; import { computed, defineComponent, inject, onMounted, ref } from 'vue';
import { CheckOutlined, SnippetsOutlined } from '@ant-design/icons-vue'; import { CheckOutlined, SnippetsOutlined, CodeSandboxOutlined } from '@ant-design/icons-vue';
import { getCodeSandboxParams } from '../utils/generateOnlineDemo';
import packageInfo from '../../../package.json';
// import { Modal } from 'ant-design-vue'; // import { Modal } from 'ant-design-vue';
export default defineComponent({ export default defineComponent({
name: 'DemoBox', name: 'DemoBox',
components: { components: {
CheckOutlined, CheckOutlined,
SnippetsOutlined, SnippetsOutlined,
CodeSandboxOutlined,
}, },
props: { props: {
jsfiddle: Object, jsfiddle: Object,
@ -100,6 +110,7 @@ export default defineComponent({
const type = ref('TS'); const type = ref('TS');
const copyTooltipVisible = ref(false); const copyTooltipVisible = ref(false);
const copied = ref(false); const copied = ref(false);
const codeRef = ref<HTMLDivElement>();
const sectionId = computed(() => { const sectionId = computed(() => {
const relativePath = props.jsfiddle?.relativePath || ''; const relativePath = props.jsfiddle?.relativePath || '';
return `${relativePath.split('/').join('-').replace('.vue', '')}`; return `${relativePath.split('/').join('-').replace('.vue', '')}`;
@ -170,6 +181,21 @@ export default defineComponent({
} }
type.value = type.value === 'TS' ? 'JS' : 'TS'; type.value = type.value === 'TS' ? 'JS' : 'TS';
}; };
const handleCodeSandbox = () => {
const code = codeRef.value!.innerText;
const params = getCodeSandboxParams(code, {
title: `${title.value} - ant-design-vue@${packageInfo.version}`,
});
const div = document.createElement('div');
div.style.display = 'none';
div.innerHTML = `<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank">
<input type="hidden" name="parameters" value="${params}" />
<input type="submit" value="Open in sandbox" />
</form>`;
document.body.appendChild(div);
(div.firstElementChild as HTMLFormElement).submit();
document.body.removeChild(div);
};
const highlightClass = computed(() => { const highlightClass = computed(() => {
return { return {
'highlight-wrapper': true, 'highlight-wrapper': true,
@ -207,6 +233,8 @@ export default defineComponent({
highlightClass, highlightClass,
sourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.sourceCode))), sourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.sourceCode))),
jsSourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.jsSourceCode))), jsSourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.jsSourceCode))),
codeRef,
handleCodeSandbox,
}; };
}, },
}); });

View File

@ -0,0 +1,94 @@
import { getParameters } from 'codesandbox/lib/api/define';
const indexHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<title>Ant Design Vue Demo</title>
<style>
body {
padding: 20px;
}
</style>
</head>
<body>
<div id="app"></div>
</body>
</html>
`;
const appVue = `<template>
<Demo />
</template>
<script>
import { defineComponent } from "vue";
import Demo from "./demo.vue";
export default defineComponent({
components: {
Demo,
},
});
</script>`;
const mainJs = `import { createApp } from "vue";
import App from "./App.vue";
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
const app = createApp(App).use(Antd);
app.mount("#app");
`;
function getDeps(code: string) {
return (code.match(/from '([^']+)';\n/g) || [])
.map(v => v.slice(6, v.length - 3))
.reduce((prevV, dep) => {
prevV[dep] = 'latest';
return prevV;
}, {});
}
type Meta = {
title: string;
};
// codeSandbox
export function getCodeSandboxParams(code: string, meta: Meta): string {
return getParameters({
files: {
'package.json': {
content: JSON.stringify({
title: meta.title,
dependencies: {
...getDeps(code),
vue: 'next',
'ant-design-vue': 'next',
},
devDependencies: {
'@vue/cli-plugin-babel': '~4.5.0',
typescript: '^4.0.5',
},
browserslist: ['> 0.2%', 'not dead'],
}),
isBinary: false,
},
'index.html': {
content: indexHtml,
isBinary: false,
},
'src/demo.vue': {
content: code,
isBinary: false,
},
'src/App.vue': {
content: appVue,
isBinary: false,
},
'src/main.js': {
content: mainJs,
isBinary: false,
},
},
});
}