From 45c058342695ec069819c9e807508319ad11e54d Mon Sep 17 00:00:00 2001 From: John Date: Mon, 8 Nov 2021 19:10:20 +0800 Subject: [PATCH] doc: support CodeSandbox (#4861) --- package.json | 1 + site/src/components/DemoBox.vue | 32 +++++++++- site/src/utils/generateOnlineDemo.ts | 94 ++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 site/src/utils/generateOnlineDemo.ts diff --git a/package.json b/package.json index d2617a8ce..b652b36e5 100644 --- a/package.json +++ b/package.json @@ -127,6 +127,7 @@ "chalk": "^4.1.1", "cheerio": "^1.0.0-rc.2", "codecov": "^3.0.0", + "codesandbox": "^2.2.3", "colorful": "^2.1.0", "commander": "^7.2.0", "compare-versions": "^3.3.0", diff --git a/site/src/components/DemoBox.vue b/site/src/components/DemoBox.vue index 05f6e3ae4..b0cfe9062 100644 --- a/site/src/components/DemoBox.vue +++ b/site/src/components/DemoBox.vue @@ -19,6 +19,12 @@
+ + +
-
+
@@ -84,13 +90,17 @@ import type { GlobalConfig } from '../App.vue'; import { GLOBAL_CONFIG } from '../SymbolKey'; 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'; export default defineComponent({ name: 'DemoBox', components: { CheckOutlined, SnippetsOutlined, + CodeSandboxOutlined, }, props: { jsfiddle: Object, @@ -100,6 +110,7 @@ export default defineComponent({ const type = ref('TS'); const copyTooltipVisible = ref(false); const copied = ref(false); + const codeRef = ref(); const sectionId = computed(() => { const relativePath = props.jsfiddle?.relativePath || ''; return `${relativePath.split('/').join('-').replace('.vue', '')}`; @@ -170,6 +181,21 @@ export default defineComponent({ } 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 = `
+ + +
`; + document.body.appendChild(div); + (div.firstElementChild as HTMLFormElement).submit(); + document.body.removeChild(div); + }; const highlightClass = computed(() => { return { 'highlight-wrapper': true, @@ -207,6 +233,8 @@ export default defineComponent({ highlightClass, sourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.sourceCode))), jsSourceCode: decodeURIComponent(escape(window.atob(props.jsfiddle?.jsSourceCode))), + codeRef, + handleCodeSandbox, }; }, }); diff --git a/site/src/utils/generateOnlineDemo.ts b/site/src/utils/generateOnlineDemo.ts new file mode 100644 index 000000000..0d9dc7f2a --- /dev/null +++ b/site/src/utils/generateOnlineDemo.ts @@ -0,0 +1,94 @@ +import { getParameters } from 'codesandbox/lib/api/define'; + +const indexHtml = ` + + + Ant Design Vue Demo + + + +
+ + +`; + +const appVue = ` + +`; + +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, + }, + }, + }); +}