Skip to content

Commit 45c0583

Browse files
authored
doc: support CodeSandbox (#4861)
1 parent c340011 commit 45c0583

File tree

3 files changed

+125
-2
lines changed

3 files changed

+125
-2
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
"chalk": "^4.1.1",
128128
"cheerio": "^1.0.0-rc.2",
129129
"codecov": "^3.0.0",
130+
"codesandbox": "^2.2.3",
130131
"colorful": "^2.1.0",
131132
"commander": "^7.2.0",
132133
"compare-versions": "^3.3.0",

site/src/components/DemoBox.vue

+30-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
</div>
2020
<div class="code-box-description" v-html="docHtml"></div>
2121
<div class="code-box-actions">
22+
<a-tooltip :title="$t('app.demo.codesandbox')">
23+
<CodeSandboxOutlined
24+
class="code-box-code-copy code-box-code-action"
25+
@click="handleCodeSandbox"
26+
/>
27+
</a-tooltip>
2228
<a-tooltip :title="$t(`app.demo.type.${type === 'JS' ? 'js' : 'ts'}`)">
2329
<span
2430
class="code-expand-icon code-box-code-action"
@@ -72,7 +78,7 @@
7278
</div>
7379
</section>
7480
<section :class="highlightClass">
75-
<div class="highlight">
81+
<div class="highlight" ref="codeRef">
7682
<slot v-if="type === 'TS'" name="htmlCode" />
7783
<slot v-else name="jsVersionHtml" />
7884
</div>
@@ -84,13 +90,17 @@
8490
import type { GlobalConfig } from '../App.vue';
8591
import { GLOBAL_CONFIG } from '../SymbolKey';
8692
import { computed, defineComponent, inject, onMounted, ref } from 'vue';
87-
import { CheckOutlined, SnippetsOutlined } from '@ant-design/icons-vue';
93+
import { CheckOutlined, SnippetsOutlined, CodeSandboxOutlined } from '@ant-design/icons-vue';
94+
import { getCodeSandboxParams } from '../utils/generateOnlineDemo';
95+
import packageInfo from '../../../package.json';
96+
8897
// import { Modal } from 'ant-design-vue';
8998
export default defineComponent({
9099
name: 'DemoBox',
91100
components: {
92101
CheckOutlined,
93102
SnippetsOutlined,
103+
CodeSandboxOutlined,
94104
},
95105
props: {
96106
jsfiddle: Object,
@@ -100,6 +110,7 @@ export default defineComponent({
100110
const type = ref('TS');
101111
const copyTooltipVisible = ref(false);
102112
const copied = ref(false);
113+
const codeRef = ref<HTMLDivElement>();
103114
const sectionId = computed(() => {
104115
const relativePath = props.jsfiddle?.relativePath || '';
105116
return `${relativePath.split('/').join('-').replace('.vue', '')}`;
@@ -170,6 +181,21 @@ export default defineComponent({
170181
}
171182
type.value = type.value === 'TS' ? 'JS' : 'TS';
172183
};
184+
const handleCodeSandbox = () => {
185+
const code = codeRef.value!.innerText;
186+
const params = getCodeSandboxParams(code, {
187+
title: `${title.value} - ant-design-vue@${packageInfo.version}`,
188+
});
189+
const div = document.createElement('div');
190+
div.style.display = 'none';
191+
div.innerHTML = `<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank">
192+
<input type="hidden" name="parameters" value="${params}" />
193+
<input type="submit" value="Open in sandbox" />
194+
</form>`;
195+
document.body.appendChild(div);
196+
(div.firstElementChild as HTMLFormElement).submit();
197+
document.body.removeChild(div);
198+
};
173199
const highlightClass = computed(() => {
174200
return {
175201
'highlight-wrapper': true,
@@ -207,6 +233,8 @@ export default defineComponent({
207233
highlightClass,
208234
sourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.sourceCode))),
209235
jsSourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.jsSourceCode))),
236+
codeRef,
237+
handleCodeSandbox,
210238
};
211239
},
212240
});

site/src/utils/generateOnlineDemo.ts

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { getParameters } from 'codesandbox/lib/api/define';
2+
3+
const indexHtml = `<!DOCTYPE html>
4+
<html lang="en">
5+
<head>
6+
<title>Ant Design Vue Demo</title>
7+
<style>
8+
body {
9+
padding: 20px;
10+
}
11+
</style>
12+
</head>
13+
<body>
14+
<div id="app"></div>
15+
</body>
16+
</html>
17+
`;
18+
19+
const appVue = `<template>
20+
<Demo />
21+
</template>
22+
23+
<script>
24+
import { defineComponent } from "vue";
25+
import Demo from "./demo.vue";
26+
27+
export default defineComponent({
28+
components: {
29+
Demo,
30+
},
31+
});
32+
</script>`;
33+
34+
const mainJs = `import { createApp } from "vue";
35+
import App from "./App.vue";
36+
import Antd from 'ant-design-vue';
37+
import 'ant-design-vue/dist/antd.css';
38+
39+
const app = createApp(App).use(Antd);
40+
app.mount("#app");
41+
`;
42+
43+
function getDeps(code: string) {
44+
return (code.match(/from '([^']+)';\n/g) || [])
45+
.map(v => v.slice(6, v.length - 3))
46+
.reduce((prevV, dep) => {
47+
prevV[dep] = 'latest';
48+
return prevV;
49+
}, {});
50+
}
51+
52+
type Meta = {
53+
title: string;
54+
};
55+
56+
// codeSandbox
57+
export function getCodeSandboxParams(code: string, meta: Meta): string {
58+
return getParameters({
59+
files: {
60+
'package.json': {
61+
content: JSON.stringify({
62+
title: meta.title,
63+
dependencies: {
64+
...getDeps(code),
65+
vue: 'next',
66+
'ant-design-vue': 'next',
67+
},
68+
devDependencies: {
69+
'@vue/cli-plugin-babel': '~4.5.0',
70+
typescript: '^4.0.5',
71+
},
72+
browserslist: ['> 0.2%', 'not dead'],
73+
}),
74+
isBinary: false,
75+
},
76+
'index.html': {
77+
content: indexHtml,
78+
isBinary: false,
79+
},
80+
'src/demo.vue': {
81+
content: code,
82+
isBinary: false,
83+
},
84+
'src/App.vue': {
85+
content: appVue,
86+
isBinary: false,
87+
},
88+
'src/main.js': {
89+
content: mainJs,
90+
isBinary: false,
91+
},
92+
},
93+
});
94+
}

0 commit comments

Comments
 (0)