├── .babelrc ├── .circleci └── config.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── demo.png ├── deploy.sh ├── docs ├── .vuepress │ ├── config.js │ └── public │ │ ├── bt.js │ │ └── ga.js ├── README.md ├── react.md ├── settings.md ├── vanilla.md ├── vue.md └── zh │ ├── README.md │ ├── react.md │ ├── settings.md │ ├── vanilla.md │ └── vue.md ├── lib ├── clientRootMixin.js └── index.js ├── package.json ├── rollup.config.js ├── src ├── clientRootMixin.js ├── common │ ├── constants.js │ └── utils.js ├── icons │ ├── code-sandbox.svg │ ├── codepen.svg │ └── jsfiddle.svg ├── index.js ├── main.js ├── online │ ├── codepen.js │ └── jsfiddle.js └── style.less └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/env", {"modules": false}] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/node:10 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/mongo:3.4.4 16 | 17 | working_directory: ~/repo 18 | 19 | branches: 20 | only: 21 | - master 22 | 23 | steps: 24 | - checkout 25 | 26 | # Download and cache dependencies 27 | - restore_cache: 28 | keys: 29 | - v1-dependencies-{{ checksum "package.json" }} 30 | # fallback to using the latest cache if no exact match is found 31 | - v1-dependencies- 32 | 33 | - run: yarn install 34 | 35 | - save_cache: 36 | paths: 37 | - node_modules 38 | key: v1-dependencies-{{ checksum "package.json" }} 39 | 40 | - run: yarn comp && yarn build 41 | 42 | 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | .DS_Store 64 | dist 65 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | node_modules 3 | src 4 | rollup.config.js 5 | yarn.lock 6 | ./deploy.sh 7 | demo.png 8 | deploy.sh 9 | .babelrc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 melon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vuepress-plugin-demo-block 2 | 3 | ![download](https://img.shields.io/npm/dm/vuepress-plugin-demo-block.svg) 4 | [![version](https://img.shields.io/npm/v/vuepress-plugin-demo-block.svg)](https://www.npmjs.com/package/vuepress-plugin-demo-block) 5 | ![language](https://img.shields.io/badge/language-javascript-yellow.svg) 6 | ![License](https://img.shields.io/badge/license-MIT-000000.svg) 7 | [![](https://img.shields.io/circleci/project/github/xiguaxigua/vuepress-plugin-demo-block/master.svg)](https://circleci.com/gh/xiguaxigua/vuepress-plugin-demo-block) 8 | 9 | ## Introduction 10 | 11 | The Demo Block is used to help you add vue, react or native js examples when writing a document. When writing component documentation, you usually need to add some related examples to the document. These examples can usually be implemented using JSFiddle or Codepen's Iframe, but the maintenance cost will be relatively high. You can quickly add examples by using Demo Block, and it is very convenient to modify. 12 | 13 | > To show how to write the example, the three points used to mark the end of the code section are separated by spaces, and the spaces need to be removed when used. 14 | 15 | ![demo](./demo.png) 16 | 17 | ## Feature 18 | 19 | - Elegant display code and examples 20 | - Support vue, react and native js 21 | - Support codepen and jsfiddle online demo 22 | 23 | ## Install 24 | 25 | ### install vuepress 26 | 27 | Reference official document [Vuepress](https://vuepress.vuejs.org) 28 | 29 | ### install plugin 30 | 31 | ``` 32 | npm i vuepress-plugin-demo-block --save-dev 33 | ``` 34 | 35 | ### set vuepress config 36 | 37 | config.js 38 | ```js 39 | module.exports = { 40 | head: [ 41 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js' }], 42 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' }], 43 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 44 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 45 | ], 46 | plugins: [ 47 | 'demo-block' 48 | ] 49 | } 50 | 51 | ``` 52 | 53 | ## Start 54 | 55 | Write the following code in the Markdown file: 56 | 57 | ### Vue Demo 58 | 59 | ```html 60 | ::: demo 61 | ```html 62 | 65 | 70 | 73 | ` ` ` <= delete spaces here 74 | ::: 75 | ``` 76 | 77 | ### React Demo 78 | ```js 79 | ::: demo [react] 80 | ```js 81 | export default class App extends React.Component { 82 | constructor (props) { 83 | super(props) 84 | this.state = { message: 'Hello World' } 85 | } 86 | render () { 87 | return ( 88 |
89 | React {this.state.message} 90 |
91 | ) 92 | } 93 | } 94 | App.__style__ = ` 95 | .box-react { color: red; } 96 | ` 97 | ` ` ` <= delete spaces here 98 | ::: 99 | ``` 100 | 101 | ### VanillaJs Demo 102 | 103 | ```html 104 | ::: demo [vanilla] 105 | ```html 106 | 107 |
108 | 109 | 113 | 118 | ` ` ` 119 | ::: 120 | ``` 121 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiguaxigua/vuepress-plugin-demo-block/9ffbffa5edd1fa1a51b3b5fb36a9fd8657ddbdaf/demo.png -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | npm run build 6 | 7 | cd docs/.vuepress/dist 8 | 9 | git init 10 | git add -A 11 | git commit -m 'deploy docs' 12 | 13 | git push -f git@github.com:xiguaxigua/vuepress-plugin-demo-block.git master:gh-pages 14 | 15 | cd - 16 | rm -rf docs/.vuepress/dist 17 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | locales: { 3 | '/': { 4 | lang: 'en-US', 5 | title: 'Demo Block', 6 | description: 'plugin for vuepress to display vue or react demo' 7 | }, 8 | '/zh/': { 9 | lang: 'zh-CN', 10 | title: 'Demo Block', 11 | description: '用于编写 vue 或 react 示例的vuepress插件' 12 | } 13 | }, 14 | ga: 'UA-122325348-1', 15 | serviceWorker: true, 16 | themeConfig: { 17 | repo: 'xiguaxigua/vuepress-plugin-demo-block', 18 | editLinks: true, 19 | docsDir: 'docs', 20 | locales: { 21 | '/': { 22 | label: 'English', 23 | selectText: 'Languages', 24 | editLinkText: 'Edit this page on GitHub', 25 | lastUpdated: 'Last Updated', 26 | serviceWorker: { 27 | updatePopup: { 28 | message: "New content is available.", 29 | buttonText: "Refresh" 30 | } 31 | }, 32 | sidebar: { 33 | '/': genSidebarConfig('Guide') 34 | } 35 | }, 36 | '/zh/': { 37 | label: '简体中文', 38 | selectText: '选择语言', 39 | editLinkText: '在 GitHub 上编辑此页', 40 | lastUpdated: '上次更新', 41 | serviceWorker: { 42 | updatePopup: { 43 | message: "发现新内容可用", 44 | buttonText: "刷新" 45 | } 46 | }, 47 | sidebar: { 48 | '/zh/': genSidebarConfig('指南') 49 | } 50 | } 51 | }, 52 | }, 53 | base: '/vuepress-plugin-demo-block/', 54 | head: [ 55 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react@16.6.3/umd/react.production.min.js' }], 56 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom@16.6.3/umd/react-dom.production.min.js' }], 57 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 58 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 59 | ['script', { src: 'https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js' }], 60 | ['script', { src: 'https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js' }], 61 | ['script', { src: 'https://cdn.jsdelivr.net/npm/v-charts/lib/line.min.js' }], 62 | ['script', { src: 'https://www.googletagmanager.com/gtag/js?id=UA-122325348-1' }], 63 | ['script', { src: '/ga.js' }], 64 | ['script', { src: '/bt.js' }], 65 | ], 66 | plugins: [ 67 | [require('../../lib/index.js'), { 68 | settings: { 69 | codepen: true 70 | } 71 | }] 72 | ] 73 | } 74 | function genSidebarConfig (title) { 75 | return [ 76 | { 77 | title, 78 | collapsable: false, 79 | children: [ 80 | '', 81 | 'vue', 82 | 'react', 83 | 'vanilla', 84 | 'settings' 85 | ] 86 | } 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /docs/.vuepress/public/bt.js: -------------------------------------------------------------------------------- 1 | window._hmt = window._hmt || []; 2 | (function() { 3 | var hm = document.createElement("script"); 4 | hm.src = "https://hm.baidu.com/hm.js?72e1ef2463dc80e5a1d91214ddec2ba9"; 5 | var s = document.getElementsByTagName("script")[0]; 6 | s.parentNode.insertBefore(hm, s); 7 | })(); 8 | -------------------------------------------------------------------------------- /docs/.vuepress/public/ga.js: -------------------------------------------------------------------------------- 1 | window.dataLayer = window.dataLayer || [] 2 | function gtag() { 3 | dataLayer.push(arguments) 4 | } 5 | gtag('js', new Date()) 6 | gtag('config', 'UA-122325348-1') 7 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The Demo Block is used to help you add vue, react or native js examples when writing a document. When writing component documentation, you usually need to add some related examples to the document. These examples can usually be implemented using JSFiddle or Codepen's Iframe, but the maintenance cost will be relatively high. You can quickly add examples by using Demo Block, and it is very convenient to modify. 4 | 5 | ::: tip 6 | To show how to write the example, the three points used to mark the end of the code section are separated by spaces, and the spaces need to be removed when used. 7 | ::: 8 | 9 | ## Install 10 | 11 | ### install vuepress 12 | 13 | Reference official document [Vuepress](https://vuepress.vuejs.org) 14 | 15 | ### install plugin 16 | 17 | ``` 18 | npm i vuepress-plugin-demo-block --save-dev 19 | ``` 20 | 21 | ### set vuepress config 22 | 23 | config.js 24 | ```js 25 | module.exports = { 26 | head: [ 27 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js' }], 28 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' }], 29 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 30 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 31 | ], 32 | plugins: [ 33 | 'demo-block' 34 | ] 35 | } 36 | ``` 37 | 38 | ## Start 39 | 40 | Write the following code in the Markdown file: 41 | 42 | ### Vue Demo 43 | 44 | ```html 45 | ::: demo 46 | ```html 47 | 50 | 55 | 58 | ` ` ` <= delete spaces here 59 | ::: 60 | ``` 61 | 62 | ::: demo 63 | ```html 64 | 67 | 72 | 75 | ``` 76 | ::: 77 | 78 | ### React Demo 79 | 80 | ```js 81 | ::: demo [react] 82 | ```js 83 | export default class App extends React.Component { 84 | constructor (props) { 85 | super(props) 86 | this.state = { message: 'Hello World' } 87 | } 88 | render () { 89 | return ( 90 |
91 | React {this.state.message} 92 |
93 | ) 94 | } 95 | } 96 | App.__style__ = ` 97 | .box-react { color: red; } 98 | ` 99 | ` ` ` <= delete spaces here 100 | ::: 101 | ``` 102 | 103 | ::: demo [react] 104 | ```js 105 | export default class App extends React.Component { 106 | constructor (props) { 107 | super(props) 108 | this.state = { message: 'Hello World' } 109 | } 110 | render () { 111 | return ( 112 |
113 | React {this.state.message} 114 |
115 | ) 116 | } 117 | } 118 | App.__style__ = ` 119 | .box-react { color: red; } 120 | ` 121 | ``` 122 | ::: 123 | 124 | ### Vanilla Demo 125 | 126 | ```html 127 | ::: demo [vanilla] 128 | ```html 129 | 130 |
131 | 132 | 136 | 141 | ` ` ` 142 | ::: 143 | ``` 144 | 145 | ::: demo [vanilla] 146 | ```html 147 | 148 |
149 | 150 | 154 | 159 | ``` 160 | ::: 161 | 162 | 163 | ### horizontal Demo 164 | 165 | ```js 166 | ::: demo [react] 167 | ```js 168 | export default class App extends React.Component { 169 | constructor (props) { 170 | super(props) 171 | this.state = { message: 'Hello World' } 172 | } 173 | render () { 174 | return ( 175 |
176 | React {this.state.message} 177 |
178 | ) 179 | } 180 | } 181 | App.__style__ = ` 182 | .box-react { color: red; } 183 | ` 184 | ` ` ` <= delete spaces here 185 | ` ` `json 186 | { 187 | "horizontal": true 188 | } 189 | ` ` ` 190 | ::: 191 | ``` 192 | 193 | ::: demo [react] 194 | ```js 195 | export default class App extends React.Component { 196 | constructor (props) { 197 | super(props) 198 | this.state = { message: 'Hello World' } 199 | } 200 | render () { 201 | return ( 202 |
203 | React {this.state.message} 204 |
205 | ) 206 | } 207 | } 208 | App.__style__ = ` 209 | .box-react { color: red; } 210 | ` 211 | ``` 212 | ```json 213 | { 214 | "horizontal": true 215 | } 216 | ``` 217 | ::: -------------------------------------------------------------------------------- /docs/react.md: -------------------------------------------------------------------------------- 1 | # React Demo 2 | 3 | A typical vue example is written in the following format: 4 | 5 | ```js 6 | ::: demo [react] 7 | ```js 8 | export default class App extends React.Component { 9 | constructor (props) { 10 | super(props) 11 | this.state = { message: 'Hello World' } 12 | } 13 | render () { 14 | return ( 15 |
16 | React {this.state.message} 17 |
18 | ) 19 | } 20 | } 21 | App.__style__ = ` 22 | .box-react { color: red; } 23 | ` 24 | ` ` ` <= delete spaces here 25 | ::: 26 | ``` 27 | 28 | It should be noted that for the convenience of parsing, the code needs to put back a Class named `App`, and `App.__style__` will be added to `body` to display the style. 29 | 30 | ## demo 31 | 32 | ```js 33 | ::: demo [react] 34 | ```js 35 | export default class App extends React.Component { 36 | constructor (props) { 37 | super(props) 38 | this.state = { number: 0 } 39 | } 40 | plus () { 41 | this.setState({ number: this.state.number + 1 }) 42 | } 43 | minus () { 44 | this.setState({ number: this.state.number - 1 }) 45 | } 46 | render () { 47 | return ( 48 |
49 | 50 | 51 | {this.state.number} 52 |
53 | ) 54 | } 55 | } 56 | App.__style__ = ` 57 | .box-react { color: red; } 58 | ` 59 | ` ` ` <= delete spaces here 60 | ::: 61 | ``` 62 | 63 | 64 | ::: demo [react] 65 | ```js 66 | export default class App extends React.Component { 67 | constructor (props) { 68 | super(props) 69 | this.state = { number: 0 } 70 | } 71 | plus () { 72 | this.setState({ number: this.state.number + 1 }) 73 | } 74 | minus () { 75 | this.setState({ number: this.state.number - 1 }) 76 | } 77 | render () { 78 | return ( 79 |
80 | 81 | 82 | {this.state.number} 83 |
84 | ) 85 | } 86 | } 87 | App.__style__ = ` 88 | .box-react { color: red; } 89 | ` 90 | ``` 91 | ::: 92 | 93 | ## use other lib 94 | 95 | If you want to use other libraries in the code, you can import the umd file of the corresponding library into config.js, and then use it directly in the code. At the same time, in order to be able to access resources in the online example (JSFiddle, Codepen), you need to configure jsLib or cssLib to the component configuration or global configuration (specific configuration reference settings) 96 | 97 | ```js 98 | module.exports = { 99 | head: [ 100 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js' }], 101 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' }], 102 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 103 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 104 | ['script', { src: 'https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js' }], 105 | ], 106 | plugins: [ 107 | 'demo-block' 108 | ] 109 | } 110 | ``` 111 | 112 | ```js 113 | ::: demo [react] 114 | ```js 115 | export default class App extends React.Component { 116 | constructor (props) { 117 | super(props) 118 | this.state = { 119 | form: { num: '123456.7000', format: '0,0.00[00]' }, 120 | result: '123,456.70' 121 | } 122 | } 123 | formChangeHandler (e) { 124 | const { name, value } = e.target 125 | const changed = {} 126 | changed[name] = value 127 | const form = Object.assign({}, this.state.form, changed) 128 | const result = window.numerify(form.num, form.format) 129 | this.setState({ form, result }) 130 | } 131 | render () { 132 | return ( 133 |
134 |

135 | number: 136 | 140 |

141 |

142 | format: 143 | 147 |

148 |

149 | result: 150 | {this.state.result} 151 |

152 |
153 | ) 154 | } 155 | } 156 | ` ` ` <= delete spaces here 157 | ` ` `json 158 | { 159 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 160 | } 161 | ` ` ` 162 | ::: 163 | ``` 164 | 165 | ::: demo [react] 166 | ```js 167 | export default class App extends React.Component { 168 | constructor (props) { 169 | super(props) 170 | this.state = { 171 | form: { num: '123456.7000', format: '0,0.00[00]' }, 172 | result: '123,456.70' 173 | } 174 | } 175 | formChangeHandler (e) { 176 | const { name, value } = e.target 177 | const changed = {} 178 | changed[name] = value 179 | const form = Object.assign({}, this.state.form, changed) 180 | const result = window.numerify(form.num, form.format) 181 | this.setState({ form, result }) 182 | } 183 | render () { 184 | return ( 185 |
186 |

187 | number: 188 | 192 |

193 |

194 | format: 195 | 199 |

200 |

201 | result: 202 | {this.state.result} 203 |

204 |
205 | ) 206 | } 207 | } 208 | ``` 209 | ```json 210 | { 211 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 212 | } 213 | ``` 214 | ::: 215 | 216 | 217 | -------------------------------------------------------------------------------- /docs/settings.md: -------------------------------------------------------------------------------- 1 | # Settings 2 | 3 | The configuration of the plugin is divided into a global configuration and a component configuration, which is used to set the style of the plugin and the external dependencies of the code after jumping to Jsfiddle or Codepen. 4 | 5 | ## globel settings 6 | 7 | config.js 8 | ```js 9 | plugins: [ 10 | ['demo-block', { 11 | settings: { 12 | jsLib: ['http://xxx'], // js dependency in the online example (jsfiddle, codepen) 13 | cssLib: ['http://xxx'], // css dependency in the online example (jsfiddle, codepen) 14 | vue: 'http://xxx', // vue dependency in the online example (jsfiddle, codepen) 15 | react: 'http://xxx', // react dependency in the online example (jsfiddle, codepen) 16 | reactDOM: 'http://xxx', // reactDOM dependency in the online example (jsfiddle, codepen) 17 | jsfiddle: true, // Whether to display the jsfiddle link 18 | codepen: true, // Whether to display the codepen link 19 | horizontal: false // Whether to display horizontal view 20 | } 21 | }], 22 | } 23 | ``` 24 | 25 | ## component settings 26 | 27 | ```html 28 | ::: demo 29 | ```html 30 | 33 | 38 | 41 | ` ` ` 42 | ` ` `json 43 | { 44 | jsLib: ['xxx'], // js dependency in the online example (jsfiddle, codepen) 45 | cssLib: ['xxx'], // css dependency in the online example (jsfiddle, codepen) 46 | horizontal: false // Whether to display horizontal view 47 | } 48 | ` ` ` 49 | ::: 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/vanilla.md: -------------------------------------------------------------------------------- 1 | # Vanilla Demo 2 | 3 | ```html 4 | ::: demo [vanilla] 5 | ```html 6 | 7 |
8 | 9 | 13 | 18 | ` ` ` 19 | ::: 20 | ``` 21 | 22 | ::: demo [vanilla] 23 | ```html 24 | 25 |
26 | 27 | 31 | 36 | ``` 37 | ::: 38 | -------------------------------------------------------------------------------- /docs/vue.md: -------------------------------------------------------------------------------- 1 | # Vue Demo 2 | 3 | A typical vue example is written in the following format: 4 | 5 | ```html 6 | ::: demo 7 | ```html 8 | 11 | 16 | 19 | ` ` ` <= delete spaces here 20 | ::: 21 | ``` 22 | 23 | The contents of `template` will be combined with `script` to the corresponding node of the page, and `style` will be placed in `body`. 24 | 25 | ## demo 26 | 27 | ```html 28 | ::: demo 29 | ```html 30 | 37 | 46 | 49 | ` ` ` <= delete spaces here 50 | ::: 51 | ``` 52 | 53 | ::: demo 54 | ```html 55 | 62 | 71 | 74 | ``` 75 | ::: 76 | 77 | ## use other lib 78 | 79 | If you want to use other libraries in the code, you can import the umd file of the corresponding library into config.js, and then use it directly in the code. At the same time, in order to be able to access resources in the online example (JSFiddle, Codepen), you need to configure jsLib or cssLib to the component configuration or global configuration (specific configuration reference settings) 80 | 81 | ```js 82 | module.exports = { 83 | head: [ 84 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js' }], 85 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' }], 86 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 87 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 88 | ['script', { src: 'https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js' }], 89 | ], 90 | plugins: [ 91 | 'demo-block' 92 | ] 93 | } 94 | ``` 95 | 96 | ```html 97 | ::: demo 98 | ```html 99 | 106 | 107 | 122 | ` ` ` <= delete spaces here 123 | ` ` `json 124 | { 125 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 126 | } 127 | ` ` ` 128 | ::: 129 | ``` 130 | 131 | ::: demo 132 | ```html 133 | 140 | 141 | 156 | ``` 157 | ```json 158 | { 159 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 160 | } 161 | ``` 162 | ::: 163 | 164 | ### user other component 165 | 166 | Rendering other components is basically the same as above. 167 | 168 | ```html 169 | ::: demo 170 | ```html 171 | 176 | 177 | 197 | ` ` ` <= delete spaces here 198 | ` ` `json 199 | { 200 | "jsLib": [ 201 | "https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js", 202 | "https://cdn.jsdelivr.net/npm/v-charts/lib/line.min.js" 203 | ] 204 | } 205 | ` ` ` 206 | ::: 207 | ``` 208 | 209 | ::: demo 210 | ```html 211 | 216 | 217 | 237 | ``` 238 | ```json 239 | { 240 | "jsLib": [ 241 | "https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js", 242 | "https://cdn.jsdelivr.net/npm/v-charts/lib/line.min.js" 243 | ] 244 | } 245 | ``` 246 | ::: 247 | -------------------------------------------------------------------------------- /docs/zh/README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | Demo Block 用于帮助你在编写文档时增加 vue ,react, 原生js 示例。在编写组件文档时,通常需要在文档上增加一些相关的示例,这些示例通常可以使用 JSFiddle 或 Codepen 的 Iframe 实现,但是维护成本会相对比较高,使用 Demo Block 可以快速的增加示例,并且可以很方便的修改。 4 | 5 | ::: tip 6 | 为了展示如何编写示例, 用于标记代码部分结束的三点增加了空格分隔,使用时需要将空格去除。 7 | ::: 8 | 9 | ## 安装 10 | 11 | ### 安装 vuepress 12 | 13 | 参考官方文档 [Vuepress](https://vuepress.vuejs.org) 14 | 15 | ### 安装插件 16 | 17 | ``` 18 | npm i vuepress-plugin-demo-block 19 | ``` 20 | 21 | ### 配置 vuepress config 22 | 23 | config.js 24 | ```js 25 | module.exports = { 26 | head: [ 27 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js' }], 28 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' }], 29 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 30 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 31 | ], 32 | plugins: [ 33 | 'demo-block' 34 | ] 35 | } 36 | ``` 37 | 38 | ## 开始使用 39 | 40 | 在 Markdown 文件中编写以下代码: 41 | 42 | ### Vue示例 43 | 44 | ```html 45 | ::: demo 46 | ```html 47 | 50 | 55 | 58 | ` ` ` <= 删除这里的空格 59 | ::: 60 | ``` 61 | 62 | ::: demo 63 | ```html 64 | 67 | 72 | 75 | ``` 76 | ::: 77 | 78 | ### React示例 79 | ```js 80 | ::: demo react 81 | ```js 82 | export default class App extends React.Component { 83 | constructor (props) { 84 | super(props) 85 | this.state = { message: 'Hello World' } 86 | } 87 | render () { 88 | return ( 89 |
90 | React {this.state.message} 91 |
92 | ) 93 | } 94 | } 95 | App.__style__ = ` 96 | .box-react { color: red; } 97 | ` 98 | ` ` ` <= 删除这里的空格 99 | ::: 100 | ``` 101 | 102 | ::: demo react 103 | ```js 104 | export default class App extends React.Component { 105 | constructor (props) { 106 | super(props) 107 | this.state = { message: 'Hello World' } 108 | } 109 | render () { 110 | return ( 111 |
112 | React {this.state.message} 113 |
114 | ) 115 | } 116 | } 117 | App.__style__ = ` 118 | .box-react { color: red; } 119 | ` 120 | ``` 121 | ::: 122 | 123 | ### 原生JS示例 124 | 125 | ```html 126 | ::: demo [vanilla] 127 | ```html 128 | 129 |
130 | 131 | 135 | 140 | ` ` ` 141 | ::: 142 | ``` 143 | 144 | ::: demo [vanilla] 145 | ```html 146 | 147 |
148 | 149 | 153 | 158 | ``` 159 | ::: 160 | 161 | ### 横向展示示例 162 | 163 | ```js 164 | ::: demo [react] 165 | ```js 166 | export default class App extends React.Component { 167 | constructor (props) { 168 | super(props) 169 | this.state = { message: 'Hello World' } 170 | } 171 | render () { 172 | return ( 173 |
174 | React {this.state.message} 175 |
176 | ) 177 | } 178 | } 179 | App.__style__ = ` 180 | .box-react { color: red; } 181 | ` 182 | ` ` ` <= delete spaces here 183 | ` ` `json 184 | { 185 | "horizontal": true 186 | } 187 | ` ` ` 188 | ::: 189 | ``` 190 | 191 | ::: demo [react] 192 | ```js 193 | export default class App extends React.Component { 194 | constructor (props) { 195 | super(props) 196 | this.state = { message: 'Hello World' } 197 | } 198 | render () { 199 | return ( 200 |
201 | React {this.state.message} 202 |
203 | ) 204 | } 205 | } 206 | App.__style__ = ` 207 | .box-react { color: red; } 208 | ` 209 | ``` 210 | ```json 211 | { 212 | "horizontal": true 213 | } 214 | ``` 215 | ::: -------------------------------------------------------------------------------- /docs/zh/react.md: -------------------------------------------------------------------------------- 1 | # React示例 2 | 3 | 一个典型的 react 示例编写格式如下: 4 | 5 | ```js 6 | ::: demo [react] 7 | ```js 8 | export default class App extends React.Component { 9 | constructor (props) { 10 | super(props) 11 | this.state = { message: 'Hello World' } 12 | } 13 | render () { 14 | return ( 15 |
16 | React {this.state.message} 17 |
18 | ) 19 | } 20 | } 21 | App.__style__ = ` 22 | .box-react { color: red; } 23 | ` 24 | ` ` ` <= delete spaces here 25 | ::: 26 | ``` 27 | 28 | 需要注意的是,为了解析的方便,代码中需要放回一个命名为 `App` 的 Class,`App.__style__`会被加到 `body` 上用于展示样式。 29 | 30 | ## 示例 31 | 32 | ```js 33 | ::: demo [react] 34 | ```js 35 | export default class App extends React.Component { 36 | constructor (props) { 37 | super(props) 38 | this.state = { number: 0 } 39 | } 40 | plus () { 41 | this.setState({ number: this.state.number + 1 }) 42 | } 43 | minus () { 44 | this.setState({ number: this.state.number - 1 }) 45 | } 46 | render () { 47 | return ( 48 |
49 | 50 | 51 | {this.state.number} 52 |
53 | ) 54 | } 55 | } 56 | App.__style__ = ` 57 | .box-react { color: red; } 58 | ` 59 | ` ` ` <= delete spaces here 60 | ::: 61 | ``` 62 | 63 | 64 | ::: demo [react] 65 | ```js 66 | export default class App extends React.Component { 67 | constructor (props) { 68 | super(props) 69 | this.state = { number: 0 } 70 | } 71 | plus () { 72 | this.setState({ number: this.state.number + 1 }) 73 | } 74 | minus () { 75 | this.setState({ number: this.state.number - 1 }) 76 | } 77 | render () { 78 | return ( 79 |
80 | 81 | 82 | {this.state.number} 83 |
84 | ) 85 | } 86 | } 87 | App.__style__ = ` 88 | .box-react { color: red; } 89 | ` 90 | ``` 91 | ::: 92 | 93 | ## 使用其他库 94 | 95 | 在代码中如果要使用其他的库,可以引入对应库的 umd 文件到 config.js 中, 然后在代码里直接使用即可。为了能够在在线示例(JSFiddle, Codepen)中正常访问到资源,需要配置 jsLib或cssLib到组件配置或全局配置中(具体配置参考settings)。 96 | 97 | ```js 98 | module.exports = { 99 | head: [ 100 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js' }], 101 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' }], 102 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 103 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 104 | ['script', { src: 'https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js' }], 105 | ], 106 | plugins: [ 107 | 'demo-block' 108 | ] 109 | } 110 | ``` 111 | 112 | ```js 113 | ::: demo [react] 114 | ```js 115 | export default class App extends React.Component { 116 | constructor (props) { 117 | super(props) 118 | this.state = { 119 | form: { num: '123456.7000', format: '0,0.00[00]' }, 120 | result: '123,456.70' 121 | } 122 | } 123 | formChangeHandler (e) { 124 | const { name, value } = e.target 125 | const changed = {} 126 | changed[name] = value 127 | const form = Object.assign({}, this.state.form, changed) 128 | const result = window.numerify(form.num, form.format) 129 | this.setState({ form, result }) 130 | } 131 | render () { 132 | return ( 133 |
134 |

135 | number: 136 | 140 |

141 |

142 | format: 143 | 147 |

148 |

149 | result: 150 | {this.state.result} 151 |

152 |
153 | ) 154 | } 155 | } 156 | ` ` ` <= delete spaces here 157 | ` ` `json 158 | { 159 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 160 | } 161 | ` ` ` 162 | ::: 163 | ``` 164 | 165 | ::: demo [react] 166 | ```js 167 | export default class App extends React.Component { 168 | constructor (props) { 169 | super(props) 170 | this.state = { 171 | form: { num: '123456.7000', format: '0,0.00[00]' }, 172 | result: '123,456.70' 173 | } 174 | } 175 | formChangeHandler (e) { 176 | const { name, value } = e.target 177 | const changed = {} 178 | changed[name] = value 179 | const form = Object.assign({}, this.state.form, changed) 180 | const result = window.numerify(form.num, form.format) 181 | this.setState({ form, result }) 182 | } 183 | render () { 184 | return ( 185 |
186 |

187 | number: 188 | 192 |

193 |

194 | format: 195 | 199 |

200 |

201 | result: 202 | {this.state.result} 203 |

204 |
205 | ) 206 | } 207 | } 208 | ``` 209 | ```json 210 | { 211 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 212 | } 213 | ``` 214 | ::: 215 | 216 | 217 | -------------------------------------------------------------------------------- /docs/zh/settings.md: -------------------------------------------------------------------------------- 1 | # 配置项 2 | 3 | 插件的配置分为全局配置和组件配置,用于设置插件的样式以及跳转到 JSFiddle 或 Codepen 后代码的外部依赖。 4 | 5 | ## 全局配置 6 | 7 | config.js 8 | ```js 9 | plugins: [ 10 | ['demo-block', { 11 | settings: { 12 | jsLib: ['http://xxx'], // 在线示例(jsfiddle, codepen)中的js依赖 13 | cssLib: ['http://xxx'], // 在线示例中的css依赖 14 | vue: 'http://xxx', // 在线示例中的vue依赖 15 | react: 'http://xxx', // 在线示例中的react依赖 16 | reactDOM: 'http://xxx', // 在线示例中的reactDOM依赖 17 | jsfiddle: true, // 是否显示 jsfiddle 链接 18 | codepen: true, // 是否显示 codepen 链接 19 | horizontal: false // 是否展示为横向样式 20 | } 21 | }], 22 | } 23 | ``` 24 | 25 | ## 组件配置 26 | 27 | ```html 28 | ::: demo 29 | ```html 30 | 33 | 38 | 41 | ` ` ` 42 | ` ` `json 43 | { 44 | jsLib: ['xxx'], // 在线示例中的js依赖 45 | cssLib: ['xxx'], // 在线示例中的css依赖 46 | horizontal: false // 是否展示为横向样式 47 | } 48 | ` ` ` 49 | ::: 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/zh/vanilla.md: -------------------------------------------------------------------------------- 1 | # Vanilla示例 2 | 3 | The demo of writing a native JS is basically the same as writing a vue demo. 4 | 5 | ```html 6 | ::: demo [vanilla] 7 | ```html 8 | 9 |
10 | 11 | 15 | 20 | ` ` ` 21 | ::: 22 | ``` 23 | 24 | ::: demo [vanilla] 25 | ```html 26 | 27 |
28 | 29 | 33 | 38 | ``` 39 | ::: -------------------------------------------------------------------------------- /docs/zh/vue.md: -------------------------------------------------------------------------------- 1 | # Vue示例 2 | 3 | 一个典型的 vue 示例编写格式如下: 4 | 5 | ```html 6 | ::: demo 7 | ```html 8 | 11 | 16 | 19 | ` ` ` <= delete spaces here 20 | ::: 21 | ``` 22 | 23 | 其中 `template` 中的内容会结合 `script` 渲染到页面的对应节点上去,`style` 会被放到 body 中。 24 | 25 | ## 示例 26 | 27 | ```html 28 | ::: demo 29 | ```html 30 | 37 | 46 | 49 | ` ` ` <= delete spaces here 50 | ::: 51 | ``` 52 | 53 | ::: demo 54 | ```html 55 | 62 | 71 | 74 | ``` 75 | ::: 76 | 77 | ## 使用其他库 78 | 79 | 在代码中如果要使用其他的库,可以引入对应库的 umd 文件到 config.js 中, 然后在代码里直接使用即可。同时,为了能够在在线示例(JSFiddle, Codepen)中正常访问到资源,需要配置 jsLib或cssLib到组件配置或全局配置中(具体配置参考settings)。 80 | 81 | ```js 82 | module.exports = { 83 | head: [ 84 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js' }], 85 | ['script', { src: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' }], 86 | ['script', { src: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js' }], 87 | ['script', { src: 'https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js' }], 88 | ['script', { src: 'https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js' }], 89 | ], 90 | plugins: [ 91 | 'demo-block' 92 | ] 93 | } 94 | ``` 95 | 96 | ```html 97 | ::: demo 98 | ```html 99 | 106 | 107 | 122 | ` ` ` <= delete spaces here 123 | ` ` `json 124 | { 125 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 126 | } 127 | ` ` ` 128 | ::: 129 | ``` 130 | 131 | ::: demo 132 | ```html 133 | 140 | 141 | 156 | ``` 157 | ```json 158 | { 159 | "jsLib": ["https://cdn.jsdelivr.net/npm/numerify/lib/index.umd.min.js"] 160 | } 161 | ``` 162 | ::: 163 | 164 | ### 使用其他组件 165 | 166 | 渲染其他组件的方式与引入其他库的方式基本相同。 167 | 168 | ```html 169 | ::: demo 170 | ```html 171 | 176 | 177 | 197 | ` ` ` <= delete spaces here 198 | ` ` `json 199 | { 200 | "jsLib": [ 201 | "https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js", 202 | "https://cdn.jsdelivr.net/npm/v-charts/lib/line.min.js" 203 | ] 204 | } 205 | ` ` ` 206 | ::: 207 | ``` 208 | 209 | ::: demo 210 | ```html 211 | 216 | 217 | 237 | ``` 238 | ```json 239 | { 240 | "jsLib": [ 241 | "https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js", 242 | "https://cdn.jsdelivr.net/npm/v-charts/lib/line.min.js" 243 | ] 244 | } 245 | ``` 246 | ::: 247 | -------------------------------------------------------------------------------- /lib/clientRootMixin.js: -------------------------------------------------------------------------------- 1 | function styleInject(css, ref) { 2 | if (ref === void 0) ref = {}; 3 | var insertAt = ref.insertAt; 4 | 5 | if (!css || typeof document === 'undefined') { 6 | return; 7 | } 8 | 9 | var head = document.head || document.getElementsByTagName('head')[0]; 10 | var style = document.createElement('style'); 11 | style.type = 'text/css'; 12 | 13 | if (insertAt === 'top') { 14 | if (head.firstChild) { 15 | head.insertBefore(style, head.firstChild); 16 | } else { 17 | head.appendChild(style); 18 | } 19 | } else { 20 | head.appendChild(style); 21 | } 22 | 23 | if (style.styleSheet) { 24 | style.styleSheet.cssText = css; 25 | } else { 26 | style.appendChild(document.createTextNode(css)); 27 | } 28 | } 29 | 30 | var css = "@media (max-width: 1000px) {\n .vuepress-plugin-demo-block__h_code {\n display: none;\n }\n .vuepress-plugin-demo-block__app {\n margin-left: auto !important;\n margin-right: auto !important;\n }\n}\n.vuepress-plugin-demo-block__wrapper {\n margin-top: 10px;\n border: 1px solid #ebebeb;\n border-radius: 4px;\n transition: all 0.2s;\n}\n.vuepress-plugin-demo-block__wrapper.vuepress-plugin-demo-block__horizontal .vuepress-plugin-demo-block__display {\n height: 400px;\n display: flex;\n}\n.vuepress-plugin-demo-block__wrapper.vuepress-plugin-demo-block__horizontal .vuepress-plugin-demo-block__display .vuepress-plugin-demo-block__app {\n width: 300px;\n border: 1px solid #ebebeb;\n box-shadow: 1px 1px 3px #ebebeb;\n margin-right: 5px;\n overflow: auto;\n}\n.vuepress-plugin-demo-block__wrapper.vuepress-plugin-demo-block__horizontal .vuepress-plugin-demo-block__display .vuepress-plugin-demo-block__h_code {\n flex: 1;\n overflow: auto;\n height: 100%;\n}\n.vuepress-plugin-demo-block__wrapper.vuepress-plugin-demo-block__horizontal .vuepress-plugin-demo-block__display .vuepress-plugin-demo-block__h_code > pre {\n overflow: visible;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__display {\n max-height: 400px;\n overflow: auto;\n}\n.vuepress-plugin-demo-block__wrapper div {\n box-sizing: border-box;\n}\n.vuepress-plugin-demo-block__wrapper:hover {\n box-shadow: 0 0 11px rgba(33, 33, 33, 0.2);\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__code {\n overflow: hidden;\n height: 0;\n padding: 0 !important;\n background-color: #282c34;\n border-radius: 0 !important;\n transition: height 0.5s;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__code pre {\n margin: 0 !important;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__display {\n padding: 20px;\n border-bottom: 1px solid #ebebeb;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer {\n position: relative;\n text-align: center;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer.vuepress-plugin-demo-block__show-link .vuepress-plugin-demo-block__jsfiddle,\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer.vuepress-plugin-demo-block__show-link .vuepress-plugin-demo-block__codepen {\n opacity: 1;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer.vuepress-plugin-demo-block__show-link .vuepress-plugin-demo-block__expand::before {\n border-top: none;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #ccc;\n border-left: 6px solid transparent;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover .vuepress-plugin-demo-block__jsfiddle,\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover .vuepress-plugin-demo-block__codepen,\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover .vuepress-plugin-demo-block__expand span,\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover .vuepress-plugin-demo-block__expand {\n opacity: 1;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover .vuepress-plugin-demo-block__expand::before {\n border-top-color: #3eaf7c !important;\n border-bottom-color: #3eaf7c !important;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover svg {\n fill: #3eaf7c !important;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__expand-text {\n transition: all 0.5s;\n opacity: 0;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer form:nth-last-child(2) {\n right: 50px;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer form:last-child {\n right: 10px;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__button {\n border-color: transparent;\n background-color: transparent;\n font-size: 14px;\n color: #3eaf7c;\n cursor: pointer;\n outline: none;\n margin: 0;\n width: 46px;\n position: relative;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__button:hover::before {\n content: attr(data-tip);\n white-space: nowrap;\n position: absolute;\n top: -30px;\n left: 50%;\n color: #eee;\n line-height: 1;\n z-index: 1000;\n border-radius: 4px;\n padding: 6px;\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n background-color: rgba(0, 0, 0, 0.8);\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__button:hover::after {\n content: '' !important;\n display: block;\n position: absolute;\n left: 50%;\n top: -5px;\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: rgba(0, 0, 0, 0.8);\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__button svg {\n width: 34px;\n height: 20px;\n fill: #ccc;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__jsfiddle,\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__codepen {\n position: absolute;\n top: 10px;\n transition: all 0.5s;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__expand {\n position: relative;\n width: 100px;\n height: 40px;\n margin: 0;\n color: #3eaf7c;\n font-size: 14px;\n background-color: transparent;\n border-color: transparent;\n outline: none;\n transition: all 0.5s;\n cursor: pointer;\n}\n.vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer .vuepress-plugin-demo-block__expand::before {\n content: \"\";\n position: absolute;\n top: 50%;\n left: 50%;\n width: 0;\n height: 0;\n border-top: 6px solid #ccc;\n border-right: 6px solid transparent;\n border-left: 6px solid transparent;\n -webkit-transform: translate(-50%, -50%);\n transform: translate(-50%, -50%);\n}\n"; 31 | styleInject(css); 32 | 33 | var CLASS_WRAPPER = 'vuepress-plugin-demo-block__wrapper'; 34 | var CLASS_DISPLAY = 'vuepress-plugin-demo-block__display'; 35 | var CLASS_CODE = 'vuepress-plugin-demo-block__code'; 36 | var CLASS_FOOTER = 'vuepress-plugin-demo-block__footer'; 37 | var CLASS_HORIZONTAL = 'vuepress-plugin-demo-block__horizontal'; 38 | var CLASS_H_CODE = 'vuepress-plugin-demo-block__h_code'; 39 | var CLASS_APP = 'vuepress-plugin-demo-block__app'; 40 | var CLASS_SHOW_LINK = 'vuepress-plugin-demo-block__show-link'; 41 | var CLASS_EXPAND = 'vuepress-plugin-demo-block__expand'; 42 | var CLASS_CODEPEN = 'vuepress-plugin-demo-block__codepen'; 43 | var CLASS_JSFIDDLE = 'vuepress-plugin-demo-block__jsfiddle'; 44 | var CLASS_BUTTON = 'vuepress-plugin-demo-block__button'; 45 | var DEFAULT_SETTINGS = { 46 | jsLib: [], 47 | cssLib: [], 48 | jsfiddle: true, 49 | codepen: true, 50 | codepenLayout: 'left', 51 | codepenJsProcessor: 'babel', 52 | codepenEditors: '101', 53 | horizontal: false, 54 | vue: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js', 55 | react: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js', 56 | reactDOM: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js' 57 | }; 58 | var SETTINGS_KEY = '$VUEPRESS_DEMO_BLOCK'; 59 | 60 | var _once = {}; 61 | 62 | var getHtmlTpl = function getHtmlTpl(html) { 63 | return "
\n".concat(html, "\n
"); 64 | }; 65 | 66 | var getVueJsTpl = function getVueJsTpl(js) { 67 | var jsContent = js.replace(/export\s+default\s*?\{\n*/, '').replace(/\n*\}\s*$/, '').trim(); 68 | return "new Vue({\n el: '#app',\n ".concat(jsContent, "\n})"); 69 | }; 70 | 71 | var toArray = function toArray(value) { 72 | return Array.prototype.slice.call(value); 73 | }; 74 | 75 | var getSettings = function getSettings(key) { 76 | return window[SETTINGS_KEY] && window[SETTINGS_KEY][key] !== undefined ? window[SETTINGS_KEY][key] : DEFAULT_SETTINGS[key]; 77 | }; 78 | var h = function h(tag, attrs, children) { 79 | var node = document.createElement(tag); 80 | attrs && Object.keys(attrs).forEach(function (key) { 81 | if (!key.indexOf('data')) { 82 | var k = key.replace('data', ''); 83 | node.dataset[k] = attrs[key]; 84 | } else { 85 | node[key] = attrs[key]; 86 | } 87 | }); 88 | children && children.forEach(function (_ref) { 89 | var tag = _ref.tag, 90 | attrs = _ref.attrs, 91 | children = _ref.children; 92 | node.appendChild(h(tag, attrs, children)); 93 | }); 94 | return node; 95 | }; 96 | var $ = function $(parent, node, returnArray) { 97 | var result = toArray(parent.querySelectorAll(".".concat(node))); 98 | return result.length === 1 && !returnArray ? result[0] : result; 99 | }; 100 | 101 | var getVueScript = function getVueScript(js, html) { 102 | var scripts = js.split(/export\s+default/); 103 | var scriptStrOrg = "(function() {".concat(scripts[0], " ; return ").concat(scripts[1], "})()"); 104 | var scriptStr = window.Babel ? window.Babel.transform(scriptStrOrg, { 105 | presets: ['es2015'] 106 | }).code : scriptStrOrg; 107 | var scriptObj = [eval][0](scriptStr); 108 | scriptObj.template = html; 109 | return scriptObj; 110 | }; 111 | 112 | var getVanillaScript = function getVanillaScript(js) { 113 | return window.Babel ? window.Babel.transform(js, { 114 | presets: ['es2015'] 115 | }).code : js; 116 | }; 117 | 118 | var getVueDetail = function getVueDetail(code, config) { 119 | var cssBlock = code.match(/"; 189 | 190 | function getCodepenBtn(_ref) { 191 | var css = _ref.css, 192 | htmlTpl = _ref.htmlTpl, 193 | jsTpl = _ref.jsTpl, 194 | jsLib = _ref.jsLib, 195 | cssLib = _ref.cssLib; 196 | var value = JSON.stringify({ 197 | css: css, 198 | html: htmlTpl, 199 | js: jsTpl, 200 | js_external: jsLib.concat(getSettings('jsLib')).join(';'), 201 | css_external: cssLib.concat(getSettings('cssLib')).join(';'), 202 | layout: getSettings('codepenLayout'), 203 | js_pre_processor: getSettings('codepenJsProcessor'), 204 | editors: getSettings('codepenEditors') 205 | }); 206 | var form = h('form', { 207 | className: CLASS_CODEPEN, 208 | target: '_blank', 209 | action: 'https://codepen.io/pen/define', 210 | method: 'post' 211 | }, [{ 212 | tag: 'input', 213 | attrs: { 214 | type: 'hidden', 215 | name: 'data', 216 | value: value 217 | } 218 | }, { 219 | tag: 'button', 220 | attrs: { 221 | type: 'submit', 222 | innerHTML: codepenIcon, 223 | className: CLASS_BUTTON, 224 | datatip: 'Codepen' 225 | } 226 | }]); 227 | return form; 228 | } 229 | 230 | var jsfiddleIcon = ""; 231 | 232 | function getJsfiddleBtn(_ref) { 233 | var css = _ref.css, 234 | htmlTpl = _ref.htmlTpl, 235 | jsTpl = _ref.jsTpl, 236 | jsLib = _ref.jsLib, 237 | cssLib = _ref.cssLib; 238 | var resource = jsLib.concat(cssLib).concat(getSettings('cssLib')).concat(getSettings('jsLib')).join(','); 239 | var form = h('form', { 240 | className: CLASS_JSFIDDLE, 241 | target: '_blank', 242 | action: 'https://jsfiddle.net/api/post/library/pure/', 243 | method: 'post' 244 | }, [{ 245 | tag: 'input', 246 | attrs: { 247 | type: 'hidden', 248 | name: 'css', 249 | value: css 250 | } 251 | }, { 252 | tag: 'input', 253 | attrs: { 254 | type: 'hidden', 255 | name: 'html', 256 | value: htmlTpl 257 | } 258 | }, { 259 | tag: 'input', 260 | attrs: { 261 | type: 'hidden', 262 | name: 'js', 263 | value: jsTpl 264 | } 265 | }, { 266 | tag: 'input', 267 | attrs: { 268 | type: 'hidden', 269 | name: 'panel_js', 270 | value: 3 271 | } 272 | }, { 273 | tag: 'input', 274 | attrs: { 275 | type: 'hidden', 276 | name: 'wrap', 277 | value: 1 278 | } 279 | }, { 280 | tag: 'input', 281 | attrs: { 282 | type: 'hidden', 283 | name: 'resources', 284 | value: resource 285 | } 286 | }, { 287 | tag: 'button', 288 | attrs: { 289 | type: 'submit', 290 | className: CLASS_BUTTON, 291 | innerHTML: jsfiddleIcon, 292 | datatip: 'JSFiddle' 293 | } 294 | }]); 295 | return form; 296 | } 297 | 298 | function webController() { 299 | var nodes = $(document, CLASS_WRAPPER, true); 300 | 301 | if (!nodes.length) { 302 | setTimeout(function (_) { 303 | webController(); 304 | }, 300); 305 | return; 306 | } 307 | 308 | nodes.forEach(function (node) { 309 | if (node.dataset.created === 'true') return; 310 | node.style.display = 'block'; 311 | var codeNode = $(node, CLASS_CODE); 312 | var displayNode = $(node, CLASS_DISPLAY); 313 | var footerNode = $(node, CLASS_FOOTER); 314 | var appNode = $(displayNode, CLASS_APP); 315 | var code = decodeURIComponent(node.dataset.code); 316 | var config = decodeURIComponent(node.dataset.config); 317 | var type = decodeURIComponent(node.dataset.type); 318 | config = config ? JSON.parse(config) : {}; 319 | var height = codeNode.querySelector('div').clientHeight; 320 | var detail = type === 'react' ? getReactDetail(code, config) : type === 'vanilla' ? getVanillaDetail(code, config) : getVueDetail(code, config); 321 | var expandNode = createExpandNode(); 322 | footerNode.appendChild(expandNode); 323 | expandNode.addEventListener('click', expandHandler.bind(null, expandNode, height, codeNode, footerNode)); 324 | 325 | if (getSettings('jsfiddle')) { 326 | footerNode.appendChild(getJsfiddleBtn(detail)); 327 | } 328 | 329 | if (getSettings('codepen')) { 330 | footerNode.appendChild(getCodepenBtn(detail)); 331 | } 332 | 333 | var horizontalConfig = config.horizontal !== undefined ? config.horizontal : getSettings('horizontal'); 334 | 335 | if (horizontalConfig) { 336 | node.classList.add(CLASS_HORIZONTAL); 337 | var hCodeNode = codeNode.firstChild.cloneNode(true); 338 | hCodeNode.classList.add(CLASS_H_CODE); 339 | displayNode.appendChild(hCodeNode); 340 | } 341 | 342 | detail.css && injectCss(detail.css); 343 | 344 | if (type === 'react') { 345 | ReactDOM.render(React.createElement(detail.js), appNode); 346 | } else if (type === 'vue') { 347 | var Comp = Vue.extend(detail.script); 348 | var app = new Comp().$mount(); 349 | appNode.appendChild(app.$el); 350 | } else if (type === 'vanilla') { 351 | appNode.innerHTML = detail.html; 352 | new Function("return (function(){".concat(detail.script, "})()"))(); 353 | } 354 | 355 | node.dataset.created = 'true'; 356 | }); 357 | } 358 | 359 | function createExpandNode() { 360 | return h('button', { 361 | className: "".concat(CLASS_EXPAND) 362 | }); 363 | } 364 | 365 | function expandHandler(expandNode, height, codeNode, footerNode) { 366 | var isExpand = expandNode.dataset.isExpand !== '1'; 367 | codeNode.style.height = isExpand ? "".concat(height, "px") : 0; 368 | 369 | if (isExpand) { 370 | footerNode.classList.add(CLASS_SHOW_LINK); 371 | } else { 372 | footerNode.classList.remove(CLASS_SHOW_LINK); 373 | } 374 | 375 | expandNode.dataset.isExpand = isExpand ? '1' : '0'; 376 | } 377 | 378 | var clientRootMixin = { 379 | mounted: function mounted() { 380 | window.$VUEPRESS_DEMO_BLOCK = SETTINGS; 381 | webController(); 382 | }, 383 | updated: function updated() { 384 | webController(); 385 | } 386 | }; 387 | 388 | export default clientRootMixin; 389 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } 4 | 5 | var path = _interopDefault(require('path')); 6 | 7 | var END_TYPE = 'container_demo_close'; 8 | var CLASS_WRAPPER = 'vuepress-plugin-demo-block__wrapper'; 9 | var CLASS_DISPLAY = 'vuepress-plugin-demo-block__display'; 10 | var CLASS_CODE = 'vuepress-plugin-demo-block__code'; 11 | var CLASS_FOOTER = 'vuepress-plugin-demo-block__footer'; 12 | var CLASS_APP = 'vuepress-plugin-demo-block__app'; 13 | 14 | module.exports = function (options, context) { 15 | return { 16 | name: 'vuepress-plugin-demo-block', 17 | define: { 18 | SETTINGS: options.settings || {} 19 | }, 20 | clientRootMixin: path.resolve(__dirname, 'clientRootMixin.js'), 21 | extendMarkdown: function extendMarkdown(md) { 22 | md.use(require('markdown-it-container'), 'demo', { 23 | render: function render(tokens, idx) { 24 | var _tokens$idx = tokens[idx], 25 | nesting = _tokens$idx.nesting, 26 | info = _tokens$idx.info; 27 | 28 | if (nesting === -1) { 29 | return "\n \n
\n \n "); 30 | } 31 | 32 | var codeStr = ''; 33 | var configStr = ''; 34 | var typeStr = ~info.indexOf('react') ? 'react' : ~info.indexOf('vanilla') ? 'vanilla' : 'vue'; 35 | 36 | for (var i = idx; i < tokens.length; i++) { 37 | var _tokens$i = tokens[i], 38 | type = _tokens$i.type, 39 | content = _tokens$i.content, 40 | _info = _tokens$i.info; 41 | if (type === END_TYPE) break; 42 | if (!content) continue; 43 | 44 | if (type === 'fence') { 45 | if (_info === 'json') { 46 | configStr = encodeURIComponent(content); 47 | } else { 48 | codeStr = encodeURIComponent(content); 49 | } 50 | } 51 | } 52 | 53 | return "\n \n
\n
\n
\n
\n "); 54 | } 55 | }); 56 | } 57 | }; 58 | }; 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuepress-plugin-demo-block", 3 | "version": "0.7.2", 4 | "description": "demo block for vuepress both support vue and react", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "dev": "vuepress dev docs", 8 | "build": "vuepress build docs", 9 | "comp": "rollup -c rollup.config.js", 10 | "watch": "rollup -wc rollup.config.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/xiguaxigua/vuepress-plugin-demo-block.git" 15 | }, 16 | "keywords": [ 17 | "vuepress-plugin", 18 | "demo-block" 19 | ], 20 | "author": "xiguaxigua", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/xiguaxigua/vuepress-plugin-demo-block/issues" 24 | }, 25 | "homepage": "https://github.com/xiguaxigua/vuepress-plugin-demo-block#readme", 26 | "devDependencies": { 27 | "@babel/core": "^7.2.2", 28 | "@babel/preset-env": "^7.2.3", 29 | "autoprefixer": "^9.4.5", 30 | "less": "^3.9.0", 31 | "markdown-it-container": "^2.0.0", 32 | "rollup": "^1.0.0", 33 | "rollup-plugin-babel": "^4.2.0", 34 | "rollup-plugin-commonjs": "^9.2.0", 35 | "rollup-plugin-node-resolve": "^4.0.0", 36 | "rollup-plugin-postcss": "^1.6.3", 37 | "rollup-plugin-string": "^2.0.2", 38 | "rollup-plugin-uglify": "^6.0.0", 39 | "vuepress": "^1.0.0-alpha.30" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import autoprefixer from "autoprefixer"; 2 | import babel from "rollup-plugin-babel"; 3 | import common from "rollup-plugin-commonjs"; 4 | import resolve from "rollup-plugin-node-resolve"; 5 | import postcss from "rollup-plugin-postcss"; 6 | import string from 'rollup-plugin-string'; 7 | 8 | export default [ 9 | { 10 | input: "src/index.js", 11 | output: { 12 | file: "lib/index.js", 13 | format: "cjs" 14 | }, 15 | external: ['path'], 16 | plugins: [babel(), common(), resolve()] 17 | }, 18 | { 19 | input: "src/clientRootMixin.js", 20 | output: { 21 | file: "lib/clientRootMixin.js", 22 | format: "esm" 23 | }, 24 | plugins: [ 25 | postcss({ plugins: [autoprefixer] }), 26 | babel(), 27 | common(), 28 | resolve(), 29 | string({ include: '**/*.svg' }) 30 | ] 31 | } 32 | ]; 33 | -------------------------------------------------------------------------------- /src/clientRootMixin.js: -------------------------------------------------------------------------------- 1 | import './style.less' 2 | 3 | import webController from './main' 4 | 5 | export default { 6 | mounted() { 7 | window.$VUEPRESS_DEMO_BLOCK = SETTINGS 8 | webController() 9 | }, 10 | 11 | updated() { 12 | webController() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/common/constants.js: -------------------------------------------------------------------------------- 1 | export const END_TYPE = 'container_demo_close' 2 | 3 | export const CLASS_WRAPPER = 'vuepress-plugin-demo-block__wrapper' 4 | export const CLASS_DISPLAY = 'vuepress-plugin-demo-block__display' 5 | export const CLASS_CODE = 'vuepress-plugin-demo-block__code' 6 | export const CLASS_FOOTER = 'vuepress-plugin-demo-block__footer' 7 | export const CLASS_HORIZONTAL = 'vuepress-plugin-demo-block__horizontal' 8 | export const CLASS_H_CODE = 'vuepress-plugin-demo-block__h_code' 9 | 10 | export const CLASS_APP = 'vuepress-plugin-demo-block__app' 11 | export const CLASS_SHOW_LINK = 'vuepress-plugin-demo-block__show-link' 12 | export const CLASS_EXPAND = 'vuepress-plugin-demo-block__expand' 13 | export const CLASS_OUTLINK = 'vuepress-plugin-demo-block__out-link' 14 | export const CLASS_CODEPEN = 'vuepress-plugin-demo-block__codepen' 15 | export const CLASS_JSFIDDLE = 'vuepress-plugin-demo-block__jsfiddle' 16 | export const CLASS_BUTTON = 'vuepress-plugin-demo-block__button' 17 | 18 | export const DEFAULT_SETTINGS = { 19 | jsLib: [], 20 | cssLib: [], 21 | jsfiddle: true, 22 | codepen: true, 23 | codepenLayout: 'left', 24 | codepenJsProcessor: 'babel', 25 | codepenEditors: '101', 26 | horizontal: false, 27 | vue: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js', 28 | react: 'https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js', 29 | reactDOM: 'https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js', 30 | } 31 | 32 | export const SETTINGS_KEY = '$VUEPRESS_DEMO_BLOCK' 33 | -------------------------------------------------------------------------------- /src/common/utils.js: -------------------------------------------------------------------------------- 1 | import { DEFAULT_SETTINGS, SETTINGS_KEY } from './constants' 2 | 3 | const _once = {} 4 | 5 | const getHtmlTpl = html => `
6 | ${html} 7 |
` 8 | 9 | const getVueJsTpl = js => { 10 | const jsContent = js 11 | .replace(/export\s+default\s*?\{\n*/, '') 12 | .replace(/\n*\}\s*$/, '') 13 | .trim() 14 | return `new Vue({ 15 | el: '#app', 16 | ${jsContent} 17 | })` 18 | } 19 | 20 | const toArray = value => Array.prototype.slice.call(value) 21 | 22 | export const getSettings = key => 23 | window[SETTINGS_KEY] && window[SETTINGS_KEY][key] !== undefined 24 | ? window[SETTINGS_KEY][key] 25 | : DEFAULT_SETTINGS[key] 26 | 27 | export const h = (tag, attrs, children) => { 28 | const node = document.createElement(tag) 29 | attrs && 30 | Object.keys(attrs).forEach(key => { 31 | if (!key.indexOf('data')) { 32 | const k = key.replace('data', '') 33 | node.dataset[k] = attrs[key] 34 | } else { 35 | node[key] = attrs[key] 36 | } 37 | }) 38 | children && 39 | children.forEach(({ tag, attrs, children }) => { 40 | node.appendChild(h(tag, attrs, children)) 41 | }) 42 | return node 43 | } 44 | 45 | export const $ = (parent, node, returnArray) => { 46 | const result = toArray(parent.querySelectorAll(`.${node}`)) 47 | return result.length === 1 && !returnArray ? result[0] : result 48 | } 49 | 50 | const getVueScript = (js, html) => { 51 | const scripts = js.split(/export\s+default/) 52 | const scriptStrOrg = `(function() {${scripts[0]} ; return ${scripts[1]}})()` 53 | const scriptStr = window.Babel 54 | ? window.Babel.transform(scriptStrOrg, { presets: ['es2015'] }).code 55 | : scriptStrOrg 56 | const scriptObj = [eval][0](scriptStr) 57 | scriptObj.template = html 58 | return scriptObj 59 | } 60 | 61 | const getVanillaScript = js => { 62 | return window.Babel 63 | ? window.Babel.transform(js, { presets: ['es2015'] }).code 64 | : js 65 | } 66 | 67 | export const getVueDetail = (code, config) => { 68 | const cssBlock = code.match(/ -------------------------------------------------------------------------------- /src/icons/codepen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/jsfiddle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | import { 4 | CLASS_APP, 5 | CLASS_CODE, 6 | CLASS_DISPLAY, 7 | CLASS_FOOTER, 8 | CLASS_WRAPPER, 9 | END_TYPE 10 | } from './common/constants' 11 | 12 | module.exports = (options, context) => ({ 13 | name: 'vuepress-plugin-demo-block', 14 | define: { 15 | SETTINGS: options.settings || {} 16 | }, 17 | clientRootMixin: path.resolve(__dirname, 'clientRootMixin.js'), 18 | extendMarkdown: md => { 19 | md.use(require('markdown-it-container'), 'demo', { 20 | render: (tokens, idx) => { 21 | const { nesting, info } = tokens[idx] 22 | if (nesting === -1) { 23 | return ` 24 |
25 |
26 | 27 | ` 28 | } 29 | let codeStr = '' 30 | let configStr = '' 31 | let typeStr = ~info.indexOf('react') 32 | ? 'react' 33 | : ~info.indexOf('vanilla') 34 | ? 'vanilla' 35 | : 'vue' 36 | for (let i = idx; i < tokens.length; i++) { 37 | const { type, content, info } = tokens[i] 38 | if (type === END_TYPE) break 39 | if (!content) continue 40 | if (type === 'fence') { 41 | if (info === 'json') { 42 | configStr = encodeURIComponent(content) 43 | } else { 44 | codeStr = encodeURIComponent(content) 45 | } 46 | } 47 | } 48 | return ` 49 |