diff options
author | Li Jin <dragon-fly@qq.com> | 2021-04-19 23:41:33 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2021-04-19 23:41:33 +0800 |
commit | 5d3b07801456d16dcc2c75dcccd48d508a6b60cc (patch) | |
tree | 2df1a154bf58d93f2475df02afbd15f1a8ba2963 /doc/docs | |
parent | ea82666506b57d6e905b7f2e5fe78498fe5a7abd (diff) | |
download | yuescript-5d3b07801456d16dcc2c75dcccd48d508a6b60cc.tar.gz yuescript-5d3b07801456d16dcc2c75dcccd48d508a6b60cc.tar.bz2 yuescript-5d3b07801456d16dcc2c75dcccd48d508a6b60cc.zip |
first commit for Yuescript document site.
Diffstat (limited to 'doc/docs')
45 files changed, 4348 insertions, 0 deletions
diff --git a/doc/docs/.vuepress/components/CompilerModal.vue b/doc/docs/.vuepress/components/CompilerModal.vue new file mode 100755 index 0000000..65ae9b0 --- /dev/null +++ b/doc/docs/.vuepress/components/CompilerModal.vue | |||
@@ -0,0 +1,32 @@ | |||
1 | <template> | ||
2 | <modal name="compiler" @before-open="prepare()" height="auto" width="80%" scrollable> | ||
3 | <yue-compiler :text="content" compileronly displayonly/> | ||
4 | </modal> | ||
5 | </template> | ||
6 | |||
7 | <script> | ||
8 | import Vue from 'vue'; | ||
9 | import VModal from 'vue-js-modal/dist/ssr.nocss'; | ||
10 | import 'vue-js-modal/dist/styles.css'; | ||
11 | Vue.use(VModal); | ||
12 | import YueCompiler from './YueCompiler.vue'; | ||
13 | |||
14 | export default { | ||
15 | components: { | ||
16 | YueCompiler, | ||
17 | }, | ||
18 | mounted () { | ||
19 | }, | ||
20 | data() { | ||
21 | return { | ||
22 | content: "", | ||
23 | }; | ||
24 | }, | ||
25 | methods: { | ||
26 | prepare() { | ||
27 | this.$data.content = window.yueCodes; | ||
28 | }, | ||
29 | }, | ||
30 | } | ||
31 | </script> | ||
32 | |||
diff --git a/doc/docs/.vuepress/components/YueCompiler.vue b/doc/docs/.vuepress/components/YueCompiler.vue new file mode 100755 index 0000000..4d72b92 --- /dev/null +++ b/doc/docs/.vuepress/components/YueCompiler.vue | |||
@@ -0,0 +1,383 @@ | |||
1 | <template> | ||
2 | <div style="width: 100%; height: auto;"> | ||
3 | <div class="parent" style="background-color: #f5f7ff;"> | ||
4 | <div class="childL" style="height: 2.5em;"> | ||
5 | <div class="childTitle">Yuescript {{ info }}</div> | ||
6 | </div> | ||
7 | <div class="childR" style="height: 2.5em;"> | ||
8 | <div class="childTitle">Lua</div> | ||
9 | </div> | ||
10 | <div class="childL" ref='yueEditor' style="height: 30em;"> | ||
11 | <ClientOnly> | ||
12 | <prism-editor class="my-editor" v-model="code" :highlight="highlighter" @input="codeChanged($event)" line-numbers :readonly="readonly"></prism-editor> | ||
13 | </ClientOnly> | ||
14 | </div> | ||
15 | <div class="childR" style="height: 30em;"> | ||
16 | <ClientOnly> | ||
17 | <prism-editor class="my-editor" v-model="compiled" :highlight="highlighter" @input="codeChanged($event)" readonly></prism-editor> | ||
18 | </ClientOnly> | ||
19 | </div> | ||
20 | </div> | ||
21 | <div v-if="!compileronly"> | ||
22 | <button class="button" @click="runCode()">Run!</button> | ||
23 | <textarea class="resultArea" readonly>{{ result }}</textarea> | ||
24 | </div> | ||
25 | </div> | ||
26 | </template> | ||
27 | |||
28 | <script> | ||
29 | import { PrismEditor } from 'vue-prism-editor'; | ||
30 | import 'vue-prism-editor/dist/prismeditor.min.css'; | ||
31 | import { highlight, languages } from 'prismjs/components/prism-core'; | ||
32 | import 'prismjs/components/prism-moonscript'; | ||
33 | import 'prismjs/components/prism-lua'; | ||
34 | |||
35 | export default { | ||
36 | props: { | ||
37 | compileronly: { | ||
38 | type: Boolean, | ||
39 | default: false, | ||
40 | }, | ||
41 | displayonly: { | ||
42 | type: Boolean, | ||
43 | default: false, | ||
44 | }, | ||
45 | text: { | ||
46 | type: String, | ||
47 | default: '', | ||
48 | }, | ||
49 | }, | ||
50 | components: { | ||
51 | PrismEditor, | ||
52 | }, | ||
53 | data() { | ||
54 | return { | ||
55 | info: 'Loading', | ||
56 | readonly: true, | ||
57 | code: '', | ||
58 | compiled: '', | ||
59 | result: '', | ||
60 | }; | ||
61 | }, | ||
62 | mounted () { | ||
63 | if (this.text !== '') { | ||
64 | this.$data.code = this.text; | ||
65 | this.codeChanged(this.text); | ||
66 | } | ||
67 | const check = ((self)=> { | ||
68 | return ()=> { | ||
69 | if (window.yue) { | ||
70 | self.$data.info = window.yue.version(); | ||
71 | self.$data.readonly = false; | ||
72 | const editor = self.$refs.yueEditor; | ||
73 | if (editor.children.length === 0) { | ||
74 | setTimeout(check, 100); | ||
75 | return; | ||
76 | } | ||
77 | const textArea = editor.children[0].children[1].children[0]; | ||
78 | textArea.focus(); | ||
79 | } else { | ||
80 | setTimeout(check, 100); | ||
81 | } | ||
82 | } | ||
83 | })(this); | ||
84 | check(); | ||
85 | }, | ||
86 | methods: { | ||
87 | runCode() { | ||
88 | if (window.yue && this.$data.compiled !== '') { | ||
89 | let res = ''; | ||
90 | try { | ||
91 | res = window.yue.exec(this.$data.code); | ||
92 | } catch (err) { | ||
93 | res = err; | ||
94 | } | ||
95 | this.$data.result = res; | ||
96 | } | ||
97 | }, | ||
98 | highlighter(code) { | ||
99 | return highlight(code, languages.moon); | ||
100 | }, | ||
101 | codeChanged(text) { | ||
102 | if (window.yue) { | ||
103 | let res = ['','compiler error, and please help opening an issue for this. Thanks a lot!']; | ||
104 | try { | ||
105 | res = window.yue.tolua(text, true, !this.displayonly, true); | ||
106 | if (res[0] !== '') { | ||
107 | this.$data.compiled = res[0]; | ||
108 | } else { | ||
109 | this.$data.compiled = res[1]; | ||
110 | } | ||
111 | } catch (error) { | ||
112 | this.$data.compiled = res[1]; | ||
113 | } | ||
114 | } | ||
115 | }, | ||
116 | } | ||
117 | } | ||
118 | </script> | ||
119 | |||
120 | <style scoped> | ||
121 | .resultArea { | ||
122 | float: left; | ||
123 | margin-right: 1em; | ||
124 | overflow: scroll; | ||
125 | overflow-wrap: break-word; | ||
126 | width: calc(100% - 120px); | ||
127 | height: 55px; | ||
128 | border-color: #b7ae8f; | ||
129 | outline: none; | ||
130 | resize: none; | ||
131 | margin-top: 5px; | ||
132 | } | ||
133 | .childL { | ||
134 | float: left; | ||
135 | width: 50%; | ||
136 | box-sizing: border-box; | ||
137 | background-clip: content-box; | ||
138 | background: #f5f7ff; | ||
139 | } | ||
140 | .childR { | ||
141 | float: left; | ||
142 | width: 50%; | ||
143 | box-sizing: border-box; | ||
144 | background-clip: content-box; | ||
145 | background: #f5f7ff; | ||
146 | } | ||
147 | .childTitle { | ||
148 | width: 100%; | ||
149 | font-size: 1.5em; | ||
150 | color: #b7ae8f; | ||
151 | text-align: center; | ||
152 | padding: 0.2em; | ||
153 | } | ||
154 | .button { | ||
155 | float: right; | ||
156 | border: none; | ||
157 | display: inline-block; | ||
158 | font-size: 1.2rem; | ||
159 | color: #fff; | ||
160 | background-color: #b7ae8f; | ||
161 | text-decoration: none; | ||
162 | padding: .8rem 1.6rem; | ||
163 | border-radius: 4px; | ||
164 | transition: background-color .1s ease; | ||
165 | box-sizing: border-box; | ||
166 | border-bottom: 1px solid #aaa07b; | ||
167 | margin-top: 10px; | ||
168 | margin-right: 5px; | ||
169 | } | ||
170 | .button:hover { | ||
171 | background-color: #beb69a; | ||
172 | } | ||
173 | .button:focus, | ||
174 | .button:active:focus, | ||
175 | .button.active:focus, | ||
176 | .button.focus, | ||
177 | .button:active.focus { | ||
178 | outline: none; | ||
179 | } | ||
180 | |||
181 | .my-editor { | ||
182 | font-family: Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace; | ||
183 | line-height: 1.375; | ||
184 | direction: ltr; | ||
185 | text-align: left; | ||
186 | white-space: pre; | ||
187 | word-spacing: normal; | ||
188 | word-break: normal; | ||
189 | -moz-tab-size: 4; | ||
190 | -o-tab-size: 4; | ||
191 | tab-size: 4; | ||
192 | -webkit-hyphens: none; | ||
193 | -moz-hyphens: none; | ||
194 | -ms-hyphens: none; | ||
195 | hyphens: none; | ||
196 | background: #f5f7ff; | ||
197 | color: #5e6687; | ||
198 | font-size: 1em; | ||
199 | overflow: scroll; | ||
200 | } | ||
201 | |||
202 | .my-editor >>> .prism-editor__textarea:focus { | ||
203 | outline: none; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | Name: Base16 Atelier Sulphurpool Light | ||
208 | Author: Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) | ||
209 | |||
210 | Prism template by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/prism/) | ||
211 | Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) | ||
212 | |||
213 | */ | ||
214 | code[class*="language-"], | ||
215 | pre[class*="language-"] { | ||
216 | font-family: Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace; | ||
217 | font-size: 1em; | ||
218 | line-height: 1.375; | ||
219 | direction: ltr; | ||
220 | text-align: left; | ||
221 | white-space: pre; | ||
222 | word-spacing: normal; | ||
223 | word-break: normal; | ||
224 | -moz-tab-size: 4; | ||
225 | -o-tab-size: 4; | ||
226 | tab-size: 4; | ||
227 | -webkit-hyphens: none; | ||
228 | -moz-hyphens: none; | ||
229 | -ms-hyphens: none; | ||
230 | hyphens: none; | ||
231 | background: #f5f7ff; | ||
232 | color: #5e6687; | ||
233 | } | ||
234 | |||
235 | pre > code[class*="language-"] { | ||
236 | font-size: 1em; | ||
237 | } | ||
238 | |||
239 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, | ||
240 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { | ||
241 | text-shadow: none; | ||
242 | background: #dfe2f1; | ||
243 | } | ||
244 | |||
245 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, | ||
246 | code[class*="language-"]::selection, code[class*="language-"] ::selection { | ||
247 | text-shadow: none; | ||
248 | background: #dfe2f1; | ||
249 | } | ||
250 | |||
251 | /* Code blocks */ | ||
252 | pre[class*="language-"] { | ||
253 | padding: 1em; | ||
254 | margin: .5em 0; | ||
255 | overflow: auto; | ||
256 | } | ||
257 | |||
258 | /* Inline code */ | ||
259 | :not(pre) > code[class*="language-"] { | ||
260 | padding: .1em; | ||
261 | border-radius: .3em; | ||
262 | } | ||
263 | |||
264 | .token.comment, | ||
265 | .token.prolog, | ||
266 | .token.doctype, | ||
267 | .token.cdata { | ||
268 | color: #898ea4; | ||
269 | } | ||
270 | |||
271 | .token.punctuation { | ||
272 | color: #5e6687; | ||
273 | } | ||
274 | |||
275 | .token.namespace { | ||
276 | opacity: .7; | ||
277 | } | ||
278 | |||
279 | .token.operator, | ||
280 | .token.boolean, | ||
281 | .token.number { | ||
282 | color: #c76b29; | ||
283 | } | ||
284 | |||
285 | .token.property { | ||
286 | color: #c08b30; | ||
287 | } | ||
288 | |||
289 | .token.tag { | ||
290 | color: #3d8fd1; | ||
291 | } | ||
292 | |||
293 | .token.string { | ||
294 | color: #22a2c9; | ||
295 | } | ||
296 | |||
297 | .token.selector { | ||
298 | color: #6679cc; | ||
299 | } | ||
300 | |||
301 | .token.attr-name { | ||
302 | color: #c76b29; | ||
303 | } | ||
304 | |||
305 | .token.entity, | ||
306 | .token.url, | ||
307 | .language-css .token.string, | ||
308 | .style .token.string { | ||
309 | color: #22a2c9; | ||
310 | } | ||
311 | |||
312 | .token.attr-value, | ||
313 | .token.keyword, | ||
314 | .token.control, | ||
315 | .token.directive, | ||
316 | .token.unit { | ||
317 | color: #ac9739; | ||
318 | } | ||
319 | |||
320 | .token.statement, | ||
321 | .token.regex, | ||
322 | .token.atrule { | ||
323 | color: #22a2c9; | ||
324 | } | ||
325 | |||
326 | .token.placeholder, | ||
327 | .token.variable { | ||
328 | color: #3d8fd1; | ||
329 | } | ||
330 | |||
331 | .token.deleted { | ||
332 | text-decoration: line-through; | ||
333 | } | ||
334 | |||
335 | .token.inserted { | ||
336 | border-bottom: 1px dotted #202746; | ||
337 | text-decoration: none; | ||
338 | } | ||
339 | |||
340 | .token.italic { | ||
341 | font-style: italic; | ||
342 | } | ||
343 | |||
344 | .token.important, | ||
345 | .token.bold { | ||
346 | font-weight: bold; | ||
347 | } | ||
348 | |||
349 | .token.important { | ||
350 | color: #c94922; | ||
351 | } | ||
352 | |||
353 | .token.entity { | ||
354 | cursor: help; | ||
355 | } | ||
356 | |||
357 | pre > code.highlight { | ||
358 | outline: 0.4em solid #c94922; | ||
359 | outline-offset: .4em; | ||
360 | } | ||
361 | |||
362 | /* overrides color-values for the Line Numbers plugin | ||
363 | * http://prismjs.com/plugins/line-numbers/ | ||
364 | */ | ||
365 | .line-numbers .line-numbers-rows { | ||
366 | border-right-color: #dfe2f1; | ||
367 | } | ||
368 | |||
369 | .line-numbers-rows > span:before { | ||
370 | color: #979db4; | ||
371 | } | ||
372 | |||
373 | /* overrides color-values for the Line Highlight plugin | ||
374 | * http://prismjs.com/plugins/line-highlight/ | ||
375 | */ | ||
376 | .line-highlight { | ||
377 | background: rgba(107, 115, 148, 0.2); | ||
378 | background: -webkit-linear-gradient(left, rgba(107, 115, 148, 0.2) 70%, rgba(107, 115, 148, 0)); | ||
379 | background: linear-gradient(to right, rgba(107, 115, 148, 0.2) 70%, rgba(107, 115, 148, 0)); | ||
380 | } | ||
381 | |||
382 | </style> | ||
383 | |||
diff --git a/doc/docs/.vuepress/components/YueDisplay.vue b/doc/docs/.vuepress/components/YueDisplay.vue new file mode 100755 index 0000000..b89805b --- /dev/null +++ b/doc/docs/.vuepress/components/YueDisplay.vue | |||
@@ -0,0 +1,49 @@ | |||
1 | <template> | ||
2 | <div> | ||
3 | <button class="button" @click="compile()">Compile</button> | ||
4 | <div style="display: none;"> | ||
5 | <slot></slot> | ||
6 | </div> | ||
7 | </div> | ||
8 | </template> | ||
9 | |||
10 | <script> | ||
11 | export default { | ||
12 | methods: { | ||
13 | compile() { | ||
14 | const node = this.$el.children[1]; | ||
15 | const code = node.innerText; | ||
16 | window.yueCodes = code; | ||
17 | this.$modal.show('compiler'); | ||
18 | }, | ||
19 | }, | ||
20 | } | ||
21 | </script> | ||
22 | |||
23 | <style scoped> | ||
24 | .button { | ||
25 | border: none; | ||
26 | display: inline-block; | ||
27 | font-size: 16px; | ||
28 | color: #fff; | ||
29 | background-color: #b7ae8f; | ||
30 | text-decoration: none; | ||
31 | padding: .4rem 0.8rem; | ||
32 | border-radius: 4px; | ||
33 | transition: background-color .1s ease; | ||
34 | box-sizing: border-box; | ||
35 | border-bottom: 1px solid #aaa07b; | ||
36 | margin-bottom: 1em; | ||
37 | } | ||
38 | .button:hover { | ||
39 | background-color: #beb69a; | ||
40 | } | ||
41 | .button:focus, | ||
42 | .button:active:focus, | ||
43 | .button.active:focus, | ||
44 | .button.focus, | ||
45 | .button:active.focus { | ||
46 | outline: none; | ||
47 | } | ||
48 | </style> | ||
49 | |||
diff --git a/doc/docs/.vuepress/config.js b/doc/docs/.vuepress/config.js new file mode 100755 index 0000000..fe34c46 --- /dev/null +++ b/doc/docs/.vuepress/config.js | |||
@@ -0,0 +1,77 @@ | |||
1 | const { description } = require('../../package') | ||
2 | |||
3 | module.exports = { | ||
4 | /** | ||
5 | * Ref:https://v1.vuepress.vuejs.org/config/#title | ||
6 | */ | ||
7 | title: 'Yuescript', | ||
8 | /** | ||
9 | * Ref:https://v1.vuepress.vuejs.org/config/#description | ||
10 | */ | ||
11 | description: description, | ||
12 | |||
13 | /** | ||
14 | * Extra tags to be injected to the page HTML `<head>` | ||
15 | * | ||
16 | * ref:https://v1.vuepress.vuejs.org/config/#head | ||
17 | */ | ||
18 | head: [ | ||
19 | ['meta', { name: 'theme-color', content: '#3eaf7c' }], | ||
20 | ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }], | ||
21 | ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }], | ||
22 | ['script', {}, `window.global = window;`], | ||
23 | ['script', {}, ` | ||
24 | var Module = { | ||
25 | onRuntimeInitialized: function() { | ||
26 | window.yue = Module; | ||
27 | window.Vue.$data.readonly = false; | ||
28 | window.Vue.$data.info = Module.version(); | ||
29 | } | ||
30 | }; | ||
31 | `], | ||
32 | ['script', {}, ` | ||
33 | var Module = { | ||
34 | onRuntimeInitialized: function() { | ||
35 | window.yue = Module; | ||
36 | } | ||
37 | }; | ||
38 | `], | ||
39 | ['script', { src: '/js/yuescript.js' }], | ||
40 | ], | ||
41 | |||
42 | /** | ||
43 | * Theme configuration, here is the default theme configuration for VuePress. | ||
44 | * | ||
45 | * ref:https://v1.vuepress.vuejs.org/theme/default-theme-config.html | ||
46 | */ | ||
47 | themeConfig: { | ||
48 | repo: '', | ||
49 | editLinks: false, | ||
50 | docsDir: '', | ||
51 | editLinkText: '', | ||
52 | lastUpdated: false, | ||
53 | nav: [ | ||
54 | { | ||
55 | text: 'Document', | ||
56 | link: '/doc/' | ||
57 | }, | ||
58 | { | ||
59 | text: 'Try yue!', | ||
60 | link: '/try/', | ||
61 | }, | ||
62 | { | ||
63 | text: 'Github', | ||
64 | link: 'https://github.com/pigpigyyy/Yuescript' | ||
65 | } | ||
66 | ], | ||
67 | }, | ||
68 | |||
69 | /** | ||
70 | * Apply plugins,ref:https://v1.vuepress.vuejs.org/zh/plugin/ | ||
71 | */ | ||
72 | plugins: [ | ||
73 | '@vuepress/plugin-back-to-top', | ||
74 | '@vuepress/plugin-medium-zoom', | ||
75 | '~plugins/vue-js-modal.js', | ||
76 | ] | ||
77 | } | ||
diff --git a/doc/docs/.vuepress/enhanceApp.js b/doc/docs/.vuepress/enhanceApp.js new file mode 100755 index 0000000..8452a86 --- /dev/null +++ b/doc/docs/.vuepress/enhanceApp.js | |||
@@ -0,0 +1,14 @@ | |||
1 | /** | ||
2 | * Client app enhancement file. | ||
3 | * | ||
4 | * https://v1.vuepress.vuejs.org/guide/basic-config.html#app-level-enhancements | ||
5 | */ | ||
6 | |||
7 | export default ({ | ||
8 | Vue, // the version of Vue being used in the VuePress app | ||
9 | options, // the options for the root Vue instance | ||
10 | router, // the router instance for the app | ||
11 | siteData // site metadata | ||
12 | }) => { | ||
13 | // ...apply enhancements for the site. | ||
14 | } | ||
diff --git a/doc/docs/.vuepress/public/image/yuescript.svg b/doc/docs/.vuepress/public/image/yuescript.svg new file mode 100644 index 0000000..b7e5884 --- /dev/null +++ b/doc/docs/.vuepress/public/image/yuescript.svg | |||
@@ -0,0 +1,53 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- Generator: Adobe Illustrator 22.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | ||
3 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ | ||
4 | <!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/"> | ||
5 | <!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/"> | ||
6 | <!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/"> | ||
7 | <!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/"> | ||
8 | <!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/"> | ||
9 | <!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/"> | ||
10 | <!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/"> | ||
11 | <!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/"> | ||
12 | ]> | ||
13 | <svg version="1.1" id="图层_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;" | ||
14 | xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="" viewBox="250 200 95.3 441.9" xml:space="preserve"> | ||
15 | <g> | ||
16 | <g> | ||
17 | <path fill="#B4AC8F" d="M209.8,522.5c-3.7,0.8-8.1,1.6-11.7,2.3c0.5-2,1.9-7.8,2.9-11.5l-2.8-2.9l-3.3,14.5c0,0.2-0.1,0.4-0.3,0.6 | ||
18 | l-6,5.7l2.4,2.6l6.1-5.8c0.2-0.2,0.3-0.3,0.5-0.3l14.7-2.5L209.8,522.5z"/> | ||
19 | <path fill="#B4AC8F" d="M225.4,551.7c-1.9,2.7-4.2,3.9-7.8,1.5c-3.6-2.5-3.4-5.2-1.6-7.8l7.7-11.2l-2.9-2l-7.8,11.4 | ||
20 | c-2.8,4-2.3,7.9,3.2,11.7c5.9,4,9.7,2.4,12.2-1.3l7.7-11.3l-3-2L225.4,551.7z"/> | ||
21 | <polygon fill="#B4AC8F" points="241.1,569.1 255.5,574.8 256.9,572.7 245.3,568 248,561.2 258.6,565.4 259.5,563 249,558.8 | ||
22 | 251.4,552.9 262.4,557.3 263.3,555 249.1,549.3 "/> | ||
23 | <path fill="#B4AC8F" d="M283.6,559.6c-4.7-0.8-8.2,0.8-8.8,4.2c-0.5,3,1.2,4.9,6.3,7.2c4,1.8,5.2,3,4.8,5.3 | ||
24 | c-0.4,2.2-2.4,3.1-5.4,2.6c-2.9-0.5-4.7-2.2-4.8-4.8l-3.5-0.6c-0.3,3.9,2.4,6.8,7.6,7.8c5.7,1,9-1.1,9.6-4.6 | ||
25 | c0.5-2.9-0.7-5.2-6.6-7.9c-3.7-1.7-4.9-2.6-4.6-4.5c0.3-1.8,1.9-2.7,4.7-2.2c3,0.5,4.1,2.1,4.1,4.2l3.4,0.6 | ||
26 | C291,563.6,289.1,560.6,283.6,559.6z"/> | ||
27 | <path fill="#B4AC8F" d="M315.3,581.1c-5.2,0.2-7-4-7.1-8.4c-0.2-4.4,1.6-8.4,6.4-8.6c3.7-0.1,5.2,1.6,5.9,3.9l3.5-0.1 | ||
28 | c-0.6-3.5-3.4-6.5-9.4-6.3c-7.2,0.3-10.3,5.5-10.1,11.2c0.2,6.3,3.2,11,10.8,10.7c6.1-0.2,8.6-3.5,9.2-7l-3.5,0.1 | ||
29 | C320.4,579,319,581,315.3,581.1z"/> | ||
30 | <path fill="#B4AC8F" d="M356.7,570.7c-0.7-2.8-2.2-4.2-4.9-4.2c1.8-1.1,3.5-2.9,2.7-5.9c-0.9-3.5-4.5-4.6-8.9-3.4l-8.9,2.3l5.3,20.6 | ||
31 | l3.4-0.9L343,570l4.1-1.1c3.9-1,5.4-0.2,6.1,2.6l0.1,0.4c0.6,2.2,1.1,4,1.7,4.8l3.4-0.9c-0.6-1.1-1.1-2.9-1.6-4.8L356.7,570.7z | ||
32 | M346.8,566.5l-4.4,1.1l-1.7-6.7l5.1-1.3c2.8-0.7,4.8-0.1,5.3,2C351.8,564.5,349.8,565.8,346.8,566.5z"/> | ||
33 | |||
34 | <rect x="370.4" y="548.3" transform="matrix(0.9105 -0.4136 0.4136 0.9105 -197.8473 203.9409)" fill="#B4AC8F" width="3.5" height="21.3"/> | ||
35 | <path fill="#B4AC8F" d="M390,536.6l-7.2,4.9l12,17.6l2.9-2l-5.1-7.4l3.9-2.7c4.3-2.9,6.1-6.7,3.7-10.2 | ||
36 | C398.1,533.6,393.9,533.9,390,536.6z M395.1,545.1l-3.7,2.6l-4.2-6.2l3.8-2.6c2.6-1.8,5-2,6.4,0 | ||
37 | C399,541.3,397.7,543.3,395.1,545.1z"/> | ||
38 | <polygon fill="#B4AC8F" points="419.6,513.4 417.7,511.6 405.1,524.8 407,526.5 412,521.2 425.6,534.2 428.1,531.6 414.5,518.7 | ||
39 | "/> | ||
40 | <path fill="#B4AC8F" d="M334.2,260.2c-2.1-0.3-4.2-0.6-6.3-0.9v14.4v0.5c22.4,24.2,36.9,55.9,39,90.9H228.7c0,0-14,0.7-14,12.3 | ||
41 | c0,12.1,11.1,14.1,13.9,14.1s69.4,0,69.4,0s8.7-0.5,8.7,6.1c0,6.3-6.4,6-8.6,6H156.6c11-74.3,69.2-133.2,143.1-145.3 | ||
42 | c-79.7,4.2-144.2,66.5-151.9,145.3h-41.1c0,0-15.3-1.8-15.3,11.5c0,13.3,11.5,12.8,14.7,12.8c0.6,0,19.5,0,41.1,0 | ||
43 | c1.5,28.3,10.4,54.8,24.7,77.4l0.1-0.1c-8.8-17.9-14.5-37.6-16.6-58.4c31.5,0,73,0,75.3,0c3.6,0,13.7-0.5,13.7-12.2 | ||
44 | c0-11.6-12.4-11.9-12.4-11.9l-101.8,0c0,0-8.9,0.7-8.9-6.4s5.8-7.4,8.4-7.4c0.6,0,190.5,0,190.5,0s14.6,1.6,14.6-11.9 | ||
45 | c0-12-12.8-11.5-17.5-11.5c-4.7,0-65.1,0-65.1,0s-9.7,0.4-9.7-6.9c0-7.3,8.2-6.9,9.6-6.9c0.7,0,59.7,0,114.7,0c0,0.7,0,1.5,0,2.2 | ||
46 | c0,38.5-14.9,73.6-39.3,99.8v0c-21.6,23.3-50.7,39.6-83.5,45.1c6.3,3.9,12.9,7.3,19.8,10.2c23.9-6.8,45.6-19,63.6-35.2v0 | ||
47 | c14.7-13.2,27-29.2,36.1-47h71.1v-6.7h-67.9c9.1-20.2,14.2-42.6,14.2-66.2c0-0.7,0-1.5,0-2.2c26.9,0,51.4,0,65.9,0 | ||
48 | c5.1,14.9,7.9,30.8,7.9,47.4c0,27.5-7.6,53.3-20.9,75.4l11.2,9.1c15.2-24.6,24-53.5,24-84.5C469.4,339.2,410.8,272.6,334.2,260.2 | ||
49 | z M216.9,435.3c0,6.5-6.3,6.9-6.3,6.9s-27,0-55.4,0c-0.3-4.3-0.5-8.6-0.5-12.9c0-0.5,0-0.9,0-1.4c27.4,0,56.2,0,56.5,0 | ||
50 | C212.2,428,216.9,428.8,216.9,435.3z M381.2,365.1c-1.8-32.4-13.1-62.2-31.3-86.7c43.3,12.8,78.4,45.1,95,86.7H381.2z"/> | ||
51 | </g> | ||
52 | </g> | ||
53 | </svg> | ||
diff --git a/doc/docs/.vuepress/styles/index.styl b/doc/docs/.vuepress/styles/index.styl new file mode 100755 index 0000000..69327fd --- /dev/null +++ b/doc/docs/.vuepress/styles/index.styl | |||
@@ -0,0 +1,9 @@ | |||
1 | /** | ||
2 | * Custom Styles here. | ||
3 | * | ||
4 | * ref:https://v1.vuepress.vuejs.org/config/#index-styl | ||
5 | */ | ||
6 | |||
7 | .home .hero img | ||
8 | max-width 450px!important | ||
9 | |||
diff --git a/doc/docs/.vuepress/styles/palette.styl b/doc/docs/.vuepress/styles/palette.styl new file mode 100755 index 0000000..389aa76 --- /dev/null +++ b/doc/docs/.vuepress/styles/palette.styl | |||
@@ -0,0 +1,12 @@ | |||
1 | /** | ||
2 | * Custom palette here. | ||
3 | * | ||
4 | * ref:https://v1.vuepress.vuejs.org/zh/config/#palette-styl | ||
5 | */ | ||
6 | |||
7 | $accentColor = #b7ae8f | ||
8 | $textColor = #2c3e50 | ||
9 | $borderColor = #eaecef | ||
10 | $codeBgColor = #f5f7ff | ||
11 | |||
12 | $contentWidth = 900px | ||
diff --git a/doc/docs/.vuepress/theme/LICENSE b/doc/docs/.vuepress/theme/LICENSE new file mode 100644 index 0000000..15f1f7e --- /dev/null +++ b/doc/docs/.vuepress/theme/LICENSE | |||
@@ -0,0 +1,21 @@ | |||
1 | The MIT License (MIT) | ||
2 | |||
3 | Copyright (c) 2018-present, Yuxi (Evan) You | ||
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 | ||
13 | all 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 | ||
21 | THE SOFTWARE. | ||
diff --git a/doc/docs/.vuepress/theme/README.md b/doc/docs/.vuepress/theme/README.md new file mode 100644 index 0000000..fc49626 --- /dev/null +++ b/doc/docs/.vuepress/theme/README.md | |||
@@ -0,0 +1,11 @@ | |||
1 | # @vuepress/theme-default | ||
2 | |||
3 | > theme-default for VuePress | ||
4 | |||
5 | ## Plugins | ||
6 | |||
7 | The default theme has the following plugin built in: | ||
8 | |||
9 | - [@vuepress/plugin-active-header-links](https://github.com/vuejs/vuepress/tree/master/packages/@vuepress/plugin-active-header-links) | ||
10 | - [@vuepress/plugin-google-analytics](https://github.com/vuejs/vuepress/tree/master/packages/%40vuepress/plugin-google-analytics) | ||
11 | - [@vuepress/plugin-search](https://github.com/vuejs/vuepress/tree/master/packages/%40vuepress/plugin-search) | ||
diff --git a/doc/docs/.vuepress/theme/components/AlgoliaSearchBox.vue b/doc/docs/.vuepress/theme/components/AlgoliaSearchBox.vue new file mode 100644 index 0000000..7071fb8 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/AlgoliaSearchBox.vue | |||
@@ -0,0 +1,172 @@ | |||
1 | <template> | ||
2 | <form | ||
3 | id="search-form" | ||
4 | class="algolia-search-wrapper search-box" | ||
5 | role="search" | ||
6 | > | ||
7 | <input | ||
8 | id="algolia-search-input" | ||
9 | class="search-query" | ||
10 | :placeholder="placeholder" | ||
11 | > | ||
12 | </form> | ||
13 | </template> | ||
14 | |||
15 | <script> | ||
16 | export default { | ||
17 | name: 'AlgoliaSearchBox', | ||
18 | |||
19 | props: ['options'], | ||
20 | |||
21 | data () { | ||
22 | return { | ||
23 | placeholder: undefined | ||
24 | } | ||
25 | }, | ||
26 | |||
27 | watch: { | ||
28 | $lang (newValue) { | ||
29 | this.update(this.options, newValue) | ||
30 | }, | ||
31 | |||
32 | options (newValue) { | ||
33 | this.update(newValue, this.$lang) | ||
34 | } | ||
35 | }, | ||
36 | |||
37 | mounted () { | ||
38 | this.initialize(this.options, this.$lang) | ||
39 | this.placeholder = this.$site.themeConfig.searchPlaceholder || '' | ||
40 | }, | ||
41 | |||
42 | methods: { | ||
43 | initialize (userOptions, lang) { | ||
44 | Promise.all([ | ||
45 | import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.js'), | ||
46 | import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.css') | ||
47 | ]).then(([docsearch]) => { | ||
48 | docsearch = docsearch.default | ||
49 | const { algoliaOptions = {}} = userOptions | ||
50 | docsearch(Object.assign( | ||
51 | {}, | ||
52 | userOptions, | ||
53 | { | ||
54 | inputSelector: '#algolia-search-input', | ||
55 | // #697 Make docsearch work well at i18n mode. | ||
56 | algoliaOptions: { | ||
57 | ...algoliaOptions, | ||
58 | facetFilters: [`lang:${lang}`].concat(algoliaOptions.facetFilters || []) | ||
59 | }, | ||
60 | handleSelected: (input, event, suggestion) => { | ||
61 | const { pathname, hash } = new URL(suggestion.url) | ||
62 | const routepath = pathname.replace(this.$site.base, '/') | ||
63 | const _hash = decodeURIComponent(hash) | ||
64 | this.$router.push(`${routepath}${_hash}`) | ||
65 | } | ||
66 | } | ||
67 | )) | ||
68 | }) | ||
69 | }, | ||
70 | |||
71 | update (options, lang) { | ||
72 | this.$el.innerHTML = '<input id="algolia-search-input" class="search-query">' | ||
73 | this.initialize(options, lang) | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | </script> | ||
78 | |||
79 | <style lang="stylus"> | ||
80 | .algolia-search-wrapper | ||
81 | & > span | ||
82 | vertical-align middle | ||
83 | .algolia-autocomplete | ||
84 | line-height normal | ||
85 | .ds-dropdown-menu | ||
86 | background-color #fff | ||
87 | border 1px solid #999 | ||
88 | border-radius 4px | ||
89 | font-size 16px | ||
90 | margin 6px 0 0 | ||
91 | padding 4px | ||
92 | text-align left | ||
93 | &:before | ||
94 | border-color #999 | ||
95 | [class*=ds-dataset-] | ||
96 | border none | ||
97 | padding 0 | ||
98 | .ds-suggestions | ||
99 | margin-top 0 | ||
100 | .ds-suggestion | ||
101 | border-bottom 1px solid $borderColor | ||
102 | .algolia-docsearch-suggestion--highlight | ||
103 | color #2c815b | ||
104 | .algolia-docsearch-suggestion | ||
105 | border-color $borderColor | ||
106 | padding 0 | ||
107 | .algolia-docsearch-suggestion--category-header | ||
108 | padding 5px 10px | ||
109 | margin-top 0 | ||
110 | background $accentColor | ||
111 | color #fff | ||
112 | font-weight 600 | ||
113 | .algolia-docsearch-suggestion--highlight | ||
114 | background rgba(255, 255, 255, 0.6) | ||
115 | .algolia-docsearch-suggestion--wrapper | ||
116 | padding 0 | ||
117 | .algolia-docsearch-suggestion--title | ||
118 | font-weight 600 | ||
119 | margin-bottom 0 | ||
120 | color $textColor | ||
121 | .algolia-docsearch-suggestion--subcategory-column | ||
122 | vertical-align top | ||
123 | padding 5px 7px 5px 5px | ||
124 | border-color $borderColor | ||
125 | background #f1f3f5 | ||
126 | &:after | ||
127 | display none | ||
128 | .algolia-docsearch-suggestion--subcategory-column-text | ||
129 | color #555 | ||
130 | .algolia-docsearch-footer | ||
131 | border-color $borderColor | ||
132 | .ds-cursor .algolia-docsearch-suggestion--content | ||
133 | background-color #e7edf3 !important | ||
134 | color $textColor | ||
135 | |||
136 | @media (min-width: $MQMobile) | ||
137 | .algolia-search-wrapper | ||
138 | .algolia-autocomplete | ||
139 | .algolia-docsearch-suggestion | ||
140 | .algolia-docsearch-suggestion--subcategory-column | ||
141 | float none | ||
142 | width 150px | ||
143 | min-width 150px | ||
144 | display table-cell | ||
145 | .algolia-docsearch-suggestion--content | ||
146 | float none | ||
147 | display table-cell | ||
148 | width 100% | ||
149 | vertical-align top | ||
150 | .ds-dropdown-menu | ||
151 | min-width 515px !important | ||
152 | |||
153 | @media (max-width: $MQMobile) | ||
154 | .algolia-search-wrapper | ||
155 | .ds-dropdown-menu | ||
156 | min-width calc(100vw - 4rem) !important | ||
157 | max-width calc(100vw - 4rem) !important | ||
158 | .algolia-docsearch-suggestion--wrapper | ||
159 | padding 5px 7px 5px 5px !important | ||
160 | .algolia-docsearch-suggestion--subcategory-column | ||
161 | padding 0 !important | ||
162 | background white !important | ||
163 | .algolia-docsearch-suggestion--subcategory-column-text:after | ||
164 | content " > " | ||
165 | font-size 10px | ||
166 | line-height 14.4px | ||
167 | display inline-block | ||
168 | width 5px | ||
169 | margin -3px 3px 0 | ||
170 | vertical-align middle | ||
171 | |||
172 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/DropdownLink.vue b/doc/docs/.vuepress/theme/components/DropdownLink.vue new file mode 100644 index 0000000..be6563f --- /dev/null +++ b/doc/docs/.vuepress/theme/components/DropdownLink.vue | |||
@@ -0,0 +1,252 @@ | |||
1 | <template> | ||
2 | <div | ||
3 | class="dropdown-wrapper" | ||
4 | :class="{ open }" | ||
5 | > | ||
6 | <button | ||
7 | class="dropdown-title" | ||
8 | type="button" | ||
9 | :aria-label="dropdownAriaLabel" | ||
10 | @click="handleDropdown" | ||
11 | > | ||
12 | <span class="title">{{ item.text }}</span> | ||
13 | <span | ||
14 | class="arrow down" | ||
15 | /> | ||
16 | </button> | ||
17 | <button | ||
18 | class="mobile-dropdown-title" | ||
19 | type="button" | ||
20 | :aria-label="dropdownAriaLabel" | ||
21 | @click="setOpen(!open)" | ||
22 | > | ||
23 | <span class="title">{{ item.text }}</span> | ||
24 | <span | ||
25 | class="arrow" | ||
26 | :class="open ? 'down' : 'right'" | ||
27 | /> | ||
28 | </button> | ||
29 | |||
30 | <DropdownTransition> | ||
31 | <ul | ||
32 | v-show="open" | ||
33 | class="nav-dropdown" | ||
34 | > | ||
35 | <li | ||
36 | v-for="(subItem, index) in item.items" | ||
37 | :key="subItem.link || index" | ||
38 | class="dropdown-item" | ||
39 | > | ||
40 | <h4 v-if="subItem.type === 'links'"> | ||
41 | {{ subItem.text }} | ||
42 | </h4> | ||
43 | |||
44 | <ul | ||
45 | v-if="subItem.type === 'links'" | ||
46 | class="dropdown-subitem-wrapper" | ||
47 | > | ||
48 | <li | ||
49 | v-for="childSubItem in subItem.items" | ||
50 | :key="childSubItem.link" | ||
51 | class="dropdown-subitem" | ||
52 | > | ||
53 | <NavLink | ||
54 | :item="childSubItem" | ||
55 | @focusout=" | ||
56 | isLastItemOfArray(childSubItem, subItem.items) && | ||
57 | isLastItemOfArray(subItem, item.items) && | ||
58 | setOpen(false) | ||
59 | " | ||
60 | /> | ||
61 | </li> | ||
62 | </ul> | ||
63 | |||
64 | <NavLink | ||
65 | v-else | ||
66 | :item="subItem" | ||
67 | @focusout="isLastItemOfArray(subItem, item.items) && setOpen(false)" | ||
68 | /> | ||
69 | </li> | ||
70 | </ul> | ||
71 | </DropdownTransition> | ||
72 | </div> | ||
73 | </template> | ||
74 | |||
75 | <script> | ||
76 | import NavLink from '@theme/components/NavLink.vue' | ||
77 | import DropdownTransition from '@theme/components/DropdownTransition.vue' | ||
78 | import last from 'lodash/last' | ||
79 | |||
80 | export default { | ||
81 | name: 'DropdownLink', | ||
82 | |||
83 | components: { | ||
84 | NavLink, | ||
85 | DropdownTransition | ||
86 | }, | ||
87 | |||
88 | props: { | ||
89 | item: { | ||
90 | required: true | ||
91 | } | ||
92 | }, | ||
93 | |||
94 | data () { | ||
95 | return { | ||
96 | open: false | ||
97 | } | ||
98 | }, | ||
99 | |||
100 | computed: { | ||
101 | dropdownAriaLabel () { | ||
102 | return this.item.ariaLabel || this.item.text | ||
103 | } | ||
104 | }, | ||
105 | |||
106 | watch: { | ||
107 | $route () { | ||
108 | this.open = false | ||
109 | } | ||
110 | }, | ||
111 | |||
112 | methods: { | ||
113 | setOpen (value) { | ||
114 | this.open = value | ||
115 | }, | ||
116 | |||
117 | isLastItemOfArray (item, array) { | ||
118 | return last(array) === item | ||
119 | }, | ||
120 | |||
121 | /** | ||
122 | * Open the dropdown when user tab and click from keyboard. | ||
123 | * | ||
124 | * Use event.detail to detect tab and click from keyboard. Ref: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail | ||
125 | * The Tab + Click is UIEvent > KeyboardEvent, so the detail is 0. | ||
126 | */ | ||
127 | handleDropdown () { | ||
128 | const isTriggerByTab = event.detail === 0 | ||
129 | if (isTriggerByTab) this.setOpen(!this.open) | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | </script> | ||
134 | |||
135 | <style lang="stylus"> | ||
136 | .dropdown-wrapper | ||
137 | cursor pointer | ||
138 | .dropdown-title | ||
139 | display block | ||
140 | font-size 0.9rem | ||
141 | font-family inherit | ||
142 | cursor inherit | ||
143 | padding inherit | ||
144 | line-height 1.4rem | ||
145 | background transparent | ||
146 | border none | ||
147 | font-weight 500 | ||
148 | color $textColor | ||
149 | &:hover | ||
150 | border-color transparent | ||
151 | .arrow | ||
152 | vertical-align middle | ||
153 | margin-top -1px | ||
154 | margin-left 0.4rem | ||
155 | .mobile-dropdown-title | ||
156 | @extends .dropdown-title | ||
157 | display none | ||
158 | font-weight 600 | ||
159 | font-size inherit | ||
160 | &:hover | ||
161 | color $accentColor | ||
162 | .nav-dropdown | ||
163 | .dropdown-item | ||
164 | color inherit | ||
165 | line-height 1.7rem | ||
166 | h4 | ||
167 | margin 0.45rem 0 0 | ||
168 | border-top 1px solid #eee | ||
169 | padding 1rem 1.5rem 0.45rem 1.25rem | ||
170 | .dropdown-subitem-wrapper | ||
171 | padding 0 | ||
172 | list-style none | ||
173 | .dropdown-subitem | ||
174 | font-size 0.9em | ||
175 | a | ||
176 | display block | ||
177 | line-height 1.7rem | ||
178 | position relative | ||
179 | border-bottom none | ||
180 | font-weight 400 | ||
181 | margin-bottom 0 | ||
182 | padding 0 1.5rem 0 1.25rem | ||
183 | &:hover | ||
184 | color $accentColor | ||
185 | &.router-link-active | ||
186 | color $accentColor | ||
187 | &::after | ||
188 | content "" | ||
189 | width 0 | ||
190 | height 0 | ||
191 | border-left 5px solid $accentColor | ||
192 | border-top 3px solid transparent | ||
193 | border-bottom 3px solid transparent | ||
194 | position absolute | ||
195 | top calc(50% - 2px) | ||
196 | left 9px | ||
197 | &:first-child h4 | ||
198 | margin-top 0 | ||
199 | padding-top 0 | ||
200 | border-top 0 | ||
201 | |||
202 | @media (max-width: $MQMobile) | ||
203 | .dropdown-wrapper | ||
204 | &.open .dropdown-title | ||
205 | margin-bottom 0.5rem | ||
206 | .dropdown-title | ||
207 | display: none | ||
208 | .mobile-dropdown-title | ||
209 | display: block | ||
210 | .nav-dropdown | ||
211 | transition height .1s ease-out | ||
212 | overflow hidden | ||
213 | .dropdown-item | ||
214 | h4 | ||
215 | border-top 0 | ||
216 | margin-top 0 | ||
217 | padding-top 0 | ||
218 | h4, & > a | ||
219 | font-size 15px | ||
220 | line-height 2rem | ||
221 | .dropdown-subitem | ||
222 | font-size 14px | ||
223 | padding-left 1rem | ||
224 | |||
225 | @media (min-width: $MQMobile) | ||
226 | .dropdown-wrapper | ||
227 | height 1.8rem | ||
228 | &:hover .nav-dropdown, | ||
229 | &.open .nav-dropdown | ||
230 | // override the inline style. | ||
231 | display block !important | ||
232 | &.open:blur | ||
233 | display none | ||
234 | .nav-dropdown | ||
235 | display none | ||
236 | // Avoid height shaked by clicking | ||
237 | height auto !important | ||
238 | box-sizing border-box; | ||
239 | max-height calc(100vh - 2.7rem) | ||
240 | overflow-y auto | ||
241 | position absolute | ||
242 | top 100% | ||
243 | right 0 | ||
244 | background-color #fff | ||
245 | padding 0.6rem 0 | ||
246 | border 1px solid #ddd | ||
247 | border-bottom-color #ccc | ||
248 | text-align left | ||
249 | border-radius 0.25rem | ||
250 | white-space nowrap | ||
251 | margin 0 | ||
252 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/DropdownTransition.vue b/doc/docs/.vuepress/theme/components/DropdownTransition.vue new file mode 100644 index 0000000..eeaf12b --- /dev/null +++ b/doc/docs/.vuepress/theme/components/DropdownTransition.vue | |||
@@ -0,0 +1,33 @@ | |||
1 | <template> | ||
2 | <transition | ||
3 | name="dropdown" | ||
4 | @enter="setHeight" | ||
5 | @after-enter="unsetHeight" | ||
6 | @before-leave="setHeight" | ||
7 | > | ||
8 | <slot /> | ||
9 | </transition> | ||
10 | </template> | ||
11 | |||
12 | <script> | ||
13 | export default { | ||
14 | name: 'DropdownTransition', | ||
15 | |||
16 | methods: { | ||
17 | setHeight (items) { | ||
18 | // explicitly set height so that it can be transitioned | ||
19 | items.style.height = items.scrollHeight + 'px' | ||
20 | }, | ||
21 | |||
22 | unsetHeight (items) { | ||
23 | items.style.height = '' | ||
24 | } | ||
25 | } | ||
26 | } | ||
27 | </script> | ||
28 | |||
29 | <style lang="stylus"> | ||
30 | .dropdown-enter, .dropdown-leave-to | ||
31 | height 0 !important | ||
32 | |||
33 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/Home.vue b/doc/docs/.vuepress/theme/components/Home.vue new file mode 100644 index 0000000..acd8744 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/Home.vue | |||
@@ -0,0 +1,175 @@ | |||
1 | <template> | ||
2 | <main | ||
3 | class="home" | ||
4 | :aria-labelledby="data.heroText !== null ? 'main-title' : null" | ||
5 | > | ||
6 | <header class="hero"> | ||
7 | <img | ||
8 | v-if="data.heroImage" | ||
9 | :src="$withBase(data.heroImage)" | ||
10 | :alt="data.heroAlt || 'hero'" | ||
11 | > | ||
12 | |||
13 | <h1 | ||
14 | v-if="data.heroText !== null" | ||
15 | id="main-title" | ||
16 | > | ||
17 | {{ data.heroText || $title || 'Hello' }} | ||
18 | </h1> | ||
19 | |||
20 | <p | ||
21 | v-if="data.tagline !== null" | ||
22 | class="description" | ||
23 | > | ||
24 | {{ data.tagline || $description || 'Welcome to your VuePress site' }} | ||
25 | </p> | ||
26 | |||
27 | <p | ||
28 | v-if="data.actionText && data.actionLink" | ||
29 | class="action" | ||
30 | > | ||
31 | <NavLink | ||
32 | class="action-button" | ||
33 | :item="actionLink" | ||
34 | /> | ||
35 | </p> | ||
36 | </header> | ||
37 | |||
38 | <div | ||
39 | v-if="data.features && data.features.length" | ||
40 | class="features" | ||
41 | > | ||
42 | <div | ||
43 | v-for="(feature, index) in data.features" | ||
44 | :key="index" | ||
45 | class="feature" | ||
46 | > | ||
47 | <h2>{{ feature.title }}</h2> | ||
48 | <p>{{ feature.details }}</p> | ||
49 | </div> | ||
50 | </div> | ||
51 | |||
52 | <Content class="theme-default-content custom" /> | ||
53 | |||
54 | <div | ||
55 | v-if="data.footer" | ||
56 | class="footer" | ||
57 | > | ||
58 | {{ data.footer }} | ||
59 | </div> | ||
60 | </main> | ||
61 | </template> | ||
62 | |||
63 | <script> | ||
64 | import NavLink from '@theme/components/NavLink.vue' | ||
65 | |||
66 | export default { | ||
67 | name: 'Home', | ||
68 | |||
69 | components: { NavLink }, | ||
70 | |||
71 | computed: { | ||
72 | data () { | ||
73 | return this.$page.frontmatter | ||
74 | }, | ||
75 | |||
76 | actionLink () { | ||
77 | return { | ||
78 | link: this.data.actionLink, | ||
79 | text: this.data.actionText | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | </script> | ||
85 | |||
86 | <style lang="stylus"> | ||
87 | .home | ||
88 | padding $navbarHeight 2rem 0 | ||
89 | max-width $homePageWidth | ||
90 | margin 0px auto | ||
91 | display block | ||
92 | .hero | ||
93 | text-align center | ||
94 | img | ||
95 | max-width: 100% | ||
96 | max-height 280px | ||
97 | display block | ||
98 | margin 3rem auto 1.5rem | ||
99 | h1 | ||
100 | font-size 3rem | ||
101 | h1, .description, .action | ||
102 | margin 1.8rem auto | ||
103 | .description | ||
104 | max-width 35rem | ||
105 | font-size 1.6rem | ||
106 | line-height 1.3 | ||
107 | color lighten($textColor, 40%) | ||
108 | .action-button | ||
109 | display inline-block | ||
110 | font-size 1.2rem | ||
111 | color #fff | ||
112 | background-color $accentColor | ||
113 | padding 0.8rem 1.6rem | ||
114 | border-radius 4px | ||
115 | transition background-color .1s ease | ||
116 | box-sizing border-box | ||
117 | border-bottom 1px solid darken($accentColor, 10%) | ||
118 | &:hover | ||
119 | background-color lighten($accentColor, 10%) | ||
120 | .features | ||
121 | border-top 1px solid $borderColor | ||
122 | padding 1.2rem 0 | ||
123 | margin-top 2.5rem | ||
124 | display flex | ||
125 | flex-wrap wrap | ||
126 | align-items flex-start | ||
127 | align-content stretch | ||
128 | justify-content space-between | ||
129 | .feature | ||
130 | flex-grow 1 | ||
131 | flex-basis 30% | ||
132 | max-width 30% | ||
133 | h2 | ||
134 | font-size 1.4rem | ||
135 | font-weight 500 | ||
136 | border-bottom none | ||
137 | padding-bottom 0 | ||
138 | color lighten($textColor, 10%) | ||
139 | p | ||
140 | color lighten($textColor, 25%) | ||
141 | .footer | ||
142 | padding 2.5rem | ||
143 | border-top 1px solid $borderColor | ||
144 | text-align center | ||
145 | color lighten($textColor, 25%) | ||
146 | |||
147 | @media (max-width: $MQMobile) | ||
148 | .home | ||
149 | .features | ||
150 | flex-direction column | ||
151 | .feature | ||
152 | max-width 100% | ||
153 | padding 0 2.5rem | ||
154 | |||
155 | @media (max-width: $MQMobileNarrow) | ||
156 | .home | ||
157 | padding-left 1.5rem | ||
158 | padding-right 1.5rem | ||
159 | .hero | ||
160 | img | ||
161 | max-height 210px | ||
162 | margin 2rem auto 1.2rem | ||
163 | h1 | ||
164 | font-size 2rem | ||
165 | h1, .description, .action | ||
166 | margin 1.2rem auto | ||
167 | .description | ||
168 | font-size 1.2rem | ||
169 | .action-button | ||
170 | font-size 1rem | ||
171 | padding 0.6rem 1.2rem | ||
172 | .feature | ||
173 | h2 | ||
174 | font-size 1.25rem | ||
175 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/NavLink.vue b/doc/docs/.vuepress/theme/components/NavLink.vue new file mode 100644 index 0000000..f7e65a4 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/NavLink.vue | |||
@@ -0,0 +1,90 @@ | |||
1 | <template> | ||
2 | <RouterLink | ||
3 | v-if="isInternal" | ||
4 | class="nav-link" | ||
5 | :to="link" | ||
6 | :exact="exact" | ||
7 | @focusout.native="focusoutAction" | ||
8 | > | ||
9 | {{ item.text }} | ||
10 | </RouterLink> | ||
11 | <a | ||
12 | v-else | ||
13 | :href="link" | ||
14 | class="nav-link external" | ||
15 | :target="target" | ||
16 | :rel="rel" | ||
17 | @focusout="focusoutAction" | ||
18 | > | ||
19 | {{ item.text }} | ||
20 | <OutboundLink v-if="isBlankTarget" /> | ||
21 | </a> | ||
22 | </template> | ||
23 | |||
24 | <script> | ||
25 | import { isExternal, isMailto, isTel, ensureExt } from '../util' | ||
26 | |||
27 | export default { | ||
28 | name: 'NavLink', | ||
29 | |||
30 | props: { | ||
31 | item: { | ||
32 | required: true | ||
33 | } | ||
34 | }, | ||
35 | |||
36 | computed: { | ||
37 | link () { | ||
38 | return ensureExt(this.item.link) | ||
39 | }, | ||
40 | |||
41 | exact () { | ||
42 | if (this.$site.locales) { | ||
43 | return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link) | ||
44 | } | ||
45 | return this.link === '/' | ||
46 | }, | ||
47 | |||
48 | isNonHttpURI () { | ||
49 | return isMailto(this.link) || isTel(this.link) | ||
50 | }, | ||
51 | |||
52 | isBlankTarget () { | ||
53 | return this.target === '_blank' | ||
54 | }, | ||
55 | |||
56 | isInternal () { | ||
57 | return !isExternal(this.link) && !this.isBlankTarget | ||
58 | }, | ||
59 | |||
60 | target () { | ||
61 | if (this.isNonHttpURI) { | ||
62 | return null | ||
63 | } | ||
64 | if (this.item.target) { | ||
65 | return this.item.target | ||
66 | } | ||
67 | return isExternal(this.link) ? '_blank' : '' | ||
68 | }, | ||
69 | |||
70 | rel () { | ||
71 | if (this.isNonHttpURI) { | ||
72 | return null | ||
73 | } | ||
74 | if (this.item.rel === false) { | ||
75 | return null | ||
76 | } | ||
77 | if (this.item.rel) { | ||
78 | return this.item.rel | ||
79 | } | ||
80 | return this.isBlankTarget ? 'noopener noreferrer' : null | ||
81 | } | ||
82 | }, | ||
83 | |||
84 | methods: { | ||
85 | focusoutAction () { | ||
86 | this.$emit('focusout') | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | </script> | ||
diff --git a/doc/docs/.vuepress/theme/components/NavLinks.vue b/doc/docs/.vuepress/theme/components/NavLinks.vue new file mode 100644 index 0000000..2656ae2 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/NavLinks.vue | |||
@@ -0,0 +1,156 @@ | |||
1 | <template> | ||
2 | <nav | ||
3 | v-if="userLinks.length || repoLink" | ||
4 | class="nav-links" | ||
5 | > | ||
6 | <!-- user links --> | ||
7 | <div | ||
8 | v-for="item in userLinks" | ||
9 | :key="item.link" | ||
10 | class="nav-item" | ||
11 | > | ||
12 | <DropdownLink | ||
13 | v-if="item.type === 'links'" | ||
14 | :item="item" | ||
15 | /> | ||
16 | <NavLink | ||
17 | v-else | ||
18 | :item="item" | ||
19 | /> | ||
20 | </div> | ||
21 | |||
22 | <!-- repo link --> | ||
23 | <a | ||
24 | v-if="repoLink" | ||
25 | :href="repoLink" | ||
26 | class="repo-link" | ||
27 | target="_blank" | ||
28 | rel="noopener noreferrer" | ||
29 | > | ||
30 | {{ repoLabel }} | ||
31 | <OutboundLink /> | ||
32 | </a> | ||
33 | </nav> | ||
34 | </template> | ||
35 | |||
36 | <script> | ||
37 | import DropdownLink from '@theme/components/DropdownLink.vue' | ||
38 | import { resolveNavLinkItem } from '../util' | ||
39 | import NavLink from '@theme/components/NavLink.vue' | ||
40 | |||
41 | export default { | ||
42 | name: 'NavLinks', | ||
43 | |||
44 | components: { | ||
45 | NavLink, | ||
46 | DropdownLink | ||
47 | }, | ||
48 | |||
49 | computed: { | ||
50 | userNav () { | ||
51 | return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || [] | ||
52 | }, | ||
53 | |||
54 | nav () { | ||
55 | const { locales } = this.$site | ||
56 | if (locales && Object.keys(locales).length > 1) { | ||
57 | const currentLink = this.$page.path | ||
58 | const routes = this.$router.options.routes | ||
59 | const themeLocales = this.$site.themeConfig.locales || {} | ||
60 | const languageDropdown = { | ||
61 | text: this.$themeLocaleConfig.selectText || 'Languages', | ||
62 | ariaLabel: this.$themeLocaleConfig.ariaLabel || 'Select language', | ||
63 | items: Object.keys(locales).map(path => { | ||
64 | const locale = locales[path] | ||
65 | const text = themeLocales[path] && themeLocales[path].label || locale.lang | ||
66 | let link | ||
67 | // Stay on the current page | ||
68 | if (locale.lang === this.$lang) { | ||
69 | link = currentLink | ||
70 | } else { | ||
71 | // Try to stay on the same page | ||
72 | link = currentLink.replace(this.$localeConfig.path, path) | ||
73 | // fallback to homepage | ||
74 | if (!routes.some(route => route.path === link)) { | ||
75 | link = path | ||
76 | } | ||
77 | } | ||
78 | return { text, link } | ||
79 | }) | ||
80 | } | ||
81 | return [...this.userNav, languageDropdown] | ||
82 | } | ||
83 | return this.userNav | ||
84 | }, | ||
85 | |||
86 | userLinks () { | ||
87 | return (this.nav || []).map(link => { | ||
88 | return Object.assign(resolveNavLinkItem(link), { | ||
89 | items: (link.items || []).map(resolveNavLinkItem) | ||
90 | }) | ||
91 | }) | ||
92 | }, | ||
93 | |||
94 | repoLink () { | ||
95 | const { repo } = this.$site.themeConfig | ||
96 | if (repo) { | ||
97 | return /^https?:/.test(repo) | ||
98 | ? repo | ||
99 | : `https://github.com/${repo}` | ||
100 | } | ||
101 | return null | ||
102 | }, | ||
103 | |||
104 | repoLabel () { | ||
105 | if (!this.repoLink) return | ||
106 | if (this.$site.themeConfig.repoLabel) { | ||
107 | return this.$site.themeConfig.repoLabel | ||
108 | } | ||
109 | |||
110 | const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0] | ||
111 | const platforms = ['GitHub', 'GitLab', 'Bitbucket'] | ||
112 | for (let i = 0; i < platforms.length; i++) { | ||
113 | const platform = platforms[i] | ||
114 | if (new RegExp(platform, 'i').test(repoHost)) { | ||
115 | return platform | ||
116 | } | ||
117 | } | ||
118 | |||
119 | return 'Source' | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | </script> | ||
124 | |||
125 | <style lang="stylus"> | ||
126 | .nav-links | ||
127 | display inline-block | ||
128 | a | ||
129 | line-height 1.4rem | ||
130 | color inherit | ||
131 | &:hover, &.router-link-active | ||
132 | color $accentColor | ||
133 | .nav-item | ||
134 | position relative | ||
135 | display inline-block | ||
136 | margin-left 1.5rem | ||
137 | line-height 2rem | ||
138 | &:first-child | ||
139 | margin-left 0 | ||
140 | .repo-link | ||
141 | margin-left 1.5rem | ||
142 | |||
143 | @media (max-width: $MQMobile) | ||
144 | .nav-links | ||
145 | .nav-item, .repo-link | ||
146 | margin-left 0 | ||
147 | |||
148 | @media (min-width: $MQMobile) | ||
149 | .nav-links a | ||
150 | &:hover, &.router-link-active | ||
151 | color $textColor | ||
152 | .nav-item > a:not(.external) | ||
153 | &:hover, &.router-link-active | ||
154 | margin-bottom -2px | ||
155 | border-bottom 2px solid lighten($accentColor, 8%) | ||
156 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/Navbar.vue b/doc/docs/.vuepress/theme/components/Navbar.vue new file mode 100644 index 0000000..f8dd49c --- /dev/null +++ b/doc/docs/.vuepress/theme/components/Navbar.vue | |||
@@ -0,0 +1,140 @@ | |||
1 | <template> | ||
2 | <header class="navbar"> | ||
3 | <SidebarButton @toggle-sidebar="$emit('toggle-sidebar')" /> | ||
4 | |||
5 | <RouterLink | ||
6 | :to="$localePath" | ||
7 | class="home-link" | ||
8 | > | ||
9 | <img | ||
10 | v-if="$site.themeConfig.logo" | ||
11 | class="logo" | ||
12 | :src="$withBase($site.themeConfig.logo)" | ||
13 | :alt="$siteTitle" | ||
14 | > | ||
15 | <span | ||
16 | v-if="$siteTitle" | ||
17 | ref="siteName" | ||
18 | class="site-name" | ||
19 | :class="{ 'can-hide': $site.themeConfig.logo }" | ||
20 | >{{ $siteTitle }}</span> | ||
21 | </RouterLink> | ||
22 | |||
23 | <div | ||
24 | class="links" | ||
25 | :style="linksWrapMaxWidth ? { | ||
26 | 'max-width': linksWrapMaxWidth + 'px' | ||
27 | } : {}" | ||
28 | > | ||
29 | <AlgoliaSearchBox | ||
30 | v-if="isAlgoliaSearch" | ||
31 | :options="algolia" | ||
32 | /> | ||
33 | <SearchBox v-else-if="$site.themeConfig.search !== false && $page.frontmatter.search !== false" /> | ||
34 | <NavLinks class="can-hide" /> | ||
35 | </div> | ||
36 | </header> | ||
37 | </template> | ||
38 | |||
39 | <script> | ||
40 | import AlgoliaSearchBox from '@AlgoliaSearchBox' | ||
41 | import SearchBox from '@SearchBox' | ||
42 | import SidebarButton from '@theme/components/SidebarButton.vue' | ||
43 | import NavLinks from '@theme/components/NavLinks.vue' | ||
44 | |||
45 | export default { | ||
46 | name: 'Navbar', | ||
47 | |||
48 | components: { | ||
49 | SidebarButton, | ||
50 | NavLinks, | ||
51 | SearchBox, | ||
52 | AlgoliaSearchBox | ||
53 | }, | ||
54 | |||
55 | data () { | ||
56 | return { | ||
57 | linksWrapMaxWidth: null | ||
58 | } | ||
59 | }, | ||
60 | |||
61 | computed: { | ||
62 | algolia () { | ||
63 | return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {} | ||
64 | }, | ||
65 | |||
66 | isAlgoliaSearch () { | ||
67 | return this.algolia && this.algolia.apiKey && this.algolia.indexName | ||
68 | } | ||
69 | }, | ||
70 | |||
71 | mounted () { | ||
72 | const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl | ||
73 | const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight')) | ||
74 | const handleLinksWrapWidth = () => { | ||
75 | if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) { | ||
76 | this.linksWrapMaxWidth = null | ||
77 | } else { | ||
78 | this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING | ||
79 | - (this.$refs.siteName && this.$refs.siteName.offsetWidth || 0) | ||
80 | } | ||
81 | } | ||
82 | handleLinksWrapWidth() | ||
83 | window.addEventListener('resize', handleLinksWrapWidth, false) | ||
84 | } | ||
85 | } | ||
86 | |||
87 | function css (el, property) { | ||
88 | // NOTE: Known bug, will return 'auto' if style value is 'auto' | ||
89 | const win = el.ownerDocument.defaultView | ||
90 | // null means not to return pseudo styles | ||
91 | return win.getComputedStyle(el, null)[property] | ||
92 | } | ||
93 | </script> | ||
94 | |||
95 | <style lang="stylus"> | ||
96 | $navbar-vertical-padding = 0.7rem | ||
97 | $navbar-horizontal-padding = 1.5rem | ||
98 | |||
99 | .navbar | ||
100 | padding $navbar-vertical-padding $navbar-horizontal-padding | ||
101 | line-height $navbarHeight - 1.4rem | ||
102 | a, span, img | ||
103 | display inline-block | ||
104 | .logo | ||
105 | height $navbarHeight - 1.4rem | ||
106 | min-width $navbarHeight - 1.4rem | ||
107 | margin-right 0.8rem | ||
108 | vertical-align top | ||
109 | .site-name | ||
110 | font-size 1.3rem | ||
111 | font-weight 600 | ||
112 | color $textColor | ||
113 | position relative | ||
114 | .links | ||
115 | padding-left 1.5rem | ||
116 | box-sizing border-box | ||
117 | background-color white | ||
118 | white-space nowrap | ||
119 | font-size 0.9rem | ||
120 | position absolute | ||
121 | right $navbar-horizontal-padding | ||
122 | top $navbar-vertical-padding | ||
123 | display flex | ||
124 | .search-box | ||
125 | flex: 0 0 auto | ||
126 | vertical-align top | ||
127 | |||
128 | @media (max-width: $MQMobile) | ||
129 | .navbar | ||
130 | padding-left 4rem | ||
131 | .can-hide | ||
132 | display none | ||
133 | .links | ||
134 | padding-left 1.5rem | ||
135 | .site-name | ||
136 | width calc(100vw - 9.4rem) | ||
137 | overflow hidden | ||
138 | white-space nowrap | ||
139 | text-overflow ellipsis | ||
140 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/Page.vue b/doc/docs/.vuepress/theme/components/Page.vue new file mode 100644 index 0000000..04ec7cb --- /dev/null +++ b/doc/docs/.vuepress/theme/components/Page.vue | |||
@@ -0,0 +1,31 @@ | |||
1 | <template> | ||
2 | <main class="page"> | ||
3 | <slot name="top" /> | ||
4 | |||
5 | <Content class="theme-default-content" /> | ||
6 | <PageEdit /> | ||
7 | |||
8 | <PageNav v-bind="{ sidebarItems }" /> | ||
9 | |||
10 | <slot name="bottom" /> | ||
11 | </main> | ||
12 | </template> | ||
13 | |||
14 | <script> | ||
15 | import PageEdit from '@theme/components/PageEdit.vue' | ||
16 | import PageNav from '@theme/components/PageNav.vue' | ||
17 | |||
18 | export default { | ||
19 | components: { PageEdit, PageNav }, | ||
20 | props: ['sidebarItems'] | ||
21 | } | ||
22 | </script> | ||
23 | |||
24 | <style lang="stylus"> | ||
25 | @require '../styles/wrapper.styl' | ||
26 | |||
27 | .page | ||
28 | padding-bottom 2rem | ||
29 | display block | ||
30 | |||
31 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/PageEdit.vue b/doc/docs/.vuepress/theme/components/PageEdit.vue new file mode 100644 index 0000000..cf9b2d2 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/PageEdit.vue | |||
@@ -0,0 +1,155 @@ | |||
1 | <template> | ||
2 | <footer class="page-edit"> | ||
3 | <div | ||
4 | v-if="editLink" | ||
5 | class="edit-link" | ||
6 | > | ||
7 | <a | ||
8 | :href="editLink" | ||
9 | target="_blank" | ||
10 | rel="noopener noreferrer" | ||
11 | >{{ editLinkText }}</a> | ||
12 | <OutboundLink /> | ||
13 | </div> | ||
14 | |||
15 | <div | ||
16 | v-if="lastUpdated" | ||
17 | class="last-updated" | ||
18 | > | ||
19 | <span class="prefix">{{ lastUpdatedText }}:</span> | ||
20 | <span class="time">{{ lastUpdated }}</span> | ||
21 | </div> | ||
22 | </footer> | ||
23 | </template> | ||
24 | |||
25 | <script> | ||
26 | import isNil from 'lodash/isNil' | ||
27 | import { endingSlashRE, outboundRE } from '../util' | ||
28 | |||
29 | export default { | ||
30 | name: 'PageEdit', | ||
31 | |||
32 | computed: { | ||
33 | lastUpdated () { | ||
34 | return this.$page.lastUpdated | ||
35 | }, | ||
36 | |||
37 | lastUpdatedText () { | ||
38 | if (typeof this.$themeLocaleConfig.lastUpdated === 'string') { | ||
39 | return this.$themeLocaleConfig.lastUpdated | ||
40 | } | ||
41 | if (typeof this.$site.themeConfig.lastUpdated === 'string') { | ||
42 | return this.$site.themeConfig.lastUpdated | ||
43 | } | ||
44 | return 'Last Updated' | ||
45 | }, | ||
46 | |||
47 | editLink () { | ||
48 | const showEditLink = isNil(this.$page.frontmatter.editLink) | ||
49 | ? this.$site.themeConfig.editLinks | ||
50 | : this.$page.frontmatter.editLink | ||
51 | |||
52 | const { | ||
53 | repo, | ||
54 | docsDir = '', | ||
55 | docsBranch = 'master', | ||
56 | docsRepo = repo | ||
57 | } = this.$site.themeConfig | ||
58 | |||
59 | if (showEditLink && docsRepo && this.$page.relativePath) { | ||
60 | return this.createEditLink( | ||
61 | repo, | ||
62 | docsRepo, | ||
63 | docsDir, | ||
64 | docsBranch, | ||
65 | this.$page.relativePath | ||
66 | ) | ||
67 | } | ||
68 | return null | ||
69 | }, | ||
70 | |||
71 | editLinkText () { | ||
72 | return ( | ||
73 | this.$themeLocaleConfig.editLinkText | ||
74 | || this.$site.themeConfig.editLinkText | ||
75 | || `Edit this page` | ||
76 | ) | ||
77 | } | ||
78 | }, | ||
79 | |||
80 | methods: { | ||
81 | createEditLink (repo, docsRepo, docsDir, docsBranch, path) { | ||
82 | const bitbucket = /bitbucket.org/ | ||
83 | if (bitbucket.test(docsRepo)) { | ||
84 | const base = docsRepo | ||
85 | return ( | ||
86 | base.replace(endingSlashRE, '') | ||
87 | + `/src` | ||
88 | + `/${docsBranch}/` | ||
89 | + (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') | ||
90 | + path | ||
91 | + `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default` | ||
92 | ) | ||
93 | } | ||
94 | |||
95 | const gitlab = /gitlab.com/ | ||
96 | if (gitlab.test(docsRepo)) { | ||
97 | const base = docsRepo | ||
98 | return ( | ||
99 | base.replace(endingSlashRE, '') | ||
100 | + `/-/edit` | ||
101 | + `/${docsBranch}/` | ||
102 | + (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') | ||
103 | + path | ||
104 | ) | ||
105 | } | ||
106 | |||
107 | const base = outboundRE.test(docsRepo) | ||
108 | ? docsRepo | ||
109 | : `https://github.com/${docsRepo}` | ||
110 | return ( | ||
111 | base.replace(endingSlashRE, '') | ||
112 | + '/edit' | ||
113 | + `/${docsBranch}/` | ||
114 | + (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') | ||
115 | + path | ||
116 | ) | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | </script> | ||
121 | |||
122 | <style lang="stylus"> | ||
123 | @require '../styles/wrapper.styl' | ||
124 | |||
125 | .page-edit | ||
126 | @extend $wrapper | ||
127 | padding-top 1rem | ||
128 | padding-bottom 1rem | ||
129 | overflow auto | ||
130 | |||
131 | .edit-link | ||
132 | display inline-block | ||
133 | a | ||
134 | color lighten($textColor, 25%) | ||
135 | margin-right 0.25rem | ||
136 | .last-updated | ||
137 | float right | ||
138 | font-size 0.9em | ||
139 | .prefix | ||
140 | font-weight 500 | ||
141 | color lighten($textColor, 25%) | ||
142 | .time | ||
143 | font-weight 400 | ||
144 | color #767676 | ||
145 | |||
146 | @media (max-width: $MQMobile) | ||
147 | .page-edit | ||
148 | .edit-link | ||
149 | margin-bottom 0.5rem | ||
150 | .last-updated | ||
151 | font-size 0.8em | ||
152 | float none | ||
153 | text-align left | ||
154 | |||
155 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/PageNav.vue b/doc/docs/.vuepress/theme/components/PageNav.vue new file mode 100644 index 0000000..4c19aae --- /dev/null +++ b/doc/docs/.vuepress/theme/components/PageNav.vue | |||
@@ -0,0 +1,163 @@ | |||
1 | <template> | ||
2 | <div | ||
3 | v-if="prev || next" | ||
4 | class="page-nav" | ||
5 | > | ||
6 | <p class="inner"> | ||
7 | <span | ||
8 | v-if="prev" | ||
9 | class="prev" | ||
10 | > | ||
11 | ← | ||
12 | <a | ||
13 | v-if="prev.type === 'external'" | ||
14 | class="prev" | ||
15 | :href="prev.path" | ||
16 | target="_blank" | ||
17 | rel="noopener noreferrer" | ||
18 | > | ||
19 | {{ prev.title || prev.path }} | ||
20 | |||
21 | <OutboundLink /> | ||
22 | </a> | ||
23 | |||
24 | <RouterLink | ||
25 | v-else | ||
26 | class="prev" | ||
27 | :to="prev.path" | ||
28 | > | ||
29 | {{ prev.title || prev.path }} | ||
30 | </RouterLink> | ||
31 | </span> | ||
32 | |||
33 | <span | ||
34 | v-if="next" | ||
35 | class="next" | ||
36 | > | ||
37 | <a | ||
38 | v-if="next.type === 'external'" | ||
39 | :href="next.path" | ||
40 | target="_blank" | ||
41 | rel="noopener noreferrer" | ||
42 | > | ||
43 | {{ next.title || next.path }} | ||
44 | |||
45 | <OutboundLink /> | ||
46 | </a> | ||
47 | |||
48 | <RouterLink | ||
49 | v-else | ||
50 | :to="next.path" | ||
51 | > | ||
52 | {{ next.title || next.path }} | ||
53 | </RouterLink> | ||
54 | → | ||
55 | </span> | ||
56 | </p> | ||
57 | </div> | ||
58 | </template> | ||
59 | |||
60 | <script> | ||
61 | import { resolvePage } from '../util' | ||
62 | import isString from 'lodash/isString' | ||
63 | import isNil from 'lodash/isNil' | ||
64 | |||
65 | export default { | ||
66 | name: 'PageNav', | ||
67 | |||
68 | props: ['sidebarItems'], | ||
69 | |||
70 | computed: { | ||
71 | prev () { | ||
72 | return resolvePageLink(LINK_TYPES.PREV, this) | ||
73 | }, | ||
74 | |||
75 | next () { | ||
76 | return resolvePageLink(LINK_TYPES.NEXT, this) | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | function resolvePrev (page, items) { | ||
82 | return find(page, items, -1) | ||
83 | } | ||
84 | |||
85 | function resolveNext (page, items) { | ||
86 | return find(page, items, 1) | ||
87 | } | ||
88 | |||
89 | const LINK_TYPES = { | ||
90 | NEXT: { | ||
91 | resolveLink: resolveNext, | ||
92 | getThemeLinkConfig: ({ nextLinks }) => nextLinks, | ||
93 | getPageLinkConfig: ({ frontmatter }) => frontmatter.next | ||
94 | }, | ||
95 | PREV: { | ||
96 | resolveLink: resolvePrev, | ||
97 | getThemeLinkConfig: ({ prevLinks }) => prevLinks, | ||
98 | getPageLinkConfig: ({ frontmatter }) => frontmatter.prev | ||
99 | } | ||
100 | } | ||
101 | |||
102 | function resolvePageLink ( | ||
103 | linkType, | ||
104 | { $themeConfig, $page, $route, $site, sidebarItems } | ||
105 | ) { | ||
106 | const { resolveLink, getThemeLinkConfig, getPageLinkConfig } = linkType | ||
107 | |||
108 | // Get link config from theme | ||
109 | const themeLinkConfig = getThemeLinkConfig($themeConfig) | ||
110 | |||
111 | // Get link config from current page | ||
112 | const pageLinkConfig = getPageLinkConfig($page) | ||
113 | |||
114 | // Page link config will overwrite global theme link config if defined | ||
115 | const link = isNil(pageLinkConfig) ? themeLinkConfig : pageLinkConfig | ||
116 | |||
117 | if (link === false) { | ||
118 | return | ||
119 | } else if (isString(link)) { | ||
120 | return resolvePage($site.pages, link, $route.path) | ||
121 | } else { | ||
122 | return resolveLink($page, sidebarItems) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | function find (page, items, offset) { | ||
127 | const res = [] | ||
128 | flatten(items, res) | ||
129 | for (let i = 0; i < res.length; i++) { | ||
130 | const cur = res[i] | ||
131 | if (cur.type === 'page' && cur.path === decodeURIComponent(page.path)) { | ||
132 | return res[i + offset] | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | function flatten (items, res) { | ||
138 | for (let i = 0, l = items.length; i < l; i++) { | ||
139 | if (items[i].type === 'group') { | ||
140 | flatten(items[i].children || [], res) | ||
141 | } else { | ||
142 | res.push(items[i]) | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | </script> | ||
147 | |||
148 | <style lang="stylus"> | ||
149 | @require '../styles/wrapper.styl' | ||
150 | |||
151 | .page-nav | ||
152 | @extend $wrapper | ||
153 | padding-top 1rem | ||
154 | padding-bottom 0 | ||
155 | .inner | ||
156 | min-height 2rem | ||
157 | margin-top 0 | ||
158 | border-top 1px solid $borderColor | ||
159 | padding-top 1rem | ||
160 | overflow auto // clear float | ||
161 | .next | ||
162 | float right | ||
163 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/Sidebar.vue b/doc/docs/.vuepress/theme/components/Sidebar.vue new file mode 100644 index 0000000..e70e333 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/Sidebar.vue | |||
@@ -0,0 +1,64 @@ | |||
1 | <template> | ||
2 | <aside class="sidebar"> | ||
3 | <NavLinks /> | ||
4 | |||
5 | <slot name="top" /> | ||
6 | |||
7 | <SidebarLinks | ||
8 | :depth="0" | ||
9 | :items="items" | ||
10 | /> | ||
11 | <slot name="bottom" /> | ||
12 | </aside> | ||
13 | </template> | ||
14 | |||
15 | <script> | ||
16 | import SidebarLinks from '@theme/components/SidebarLinks.vue' | ||
17 | import NavLinks from '@theme/components/NavLinks.vue' | ||
18 | |||
19 | export default { | ||
20 | name: 'Sidebar', | ||
21 | |||
22 | components: { SidebarLinks, NavLinks }, | ||
23 | |||
24 | props: ['items'] | ||
25 | } | ||
26 | </script> | ||
27 | |||
28 | <style lang="stylus"> | ||
29 | .sidebar | ||
30 | ul | ||
31 | padding 0 | ||
32 | margin 0 | ||
33 | list-style-type none | ||
34 | a | ||
35 | display inline-block | ||
36 | .nav-links | ||
37 | display none | ||
38 | border-bottom 1px solid $borderColor | ||
39 | padding 0.5rem 0 0.75rem 0 | ||
40 | a | ||
41 | font-weight 600 | ||
42 | .nav-item, .repo-link | ||
43 | display block | ||
44 | line-height 1.25rem | ||
45 | font-size 1.1em | ||
46 | padding 0.5rem 0 0.5rem 1.5rem | ||
47 | & > .sidebar-links | ||
48 | padding 1.5rem 0 | ||
49 | & > li > a.sidebar-link | ||
50 | font-size 1.1em | ||
51 | line-height 1.7 | ||
52 | font-weight bold | ||
53 | & > li:not(:first-child) | ||
54 | margin-top .75rem | ||
55 | |||
56 | @media (max-width: $MQMobile) | ||
57 | .sidebar | ||
58 | .nav-links | ||
59 | display block | ||
60 | .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after | ||
61 | top calc(1rem - 2px) | ||
62 | & > .sidebar-links | ||
63 | padding 1rem 0 | ||
64 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/SidebarButton.vue b/doc/docs/.vuepress/theme/components/SidebarButton.vue new file mode 100644 index 0000000..3f54afd --- /dev/null +++ b/doc/docs/.vuepress/theme/components/SidebarButton.vue | |||
@@ -0,0 +1,40 @@ | |||
1 | <template> | ||
2 | <div | ||
3 | class="sidebar-button" | ||
4 | @click="$emit('toggle-sidebar')" | ||
5 | > | ||
6 | <svg | ||
7 | class="icon" | ||
8 | xmlns="http://www.w3.org/2000/svg" | ||
9 | aria-hidden="true" | ||
10 | role="img" | ||
11 | viewBox="0 0 448 512" | ||
12 | > | ||
13 | <path | ||
14 | fill="currentColor" | ||
15 | d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z" | ||
16 | class="" | ||
17 | /> | ||
18 | </svg> | ||
19 | </div> | ||
20 | </template> | ||
21 | |||
22 | <style lang="stylus"> | ||
23 | .sidebar-button | ||
24 | cursor pointer | ||
25 | display none | ||
26 | width 1.25rem | ||
27 | height 1.25rem | ||
28 | position absolute | ||
29 | padding 0.6rem | ||
30 | top 0.6rem | ||
31 | left 1rem | ||
32 | .icon | ||
33 | display block | ||
34 | width 1.25rem | ||
35 | height 1.25rem | ||
36 | |||
37 | @media (max-width: $MQMobile) | ||
38 | .sidebar-button | ||
39 | display block | ||
40 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/SidebarGroup.vue b/doc/docs/.vuepress/theme/components/SidebarGroup.vue new file mode 100644 index 0000000..d7f1929 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/SidebarGroup.vue | |||
@@ -0,0 +1,141 @@ | |||
1 | <template> | ||
2 | <section | ||
3 | class="sidebar-group" | ||
4 | :class="[ | ||
5 | { | ||
6 | collapsable, | ||
7 | 'is-sub-group': depth !== 0 | ||
8 | }, | ||
9 | `depth-${depth}` | ||
10 | ]" | ||
11 | > | ||
12 | <RouterLink | ||
13 | v-if="item.path" | ||
14 | class="sidebar-heading clickable" | ||
15 | :class="{ | ||
16 | open, | ||
17 | 'active': isActive($route, item.path) | ||
18 | }" | ||
19 | :to="item.path" | ||
20 | @click.native="$emit('toggle')" | ||
21 | > | ||
22 | <span>{{ item.title }}</span> | ||
23 | <span | ||
24 | v-if="collapsable" | ||
25 | class="arrow" | ||
26 | :class="open ? 'down' : 'right'" | ||
27 | /> | ||
28 | </RouterLink> | ||
29 | |||
30 | <p | ||
31 | v-else | ||
32 | class="sidebar-heading" | ||
33 | :class="{ open }" | ||
34 | @click="$emit('toggle')" | ||
35 | > | ||
36 | <span>{{ item.title }}</span> | ||
37 | <span | ||
38 | v-if="collapsable" | ||
39 | class="arrow" | ||
40 | :class="open ? 'down' : 'right'" | ||
41 | /> | ||
42 | </p> | ||
43 | |||
44 | <DropdownTransition> | ||
45 | <SidebarLinks | ||
46 | v-if="open || !collapsable" | ||
47 | class="sidebar-group-items" | ||
48 | :items="item.children" | ||
49 | :sidebar-depth="item.sidebarDepth" | ||
50 | :initial-open-group-index="item.initialOpenGroupIndex" | ||
51 | :depth="depth + 1" | ||
52 | /> | ||
53 | </DropdownTransition> | ||
54 | </section> | ||
55 | </template> | ||
56 | |||
57 | <script> | ||
58 | import { isActive } from '../util' | ||
59 | import DropdownTransition from '@theme/components/DropdownTransition.vue' | ||
60 | |||
61 | export default { | ||
62 | name: 'SidebarGroup', | ||
63 | |||
64 | components: { | ||
65 | DropdownTransition | ||
66 | }, | ||
67 | |||
68 | props: [ | ||
69 | 'item', | ||
70 | 'open', | ||
71 | 'collapsable', | ||
72 | 'depth' | ||
73 | ], | ||
74 | |||
75 | // ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components | ||
76 | beforeCreate () { | ||
77 | this.$options.components.SidebarLinks = require('@theme/components/SidebarLinks.vue').default | ||
78 | }, | ||
79 | |||
80 | methods: { isActive } | ||
81 | } | ||
82 | </script> | ||
83 | |||
84 | <style lang="stylus"> | ||
85 | .sidebar-group | ||
86 | .sidebar-group | ||
87 | padding-left 0.5em | ||
88 | &:not(.collapsable) | ||
89 | .sidebar-heading:not(.clickable) | ||
90 | cursor auto | ||
91 | color inherit | ||
92 | // refine styles of nested sidebar groups | ||
93 | &.is-sub-group | ||
94 | padding-left 0 | ||
95 | & > .sidebar-heading | ||
96 | font-size 0.95em | ||
97 | line-height 1.4 | ||
98 | font-weight normal | ||
99 | padding-left 2rem | ||
100 | &:not(.clickable) | ||
101 | opacity 0.5 | ||
102 | & > .sidebar-group-items | ||
103 | padding-left 1rem | ||
104 | & > li > .sidebar-link | ||
105 | font-size: 0.95em; | ||
106 | border-left none | ||
107 | &.depth-2 | ||
108 | & > .sidebar-heading | ||
109 | border-left none | ||
110 | |||
111 | .sidebar-heading | ||
112 | color $textColor | ||
113 | transition color .15s ease | ||
114 | cursor pointer | ||
115 | font-size 1.1em | ||
116 | font-weight bold | ||
117 | // text-transform uppercase | ||
118 | padding 0.35rem 1.5rem 0.35rem 1.25rem | ||
119 | width 100% | ||
120 | box-sizing border-box | ||
121 | margin 0 | ||
122 | border-left 0.25rem solid transparent | ||
123 | &.open, &:hover | ||
124 | color inherit | ||
125 | .arrow | ||
126 | position relative | ||
127 | top -0.12em | ||
128 | left 0.5em | ||
129 | &.clickable | ||
130 | &.active | ||
131 | font-weight 600 | ||
132 | color $accentColor | ||
133 | border-left-color $accentColor | ||
134 | &:hover | ||
135 | color $accentColor | ||
136 | |||
137 | .sidebar-group-items | ||
138 | transition height .1s ease-out | ||
139 | font-size 0.95em | ||
140 | overflow hidden | ||
141 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/SidebarLink.vue b/doc/docs/.vuepress/theme/components/SidebarLink.vue new file mode 100644 index 0000000..4cd7665 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/SidebarLink.vue | |||
@@ -0,0 +1,133 @@ | |||
1 | <script> | ||
2 | import { isActive, hashRE, groupHeaders } from '../util' | ||
3 | |||
4 | export default { | ||
5 | functional: true, | ||
6 | |||
7 | props: ['item', 'sidebarDepth'], | ||
8 | |||
9 | render (h, | ||
10 | { | ||
11 | parent: { | ||
12 | $page, | ||
13 | $site, | ||
14 | $route, | ||
15 | $themeConfig, | ||
16 | $themeLocaleConfig | ||
17 | }, | ||
18 | props: { | ||
19 | item, | ||
20 | sidebarDepth | ||
21 | } | ||
22 | }) { | ||
23 | // use custom active class matching logic | ||
24 | // due to edge case of paths ending with / + hash | ||
25 | const selfActive = isActive($route, item.path) | ||
26 | // for sidebar: auto pages, a hash link should be active if one of its child | ||
27 | // matches | ||
28 | const active = item.type === 'auto' | ||
29 | ? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug)) | ||
30 | : selfActive | ||
31 | const link = item.type === 'external' | ||
32 | ? renderExternal(h, item.path, item.title || item.path) | ||
33 | : renderLink(h, item.path, item.title || item.path, active) | ||
34 | |||
35 | const maxDepth = [ | ||
36 | $page.frontmatter.sidebarDepth, | ||
37 | sidebarDepth, | ||
38 | $themeLocaleConfig.sidebarDepth, | ||
39 | $themeConfig.sidebarDepth, | ||
40 | 1 | ||
41 | ].find(depth => depth !== undefined) | ||
42 | |||
43 | const displayAllHeaders = $themeLocaleConfig.displayAllHeaders | ||
44 | || $themeConfig.displayAllHeaders | ||
45 | |||
46 | if (item.type === 'auto') { | ||
47 | return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)] | ||
48 | } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) { | ||
49 | const children = groupHeaders(item.headers) | ||
50 | return [link, renderChildren(h, children, item.path, $route, maxDepth)] | ||
51 | } else { | ||
52 | return link | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | |||
57 | function renderLink (h, to, text, active, level) { | ||
58 | const component = { | ||
59 | props: { | ||
60 | to, | ||
61 | activeClass: '', | ||
62 | exactActiveClass: '' | ||
63 | }, | ||
64 | class: { | ||
65 | active, | ||
66 | 'sidebar-link': true | ||
67 | } | ||
68 | } | ||
69 | |||
70 | if (level > 2) { | ||
71 | component.style = { | ||
72 | 'padding-left': level + 'rem' | ||
73 | } | ||
74 | } | ||
75 | |||
76 | return h('RouterLink', component, text) | ||
77 | } | ||
78 | |||
79 | function renderChildren (h, children, path, route, maxDepth, depth = 1) { | ||
80 | if (!children || depth > maxDepth) return null | ||
81 | return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => { | ||
82 | const active = isActive(route, path + '#' + c.slug) | ||
83 | return h('li', { class: 'sidebar-sub-header' }, [ | ||
84 | renderLink(h, path + '#' + c.slug, c.title, active, c.level - 1), | ||
85 | renderChildren(h, c.children, path, route, maxDepth, depth + 1) | ||
86 | ]) | ||
87 | })) | ||
88 | } | ||
89 | |||
90 | function renderExternal (h, to, text) { | ||
91 | return h('a', { | ||
92 | attrs: { | ||
93 | href: to, | ||
94 | target: '_blank', | ||
95 | rel: 'noopener noreferrer' | ||
96 | }, | ||
97 | class: { | ||
98 | 'sidebar-link': true | ||
99 | } | ||
100 | }, [text, h('OutboundLink')]) | ||
101 | } | ||
102 | </script> | ||
103 | |||
104 | <style lang="stylus"> | ||
105 | .sidebar .sidebar-sub-headers | ||
106 | padding-left 1rem | ||
107 | font-size 0.95em | ||
108 | |||
109 | a.sidebar-link | ||
110 | font-size 1em | ||
111 | font-weight 400 | ||
112 | display inline-block | ||
113 | color $textColor | ||
114 | border-left 0.25rem solid transparent | ||
115 | padding 0.35rem 1rem 0.35rem 1.25rem | ||
116 | line-height 1.4 | ||
117 | width: 100% | ||
118 | box-sizing: border-box | ||
119 | &:hover | ||
120 | color $accentColor | ||
121 | &.active | ||
122 | font-weight 600 | ||
123 | color $accentColor | ||
124 | border-left-color $accentColor | ||
125 | .sidebar-group & | ||
126 | padding-left 2rem | ||
127 | .sidebar-sub-headers & | ||
128 | padding-top 0.25rem | ||
129 | padding-bottom 0.25rem | ||
130 | border-left none | ||
131 | &.active | ||
132 | font-weight 500 | ||
133 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/components/SidebarLinks.vue b/doc/docs/.vuepress/theme/components/SidebarLinks.vue new file mode 100644 index 0000000..55e6288 --- /dev/null +++ b/doc/docs/.vuepress/theme/components/SidebarLinks.vue | |||
@@ -0,0 +1,106 @@ | |||
1 | <template> | ||
2 | <ul | ||
3 | v-if="items.length" | ||
4 | class="sidebar-links" | ||
5 | > | ||
6 | <li | ||
7 | v-for="(item, i) in items" | ||
8 | :key="i" | ||
9 | > | ||
10 | <SidebarGroup | ||
11 | v-if="item.type === 'group'" | ||
12 | :item="item" | ||
13 | :open="i === openGroupIndex" | ||
14 | :collapsable="item.collapsable || item.collapsible" | ||
15 | :depth="depth" | ||
16 | @toggle="toggleGroup(i)" | ||
17 | /> | ||
18 | <SidebarLink | ||
19 | v-else | ||
20 | :sidebar-depth="sidebarDepth" | ||
21 | :item="item" | ||
22 | /> | ||
23 | </li> | ||
24 | </ul> | ||
25 | </template> | ||
26 | |||
27 | <script> | ||
28 | import SidebarGroup from '@theme/components/SidebarGroup.vue' | ||
29 | import SidebarLink from '@theme/components/SidebarLink.vue' | ||
30 | import { isActive } from '../util' | ||
31 | |||
32 | export default { | ||
33 | name: 'SidebarLinks', | ||
34 | |||
35 | components: { SidebarGroup, SidebarLink }, | ||
36 | |||
37 | props: [ | ||
38 | 'items', | ||
39 | 'depth', // depth of current sidebar links | ||
40 | 'sidebarDepth', // depth of headers to be extracted | ||
41 | 'initialOpenGroupIndex' | ||
42 | ], | ||
43 | |||
44 | data () { | ||
45 | return { | ||
46 | openGroupIndex: this.initialOpenGroupIndex || 0 | ||
47 | } | ||
48 | }, | ||
49 | |||
50 | watch: { | ||
51 | '$route' () { | ||
52 | this.refreshIndex() | ||
53 | } | ||
54 | }, | ||
55 | |||
56 | created () { | ||
57 | this.refreshIndex() | ||
58 | }, | ||
59 | |||
60 | methods: { | ||
61 | refreshIndex () { | ||
62 | const index = resolveOpenGroupIndex( | ||
63 | this.$route, | ||
64 | this.items | ||
65 | ) | ||
66 | if (index > -1) { | ||
67 | this.openGroupIndex = index | ||
68 | } | ||
69 | }, | ||
70 | |||
71 | toggleGroup (index) { | ||
72 | this.openGroupIndex = index === this.openGroupIndex ? -1 : index | ||
73 | }, | ||
74 | |||
75 | isActive (page) { | ||
76 | return isActive(this.$route, page.regularPath) | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | function resolveOpenGroupIndex (route, items) { | ||
82 | for (let i = 0; i < items.length; i++) { | ||
83 | const item = items[i] | ||
84 | if (descendantIsActive(route, item)) { | ||
85 | return i | ||
86 | } | ||
87 | } | ||
88 | return -1 | ||
89 | } | ||
90 | |||
91 | function descendantIsActive (route, item) { | ||
92 | if (item.type === 'group') { | ||
93 | const childIsActive = item.path && isActive(route, item.path) | ||
94 | const grandChildIsActive = item.children.some(child => { | ||
95 | if (child.type === 'group') { | ||
96 | return descendantIsActive(route, child) | ||
97 | } else { | ||
98 | return child.type === 'page' && isActive(route, child.path) | ||
99 | } | ||
100 | }) | ||
101 | |||
102 | return childIsActive || grandChildIsActive | ||
103 | } | ||
104 | return false | ||
105 | } | ||
106 | </script> | ||
diff --git a/doc/docs/.vuepress/theme/global-components/Badge.vue b/doc/docs/.vuepress/theme/global-components/Badge.vue new file mode 100644 index 0000000..53951f9 --- /dev/null +++ b/doc/docs/.vuepress/theme/global-components/Badge.vue | |||
@@ -0,0 +1,44 @@ | |||
1 | <script> | ||
2 | export default { | ||
3 | functional: true, | ||
4 | props: { | ||
5 | type: { | ||
6 | type: String, | ||
7 | default: 'tip' | ||
8 | }, | ||
9 | text: String, | ||
10 | vertical: { | ||
11 | type: String, | ||
12 | default: 'top' | ||
13 | } | ||
14 | }, | ||
15 | render (h, { props, slots }) { | ||
16 | return h('span', { | ||
17 | class: ['badge', props.type], | ||
18 | style: { | ||
19 | verticalAlign: props.vertical | ||
20 | } | ||
21 | }, props.text || slots().default) | ||
22 | } | ||
23 | } | ||
24 | </script> | ||
25 | |||
26 | <style lang="stylus" scoped> | ||
27 | .badge | ||
28 | display inline-block | ||
29 | font-size 14px | ||
30 | height 18px | ||
31 | line-height 18px | ||
32 | border-radius 3px | ||
33 | padding 0 6px | ||
34 | color white | ||
35 | background-color #42b983 | ||
36 | &.tip, &.green | ||
37 | background-color $badgeTipColor | ||
38 | &.error | ||
39 | background-color $badgeErrorColor | ||
40 | &.warning, &.warn, &.yellow | ||
41 | background-color $badgeWarningColor | ||
42 | & + & | ||
43 | margin-left 5px | ||
44 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/global-components/CodeBlock.vue b/doc/docs/.vuepress/theme/global-components/CodeBlock.vue new file mode 100644 index 0000000..d59d85b --- /dev/null +++ b/doc/docs/.vuepress/theme/global-components/CodeBlock.vue | |||
@@ -0,0 +1,41 @@ | |||
1 | <template> | ||
2 | <div | ||
3 | class="theme-code-block" | ||
4 | :class="{ 'theme-code-block__active': active }" | ||
5 | > | ||
6 | <slot /> | ||
7 | </div> | ||
8 | </template> | ||
9 | |||
10 | <script> | ||
11 | export default { | ||
12 | name: 'CodeBlock', | ||
13 | props: { | ||
14 | title: { | ||
15 | type: String, | ||
16 | required: true | ||
17 | }, | ||
18 | active: { | ||
19 | type: Boolean, | ||
20 | default: false | ||
21 | } | ||
22 | }, | ||
23 | mounted () { | ||
24 | if (this.$parent && this.$parent.loadTabs) { | ||
25 | this.$parent.loadTabs() | ||
26 | } | ||
27 | } | ||
28 | } | ||
29 | </script> | ||
30 | |||
31 | <style scoped> | ||
32 | .theme-code-block { | ||
33 | display: none; | ||
34 | } | ||
35 | .theme-code-block__active { | ||
36 | display: block; | ||
37 | } | ||
38 | .theme-code-block > pre { | ||
39 | background-color: orange; | ||
40 | } | ||
41 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/global-components/CodeGroup.vue b/doc/docs/.vuepress/theme/global-components/CodeGroup.vue new file mode 100644 index 0000000..ac6ec55 --- /dev/null +++ b/doc/docs/.vuepress/theme/global-components/CodeGroup.vue | |||
@@ -0,0 +1,120 @@ | |||
1 | <template> | ||
2 | <ClientOnly> | ||
3 | <div class="theme-code-group"> | ||
4 | <div class="theme-code-group__nav"> | ||
5 | <ul class="theme-code-group__ul"> | ||
6 | <li | ||
7 | v-for="(tab, i) in codeTabs" | ||
8 | :key="tab.title" | ||
9 | class="theme-code-group__li" | ||
10 | > | ||
11 | <button | ||
12 | class="theme-code-group__nav-tab" | ||
13 | :class="{ | ||
14 | 'theme-code-group__nav-tab-active': i === activeCodeTabIndex, | ||
15 | }" | ||
16 | @click="changeCodeTab(i)" | ||
17 | > | ||
18 | {{ tab.title }} | ||
19 | </button> | ||
20 | </li> | ||
21 | </ul> | ||
22 | </div> | ||
23 | <slot /> | ||
24 | <pre | ||
25 | v-if="codeTabs.length < 1" | ||
26 | class="pre-blank" | ||
27 | >// Make sure to add code blocks to your code group</pre> | ||
28 | </div> | ||
29 | </ClientOnly> | ||
30 | </template> | ||
31 | |||
32 | <script> | ||
33 | export default { | ||
34 | name: 'CodeGroup', | ||
35 | data () { | ||
36 | return { | ||
37 | codeTabs: [], | ||
38 | activeCodeTabIndex: -1 | ||
39 | } | ||
40 | }, | ||
41 | watch: { | ||
42 | activeCodeTabIndex (index) { | ||
43 | this.activateCodeTab(index) | ||
44 | } | ||
45 | }, | ||
46 | mounted () { | ||
47 | this.loadTabs() | ||
48 | }, | ||
49 | methods: { | ||
50 | changeCodeTab (index) { | ||
51 | this.activeCodeTabIndex = index | ||
52 | }, | ||
53 | loadTabs () { | ||
54 | this.codeTabs = (this.$slots.default || []).filter(slot => Boolean(slot.componentOptions)).map((slot, index) => { | ||
55 | if (slot.componentOptions.propsData.active === '') { | ||
56 | this.activeCodeTabIndex = index | ||
57 | } | ||
58 | |||
59 | return { | ||
60 | title: slot.componentOptions.propsData.title, | ||
61 | elm: slot.elm | ||
62 | } | ||
63 | }) | ||
64 | |||
65 | if (this.activeCodeTabIndex === -1 && this.codeTabs.length > 0) { | ||
66 | this.activeCodeTabIndex = 0 | ||
67 | } | ||
68 | |||
69 | this.activateCodeTab(0) | ||
70 | }, | ||
71 | activateCodeTab (index) { | ||
72 | this.codeTabs.forEach(tab => { | ||
73 | if (tab.elm) { | ||
74 | tab.elm.classList.remove('theme-code-block__active') | ||
75 | } | ||
76 | }) | ||
77 | |||
78 | if (this.codeTabs[index].elm) { | ||
79 | this.codeTabs[index].elm.classList.add('theme-code-block__active') | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | </script> | ||
85 | |||
86 | <style lang="stylus" scoped> | ||
87 | .theme-code-group {} | ||
88 | .theme-code-group__nav { | ||
89 | margin-bottom: -35px; | ||
90 | background-color: $codeBgColor; | ||
91 | padding-bottom: 22px; | ||
92 | border-top-left-radius: 6px; | ||
93 | border-top-right-radius: 6px; | ||
94 | padding-left: 10px; | ||
95 | padding-top: 10px; | ||
96 | } | ||
97 | .theme-code-group__ul { | ||
98 | margin: auto 0; | ||
99 | padding-left: 0; | ||
100 | display: inline-flex; | ||
101 | list-style: none; | ||
102 | } | ||
103 | .theme-code-group__li {} | ||
104 | .theme-code-group__nav-tab { | ||
105 | border: 0; | ||
106 | padding: 5px; | ||
107 | cursor: pointer; | ||
108 | background-color: transparent; | ||
109 | font-size: 0.85em; | ||
110 | line-height: 1.4; | ||
111 | color: rgba(255, 255, 255, 0.9); | ||
112 | font-weight: 600; | ||
113 | } | ||
114 | .theme-code-group__nav-tab-active { | ||
115 | border-bottom: #42b983 1px solid; | ||
116 | } | ||
117 | .pre-blank { | ||
118 | color: #42b983; | ||
119 | } | ||
120 | </style> | ||
diff --git a/doc/docs/.vuepress/theme/index.js b/doc/docs/.vuepress/theme/index.js new file mode 100644 index 0000000..baaf102 --- /dev/null +++ b/doc/docs/.vuepress/theme/index.js | |||
@@ -0,0 +1,59 @@ | |||
1 | const path = require('path') | ||
2 | |||
3 | // Theme API. | ||
4 | module.exports = (options, ctx) => { | ||
5 | const { themeConfig, siteConfig } = ctx | ||
6 | |||
7 | // resolve algolia | ||
8 | const isAlgoliaSearch = ( | ||
9 | themeConfig.algolia | ||
10 | || Object | ||
11 | .keys(siteConfig.locales && themeConfig.locales || {}) | ||
12 | .some(base => themeConfig.locales[base].algolia) | ||
13 | ) | ||
14 | |||
15 | const enableSmoothScroll = themeConfig.smoothScroll === true | ||
16 | |||
17 | return { | ||
18 | alias () { | ||
19 | return { | ||
20 | '@AlgoliaSearchBox': isAlgoliaSearch | ||
21 | ? path.resolve(__dirname, 'components/AlgoliaSearchBox.vue') | ||
22 | : path.resolve(__dirname, 'noopModule.js') | ||
23 | } | ||
24 | }, | ||
25 | |||
26 | plugins: [ | ||
27 | ['@vuepress/active-header-links', options.activeHeaderLinks], | ||
28 | '@vuepress/search', | ||
29 | '@vuepress/plugin-nprogress', | ||
30 | ['container', { | ||
31 | type: 'tip', | ||
32 | defaultTitle: { | ||
33 | '/': 'TIP', | ||
34 | '/zh/': '提示' | ||
35 | } | ||
36 | }], | ||
37 | ['container', { | ||
38 | type: 'warning', | ||
39 | defaultTitle: { | ||
40 | '/': 'WARNING', | ||
41 | '/zh/': '注意' | ||
42 | } | ||
43 | }], | ||
44 | ['container', { | ||
45 | type: 'danger', | ||
46 | defaultTitle: { | ||
47 | '/': 'WARNING', | ||
48 | '/zh/': '警告' | ||
49 | } | ||
50 | }], | ||
51 | ['container', { | ||
52 | type: 'details', | ||
53 | before: info => `<details class="custom-block details">${info ? `<summary>${info}</summary>` : ''}\n`, | ||
54 | after: () => '</details>\n' | ||
55 | }], | ||
56 | ['smooth-scroll', enableSmoothScroll] | ||
57 | ] | ||
58 | } | ||
59 | } | ||
diff --git a/doc/docs/.vuepress/theme/layouts/404.vue b/doc/docs/.vuepress/theme/layouts/404.vue new file mode 100644 index 0000000..2cbfa0f --- /dev/null +++ b/doc/docs/.vuepress/theme/layouts/404.vue | |||
@@ -0,0 +1,30 @@ | |||
1 | <template> | ||
2 | <div class="theme-container"> | ||
3 | <div class="theme-default-content"> | ||
4 | <h1>404</h1> | ||
5 | |||
6 | <blockquote>{{ getMsg() }}</blockquote> | ||
7 | |||
8 | <RouterLink to="/"> | ||
9 | Take me home. | ||
10 | </RouterLink> | ||
11 | </div> | ||
12 | </div> | ||
13 | </template> | ||
14 | |||
15 | <script> | ||
16 | const msgs = [ | ||
17 | `There's nothing here.`, | ||
18 | `How did we get here?`, | ||
19 | `That's a Four-Oh-Four.`, | ||
20 | `Looks like we've got some broken links.` | ||
21 | ] | ||
22 | |||
23 | export default { | ||
24 | methods: { | ||
25 | getMsg () { | ||
26 | return msgs[Math.floor(Math.random() * msgs.length)] | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | </script> | ||
diff --git a/doc/docs/.vuepress/theme/layouts/Layout.vue b/doc/docs/.vuepress/theme/layouts/Layout.vue new file mode 100644 index 0000000..3298070 --- /dev/null +++ b/doc/docs/.vuepress/theme/layouts/Layout.vue | |||
@@ -0,0 +1,151 @@ | |||
1 | <template> | ||
2 | <div | ||
3 | class="theme-container" | ||
4 | :class="pageClasses" | ||
5 | @touchstart="onTouchStart" | ||
6 | @touchend="onTouchEnd" | ||
7 | > | ||
8 | <Navbar | ||
9 | v-if="shouldShowNavbar" | ||
10 | @toggle-sidebar="toggleSidebar" | ||
11 | /> | ||
12 | |||
13 | <div | ||
14 | class="sidebar-mask" | ||
15 | @click="toggleSidebar(false)" | ||
16 | /> | ||
17 | |||
18 | <Sidebar | ||
19 | :items="sidebarItems" | ||
20 | @toggle-sidebar="toggleSidebar" | ||
21 | > | ||
22 | <template #top> | ||
23 | <slot name="sidebar-top" /> | ||
24 | </template> | ||
25 | <template #bottom> | ||
26 | <slot name="sidebar-bottom" /> | ||
27 | </template> | ||
28 | </Sidebar> | ||
29 | |||
30 | <Home v-if="$page.frontmatter.home" /> | ||
31 | |||
32 | <Page | ||
33 | v-else | ||
34 | :sidebar-items="sidebarItems" | ||
35 | > | ||
36 | <template #top> | ||
37 | <slot name="page-top" /> | ||
38 | </template> | ||
39 | <template #bottom> | ||
40 | <slot name="page-bottom" /> | ||
41 | </template> | ||
42 | </Page> | ||
43 | </div> | ||
44 | </template> | ||
45 | |||
46 | <script> | ||
47 | import Home from '@theme/components/Home.vue' | ||
48 | import Navbar from '@theme/components/Navbar.vue' | ||
49 | import Page from '@theme/components/Page.vue' | ||
50 | import Sidebar from '@theme/components/Sidebar.vue' | ||
51 | import { resolveSidebarItems } from '../util' | ||
52 | |||
53 | export default { | ||
54 | name: 'Layout', | ||
55 | |||
56 | components: { | ||
57 | Home, | ||
58 | Page, | ||
59 | Sidebar, | ||
60 | Navbar | ||
61 | }, | ||
62 | |||
63 | data () { | ||
64 | return { | ||
65 | isSidebarOpen: false | ||
66 | } | ||
67 | }, | ||
68 | |||
69 | computed: { | ||
70 | shouldShowNavbar () { | ||
71 | const { themeConfig } = this.$site | ||
72 | const { frontmatter } = this.$page | ||
73 | if ( | ||
74 | frontmatter.navbar === false | ||
75 | || themeConfig.navbar === false) { | ||
76 | return false | ||
77 | } | ||
78 | return ( | ||
79 | this.$title | ||
80 | || themeConfig.logo | ||
81 | || themeConfig.repo | ||
82 | || themeConfig.nav | ||
83 | || this.$themeLocaleConfig.nav | ||
84 | ) | ||
85 | }, | ||
86 | |||
87 | shouldShowSidebar () { | ||
88 | const { frontmatter } = this.$page | ||
89 | return ( | ||
90 | !frontmatter.home | ||
91 | && frontmatter.sidebar !== false | ||
92 | && this.sidebarItems.length | ||
93 | ) | ||
94 | }, | ||
95 | |||
96 | sidebarItems () { | ||
97 | return resolveSidebarItems( | ||
98 | this.$page, | ||
99 | this.$page.regularPath, | ||
100 | this.$site, | ||
101 | this.$localePath | ||
102 | ) | ||
103 | }, | ||
104 | |||
105 | pageClasses () { | ||
106 | const userPageClass = this.$page.frontmatter.pageClass | ||
107 | return [ | ||
108 | { | ||
109 | 'no-navbar': !this.shouldShowNavbar, | ||
110 | 'sidebar-open': this.isSidebarOpen, | ||
111 | 'no-sidebar': !this.shouldShowSidebar | ||
112 | }, | ||
113 | userPageClass | ||
114 | ] | ||
115 | } | ||
116 | }, | ||
117 | |||
118 | mounted () { | ||
119 | this.$router.afterEach(() => { | ||
120 | this.isSidebarOpen = false | ||
121 | }) | ||
122 | }, | ||
123 | |||
124 | methods: { | ||
125 | toggleSidebar (to) { | ||
126 | this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen | ||
127 | this.$emit('toggle-sidebar', this.isSidebarOpen) | ||
128 | }, | ||
129 | |||
130 | // side swipe | ||
131 | onTouchStart (e) { | ||
132 | this.touchStart = { | ||
133 | x: e.changedTouches[0].clientX, | ||
134 | y: e.changedTouches[0].clientY | ||
135 | } | ||
136 | }, | ||
137 | |||
138 | onTouchEnd (e) { | ||
139 | const dx = e.changedTouches[0].clientX - this.touchStart.x | ||
140 | const dy = e.changedTouches[0].clientY - this.touchStart.y | ||
141 | if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) { | ||
142 | if (dx > 0 && this.touchStart.x <= 80) { | ||
143 | this.toggleSidebar(true) | ||
144 | } else { | ||
145 | this.toggleSidebar(false) | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | </script> | ||
diff --git a/doc/docs/.vuepress/theme/noopModule.js b/doc/docs/.vuepress/theme/noopModule.js new file mode 100644 index 0000000..b1c6ea4 --- /dev/null +++ b/doc/docs/.vuepress/theme/noopModule.js | |||
@@ -0,0 +1 @@ | |||
export default {} | |||
diff --git a/doc/docs/.vuepress/theme/package.json b/doc/docs/.vuepress/theme/package.json new file mode 100644 index 0000000..d5dfc26 --- /dev/null +++ b/doc/docs/.vuepress/theme/package.json | |||
@@ -0,0 +1,44 @@ | |||
1 | { | ||
2 | "name": "@vuepress/theme-default", | ||
3 | "version": "1.8.2", | ||
4 | "description": "Default theme for VuePress", | ||
5 | "keywords": [ | ||
6 | "documentation", | ||
7 | "generator", | ||
8 | "vue", | ||
9 | "vuepress" | ||
10 | ], | ||
11 | "homepage": "https://github.com/vuejs/vuepress/blob/master/packages/@vuepress/theme-default#readme", | ||
12 | "bugs": { | ||
13 | "url": "https://github.com/vuejs/vuepress/issues" | ||
14 | }, | ||
15 | "repository": { | ||
16 | "type": "git", | ||
17 | "url": "git+https://github.com/vuejs/vuepress.git", | ||
18 | "directory": "packages/@vuepress/theme-default" | ||
19 | }, | ||
20 | "license": "MIT", | ||
21 | "author": "Evan You", | ||
22 | "main": "index.js", | ||
23 | "dependencies": { | ||
24 | "@vuepress/plugin-active-header-links": "1.8.2", | ||
25 | "@vuepress/plugin-nprogress": "1.8.2", | ||
26 | "@vuepress/plugin-search": "1.8.2", | ||
27 | "docsearch.js": "^2.5.2", | ||
28 | "lodash": "^4.17.15", | ||
29 | "stylus": "^0.54.8", | ||
30 | "stylus-loader": "^3.0.2", | ||
31 | "vuepress-plugin-container": "^2.0.2", | ||
32 | "vuepress-plugin-smooth-scroll": "^0.0.3" | ||
33 | }, | ||
34 | "publishConfig": { | ||
35 | "access": "public" | ||
36 | }, | ||
37 | "maintainers": [ | ||
38 | { | ||
39 | "name": "ULIVZ", | ||
40 | "email": "chl814@foxmail.com" | ||
41 | } | ||
42 | ], | ||
43 | "gitHead": "11eed0f0f105b97a7324cfa8e59d7d27bb966842" | ||
44 | } | ||
diff --git a/doc/docs/.vuepress/theme/styles/arrow.styl b/doc/docs/.vuepress/theme/styles/arrow.styl new file mode 100644 index 0000000..20bffc0 --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/arrow.styl | |||
@@ -0,0 +1,22 @@ | |||
1 | @require './config' | ||
2 | |||
3 | .arrow | ||
4 | display inline-block | ||
5 | width 0 | ||
6 | height 0 | ||
7 | &.up | ||
8 | border-left 4px solid transparent | ||
9 | border-right 4px solid transparent | ||
10 | border-bottom 6px solid $arrowBgColor | ||
11 | &.down | ||
12 | border-left 4px solid transparent | ||
13 | border-right 4px solid transparent | ||
14 | border-top 6px solid $arrowBgColor | ||
15 | &.right | ||
16 | border-top 4px solid transparent | ||
17 | border-bottom 4px solid transparent | ||
18 | border-left 6px solid $arrowBgColor | ||
19 | &.left | ||
20 | border-top 4px solid transparent | ||
21 | border-bottom 4px solid transparent | ||
22 | border-right 6px solid $arrowBgColor | ||
diff --git a/doc/docs/.vuepress/theme/styles/code.styl b/doc/docs/.vuepress/theme/styles/code.styl new file mode 100644 index 0000000..0cb4081 --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/code.styl | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | |||
3 | Name: Base16 Atelier Sulphurpool Light | ||
4 | Author: Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) | ||
5 | |||
6 | Prism template by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/prism/) | ||
7 | Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) | ||
8 | |||
9 | */ | ||
10 | code[class*="language-"], | ||
11 | pre[class*="language-"] { | ||
12 | font-family: Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace; | ||
13 | font-size: 1em; | ||
14 | line-height: 1.375; | ||
15 | direction: ltr; | ||
16 | text-align: left; | ||
17 | white-space: pre; | ||
18 | word-spacing: normal; | ||
19 | word-break: normal; | ||
20 | -moz-tab-size: 4; | ||
21 | -o-tab-size: 4; | ||
22 | tab-size: 4; | ||
23 | -webkit-hyphens: none; | ||
24 | -moz-hyphens: none; | ||
25 | -ms-hyphens: none; | ||
26 | hyphens: none; | ||
27 | background: #f5f7ff; | ||
28 | color: #5e6687; | ||
29 | } | ||
30 | |||
31 | pre > code[class*="language-"] { | ||
32 | font-size: 1em; | ||
33 | } | ||
34 | |||
35 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, | ||
36 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { | ||
37 | text-shadow: none; | ||
38 | background: #dfe2f1; | ||
39 | } | ||
40 | |||
41 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, | ||
42 | code[class*="language-"]::selection, code[class*="language-"] ::selection { | ||
43 | text-shadow: none; | ||
44 | background: #dfe2f1; | ||
45 | } | ||
46 | |||
47 | /* Code blocks */ | ||
48 | pre[class*="language-"] { | ||
49 | padding: 1em; | ||
50 | margin: .5em 0; | ||
51 | overflow: auto; | ||
52 | } | ||
53 | |||
54 | /* Inline code */ | ||
55 | :not(pre) > code[class*="language-"] { | ||
56 | padding: .1em; | ||
57 | border-radius: .3em; | ||
58 | } | ||
59 | |||
60 | .token.comment, | ||
61 | .token.prolog, | ||
62 | .token.doctype, | ||
63 | .token.cdata { | ||
64 | color: #898ea4; | ||
65 | } | ||
66 | |||
67 | .token.punctuation { | ||
68 | color: #5e6687; | ||
69 | } | ||
70 | |||
71 | .token.namespace { | ||
72 | opacity: .7; | ||
73 | } | ||
74 | |||
75 | .token.operator, | ||
76 | .token.boolean, | ||
77 | .token.number { | ||
78 | color: #c76b29; | ||
79 | } | ||
80 | |||
81 | .token.property { | ||
82 | color: #c08b30; | ||
83 | } | ||
84 | |||
85 | .token.tag { | ||
86 | color: #3d8fd1; | ||
87 | } | ||
88 | |||
89 | .token.string { | ||
90 | color: #22a2c9; | ||
91 | } | ||
92 | |||
93 | .token.selector { | ||
94 | color: #6679cc; | ||
95 | } | ||
96 | |||
97 | .token.attr-name { | ||
98 | color: #c76b29; | ||
99 | } | ||
100 | |||
101 | .token.entity, | ||
102 | .token.url, | ||
103 | .language-css .token.string, | ||
104 | .style .token.string { | ||
105 | color: #22a2c9; | ||
106 | } | ||
107 | |||
108 | .token.attr-value, | ||
109 | .token.keyword, | ||
110 | .token.control, | ||
111 | .token.directive, | ||
112 | .token.unit { | ||
113 | color: #ac9739; | ||
114 | } | ||
115 | |||
116 | .token.statement, | ||
117 | .token.regex, | ||
118 | .token.atrule { | ||
119 | color: #22a2c9; | ||
120 | } | ||
121 | |||
122 | .token.placeholder, | ||
123 | .token.variable { | ||
124 | color: #3d8fd1; | ||
125 | } | ||
126 | |||
127 | .token.deleted { | ||
128 | text-decoration: line-through; | ||
129 | } | ||
130 | |||
131 | .token.inserted { | ||
132 | border-bottom: 1px dotted #202746; | ||
133 | text-decoration: none; | ||
134 | } | ||
135 | |||
136 | .token.italic { | ||
137 | font-style: italic; | ||
138 | } | ||
139 | |||
140 | .token.important, | ||
141 | .token.bold { | ||
142 | font-weight: bold; | ||
143 | } | ||
144 | |||
145 | .token.important { | ||
146 | color: #c94922; | ||
147 | } | ||
148 | |||
149 | .token.entity { | ||
150 | cursor: help; | ||
151 | } | ||
152 | |||
153 | pre > code.highlight { | ||
154 | outline: 0.4em solid #c94922; | ||
155 | outline-offset: .4em; | ||
156 | } | ||
157 | |||
158 | /* overrides color-values for the Line Numbers plugin | ||
159 | * http://prismjs.com/plugins/line-numbers/ | ||
160 | */ | ||
161 | .line-numbers .line-numbers-rows { | ||
162 | border-right-color: #dfe2f1; | ||
163 | } | ||
164 | |||
165 | .line-numbers-rows > span:before { | ||
166 | color: #979db4; | ||
167 | } | ||
168 | |||
169 | /* overrides color-values for the Line Highlight plugin | ||
170 | * http://prismjs.com/plugins/line-highlight/ | ||
171 | */ | ||
172 | .line-highlight { | ||
173 | background: rgba(107, 115, 148, 0.2); | ||
174 | background: -webkit-linear-gradient(left, rgba(107, 115, 148, 0.2) 70%, rgba(107, 115, 148, 0)); | ||
175 | background: linear-gradient(to right, rgba(107, 115, 148, 0.2) 70%, rgba(107, 115, 148, 0)); | ||
176 | } | ||
diff --git a/doc/docs/.vuepress/theme/styles/config.styl b/doc/docs/.vuepress/theme/styles/config.styl new file mode 100644 index 0000000..9e40321 --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/config.styl | |||
@@ -0,0 +1 @@ | |||
$contentClass = '.theme-default-content' | |||
diff --git a/doc/docs/.vuepress/theme/styles/custom-blocks.styl b/doc/docs/.vuepress/theme/styles/custom-blocks.styl new file mode 100644 index 0000000..5b86816 --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/custom-blocks.styl | |||
@@ -0,0 +1,44 @@ | |||
1 | .custom-block | ||
2 | .custom-block-title | ||
3 | font-weight 600 | ||
4 | margin-bottom -0.4rem | ||
5 | &.tip, &.warning, &.danger | ||
6 | padding .1rem 1.5rem | ||
7 | border-left-width .5rem | ||
8 | border-left-style solid | ||
9 | margin 1rem 0 | ||
10 | &.tip | ||
11 | background-color #f3f5f7 | ||
12 | border-color #42b983 | ||
13 | &.warning | ||
14 | background-color rgba(255,229,100,.3) | ||
15 | border-color darken(#ffe564, 35%) | ||
16 | color darken(#ffe564, 70%) | ||
17 | .custom-block-title | ||
18 | color darken(#ffe564, 50%) | ||
19 | a | ||
20 | color $textColor | ||
21 | &.danger | ||
22 | background-color #ffe6e6 | ||
23 | border-color darken(red, 20%) | ||
24 | color darken(red, 70%) | ||
25 | .custom-block-title | ||
26 | color darken(red, 40%) | ||
27 | a | ||
28 | color $textColor | ||
29 | &.details | ||
30 | display block | ||
31 | position relative | ||
32 | border-radius 2px | ||
33 | margin 1.6em 0 | ||
34 | padding 1.6em | ||
35 | background-color #eee | ||
36 | h4 | ||
37 | margin-top 0 | ||
38 | figure, p | ||
39 | &:last-child | ||
40 | margin-bottom 0 | ||
41 | padding-bottom 0 | ||
42 | summary | ||
43 | outline none | ||
44 | cursor pointer | ||
diff --git a/doc/docs/.vuepress/theme/styles/index.styl b/doc/docs/.vuepress/theme/styles/index.styl new file mode 100644 index 0000000..ecef658 --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/index.styl | |||
@@ -0,0 +1,202 @@ | |||
1 | @require './config' | ||
2 | @require './code' | ||
3 | @require './custom-blocks' | ||
4 | @require './arrow' | ||
5 | @require './wrapper' | ||
6 | @require './toc' | ||
7 | |||
8 | html, body | ||
9 | padding 0 | ||
10 | margin 0 | ||
11 | background-color #fff | ||
12 | |||
13 | body | ||
14 | font-family -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif | ||
15 | -webkit-font-smoothing antialiased | ||
16 | -moz-osx-font-smoothing grayscale | ||
17 | font-size 16px | ||
18 | color $textColor | ||
19 | |||
20 | .page | ||
21 | padding-left $sidebarWidth | ||
22 | |||
23 | .navbar | ||
24 | position fixed | ||
25 | z-index 20 | ||
26 | top 0 | ||
27 | left 0 | ||
28 | right 0 | ||
29 | height $navbarHeight | ||
30 | background-color #fff | ||
31 | box-sizing border-box | ||
32 | border-bottom 1px solid $borderColor | ||
33 | |||
34 | .sidebar-mask | ||
35 | position fixed | ||
36 | z-index 9 | ||
37 | top 0 | ||
38 | left 0 | ||
39 | width 100vw | ||
40 | height 100vh | ||
41 | display none | ||
42 | |||
43 | .sidebar | ||
44 | font-size 16px | ||
45 | background-color #fff | ||
46 | width $sidebarWidth | ||
47 | position fixed | ||
48 | z-index 10 | ||
49 | margin 0 | ||
50 | top $navbarHeight | ||
51 | left 0 | ||
52 | bottom 0 | ||
53 | box-sizing border-box | ||
54 | border-right 1px solid $borderColor | ||
55 | overflow-y auto | ||
56 | |||
57 | {$contentClass}:not(.custom) | ||
58 | @extend $wrapper | ||
59 | > *:first-child | ||
60 | margin-top $navbarHeight | ||
61 | |||
62 | a:hover | ||
63 | text-decoration underline | ||
64 | |||
65 | p.demo | ||
66 | padding 1rem 1.5rem | ||
67 | border 1px solid #ddd | ||
68 | border-radius 4px | ||
69 | |||
70 | img | ||
71 | max-width 100% | ||
72 | |||
73 | {$contentClass}.custom | ||
74 | padding 0 | ||
75 | margin 0 | ||
76 | |||
77 | img | ||
78 | max-width 100% | ||
79 | |||
80 | a | ||
81 | font-weight 500 | ||
82 | color $accentColor | ||
83 | text-decoration none | ||
84 | |||
85 | p a code | ||
86 | font-weight 400 | ||
87 | color $accentColor | ||
88 | |||
89 | kbd | ||
90 | background #eee | ||
91 | border solid 0.15rem #ddd | ||
92 | border-bottom solid 0.25rem #ddd | ||
93 | border-radius 0.15rem | ||
94 | padding 0 0.15em | ||
95 | |||
96 | blockquote | ||
97 | font-size 1rem | ||
98 | color #999; | ||
99 | border-left .2rem solid #dfe2e5 | ||
100 | margin 1rem 0 | ||
101 | padding .25rem 0 .25rem 1rem | ||
102 | |||
103 | & > p | ||
104 | margin 0 | ||
105 | |||
106 | ul, ol | ||
107 | padding-left 1.2em | ||
108 | |||
109 | strong | ||
110 | font-weight 600 | ||
111 | |||
112 | h1, h2, h3, h4, h5, h6 | ||
113 | font-weight 600 | ||
114 | line-height 1.25 | ||
115 | |||
116 | {$contentClass}:not(.custom) > & | ||
117 | margin-top (0.5rem - $navbarHeight) | ||
118 | padding-top ($navbarHeight + 1rem) | ||
119 | margin-bottom 0 | ||
120 | |||
121 | &:first-child | ||
122 | margin-top -1.5rem | ||
123 | margin-bottom 1rem | ||
124 | |||
125 | + p, + pre, + .custom-block | ||
126 | margin-top 2rem | ||
127 | |||
128 | &:focus .header-anchor, | ||
129 | &:hover .header-anchor | ||
130 | opacity: 1 | ||
131 | |||
132 | h1 | ||
133 | font-size 2.2rem | ||
134 | |||
135 | h2 | ||
136 | font-size 1.65rem | ||
137 | padding-bottom .3rem | ||
138 | border-bottom 1px solid $borderColor | ||
139 | |||
140 | h3 | ||
141 | font-size 1.35rem | ||
142 | |||
143 | a.header-anchor | ||
144 | font-size 0.85em | ||
145 | float left | ||
146 | margin-left -0.87em | ||
147 | padding-right 0.23em | ||
148 | margin-top 0.125em | ||
149 | opacity 0 | ||
150 | |||
151 | &:focus, | ||
152 | &:hover | ||
153 | text-decoration none | ||
154 | |||
155 | code, kbd, .line-number | ||
156 | font-family Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace | ||
157 | |||
158 | p, ul, ol | ||
159 | line-height 1.7 | ||
160 | |||
161 | hr | ||
162 | border 0 | ||
163 | border-top 1px solid $borderColor | ||
164 | |||
165 | table | ||
166 | border-collapse collapse | ||
167 | margin 1rem 0 | ||
168 | display: block | ||
169 | overflow-x: auto | ||
170 | |||
171 | tr | ||
172 | border-top 1px solid #dfe2e5 | ||
173 | |||
174 | &:nth-child(2n) | ||
175 | background-color #f6f8fa | ||
176 | |||
177 | th, td | ||
178 | border 1px solid #dfe2e5 | ||
179 | padding .6em 1em | ||
180 | |||
181 | .theme-container | ||
182 | &.sidebar-open | ||
183 | .sidebar-mask | ||
184 | display: block | ||
185 | |||
186 | &.no-navbar | ||
187 | {$contentClass}:not(.custom) > h1, h2, h3, h4, h5, h6 | ||
188 | margin-top 1.5rem | ||
189 | padding-top 0 | ||
190 | |||
191 | .sidebar | ||
192 | top 0 | ||
193 | |||
194 | @media (min-width: ($MQMobile + 1px)) | ||
195 | .theme-container.no-sidebar | ||
196 | .sidebar | ||
197 | display none | ||
198 | |||
199 | .page | ||
200 | padding-left 0 | ||
201 | |||
202 | @require 'mobile.styl' | ||
diff --git a/doc/docs/.vuepress/theme/styles/mobile.styl b/doc/docs/.vuepress/theme/styles/mobile.styl new file mode 100644 index 0000000..f5bd327 --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/mobile.styl | |||
@@ -0,0 +1,37 @@ | |||
1 | @require './config' | ||
2 | |||
3 | $mobileSidebarWidth = $sidebarWidth * 0.82 | ||
4 | |||
5 | // narrow desktop / iPad | ||
6 | @media (max-width: $MQNarrow) | ||
7 | .sidebar | ||
8 | font-size 15px | ||
9 | width $mobileSidebarWidth | ||
10 | .page | ||
11 | padding-left $mobileSidebarWidth | ||
12 | |||
13 | // wide mobile | ||
14 | @media (max-width: $MQMobile) | ||
15 | .sidebar | ||
16 | top 0 | ||
17 | padding-top $navbarHeight | ||
18 | transform translateX(-100%) | ||
19 | transition transform .2s ease | ||
20 | .page | ||
21 | padding-left 0 | ||
22 | .theme-container | ||
23 | &.sidebar-open | ||
24 | .sidebar | ||
25 | transform translateX(0) | ||
26 | &.no-navbar | ||
27 | .sidebar | ||
28 | padding-top: 0 | ||
29 | |||
30 | // narrow mobile | ||
31 | @media (max-width: $MQMobileNarrow) | ||
32 | h1 | ||
33 | font-size 1.9rem | ||
34 | {$contentClass} | ||
35 | div[class*="language-"] | ||
36 | margin 0.85rem -1.5rem | ||
37 | border-radius 0 | ||
diff --git a/doc/docs/.vuepress/theme/styles/toc.styl b/doc/docs/.vuepress/theme/styles/toc.styl new file mode 100644 index 0000000..d3e7106 --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/toc.styl | |||
@@ -0,0 +1,3 @@ | |||
1 | .table-of-contents | ||
2 | .badge | ||
3 | vertical-align middle | ||
diff --git a/doc/docs/.vuepress/theme/styles/wrapper.styl b/doc/docs/.vuepress/theme/styles/wrapper.styl new file mode 100644 index 0000000..a99262c --- /dev/null +++ b/doc/docs/.vuepress/theme/styles/wrapper.styl | |||
@@ -0,0 +1,9 @@ | |||
1 | $wrapper | ||
2 | max-width $contentWidth | ||
3 | margin 0 auto | ||
4 | padding 2rem 2.5rem | ||
5 | @media (max-width: $MQNarrow) | ||
6 | padding 2rem | ||
7 | @media (max-width: $MQMobileNarrow) | ||
8 | padding 1.5rem | ||
9 | |||
diff --git a/doc/docs/.vuepress/theme/util/index.js b/doc/docs/.vuepress/theme/util/index.js new file mode 100644 index 0000000..92fcd3b --- /dev/null +++ b/doc/docs/.vuepress/theme/util/index.js | |||
@@ -0,0 +1,244 @@ | |||
1 | export const hashRE = /#.*$/ | ||
2 | export const extRE = /\.(md|html)$/ | ||
3 | export const endingSlashRE = /\/$/ | ||
4 | export const outboundRE = /^[a-z]+:/i | ||
5 | |||
6 | export function normalize (path) { | ||
7 | return decodeURI(path) | ||
8 | .replace(hashRE, '') | ||
9 | .replace(extRE, '') | ||
10 | } | ||
11 | |||
12 | export function getHash (path) { | ||
13 | const match = path.match(hashRE) | ||
14 | if (match) { | ||
15 | return match[0] | ||
16 | } | ||
17 | } | ||
18 | |||
19 | export function isExternal (path) { | ||
20 | return outboundRE.test(path) | ||
21 | } | ||
22 | |||
23 | export function isMailto (path) { | ||
24 | return /^mailto:/.test(path) | ||
25 | } | ||
26 | |||
27 | export function isTel (path) { | ||
28 | return /^tel:/.test(path) | ||
29 | } | ||
30 | |||
31 | export function ensureExt (path) { | ||
32 | if (isExternal(path)) { | ||
33 | return path | ||
34 | } | ||
35 | const hashMatch = path.match(hashRE) | ||
36 | const hash = hashMatch ? hashMatch[0] : '' | ||
37 | const normalized = normalize(path) | ||
38 | |||
39 | if (endingSlashRE.test(normalized)) { | ||
40 | return path | ||
41 | } | ||
42 | return normalized + '.html' + hash | ||
43 | } | ||
44 | |||
45 | export function isActive (route, path) { | ||
46 | const routeHash = decodeURIComponent(route.hash) | ||
47 | const linkHash = getHash(path) | ||
48 | if (linkHash && routeHash !== linkHash) { | ||
49 | return false | ||
50 | } | ||
51 | const routePath = normalize(route.path) | ||
52 | const pagePath = normalize(path) | ||
53 | return routePath === pagePath | ||
54 | } | ||
55 | |||
56 | export function resolvePage (pages, rawPath, base) { | ||
57 | if (isExternal(rawPath)) { | ||
58 | return { | ||
59 | type: 'external', | ||
60 | path: rawPath | ||
61 | } | ||
62 | } | ||
63 | if (base) { | ||
64 | rawPath = resolvePath(rawPath, base) | ||
65 | } | ||
66 | const path = normalize(rawPath) | ||
67 | for (let i = 0; i < pages.length; i++) { | ||
68 | if (normalize(pages[i].regularPath) === path) { | ||
69 | return Object.assign({}, pages[i], { | ||
70 | type: 'page', | ||
71 | path: ensureExt(pages[i].path) | ||
72 | }) | ||
73 | } | ||
74 | } | ||
75 | console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`) | ||
76 | return {} | ||
77 | } | ||
78 | |||
79 | function resolvePath (relative, base, append) { | ||
80 | const firstChar = relative.charAt(0) | ||
81 | if (firstChar === '/') { | ||
82 | return relative | ||
83 | } | ||
84 | |||
85 | if (firstChar === '?' || firstChar === '#') { | ||
86 | return base + relative | ||
87 | } | ||
88 | |||
89 | const stack = base.split('/') | ||
90 | |||
91 | // remove trailing segment if: | ||
92 | // - not appending | ||
93 | // - appending to trailing slash (last segment is empty) | ||
94 | if (!append || !stack[stack.length - 1]) { | ||
95 | stack.pop() | ||
96 | } | ||
97 | |||
98 | // resolve relative path | ||
99 | const segments = relative.replace(/^\//, '').split('/') | ||
100 | for (let i = 0; i < segments.length; i++) { | ||
101 | const segment = segments[i] | ||
102 | if (segment === '..') { | ||
103 | stack.pop() | ||
104 | } else if (segment !== '.') { | ||
105 | stack.push(segment) | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // ensure leading slash | ||
110 | if (stack[0] !== '') { | ||
111 | stack.unshift('') | ||
112 | } | ||
113 | |||
114 | return stack.join('/') | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * @param { Page } page | ||
119 | * @param { string } regularPath | ||
120 | * @param { SiteData } site | ||
121 | * @param { string } localePath | ||
122 | * @returns { SidebarGroup } | ||
123 | */ | ||
124 | export function resolveSidebarItems (page, regularPath, site, localePath) { | ||
125 | const { pages, themeConfig } = site | ||
126 | |||
127 | const localeConfig = localePath && themeConfig.locales | ||
128 | ? themeConfig.locales[localePath] || themeConfig | ||
129 | : themeConfig | ||
130 | |||
131 | const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar | ||
132 | if (pageSidebarConfig === 'auto') { | ||
133 | return resolveHeaders(page) | ||
134 | } | ||
135 | |||
136 | const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar | ||
137 | if (!sidebarConfig) { | ||
138 | return [] | ||
139 | } else { | ||
140 | const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig) | ||
141 | if (config === 'auto') { | ||
142 | return resolveHeaders(page) | ||
143 | } | ||
144 | return config | ||
145 | ? config.map(item => resolveItem(item, pages, base)) | ||
146 | : [] | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * @param { Page } page | ||
152 | * @returns { SidebarGroup } | ||
153 | */ | ||
154 | function resolveHeaders (page) { | ||
155 | const headers = groupHeaders(page.headers || []) | ||
156 | return [{ | ||
157 | type: 'group', | ||
158 | collapsable: false, | ||
159 | title: page.title, | ||
160 | path: null, | ||
161 | children: headers.map(h => ({ | ||
162 | type: 'auto', | ||
163 | title: h.title, | ||
164 | basePath: page.path, | ||
165 | path: page.path + '#' + h.slug, | ||
166 | children: h.children || [] | ||
167 | })) | ||
168 | }] | ||
169 | } | ||
170 | |||
171 | export function groupHeaders (headers) { | ||
172 | // group h3s under h2 | ||
173 | headers = headers.map(h => Object.assign({}, h)) | ||
174 | let lastH2 | ||
175 | headers.forEach(h => { | ||
176 | if (h.level === 2) { | ||
177 | lastH2 = h | ||
178 | } else if (lastH2) { | ||
179 | (lastH2.children || (lastH2.children = [])).push(h) | ||
180 | } | ||
181 | }) | ||
182 | return headers.filter(h => h.level === 2) | ||
183 | } | ||
184 | |||
185 | export function resolveNavLinkItem (linkItem) { | ||
186 | return Object.assign(linkItem, { | ||
187 | type: linkItem.items && linkItem.items.length ? 'links' : 'link' | ||
188 | }) | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * @param { Route } route | ||
193 | * @param { Array<string|string[]> | Array<SidebarGroup> | [link: string]: SidebarConfig } config | ||
194 | * @returns { base: string, config: SidebarConfig } | ||
195 | */ | ||
196 | export function resolveMatchingConfig (regularPath, config) { | ||
197 | if (Array.isArray(config)) { | ||
198 | return { | ||
199 | base: '/', | ||
200 | config: config | ||
201 | } | ||
202 | } | ||
203 | for (const base in config) { | ||
204 | if (ensureEndingSlash(regularPath).indexOf(encodeURI(base)) === 0) { | ||
205 | return { | ||
206 | base, | ||
207 | config: config[base] | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | return {} | ||
212 | } | ||
213 | |||
214 | function ensureEndingSlash (path) { | ||
215 | return /(\.html|\/)$/.test(path) | ||
216 | ? path | ||
217 | : path + '/' | ||
218 | } | ||
219 | |||
220 | function resolveItem (item, pages, base, groupDepth = 1) { | ||
221 | if (typeof item === 'string') { | ||
222 | return resolvePage(pages, item, base) | ||
223 | } else if (Array.isArray(item)) { | ||
224 | return Object.assign(resolvePage(pages, item[0], base), { | ||
225 | title: item[1] | ||
226 | }) | ||
227 | } else { | ||
228 | const children = item.children || [] | ||
229 | if (children.length === 0 && item.path) { | ||
230 | return Object.assign(resolvePage(pages, item.path, base), { | ||
231 | title: item.title | ||
232 | }) | ||
233 | } | ||
234 | return { | ||
235 | type: 'group', | ||
236 | path: item.path, | ||
237 | title: item.title, | ||
238 | sidebarDepth: item.sidebarDepth, | ||
239 | initialOpenGroupIndex: item.initialOpenGroupIndex, | ||
240 | children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)), | ||
241 | collapsable: item.collapsable !== false | ||
242 | } | ||
243 | } | ||
244 | } | ||
diff --git a/doc/docs/README.md b/doc/docs/README.md new file mode 100755 index 0000000..dfc01d1 --- /dev/null +++ b/doc/docs/README.md | |||
@@ -0,0 +1,8 @@ | |||
1 | --- | ||
2 | home: true | ||
3 | heroImage: ./image/yuescript.svg | ||
4 | tagline: A language that compiles to Lua | ||
5 | actionText: Quick Start → | ||
6 | actionLink: /doc/ | ||
7 | footer: Made by Jin with ❤️ | ||
8 | --- | ||
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md new file mode 100755 index 0000000..0d43d04 --- /dev/null +++ b/doc/docs/doc/README.md | |||
@@ -0,0 +1,594 @@ | |||
1 | --- | ||
2 | sidebar: auto | ||
3 | --- | ||
4 | |||
5 | <CompilerModal /> | ||
6 | |||
7 | # Yuescript | ||
8 | <img src="/image/yuescript.svg" width="300" height="300" alt="logo"/> | ||
9 | |||
10 | ## Introduction | ||
11 | |||
12 | Yuescript is a dynamic language that compiles to Lua. The codes written in Yuescript are expressive and extremely concise. And it is suitable for writing some changing application logic with more maintainable codes and runs in a Lua embeded environment such as games or website servers. | ||
13 | |||
14 | Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ]. | ||
15 | |||
16 | ### An Overview of Yuescript | ||
17 | ```moonscript | ||
18 | -- import syntax | ||
19 | import "yue" as :p, :to_lua | ||
20 | |||
21 | -- implicit objects | ||
22 | inventory = | ||
23 | equipment: | ||
24 | * "sword" | ||
25 | * "shield" | ||
26 | items: | ||
27 | * name: "potion" | ||
28 | count: 10 | ||
29 | * name: "bread" | ||
30 | count: 3 | ||
31 | |||
32 | -- backcall | ||
33 | {1, 2, 3} | ||
34 | |> map (x)-> x * 2 | ||
35 | |> filter (x)-> x > 4 | ||
36 | |> reduce 0, (a, b)-> a + b | ||
37 | |||
38 | |||
39 | -- metatable manipulation | ||
40 | apple = | ||
41 | size: 15 | ||
42 | index#: {color: 0x00ffff} | ||
43 | p apple.color, apple.#?, apple.index# | ||
44 | |||
45 | -- js-like export syntax | ||
46 | export yuescript = "月之脚本" | ||
47 | ``` | ||
48 | <YueDisplay> | ||
49 | <pre> | ||
50 | -- import syntax | ||
51 | import "yue" as :p, :to_lua | ||
52 | |||
53 | -- implicit objects | ||
54 | inventory = | ||
55 | equipment: | ||
56 | * "sword" | ||
57 | * "shield" | ||
58 | items: | ||
59 | * name: "potion" | ||
60 | count: 10 | ||
61 | * name: "bread" | ||
62 | count: 3 | ||
63 | |||
64 | -- backcall | ||
65 | {1, 2, 3} | ||
66 | |> map (x)-> x * 2 | ||
67 | |> filter (x)-> x > 4 | ||
68 | |> reduce 0, (a, b)-> a + b | ||
69 | |||
70 | |||
71 | -- metatable manipulation | ||
72 | apple = | ||
73 | size: 15 | ||
74 | index#: {color: 0x00ffff} | ||
75 | p apple.color, apple.#?, apple.index# | ||
76 | |||
77 | -- js-like export syntax | ||
78 | export yuescript = "月之脚本" | ||
79 | </pre> | ||
80 | </YueDisplay> | ||
81 | |||
82 | ## Installation | ||
83 | |||
84 | * **Lua Module** | ||
85 | |||
86 |   Install [luarocks](https://luarocks.org), a package manager for Lua modules. Then install it as a Lua module and executable with: | ||
87 | |||
88 | ``` | ||
89 | > luarocks install yuescript | ||
90 | ``` | ||
91 | |||
92 |   Or you can build `yue.so` file with: | ||
93 | |||
94 | ``` | ||
95 | > make shared LUAI=/usr/local/include/lua LUAL=/usr/local/lib/lua | ||
96 | ``` | ||
97 | |||
98 |   Then get the binary file from path **bin/shared/yue.so**. | ||
99 | |||
100 | * **Binary Tool** | ||
101 | |||
102 |   Clone this repo, then build and install executable with: | ||
103 | ``` | ||
104 | > make install | ||
105 | ``` | ||
106 | |||
107 |   Build Yuescript tool without macro feature: | ||
108 | ``` | ||
109 | > make install NO_MACRO=true | ||
110 | ``` | ||
111 | |||
112 |   Build Yuescript tool without built-in Lua binary: | ||
113 | ``` | ||
114 | > make install NO_LUA=true | ||
115 | ``` | ||
116 | |||
117 | ## Usage | ||
118 | |||
119 |   Require the Yuescript module in Lua: | ||
120 | ```Lua | ||
121 | -- require `main.yue` in Lua | ||
122 | require("yue")("main") | ||
123 | |||
124 | -- use the Yuescript compiler in Lua | ||
125 | local yue = require("yue") | ||
126 | local codes, err, globals = yue.to_lua([[ | ||
127 | f = -> | ||
128 | print "hello world" | ||
129 | f! | ||
130 | ]],{ | ||
131 | implicit_return_root = true, | ||
132 | reserve_line_number = true, | ||
133 | lint_global = true | ||
134 | }) | ||
135 | ``` | ||
136 |   Use Yuescript tool with: | ||
137 | ``` | ||
138 | > yue -h | ||
139 | Usage: yue [options|files|directories] ... | ||
140 | |||
141 | -h Print this message | ||
142 | -e str Execute a file or raw codes | ||
143 | -t path Specify where to place compiled files | ||
144 | -o file Write output to file | ||
145 | -s Use spaces in generated codes instead of tabs | ||
146 | -m Generate minified codes | ||
147 | -p Write output to standard out | ||
148 | -b Dump compile time (doesn't write output) | ||
149 | -l Write line numbers from source codes | ||
150 | -v Print version | ||
151 | -- Read from standard in, print to standard out | ||
152 | (Must be first and only argument) | ||
153 | |||
154 | Execute without options to enter REPL, type symbol '$' | ||
155 | in a single line to start/stop multi-line mode | ||
156 | ``` | ||
157 |   Use cases: | ||
158 |   Recursively compile every Yuescript file with extension **.yue** under current path: **yue .** | ||
159 |   Compile and save results to a target path: **yue -t /target/path/ .** | ||
160 |   Compile and reserve debug info: **yue -l .** | ||
161 |   Compile and generate minified codes: **yue -m .** | ||
162 |   Execute raw codes: **yue -e 'print 123'** | ||
163 |   Execute a Yuescript file: **yue -e main.yue** | ||
164 | |||
165 | ## Macro | ||
166 | |||
167 | ### Common Usage | ||
168 | Macro function is used for evaluating a string in the compile time and insert the generated codes into final compilation. | ||
169 | |||
170 | ```moonscript | ||
171 | macro config = (debugging)-> | ||
172 | global debugMode = debugging == "true" | ||
173 | "" | ||
174 | |||
175 | macro asserts = (cond)-> | ||
176 | debugMode and "assert #{cond}" or "" | ||
177 | |||
178 | macro assert = (cond)-> | ||
179 | debugMode and "assert #{cond}" or "#{cond}" | ||
180 | |||
181 | $config true | ||
182 | $asserts item ~= nil | ||
183 | |||
184 | $config false | ||
185 | value = $assert item | ||
186 | |||
187 | -- the passed expressions are treated as strings | ||
188 | macro and = (...)-> "#{ table.concat {...}, ' and ' }" | ||
189 | if $and f1!, f2!, f3! | ||
190 | print "OK" | ||
191 | ``` | ||
192 | <YueDisplay> | ||
193 | <pre> | ||
194 | macro config = (debugging)-> | ||
195 | global debugMode = debugging == "true" | ||
196 | "" | ||
197 | |||
198 | macro asserts = (cond)-> | ||
199 | debugMode and "assert #{cond}" or "" | ||
200 | |||
201 | macro assert = (cond)-> | ||
202 | debugMode and "assert #{cond}" or "#{cond}" | ||
203 | |||
204 | $config true | ||
205 | $asserts item ~= nil | ||
206 | |||
207 | $config false | ||
208 | value = $assert item | ||
209 | |||
210 | -- the passed expressions are treated as strings | ||
211 | macro and = (...)-> "#{ table.concat {...}, ' and ' }" | ||
212 | if $and f1!, f2!, f3! | ||
213 | print "OK" | ||
214 | </pre> | ||
215 | </YueDisplay> | ||
216 | |||
217 | ### Insert Raw Codes | ||
218 | |||
219 | A macro function can either return a Yuescript string or a config table containing Lua codes. | ||
220 | ```moonscript | ||
221 | macro yueFunc = (var)-> "local #{var} = ->" | ||
222 | $yueFunc funcA | ||
223 | funcA = -> "assign the Yue defined variable" | ||
224 | |||
225 | -- take care and let Yuescript know the | ||
226 | -- local variables you declared in Lua code | ||
227 | macro luaFunc = (var)-> { | ||
228 | codes: "local function #{var}() end" | ||
229 | type: "lua" | ||
230 | locals: {var} | ||
231 | } | ||
232 | $luaFunc funcB | ||
233 | funcB = -> "assign the Lua defined variable" | ||
234 | |||
235 | macro lua = (code)-> { | ||
236 | :code | ||
237 | type: "lua" | ||
238 | } | ||
239 | |||
240 | -- the raw string leading and ending symbols are auto trimed | ||
241 | $lua[==[ | ||
242 | -- raw Lua codes insertion | ||
243 | if cond then | ||
244 | print("output") | ||
245 | end | ||
246 | ]==] | ||
247 | ``` | ||
248 | <YueDisplay> | ||
249 | <pre> | ||
250 | macro yueFunc = (var)-> "local #{var} = ->" | ||
251 | $yueFunc funcA | ||
252 | funcA = -> "assign the Yue defined variable" | ||
253 | |||
254 | -- take care and let Yuescript know the | ||
255 | -- local variables you declared in Lua codes | ||
256 | macro luaFunc = (var)-> { | ||
257 | codes: "local function #{var}() end" | ||
258 | type: "lua" | ||
259 | locals: {var} | ||
260 | } | ||
261 | $luaFunc funcB | ||
262 | funcB = -> "assign the Lua defined variable" | ||
263 | |||
264 | macro lua = (code)-> { | ||
265 | :code | ||
266 | type: "lua" | ||
267 | } | ||
268 | |||
269 | -- the raw string leading and ending symbols are auto trimed | ||
270 | $lua[==[ | ||
271 | -- raw Lua codes insertion | ||
272 | if cond then | ||
273 | print("output") | ||
274 | end | ||
275 | ]==] | ||
276 | </pre> | ||
277 | </YueDisplay> | ||
278 | |||
279 | ### Export Macro | ||
280 | |||
281 | Macro functions can be exported from a module and get imported in another module. It is recommanded to export macro functions in a single file to speed up compilation. | ||
282 | ```moonscript | ||
283 | -- file: utils.yue | ||
284 | export macro map = (items, action)-> "[#{action} for _ in *#{items}]" | ||
285 | export macro filter = (items, action)-> "[_ for _ in *#{items} when #{action}]" | ||
286 | export macro foreach = (items, action)-> "for _ in *#{items} | ||
287 | #{action}" | ||
288 | |||
289 | -- file main.yue | ||
290 | import "utils" as { | ||
291 | $, -- symbol to import all macros | ||
292 | $foreach: $each -- rename macro $foreach to $each | ||
293 | } | ||
294 | {1, 2, 3} |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
295 | ``` | ||
296 | <YueDisplay> | ||
297 | <pre> | ||
298 | -- file: utils.yue | ||
299 | export macro map = (items, action)-> "[#{action} for _ in *#{items}]" | ||
300 | export macro filter = (items, action)-> "[_ for _ in *#{items} when #{action}]" | ||
301 | export macro foreach = (items, action)-> "for _ in *#{items} | ||
302 | #{action}" | ||
303 | |||
304 | -- file main.yue | ||
305 | -- import function is not available in browser, try it in a real environment | ||
306 | --[[ | ||
307 | import "utils" as { | ||
308 | $, -- symbol to import all macros | ||
309 | $foreach: $each -- rename macro $foreach to $each | ||
310 | } | ||
311 | {1, 2, 3} |> $map(_ * 2) |> $filter(_ > 4) |> $each print _ | ||
312 | ]] | ||
313 | </pre> | ||
314 | </YueDisplay> | ||
315 | |||
316 | ## Special Operator | ||
317 | |||
318 | ### Metatable | ||
319 | |||
320 | The **#** operator can be used as a shortcut for metatable manipulation. | ||
321 | |||
322 | * **Metatable Creation** | ||
323 | Create normal table with key **#** or metamethod key that ends with **#**. | ||
324 | |||
325 | ```moonscript | ||
326 | mt = {} | ||
327 | add = (right)=> #: mt, value: @value + right.value | ||
328 | mt.__add = add | ||
329 | |||
330 | a = #: mt, value: 1 | ||
331 | -- set field with variable of the same name | ||
332 | b = :add#, value: 2 | ||
333 | c = add#: mt.__add, value: 3 | ||
334 | |||
335 | d = a + b + c | ||
336 | print d.value | ||
337 | |||
338 | close _ = close#: -> print "out of scope" | ||
339 | ``` | ||
340 | <YueDisplay> | ||
341 | <pre> | ||
342 | mt = {} | ||
343 | add = (right)=> #: mt, value: @value + right.value | ||
344 | mt.__add = add | ||
345 | |||
346 | a = #: mt, value: 1 | ||
347 | -- set field with variable of the same name | ||
348 | b = :add#, value: 2 | ||
349 | c = add#: mt.__add, value: 3 | ||
350 | |||
351 | d = a + b + c | ||
352 | print d.value | ||
353 | |||
354 | close _ = close#: -> print "out of scope" | ||
355 | </pre> | ||
356 | </YueDisplay> | ||
357 | |||
358 | * **Metatable Accessing** | ||
359 | Accessing metatable with key **#** or metamethod key that ends with **#**. | ||
360 | |||
361 | ```moonscript | ||
362 | -- create with metatable containing field "value" | ||
363 | tb = ["value"]#: 123 | ||
364 | tb.index# = tb.# | ||
365 | print tb.value | ||
366 | |||
367 | tb.# = __index: {item: "hello"} | ||
368 | print tb.item | ||
369 | ``` | ||
370 | <YueDisplay> | ||
371 | <pre> | ||
372 | -- create with metatable containing field "value" | ||
373 | tb = ["value"]#: 123 | ||
374 | tb.index# = tb.# | ||
375 | print tb.value | ||
376 | |||
377 | tb.# = __index: {item: "hello"} | ||
378 | print tb.item | ||
379 | </pre> | ||
380 | </YueDisplay> | ||
381 | |||
382 | * **Metatable Destructure** | ||
383 | Destruct metatable with metamethod key that ends with **#**. | ||
384 | |||
385 | ```moonscript | ||
386 | {item, :new, :close#, index#: getter} = tb | ||
387 | print item, new, close, getter | ||
388 | ``` | ||
389 | <YueDisplay> | ||
390 | <pre> | ||
391 | {item, :new, :close#, index#: getter} = tb | ||
392 | print item, new, close, getter | ||
393 | </pre> | ||
394 | </YueDisplay> | ||
395 | |||
396 | ### Existence | ||
397 | |||
398 | The **?** operator can be used in a variety of contexts to check for existence. | ||
399 | |||
400 | ```moonscript | ||
401 | func?! | ||
402 | print abc?["hello world"]?.xyz | ||
403 | |||
404 | x = tab?.value | ||
405 | len = utf8?.len or string?.len or (o)-> #o | ||
406 | |||
407 | if print and x? | ||
408 | print x | ||
409 | |||
410 | with? io.open "test.txt", "w" | ||
411 | \write "hello" | ||
412 | \close! | ||
413 | ``` | ||
414 | <YueDisplay> | ||
415 | <pre> | ||
416 | func?! | ||
417 | print abc?["hello world"]?.xyz | ||
418 | |||
419 | x = tab?.value | ||
420 | len = utf8?.len or string?.len or (o)-> #o | ||
421 | |||
422 | if print and x? | ||
423 | print x | ||
424 | |||
425 | with? io.open "test.txt", "w" | ||
426 | \write "hello" | ||
427 | \close! | ||
428 | </pre> | ||
429 | </YueDisplay> | ||
430 | |||
431 | ### Piping | ||
432 | |||
433 | Instead of a series of nested function calls, you can pipe values with operator **|>**. | ||
434 | ```moonscript | ||
435 | "hello" |> print | ||
436 | 1 |> print 2 -- insert pipe item as the first argument | ||
437 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
438 | |||
439 | -- pipe expression in multiline | ||
440 | readFile "example.txt" | ||
441 | |> extract language, {} | ||
442 | |> parse language | ||
443 | |> emit | ||
444 | |> render | ||
445 | |||
446 | ``` | ||
447 | <YueDisplay> | ||
448 | <pre> | ||
449 | "hello" |> print | ||
450 | 1 |> print 2 -- insert pipe item as the first argument | ||
451 | 2 |> print 1, _, 3 -- pipe with a placeholder | ||
452 | |||
453 | -- pipe expression in multiline | ||
454 | readFile "example.txt" | ||
455 | |> extract language, {} | ||
456 | |> parse language | ||
457 | |> emit | ||
458 | |> render | ||
459 | |||
460 | </pre> | ||
461 | </YueDisplay> | ||
462 | |||
463 | ## Module | ||
464 | |||
465 | ### Import | ||
466 | |||
467 | The import statement is a syntax sugar for requiring a module or help extracting items from an imported module. | ||
468 | |||
469 | ```moonscript | ||
470 | -- used as table destructure | ||
471 | do | ||
472 | import C, Ct, Cmt from require "lpeg" | ||
473 | import insert, concat from table | ||
474 | |||
475 | -- shortcut for requring a module | ||
476 | do | ||
477 | import 'module' | ||
478 | import 'module_x' | ||
479 | import "d-a-s-h-e-s" | ||
480 | import "module.part" | ||
481 | |||
482 | -- requring module with aliasing or table destruction | ||
483 | do | ||
484 | import "player" as PlayerModule | ||
485 | import "lpeg" as :C, :Ct, :Cmt | ||
486 | import "export" as {one, two, Something:{umm:{ch}}} | ||
487 | ``` | ||
488 | <YueDisplay> | ||
489 | <pre> | ||
490 | -- used as table destruction | ||
491 | do | ||
492 | import C, Ct, Cmt from require "lpeg" | ||
493 | import insert, concat from table | ||
494 | |||
495 | -- shortcut for requring a module | ||
496 | do | ||
497 | import 'module' | ||
498 | import 'module_x' | ||
499 | import "d-a-s-h-e-s" | ||
500 | import "module.part" | ||
501 | |||
502 | -- requring module with aliasing or table destruction | ||
503 | do | ||
504 | import "player" as PlayerModule | ||
505 | import "lpeg" as :C, :Ct, :Cmt | ||
506 | import "export" as {one, two, Something:{umm:{ch}}} | ||
507 | </pre> | ||
508 | </YueDisplay> | ||
509 | |||
510 | ### Export | ||
511 | |||
512 | The export statement offers a concise way to define modules. | ||
513 | |||
514 | * **Named Export** | ||
515 | Named export will define a local variable as well as adding a field in the exported table. | ||
516 | |||
517 | ```moonscript | ||
518 | export a, b, c = 1, 2, 3 | ||
519 | export cool = "cat" | ||
520 | |||
521 | export What = if this | ||
522 | "abc" | ||
523 | else | ||
524 | "def" | ||
525 | |||
526 | export y = -> | ||
527 | hallo = 3434 | ||
528 | |||
529 | export class Something | ||
530 | umm: "cool" | ||
531 | ``` | ||
532 | <YueDisplay> | ||
533 | <pre> | ||
534 | export a, b, c = 1, 2, 3 | ||
535 | export cool = "cat" | ||
536 | |||
537 | export What = if this | ||
538 | "abc" | ||
539 | else | ||
540 | "def" | ||
541 | |||
542 | export y = -> | ||
543 | hallo = 3434 | ||
544 | |||
545 | export class Something | ||
546 | umm: "cool" | ||
547 | </pre> | ||
548 | </YueDisplay> | ||
549 | |||
550 | * **Unnamed Export** | ||
551 | Unnamed export will add the target item into the array part of the exported table. | ||
552 | |||
553 | ```moonscript | ||
554 | d, e, f = 3, 2, 1 | ||
555 | export d, e, f | ||
556 | |||
557 | export if this | ||
558 | 123 | ||
559 | else | ||
560 | 456 | ||
561 | |||
562 | export with tmp | ||
563 | j = 2000 | ||
564 | ``` | ||
565 | <YueDisplay> | ||
566 | <pre> | ||
567 | d, e, f = 3, 2, 1 | ||
568 | export d, e, f | ||
569 | |||
570 | export if this | ||
571 | 123 | ||
572 | else | ||
573 | 456 | ||
574 | |||
575 | export with tmp | ||
576 | j = 2000 | ||
577 | </pre> | ||
578 | </YueDisplay> | ||
579 | |||
580 | * **Default Export** | ||
581 | Using the **default** keyword in export statement to replace the exported table with any thing. | ||
582 | |||
583 | ```moonscript | ||
584 | export default -> | ||
585 | print "hello" | ||
586 | 123 | ||
587 | ``` | ||
588 | <YueDisplay> | ||
589 | <pre> | ||
590 | export default -> | ||
591 | print "hello" | ||
592 | 123 | ||
593 | </pre> | ||
594 | </YueDisplay> \ No newline at end of file | ||
diff --git a/doc/docs/try/README.md b/doc/docs/try/README.md new file mode 100755 index 0000000..d6ba5dd --- /dev/null +++ b/doc/docs/try/README.md | |||
@@ -0,0 +1,6 @@ | |||
1 | # Yuescript Online Compiler | ||
2 | --- | ||
3 | |||
4 | Try Yuescript in the browser with WASM. | ||
5 | |||
6 | <YueCompiler /> | ||