Compare commits

...
66 Commits
Author SHA1 Message Date
qingwei.li 9defe1bf7d -> v1.5.2 2017-01-10 14:40:36 +08:00
qingwei.li b87f6ae5e8 bump 1.5.2 2017-01-10 14:40:21 +08:00
qingwei.li b8b9dbc872 Fixed number at the beginning of the slug, fixed #51 2017-01-10 14:39:40 +08:00
qingwei.li f7779b01d9 -> v1.5.1 2017-01-09 17:50:54 +08:00
qingwei.li 1c935b2fd7 bump 1.5.1 2017-01-09 17:50:43 +08:00
cinwell.liandGitHub 114955558e Remove HTML tag when handling slug, fixed #49 (#50)
* Remove HTML tag when handling slug, fixed #49

* Fix slugify
2017-01-09 17:47:38 +08:00
qingwei.li 847cf3b656 Update readme 2017-01-05 10:33:48 +08:00
Sina Nedadahandehandcinwell.li 356b937d44 Clean up readme (#48)
* Readme/homepage cleanup

* Readme cleanup
2017-01-05 10:31:41 +08:00
qingwei.li 8df57f0bc2 -> v1.5.0 2017-01-04 21:49:51 +08:00
qingwei.li 73dfbf5be3 Update package size 2017-01-04 21:49:16 +08:00
qingwei.li ecba3f1b05 bump 1.5.0 2017-01-04 21:42:40 +08:00
qingwei.li e5452243b1 Update docs 2017-01-04 21:41:35 +08:00
qingwei.li 8b1000a4a5 feat: Markdown parser is configurable, #42 2017-01-04 21:41:08 +08:00
qingwei.li 897283418a init config by window. 2017-01-04 20:47:55 +08:00
qingwei.li 7be6baae7a Fix nav highlight 2017-01-04 20:04:15 +08:00
qingwei.li 24ab3d4d10 Update change log 2017-01-03 15:50:31 +08:00
qingwei.li 424a243c5c Fix slugify 2017-01-03 15:48:57 +08:00
rozboandcinwell.li 9ce47c48af add showcase and edit Development Tips (#47) 2017-01-02 07:31:03 +08:00
qingwei.li 4e7485aa1f Update version 2017-01-01 12:02:06 +08:00
qingwei.li cb592e7bf0 -> v1.4.3 2017-01-01 12:01:36 +08:00
qingwei.li 3c01d1f82d bump 1.4.3 2017-01-01 12:01:23 +08:00
qingwei.li 00253d3148 Tweak style 2017-01-01 12:01:01 +08:00
qingwei.li d23881ba7c Update version 2016-12-31 22:23:47 +08:00
qingwei.li f0a99c0d1d Update change log 2016-12-31 22:06:43 +08:00
qingwei.li b952a3a08c -> v1.4.2 2016-12-31 22:05:10 +08:00
qingwei.li 2bb8641303 bump 1.4.3 2016-12-31 22:04:54 +08:00
qingwei.li 66d7919fa9 Fix href type, fixed #46 2016-12-31 22:04:14 +08:00
qingwei.li 580767bf78 Clear dev.html 2016-12-31 15:12:28 +08:00
qingwei.li d6b996f4c1 Add changelog 2016-12-31 15:07:02 +08:00
qingwei.li b4e0d54d7b Fix menu toggle style 2016-12-31 14:53:27 +08:00
qingwei.li b15b286c5c -> v1.4.1 2016-12-31 14:16:54 +08:00
qingwei.li 5ab86271c2 bump 1.4.1 2016-12-31 14:16:39 +08:00
qingwei.li 9638eee50d fix generate slug, fixed #45 2016-12-31 14:16:15 +08:00
qingwei.li 375a1dd3e1 -> v1.4.0 2016-12-31 13:47:28 +08:00
qingwei.li 3069ad3928 bump 1.4.0 2016-12-31 13:47:16 +08:00
qingwei.li b287f57c86 Add custom cover background 2016-12-31 13:40:29 +08:00
qingwei.li e932ff66b9 max-sub-level => sub-max-level 2016-12-31 11:50:30 +08:00
nsinaandcinwell.li 7a10e4aecf Readme/homepage cleanup 2016-12-31 10:22:31 +08:00
qingwei.li 41e7ef6863 Add docs 2016-12-30 18:09:13 +08:00
qingwei.li 7ce166501b Add render sub menu 2016-12-30 17:58:39 +08:00
qingwei.li b9aeb4a922 Fix scroll highlight when Vue exist 2016-12-27 23:58:26 +08:00
qingwei.li 9ac8293c0a Update docs 2016-12-26 23:47:26 +08:00
qingwei.li aa3121eca2 Bye 🎅 2016-12-25 20:59:08 +08:00
qingwei.li 0e615abbdc -> v1.3.5 2016-12-25 20:13:21 +08:00
qingwei.li cb2b191ba1 bump 1.3.5 2016-12-25 20:13:11 +08:00
qingwei.li 6adcfffba9 fix vue 2016-12-25 20:12:03 +08:00
qingwei.li f165470265 -> v1.3.4 2016-12-25 18:34:14 +08:00
qingwei.li bbb7b4a9d6 bump 1.3.4 2016-12-25 18:33:57 +08:00
qingwei.li 540095ee35 Support vuep 2016-12-25 18:33:12 +08:00
qingwei.li bd354094c0 🎄 Merry Christmas 2016-12-24 20:32:04 +08:00
qingwei.li 6e81e66441 404.dev => dev 2016-12-24 19:50:41 +08:00
qingwei.li 67f9083ff7 Remove 404.html 2016-12-24 19:50:04 +08:00
qingwei.li 383b976ddd Update docs 2016-12-24 11:33:48 +08:00
qingwei.li 54ba970552 -> v1.3.3 2016-12-23 21:47:42 +08:00
qingwei.li 16623c9301 bump 1.3.3 2016-12-23 21:47:31 +08:00
qingwei.li 668c5ca714 fix lint 2016-12-23 21:47:15 +08:00
qingwei.li d0861d7427 Fixed cover rendering timing 2016-12-23 21:46:12 +08:00
qingwei.li 97669e0d28 Add similar projects into readme 2016-12-23 09:25:30 +08:00
qingwei.li a0408b7a38 -> v1.3.2 2016-12-23 01:20:57 +08:00
qingwei.li f917da8214 bump 1.3.2 2016-12-23 01:20:47 +08:00
qingwei.li 64309beee9 Fixed render link 2016-12-23 01:20:28 +08:00
qingwei.li 4c8c0349e6 -> v1.3.1 2016-12-23 00:25:05 +08:00
qingwei.li 91b6720219 bump 1.3.1 2016-12-23 00:24:45 +08:00
qingwei.li c93ba1ea16 Fixed cover page style 2016-12-23 00:24:24 +08:00
qingwei.li 4f5a150c17 update cdn 2016-12-22 01:03:52 +08:00
qingwei.li 801df6ae3e Update changelog
Update changelog
2016-12-22 00:30:30 +08:00
25 changed files with 898 additions and 343 deletions
+1
View File
@@ -1,3 +1,4 @@
.DS_Store
*.log
node_modules
yarn.lock
+72 -3
View File
@@ -1,12 +1,81 @@
## 1.5.2
### Bug fixes
- Fixed number at the beginning of the slug
## 1.5.1
### Bug fixes
- Remove HTML tag when handling slug
## 1.5.0
### Bug fixes
- Fix slugify.
- Fix nav highlight.
### Features
- Initialize the configuration by `window.$docsify`.
- Markdown parser is configurable.
## 1.4.3
### Bug fixes
- Tweak style.
## 1.4.2
### Bug fixes
- Fix toggle button style.
- Support `mailto`, `tel`, etc. href type
- Fix scroll to top.
## 1.4.1
### Bug fixes
- Fix generate slug.
## 1.4.0 Happly new year 🎉
### Features
- Display TOC in the custom sidebar, `data-sub-max-level`.
- Custom background in coverpage.
### Bug fixes
- Fix scroll highlight when Vue exist.
## 1.3.5
### Bug fixes
- Fix vue
## 1.3.4
### Bug fixes
- Supports [vuep](https://github.com/QingWei-Li/vuep)
## 1.3.3
### Bug fixes
- Fixed cover rendering timing
## 1.3.2
### Bug fixes
- Fixed render link
## 1.3.1
### Bug fixes
- Fixed cover page style
- Generate the correct link when rendering the article
## 1.3.0
### Features
- Add cover page
- add `<kbd>` style
- headling can be cliked
### Bug fixes
- sidebar highlight
- headling can be cliked
- add `<kbd>` style
### break change
- Navbar no longer fixed at the top
## 1.2.0
### Features
+15 -7
View File
@@ -19,7 +19,7 @@
- [CLI](https://github.com/QingWei-Li/docsify-cli)
## Features
- Simple and lightweight (~12kb gzipped)
- Simple and lightweight (~13kB gzipped)
- Multiple themes
- Not build static html files
@@ -42,12 +42,6 @@ index.html
</html>
```
Or create a `404.html` and `README.md` into `/docs`. Just remove `data-router`
```html
<script src="//unpkg.com/docsify"></script>
```
## CDN
- UNPKG [https://unpkg.com/docsify/](https://unpkg.com/docsify/)
- jsDelivr [http://www.jsdelivr.com/projects/docsify](http://www.jsdelivr.com/projects/docsify)
@@ -57,6 +51,11 @@ These open-source projects are using docsify to generate their sites. Pull reque
- [docsify](https://docsify.js.org) - A magical documentation site generator.
- [Snipaste](https://docs.snipaste.com/) - A new way to boost your productivity.
- [puck](https://puck.zz173.com/) - A small & magical php framework.
## Similar projects
- [docute](https://github.com/egoist/docute) - 📜 Effortlessly documentation done right
- [docpress](https://github.com/docpress/docpress) - Documentation website generator
## Contributing
@@ -69,11 +68,20 @@ These open-source projects are using docsify to generate their sites. Pull reque
## Development
### prepare
```shell
npm i && npm run dev
open http://localhost:3000
```
### More Language Highlight
```html
<script src="//unpkg.com/docsify"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.js"></script>
<script src="//unpkg.com/prismjs/components/prism-php.js"></script>
```
## License
MIT
+1 -1
View File
@@ -5,7 +5,7 @@ var fs = require('fs')
http.createServer(function (req, res) {
serveStatic('.')(req, res, function () {
res.writeHead(404, { 'Content-Type': 'text/html' })
res.end(fs.readFileSync('404.dev.html'))
res.end(fs.readFileSync('dev.html'))
})
}).listen(3000, '0.0.0.0')
View File
+169 -39
View File
@@ -8,7 +8,7 @@ mkdir docs && cd docs
```
### Create entry file
Create a `404.html` file
Create a `index.html` file
```html
<!DOCTYPE html>
@@ -20,7 +20,7 @@ Create a `404.html` file
<body>
<div id="app"></div>
</body>
<script src="//unpkg.com/docsify"></script>
<script src="//unpkg.com/docsify" data-router></script>
</html>
```
@@ -29,16 +29,16 @@ Create `README.md` as the main page
```
# Title
## balabala
## blabla
```
### Deploy!
Push and open the **GitHub Pages** feature
Push code and activate **GitHub Pages** via your repo's settings
![image](https://cloud.githubusercontent.com/assets/7565692/20639058/e65e6d22-b3f3-11e6-9b8b-6309c89826f2.png)
## CLI
Easy to setup and preivew a docs.
Easy to setup and preview a docs.
### Install
```shell
@@ -60,7 +60,11 @@ docsify serve docs
Read more [docsify-cli](https://github.com/QingWei-Li/docsify-cli)
## Themes
## More
### Themes
Currently available `vue.css` and `buble.css`
```html
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
@@ -74,22 +78,19 @@ Minified files
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/buble.css">
```
## More
### Multiple pages
If you need other pages, directly create the markdown file, such as `guide.md` is `/guide`.
If you need other pages, directly create the markdown file, such as `guide.md` is `/#/guide`.
### Navbar
Code in `404.html`
Code in `index.html`
```html
<nav>
<a href="/docsify/">En</a>
<a href="/docsify/zh-cn">中文</a>
<a href="/#/docsify/">En</a>
<a href="/#/docsify/zh-cn">中文</a>
</nav>
```
### CDN
- UNPKG [https://unpkg.com/docsify/](https://unpkg.com/docsify/)
- jsDelivr [http://www.jsdelivr.com/projects/docsify](http://www.jsdelivr.com/projects/docsify)
@@ -97,7 +98,7 @@ Code in `404.html`
### Cover Page
Through the markdown can generate a cover page. create a `_coverpage.md` and set `data-coverpage` in script tag.
Generate a cover page with markdown. Create a `_coverpage.md` and set `data-coverpage` in the script tag.
```markdown
![logo](_media/icon.svg)
@@ -115,31 +116,92 @@ Through the markdown can generate a cover page. create a `_coverpage.md` and set
[Get Started](#quick-start)
```
#### Custom background
Currently the background of the cover page is generated randomly. We can customize the background color, or add a background image.
### Options
```markdown
# docsify <small>1.2.0</small>
#### repo
> xxx
[GitHub](https://github.com/QingWei-Li/docsify/)
[Get Started](#quick-start)
<!-- background image -->
![](_media/bg.png)
<!-- background color -->
![color](#f0f0f0)
```
### Markdown parser
Docsify uses [marked](https://github.com/chjj/marked) to parse markdown. We can configure it
```js
window.$docsify = {
markdown: {
smartypants: true
}
}
```
And it can even be customized
```js
window.$docsify = {
markdown: function(marked) {
// ...
return marked
}
}
```
## Options
You can add configurations in the script tag attributes or with `window.$docsify`.
### repo
Display the [GitHub Corner](http://tholman.com/github-corners/) widget.
```html
<script src="//unpkg.com/docsify" data-repo="your/repo"></script>
```
#### max-level
Toc level.
```js
window.$docsify = {
repo: 'your/repo'
}
```
### max-level
TOC level.
```html
<script src="//unpkg.com/docsify" data-max-level="6"></script>
```
#### el
```js
window.$docsify = {
maxLevel: 6
}
```
### el
Root element.
```html
<script src="//unpkg.com/docsify" data-el="#app"></script>
```
#### sidebar-toggle
```js
window.$docsify = {
el: '#app'
}
```
### sidebar-toggle
Sidebar with toggle
@@ -147,9 +209,15 @@ Sidebar with toggle
<script src="//unpkg.com/docsify" data-sidebar-toggle></script>
```
#### sidebar
```js
window.$docsify = {
sidebarToggle: true
}
```
Custom sidebar. if it'set, the TOC will be disabeld. Bind global variables on the `data-sidebar`.
### sidebar
Custom sidebar. If it's set, the TOC will be disabled. Bind global variables on the `data-sidebar`.
![image](https://cloud.githubusercontent.com/assets/7565692/20647425/de5ab1c2-b4ce-11e6-863a-135868f2f9b4.png)
@@ -171,10 +239,16 @@ Custom sidebar. if it'set, the TOC will be disabeld. Bind global variables on th
```
#### load-sidebar
```js
window.$docsify = {
sidebar: 'sidebar'
}
```
Load sidebar markdown file. If it is configured, load the current directory `_sidebar.md` by default. If the file isn't exist, sidebar will appear TOC.
** you should add `.nojekyll` into docs folder, to prevent GitHub Pages from ignoring the `_sidebar.md`**
### load-sidebar
Load sidebar markdown file. If it is configured, load the current directory `_sidebar.md` by default. If the file doesn't exist, the sidebar will appear as a TOC.
** you should add `.nojekyll` into docs folder to prevent GitHub Pages from ignoring the `_sidebar.md`**
```html
<script src="/lib/docsify.js" data-load-sidebar></script>
@@ -186,6 +260,12 @@ You can specify a file:
<script src="/lib/docsify.js" data-load-sidebar="_sidebar.md"></script>
```
```js
window.$docsify = {
loadSidebar: '_sidebar.md'
}
```
The contents of the file can be:
```markdown
@@ -195,16 +275,27 @@ The contents of the file can be:
- [Getting Started](/getting-started)
- [Dynamic Route Matching](/dynamic-matching)
- [Nested Routes](/nested-routes)
- [Programmatic Navigation](/navigation)
- [Named Routes](/named-routes)
- [Named Views](/named-views)
- [Redirect and Alias](/redirect-and-alias)
- [HTML5 History Mode](/history-mode)
```
#### load-navbar
### sub-max-level
Load navbar markdown file. If it is configured, load the current directory `_navbar.md` by default.
Display TOC in the custom sidebar. The default value is 0.
```html
<script src="/lib/docsify.js" data-load-sidebar data-max-sub-level="4"></script>
```
```js
window.$docsify = {
maxSubLevel: 4
}
```
### load-navbar
Load navbar markdown file. If it is configured, load the current directory `_navbar.md` by default.
```html
<script src="/lib/docsify.js" data-load-navbar></script>
@@ -216,6 +307,12 @@ You can specify a file:
<script src="/lib/docsify.js" data-load-navbar="_navbar.md"></script>
```
```js
window.$docsify = {
loadNavbar: '_navbar.md'
}
```
The contents of the file can be:
```markdown
@@ -232,15 +329,22 @@ If you write a sub level list, it will generate a dropdown list.
- [chinese](/zh-cn)
```
#### router
### router
Hash router. You can replace `404.html` with `index.html`.
Hash router.
```html
<script src="/lib/docsify.js" data-router></script>
```
#### auto2top
```js
window.$docsify = {
router: true
}
```
### auto2top
Scroll to the top on changing hash.
@@ -249,9 +353,15 @@ Scroll to the top on changing hash.
<script src="/lib/docsify.js" data-auto2top></script>
```
#### homepage
```js
window.$docsify = {
auto2top: true
}
```
`README.md` will be render as homepage for your website in docs folder, but sometimes we want to specify another file as a homepage, or even use the `README.md` in your repo. we can use (need `data-router`):
### homepage
`README.md` will be rendered as a homepage for your website in the docs folder, but sometimes we want to specify another file as a homepage, or even use the `README.md` in your repo. We can use (need `data-router`):
```html
<script src="/lib/docsify.js" data-homepage="https://raw.githubusercontent.com/QingWei-Li/docsify/master/README.md"></script>
@@ -260,7 +370,14 @@ Scroll to the top on changing hash.
```
#### basePath
```js
window.$docsify = {
homepage: true
}
```
### basePath
If your HTML entry file and the markdown files are in different directories, we can use:
@@ -272,7 +389,14 @@ If your HTML entry file and the markdown files are in different directories, we
```
#### coverpage
```js
window.$docsify = {
basePath: '/base/'
}
```
### coverpage
Generate cover page.
@@ -280,4 +404,10 @@ Generate cover page.
<script src="/lib/docsify.js" data-coverpage></script>
<!-- or -->
<script src="/lib/docsify.js" data-coverpage="other.md"></script>
```
```js
window.$docsify = {
coverpage: true
}
```
+2 -2
View File
@@ -1,10 +1,10 @@
![logo](_media/icon.svg)
# docsify <small>1.3.0</small>
# docsify <small>1.5.2</small>
> A magical documentation site generator.
- Simple and lightweight (~12kb gzipped)
- Simple and lightweight (~13kB gzipped)
- Multiple themes
- Not build static html files
+2 -2
View File
@@ -6,7 +6,7 @@
<link rel="icon" href="favicon.ico">
<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="//cdn.jsdelivr.net/docsify/latest/lib/themes/vue.css">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
</head>
<body>
<nav>
@@ -16,7 +16,7 @@
<div id="app"></div>
</body>
<script
src="//cdn.jsdelivr.net/docsify/latest/lib/docsify.min.js"
src="//unpkg.com/docsify/lib/docsify.min.js"
data-max-level="4"
data-sidebar-toggle
data-coverpage
+166 -31
View File
@@ -14,7 +14,7 @@ mkdir docs && cd docs
```
### 创建入口文件
创建一个 `404.html` 文件,内容为
创建一个 `index.html` 文件,内容为
```html
<!DOCTYPE html>
<html>
@@ -25,7 +25,7 @@ mkdir docs && cd docs
<body>
<div id="app"></div>
</body>
<script src="//unpkg.com/docsify"></script>
<script src="//unpkg.com/docsify" data-router></script>
</html>
```
@@ -65,8 +65,11 @@ docsify serve docs
更多选项参考 [docsify-cli](https://github.com/QingWei-Li/docsify-cli)
## 主题
目前提供 vue.css 和 buble.css,直接修改 `404.html` 里的 cdn 地址即可
## 更多功能
### 主题
目前提供 vue.css 和 buble.css,直接修改 `index.html` 里的 cdn 地址即可
```html
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
<link rel="stylesheet" href="//unpkg.com/docsify/themes/buble.css">
@@ -79,22 +82,21 @@ docsify serve docs
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/buble.css">
```
## 更多功能
### 多页面
`README.md` 作为主页面,如果需要其他页面,直接在文档目录下创建对应的 `*.md` 文件,例如创建一个 `guide.md` 那么对应的路由就是 `/guide`
`README.md` 作为主页面,如果需要其他页面,直接在文档目录下创建对应的 `*.md` 文件,例如创建一个 `guide.md` 那么对应的路由就是 `/#/guide`
### 导航
导航需要自己写在 `404.html` 文件里,效果参考本文档
导航需要自己写在 `index.html` 文件里,效果参考本文档
```html
<nav>
<a href="/docsify/">En</a>
<a href="/docsify/zh-cn">中文</a>
<a href="/#/docsify/">En</a>
<a href="/#/docsify/zh-cn">中文</a>
</nav>
```
### CDN
- UNPKG [https://unpkg.com/docsify/](https://unpkg.com/docsify/)
- jsDelivr [http://www.jsdelivr.com/projects/docsify](http://www.jsdelivr.com/projects/docsify)
@@ -120,30 +122,94 @@ docsify serve docs
```
#### 自定义封面背景
默认的背景是随机生成的,你可以自定义背景色或者背景图片。只需要在文档末尾用添加图片的 Markdown 语法
### 配置参数
```markdown
# docsify <small>1.2.0</small>
#### repo
参考本文档的右上角的 GitHub 图标,如果要开启的话,将 `404.html` 里的 script 改成
> xxx
[GitHub](https://github.com/QingWei-Li/docsify/)
[Get Started](#quick-start)
<!-- 背景图片 -->
![](_media/bg.png)
<!-- 背景色 -->
![color](#f0f0f0)
```
### 自定义 Markdown parser
默认使用 [marked](https://github.com/chjj/marked) 处理 markdown 部分,你可以修改默认配置
```js
window.$docsify = {
markdown: {
smartypants: true
}
}
```
甚至可以完全定制化
```js
window.$docsify = {
markdown: function(marked) {
// ...
return marked
}
}
```
## 配置参数
你可以通过在标签上添加属性的方式,或者给 `window.$docsify` 传配置信息。
### repo
参考本文档的右上角的 GitHub 图标,如果要开启的话,将 `index.html` 里的 script 改成
```html
<script src="//unpkg.com/docsify" data-repo="your/repo"></script>
```
#### max-level
```js
window.$docsify = {
repo: 'your/repo'
}
```
### max-level
目录最大展开层级,默认值为 6
```html
<script src="//unpkg.com/docsify" data-max-level="6"></script>
```
#### el
```js
window.$docsify = {
maxLevel: 6
}
```
### el
替换节点元素,默认为 `#app`
```html
<script src="//unpkg.com/docsify" data-el="#app"></script>
```
#### sidebar-toggle
```js
window.$docsify = {
el: '#app'
}
```
### sidebar-toggle
Sidebar 开关按钮
@@ -151,7 +217,14 @@ Sidebar 开关按钮
<script src="//unpkg.com/docsify" data-sidebar-toggle></script>
```
#### sidebar
```js
window.$docsify = {
sidebarToggle: true
}
```
### sidebar
设置后 TOC 功能将不可用,适合导航较多的文档,`data-sidebar` 传入全局变量名。
@@ -174,7 +247,14 @@ Sidebar 开关按钮
<script src="/lib/docsify.js" data-sidebar="sidebar"></script>
```
#### load-sidebar
```js
window.$docsify = {
sidebar: 'sidebar'
}
```
### load-sidebar
读取侧边栏配置文件,如果配置,默认加载当前目录下的 `_sidebar.md`。如果文件不存在,会显示 TOC 作为侧边栏内容。如果你有二级目录,也应该放置一份配置文件。
**如果用 `_` 开头作为文件名,你应该在文档目录下添加 `.nojekyll`,阻止 GitHub Pages 忽略下划线开头的文件。**
@@ -183,12 +263,19 @@ Sidebar 开关按钮
<script src="/lib/docsify.js" data-load-sidebar></script>
```
你可以指定侧边栏文件名
```html
<script src="/lib/docsify.js" data-load-sidebar="_sidebar.md"></script>
```
```js
window.$docsify = {
loadSidebar: '_sidebar.md'
}
```
`_sidebar.md` 的内容可以是这样的
```markdown
@@ -198,14 +285,24 @@ Sidebar 开关按钮
- [Getting Started](/getting-started)
- [Dynamic Route Matching](/dynamic-matching)
- [Nested Routes](/nested-routes)
- [Programmatic Navigation](/navigation)
- [Named Routes](/named-routes)
- [Named Views](/named-views)
- [Redirect and Alias](/redirect-and-alias)
- [HTML5 History Mode](/history-mode)
```
#### load-navbar
### sub-max-level
显示 TOC 在自定义的侧边栏里,默认最大显示 0 层。
```html
<script src="/lib/docsify.js" data-load-sidebar data-max-sub-level="4"></script>
```
```js
window.$docsify = {
maxSubLevel: 4
}
```
### load-navbar
读取导航配置文件,如果配置,默认加载当前目录下的 `_navbar.md`。如果文件不存在,会显示 html 里定义的导航栏。
@@ -219,6 +316,12 @@ Sidebar 开关按钮
<script src="/lib/docsify.js" data-load-navbar="_navbar.md"></script>
```
```js
window.$docsify = {
loadNavbar: '_navbar.md'
}
```
`_navbar.md` 的内容可以是这样
```markdown
@@ -235,15 +338,21 @@ Sidebar 开关按钮
```
#### router
### router
开启 hash router 功能,此时可以创建 `index.html` 作为入口文件,同时多页面切换不会重新加载资源。资源路径会被替换成 `/#/` 的形式。
开启 hash router 功能,同时多页面切换不会重新加载资源。资源路径会被替换成 `/#/` 的形式。
```html
<script src="/lib/docsify.js" data-router></script>
```
#### auto2top
```js
window.$docsify = {
router: true
}
```
### auto2top
切换路由时自动跳转到页面顶部
@@ -252,7 +361,13 @@ Sidebar 开关按钮
<script src="/lib/docsify.js" data-auto2top></script>
```
#### homepage
```js
window.$docsify = {
auto2top: true
}
```
### homepage
默认情况下网站会将根目录下 `README.md` 作为首页渲染,但是有些时候我们想指定其他文件,甚至想直接将 repo 下的 README 作为首页。你可以这样做(需要设置 `data-router`):
@@ -263,7 +378,13 @@ Sidebar 开关按钮
<script src="/lib/docsify.js" data-homepage="Welcome.md"></script>
```
#### basePath
```js
window.$docsify = {
homepage: true
}
```
### basePath
指定加载文档的路径,如果你的 HTML 入口文件和文档是放在不同地方,你可以设置:
@@ -274,9 +395,16 @@ Sidebar 开关按钮
<script src="/lib/docsify.js" data-base-path="https://docsify.js.org/"></script>
```
#### coverpage
生成封面,参考 [#封面](#封面).
```js
window.$docsify = {
basePath: '/base/'
}
```
### coverpage
生成封面,参考 [#封面](/zh-cn#封面).
```html
<script src="/lib/docsify.js" data-coverpage></script>
@@ -284,3 +412,10 @@ Sidebar 开关按钮
<script src="/lib/docsify.js" data-coverpage="other.md"></script>
```
```js
window.$docsify = {
coverpage: true
}
```
+194 -111
View File
@@ -114,6 +114,60 @@ function isMobile () {
return document.body.clientWidth <= 600
}
function slugify (string) {
var re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g;
var maintainCase = false;
var replacement = '-';
slugify.occurrences = slugify.occurrences || {};
if (typeof string !== 'string') { return '' }
if (!maintainCase) { string = string.toLowerCase(); }
var slug = string.trim()
.replace(/<[^>\d]+>/g, '')
.replace(re, '')
.replace(/\s/g, replacement)
.replace(/-+/g, replacement)
.replace(/^(\d)/, '_$1');
var occurrences = slugify.occurrences[slug];
if (slugify.occurrences.hasOwnProperty(slug)) {
occurrences++;
} else {
occurrences = 0;
}
slugify.occurrences[slug] = occurrences;
if (occurrences) {
slug = slug + '-' + occurrences;
}
return slug
}
slugify.clear = function () {
slugify.occurrences = {};
};
var hasOwnProperty = Object.prototype.hasOwnProperty;
var merge = Object.assign || function (to) {
var arguments$1 = arguments;
for (var i = 1; i < arguments.length; i++) {
var from = Object(arguments$1[i]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
}
return to
};
/**
* Active sidebar when scroll
* @link https://buble.surge.sh/
@@ -130,7 +184,10 @@ function scrollActiveSidebar () {
var li = lis[i];
var href = li.querySelector('a').getAttribute('href');
if (href !== '/') { href = href.match(/#([^#]+)$/g)[0].slice(1); }
if (href !== '/') {
var match = href.match('#([^#]+)$');
if (match && match.length) { href = match[0].slice(1); }
}
nav[decodeURIComponent(href)] = li;
}
@@ -174,19 +231,23 @@ function activeLink (dom, activeParent) {
var host = window.location.href;
dom = typeof dom === 'object' ? dom : document.querySelector(dom);
if (!dom) { return
if (!dom) { return }
var target;[].slice.call(dom.querySelectorAll('a'))
.sort(function (a, b) { return b.href.length - a.href.length; })
.forEach(function (node) {
if (host.indexOf(node.href) === 0 && !target) {
activeParent
? node.parentNode.setAttribute('class', 'active')
: node.setAttribute('class', 'active');
target = node;
} else {
activeParent
? node.parentNode.removeAttribute('class')
: node.removeAttribute('class');
}
});
; }[].slice.call(dom.querySelectorAll('a')).forEach(function (node) {
if (node.href === host) {
activeParent
? node.parentNode.setAttribute('class', 'active')
: node.setAttribute('class', 'active');
} else {
activeParent
? node.parentNode.removeAttribute('class')
: node.removeAttribute('class');
}
});
return target
}
/**
@@ -199,19 +260,14 @@ function bindToggle (dom) {
dom.addEventListener('click', function () { return body.classList.toggle('close'); });
if (!/mobile/i.test(navigator.userAgent)) { return }
document.querySelector('aside').addEventListener('click', function (event) {
body.classList.toggle('close');
});
if (isMobile()) {
document.querySelector('aside')
.addEventListener('click', function (_) { return body.classList.toggle('close'); });
}
}
var cacheContentDOM;
function scroll2Top () {
if (!cacheContentDOM) {
var dom = isMobile() ? 'body' : 'section.content';
cacheContentDOM = document.querySelector(dom);
}
cacheContentDOM.scrollTop = 0;
document.body.scrollTop = 0;
}
function sticky () {
@@ -2338,7 +2394,10 @@ function corner (data) {
* Render main content
*/
function main (tpl) {
return ("<main>\n " + tpl + "\n <aside class=\"sidebar\"></aside>\n <section class=\"content\">\n <article class=\"markdown-section\"></article>\n </section>\n </main>")
var aside = tpl + "<aside class=\"sidebar\"></aside>";
return (isMobile() ? (aside + "<main>") : ("<main>" + aside)) +
"<section class=\"content\">\n <article class=\"markdown-section\"></article>\n </section>\n </main>"
}
/**
@@ -2348,11 +2407,11 @@ function cover () {
var SL = ', 100%, 85%';
var bgc = "linear-gradient(to left bottom, hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 0%, hsl(" + (Math.floor(Math.random() * 255) + SL) + ") 100%)";
return ("<section class=\"cover\" style=\"background: " + bgc + "\">\n <div class=\"cover-main\"></div>\n </section>")
return ("<section class=\"cover\" style=\"background: " + bgc + "\">\n <div class=\"cover-main\"></div>\n <div class=\"mask\"></div>\n </section>")
}
function toggle () {
return "<button class=\"sidebar-toggle\">\n <span></span><span></span><span></span>\n </button>"
return "<button class=\"sidebar-toggle\">\n <div class=\"sidebar-toggle-button\">\n <span></span><span></span><span></span>\n </div>\n </button>"
}
/**
@@ -2377,51 +2436,66 @@ function tree (toc, tpl) {
}
var OPTIONS$1 = {};
var markdown = marked;
var toc = [];
var CACHE = {};
var renderTo = function (dom, content) {
dom = typeof dom === 'object' ? dom : document.querySelector(dom);
dom.innerHTML = content;
slugify.clear();
return dom
};
var toc = [];
var renderer = new marked.Renderer();
/**
* render anchor tag
* @link https://github.com/chjj/marked#overriding-renderer-methods
* init render
* @param {Object} options
*/
renderer.heading = function (text, level) {
var slug = text.toLowerCase()
.replace(/<(?:.|\n)*?>/gm, '')
.replace(/[^\w|\u4e00-\u9fa5]+/g, '-');
var route = '';
function init (options) {
OPTIONS$1 = options;
if (OPTIONS$1.router) {
route = "#/" + (getRoute());
var renderer = new marked.Renderer();
/**
* render anchor tag
* @link https://github.com/chjj/marked#overriding-renderer-methods
*/
renderer.heading = function (text, level) {
var slug = slugify(text);
var route = '';
if (OPTIONS$1.router) {
route = "#/" + (getRoute());
}
toc.push({ level: level, slug: (route + "#" + (encodeURIComponent(slug))), title: text });
return ("<h" + level + " id=\"" + slug + "\"><a href=\"" + route + "#" + slug + "\" data-id=\"" + slug + "\" class=\"anchor\"><span>" + text + "</span></a></h" + level + ">")
};
// highlight code
renderer.code = function (code, lang) {
if ( lang === void 0 ) lang = '';
var hl = prism.highlight(code, prism.languages[lang] || prism.languages.markup)
.replace(/{{/g, '<span>{{</span>');
return ("<pre data-lang=\"" + lang + "\"><code class=\"lang-" + lang + "\">" + hl + "</code></pre>")
};
renderer.link = function (href, title, text) {
if (OPTIONS$1.router && !/:/.test(href)) {
href = ("#/" + href).replace(/\/\//g, '/');
}
return ("<a href=\"" + href + "\" title=\"" + (title || '') + "\">" + text + "</a>")
};
if (typeof OPTIONS$1.markdown === 'function') {
markdown.setOptions({ renderer: renderer });
markdown = OPTIONS$1.markdown.call(this, markdown);
} else {
markdown.setOptions(merge({ renderer: renderer }, OPTIONS$1.markdown));
}
toc.push({ level: level, slug: (route + "#" + (encodeURIComponent(slug))), title: text });
return ("<a href=\"" + route + "#" + slug + "\" data-id=\"" + slug + "\" class=\"anchor\"><h" + level + " id=\"" + slug + "\">" + text + "</h" + level + "></a>")
};
// highlight code
renderer.code = function (code, lang) {
if ( lang === void 0 ) lang = '';
var hl = prism.highlight(code, prism.languages[lang] || prism.languages.markup);
return ("<pre data-lang=\"" + lang + "\"><code class=\"lang-" + lang + "\">" + hl + "</code></pre>")
};
renderer.link = function (href, title, text) {
if (OPTIONS$1.router && !/^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(href)) {
href = !/^\/#/.test(href) ? ("#" + href) : href;
}
return ("<a href=\"" + href + "\" title=\"" + (title || '') + "\">" + text + "</a>")
};
marked.setOptions({ renderer: renderer });
}
/**
* App
@@ -2450,12 +2524,13 @@ function renderApp (dom, replace) {
* article
*/
function renderArticle (content) {
renderTo('article', content ? marked(content) : 'not found');
if (!renderSidebar.rendered) { renderSidebar(null, OPTIONS$1); }
if (!renderNavbar.rendered) { renderNavbar(null, OPTIONS$1); }
renderSidebar.rendered = false;
renderNavbar.rendered = false;
renderTo('article', content ? markdown(content) : 'not found');
if (!OPTIONS$1.sidebar && !OPTIONS$1.loadSidebar) { renderSidebar(); }
if (content && typeof Vue !== 'undefined' && typeof Vuep !== 'undefined') {
var vm = new Vue({ el: 'main' }); // eslint-disable-line
vm.$nextTick(function (_) { return scrollActiveSidebar(); });
}
if (OPTIONS$1.auto2top) { scroll2Top(); }
}
@@ -2465,9 +2540,8 @@ function renderArticle (content) {
function renderNavbar (content) {
if (CACHE.navbar && CACHE.navbar === content) { return }
CACHE.navbar = content;
renderNavbar.rendered = true;
if (content) { renderTo('nav', marked(content)); }
if (content) { renderTo('nav', markdown(content)); }
activeLink('nav');
}
@@ -2475,23 +2549,27 @@ function renderNavbar (content) {
* sidebar
*/
function renderSidebar (content) {
var isToc = false;
var html;
if (content) {
content = marked(content);
html = markdown(content);
} else if (OPTIONS$1.sidebar) {
content = tree(OPTIONS$1.sidebar, '<ul>');
html = tree(OPTIONS$1.sidebar, '<ul>');
} else {
content = tree(genTree(toc, OPTIONS$1.maxLevel), '<ul>');
isToc = true;
html = tree(genTree(toc, OPTIONS$1.maxLevel), '<ul>');
}
renderSidebar.rendered = true;
if (CACHE.sidebar && CACHE.sidebar === content) { return }
CACHE.sidebar = content;
renderTo('aside.sidebar', content);
if (isToc) { scrollActiveSidebar(); }
renderTo('aside.sidebar', html);
var target = activeLink('aside.sidebar', true);
if (content) { renderSubSidebar(target); }
toc = [];
scrollActiveSidebar();
}
function renderSubSidebar (target) {
if (!OPTIONS$1.subMaxLevel) { return }
target.parentNode.innerHTML += tree(genTree(toc, OPTIONS$1.subMaxLevel), '<ul>');
}
/**
@@ -2500,12 +2578,33 @@ function renderSidebar (content) {
function renderCover (content) {
renderCover.dom = renderCover.dom || document.querySelector('section.cover');
if (!content) {
renderCover.dom.classList.add('hidden');
} else {
renderCover.dom.classList.remove('hidden');
!renderCover.rendered && renderTo('.cover-main', marked(content));
renderCover.rendered = true;
renderCover.dom.classList.remove('show');
return
}
renderCover.dom.classList.add('show');
if (renderCover.rendered) { return }
// render cover
var html = markdown(content);
var match = html.trim().match('<p><img[^s]+src="(.*?)"[^a]+alt="(.*?)"></p>$');
// render background
if (match) {
var coverEl = document.querySelector('section.cover');
if (match[2] === 'color') {
coverEl.style.background = match[1];
} else {
coverEl.classList.add('has-mask');
coverEl.style.backgroundImage = "url(" + (match[1]) + ")";
}
html = html.replace(match[0], '');
}
renderTo('.cover-main', html);
renderCover.rendered = true;
sticky();
}
/**
@@ -2545,18 +2644,11 @@ function renderLoading (ref) {
}
}
/**
* Load Config
* @param {Object} options
*/
function config (options) {
OPTIONS$1 = options;
}
var OPTIONS = {
var OPTIONS = merge({
el: '#app',
repo: '',
maxLevel: 6,
subMaxLevel: 0,
sidebar: '',
sidebarToggle: false,
loadSidebar: null,
@@ -2566,7 +2658,7 @@ var OPTIONS = {
coverpage: '',
basePath: '',
auto2top: false
};
}, window.$docsify);
var script = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop();
// load configuration for script attribute
@@ -2582,7 +2674,7 @@ if (script) {
}
// load options
config(OPTIONS);
init(OPTIONS);
var cacheRoute = null;
var cacheXhr = null;
@@ -2591,7 +2683,6 @@ var mainRender = function (cb) {
var route = OPTIONS.basePath + getRoute();
if (cacheRoute === route) { return cb() }
var wait;
var basePath = cacheRoute = route;
if (!/\//.test(basePath)) {
@@ -2610,12 +2701,8 @@ var mainRender = function (cb) {
}
// Render Cover page
if (OPTIONS.coverpage) {
if (page === OPTIONS.homepage) {
load(OPTIONS.coverpage).then(renderCover);
} else {
renderCover();
}
if (OPTIONS.coverpage && page === OPTIONS.homepage) {
load(OPTIONS.coverpage).then(renderCover);
}
cacheXhr && cacheXhr.abort && cacheXhr.abort();
@@ -2623,23 +2710,20 @@ var mainRender = function (cb) {
cacheXhr = load(page, 'GET', renderLoading);
cacheXhr.then(function (result) {
renderArticle(result);
// clear cover
if (OPTIONS.coverpage && page !== OPTIONS.homepage) { renderCover(); }
// render sidebar
if (OPTIONS.loadSidebar) {
if (wait === false) { cb(); }
wait = false;
load(basePath + OPTIONS.loadSidebar)
.then(function (result) {
renderSidebar(result);
cb();
});
} else {
cb();
}
}, function (_) { return renderArticle(null); });
// Render sidebar
if (OPTIONS.loadSidebar) {
load(basePath + OPTIONS.loadSidebar).then(function (result) {
renderSidebar(result);
if (wait === false) { cb(); }
wait = false;
});
}
// Render navbar
if (OPTIONS.loadNavbar) {
load(basePath + OPTIONS.loadNavbar).then(renderNavbar);
@@ -2651,9 +2735,8 @@ var Docsify = function () {
var replace = dom !== document.body;
var main = function () {
mainRender(function (_) {
activeLink('aside.sidebar', true);
scrollIntoView();
OPTIONS.coverpage && sticky();
activeLink('nav');
});
};
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "docsify",
"version": "1.3.0",
"version": "1.5.2",
"description": "A magical documentation generator.",
"main": "lib/docsify.js",
"files": [
+26 -22
View File
@@ -16,7 +16,10 @@ export function scrollActiveSidebar () {
const li = lis[i]
let href = li.querySelector('a').getAttribute('href')
if (href !== '/') href = href.match(/#([^#]+)$/g)[0].slice(1)
if (href !== '/') {
const match = href.match('#([^#]+)$')
if (match && match.length) href = match[0].slice(1)
}
nav[decodeURIComponent(href)] = li
}
@@ -61,18 +64,24 @@ export function activeLink (dom, activeParent) {
dom = typeof dom === 'object' ? dom : document.querySelector(dom)
if (!dom) return
let target
;[].slice.call(dom.querySelectorAll('a')).forEach(node => {
if (node.href === host) {
activeParent
? node.parentNode.setAttribute('class', 'active')
: node.setAttribute('class', 'active')
} else {
activeParent
? node.parentNode.removeAttribute('class')
: node.removeAttribute('class')
}
})
;[].slice.call(dom.querySelectorAll('a'))
.sort((a, b) => b.href.length - a.href.length)
.forEach(node => {
if (host.indexOf(node.href) === 0 && !target) {
activeParent
? node.parentNode.setAttribute('class', 'active')
: node.setAttribute('class', 'active')
target = node
} else {
activeParent
? node.parentNode.removeAttribute('class')
: node.removeAttribute('class')
}
})
return target
}
/**
@@ -85,19 +94,14 @@ export function bindToggle (dom) {
dom.addEventListener('click', () => body.classList.toggle('close'))
if (!/mobile/i.test(navigator.userAgent)) return
document.querySelector('aside').addEventListener('click', event => {
body.classList.toggle('close')
})
if (isMobile()) {
document.querySelector('aside')
.addEventListener('click', _ => body.classList.toggle('close'))
}
}
let cacheContentDOM
export function scroll2Top () {
if (!cacheContentDOM) {
const dom = isMobile() ? 'body' : 'section.content'
cacheContentDOM = document.querySelector(dom)
}
cacheContentDOM.scrollTop = 0
document.body.scrollTop = 0
}
export function sticky () {
+17 -25
View File
@@ -1,11 +1,12 @@
import { load, camel2kebab, isNil, getRoute } from './util'
import { activeLink, scrollIntoView, sticky } from './event'
import { load, camel2kebab, isNil, getRoute, merge } from './util'
import { scrollIntoView, activeLink } from './event'
import * as render from './render'
const OPTIONS = {
const OPTIONS = merge({
el: '#app',
repo: '',
maxLevel: 6,
subMaxLevel: 0,
sidebar: '',
sidebarToggle: false,
loadSidebar: null,
@@ -15,7 +16,7 @@ const OPTIONS = {
coverpage: '',
basePath: '',
auto2top: false
}
}, window.$docsify)
const script = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop()
// load configuration for script attribute
@@ -31,7 +32,7 @@ if (script) {
}
// load options
render.config(OPTIONS)
render.init(OPTIONS)
let cacheRoute = null
let cacheXhr = null
@@ -40,7 +41,6 @@ const mainRender = function (cb) {
const route = OPTIONS.basePath + getRoute()
if (cacheRoute === route) return cb()
let wait
let basePath = cacheRoute = route
if (!/\//.test(basePath)) {
@@ -59,12 +59,8 @@ const mainRender = function (cb) {
}
// Render Cover page
if (OPTIONS.coverpage) {
if (page === OPTIONS.homepage) {
load(OPTIONS.coverpage).then(render.renderCover)
} else {
render.renderCover()
}
if (OPTIONS.coverpage && page === OPTIONS.homepage) {
load(OPTIONS.coverpage).then(render.renderCover)
}
cacheXhr && cacheXhr.abort && cacheXhr.abort()
@@ -72,23 +68,20 @@ const mainRender = function (cb) {
cacheXhr = load(page, 'GET', render.renderLoading)
cacheXhr.then(result => {
render.renderArticle(result)
// clear cover
if (OPTIONS.coverpage && page !== OPTIONS.homepage) render.renderCover()
// render sidebar
if (OPTIONS.loadSidebar) {
if (wait === false) cb()
wait = false
load(basePath + OPTIONS.loadSidebar)
.then(result => {
render.renderSidebar(result)
cb()
})
} else {
cb()
}
}, _ => render.renderArticle(null))
// Render sidebar
if (OPTIONS.loadSidebar) {
load(basePath + OPTIONS.loadSidebar).then(result => {
render.renderSidebar(result)
if (wait === false) cb()
wait = false
})
}
// Render navbar
if (OPTIONS.loadNavbar) {
load(basePath + OPTIONS.loadNavbar).then(render.renderNavbar)
@@ -100,9 +93,8 @@ const Docsify = function () {
const replace = dom !== document.body
const main = function () {
mainRender(_ => {
activeLink('aside.sidebar', true)
scrollIntoView()
OPTIONS.coverpage && sticky()
activeLink('nav')
})
}
+90 -59
View File
@@ -2,52 +2,67 @@ import marked from 'marked'
import Prism from 'prismjs'
import * as tpl from './tpl'
import { activeLink, scrollActiveSidebar, bindToggle, scroll2Top, sticky } from './event'
import { genTree, getRoute, isMobile } from './util'
import { genTree, getRoute, isMobile, slugify, merge } from './util'
let OPTIONS = {}
let markdown = marked
let toc = []
const CACHE = {}
const renderTo = function (dom, content) {
dom = typeof dom === 'object' ? dom : document.querySelector(dom)
dom.innerHTML = content
slugify.clear()
return dom
}
let toc = []
const renderer = new marked.Renderer()
/**
* render anchor tag
* @link https://github.com/chjj/marked#overriding-renderer-methods
* init render
* @param {Object} options
*/
renderer.heading = function (text, level) {
const slug = text.toLowerCase()
.replace(/<(?:.|\n)*?>/gm, '')
.replace(/[^\w|\u4e00-\u9fa5]+/g, '-')
let route = ''
export function init (options) {
OPTIONS = options
if (OPTIONS.router) {
route = `#/${getRoute()}`
const renderer = new marked.Renderer()
/**
* render anchor tag
* @link https://github.com/chjj/marked#overriding-renderer-methods
*/
renderer.heading = function (text, level) {
const slug = slugify(text)
let route = ''
if (OPTIONS.router) {
route = `#/${getRoute()}`
}
toc.push({ level, slug: `${route}#${encodeURIComponent(slug)}`, title: text })
return `<h${level} id="${slug}"><a href="${route}#${slug}" data-id="${slug}" class="anchor"><span>${text}</span></a></h${level}>`
}
// highlight code
renderer.code = function (code, lang = '') {
const hl = Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup)
.replace(/{{/g, '<span>{{</span>')
return `<pre data-lang="${lang}"><code class="lang-${lang}">${hl}</code></pre>`
}
renderer.link = function (href, title, text) {
if (OPTIONS.router && !/:/.test(href)) {
href = `#/${href}`.replace(/\/\//g, '/')
}
return `<a href="${href}" title="${title || ''}">${text}</a>`
}
toc.push({ level, slug: `${route}#${encodeURIComponent(slug)}`, title: text })
return `<a href="${route}#${slug}" data-id="${slug}" class="anchor"><h${level} id="${slug}">${text}</h${level}></a>`
}
// highlight code
renderer.code = function (code, lang = '') {
const hl = Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup)
return `<pre data-lang="${lang}"><code class="lang-${lang}">${hl}</code></pre>`
}
renderer.link = function (href, title, text) {
if (OPTIONS.router && !/^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/.test(href)) {
href = !/^\/#/.test(href) ? `#${href}` : href
if (typeof OPTIONS.markdown === 'function') {
markdown.setOptions({ renderer })
markdown = OPTIONS.markdown.call(this, markdown)
} else {
markdown.setOptions(merge({ renderer }, OPTIONS.markdown))
}
return `<a href="${href}" title="${title || ''}">${text}</a>`
}
marked.setOptions({ renderer })
/**
* App
@@ -76,12 +91,13 @@ export function renderApp (dom, replace) {
* article
*/
export function renderArticle (content) {
renderTo('article', content ? marked(content) : 'not found')
if (!renderSidebar.rendered) renderSidebar(null, OPTIONS)
if (!renderNavbar.rendered) renderNavbar(null, OPTIONS)
renderSidebar.rendered = false
renderNavbar.rendered = false
renderTo('article', content ? markdown(content) : 'not found')
if (!OPTIONS.sidebar && !OPTIONS.loadSidebar) renderSidebar()
if (content && typeof Vue !== 'undefined' && typeof Vuep !== 'undefined') {
const vm = new Vue({ el: 'main' }) // eslint-disable-line
vm.$nextTick(_ => scrollActiveSidebar())
}
if (OPTIONS.auto2top) scroll2Top()
}
@@ -91,9 +107,8 @@ export function renderArticle (content) {
export function renderNavbar (content) {
if (CACHE.navbar && CACHE.navbar === content) return
CACHE.navbar = content
renderNavbar.rendered = true
if (content) renderTo('nav', marked(content))
if (content) renderTo('nav', markdown(content))
activeLink('nav')
}
@@ -101,23 +116,27 @@ export function renderNavbar (content) {
* sidebar
*/
export function renderSidebar (content) {
let isToc = false
let html
if (content) {
content = marked(content)
html = markdown(content)
} else if (OPTIONS.sidebar) {
content = tpl.tree(OPTIONS.sidebar, '<ul>')
html = tpl.tree(OPTIONS.sidebar, '<ul>')
} else {
content = tpl.tree(genTree(toc, OPTIONS.maxLevel), '<ul>')
isToc = true
html = tpl.tree(genTree(toc, OPTIONS.maxLevel), '<ul>')
}
renderSidebar.rendered = true
if (CACHE.sidebar && CACHE.sidebar === content) return
CACHE.sidebar = content
renderTo('aside.sidebar', content)
if (isToc) scrollActiveSidebar()
renderTo('aside.sidebar', html)
const target = activeLink('aside.sidebar', true)
if (content) renderSubSidebar(target)
toc = []
scrollActiveSidebar()
}
export function renderSubSidebar (target) {
if (!OPTIONS.subMaxLevel) return
target.parentNode.innerHTML += tpl.tree(genTree(toc, OPTIONS.subMaxLevel), '<ul>')
}
/**
@@ -126,12 +145,33 @@ export function renderSidebar (content) {
export function renderCover (content) {
renderCover.dom = renderCover.dom || document.querySelector('section.cover')
if (!content) {
renderCover.dom.classList.add('hidden')
} else {
renderCover.dom.classList.remove('hidden')
!renderCover.rendered && renderTo('.cover-main', marked(content))
renderCover.rendered = true
renderCover.dom.classList.remove('show')
return
}
renderCover.dom.classList.add('show')
if (renderCover.rendered) return
// render cover
let html = markdown(content)
const match = html.trim().match('<p><img[^s]+src="(.*?)"[^a]+alt="(.*?)"></p>$')
// render background
if (match) {
const coverEl = document.querySelector('section.cover')
if (match[2] === 'color') {
coverEl.style.background = match[1]
} else {
coverEl.classList.add('has-mask')
coverEl.style.backgroundImage = `url(${match[1]})`
}
html = html.replace(match[0], '')
}
renderTo('.cover-main', html)
renderCover.rendered = true
sticky()
}
/**
@@ -166,12 +206,3 @@ export function renderLoading ({ loaded, total, step }) {
}, 200)
}
}
/**
* Load Config
* @param {Object} options
*/
export function config (options) {
OPTIONS = options
}
+28 -9
View File
@@ -1,16 +1,27 @@
section.cover {
&.hidden {
display: none;
align-items: center;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
height: 100vh;
display: none;
&.show {
display: flex;
}
height: 100vh;
position: relative;
&.has-mask .mask {
position: absolute;
size: 100%;
background-color: $color-bg;
opacity: .8;
}
.cover-main {
position: absolute 0 0 0 0;
padding: 20vh 0;
flex: 1;
text-align: center;
margin: 0 16px;
margin: -20px 16px 0;
z-index: 1;
}
a {
@@ -22,6 +33,11 @@ section.cover {
}
}
p {
margin: 1em 0;
line-height: 1.5rem;
}
h1 {
text-align: center;
font-size: 2.5rem;
@@ -30,6 +46,10 @@ section.cover {
font-weight: 300;
color: inherit;
a {
display: block;
}
small {
position: absolute;
bottom: -.4375rem;
@@ -50,8 +70,7 @@ section.cover {
line-height: 1.8;
}
p a {
margin-top: 1em;
.cover-main p:last-child a {
border-radius: 2em;
border: 1px solid $color-primary;
box-sizing: border-box;
+38 -11
View File
@@ -31,6 +31,7 @@ body {
letter-spacing: 0;
margin: 0;
overflow-x: hidden;
color: $color-text;
}
img {
@@ -95,7 +96,7 @@ nav {
display: inline-block;
ul {
background-color: rgba(#fff, .6);
background-color: rgba($color-bg, .6);
border: 1px solid $color-primary;
opacity: 0;
overflow: hidden;
@@ -150,7 +151,7 @@ nav {
}
svg {
color: #fff;
color: $color-bg;
height: 80px;
width: 80px;
fill: $color-primary;
@@ -159,14 +160,18 @@ nav {
/* main */
main {
size: 100% 100%;
size: 100vw 100%;
position: relative;
}
.anchor {
text-decoration: none;
transition: all .3s;
display: block;
display: inline-block;
span {
color: $color-text;
}
&:hover {
text-decoration: underline;
@@ -177,7 +182,7 @@ main {
.sidebar {
border-right: 1px solid rgba(0, 0, 0, .07);
overflow-y: auto;
padding-top: 40px;
padding: 40px 0;
position: absolute 0 * 0 0;
transition: transform 250ms ease-out;
width: $sidebar-width;
@@ -206,17 +211,18 @@ main {
.sidebar-toggle {
background-color: transparent;
border: 0;
bottom: 10px;
left: 10px;
outline: none;
position: absolute;
position: absolute * * 0 0;
text-align: center;
transition: opacity .3s;
width: 30px;
z-index: 30;
outline: none;
width: calc($sidebar-width - 16px);
padding: 10px;
background-color: rgba($color-bg, .8);
&:hover {
.sidebar-toggle-button:hover {
opacity: .4;
}
@@ -290,6 +296,10 @@ body.close {
transform: translateX(-$sidebar-width);
}
.sidebar-toggle {
width: auto;
}
.content {
left: 0;
}
@@ -308,6 +318,11 @@ body.close {
top: 30px;
}
main {
height: auto;
overflow-x: hidden;
}
.sidebar {
left: -$sidebar-width;
transition: transform 250ms ease-out;
@@ -315,7 +330,8 @@ body.close {
.content {
left: 0;
min-width: 100vw;
max-width: 100vw;
position: static;
transition: transform 250ms ease;
}
@@ -323,17 +339,28 @@ body.close {
transition: transform 250ms ease-out;
}
.sidebar-toggle {
width: auto;
background-color: transparent;
}
body.close {
.sidebar {
transform: translateX($sidebar-width);
}
.sidebar-toggle {
width: calc($sidebar-width - 16px);
background-color: rgba($color-bg, .8);
transition: 1s background-color;
}
.content {
transform: translateX($sidebar-width);
}
nav, .github-corner {
transform: translateX($sidebar-width);
display: none;
}
}
+3 -4
View File
@@ -1,18 +1,17 @@
@import url('https://fonts.googleapis.com/css?family=Inconsolata|Inconsolata-Bold');
$color-primary: #0074D9;
$color-bg: #fff;
$color-text: #34495e;
$sidebar-width: 16em;
@import "basic/layout";
@import "basic/coverpage";
body {
color: #34495e;
}
/* sidebar */
.sidebar {
color: #364149;
background-color: #fff;
background-color: $color-bg;
a {
color: #666;
+2
View File
@@ -1,3 +1,5 @@
$color-primary: #000;
$color-bg: #fff;
$color-text: #000;
$sidebar-width: 300px;
@import "basic/layout";
+4 -3
View File
@@ -1,20 +1,21 @@
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600');
$color-primary: #42b983;
$color-bg: #fff;
$color-text: #34495e;
$sidebar-width: 300px;
@import "basic/layout";
@import "basic/coverpage";
body {
background-color: #fff;
color: #34495e;
background-color: $color-bg;
}
/* sidebar */
.sidebar {
color: #364149;
background-color: #fff;
background-color: $color-bg;
li {
margin: 6px 15px;
+11 -8
View File
@@ -1,4 +1,4 @@
import { isMobile } from './util'
/**
* Render github corner
* @param {Object} data
@@ -23,13 +23,13 @@ export function corner (data) {
* Render main content
*/
export function main (tpl) {
return `<main>
${tpl}
<aside class="sidebar"></aside>
<section class="content">
const aside = `${tpl}<aside class="sidebar"></aside>`
return (isMobile() ? `${aside}<main>` : `<main>${aside}`) +
`<section class="content">
<article class="markdown-section"></article>
</section>
</main>`
</main>`
}
/**
@@ -41,13 +41,16 @@ export function cover () {
return `<section class="cover" style="background: ${bgc}">
<div class="cover-main"></div>
<div class="mask"></div>
</section>`
}
export function toggle () {
return `<button class="sidebar-toggle">
<span></span><span></span><span></span>
</button>`
<div class="sidebar-toggle-button">
<span></span><span></span><span></span>
</div>
</button>`
}
/**
+51
View File
@@ -106,3 +106,54 @@ export function isMobile () {
return document.body.clientWidth <= 600
}
export function slugify (string) {
const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^`{|}~]/g
const maintainCase = false
const replacement = '-'
slugify.occurrences = slugify.occurrences || {}
if (typeof string !== 'string') return ''
if (!maintainCase) string = string.toLowerCase()
let slug = string.trim()
.replace(/<[^>\d]+>/g, '')
.replace(re, '')
.replace(/\s/g, replacement)
.replace(/-+/g, replacement)
.replace(/^(\d)/, '_$1')
let occurrences = slugify.occurrences[slug]
if (slugify.occurrences.hasOwnProperty(slug)) {
occurrences++
} else {
occurrences = 0
}
slugify.occurrences[slug] = occurrences
if (occurrences) {
slug = slug + '-' + occurrences
}
return slug
}
slugify.clear = function () {
slugify.occurrences = {}
}
const hasOwnProperty = Object.prototype.hasOwnProperty
export const merge = Object.assign || function (to) {
for (let i = 1; i < arguments.length; i++) {
const from = Object(arguments[i])
for (const key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key]
}
}
}
return to
}