Compare commits

..

37 commits

Author SHA1 Message Date
James Hegedus
1d3246a26f
Fix typo in docs #869
Fix typo
2019-06-18 09:02:10 +10:00
Parkjunwoo
8ea4865c84 Fix typo 2019-06-18 00:30:43 +09:00
Anton Wilhelm
676f84cffa chore: add changelog 4.9.4 2019-05-05 18:41:18 +02:00
Anton Wilhelm
7bdcadc7d7 [build] 4.9.4 next 2019-05-05 18:41:17 +02:00
Anton Wilhelm
5bd24fb83c Do not commit any files in lib during release 2019-05-05 18:35:34 +02:00
Anton Wilhelm
76cc0f672b Cleanup gitignore 2019-05-05 18:12:20 +02:00
Anton Wilhelm
3f50381090 Add matomo plugin to build script 2019-05-05 18:12:13 +02:00
Anton Wilhelm
b847c20cab Remove lib files from version control 2019-05-05 13:29:56 +02:00
James Hegedus
ce829b24d6
Merge pull request #827 from rodrigobdz/link-showcase
Fix #826: Link directly to showcase in readme and website
2019-04-26 17:01:22 +10:00
Rodrigo Bermudez Schettino
1ce53cf9ec
Readme: Improve outdated links to showcase
Link to Showcase in awesome-docsify.
2019-04-26 11:25:17 +08:00
Gorgi Kosev
bc1d8e4bda add scoring and sort to search plugin 2019-04-23 16:29:30 +02:00
Alexandru Cambose
78f5564a30 Updated to remove all headers under it 2019-04-23 07:08:29 +02:00
Alexandru Cambose
6cc069cb9f Added filtering in sidebar for ignoreSubHeading 2019-04-23 07:08:29 +02:00
Anton Wilhelm
d355272461 chore: add changelog 4.9.2 2019-04-21 12:06:17 +02:00
Anton Wilhelm
af161cd3b4 [build] 4.9.2 next 2019-04-21 12:06:16 +02:00
Anton Wilhelm
5bcb016bee Keep themes directory which is required for npm run dev 2019-04-21 12:05:41 +02:00
Anton Wilhelm
b38c2065e0 add execute access to release.sh 2019-04-21 12:01:04 +02:00
Anton Wilhelm
e5bab8d967 Add link to develop branch preview on netlify 2019-04-21 11:58:07 +02:00
Anton Wilhelm
da3e2d7b18 Remove lib directory from version control 2019-04-21 11:53:30 +02:00
Anton Wilhelm
b93a667f24 provide plugin for matomo 2019-04-21 11:17:14 +02:00
Anton Wilhelm
e8d850c9ba align dev index.html to production 2019-04-14 21:03:34 +02:00
Anton Wilhelm
514a027991
Minor update of bug template 2019-04-14 21:01:24 +02:00
Anton Wilhelm
314e2d9d39
Align IE support from root README.md 2019-04-14 11:27:03 +02:00
Anton Wilhelm
a86de3d81a Remove IE10 from supported browsers 2019-04-13 23:37:11 +02:00
Persevere Von
5f960102e7 Create .gitkeep
Fix #812
2019-04-13 17:38:57 +02:00
Anton Wilhelm
0bd5c8b020 fix #812 add empty themes directory for local watch setup 2019-04-13 15:42:22 +02:00
Anton Wilhelm
044a5ec2b8 add OS to GitHub template 2019-04-13 15:41:35 +02:00
Anton Wilhelm
b15eccfac0 add npm and nodejs version to template 2019-04-13 15:33:49 +02:00
Anton Wilhelm
4e0298088b
Merge pull request #817 from docsifyjs/update-github-templates
Update GitHub templates
2019-04-13 15:29:11 +02:00
Anton Wilhelm
09616dec06 Update GitHub templates 2019-04-13 15:28:12 +02:00
Anton Wilhelm
f74b53f53e
Merge pull request #733 from jthegedus/master
document customising page title with sidebar
2019-04-08 08:26:36 +02:00
Anton Wilhelm
bba44fb536
Merge pull request #714 from ENOVACOM/relative-path
feat: allows relative path, fixed #590
2019-04-07 22:23:18 +02:00
Anton Wilhelm
270fa6cb41
Merge pull request #807 from cyrilf/patch-1
Fix typo in edit button example
2019-04-05 19:58:06 +02:00
cyrilf
24e61f5e2f
Fix typo in Edit Button example
Missing trailing slash in the Edit button url
2019-04-06 00:11:54 +10:00
Sylvain Brocard
ca8ae50717 IE compatibility and add unit tests 2019-03-25 17:20:09 +01:00
Sylvain Brocard
31654f12ec feat: allows relative path, fixed #590 2019-03-25 16:33:03 +01:00
jthegedus
99dbaa3050 document customising page title with sidebar 2019-01-05 19:19:54 +11:00
40 changed files with 590 additions and 479 deletions

View file

@ -1,2 +0,0 @@
<!-- Love docsify? Please consider supporting our collective:
👉 https://opencollective.com/docsify/donate -->

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
---
<!-- Please don't delete this template or we'll close your issue -->
<!-- Please use English language -->
<!-- Before creating an issue please make sure you are using the latest version of Docsify. -->
<!-- Please ask questions on StackOverflow: https://stackoverflow.com/questions/ask?tags=docsify -->
## Bug Report
#### Steps to reproduce
#### What is current behaviour
#### What is the expected behaviour
#### Other relevant information
<!-- (Update "[ ]" to "[x]" to check a box) -->
- [ ] Bug does still occur when all/other plugins are disabled?
- Your OS:
- Node.js version:
- npm/yarn version:
- Browser version:
- Docsify version:
- Docsify plugins:
<!-- Love docsify? Please consider supporting our collective:
👉 https://opencollective.com/docsify/donate -->

View file

@ -0,0 +1,25 @@
---
name: Feature request
about: Suggest an idea for this project
---
<!-- Please don't delete this template or we'll close your issue -->
<!-- Please use English language -->
<!-- Before creating an issue please make sure you are using the latest version of Docsify. -->
<!-- Please ask questions on StackOverflow 👉 https://stackoverflow.com/questions/ask?tags=docsify -->
## 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?

View file

@ -1,5 +1,54 @@
Please makes sure these boxes are checked before submitting your PR, thank you! <!-- Please use English language -->
<!-- Please don't delete this template -->
<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->
**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:**
---
* [ ] 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. * [ ] DO NOT include files inside `lib` directory.

9
.gitignore vendored
View file

@ -1,8 +1,9 @@
*.log *.log
.DS_Store .DS_Store
/themes/*
!.gitkeep
node_modules
lib
.idea .idea
node_modules
themes/
lib/
# exceptions
!.gitkeep

View file

@ -1,3 +1,23 @@
<a name="4.9.4"></a>
## [4.9.4](https://github.com/docsifyjs/docsify/compare/v4.9.2...v4.9.4) (2019-05-05)
<a name="4.9.2"></a>
## [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))
<a name="4.9.1"></a> <a name="4.9.1"></a>
## [4.9.1](https://github.com/docsifyjs/docsify/compare/v4.9.0...v4.9.1) (2019-02-21) ## [4.9.1](https://github.com/docsifyjs/docsify/compare/v4.9.0...v4.9.1) (2019-02-21)

View file

@ -27,6 +27,7 @@
## Links ## Links
- [`develop` branch preview](https://docsifyjs.netlify.com/)
- [Documentation](https://docsify.js.org) - [Documentation](https://docsify.js.org)
- [CLI](https://github.com/docsifyjs/docsify-cli) - [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) - CDN: [UNPKG](https://unpkg.com/docsify/) | [jsDelivr](https://cdn.jsdelivr.net/npm/docsify/) | [cdnjs](https://cdnjs.com/libraries/docsify)
@ -40,7 +41,7 @@
- Smart full-text search plugin - Smart full-text search plugin
- Multiple themes - Multiple themes
- Useful plugin API - Useful plugin API
- Compatible with IE10+ - Compatible with IE11
- Support SSR ([example](https://github.com/docsifyjs/docsify-ssr-demo)) - Support SSR ([example](https://github.com/docsifyjs/docsify-ssr-demo))
- Support embedded files - Support embedded files
@ -54,7 +55,7 @@ Look at [this tutorial](https://docsify.js.org/#/quickstart)
These projects are using docsify to generate their sites. Pull requests welcome :blush: These projects are using docsify to generate their sites. Pull requests welcome :blush:
Move to [awesome-docsify](https://github.com/docsifyjs/awesome-docsify) Move to [awesome-docsify](https://github.com/docsifyjs/awesome-docsify#showcase)
## Similar projects ## Similar projects

View file

@ -55,6 +55,7 @@ const buildAllPlugin = function () {
var plugins = [ var plugins = [
{name: 'search', input: 'search/index.js'}, {name: 'search', input: 'search/index.js'},
{name: 'ga', input: 'ga.js'}, {name: 'ga', input: 'ga.js'},
{name: 'matomo', input: 'matomo.js'},
{name: 'emoji', input: 'emoji.js'}, {name: 'emoji', input: 'emoji.js'},
{name: 'external-script', input: 'external-script.js'}, {name: 'external-script', input: 'external-script.js'},
{name: 'front-matter', input: 'front-matter/index.js'}, {name: 'front-matter', input: 'front-matter/index.js'},

1
build/release.sh Normal file → Executable file
View file

@ -29,7 +29,6 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then
# commit # commit
git add -A git add -A
git add -f lib/ -A
git commit -m "[build] $VERSION $RELEASE_TAG" git commit -m "[build] $VERSION $RELEASE_TAG"
npm --no-git-tag-version version $VERSION --message "[release] $VERSION $RELEASE_TAG" npm --no-git-tag-version version $VERSION --message "[release] $VERSION $RELEASE_TAG"

View file

@ -16,12 +16,12 @@ See the [Quick start](quickstart.md) guide for more details.
- Multiple themes - Multiple themes
- Useful plugin API - Useful plugin API
- Emoji support - Emoji support
- Compatible with IE10+ - Compatible with IE11
- Support server-side rendering ([example](https://github.com/docsifyjs/docsify-ssr-demo)) - Support server-side rendering ([example](https://github.com/docsifyjs/docsify-ssr-demo))
## Examples ## Examples
Check out the [Showcase](https://github.com/docsifyjs/docsify/#showcase) to see docsify in use. Check out the [Showcase](https://github.com/docsifyjs/awesome-docsify#showcase) to see docsify in use.
## Donate ## Donate

View file

@ -1,6 +1,6 @@
![logo](_media/icon.svg) ![logo](_media/icon.svg)
# docsify <small>4.9.1</small> # docsify <small>4.9.4</small>
> A magical documentation site generator. > A magical documentation site generator.

View file

@ -23,7 +23,6 @@
- [Offline Mode(PWA)](pwa.md) - [Offline Mode(PWA)](pwa.md)
- [Server-Side Rendering(SSR)](ssr.md) - [Server-Side Rendering(SSR)](ssr.md)
- [Embed Files](embed-files.md) - [Embed Files](embed-files.md)
- [Generate static html](static.md)
- [Awesome docsify](awesome.md) - [Awesome docsify](awesome.md)
- [Changelog](changelog.md) - [Changelog](changelog.md)

View file

@ -150,6 +150,46 @@ 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 ## coverpage
- Type: `Boolean|String|String[]|Object` - Type: `Boolean|String|String[]|Object`

View file

@ -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) ![github pages](_images/deploy-github-pages.png)
!> You can also save files in the root directory and select `master branch`. !> 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 ## GitLab Pages

View file

@ -7,72 +7,24 @@ docsify extends Markdown syntax to make your documents more readable.
Important content like: Important content like:
```markdown ```markdown
> [!] **Time** is money, my friend! !> **Time** is money, my friend!
``` ```
is rendered as: is rendered as:
> [!] **Time** is money, my friend! !> **Time** is money, my friend!
## General tips ## General tips
General tips like: General tips like:
```markdown ```markdown
> [?] _TODO_ unit test ?> _TODO_ unit test
``` ```
are rendered as: 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 ## Ignore to compile link
@ -87,13 +39,13 @@ It will be compiled to `<a href="/#/demo/">link</a>` and will be loaded `/demo/R
Now you can do that Now you can do that
```md ```md
[link](/demo/ ":ignore") [link](/demo/ ':ignore')
``` ```
You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set title for link. You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set title for link.
```md ```md
[link](/demo/ ":ignore title") [link](/demo/ ':ignore title')
<a href="/demo/" title="title">link</a> <a href="/demo/" title="title">link</a>
``` ```
@ -101,14 +53,14 @@ You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set ti
## Set target attribute for link ## Set target attribute for link
```md ```md
[link](/demo ":target=_blank") [link](/demo ':target=_blank')
[link](/demo2 ":target=_self") [link](/demo2 ':target=_self')
``` ```
## Disable link ## Disable link
```md ```md
[link](/demo ":disabled") [link](/demo ':disabled')
``` ```
## Github Task Lists ## Github Task Lists
@ -132,17 +84,17 @@ You will get `<a href="/demo/">link</a>`html. Do not worry, you can still set ti
## Image resizing ## Image resizing
```md ```md
![logo](https://docsify.js.org/_media/icon.svg ":size=50x100") ![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=100')
<!-- Support percentage --> <!-- Support percentage -->
![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=50x100')
![logo](https://docsify.js.org/_media/icon.svg ":size=100") ![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%')
## Customise ID for headings ## Customise ID for headings

View file

@ -1,137 +1,104 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="UTF-8" />
<title>docsify</title>
<link rel="icon" href="_media/favicon.ico" />
<meta
name="google-site-verification"
content="6t0LoIeFksrjF4c9sqUEsVXiQNxLp2hgoqo0KryT-sE"
/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta
name="keywords"
content="doc,docs,documentation,gitbook,creator,generator,github,jekyll,github-pages"
/>
<meta name="description" content="A magical documentation generator." />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<link
rel="stylesheet"
href="//unpkg.com/docsify/lib/themes/vue.css"
title="vue"
/>
<link
rel="stylesheet"
href="//unpkg.com/docsify/lib/themes/dark.css"
title="dark"
disabled
/>
<link
rel="stylesheet"
href="//unpkg.com/docsify/lib/themes/buble.css"
title="buble"
disabled
/>
<link
rel="stylesheet"
href="//unpkg.com/docsify/lib/themes/pure.css"
title="pure"
disabled
/>
<script src="//unpkg.com/docsify-plugin-codefund/index.js"></script>
<style>
nav.app-nav li ul {
min-width: 100px;
}
</style>
</head>
<body> <head>
<div id="app">Loading ...</div> <meta charset="UTF-8">
<script> <title>docsify</title>
window.$docsify = { <link rel="icon" href="_media/favicon.ico">
alias: { <meta name="google-site-verification" content="6t0LoIeFksrjF4c9sqUEsVXiQNxLp2hgoqo0KryT-sE" />
".*?/awesome": <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
"https://raw.githubusercontent.com/docsifyjs/awesome-docsify/master/README.md", <meta name="keywords" content="doc,docs,documentation,gitbook,creator,generator,github,jekyll,github-pages">
".*?/changelog": <meta name="description" content="A magical documentation generator.">
"https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG.md", <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
"/.*/_navbar.md": "/_navbar.md", <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="vue">
"/zh-cn/(.*)": <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/dark.css" title="dark" disabled>
"https://raw.githubusercontent.com/docsifyjs/docs-zh/master/$1", <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/buble.css" title="buble" disabled>
"/de-de/(.*)": <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/pure.css" title="pure" disabled>
"https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1", <script src="//unpkg.com/docsify-plugin-codefund/index.js"></script>
"/ru/(.*)": <style>
"https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1", nav.app-nav li ul {
"/es/(.*)": min-width: 100px;
"https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1" }
</style>
</head>
<body>
<div id="app">Loading ...</div>
<script>
window.$docsify = {
alias: {
'.*?/awesome': 'https://raw.githubusercontent.com/docsifyjs/awesome-docsify/master/README.md',
'.*?/changelog': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG.md',
'/.*/_navbar.md': '/_navbar.md',
'/zh-cn/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-zh/master/$1',
'/de-de/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1',
'/ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1',
'/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1'
},
auto2top: true,
coverpage: true,
executeScript: true,
loadSidebar: true,
loadNavbar: true,
mergeNavbar: true,
maxLevel: 4,
subMaxLevel: 2,
ga: 'UA-106147152-1',
matomo: {
host: '//matomo.thunderwave.de',
id: 6
},
name: 'docsify',
search: {
noData: {
'/de-de/': 'Keine Ergebnisse!',
'/zh-cn/': '没有结果!',
'/': 'No results!'
}, },
auto2top: true, paths: 'auto',
coverpage: true, placeholder: {
executeScript: true, '/de-de/': 'Suche',
loadSidebar: true, '/zh-cn/': '搜索',
loadNavbar: true, '/': 'Search'
mergeNavbar: true, }
maxLevel: 4, },
subMaxLevel: 2, formatUpdated: '{MM}/{DD} {HH}:{mm}',
ga: "UA-106147152-1", plugins: [
name: "docsify", function (hook, vm) {
search: { hook.beforeEach(function (html) {
noData: { if (/githubusercontent\.com/.test(vm.route.file)) {
"/de-de/": "Keine Ergebnisse!", url = vm.route.file
"/zh-cn/": "没有结果!", .replace('raw.githubusercontent.com', 'github.com')
"/": "No results!" .replace(/\/master/, '/blob/master')
}, } else {
paths: "auto", url = 'https://github.com/docsifyjs/docsify/blob/master/docs/' + vm.route.file
placeholder: { }
"/de-de/": "Suche", var editHtml = '[:memo: Edit Document](' + url + ')\n'
"/zh-cn/": "搜索",
"/": "Search" return editHtml
} + html
+ '\n\n----\n\n'
+ '<a href="https://docsify.js.org" target="_blank" style="color: inherit; font-weight: normal; text-decoration: none;">Powered by docsify</a>'
})
}, },
formatUpdated: "{MM}/{DD} {HH}:{mm}", DocsifyCodefund.create('fae1f9a4-870c-4c25-b8e0-c80464f7a95c')
plugins: [ ]
function(hook, vm) { }
hook.beforeEach(function(html) { </script>
if (/githubusercontent\.com/.test(vm.route.file)) { <script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
url = vm.route.file <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
.replace("raw.githubusercontent.com", "github.com") <script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
.replace(/\/master/, "/blob/master"); <script src="//unpkg.com/docsify/lib/plugins/matomo.min.js"></script>
} else { <script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
url = <script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
"https://github.com/docsifyjs/docsify/blob/master/docs/" + <script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
vm.route.file;
} <script>
var editHtml = "[:memo: Edit Document](" + url + ")\n"; ((window.gitter = {}).chat = {}).options = {
return ( room: 'docsifyjs/Lobby'
editHtml + };
html + </script>
"\n\n----\n\n" + <script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer></script>
'<a href="https://docsify.js.org" target="_blank" style="color: inherit; font-weight: normal; text-decoration: none;">Powered by docsify</a>' </body>
);
});
},
DocsifyCodefund.create("fae1f9a4-870c-4c25-b8e0-c80464f7a95c")
]
};
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
<script>
((window.gitter = {}).chat = {}).options = {
room: "docsifyjs/Lobby"
};
</script>
<script
src="https://sidecar.gitter.im/dist/sidecar.v1.js"
async
defer
></script>
</body>
</html> </html>

View file

@ -72,6 +72,16 @@ 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. !> 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
<!-- docs/_sidebar.md -->
* [Home](/)
* [Guide](guide.md "The greatest guide in the world")
```
## Table of Contents ## Table of Contents
Once you've created `_sidebar.md`, the sidebar content is automatically generated based on the headers in the markdown files. Once you've created `_sidebar.md`, the sidebar content is automatically generated based on the headers in the markdown files.

View file

@ -1,50 +0,0 @@
# 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: `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Doc</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="vue">
</head>
<body>
<!--inject-app-->
<!--inject-config-->
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
</body>
</html>`, // 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)

View file

@ -79,7 +79,7 @@ window.$docsify = {
function(hook, vm) { function(hook, vm) {
hook.beforeEach(function(html) { hook.beforeEach(function(html) {
var url = var url =
'https://github.com/docsifyjs/docsify/blob/master/docs' + 'https://github.com/docsifyjs/docsify/blob/master/docs/' +
vm.route.file; vm.route.file;
var editHtml = '[📝 EDIT DOCUMENT](' + url + ')\n'; var editHtml = '[📝 EDIT DOCUMENT](' + url + ')\n';

View file

@ -21,48 +21,64 @@
<script> <script>
window.$docsify = { window.$docsify = {
alias: { alias: {
'.*?/changelog': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG', '.*?/awesome': 'https://raw.githubusercontent.com/docsifyjs/awesome-docsify/master/README.md',
'.*?/changelog': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG.md',
'/.*/_navbar.md': '/_navbar.md', '/.*/_navbar.md': '/_navbar.md',
'/zh-cn/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-zh/master/$1', '/zh-cn/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-zh/master/$1',
'/de-de/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1', '/de-de/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1',
'/ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1', '/ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1',
'/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1' '/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1'
}, },
notFoundPage: '_404.html',
auto2top: true, auto2top: true,
basePath: '/docs/', basePath: '/docs/',
executeScript: true,
loadNavbar: true,
loadSidebar: true,
coverpage: true, coverpage: true,
name: 'docsify', executeScript: true,
subMaxLevel: 2, loadSidebar: true,
loadNavbar: true,
mergeNavbar: true, mergeNavbar: true,
maxLevel: 4,
subMaxLevel: 2,
name: 'docsify',
search: {
noData: {
'/de-de/': 'Keine Ergebnisse!',
'/zh-cn/': '没有结果!',
'/': 'No results!'
},
paths: 'auto',
placeholder: {
'/de-de/': 'Suche',
'/zh-cn/': '搜索',
'/': 'Search'
}
},
formatUpdated: '{MM}/{DD} {HH}:{mm}', formatUpdated: '{MM}/{DD} {HH}:{mm}',
plugins: [ plugins: [
function (hook, vm) { function (hook, vm) {
hook.beforeEach(function (html) { hook.beforeEach(function (html) {
var url
if (/githubusercontent\.com/.test(vm.route.file)) { if (/githubusercontent\.com/.test(vm.route.file)) {
url = vm.route.file url = vm.route.file
.replace('raw.githubusercontent.com', 'github.com') .replace('raw.githubusercontent.com', 'github.com')
.replace(/\/master/, '/blob/master') .replace(/\/master/, '/blob/master')
} else { } else {
url = 'https://github.com/docsifyjs/docsify/blob/master/' + vm.route.file url = 'https://github.com/docsifyjs/docsify/blob/master/docs/' + vm.route.file
} }
var editHtml = '[:memo: Edit Document](' + url + ')\n' var editHtml = '[:memo: Edit Document](' + url + ')\n'
return editHtml return editHtml
+ html + html
+ '\n\n----\n\n' + '\n\n----\n\n'
+ 'Last modified {docsify-updated} ' + '<a href="https://docsify.js.org" target="_blank" style="color: inherit; font-weight: normal; text-decoration: none;">Powered by docsify</a>'
+ editHtml
}) })
} },
] ]
} }
</script> </script>
<script src="/lib/docsify.js"></script> <script src="/lib/docsify.js"></script>
<script src="/lib/plugins/search.js"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
</body> </body>
</html> </html>

2
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "docsify", "name": "docsify",
"version": "4.9.1", "version": "4.9.4",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View file

@ -1,6 +1,6 @@
{ {
"name": "docsify", "name": "docsify",
"version": "4.9.1", "version": "4.9.4",
"description": "A magical documentation generator.", "description": "A magical documentation generator.",
"author": { "author": {
"name": "qingwei-li", "name": "qingwei-li",
@ -32,11 +32,11 @@
"watch:css": "run-p 'css -- -o themes -w'", "watch:css": "run-p 'css -- -o themes -w'",
"watch:js": "node build/build.js", "watch:js": "node build/build.js",
"build:css:min": "mkdir lib/themes && run-p 'css -- -o lib/themes' && node build/mincss.js", "build:css:min": "mkdir lib/themes && run-p 'css -- -o lib/themes' && node build/mincss.js",
"build:css": "mkdir themes && run-p 'css -- -o themes'", "build:css": "mkdir -p themes && run-p 'css -- -o themes'",
"build:js": "cross-env NODE_ENV=production node build/build.js", "build:js": "cross-env NODE_ENV=production node build/build.js",
"build:ssr": "node build/ssr.js", "build:ssr": "node build/ssr.js",
"build:cover": "node build/cover.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:next": "cross-env RELEASE_TAG=next sh build/release.sh",
"pub": "sh build/release.sh", "pub": "sh build/release.sh",
"postinstall": "opencollective postinstall" "postinstall": "opencollective postinstall"

View file

@ -22,7 +22,7 @@ function mainTpl(config) {
html += tpl.corner(config.repo) html += tpl.corner(config.repo)
} }
if (config.coverpage) { if (config.coverpage) {
html += '<!--cover-->' html += tpl.cover()
} }
html += tpl.main(config) html += tpl.main(config)
@ -31,13 +31,12 @@ function mainTpl(config) {
} }
export default class Renderer { export default class Renderer {
constructor({template, config, cache, path}) { constructor({template, config, cache}) {
this.html = template this.html = template
this.config = config = Object.assign({}, config, { this.config = config = Object.assign({}, config, {
routerMode: 'history' routerMode: 'history'
}) })
this.cache = cache this.cache = cache
this.path = path
this.router = new AbstractHistory(config) this.router = new AbstractHistory(config)
this.compiler = new Compiler(config, this.router) this.compiler = new Compiler(config, this.router)
@ -53,19 +52,9 @@ export default class Renderer {
} }
_getPath(url) { _getPath(url) {
const path = resolve(this.path, url) const file = this.router.getFile(url)
const file = this.router.getFile(path)
return file
}
async render(url) { return isAbsolutePath(file) ? file : cwd(`./${file}`)
const content = await this.renderToString(url)
return {
content,
url: this.router.parse(url).path,
path: this._getPath(url)
}
} }
async renderToString(url) { async renderToString(url) {
@ -77,35 +66,32 @@ export default class Renderer {
if (loadSidebar) { if (loadSidebar) {
const name = loadSidebar === true ? '_sidebar.md' : loadSidebar const name = loadSidebar === true ? '_sidebar.md' : loadSidebar
const sidebarFile = this._getPath(resolvePathname(name, url)) const sidebarFile = this._getPath(resolve(url, `./${name}`))
this._renderHtml('sidebar', await this._render(sidebarFile, 'sidebar')) this._renderHtml('sidebar', await this._render(sidebarFile, 'sidebar'))
} }
if (loadNavbar) { if (loadNavbar) {
const name = loadNavbar === true ? '_navbar.md' : loadNavbar const name = loadNavbar === true ? '_navbar.md' : loadNavbar
const navbarFile = this._getPath(resolvePathname(name, url)) const navbarFile = this._getPath(resolve(url, `./${name}`))
this._renderHtml('navbar', await this._render(navbarFile, 'navbar')) this._renderHtml('navbar', await this._render(navbarFile, 'navbar'))
} }
if (coverpage) { if (coverpage) {
let name = null let path = null
if (typeof coverpage === 'string') {
if (typeof coverpage === 'string' || coverpage === true) { if (url === '/') {
if (url === 'README.md') { path = coverpage
name = coverpage === true ? '_coverpage.md' : coverpage
} }
} else if (Array.isArray(coverpage)) { } else if (Array.isArray(coverpage)) {
name = coverpage.indexOf(url) > -1 && '_coverpage.md' path = coverpage.indexOf(url) > -1 && '_coverpage.md'
} else { } else {
const cover = coverpage[url] const cover = coverpage[url]
name = cover === true ? '_coverpage.md' : cover path = cover === true ? '_coverpage.md' : cover
} }
if (name) { const coverFile = this._getPath(resolve(url, `./${path}`))
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 const html = this.html
@ -122,7 +108,6 @@ export default class Renderer {
async _render(path, type) { async _render(path, type) {
let html = await this._loadFile(path) let html = await this._loadFile(path)
const {subMaxLevel, maxLevel} = this.config const {subMaxLevel, maxLevel} = this.config
let tokens let tokens
@ -141,8 +126,7 @@ export default class Renderer {
tokens = await new Promise(r => { tokens = await new Promise(r => {
prerenderEmbed( prerenderEmbed(
{ {
// Url is absolute path fetch: url => this._loadFile(this._getPath(url)),
fetch: url => this._loadFile(this._getPath('.' + url)),
compiler: this.compiler, compiler: this.compiler,
raw: html raw: html
}, },
@ -179,7 +163,7 @@ export default class Renderer {
return content return content
} catch (e) { } catch (e) {
this.lock = this.lock || 0 this.lock = this.lock || 0
if (++this.lock > 4) { if (++this.lock > 10) {
this.lock = 0 this.lock = 0
return return
} }

View file

@ -37,5 +37,5 @@
"integrity": "sha1-6DWIAbhrg7F1YNTjw4LXrvIQCUQ=" "integrity": "sha1-6DWIAbhrg7F1YNTjw4LXrvIQCUQ="
} }
}, },
"version": "4.9.1" "version": "4.9.4"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "docsify-server-renderer", "name": "docsify-server-renderer",
"version": "4.9.1", "version": "4.9.4",
"description": "docsify server renderer", "description": "docsify server renderer",
"author": { "author": {
"name": "qingwei-li", "name": "qingwei-li",

View file

@ -25,7 +25,8 @@ export default function () {
formatUpdated: '', formatUpdated: '',
externalLinkTarget: '_blank', externalLinkTarget: '_blank',
routerMode: 'hash', routerMode: 'hash',
noCompileLinks: [] noCompileLinks: [],
relativePath: false
}, },
window.$docsify window.$docsify
) )

View file

@ -1,12 +1,6 @@
import marked from 'marked' import marked from 'marked'
import Prism from 'prismjs' import Prism from 'prismjs'
import { import {helper as helperTpl, tree as treeTpl} from './tpl'
helper as helperTpl,
newHelper as newHelperTpl,
tree as treeTpl,
cover as coverTpl,
details as detailsTpl
} from './tpl'
import {genTree} from './gen-tree' import {genTree} from './gen-tree'
import {slugify} from './slugify' import {slugify} from './slugify'
import {emojify} from './emojify' import {emojify} from './emojify'
@ -197,7 +191,7 @@ export class Compiler {
/** /**
* Render anchor tag * Render anchor tag
* @link https://marked.js.org/#/USING_PRO.md#renderer * @link https://github.com/markedjs/marked#overriding-renderer-methods
*/ */
origin.heading = renderer.heading = function (text, level) { origin.heading = renderer.heading = function (text, level) {
let {str, config} = getAndRemoveConfig(text) let {str, config} = getAndRemoveConfig(text)
@ -309,68 +303,22 @@ export class Compiler {
return `<img src="${url}"data-origin="${href}" alt="${text}"${attrs}>` return `<img src="${url}"data-origin="${href}" alt="${text}"${attrs}>`
} }
origin.list = renderer.list = function (body, ordered, start) { origin.list = renderer.list = function (body, ordered, start) {
const isTaskList = /<li class="task-list-item">/.test( const isTaskList = /<li class="task-list-item">/.test(body.split('class="task-list"')[0])
body.split('class="task-list"')[0]
)
const isStartReq = start && start > 1 const isStartReq = start && start > 1
const tag = ordered ? 'ol' : 'ul' const tag = ordered ? 'ol' : 'ul'
const tagAttrs = [ const tagAttrs = [
isTaskList ? 'class="task-list"' : '', (isTaskList ? 'class="task-list"' : ''),
isStartReq ? `start="${start}"` : '' (isStartReq ? `start="${start}"` : '')
] ].join(' ').trim()
.join(' ')
.trim()
return `<${tag} ${tagAttrs}>${body}</${tag}>` return `<${tag} ${tagAttrs}>${body}</${tag}>`
} }
origin.listitem = renderer.listitem = function (text) { origin.listitem = renderer.listitem = function (text) {
const isTaskItem = /^(<input.*type="checkbox"[^>]*>)/.test(text) const isTaskItem = /^(<input.*type="checkbox"[^>]*>)/.test(text)
const html = isTaskItem ? const html = isTaskItem ? `<li class="task-list-item"><label>${text}</label></li>` : `<li>${text}</li>`
`<li class="task-list-item"><label>${text}</label></li>` :
`<li>${text}</li>`
return html return html
} }
origin.blockquote = renderer.blockquote = function (quote) {
const m = quote.match(/^\<p\>(\[\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\>([^<]+)<\/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 renderer.origin = origin
@ -381,13 +329,25 @@ export class Compiler {
* Compile sidebar * Compile sidebar
*/ */
sidebar(text, level) { sidebar(text, level) {
const {toc} = this
const currentPath = this.router.getCurrentPath() const currentPath = this.router.getCurrentPath()
let html = '' let html = ''
if (text) { if (text) {
html = this.compile(text) html = this.compile(text)
} else { } else {
const tree = this.cacheTree[currentPath] || genTree(this.toc, level) 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)
html = treeTpl(tree, '<ul>{inner}</ul>') html = treeTpl(tree, '<ul>{inner}</ul>')
this.cacheTree[currentPath] = tree this.cacheTree[currentPath] = tree
} }
@ -412,7 +372,6 @@ export class Compiler {
for (let i = 0; i < toc.length; i++) { for (let i = 0; i < toc.length; i++) {
toc[i].ignoreSubHeading && toc.splice(i, 1) && i-- toc[i].ignoreSubHeading && toc.splice(i, 1) && i--
} }
const tree = cacheTree[currentPath] || genTree(toc, level) const tree = cacheTree[currentPath] || genTree(toc, level)
cacheTree[currentPath] = tree cacheTree[currentPath] = tree
@ -427,37 +386,12 @@ export class Compiler {
/** /**
* Compile cover page * Compile cover page
*/ */
cover(text, isHTML = false) { cover(text) {
let html = text const cacheToc = this.toc.slice()
if (!isHTML) { const html = this.compile(text)
const cacheToc = this.toc.slice()
html = this.compile(text) || ''
this.toc = cacheToc.slice()
}
const m = html this.toc = cacheToc.slice()
.trim()
.match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$')
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 coverTpl({ return html
style,
hasMask,
text: html
})
} }
} }

View file

@ -22,10 +22,8 @@ function walkFetchEmbed({embedTokens, compile, fetch}, cb) {
} else if (token.embed.type === 'code') { } else if (token.embed.type === 'code') {
if (token.embed.fragment) { if (token.embed.fragment) {
const fragment = token.embed.fragment const fragment = token.embed.fragment
const pattern = new RegExp( const pattern = new RegExp(`(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]`)
`(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\[${fragment}\\]` text = ((text.match(pattern) || [])[1] || '').trim()
)
text = ((text.match(pattern) || [])[1] || '').trim()
} }
embedToken = compile.lexer( embedToken = compile.lexer(
'```' + '```' +

View file

@ -175,10 +175,30 @@ export function renderMixin(proto) {
} }
dom.toggleClass(el, 'add', 'show') dom.toggleClass(el, 'add', 'show')
let html = this.compiler.cover(text, this.coverIsHTML) let html = this.coverIsHTML ? text : this.compiler.cover(text)
this._renderTo('.cover-placeholder', html, true) const m = html
.trim()
.match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$')
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() sticky()
} }
@ -208,9 +228,8 @@ export function initRender(vm) {
if (config.repo) { if (config.repo) {
html += tpl.corner(config.repo) html += tpl.corner(config.repo)
} }
if (config.coverpage) { if (config.coverpage) {
html += '<div class=cover-placeholder></div>' html += tpl.cover()
} }
if (config.logo) { if (config.logo) {

View file

@ -57,19 +57,16 @@ export function main(config) {
/** /**
* Cover Page * Cover Page
*/ */
export function cover({style, text, hasMask}) { export function cover() {
const SL = ', 100%, 85%' const SL = ', 100%, 85%'
style = const bgc =
style || 'linear-gradient(to left bottom, ' +
'background: linear-gradient(to left bottom, ' + `hsl(${Math.floor(Math.random() * 255) + SL}) 0%,` +
`hsl(${Math.floor(Math.random() * 255) + SL}) 0%,` + `hsl(${Math.floor(Math.random() * 255) + SL}) 100%)`
`hsl(${Math.floor(Math.random() * 255) + SL}) 100%)`
return ( return (
`<section class="cover show ${ `<section class="cover show" style="background: ${bgc}">` +
hasMask ? ' has-mask' : '' '<div class="cover-main"><!--cover--></div>' +
}" style="${style}">` +
`<div class="cover-main">${text}</div>` +
'<div class="mask"></div>' + '<div class="mask"></div>' +
'</section>' '</section>'
) )
@ -87,9 +84,7 @@ export function tree(toc, tpl = '<ul class="app-sub-sidebar">{inner}</ul>') {
} }
let innerHTML = '' let innerHTML = ''
toc.forEach(node => { toc.forEach(node => {
innerHTML += `<li><a class="section-link" href="${node.slug}">${ innerHTML += `<li><a class="section-link" href="${node.slug}">${node.title}</a></li>`
node.title
}</a></li>`
if (node.children) { if (node.children) {
innerHTML += tree(node.children, tpl) innerHTML += tree(node.children, tpl)
} }
@ -101,17 +96,6 @@ export function helper(className, content) {
return `<p class="${className}">${content.slice(5).trim()}</p>` return `<p class="${className}">${content.slice(5).trim()}</p>`
} }
export function newHelper(className, content) {
return `<div class="${className}">${content}</div>`
}
export function theme(color) { export function theme(color) {
return `<style>:root{--theme-color: ${color};}</style>` return `<style>:root{--theme-color: ${color};}</style>`
} }
export function details({open, summary, html}) {
return `<details ${open ? 'open=open' : ''}>${
summary ? `<summary>${summary}</summary>` : ''
}
${html}</details>`
}

View file

@ -7,7 +7,7 @@ export class AbstractHistory extends History {
this.mode = 'abstract' this.mode = 'abstract'
} }
parse(path = '') { parse(path) {
let query = '' let query = ''
const queryIndex = path.indexOf('?') const queryIndex = path.indexOf('?')

View file

@ -3,7 +3,8 @@ import {
isAbsolutePath, isAbsolutePath,
stringifyQuery, stringifyQuery,
cleanPath, cleanPath,
replaceSlug replaceSlug,
resolvePath
} from '../util' } from '../util'
import {noop, merge} from '../../util/core' import {noop, merge} from '../../util/core'
@ -21,11 +22,9 @@ function getAlias(path, alias, last) {
} }
function getFileName(path, ext) { function getFileName(path, ext) {
return /\.\w+$/.test(path) ? return new RegExp(`\\.(${ext.replace(/^\./, '')}|html)$`, 'g').test(path) ?
path : path :
/\/$/g.test(path) ? /\/$/g.test(path) ? `${path}README${ext}` : `${path}${ext}`
`${path}README${ext}` :
`${path}${ext}`
} }
export class History { export class History {
@ -75,9 +74,13 @@ export class History {
if (local) { if (local) {
const idIndex = currentRoute.indexOf('?') const idIndex = currentRoute.indexOf('?')
path = path =
(idIndex > 0 ? currentRoute.substr(0, idIndex) : currentRoute) + path (idIndex > 0 ? currentRoute.substring(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) return cleanPath('/' + path)
} }
} }

View file

@ -46,15 +46,27 @@ export const isAbsolutePath = cached(path => {
export const getParentPath = cached(path => { export const getParentPath = cached(path => {
return /\/$/g.test(path) ? return /\/$/g.test(path) ?
path : path :
(path = path.match(/(\S*\/)[^/]+$/)) ? (path = path.match(/(\S*\/)[^/]+$/)) ? path[1] : ''
path[1] :
''
}) })
export const cleanPath = cached(path => { export const cleanPath = cached(path => {
return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/') 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) { export function getPath(...args) {
return cleanPath(args.join('/')) return cleanPath(args.join('/'))
} }

37
src/plugins/matomo.js Normal file
View file

@ -0,0 +1,37 @@
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)

View file

@ -96,29 +96,27 @@ export function search(query) {
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
const post = data[i] const post = data[i]
let isMatch = false let matchesScore = 0
let resultStr = '' let resultStr = ''
const postTitle = post.title && post.title.trim() const postTitle = post.title && post.title.trim()
const postContent = post.body && post.body.trim() const postContent = post.body && post.body.trim()
const postUrl = post.slug || '' const postUrl = post.slug || ''
if (postTitle && postContent) { if (postTitle) {
keywords.forEach(keyword => { keywords.forEach( keyword => {
// From https://github.com/sindresorhus/escape-string-regexp // From https://github.com/sindresorhus/escape-string-regexp
const regEx = new RegExp( const regEx = new RegExp(
keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'), keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
'gi' 'gi'
) );
let indexTitle = -1 let indexTitle = -1
let indexContent = -1 let indexContent = -1
indexTitle = postTitle && postTitle.search(regEx) indexTitle = postTitle ? postTitle.search(regEx) : -1
indexContent = postContent && postContent.search(regEx) indexContent = postContent ? postContent.search(regEx) : -1
if (indexTitle < 0 && indexContent < 0) { if (indexTitle >= 0 || indexContent >= 0) {
isMatch = false matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0;
} else {
isMatch = true
if (indexContent < 0) { if (indexContent < 0) {
indexContent = 0 indexContent = 0
} }
@ -144,11 +142,12 @@ export function search(query) {
} }
}) })
if (isMatch) { if (matchesScore > 0) {
const matchingPost = { const matchingPost = {
title: escapeHtml(postTitle), title: escapeHtml(postTitle),
content: resultStr, content: postContent ? resultStr : '',
url: postUrl url: postUrl,
score: matchesScore
} }
matchingResults.push(matchingPost) matchingResults.push(matchingPost)
@ -156,7 +155,7 @@ export function search(query) {
} }
} }
return matchingResults return matchingResults.sort((r1, r2) => r2.score - r1.score);
} }
export function init(config, vm) { export function init(config, vm) {

View file

@ -321,9 +321,6 @@ body.sticky
border-bottom 1px solid #eee border-bottom 1px solid #eee
margin 2em 0 margin 2em 0
.markdown-section summary
cursor pointer
.markdown-section iframe .markdown-section iframe
border 1px solid #eee border 1px solid #eee
/* fix horizontal overflow on iOS Safari */ /* fix horizontal overflow on iOS Safari */
@ -354,7 +351,6 @@ body.sticky
background-color #f8f8f8 background-color #f8f8f8
.markdown-section p.tip .markdown-section p.tip
.markdown-section .docsify-tip
background-color #f8f8f8 background-color #f8f8f8
border-bottom-right-radius 2px border-bottom-right-radius 2px
border-left 4px solid #f66 border-left 4px solid #f66
@ -386,23 +382,9 @@ body.sticky
color $color-text color $color-text
.markdown-section p.warn .markdown-section p.warn
.markdown-section .docsify-warn
background rgba($color-primary, 0.1) background rgba($color-primary, 0.1)
border-radius 2px border-radius 2px
padding 1rem 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 .markdown-section ul.task-list > li
list-style-type none list-style-type none

View file

@ -216,7 +216,6 @@ pre::after
top 0 top 0
.markdown-section p.tip .markdown-section p.tip
.markdown-section .docsify-tip
background-color #282828 background-color #282828
color #657b83 color #657b83

62
test/unit/base.js Normal file
View file

@ -0,0 +1,62 @@
/* 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')
})
})

30
test/unit/util.js Normal file
View file

@ -0,0 +1,30 @@
/* 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')
})
})

1
themes/.gitkeep Normal file
View file

@ -0,0 +1 @@