diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..0bd565e --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 35d6b90..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve - ---- - - - - - -## Bug Report - -#### Steps to reproduce - - - -#### What is current behaviour - - - -#### What is the expected behaviour - - - -#### Other relevant information - - -- [ ] Bug does still occur when all/other plugins are disabled? - -- Your OS: -- Node.js version: -- npm/yarn version: -- Browser version: -- Docsify version: -- Docsify plugins: - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 501e4de..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project - ---- - - - - - -## Feature request - -#### What problem does this feature solve? - - - -#### What does the proposed API look like? - - - -#### How should this be implemented in your opinion? - - - -#### Are you willing to work on this yourself? diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bb31bd4..79a5281 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,54 +1,5 @@ - - - - - - -**Summary** - -**What kind of change does this PR introduce?** (check at least one) - -- [ ] Bugfix -- [ ] Feature -- [ ] Code style update -- [ ] Refactor -- [ ] Docs -- [ ] Build-related changes -- [ ] Other, please describe: - -If changing the UI of default theme, please provide the **before/after** screenshot: - -**Does this PR introduce a breaking change?** (check one) - -- [ ] Yes -- [ ] No - -If yes, please describe the impact and migration path for existing applications: - -**The PR fulfills these requirements:** - -- [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number) - -You have tested in the following browsers: (Providing a detailed version will be better.) - -- [ ] Chrome -- [ ] Firefox -- [ ] Safari -- [ ] Edge -- [ ] IE - -If adding a **new feature**, the PR's description includes: - -- [ ] A convincing reason for adding this feature -- [ ] Related documents have been updated -- [ ] Related tests have been updated - -To avoid wasting your time, it's best to open a **feature request issue** first and wait for approval before working on it. - - -**Other information:** - ---- +Please makes sure these boxes are checked before submitting your PR, thank you! +* [ ] Make sure you are merging your commits to `master` branch. +* [ ] Add some descriptions and refer relative issues for you PR. * [ ] DO NOT include files inside `lib` directory. - diff --git a/.gitignore b/.gitignore index ea4b5b8..7235d84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ *.log .DS_Store -.idea +/themes/* +!.gitkeep node_modules -themes/ -lib/ +lib +.idea -# exceptions -!.gitkeep \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 267d402..5a50a98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,3 @@ - -## [4.9.4](https://github.com/docsifyjs/docsify/compare/v4.9.2...v4.9.4) (2019-05-05) - - - - -## [4.9.2](https://github.com/docsifyjs/docsify/compare/v4.9.1...v4.9.2) (2019-04-21) - - -### Bug Fixes - -* re-render gitalk when router changed ([11ea1f8](https://github.com/docsifyjs/docsify/commit/11ea1f8)) - - -### Features - -* allows relative path, fixed [#590](https://github.com/docsifyjs/docsify/issues/590) ([31654f1](https://github.com/docsifyjs/docsify/commit/31654f1)) - - - ## [4.9.1](https://github.com/docsifyjs/docsify/compare/v4.9.0...v4.9.1) (2019-02-21) diff --git a/README.md b/README.md index b8da0d8..a1ae1c8 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ ## Links -- [`develop` branch preview](https://docsifyjs.netlify.com/) - [Documentation](https://docsify.js.org) - [CLI](https://github.com/docsifyjs/docsify-cli) - CDN: [UNPKG](https://unpkg.com/docsify/) | [jsDelivr](https://cdn.jsdelivr.net/npm/docsify/) | [cdnjs](https://cdnjs.com/libraries/docsify) @@ -41,7 +40,7 @@ - Smart full-text search plugin - Multiple themes - Useful plugin API -- Compatible with IE11 +- Compatible with IE10+ - Support SSR ([example](https://github.com/docsifyjs/docsify-ssr-demo)) - Support embedded files @@ -55,7 +54,7 @@ Look at [this tutorial](https://docsify.js.org/#/quickstart) These projects are using docsify to generate their sites. Pull requests welcome :blush: -Move to [awesome-docsify](https://github.com/docsifyjs/awesome-docsify#showcase) +Move to [awesome-docsify](https://github.com/docsifyjs/awesome-docsify) ## Similar projects diff --git a/build/build.js b/build/build.js index 7b61224..b9068b9 100644 --- a/build/build.js +++ b/build/build.js @@ -55,7 +55,6 @@ const buildAllPlugin = function () { var plugins = [ {name: 'search', input: 'search/index.js'}, {name: 'ga', input: 'ga.js'}, - {name: 'matomo', input: 'matomo.js'}, {name: 'emoji', input: 'emoji.js'}, {name: 'external-script', input: 'external-script.js'}, {name: 'front-matter', input: 'front-matter/index.js'}, diff --git a/build/release.sh b/build/release.sh old mode 100755 new mode 100644 index a328322..da15a38 --- a/build/release.sh +++ b/build/release.sh @@ -29,6 +29,7 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then # commit git add -A + git add -f lib/ -A git commit -m "[build] $VERSION $RELEASE_TAG" npm --no-git-tag-version version $VERSION --message "[release] $VERSION $RELEASE_TAG" diff --git a/docs/README.md b/docs/README.md index e625420..d27f1ae 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,12 +16,12 @@ See the [Quick start](quickstart.md) guide for more details. - Multiple themes - Useful plugin API - Emoji support -- Compatible with IE11 +- Compatible with IE10+ - Support server-side rendering ([example](https://github.com/docsifyjs/docsify-ssr-demo)) ## Examples -Check out the [Showcase](https://github.com/docsifyjs/awesome-docsify#showcase) to see docsify in use. +Check out the [Showcase](https://github.com/docsifyjs/docsify/#showcase) to see docsify in use. ## Donate diff --git a/docs/_coverpage.md b/docs/_coverpage.md index 1decbd6..0a18f97 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,6 +1,6 @@ ![logo](_media/icon.svg) -# docsify 4.9.4 +# docsify 4.9.1 > A magical documentation site generator. diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 051514b..c8ab579 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -23,6 +23,7 @@ - [Offline Mode(PWA)](pwa.md) - [Server-Side Rendering(SSR)](ssr.md) - [Embed Files](embed-files.md) + - [Generate static html](static.md) - [Awesome docsify](awesome.md) - [Changelog](changelog.md) diff --git a/docs/configuration.md b/docs/configuration.md index ba48475..830748f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -150,46 +150,6 @@ window.$docsify = { }; ``` -## relativePath - -- Type: `Boolean` -- Default: `false` - -If **true** links are relative to the current context. - -For example, the directory structure is as follows: - -```text -. -โ””โ”€โ”€ docs - โ”œโ”€โ”€ README.md - โ”œโ”€โ”€ guide.md - โ””โ”€โ”€ zh-cn - โ”œโ”€โ”€ README.md - โ”œโ”€โ”€ guide.md - โ””โ”€โ”€ config - โ””โ”€โ”€ example.md -``` - -With relative path **enabled** and current URL `http://domain.com/zh-cn/README`, given links will resolve to: - -```text -guide.md => http://domain.com/zh-cn/guide -config/example.md => http://domain.com/zh-cn/config/example -../README.md => http://domain.com/README -/README.md => http://domain.com/README -``` - -```js -window.$docsify = { - // Relative path enabled - relativePath: true, - - // Relative path disabled (default value) - relativePath: false -}; -``` - ## coverpage - Type: `Boolean|String|String[]|Object` diff --git a/docs/deploy.md b/docs/deploy.md index a879f2e..7d47e0f 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -15,7 +15,7 @@ It is recommended that you save your files to the `./docs` subfolder of the `mas ![github pages](_images/deploy-github-pages.png) !> You can also save files in the root directory and select `master branch`. -You'll need to place a `.nojekyll` file in the deploy location (such as `/docs` or the gh-pages branch) +You'll need to place a `.nojekyll` file in the deploy location (such as `/docs` or the gh-pages branch ## GitLab Pages diff --git a/docs/helpers.md b/docs/helpers.md index b047d36..9075448 100644 --- a/docs/helpers.md +++ b/docs/helpers.md @@ -7,24 +7,72 @@ docsify extends Markdown syntax to make your documents more readable. Important content like: ```markdown -!> **Time** is money, my friend! +> [!] **Time** is money, my friend! ``` is rendered as: -!> **Time** is money, my friend! +> [!] **Time** is money, my friend! ## General tips General tips like: ```markdown -?> _TODO_ unit test +> [?] _TODO_ unit test ``` are rendered as: -?> _TODO_ unit test +> [?] _TODO_ unit test + +## More tips + +```markdown +> [x] bad + +> [v] good +``` + +> [x] bad + +> [v] good + +## Details + +````markdown +> [details] Sample code +> +> js code +> +> ```javascript +> console.log("foo"); +> ``` + +> [details:open] Sample code open +> +> js code +> +> ```javascript +> console.log("foo"); +> ``` +```` + +> [details] Sample code +> +> js code +> +> ```javascript +> console.log("foo"); +> ``` + +> [details:open] Sample code open +> +> js code +> +> ```javascript +> console.log("foo"); +> ``` ## Ignore to compile link @@ -39,13 +87,13 @@ It will be compiled to `link` and will be loaded `/demo/R Now you can do that ```md -[link](/demo/ ':ignore') +[link](/demo/ ":ignore") ``` You will get `link`html. Do not worry, you can still set title for link. ```md -[link](/demo/ ':ignore title') +[link](/demo/ ":ignore title") link ``` @@ -53,14 +101,14 @@ You will get `link`html. Do not worry, you can still set ti ## Set target attribute for link ```md -[link](/demo ':target=_blank') -[link](/demo2 ':target=_self') +[link](/demo ":target=_blank") +[link](/demo2 ":target=_self") ``` ## Disable link ```md -[link](/demo ':disabled') +[link](/demo ":disabled") ``` ## Github Task Lists @@ -84,17 +132,17 @@ You will get `link`html. Do not worry, you can still set ti ## Image resizing ```md -![logo](https://docsify.js.org/_media/icon.svg ':size=50x100') -![logo](https://docsify.js.org/_media/icon.svg ':size=100') +![logo](https://docsify.js.org/_media/icon.svg ":size=50x100") +![logo](https://docsify.js.org/_media/icon.svg ":size=100") -![logo](https://docsify.js.org/_media/icon.svg ':size=10%') +![logo](https://docsify.js.org/_media/icon.svg ":size=10%") ``` -![logo](https://docsify.js.org/_media/icon.svg ':size=50x100') -![logo](https://docsify.js.org/_media/icon.svg ':size=100') -![logo](https://docsify.js.org/_media/icon.svg ':size=10%') +![logo](https://docsify.js.org/_media/icon.svg ":size=50x100") +![logo](https://docsify.js.org/_media/icon.svg ":size=100") +![logo](https://docsify.js.org/_media/icon.svg ":size=10%") ## Customise ID for headings diff --git a/docs/index.html b/docs/index.html index 6d0e008..bff4ca1 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,104 +1,137 @@ + + + docsify + + + + + + + + + + + + + - - - docsify - - - - - - - - - - - - - - - -
Loading ...
- - - - - - - - - - - - - + formatUpdated: "{MM}/{DD} {HH}:{mm}", + plugins: [ + function(hook, vm) { + hook.beforeEach(function(html) { + if (/githubusercontent\.com/.test(vm.route.file)) { + url = vm.route.file + .replace("raw.githubusercontent.com", "github.com") + .replace(/\/master/, "/blob/master"); + } else { + url = + "https://github.com/docsifyjs/docsify/blob/master/docs/" + + vm.route.file; + } + var editHtml = "[:memo: Edit Document](" + url + ")\n"; + return ( + editHtml + + html + + "\n\n----\n\n" + + 'Powered by docsify' + ); + }); + }, + DocsifyCodefund.create("fae1f9a4-870c-4c25-b8e0-c80464f7a95c") + ] + }; + + + + + + + + + + diff --git a/docs/more-pages.md b/docs/more-pages.md index 46e7df8..38184a2 100644 --- a/docs/more-pages.md +++ b/docs/more-pages.md @@ -72,16 +72,6 @@ You can specify `alias` to avoid unnecessary fallback. !> You can create a `README.md` file in a subdirectory to use it as the landing page for the route. -## Set Page Titles from Sidebar Selection - -A page's `title` tag is generated from the _selected_ sidebar item name. For better SEO, you can customize the title by specifying a string after the filename. - -```markdown - -* [Home](/) -* [Guide](guide.md "The greatest guide in the world") -``` - ## Table of Contents Once you've created `_sidebar.md`, the sidebar content is automatically generated based on the headers in the markdown files. diff --git a/docs/static.md b/docs/static.md new file mode 100644 index 0000000..98bcb75 --- /dev/null +++ b/docs/static.md @@ -0,0 +1,50 @@ +# Generate static html + +> _Experimental feature_ + +Generating static html files is good for SEO and speeds up the first rendering. + +But this is not an advantage of docsify. If you only need powerful static documentation, choose another documentation tool like Gitbook or Vuepress. + +## Configuration + +You can configure it in a special config file. + +_config.js_ + +```js +module.exports = { + template: ` + + + + My Doc + + + + + + + + + +`, // or html file path + + config: { + // docsify config + coverpage: true + } +}; +``` + +## Generate + +Please use docsify-cli 5.0+ and run this command. + +```sh +docsify static docs -c config.js +``` + +## Simple Demo + +This is an example showing the docsify official documentation generating static files. [docsify-static-demo](https://github.com/docsifyjs/docsify-static-demo) diff --git a/docs/write-a-plugin.md b/docs/write-a-plugin.md index baa894e..d6605d4 100644 --- a/docs/write-a-plugin.md +++ b/docs/write-a-plugin.md @@ -79,7 +79,7 @@ window.$docsify = { function(hook, vm) { hook.beforeEach(function(html) { var url = - 'https://github.com/docsifyjs/docsify/blob/master/docs/' + + 'https://github.com/docsifyjs/docsify/blob/master/docs' + vm.route.file; var editHtml = '[๐Ÿ“ EDIT DOCUMENT](' + url + ')\n'; diff --git a/index.html b/index.html index 59e6911..f15433b 100644 --- a/index.html +++ b/index.html @@ -21,64 +21,48 @@ - - - - diff --git a/package-lock.json b/package-lock.json index bb18bcb..a0582ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "docsify", - "version": "4.9.4", + "version": "4.9.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1661f40..c61835b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docsify", - "version": "4.9.4", + "version": "4.9.1", "description": "A magical documentation generator.", "author": { "name": "qingwei-li", @@ -32,11 +32,11 @@ "watch:css": "run-p 'css -- -o themes -w'", "watch:js": "node build/build.js", "build:css:min": "mkdir lib/themes && run-p 'css -- -o lib/themes' && node build/mincss.js", - "build:css": "mkdir -p themes && run-p 'css -- -o themes'", + "build:css": "mkdir themes && run-p 'css -- -o themes'", "build:js": "cross-env NODE_ENV=production node build/build.js", "build:ssr": "node build/ssr.js", "build:cover": "node build/cover.js", - "build": "rimraf lib themes/* && run-s build:js build:css build:css:min build:ssr build:cover", + "build": "rimraf lib themes && run-s build:js build:css build:css:min build:ssr build:cover", "pub:next": "cross-env RELEASE_TAG=next sh build/release.sh", "pub": "sh build/release.sh", "postinstall": "opencollective postinstall" diff --git a/packages/docsify-server-renderer/index.js b/packages/docsify-server-renderer/index.js index 21fb5c7..e65018e 100644 --- a/packages/docsify-server-renderer/index.js +++ b/packages/docsify-server-renderer/index.js @@ -22,7 +22,7 @@ function mainTpl(config) { html += tpl.corner(config.repo) } if (config.coverpage) { - html += tpl.cover() + html += '' } html += tpl.main(config) @@ -31,12 +31,13 @@ function mainTpl(config) { } export default class Renderer { - constructor({template, config, cache}) { + constructor({template, config, cache, path}) { this.html = template this.config = config = Object.assign({}, config, { routerMode: 'history' }) this.cache = cache + this.path = path this.router = new AbstractHistory(config) this.compiler = new Compiler(config, this.router) @@ -52,9 +53,19 @@ export default class Renderer { } _getPath(url) { - const file = this.router.getFile(url) + const path = resolve(this.path, url) + const file = this.router.getFile(path) + return file + } - return isAbsolutePath(file) ? file : cwd(`./${file}`) + async render(url) { + const content = await this.renderToString(url) + + return { + content, + url: this.router.parse(url).path, + path: this._getPath(url) + } } async renderToString(url) { @@ -66,32 +77,35 @@ export default class Renderer { if (loadSidebar) { const name = loadSidebar === true ? '_sidebar.md' : loadSidebar - const sidebarFile = this._getPath(resolve(url, `./${name}`)) + const sidebarFile = this._getPath(resolvePathname(name, url)) this._renderHtml('sidebar', await this._render(sidebarFile, 'sidebar')) } if (loadNavbar) { const name = loadNavbar === true ? '_navbar.md' : loadNavbar - const navbarFile = this._getPath(resolve(url, `./${name}`)) + const navbarFile = this._getPath(resolvePathname(name, url)) this._renderHtml('navbar', await this._render(navbarFile, 'navbar')) } if (coverpage) { - let path = null - if (typeof coverpage === 'string') { - if (url === '/') { - path = coverpage + let name = null + + if (typeof coverpage === 'string' || coverpage === true) { + if (url === 'README.md') { + name = coverpage === true ? '_coverpage.md' : coverpage } } else if (Array.isArray(coverpage)) { - path = coverpage.indexOf(url) > -1 && '_coverpage.md' + name = coverpage.indexOf(url) > -1 && '_coverpage.md' } else { const cover = coverpage[url] - path = cover === true ? '_coverpage.md' : cover + name = cover === true ? '_coverpage.md' : cover } - const coverFile = this._getPath(resolve(url, `./${path}`)) + if (name) { + const coverFile = this._getPath(resolvePathname(name, url)) - this._renderHtml('cover', await this._render(coverFile), 'cover') + this._renderHtml('cover', await this._render(coverFile, 'cover')) + } } const html = this.html @@ -108,6 +122,7 @@ export default class Renderer { async _render(path, type) { let html = await this._loadFile(path) + const {subMaxLevel, maxLevel} = this.config let tokens @@ -126,7 +141,8 @@ export default class Renderer { tokens = await new Promise(r => { prerenderEmbed( { - fetch: url => this._loadFile(this._getPath(url)), + // Url is absolute path + fetch: url => this._loadFile(this._getPath('.' + url)), compiler: this.compiler, raw: html }, @@ -163,7 +179,7 @@ export default class Renderer { return content } catch (e) { this.lock = this.lock || 0 - if (++this.lock > 10) { + if (++this.lock > 4) { this.lock = 0 return } diff --git a/packages/docsify-server-renderer/package-lock.json b/packages/docsify-server-renderer/package-lock.json index e8ff0a6..ccb68d4 100644 --- a/packages/docsify-server-renderer/package-lock.json +++ b/packages/docsify-server-renderer/package-lock.json @@ -37,5 +37,5 @@ "integrity": "sha1-6DWIAbhrg7F1YNTjw4LXrvIQCUQ=" } }, - "version": "4.9.4" + "version": "4.9.1" } diff --git a/packages/docsify-server-renderer/package.json b/packages/docsify-server-renderer/package.json index 5ff206e..9960401 100644 --- a/packages/docsify-server-renderer/package.json +++ b/packages/docsify-server-renderer/package.json @@ -1,6 +1,6 @@ { "name": "docsify-server-renderer", - "version": "4.9.4", + "version": "4.9.1", "description": "docsify server renderer", "author": { "name": "qingwei-li", diff --git a/src/core/config.js b/src/core/config.js index a1386b2..0a8763a 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -25,8 +25,7 @@ export default function () { formatUpdated: '', externalLinkTarget: '_blank', routerMode: 'hash', - noCompileLinks: [], - relativePath: false + noCompileLinks: [] }, window.$docsify ) diff --git a/src/core/render/compiler.js b/src/core/render/compiler.js index 354b6a9..502d938 100644 --- a/src/core/render/compiler.js +++ b/src/core/render/compiler.js @@ -1,6 +1,12 @@ import marked from 'marked' import Prism from 'prismjs' -import {helper as helperTpl, tree as treeTpl} from './tpl' +import { + helper as helperTpl, + newHelper as newHelperTpl, + tree as treeTpl, + cover as coverTpl, + details as detailsTpl +} from './tpl' import {genTree} from './gen-tree' import {slugify} from './slugify' import {emojify} from './emojify' @@ -191,7 +197,7 @@ export class Compiler { /** * Render anchor tag - * @link https://github.com/markedjs/marked#overriding-renderer-methods + * @link https://marked.js.org/#/USING_PRO.md#renderer */ origin.heading = renderer.heading = function (text, level) { let {str, config} = getAndRemoveConfig(text) @@ -303,22 +309,68 @@ export class Compiler { return `${text}` } origin.list = renderer.list = function (body, ordered, start) { - const isTaskList = /
  • /.test(body.split('class="task-list"')[0]) + const isTaskList = /
  • /.test( + body.split('class="task-list"')[0] + ) const isStartReq = start && start > 1 const tag = ordered ? 'ol' : 'ul' const tagAttrs = [ - (isTaskList ? 'class="task-list"' : ''), - (isStartReq ? `start="${start}"` : '') - ].join(' ').trim() + isTaskList ? 'class="task-list"' : '', + isStartReq ? `start="${start}"` : '' + ] + .join(' ') + .trim() return `<${tag} ${tagAttrs}>${body}` } origin.listitem = renderer.listitem = function (text) { const isTaskItem = /^(]*>)/.test(text) - const html = isTaskItem ? `
  • ` : `
  • ${text}
  • ` + const html = isTaskItem ? + `
  • ` : + `
  • ${text}
  • ` return html } + origin.blockquote = renderer.blockquote = function (quote) { + const m = quote.match(/^\(\[\S+\])/) + + if (m) { + const text = quote.replace(m[1], '') + switch (m[1]) { + case '[!]': + result = newHelperTpl('docsify-tip', text) + break + case '[?]': + result = newHelperTpl('docsify-warn', text) + break + case '[x]': + result = newHelperTpl('docsify-error', text) + break + case '[v]': + result = newHelperTpl('docsify-success', text) + break + case '[details]': + case '[details:open]': + let summary = false + const html = text.replace( + /^\([^<]+)<\/p>([\s\S]+)/, + (m, m1, m2) => { + summary = m1 + return m2 + } + ) + const open = Boolean(/:open/.test(m[1])) + + result = detailsTpl({open, summary, html}) + break + default: + return quote + } + return result + } + + return quote + } renderer.origin = origin @@ -329,25 +381,13 @@ export class Compiler { * Compile sidebar */ sidebar(text, level) { - const {toc} = this const currentPath = this.router.getCurrentPath() let html = '' if (text) { html = this.compile(text) } else { - for (let i = 0; i < toc.length; i++) { - if (toc[i].ignoreSubHeading) { - const deletedHeaderLevel = toc[i].level - toc.splice(i, 1) - // Remove headers who are under current header - for (let j = i; deletedHeaderLevel < toc[j].level && j < toc.length; j++) { - toc.splice(j, 1) && j-- && i++ - } - i-- - } - } - const tree = this.cacheTree[currentPath] || genTree(toc, level) + const tree = this.cacheTree[currentPath] || genTree(this.toc, level) html = treeTpl(tree, '') this.cacheTree[currentPath] = tree } @@ -372,6 +412,7 @@ export class Compiler { for (let i = 0; i < toc.length; i++) { toc[i].ignoreSubHeading && toc.splice(i, 1) && i-- } + const tree = cacheTree[currentPath] || genTree(toc, level) cacheTree[currentPath] = tree @@ -386,12 +427,37 @@ export class Compiler { /** * Compile cover page */ - cover(text) { - const cacheToc = this.toc.slice() - const html = this.compile(text) + cover(text, isHTML = false) { + let html = text + if (!isHTML) { + const cacheToc = this.toc.slice() + html = this.compile(text) || '' + this.toc = cacheToc.slice() + } - this.toc = cacheToc.slice() + const m = html + .trim() + .match('

    ([^<]*?)

    $') + let style = '' + let hasMask = false + if (m) { + if (m[2] === 'color') { + style = `background: ${m[1] + (m[3] || '')}` + } else { + let path = m[1] + hasMask = true + if (!isAbsolutePath(m[1])) { + path = getPath(this.router.getBasePath(), m[1]) + } + style = `background-image: url(${path}); background-size: cover; background-position: center center;` + } + html = html.replace(m[0], '') + } - return html + return coverTpl({ + style, + hasMask, + text: html + }) } } diff --git a/src/core/render/embed.js b/src/core/render/embed.js index 8218374..726bfce 100644 --- a/src/core/render/embed.js +++ b/src/core/render/embed.js @@ -22,8 +22,10 @@ function walkFetchEmbed({embedTokens, compile, fetch}, cb) { } else if (token.embed.type === 'code') { if (token.embed.fragment) { const fragment = token.embed.fragment - const pattern = new RegExp(`(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]`) - text = ((text.match(pattern)ย || [])[1] || '').trim() + const pattern = new RegExp( + `(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]` + ) + text = ((text.match(pattern) || [])[1] || '').trim() } embedToken = compile.lexer( '```' + diff --git a/src/core/render/index.js b/src/core/render/index.js index fae1bc5..936d507 100644 --- a/src/core/render/index.js +++ b/src/core/render/index.js @@ -175,30 +175,10 @@ export function renderMixin(proto) { } dom.toggleClass(el, 'add', 'show') - let html = this.coverIsHTML ? text : this.compiler.cover(text) + let html = this.compiler.cover(text, this.coverIsHTML) - const m = html - .trim() - .match('

    ([^<]*?)

    $') + this._renderTo('.cover-placeholder', html, true) - if (m) { - if (m[2] === 'color') { - el.style.background = m[1] + (m[3] || '') - } else { - let path = m[1] - - dom.toggleClass(el, 'add', 'has-mask') - if (!isAbsolutePath(m[1])) { - path = getPath(this.router.getBasePath(), m[1]) - } - el.style.backgroundImage = `url(${path})` - el.style.backgroundSize = 'cover' - el.style.backgroundPosition = 'center center' - } - html = html.replace(m[0], '') - } - - this._renderTo('.cover-main', html) sticky() } @@ -228,8 +208,9 @@ export function initRender(vm) { if (config.repo) { html += tpl.corner(config.repo) } + if (config.coverpage) { - html += tpl.cover() + html += '
    ' } if (config.logo) { diff --git a/src/core/render/tpl.js b/src/core/render/tpl.js index 71f5652..a29f155 100644 --- a/src/core/render/tpl.js +++ b/src/core/render/tpl.js @@ -57,16 +57,19 @@ export function main(config) { /** * Cover Page */ -export function cover() { +export function cover({style, text, hasMask}) { const SL = ', 100%, 85%' - const bgc = - 'linear-gradient(to left bottom, ' + - `hsl(${Math.floor(Math.random() * 255) + SL}) 0%,` + - `hsl(${Math.floor(Math.random() * 255) + SL}) 100%)` + style = + style || + 'background: linear-gradient(to left bottom, ' + + `hsl(${Math.floor(Math.random() * 255) + SL}) 0%,` + + `hsl(${Math.floor(Math.random() * 255) + SL}) 100%)` return ( - `
    ` + - '
    ' + + `
    ` + + `
    ${text}
    ` + '
    ' + '
    ' ) @@ -84,7 +87,9 @@ export function tree(toc, tpl = '
      {inner}
    ') { } let innerHTML = '' toc.forEach(node => { - innerHTML += `
  • ${node.title}
  • ` + innerHTML += `
  • ${ + node.title + }
  • ` if (node.children) { innerHTML += tree(node.children, tpl) } @@ -96,6 +101,17 @@ export function helper(className, content) { return `

    ${content.slice(5).trim()}

    ` } +export function newHelper(className, content) { + return `
    ${content}
    ` +} + export function theme(color) { return `` } + +export function details({open, summary, html}) { + return `
    ${ + summary ? `${summary}` : '' + } + ${html}
    ` +} diff --git a/src/core/router/history/abstract.js b/src/core/router/history/abstract.js index 2c0bd95..9731af1 100644 --- a/src/core/router/history/abstract.js +++ b/src/core/router/history/abstract.js @@ -7,7 +7,7 @@ export class AbstractHistory extends History { this.mode = 'abstract' } - parse(path) { + parse(path = '') { let query = '' const queryIndex = path.indexOf('?') diff --git a/src/core/router/history/base.js b/src/core/router/history/base.js index 7ea763d..6ed56a8 100644 --- a/src/core/router/history/base.js +++ b/src/core/router/history/base.js @@ -3,8 +3,7 @@ import { isAbsolutePath, stringifyQuery, cleanPath, - replaceSlug, - resolvePath + replaceSlug } from '../util' import {noop, merge} from '../../util/core' @@ -22,9 +21,11 @@ function getAlias(path, alias, last) { } function getFileName(path, ext) { - return new RegExp(`\\.(${ext.replace(/^\./, '')}|html)$`, 'g').test(path) ? + return /\.\w+$/.test(path) ? path : - /\/$/g.test(path) ? `${path}README${ext}` : `${path}${ext}` + /\/$/g.test(path) ? + `${path}README${ext}` : + `${path}${ext}` } export class History { @@ -74,13 +75,9 @@ export class History { if (local) { const idIndex = currentRoute.indexOf('?') path = - (idIndex > 0 ? currentRoute.substring(0, idIndex) : currentRoute) + path + (idIndex > 0 ? currentRoute.substr(0, idIndex) : currentRoute) + path } - if (this.config.relativePath && path.indexOf('/') !== 0) { - const currentDir = currentRoute.substring(0, currentRoute.lastIndexOf('/') + 1) - return cleanPath(resolvePath(currentDir + path)) - } return cleanPath('/' + path) } } diff --git a/src/core/router/util.js b/src/core/router/util.js index 2ed88c5..13c8109 100644 --- a/src/core/router/util.js +++ b/src/core/router/util.js @@ -46,27 +46,15 @@ export const isAbsolutePath = cached(path => { export const getParentPath = cached(path => { return /\/$/g.test(path) ? path : - (path = path.match(/(\S*\/)[^/]+$/)) ? path[1] : '' + (path = path.match(/(\S*\/)[^/]+$/)) ? + path[1] : + '' }) export const cleanPath = cached(path => { return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/') }) -export const resolvePath = cached(path => { - const segments = path.replace(/^\//, '').split('/') - let resolved = [] - for (let i = 0, len = segments.length; i < len; i++) { - const segment = segments[i] - if (segment === '..') { - resolved.pop() - } else if (segment !== '.') { - resolved.push(segment) - } - } - return '/' + resolved.join('/') -}) - export function getPath(...args) { return cleanPath(args.join('/')) } diff --git a/src/plugins/matomo.js b/src/plugins/matomo.js deleted file mode 100644 index 7b61cba..0000000 --- a/src/plugins/matomo.js +++ /dev/null @@ -1,37 +0,0 @@ -function appendScript(options) { - const script = document.createElement('script') - script.async = true - script.src = options.host + '/matomo.js' - document.body.appendChild(script) -} - -function init(options) { - window._paq = window._paq || [] - window._paq.push(['trackPageView']) - window._paq.push(['enableLinkTracking']) - setTimeout(function() { - appendScript(options) - window._paq.push(['setTrackerUrl', options.host + '/matomo.php']) - window._paq.push(['setSiteId', options.id + '']) - }, 0) -} - -function collect() { - if (!window._paq) { - init($docsify.matomo) - } - window._paq.push(['setCustomUrl', window.location.hash.substr(1)]) - window._paq.push(['setDocumentTitle', document.title]) - window._paq.push(['trackPageView']) -} - -const install = function (hook) { - if (!$docsify.matomo) { - console.error('[Docsify] matomo is required.') - return - } - - hook.beforeEach(collect) -} - -$docsify.plugins = [].concat(install, $docsify.plugins) diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index 2c9febf..4f14ecd 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -96,27 +96,29 @@ export function search(query) { for (let i = 0; i < data.length; i++) { const post = data[i] - let matchesScore = 0 + let isMatch = false let resultStr = '' const postTitle = post.title && post.title.trim() const postContent = post.body && post.body.trim() const postUrl = post.slug || '' - if (postTitle) { - keywords.forEach( keyword => { + if (postTitle && postContent) { + keywords.forEach(keyword => { // From https://github.com/sindresorhus/escape-string-regexp const regEx = new RegExp( keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'), 'gi' - ); + ) let indexTitle = -1 let indexContent = -1 - indexTitle = postTitle ? postTitle.search(regEx) : -1 - indexContent = postContent ? postContent.search(regEx) : -1 + indexTitle = postTitle && postTitle.search(regEx) + indexContent = postContent && postContent.search(regEx) - if (indexTitle >= 0 || indexContent >= 0) { - matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0; + if (indexTitle < 0 && indexContent < 0) { + isMatch = false + } else { + isMatch = true if (indexContent < 0) { indexContent = 0 } @@ -142,12 +144,11 @@ export function search(query) { } }) - if (matchesScore > 0) { + if (isMatch) { const matchingPost = { title: escapeHtml(postTitle), - content: postContent ? resultStr : '', - url: postUrl, - score: matchesScore + content: resultStr, + url: postUrl } matchingResults.push(matchingPost) @@ -155,7 +156,7 @@ export function search(query) { } } - return matchingResults.sort((r1, r2) => r2.score - r1.score); + return matchingResults } export function init(config, vm) { diff --git a/src/themes/basic/_layout.styl b/src/themes/basic/_layout.styl index 387fd79..a3556d9 100644 --- a/src/themes/basic/_layout.styl +++ b/src/themes/basic/_layout.styl @@ -321,6 +321,9 @@ body.sticky border-bottom 1px solid #eee margin 2em 0 +.markdown-section summary + cursor pointer + .markdown-section iframe border 1px solid #eee /* fix horizontal overflow on iOS Safari */ @@ -351,6 +354,7 @@ body.sticky background-color #f8f8f8 .markdown-section p.tip +.markdown-section .docsify-tip background-color #f8f8f8 border-bottom-right-radius 2px border-left 4px solid #f66 @@ -382,9 +386,23 @@ body.sticky color $color-text .markdown-section p.warn +.markdown-section .docsify-warn background rgba($color-primary, 0.1) border-radius 2px padding 1rem + margin: 2em 0 + +.markdown-section .docsify-success + background rgba(#42b983, 0.1) + border-radius 2px + padding 1rem + margin: 2em 0 + +.markdown-section .docsify-error + background rgba(#f66, 0.1) + border-radius 2px + margin: 2em 0 + padding 1rem .markdown-section ul.task-list > li list-style-type none diff --git a/src/themes/dark.styl b/src/themes/dark.styl index 02ca630..7c5eb50 100644 --- a/src/themes/dark.styl +++ b/src/themes/dark.styl @@ -216,6 +216,7 @@ pre::after top 0 .markdown-section p.tip +.markdown-section .docsify-tip background-color #282828 color #657b83 diff --git a/test/unit/base.js b/test/unit/base.js deleted file mode 100644 index 036700b..0000000 --- a/test/unit/base.js +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint-env node, chai, mocha */ -require = require('esm')(module/*, options*/) -const {expect} = require('chai') -const {History} = require('../../src/core/router/history/base') - -class MockHistory extends History { - parse(path) { - return {path} - } -} - -describe('router/history/base', function () { - describe('relativePath true', function () { - var history - - beforeEach(function () { - history = new MockHistory({relativePath: true}) - }) - - it('toURL', function () { - // WHEN - const url = history.toURL('guide.md', {}, '/zh-ch/') - - // THEN - expect(url).equal('/zh-ch/guide') - }) - - it('toURL with double dot', function () { - // WHEN - const url = history.toURL('../README.md', {}, '/zh-ch/') - - // THEN - expect(url).equal('/README') - }) - - it('toURL child path', function () { - // WHEN - const url = history.toURL('config/example.md', {}, '/zh-ch/') - - // THEN - expect(url).equal('/zh-ch/config/example') - }) - - it('toURL absolute path', function () { - // WHEN - const url = history.toURL('/README', {}, '/zh-ch/') - - // THEN - expect(url).equal('/README') - }) - }) - - it('toURL without relative path', function () { - const history = new MockHistory({relativePath: false}) - - // WHEN - const url = history.toURL('README', {}, '/zh-ch/') - - // THEN - expect(url).equal('/README') - }) -}) diff --git a/test/unit/util.js b/test/unit/util.js deleted file mode 100644 index 1e65daf..0000000 --- a/test/unit/util.js +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-env node, chai, mocha */ -require = require('esm')(module/*, options*/) -const {expect} = require('chai') -const {resolvePath} = require('../../src/core/router/util') - -describe('router/util', function () { - it('resolvePath', async function () { - // WHEN - const result = resolvePath('hello.md') - - // THEN - expect(result).equal('/hello.md') - }) - - it('resolvePath with dot', async function () { - // WHEN - const result = resolvePath('./hello.md') - - // THEN - expect(result).equal('/hello.md') - }) - - it('resolvePath with two dots', async function () { - // WHEN - const result = resolvePath('test/../hello.md') - - // THEN - expect(result).equal('/hello.md') - }) -}) diff --git a/themes/.gitkeep b/themes/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/themes/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -