├── .gitattributes ├── .gitignore ├── src ├── event.js ├── css │ ├── global.css │ ├── injected-components.css │ ├── main.css │ ├── prism.css │ └── page-content.css ├── utils │ ├── constants.js │ ├── removeMarkdownExtension.js │ ├── load.js │ ├── alternativeComponents.js │ ├── highlight.js │ ├── parseCodeOptions.js │ ├── index.js │ ├── __test__ │ │ └── index.test.js │ ├── prismLanguages.json │ ├── cssVariables.js │ └── markedRenderer.js ├── plugins │ ├── search │ │ ├── index.js │ │ └── SearchBar.vue │ ├── i18n │ │ ├── index.js │ │ └── LanguageSelector.vue │ ├── versions │ │ ├── index.js │ │ └── VersionsSelector.vue │ ├── evaluateContent │ │ └── index.js │ ├── dark-theme-toggler │ │ ├── index.js │ │ └── DarkThemeToggler.vue │ └── banner-footer │ │ └── index.js ├── components │ ├── SidebarMask.vue │ ├── InjectedComponents.js │ ├── icons │ │ └── ExternalLinkIcon.vue │ ├── Gist.vue │ ├── Badge.vue │ ├── ImageZoom.vue │ ├── UniLink.vue │ ├── EditLink.vue │ ├── Loading.vue │ ├── PageToc.vue │ ├── SidebarToggle.vue │ ├── Root.vue │ ├── Note.vue │ ├── PrevNextLinks.vue │ ├── DocuteSelect.vue │ ├── Sidebar.vue │ ├── Header.vue │ ├── HeaderNav.vue │ └── SidebarItem.vue ├── router.js ├── hooks.js ├── PluginAPI.js ├── index.js ├── views │ └── Home.vue └── store.js ├── .prettierrc ├── .babelrc.js ├── .editorconfig ├── website ├── docs │ ├── zh │ │ ├── credits.md │ │ ├── guide │ │ │ ├── use-with-bundlers.md │ │ │ ├── internationalization.md │ │ │ ├── plugin.md │ │ │ ├── use-vue-in-markdown.md │ │ │ ├── deployment.md │ │ │ ├── offline-support.md │ │ │ ├── customization.md │ │ │ └── markdown-features.md │ │ ├── plugin-api.md │ │ ├── README.md │ │ ├── builtin-components.md │ │ └── options.md │ ├── credits.md │ ├── sw.js │ ├── guide │ │ ├── use-with-bundlers.md │ │ ├── internationalization.md │ │ ├── plugin.md │ │ ├── use-vue-in-markdown.md │ │ ├── deployment.md │ │ ├── offline-support.md │ │ ├── customization.md │ │ └── markdown-features.md │ ├── plugin-api.md │ ├── README.md │ ├── builtin-components.md │ └── options.md ├── components │ └── ColorBox.vue └── index.js ├── postcss.config.js ├── .github └── FUNDING.yml ├── release.config.js ├── now.json ├── circle.yml ├── LICENSE ├── README.md └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | /lib 4 | -------------------------------------------------------------------------------- /src/event.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default new Vue() 4 | -------------------------------------------------------------------------------- /src/css/global.css: -------------------------------------------------------------------------------- 1 | @import "main.css"; 2 | @import "injected-components.css"; 3 | -------------------------------------------------------------------------------- /src/utils/constants.js: -------------------------------------------------------------------------------- 1 | export const INITIAL_STATE_NAME = '__DOCUTE_INITIAL_STATE__' 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "useTabs": false 5 | } 6 | -------------------------------------------------------------------------------- /src/plugins/search/index.js: -------------------------------------------------------------------------------- 1 | import SearchBar from './SearchBar.vue' 2 | 3 | export default { 4 | name: 'search', 5 | extend(api) { 6 | api.registerComponent('header-right:start', SearchBar) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.babelrc.js: -------------------------------------------------------------------------------- 1 | const IS_TEST = process.env.NODE_ENV === 'test' 2 | 3 | module.exports = { 4 | presets: [ 5 | ['minimal', { 6 | mode: 'loose' 7 | }], 8 | IS_TEST && 'power-assert' 9 | ].filter(Boolean) 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /src/utils/removeMarkdownExtension.js: -------------------------------------------------------------------------------- 1 | const RE = /\.md$/ 2 | 3 | export default input => { 4 | let [path, hash] = input.split('#') 5 | if (RE.test(path)) { 6 | path = path.replace(RE, '') 7 | } 8 | return `${path}${hash ? `#${hash}` : ''}` 9 | } 10 | -------------------------------------------------------------------------------- /website/docs/zh/credits.md: -------------------------------------------------------------------------------- 1 | # 致谢 2 | 3 | Docute 的 UI 灵感来源于下列网站: 4 | 5 | - [Vue.js](https://vuejs.org) 6 | - [ZEIT Docs](https://zeit.co/docs) 7 | 8 | Docute 是一个开源项目,因此也使用了很多优秀的开源项目,比如: 9 | 10 |
${text}`
44 | const origCode = renderer.code
45 | renderer.code = function(code, lang, escaped, opts) {
46 | opts = opts || {}
47 | const {env} = this.options
48 |
49 | if (opts.mixin) {
50 | env.mixins.push(code)
51 | return ''
52 | }
53 |
54 | let res = origCode.call(this, code, lang, escaped)
55 |
56 | if (!opts.interpolate) {
57 | res = res.replace(/^/, '')
58 | }
59 |
60 | if (opts.highlight) {
61 | const codeMask = code
62 | .split('\n')
63 | .map((v, i) => {
64 | i += 1
65 | const shouldHighlight = opts.highlight.some(number => {
66 | if (typeof number === 'number') {
67 | return number === i
68 | }
69 | if (typeof number === 'string') {
70 | const [start, end] = number.split('-').map(Number)
71 | return i >= start && (!end || i <= end)
72 | }
73 | return false
74 | })
75 | const escapedLine = v ? marked.escape(v) : ''
76 | return shouldHighlight
77 | ? `${escapedLine}`
78 | : `${escapedLine}`
79 | })
80 | .join('')
81 | res += `${codeMask}`
84 | }
85 |
86 | return `${res}`
87 | }
88 |
89 | return hooks.process('extendMarkedRenderer', renderer)
90 | }
91 |
--------------------------------------------------------------------------------
/src/components/Sidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
84 |
85 |
120 |
--------------------------------------------------------------------------------
/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
73 |
74 |
144 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import {sync} from 'vuex-router-sync'
3 | import PluginAPI from './PluginAPI'
4 | import Root from './components/Root.vue'
5 | import store from './store'
6 | import createRouter from './router'
7 | import {inBrowser} from './utils'
8 | import alternativeComponents from './utils/alternativeComponents'
9 | import ImageZoom from './components/ImageZoom.vue'
10 | import Badge from './components/Badge.vue'
11 | import DocuteSelect from './components/DocuteSelect.vue'
12 | import Note from './components/Note.vue'
13 | import Gist from './components/Gist.vue'
14 | import Loading from './components/Loading.vue'
15 | import ExternalLinkIcon from './components/icons/ExternalLinkIcon.vue'
16 | import {INITIAL_STATE_NAME} from './utils/constants'
17 |
18 | // Built-in plugins
19 | import i18nPlugin from './plugins/i18n'
20 | import evaluateContentPlugin from './plugins/evaluateContent'
21 | import versionsPlugin from './plugins/versions'
22 | import bannerFooter from './plugins/banner-footer'
23 | import darkThemeToggler from './plugins/dark-theme-toggler'
24 | import searchPlugin from './plugins/search'
25 |
26 | Vue.component(ImageZoom.name, ImageZoom)
27 | Vue.component(Badge.name, Badge)
28 | Vue.component(DocuteSelect.name, DocuteSelect)
29 | Vue.component(Note.name, Note)
30 | Vue.component(ExternalLinkIcon.name, ExternalLinkIcon)
31 | Vue.component(Gist.name, Gist)
32 | Vue.component(Loading.name, Loading)
33 | Vue.use(alternativeComponents)
34 |
35 | Vue.mixin({
36 | created() {
37 | const pluginApi = this.$options.pluginApi || this.$root.$pluginApi
38 | if (pluginApi) {
39 | this.$pluginApi = pluginApi
40 | }
41 | }
42 | })
43 |
44 | class Docute {
45 | constructor(config = {}) {
46 | const router = createRouter(config.router)
47 | sync(store, router)
48 |
49 | this.router = router
50 | this.store = store
51 |
52 | store.commit('SET_CONFIG', {
53 | title: inBrowser && document.title,
54 | ...config
55 | })
56 |
57 | const plugins = [
58 | i18nPlugin,
59 | evaluateContentPlugin,
60 | versionsPlugin,
61 | bannerFooter,
62 | darkThemeToggler,
63 | searchPlugin,
64 | ...(store.state.originalConfig.plugins || [])
65 | ]
66 | this.pluginApi = new PluginAPI({plugins, store, router})
67 | this.applyPlugins()
68 |
69 | this.app = new Vue({
70 | router,
71 | store,
72 | pluginApi: this.pluginApi,
73 | render: h => h(Root)
74 | })
75 |
76 | if (config.mount !== false) {
77 | this.mount()
78 | }
79 | }
80 |
81 | mount() {
82 | const {target} = store.getters
83 | // Force hydration when there's initial state
84 | if (window[INITIAL_STATE_NAME]) {
85 | this.app.$mount(`#${target}`, true)
86 | } else {
87 | this.app.$mount(`#${target}`)
88 | }
89 | return this
90 | }
91 |
92 | /**
93 | * @private
94 | */
95 | applyPlugins() {
96 | for (const plugin of this.pluginApi.plugins) {
97 | plugin.extend(this.pluginApi)
98 | }
99 | }
100 | }
101 |
102 | Docute.version = __DOCUTE_VERSION__
103 |
104 | export default Docute
105 |
106 | if (typeof window !== 'undefined') {
107 | window.Vue = Vue
108 | // eslint-disable-next-line
109 | window['__DOCUTE_VERSION__'] = __DOCUTE_VERSION__
110 | }
111 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docute",
3 | "version": "4.11.0",
4 | "scripts": {
5 | "build:umd": "poi --config build/poi.lib.config.js --prod",
6 | "build:es": "vue-compile src --config build/vue-compile.config.js",
7 | "build": "npm run build:umd && npm run build:es",
8 | "test": "npm run lint && npm run test:unit",
9 | "lint": "xo",
10 | "website": "poi --serve --config build/poi.website.config.js",
11 | "build:website": "poi --prod --config build/poi.website.config.js",
12 | "now-build": "npm run build:website",
13 | "prepublishOnly": "npm run build",
14 | "commit": "git-cz",
15 | "test:unit": "poi puppet src/**/*.test.js --test --plugin @poi/puppet --framework mocha"
16 | },
17 | "dependencies": {
18 | "jump.js": "^1.0.2",
19 | "loadjs": "^3.5.4",
20 | "marked": "^0.7.0",
21 | "medium-zoom": "^1.0.2",
22 | "prismjs": "^1.15.0",
23 | "throttle-debounce": "^2.1.0",
24 | "vue": "^2.6.10",
25 | "vue-content-loader": "^0.2.1",
26 | "vue-router": "^3.0.1",
27 | "vue-router-prefetch": "^1.1.1",
28 | "vue-template-compiler": "^2.6.10",
29 | "vuex": "^3.0.1",
30 | "vuex-router-sync": "^5.0.0"
31 | },
32 | "devDependencies": {
33 | "@babel/plugin-syntax-object-rest-spread": "^7.0.0",
34 | "@poi/plugin-puppet": "^0.1.4",
35 | "@semantic-release/git": "^7.0.5",
36 | "babel-preset-minimal": "^0.1.1",
37 | "babel-preset-power-assert": "^3.0.0",
38 | "bili": "^4.8.1",
39 | "commitizen": "^3.0.5",
40 | "cz-conventional-changelog": "^2.1.0",
41 | "docute-google-analytics": "^1.1.0",
42 | "eslint-config-rem": "^3.0.0",
43 | "eslint-plugin-vue": "^5.0.0-beta.3",
44 | "fast-async": "^6.3.8",
45 | "html-template-tag": "^2.0.0",
46 | "husky": "^1.0.1",
47 | "lint-staged": "^7.3.0",
48 | "poi": "^12.4.8",
49 | "postcss-import": "^12.0.0",
50 | "postcss-preset-env": "^6.0.3",
51 | "power-assert": "^1.6.1",
52 | "rollup-plugin-vue": "^4.3.2",
53 | "semantic-release": "^15.12.0",
54 | "vue-compile": "^0.3.1",
55 | "webpack-node-externals": "^1.7.2",
56 | "xo": "^0.23.0"
57 | },
58 | "repository": {
59 | "url": "egoist/docute",
60 | "type": "git"
61 | },
62 | "main": "dist/docute.js",
63 | "module": "lib/index.js",
64 | "files": [
65 | "dist",
66 | "lib",
67 | "!**/__test__/**"
68 | ],
69 | "description": "Effortlessly documentation done right.",
70 | "author": "egoist <0x142857@gmail.com>",
71 | "license": "MIT",
72 | "xo": {
73 | "extends": [
74 | "rem",
75 | "plugin:vue/essential"
76 | ],
77 | "prettier": true,
78 | "ignores": [
79 | "**/website/**",
80 | "**/dist/**"
81 | ],
82 | "envs": [
83 | "browser",
84 | "mocha"
85 | ],
86 | "globals": [
87 | "__DOCUTE_VERSION__"
88 | ],
89 | "extensions": [
90 | "vue"
91 | ],
92 | "rules": {
93 | "unicorn/filename-case": "off",
94 | "unicorn/no-abusive-eslint-disable": "off",
95 | "require-atomic-updates": "off"
96 | }
97 | },
98 | "husky": {
99 | "hooks": {
100 | "pre-commit": "lint-staged"
101 | }
102 | },
103 | "lint-staged": {
104 | "*.{js,css,md,vue}": [
105 | "xo --fix",
106 | "git add"
107 | ]
108 | },
109 | "config": {
110 | "commitizen": {
111 | "path": "./node_modules/cz-conventional-changelog"
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/website/docs/zh/guide/customization.md:
--------------------------------------------------------------------------------
1 | # 自定义
2 |
3 | Cusotmizing Docute is as fun as playing with Lego bricks.
4 |
5 | ## 导航栏
6 |
7 | ```js
8 | new Docute({
9 | title: 'Docute',
10 | nav: [
11 | {
12 | title: 'Home',
13 | link: '/'
14 | },
15 | {
16 | title: 'GitHub',
17 | link: 'https://github.com/egoist/docute'
18 | },
19 | // A dropdown menu
20 | {
21 | title: 'Community',
22 | children: [
23 | {
24 | title: 'Spectrum',
25 | link: 'https://spectrum.chat/your-community'
26 | },
27 | {
28 | title: 'Discord',
29 | link: 'https://discord.app/your-discord-server'
30 | }
31 | ]
32 | }
33 | ]
34 | })
35 | ```
36 |
37 | `title` 选项的默认值是 `` 标签的内容,因此这个选项不是必需的。
38 |
39 | 显示效果请参考本站的导航栏。
40 |
41 | ## 侧边栏
42 |
43 | 侧边栏一般用于跨页面的导航, 不过正如本站的导航栏,它也显示了一个版本选择器和语言选择器。
44 |
45 | ```js
46 | new Docute({
47 | sidebar: [
48 | // A sidebar item, with child links
49 | {
50 | title: 'Guide',
51 | children: [
52 | {
53 | title: 'Getting Started',
54 | link: '/guide/getting-started'
55 | },
56 | {
57 | title: 'Installation',
58 | link: '/guide/installation'
59 | }
60 | ]
61 | },
62 | // An external link
63 | {
64 | title: 'GitHub',
65 | link: 'https://github.com/egoist/docute'
66 | }
67 | ]
68 | })
69 | ```
70 |
71 | 查看 [sidebar](../options.md#sidebar) 选项的文档来了解更多细节。
72 |
73 | ## 布局
74 |
75 | Docute 默认使用宽屏布局, 但是也有其他选项:
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | ```js {interpolate:true}
84 | new Docute({
85 | layout: '{{ $store.state.originalConfig.layout }}'
86 | })
87 | ```
88 |
89 | ## 多版本文档
90 |
91 | 假设你的 Git 项目有一个 `master` 分支用于存放最新文档,以及 `v0.1` `v0.2` 分支用于旧版本的文档,你可以用一个 Docute 文档网站来显示多个版本的文档,通过使用 [`overrides`](../options.md#overrides) 和 [`sourcePath`](../options.md#sourcepath) 选项就能办到。
92 |
93 | ```js
94 | // 让这些路径从不同的地方获取 Markdown 文件
95 | overrides: {
96 | '/v0.1/': {
97 | sourcePath: 'https://raw.githubusercontent.com/user/repo/v0.1'
98 | },
99 | '/v0.2/': {
100 | sourcePath: 'https://raw.githubusercontent.com/user/repo/v0.2'
101 | }
102 | },
103 | // 用 `versions` 选项在侧边栏添加一个版本选择器
104 | versions: {
105 | 'v1 (Latest)': {
106 | link: '/'
107 | },
108 | 'v0.2': {
109 | link: '/v0.2/'
110 | },
111 | 'v0.1': {
112 | link: '/v0.1/'
113 | }
114 | }
115 | ```
116 |
117 | ## 自定义字体
118 |
119 | Apply custom fonts to your website is pretty easy, you can simply add a `
131 | ```
132 |
133 | to toggle the custom fonts on this website.
134 |
135 | By default a fresh Docute website will use system default fonts.
136 |
137 | ## 自定义样式
138 |
139 | You can use [`cssVariables`](../options.md#cssvariables) option to customize site style:
140 |
141 | ```js
142 | new Docute({
143 | cssVariables: {
144 | sidebarWidth: '300px'
145 | }
146 | })
147 |
148 | // Or using a function to get current theme
149 | new Docute({
150 | cssVariables(theme) {
151 | return theme === 'dark' ? {} : {}
152 | }
153 | })
154 | ```
155 |
156 | The `cssVariables` used by the the {{ $store.getters.config.theme }} theme:
157 |
158 |
159 | -
160 | {{key}}:
161 | {{value}}
162 |
163 |
164 |
165 | Note that these properties are defined in camelCase but you should reference them in CSS using kebab-case:
166 |
167 | ```css
168 | .Sidebar {
169 | width: var(--sidebar-width);
170 | }
171 | ```
172 |
--------------------------------------------------------------------------------
/src/components/HeaderNav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ item.title }}
7 |
8 |
9 |
10 | -
15 |
{{ childItem.title }}
21 |
22 |
23 |
24 |
25 | {{ item.title }}
32 |
33 |
34 |
35 |
36 |
57 |
58 |
197 |
--------------------------------------------------------------------------------
/src/plugins/search/SearchBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
23 |
24 |
30 |
31 |
32 | {{ item.label }}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
93 |
94 |
208 |
--------------------------------------------------------------------------------
/src/css/page-content.css:
--------------------------------------------------------------------------------
1 | .page-content {
2 | & > *:first-child {
3 | margin-top: 0;
4 | }
5 |
6 | &.has-page-title > h2:first-child {
7 | margin-top: 7rem;
8 | }
9 |
10 | & h1,
11 | & h2,
12 | & h3,
13 | & h4,
14 | & h5,
15 | & h6 {
16 | font-weight: 300;
17 | line-height: 1.2;
18 | }
19 |
20 | & h1 {
21 | font-size: 3rem;
22 | margin-bottom: 1.4rem;
23 | }
24 |
25 | & h2 {
26 | font-size: 2rem;
27 | border-bottom: 1px solid var(--border-color);
28 | margin-top: 7rem;
29 | padding-bottom: 5px;
30 | }
31 |
32 | & h3 {
33 | font-size: 1.7rem;
34 | margin: 40px 0 30px 0;
35 | }
36 |
37 | & h4 {
38 | font-size: 1.4rem;
39 | }
40 |
41 | & h5 {
42 | font-size: 1.1rem;
43 | }
44 |
45 | & p {
46 | margin: 15px 0;
47 | }
48 |
49 | & table {
50 | width: 100%;
51 | border-spacing: 0;
52 | border-collapse: separate;
53 | }
54 |
55 | & table th,
56 | & table td {
57 | padding: 12px 10px;
58 | border-bottom: 1px solid var(--border-color);
59 | text-align: left;
60 | }
61 |
62 | & thead th {
63 | color: var(--table-header-color);
64 | background: var(--table-header-background);
65 | border-bottom: 1px solid var(--border-color);
66 | border-top: 1px solid var(--border-color);
67 | font-weight: 400;
68 | font-size: 12px;
69 | padding: 10px;
70 |
71 | &:first-child {
72 | border-left: 1px solid var(--border-color);
73 | border-radius: 4px 0px 0px 4px;
74 | }
75 |
76 | &:last-child {
77 | border-right: 1px solid var(--border-color);
78 | border-radius: 0 4px 4px 0;
79 | }
80 | }
81 |
82 | & .pre-wrapper {
83 | margin: 2rem 0;
84 | position: relative;
85 | border-radius: 4px;
86 | background: var(--code-block-background);
87 | box-shadow: inset 0 0 0 var(--code-block-shadow-width) var(--code-block-shadow-color);
88 |
89 | &:before {
90 | content: attr(data-lang);
91 | position: absolute;
92 | top: 5px;
93 | right: 10px;
94 | font-size: 12px;
95 | color: #cacaca;
96 | }
97 |
98 | & code {
99 | color: var(--code-block-text-color);
100 | }
101 | }
102 |
103 | & pre,
104 | & .code-mask {
105 | overflow: auto;
106 | position: relative;
107 | margin: 0;
108 | z-index: 2;
109 | font-family: var(--code-font);
110 | white-space: pre;
111 |
112 | & code {
113 | box-shadow: none;
114 | margin: 0;
115 | padding: 0;
116 | border: none;
117 | font-size: 1em;
118 | background: transparent;
119 | }
120 |
121 | @media print {
122 | white-space: pre-wrap;
123 | word-break: break-word;
124 | }
125 | }
126 |
127 | & pre {
128 | padding: 20px;
129 | }
130 |
131 | & .code-mask {
132 | position: absolute;
133 | top: 0;
134 | left: 0;
135 | right: 0;
136 | z-index: 1;
137 | padding-top: 20px;
138 | border: none;
139 | color: transparent;
140 | }
141 |
142 | & .code-line {
143 | display: block;
144 | padding: 0 20px;
145 | &.highlighted {
146 | background: var(--highlighted-line-background);
147 | position: relative;
148 | &:before {
149 | content: '';
150 | display: block;
151 | width: 3px;
152 | top: 0;
153 | left: 0;
154 | bottom: 0;
155 | background: var(--highlighted-line-border-color);
156 | position: absolute;
157 | }
158 | }
159 | }
160 |
161 | & code {
162 | font-family: var(--code-font);
163 | font-size: 90%;
164 | background: var(--inline-code-background);
165 | border-radius: 4px;
166 | padding: 3px 5px;
167 | color: var(--inline-code-color);
168 | }
169 |
170 | & > ul,
171 | & > ol {
172 | padding-left: 20px;
173 | margin: 1rem 0;
174 | }
175 |
176 | & .contains-task-list {
177 | list-style: none;
178 | padding-left: 0;
179 | }
180 |
181 | & img {
182 | max-width: 100%;
183 | }
184 |
185 | & blockquote {
186 | background: #f1f1f1;
187 | border-left: 8px solid #ccc;
188 | margin: 20px 0;
189 | padding: 14px 16px;
190 | color: #6a737d;
191 |
192 | & p {
193 | margin: 15px 0 0 0;
194 | }
195 |
196 | & > *:first-child {
197 | margin-top: 0;
198 | }
199 | }
200 |
201 | & hr {
202 | height: 1px;
203 | padding: 0;
204 | margin: 3rem 0;
205 | background-color: #e1e4e8;
206 | border: 0;
207 | }
208 |
209 | & .header-anchor {
210 | float: left;
211 | line-height: 1;
212 | margin-left: -20px;
213 | padding-right: 4px;
214 | opacity: 0;
215 | border-bottom: none;
216 |
217 | &:hover {
218 | opacity: 1;
219 | border-bottom: none;
220 | }
221 |
222 | & .anchor-icon {
223 | vertical-align: middle;
224 | fill: currentColor;
225 | }
226 | }
227 |
228 | & .markdown-header:focus,
229 | & .markdown-header:hover {
230 | outline: none;
231 | & .header-anchor {
232 | opacity: 1;
233 | }
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/website/docs/guide/customization.md:
--------------------------------------------------------------------------------
1 | # Customization
2 |
3 | Customizing Docute is as fun as playing with Lego bricks.
4 |
5 | ## Navbar
6 |
7 | The navbar is used for site-level navigation. It usually contains a link to your homepage and a link to your project's repository. However you can add whatever you want there.
8 |
9 | ```js
10 | new Docute({
11 | title: 'Docute',
12 | nav: [
13 | {
14 | title: 'Home',
15 | link: '/'
16 | },
17 | {
18 | title: 'GitHub',
19 | link: 'https://github.com/egoist/docute'
20 | },
21 | // A dropdown menu
22 | {
23 | title: 'Community',
24 | children: [
25 | {
26 | title: 'Spectrum',
27 | link: 'https://spectrum.chat/your-community'
28 | },
29 | {
30 | title: 'Discord',
31 | link: 'https://discord.app/your-discord-server'
32 | }
33 | ]
34 | }
35 | ]
36 | })
37 | ```
38 |
39 | The `title` option defaults to the value of `` tag in your HTML, so it's completely optional.
40 |
41 | Check out the navbar of this website to see how it looks.
42 |
43 | ## Sidebar
44 |
45 | Sidebar is mainly used for navigations between pages. As you can see from this page, we also use it to display a version selector and a language selector.
46 |
47 | ```js
48 | new Docute({
49 | sidebar: [
50 | // A sidebar item, with child links
51 | {
52 | title: 'Guide',
53 | children: [
54 | {
55 | title: 'Getting Started',
56 | link: '/guide/getting-started'
57 | },
58 | {
59 | title: 'Installation',
60 | link: '/guide/installation'
61 | }
62 | ]
63 | },
64 | // An external link
65 | {
66 | title: 'GitHub',
67 | link: 'https://github.com/egoist/docute'
68 | }
69 | ]
70 | })
71 | ```
72 |
73 | Check out the [sidebar](../options.md#sidebar) option reference for more details.
74 |
75 | ## Layout
76 |
77 | Docute by default uses a wide-screen layout as you see, but there're more layouts available:
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | ```js {interpolate:true}
86 | new Docute({
87 | layout: '{{ $store.state.originalConfig.layout }}'
88 | })
89 | ```
90 |
91 | ## Versioning
92 |
93 | Let's say you have `master` branch for the latest docs and `v0.1` `v0.2` branches for older versions, you can use one Docute website to serve them all, with the help of [`overrides`](../options.md#overrides) and [`sourcePath`](../options.md#sourcepath) option.
94 |
95 | ```js
96 | new Docute({
97 | // Configure following paths to load Markdown files from different path
98 | overrides: {
99 | '/v0.1/': {
100 | sourcePath: 'https://raw.githubusercontent.com/user/repo/v0.1'
101 | },
102 | '/v0.2/': {
103 | sourcePath: 'https://raw.githubusercontent.com/user/repo/v0.2'
104 | }
105 | },
106 | // Use `versions` option to add a version selector
107 | // In the sidebar
108 | versions: {
109 | 'v1 (Latest)': {
110 | link: '/'
111 | },
112 | 'v0.2': {
113 | link: '/v0.2/'
114 | },
115 | 'v0.1': {
116 | link: '/v0.1/'
117 | }
118 | }
119 | })
120 | ```
121 |
122 | ## Custom Fonts
123 |
124 | Apply custom fonts to your website is pretty easy, you can simply add a `
136 | ```
137 |
138 | to toggle the custom fonts on this website.
139 |
140 | By default a fresh Docute website will use system default fonts.
141 |
142 | ## Custom Style
143 |
144 | You can use [`cssVariables`](../options.md#cssvariables) option to customize site style:
145 |
146 | ```js
147 | new Docute({
148 | cssVariables: {
149 | sidebarWidth: '300px'
150 | }
151 | })
152 |
153 | // Or using a function to get current theme
154 | new Docute({
155 | cssVariables(theme) {
156 | return theme === 'dark' ? {} : {}
157 | }
158 | })
159 | ```
160 |
161 | The `cssVariables` used by the the {{ $store.getters.config.theme }} theme:
162 |
163 |
164 | -
165 | {{key}}:
166 | {{value}}
167 |
168 |
169 |
170 | Note that these properties are defined in camelCase but you should reference them in CSS using kebab-case:
171 |
172 | ```css
173 | .Sidebar {
174 | width: var(--sidebar-width);
175 | }
176 | ```
177 |
--------------------------------------------------------------------------------
/src/components/SidebarItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
23 |
24 | {{ item.title }}
25 |
26 | {{ item.title }}
33 |
34 |
35 |
36 |
37 |
41 |
42 | {{ link.title }}
50 |
51 |
52 |
53 |
54 |
55 |
56 |
110 |
111 |
214 |
--------------------------------------------------------------------------------
/website/docs/zh/guide/markdown-features.md:
--------------------------------------------------------------------------------
1 | # 撰写
2 |
3 | 文档应易于阅读且易于撰写。
4 |
5 | ## 文档规范
6 |
7 | 文档应以 Markdown 格式展现:
8 |
9 | ```markdown
10 | # 标题
11 |
12 | 内容填在这里...
13 | ```
14 |
15 | 如果你不知道它是什么,请查阅 [Markdown](https://daringfireball.net/projects/markdown/)。
16 |
17 | ## 链接
18 |
19 | ### 内部链接
20 |
21 | 内部链接会转换为 `` 进行 SPA 式导航。
22 |
23 | __输入__:
24 |
25 | ```markdown
26 | - [首页](/zh/)
27 | - [在 Markdown 中使用 Vue](/zh/guide/use-vue-in-markdown)
28 | - [查看 `title` 选项](../options.md#title)
29 | ```
30 |
31 | __输出__:
32 |
33 | - [首页](/zh/)
34 | - [在 Markdown 中使用 Vue](/zh/guide/use-vue-in-markdown)
35 | - [查看 `title` 选项](../options.md#title)
36 |
37 | ### 外部链接
38 |
39 | 外部链接会自动添加 HTML 属性 `target="_blank" rel="noopener noreferrer"`,例如:
40 |
41 | __输入__:
42 |
43 | ```markdown
44 | - [Docute website](https://docute.org)
45 | - [Docute repo](https://github.com/egoist/docute)
46 | ```
47 |
48 | __输出__:
49 |
50 | - [Docute website](https://docute.org)
51 | - [Docute repo](https://github.com/egoist/docute)
52 |
53 | ## 任务列表
54 |
55 | __输入__:
56 |
57 | ```markdown
58 | - [ ] Rule the web
59 | - [x] Conquer the world
60 | - [ ] Learn Docute
61 | ```
62 |
63 | __输出__:
64 |
65 | - [ ] Rule the web
66 | - [x] Conquer the world
67 | - [ ] Learn Docute
68 |
69 | ## 代码高亮 Highlighting
70 |
71 | 代码框使用 [Prism.js](https://prismjs.com/) 高亮显示,示例代码:
72 |
73 | ```js
74 | // Returns a function, that, as long as it continues to be invoked, will not
75 | // be triggered. The function will be called after it stops being called for
76 | // N milliseconds. If `immediate` is passed, trigger the function on the
77 | // leading edge, instead of the trailing.
78 | function debounce(func, wait, immediate) {
79 | var timeout;
80 | return function() {
81 | var context = this, args = arguments;
82 | var later = function() {
83 | timeout = null;
84 | if (!immediate) func.apply(context, args);
85 | };
86 | var callNow = immediate && !timeout;
87 | clearTimeout(timeout);
88 | timeout = setTimeout(later, wait);
89 | if (callNow) func.apply(context, args);
90 | };
91 | };
92 | ```
93 |
94 | 默认支持的语言:
95 |
96 |
97 | -
98 | {{ lang }}
99 |
100 |
101 |
102 | 你可以查看[高亮](/zh/options#highlight)选项添加更多语言。
103 |
104 | ## Code Fence Options
105 |
106 | Next to the code fence language, you can use a JS object to specify options:
107 |
108 | ````markdown
109 | ```js {highlightLines: [2]}
110 | function foo() {
111 | console.log('foo')
112 | }
113 | ```
114 | ````
115 |
116 | Available options:
117 |
118 | - `highlightLines`: [Line Highlighting in Code Fences](#line-highlighting-in-code-fences)
119 | - `mixin`: [Adding Vue Mixin](#adding-vue-mixin)
120 |
121 | ## 代码框中某行高亮显示
122 |
123 | __输入:__
124 |
125 | ````markdown
126 | ```js {highlight:[3,'5-7',12]}
127 | class SkinnedMesh extends THREE.Mesh {
128 | constructor(geometry, materials) {
129 | super(geometry, materials);
130 |
131 | this.idMatrix = SkinnedMesh.defaultMatrix();
132 | this.bones = [];
133 | this.boneMatrices = [];
134 | //...
135 | }
136 | update(camera) {
137 | //...
138 | super.update();
139 | }
140 | static defaultMatrix() {
141 | return new THREE.Matrix4();
142 | }
143 | }
144 | ```
145 | ````
146 |
147 | __输出:__
148 |
149 | ```js {highlight:[3,'5-7',12]}
150 | class SkinnedMesh extends THREE.Mesh {
151 | constructor(geometry, materials) {
152 | super(geometry, materials);
153 |
154 | this.idMatrix = SkinnedMesh.defaultMatrix();
155 | this.bones = [];
156 | this.boneMatrices = [];
157 | //...
158 | }
159 | update(camera) {
160 | //...
161 | super.update();
162 | }
163 | static defaultMatrix() {
164 | return new THREE.Matrix4();
165 | }
166 | }
167 | ```
168 |
169 | ## Adding Vue Mixin
170 |
171 | Adding a Vue mixin to the Markdown component:
172 |
173 | ````markdown
174 | people love Docute.
175 |
176 | ```js {mixin:true}
177 | {
178 | data() {
179 | return {
180 | count: 1000
181 | }
182 | }
183 | }
184 | ```
185 | ````
186 |
187 | people love Docute.
188 |
189 | ```js {mixin:true}
190 | {
191 | data() {
192 | return {
193 | count: 1000
194 | }
195 | }
196 | }
197 | ```
198 |
199 | ## 使用 Mermaid
200 |
201 | [Mermaid](https://mermaidjs.github.io/) 是一种纯文本撰写图表的方法,你可以使用简单的 Docute 插件来添加对 Mermaid 的支持:
202 |
203 | ```html
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
219 | ```
220 |
221 | ## HTML in Markdown
222 |
223 | You can write HTML in Markdown, for example:
224 |
225 | ```markdown
226 | __FAQ__:
227 |
228 | what is the meaning of life?
229 |
230 | some say it is __42__, some say it is still unknown.
231 |
232 | ```
233 |
234 | __FAQ__:
235 |
236 | what is the meaning of life?
237 |
238 | some say it is __42__, some say it is still unknown.
239 |
240 |
241 |
242 |
243 | In fact you can even use Vue directives and Vue components in Markdown too, learn more about it [here](./use-vue-in-markdown.md).
244 |
--------------------------------------------------------------------------------
/website/docs/zh/builtin-components.md:
--------------------------------------------------------------------------------
1 | # 内置组件
2 |
3 | Docute 附带一些内置的 Vue 组件。
4 |
5 | ## ``
6 |
7 | 使用与 Medium 相同的缩放效果显示 image 。
8 |
9 | |属性|类型|默认值|描述|
10 | |---|---|---|---|
11 | |url|`string`|N/A|Image 的 URL|
12 | | title | `string` | N/A | Image title |
13 | |alt|`string`|N/A|占位文字|
14 | |border|`boolean`|`false`|是否显示图像周围的边框|
15 | |width|`string`|N/A|Image 宽度|
16 |
17 | 示例:
18 |
19 | ```markdown
20 |
25 | ```
26 |
27 |
28 |
29 |
30 | ## ``
31 |
32 | A small count and labeling component.
33 |
34 | | Prop | Type | Default | Description |
35 | | -------- | --------------------------------------------------- | ------- | ----------------------- |
36 | | type | 'tip' | 'success' | 'warning' | 'danger' | N/A | Badge type |
37 | | color | `string` | N/A | Custom background color |
38 | | children | `string` | N/A | Badge text |
39 |
40 |
41 |
42 | Example:
43 |
44 | ```markdown
45 | - Feature 1 Badge
46 | - Feature 2 Tip
47 | - Feature 3 Success
48 | - Feature 4 Warning
49 | - Feature 5 Danger
50 | - Feature 6 Custom Color
51 | ```
52 |
53 | - Feature 1 Badge
54 | - Feature 2 Tip
55 | - Feature 3 Success
56 | - Feature 4 Warning
57 | - Feature 5 Danger
58 | - Feature 6 Custom Color
59 |
60 | ## ``
61 |
62 | Colored note blocks, to emphasize part of your page.
63 |
64 | | Prop | Type | Default | Description |
65 | | -------- | ------------------------------------------------------------------- | ------------------- | ------------------------------------------------- |
66 | | type | 'tip' | 'warning' | 'danger' | 'success' | N/A | Note type |
67 | | label | `string` `boolean` | The value of `type` | Custom note label text, use `false` to hide label |
68 | | children | `string` | N/A | Note content |
69 |
70 |
71 |
72 | Examples:
73 |
74 | ```markdown
75 |
76 |
77 | This is a note that details something important.
78 | [A link to helpful information.](https://docute.org)
79 |
80 |
81 |
82 |
83 |
84 |
85 | This is a tip for something that is possible.
86 |
87 |
88 |
89 |
90 |
91 |
92 | This is a warning for something very important.
93 |
94 |
95 |
96 |
97 |
98 |
99 | This is a danger for something to take action for.
100 |
101 |
102 | ```
103 |
104 |
105 |
106 | This is a note that details something important.
107 | [A link to helpful information.](https://docute.org)
108 |
109 |
110 |
111 |
112 |
113 |
114 | This is a tip for something that is possible.
115 |
116 |
117 |
118 |
119 |
120 |
121 | This is a warning for something very important.
122 |
123 |
124 |
125 |
126 |
127 |
128 | This is a danger for something to take action for.
129 |
130 |
131 |
132 | ## ``
133 |
134 | Embed [GitHub Gist](https://gist.github.com/) into your Markdown documents.
135 |
136 | |Prop|Type|Default|Description|
137 | |---|---|---|---|
138 | |id|`string`|N/A|Gist ID|
139 |
140 | Example:
141 |
142 | ```markdown
143 |
144 | ```
145 |
146 |
147 |
148 | ## ``
149 |
150 | A customized `