├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── README_CN.md ├── build ├── lint-commits.sh └── webpack.config.js ├── commitlint.config.js ├── examples ├── 1_quickstart.md ├── 2_configuration.md ├── 3_theme.md ├── 4_features │ ├── 1_introduction.md │ ├── 2_assets.md │ ├── 4_grammar.md │ └── 5_menus.md ├── assets │ ├── example-multilayer-menu.png │ ├── example-pages.png │ ├── example-sort.png │ ├── theme-dark.png │ ├── theme-default.png │ ├── theme-element.png │ └── theme-plain.png ├── highlight.css ├── highlight.js ├── others │ └── about.md └── paper.config.json ├── logo.png ├── package-lock.json ├── package.json ├── src ├── bin │ ├── paper-build.ts │ ├── paper-deploy.ts │ ├── paper-implode.ts │ ├── paper-init.ts │ ├── paper-server.ts │ └── paper.ts ├── compile.ts ├── scripts │ ├── event.ts │ ├── generator.ts │ ├── index.ts │ ├── plugins │ │ ├── back.ts │ │ ├── highlight.ts │ │ ├── indicator.ts │ │ └── responsive.ts │ ├── router.ts │ └── utils.ts └── utils │ ├── check.ts │ ├── config.default.ts │ ├── file.ts │ ├── filter.ts │ ├── highlight.ts │ └── log.ts ├── templates └── app │ └── index.html ├── tsconfig.json ├── tslint.json └── typings ├── paper └── index.d.ts └── webpack └── index.d.ts /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | DhyanaChina Contributing Guide 2 | 3 | ### Pull Request Guidelines 4 | - Fork this repository to your own account. Do not create branches here. 5 | - Commit info should be formatted by the [rules](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines). 6 | - Rebase before creating a PR to keep commit history clear. 7 | - Merging a PR takes two maintainers: one approves the changes after reviewing, and then the other reviews and merges. 8 | 9 | ### Code Style 10 | Follow TSLint 11 | 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | [prompt]:<>(please add labels first) 2 | Type: 3 | - [ ] Bug 4 | - [ ] Feature 5 | - [ ] Help 6 | 7 | Version & Environment: 8 | 9 | 10 | Description: 11 | 12 | 13 | Screenshots: 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## PR Checklist 2 | 3 | - [ ] Fix linting errors 4 | - [ ] Label has been added 5 | 6 | 7 | ## Change information 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Optional npm cache directory 40 | .npm 41 | 42 | # Optional eslint cache 43 | .eslintcache 44 | 45 | # Optional REPL history 46 | .node_repl_history 47 | 48 | # Output of 'npm pack' 49 | *.tgz 50 | 51 | # Yarn Integrity file 52 | .yarn-integrity 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # compile cache 58 | templates/temp 59 | templates/target 60 | dist/ 61 | 62 | # docs 63 | docs/ 64 | 65 | # IDE WebStorm 66 | .idea/ 67 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | 4 | node_js: 5 | - 8.6.0 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | before_install: git fetch --depth=1000 12 | 13 | install: 14 | - npm i -g typescript webpack 15 | - npm i 16 | 17 | script: 18 | - /bin/bash build/lint-commits.sh 19 | - npm run build 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 DhyanaChina 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |

5 | 6 |

7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 | > elegant document generation tool. [preview](http://paper.wittsay.cc/). 15 | 16 | > quickly build and deploy markdown files with a few commands. 17 | 18 | ## Guide 19 | - [Feature](#feature) 20 | - [Getting Started](#getting-started) 21 | - [Configuration Details](#configuration-details) 22 | - [Documentation](http://paper.wittsay.cc/) 23 | - [LICENSE](#license) 24 | - [中文](README_CN.md) 25 | 26 | ### Feature 27 | - Agility. just one script(only ~3kb gzipped), no framework. 28 | - Easy. just one command. 29 | - Lazy load. 30 | - Auto compatible mobile phone. 31 | - [More themes](https://github.com/DhyanaChina/simpler-paper-themes). 32 | 33 | ### Getting Started 34 | 1. Install: `npm i -g simpler-paper` 35 | 2. Init: `paper init` . To create the document folder or generate the config file in existing folder. 36 | 3. Add markdown files in document folder. 37 | - Create a folder named "assets" to store the images if needed.🤔🤔 38 | - Add a munber prefix connected by '_' to sort the document or folder. (e.g. 1_firstDoc.md) 39 | - Hierarchical directory generated by the documents folder. 40 | 4. Build: `paper build` . If you want to preview, run `paper server` . 41 | 5. Deploy: `paper deploy` . Deploy a Git repository to GitHub. 42 | Remember to [set](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#enabling-github-pages-to-publish-your-site-from-master-or-gh-pages) to GitHub pages. 43 | 44 | ### Configuration Details 45 | You can create a `paper.config.json` file in the document directory. 46 | 47 | > Run `paper init` can quickly create `paper.config.json` 48 | 49 | ```typescript 50 | // paper.config.json 51 | { 52 | // document the alias, the value will be displayed after compilation, default: null 53 | "alias": { 54 | "quickstart": "Getting Started", 55 | ... 56 | }, 57 | 58 | // document title, default: "simpler paper" 59 | "title": "", 60 | 61 | // back to top button, default: true 62 | "backToTop": true, 63 | 64 | // document page path, default: "/" 65 | "docPath": "/", 66 | 67 | // loading indicator, default: true 68 | "indicator": true 69 | } 70 | ``` 71 | 72 | 73 | ### LICENSE 74 | 75 | [**MIT**](LICENSE) 76 | 77 | 78 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |

5 |

6 | 7 | 8 | 9 | 10 | 11 |

12 | 13 | > 一个简单易用的文档生成器. [预览](http://paper.wittsay.cc/)。 14 | > 快速的将众多 Markdown 文件生成结构化的网站,并一键部署至 github。 15 | 16 | ## 目录 17 | - [特点](#特点) 18 | - [快速上手](#快速上手) 19 | - [配置文件说明](#配置文件说明) 20 | - [更多文档](http://paper.wittsay.cc/) 21 | - [LICENSE](#license) 22 | - [English](README.md) 23 | 24 | ### 特点 25 | - 敏捷。只有一个脚本(gzip 后约 3k),没有任何框架。 26 | - 简单。只需要运行一个命令。 27 | - 懒加载,首屏加载更快。 28 | - 适应移动设备。 29 | - [更多的主题](https://github.com/DhyanaChina/simpler-paper-themes)。 30 | 31 | ### 快速上手 32 | 1. 安装:`npm i -g simpler-paper` 。 33 | 2. 初始化:`paper init` ,帮助你创建一个配置文件。 34 | 3. 添加文档: 35 | - 不要忘了在文档文件夹中添加你的 Markdown 文件。 36 | - 创建 `assets` 文件夹来存储图片。 37 | - 多层目录的菜单结构是按文档的目录层次决定的,无需配置。 38 | - 改变文件顺序,如使某个文件夹或 xxx.md 排列在更前面,只需要为文件或文件夹的名称增加数字前缀即可, 39 | 这些数字代表着权重,类似于 CSS z-index:100000_install.md (我知道你经常这样干🙄🙄)。 40 | 4. 构建:`paper build` 。运行 `paper server` 进行本地预览。 41 | 5. 部署:`paper deploy` 。确保当前操作目录为 Git 仓库。 42 | 完成部署后[设置](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#enabling-github-pages-to-publish-your-site-from-master-or-gh-pages) 为 GitHub pages 。 43 | 44 | ### 配置文件说明 45 | 配置文件是 `paper init` 过程中指定文档文件夹下的 `paper.config.json` 。 46 | 47 | > 运行 `paper init` 命令可以快速创建配置文件。 48 | 49 | ```typescript 50 | // paper.config.json 51 | { 52 | // 文档别名, 单个文档对应的别名, 不创建默认使用文件名 默认值: null 53 | "alias": { 54 | "quickstart": "Getting Started", 55 | ... 56 | }, 57 | 58 | // 文档标题, 默认值: "simpler paper" 59 | "title": "", 60 | 61 | // 在文档右侧生成迷你目录地图, 默认值: true 62 | "minimap": true, 63 | 64 | // 返回至顶部的按钮, 默认值: true 65 | "backToTop": true, 66 | 67 | // 文档的路径, 默认值: "/" 68 | "docPath": "/", 69 | 70 | // 加载指示器, 默认值: true 71 | "indicator": true 72 | } 73 | ``` 74 | 75 | 76 | ## LICENSE 77 | 78 | [**MIT**](LICENSE) 79 | 80 | 81 | -------------------------------------------------------------------------------- /build/lint-commits.sh: -------------------------------------------------------------------------------- 1 | # lint-commits.sh 2 | #!/bin/bash 3 | set -e 4 | set -u 5 | 6 | if [[ $TRAVIS_PULL_REQUEST_SLUG != "" && $TRAVIS_PULL_REQUEST_SLUG != $TRAVIS_REPO_SLUG ]]; then 7 | # This is a Pull Request from a different slug, hence a forked repository 8 | git remote add "$TRAVIS_PULL_REQUEST_SLUG" "https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git" 9 | git fetch "$TRAVIS_PULL_REQUEST_SLUG" 10 | 11 | # Use the fetched remote pointing to the source clone for comparison 12 | TO="$TRAVIS_PULL_REQUEST_SLUG/$TRAVIS_PULL_REQUEST_BRANCH" 13 | else 14 | # This is a Pull Request from the same remote, no clone repository 15 | TO=$TRAVIS_COMMIT 16 | fi 17 | 18 | 19 | # Lint all commits in the PR 20 | # - Covers fork pull requests (when TO=slug/branch) 21 | # - Covers branch pull requests (when TO=branch) 22 | ./node_modules/.bin/commitlint --from="$TRAVIS_BRANCH" --to="$TO" 23 | 24 | # Always lint the triggerig commit 25 | # - Covers direct commits 26 | ./node_modules/.bin/commitlint --from="$TRAVIS_COMMIT" 27 | -------------------------------------------------------------------------------- /build/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | const webpack = require('webpack') 4 | const webpackMerge = require('webpack-merge') 5 | const lintConfig = require('../tslint.json') 6 | const promisify = require('util').promisify 7 | const readDir = promisify(fs.readdir) 8 | const isDebug = process.env.DEBUG || false 9 | const manifest = require('../package.json') 10 | 11 | 12 | module.exports = (async() => { 13 | const externals = Object.keys(manifest.dependencies).reduce((pre, next) => 14 | Object.assign({}, pre, { [next]: `require('${next}')`}), {}) 15 | 16 | const entries = await readDir(path.join(__dirname, '../src/bin')) 17 | const entryName = fileName => `bin/${fileName.split('.ts')[0]}` 18 | const entriesMap = entries.reduce((pre, next) => Object.assign({}, 19 | pre, { [entryName(next)]: path.resolve(__dirname, `../src/bin/${next}`) }), {}) 20 | 21 | const base = { 22 | output: { 23 | path: path.resolve(__dirname, '../dist'), 24 | filename: '[name].js', 25 | }, 26 | 27 | devtool: isDebug ? 'source-map' : '', 28 | 29 | target: 'node', 30 | 31 | node: { 32 | __dirname: false, 33 | __filename: true, 34 | }, 35 | 36 | resolve: { 37 | extensions: [ '.ts', '.js'], 38 | modules: [ 39 | path.join(__dirname, '../node_modules'), 40 | ], 41 | }, 42 | 43 | module: { 44 | loaders: [ 45 | { 46 | test: /\.ts/, 47 | enforce: 'pre', 48 | exclude: /node_modules/, 49 | loader: 'tslint-loader', 50 | options: { 51 | configuration: lintConfig, 52 | }, 53 | }, 54 | { 55 | test: /\.ts$/, 56 | loader: 'ts-loader', 57 | exclude: /node_modules/, 58 | options: { 59 | configFile: path.resolve(__dirname, '../tsconfig.json'), 60 | } 61 | }, 62 | ], 63 | }, 64 | 65 | plugins: [ 66 | new webpack.BannerPlugin({ 67 | raw: true, 68 | banner: '#!/usr/bin/env node', 69 | exclude: 'index.js', 70 | }), 71 | new webpack.optimize.UglifyJsPlugin({ 72 | compress: { warnings: false }, 73 | }), 74 | ], 75 | } 76 | 77 | const server = { 78 | entry: entriesMap, 79 | externals: externals, 80 | target: 'node', 81 | } 82 | const client = { 83 | entry: { 84 | index: path.resolve(__dirname, '../src/scripts/index.ts'), 85 | }, 86 | target: 'web', 87 | } 88 | return [webpackMerge(base, server), webpackMerge(base, client)] 89 | })() 90 | 91 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-angular'] } 2 | -------------------------------------------------------------------------------- /examples/1_quickstart.md: -------------------------------------------------------------------------------- 1 | ## QuickStart 2 | [simpler-paper](https://github.com/DhyanaChina/simpler-paper) is a minimalist document generator. 3 | you only need to run a command, all of the Markdown will be automatically integrated into the site. 4 | 5 | In principle, we have reduced the configuration as much as possible, most of the functions are customary, 6 | you can find the way to use in the **feature** directory. 7 | 8 | In addition, we have also prepared a different style of css-style for you, you never to worry about style. everything is so simple. 9 | 10 | 11 | ### Build and preview 12 | with just one command, you can easily compile the file and the local preview. 13 | ```bash 14 | # install 15 | npm install -g simpler-paper 16 | 17 | # init 18 | paper init 19 | 20 | # dont forget to add some markdown files. 21 | # build to html 22 | paper build 23 | 24 | # preview 25 | paper s 26 | ``` 27 | 28 | ### Deploy 29 | 30 | ```bash 31 | # In default, the document will be released to github. 32 | paper deploy 33 | ``` 34 | 35 | you need set github pages (maybe...🙄): 36 | 37 | 1. go to your rep. 38 | 2. Settings > Options > GitHub Pages 39 | 3. choose the source for **gh-pages branch** 40 | 41 | the actual effect: 42 | 43 | ![example](assets/example-pages.png) 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/2_configuration.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | Configuration file can help you set up a more detailed document,it is under your document folder, 3 | if you are confused about these configurations, you can skip here~~ 4 | 5 | ### Add paper.config.json 6 | > run `paper init` can quickly create configuration file, if you can't find `paper.config.json`. 7 | 8 | Example: 9 | 10 | ```html 11 | 12 | ------------- project dir 13 | |--- build 14 | |--- dist 15 | |--- scripts 16 | |--- docs 17 | | |--- quickstart.md 18 | | |--- hello.md 19 | | |--- paper.config.json (add paper.config.json in doc dir) 20 | ... 21 | ``` 22 | 23 | 24 | ### All Properties 25 | 26 | | key | type | default | description | 27 | | --- | --- | --- | --- | 28 | | alias | `{ [string]: string }` | `{}` | document the alias, the value will be displayed after compilation | 29 | | title | `string` | `'document title'` | simpler paper | 30 | | minimap | `boolean` | `true` | generate mini maps on the right side of each document | 31 | | backToTop | `boolean` | `true` | back to top button | 32 | | indicator | `boolean` | `true` | loading indicator | 33 | | docPath | `string` | `'/'` | document page path | 34 | | theme | `string` | `'default'` | paper theme | 35 | | output | `string` | `'dist'` | compile ouput | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/3_theme.md: -------------------------------------------------------------------------------- 1 | ## Theme 2 | The sense of design has always been a part of our great importance, we hope simpler-paper is not just readable, 3 | it also needs to be pleasing, charismatic and special. 4 | 5 | the style of the **simpler-paper** comes from [simpler-paper-themes](https://github.com/DhyanaChina/simpler-paper-themes). 6 | here is a list of all topics at present. 7 | 8 | > if you want to create a new theme, go to [simpler-paper-themes](https://github.com/DhyanaChina/simpler-paper-themes). 9 | 10 | - Default `theme: "default"` 11 | 12 | 13 | 14 | - Element `theme: "element"` 15 | 16 | 17 | 18 | - Plain `theme: "plain"` 19 | 20 | 21 | 22 | - Dark `theme: "dark` 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/4_features/1_introduction.md: -------------------------------------------------------------------------------- 1 | ## Features 2 | `simpler-paper` contains a lot of conventions, 3 | and in some cases you need only a few simple steps to achieve more customizing effects. 4 | 5 | 6 | Of course, you don't need them and you can make a good document, 7 | these simple features can help you reduce the annoyance of editing documents and focus on the content of the document, 8 | that's our purpose too. 9 | 10 | The features include the following parts: 11 | 12 | - [Assets File](#/features/assets.md) 13 | - [Grammar](#/features/grammar.md) 14 | - [Menus](#/features/menus.md) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/4_features/2_assets.md: -------------------------------------------------------------------------------- 1 | ## Assets 2 | 3 | Just create a folder named `assets` under the folder. 4 | the `assets` folder will not be compiled. static folders do not need to be configured, 5 | its name is always `assets`. this is a convention. 6 | 7 | In the document, you can use them as usual: `![name](assets/show.png)` 8 | 9 | -------------------------------------------------------------------------------- /examples/4_features/4_grammar.md: -------------------------------------------------------------------------------- 1 | ## Grammar extend 2 | Apart from the standard grammar, we have also prepared some sweeter sweets for you. 3 | 4 | ### Prompt message 5 | 6 | - **info** 7 | 8 | `#> info message` will be output: 9 | 10 | #> info message 11 | 12 | - **warning** 13 | 14 | `?> warning message` will be output: 15 | 16 | ?> warning message 17 | 18 | - **error** 19 | 20 | `!> error message` will be output: 21 | 22 | !> error message 23 | 24 | 25 | 26 | ### Code highlighting 27 | 28 | Adding `highlight.js` files and `highlight.css` files will automatically open the code highlighting 29 | You can download and download these files here: [highlightjs](https://highlightjs.org/download/) 30 | 31 | ```html 32 | |____docs 33 | | |____paper.config.json 34 | | |____3_theme.md 35 | | |____4_features.md 36 | | |____1_quickstart.md 37 | | |____2_configuration.md 38 | | |____highlight.css 39 | | |____highlight.js 40 | 41 | ``` 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/4_features/5_menus.md: -------------------------------------------------------------------------------- 1 | ## Menu 2 | 3 | 4 | ### Multilayer Menus 5 | if you want to create a menu that contains parent-child relationships, you just need to create folders. 6 | simpler-paper automatically generate menus based on hierarchical relationships. 7 | like: 8 | 9 | ```html 10 | **doc source** 11 | |____docs 12 | | |____install 13 | | | |____install.1.md 14 | | | |____install.2.md 15 | | |____problems 16 | | | |____answer.1.md 17 | | | |____answer.2.md 18 | | |____paper.config.json 19 | 20 | ``` 21 | run `paper bd` and get the following effect: 22 | 23 | ![example1](assets/example-multilayer-menu.png) 24 | 25 |
26 |
27 | 28 | ### Ordering 29 | 30 | both files and folders support manually specifying weights, you just need to add a prefix to them. 31 | prefixes are automatically removed after compilation. 32 | like: 33 | 34 | ```html 35 | **doc source** 36 | |____docs 37 | | |____install 38 | | | |____9_install.1.md 39 | | | |____5_install.2.md 40 | | |____problems 41 | | | |____answer.1.md 42 | | | |____answer.2.md 43 | | |____paper.config.json 44 | ``` 45 | run `paper bd` and get the following effect: 46 | 47 | ![example2](assets/example-sort.png) 48 | 49 |
50 |
51 | -------------------------------------------------------------------------------- /examples/assets/example-multilayer-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/examples/assets/example-multilayer-menu.png -------------------------------------------------------------------------------- /examples/assets/example-pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/examples/assets/example-pages.png -------------------------------------------------------------------------------- /examples/assets/example-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/examples/assets/example-sort.png -------------------------------------------------------------------------------- /examples/assets/theme-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/examples/assets/theme-dark.png -------------------------------------------------------------------------------- /examples/assets/theme-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/examples/assets/theme-default.png -------------------------------------------------------------------------------- /examples/assets/theme-element.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/examples/assets/theme-element.png -------------------------------------------------------------------------------- /examples/assets/theme-plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/examples/assets/theme-plain.png -------------------------------------------------------------------------------- /examples/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Original highlight.js style (c) Ivan Sagalaev 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | background: #F0F0F0; 12 | } 13 | 14 | 15 | /* Base color: saturation 0; */ 16 | 17 | .hljs, 18 | .hljs-subst { 19 | color: #444; 20 | } 21 | 22 | .hljs-comment { 23 | color: #888888; 24 | } 25 | 26 | .hljs-keyword, 27 | .hljs-attribute, 28 | .hljs-selector-tag, 29 | .hljs-meta-keyword, 30 | .hljs-doctag, 31 | .hljs-name { 32 | font-weight: bold; 33 | } 34 | 35 | 36 | /* User color: hue: 0 */ 37 | 38 | .hljs-type, 39 | .hljs-string, 40 | .hljs-number, 41 | .hljs-selector-id, 42 | .hljs-selector-class, 43 | .hljs-quote, 44 | .hljs-template-tag, 45 | .hljs-deletion { 46 | color: #880000; 47 | } 48 | 49 | .hljs-title, 50 | .hljs-section { 51 | color: #880000; 52 | font-weight: bold; 53 | } 54 | 55 | .hljs-regexp, 56 | .hljs-symbol, 57 | .hljs-variable, 58 | .hljs-template-variable, 59 | .hljs-link, 60 | .hljs-selector-attr, 61 | .hljs-selector-pseudo { 62 | color: #BC6060; 63 | } 64 | 65 | 66 | /* Language color: hue: 90; */ 67 | 68 | .hljs-literal { 69 | color: #78A960; 70 | } 71 | 72 | .hljs-built_in, 73 | .hljs-bullet, 74 | .hljs-code, 75 | .hljs-addition { 76 | color: #397300; 77 | } 78 | 79 | 80 | /* Meta color: hue: 200 */ 81 | 82 | .hljs-meta { 83 | color: #1f7199; 84 | } 85 | 86 | .hljs-meta-string { 87 | color: #4d99bf; 88 | } 89 | 90 | 91 | /* Misc effects */ 92 | 93 | .hljs-emphasis { 94 | font-style: italic; 95 | } 96 | 97 | .hljs-strong { 98 | font-weight: bold; 99 | } 100 | -------------------------------------------------------------------------------- /examples/highlight.js: -------------------------------------------------------------------------------- 1 | /*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */ 2 | !function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){s+=""}function c(e){("start"===e.event?o:u)(e.node)}for(var l=0,s="",f=[];e.length||r.length;){var g=i();if(s+=n(a.substring(l,g[0].offset)),l=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===l);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return s+n(a.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?u("keyword",a.k):x(a.k).forEach(function(e){u(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return l("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var c=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=c.length?t(c.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function l(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":I.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=l(E,r),e?(B+=e[1],a+=p(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!y[E.sL])return n(k);var t=e?f(E.sL,k,!0,x[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(B+=t.r),e&&(x[E.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=null!=E.sL?d():h(),k=""}function v(e){L+=e.cN?p(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(k+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),b(),t.rB||t.eB||(k=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),b(),a.eE&&(k=n));do E.cN&&(L+=C),E.skip||(B+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,E=i||N,x={},L="";for(R=E;R!==N;R=R.parent)R.cN&&(L=p(R.cN,"",!0)+L);var k="",B=0;try{for(var M,j,O=0;;){if(E.t.lastIndex=O,M=E.t.exec(t),!M)break;j=m(t.substring(O,M.index),M[0]),O=M.index+j}for(m(t.substr(O)),R=E;R.parent;R=R.parent)R.cN&&(L+=C);return{r:B,value:L,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function g(e,t){t=t||I.languages||x(y);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return I.tabReplace||I.useBR?e.replace(M,function(e,n){return I.useBR&&"\n"===e?"
":I.tabReplace?n.replace(/\t/g,I.tabReplace):""}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function d(e){var n,t,r,o,l,s=i(e);a(s)||(I.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,l=n.textContent,r=s?f(s,l,!0):g(l),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),l)),r.value=p(r.value),e.innerHTML=r.value,e.className=h(e.className,s,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){I=o(I,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,d)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=y[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function R(){return x(y)}function w(e){return e=(e||"").toLowerCase(),y[e]||y[L[e]]}var E=[],x=Object.keys,y={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="
",I={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=d,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0}]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[t],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("powershell",function(e){var t={b:"`[\\s\\S]",r:0},o={cN:"variable",v:[{b:/\$[\w\d][\w\d_:]*/}]},r={cN:"literal",b:/\$(null|true|false)\b/},n={cN:"string",v:[{b:/"/,e:/"/},{b:/@"/,e:/^"@/}],c:[t,o,{cN:"variable",b:/\$[A-z]/,e:/[^A-z]/}]},a={cN:"string",v:[{b:/'/,e:/'/},{b:/@'/,e:/^'@/}]},i={cN:"doctag",v:[{b:/\.(synopsis|description|example|inputs|outputs|notes|link|component|role|functionality)/},{b:/\.(parameter|forwardhelptargetname|forwardhelpcategory|remotehelprunspace|externalhelp)\s+\S+/}]},s=e.inherit(e.C(null,null),{v:[{b:/#/,e:/$/},{b:/<#/,e:/#>/}],c:[i]});return{aliases:["ps"],l:/-?[A-z\.\-]+/,cI:!0,k:{keyword:"if else foreach return function do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch",built_in:"Add-Computer Add-Content Add-History Add-JobTrigger Add-Member Add-PSSnapin Add-Type Checkpoint-Computer Clear-Content Clear-EventLog Clear-History Clear-Host Clear-Item Clear-ItemProperty Clear-Variable Compare-Object Complete-Transaction Connect-PSSession Connect-WSMan Convert-Path ConvertFrom-Csv ConvertFrom-Json ConvertFrom-SecureString ConvertFrom-StringData ConvertTo-Csv ConvertTo-Html ConvertTo-Json ConvertTo-SecureString ConvertTo-Xml Copy-Item Copy-ItemProperty Debug-Process Disable-ComputerRestore Disable-JobTrigger Disable-PSBreakpoint Disable-PSRemoting Disable-PSSessionConfiguration Disable-WSManCredSSP Disconnect-PSSession Disconnect-WSMan Disable-ScheduledJob Enable-ComputerRestore Enable-JobTrigger Enable-PSBreakpoint Enable-PSRemoting Enable-PSSessionConfiguration Enable-ScheduledJob Enable-WSManCredSSP Enter-PSSession Exit-PSSession Export-Alias Export-Clixml Export-Console Export-Counter Export-Csv Export-FormatData Export-ModuleMember Export-PSSession ForEach-Object Format-Custom Format-List Format-Table Format-Wide Get-Acl Get-Alias Get-AuthenticodeSignature Get-ChildItem Get-Command Get-ComputerRestorePoint Get-Content Get-ControlPanelItem Get-Counter Get-Credential Get-Culture Get-Date Get-Event Get-EventLog Get-EventSubscriber Get-ExecutionPolicy Get-FormatData Get-Host Get-HotFix Get-Help Get-History Get-IseSnippet Get-Item Get-ItemProperty Get-Job Get-JobTrigger Get-Location Get-Member Get-Module Get-PfxCertificate Get-Process Get-PSBreakpoint Get-PSCallStack Get-PSDrive Get-PSProvider Get-PSSession Get-PSSessionConfiguration Get-PSSnapin Get-Random Get-ScheduledJob Get-ScheduledJobOption Get-Service Get-TraceSource Get-Transaction Get-TypeData Get-UICulture Get-Unique Get-Variable Get-Verb Get-WinEvent Get-WmiObject Get-WSManCredSSP Get-WSManInstance Group-Object Import-Alias Import-Clixml Import-Counter Import-Csv Import-IseSnippet Import-LocalizedData Import-PSSession Import-Module Invoke-AsWorkflow Invoke-Command Invoke-Expression Invoke-History Invoke-Item Invoke-RestMethod Invoke-WebRequest Invoke-WmiMethod Invoke-WSManAction Join-Path Limit-EventLog Measure-Command Measure-Object Move-Item Move-ItemProperty New-Alias New-Event New-EventLog New-IseSnippet New-Item New-ItemProperty New-JobTrigger New-Object New-Module New-ModuleManifest New-PSDrive New-PSSession New-PSSessionConfigurationFile New-PSSessionOption New-PSTransportOption New-PSWorkflowExecutionOption New-PSWorkflowSession New-ScheduledJobOption New-Service New-TimeSpan New-Variable New-WebServiceProxy New-WinEvent New-WSManInstance New-WSManSessionOption Out-Default Out-File Out-GridView Out-Host Out-Null Out-Printer Out-String Pop-Location Push-Location Read-Host Receive-Job Register-EngineEvent Register-ObjectEvent Register-PSSessionConfiguration Register-ScheduledJob Register-WmiEvent Remove-Computer Remove-Event Remove-EventLog Remove-Item Remove-ItemProperty Remove-Job Remove-JobTrigger Remove-Module Remove-PSBreakpoint Remove-PSDrive Remove-PSSession Remove-PSSnapin Remove-TypeData Remove-Variable Remove-WmiObject Remove-WSManInstance Rename-Computer Rename-Item Rename-ItemProperty Reset-ComputerMachinePassword Resolve-Path Restart-Computer Restart-Service Restore-Computer Resume-Job Resume-Service Save-Help Select-Object Select-String Select-Xml Send-MailMessage Set-Acl Set-Alias Set-AuthenticodeSignature Set-Content Set-Date Set-ExecutionPolicy Set-Item Set-ItemProperty Set-JobTrigger Set-Location Set-PSBreakpoint Set-PSDebug Set-PSSessionConfiguration Set-ScheduledJob Set-ScheduledJobOption Set-Service Set-StrictMode Set-TraceSource Set-Variable Set-WmiInstance Set-WSManInstance Set-WSManQuickConfig Show-Command Show-ControlPanelItem Show-EventLog Sort-Object Split-Path Start-Job Start-Process Start-Service Start-Sleep Start-Transaction Start-Transcript Stop-Computer Stop-Job Stop-Process Stop-Service Stop-Transcript Suspend-Job Suspend-Service Tee-Object Test-ComputerSecureChannel Test-Connection Test-ModuleManifest Test-Path Test-PSSessionConfigurationFile Trace-Command Unblock-File Undo-Transaction Unregister-Event Unregister-PSSessionConfiguration Unregister-ScheduledJob Update-FormatData Update-Help Update-List Update-TypeData Use-Transaction Wait-Event Wait-Job Wait-Process Where-Object Write-Debug Write-Error Write-EventLog Write-Host Write-Output Write-Progress Write-Verbose Write-Warning Add-MDTPersistentDrive Disable-MDTMonitorService Enable-MDTMonitorService Get-MDTDeploymentShareStatistics Get-MDTMonitorData Get-MDTOperatingSystemCatalog Get-MDTPersistentDrive Import-MDTApplication Import-MDTDriver Import-MDTOperatingSystem Import-MDTPackage Import-MDTTaskSequence New-MDTDatabase Remove-MDTMonitorData Remove-MDTPersistentDrive Restore-MDTPersistentDrive Set-MDTMonitorData Test-MDTDeploymentShare Test-MDTMonitorData Update-MDTDatabaseSchema Update-MDTDeploymentShare Update-MDTLinkedDS Update-MDTMedia Update-MDTMedia Add-VamtProductKey Export-VamtData Find-VamtManagedMachine Get-VamtConfirmationId Get-VamtProduct Get-VamtProductKey Import-VamtData Initialize-VamtData Install-VamtConfirmationId Install-VamtProductActivation Install-VamtProductKey Update-VamtProduct",nomarkup:"-ne -eq -lt -gt -ge -le -not -like -notlike -match -notmatch -contains -notcontains -in -notin -replace"},c:[t,e.NM,n,a,r,o,s]}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("shell",function(s){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}}); -------------------------------------------------------------------------------- /examples/others/about.md: -------------------------------------------------------------------------------- 1 | 😁😁😁😁 2 | 3 | Repo Link: [simpler-paper](https://github.com/DhyanaChina/simpler-paper) 4 | 5 | other projects: 6 | [angular-mock-api](https://github.com/DhyanaChina/ng-mocker) 7 | [angular-storage](https://github.com/DhyanaChina/storage-angular) 8 | [touch-dog](https://github.com/DhyanaChina/touch-dog) 9 | 10 | 11 | **contact me:** 12 | 13 | > Witt, mail: nanazuimeng123##gmail.com (replace '##') 14 | -------------------------------------------------------------------------------- /examples/paper.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "alias": { 3 | "quickstart": "getting started", 4 | "grammar": "grammar extend" 5 | }, 6 | "title": "simpler paper", 7 | "minimap": true, 8 | "backToTop": true, 9 | "output": "docs", 10 | "expandAll": false, 11 | "docPath": "/" 12 | } 13 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unix/simpler-paper/a2d02b3fa67e3bf39cd2de0238342fcb51bcd8d7/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simpler-paper", 3 | "version": "0.3.7", 4 | "description": "A very simple document generator.", 5 | "main": "dist/bin/paper.js", 6 | "scripts": { 7 | "start": "webpack --config ./build/webpack.config.js --progress --watch", 8 | "build": "rm -rf ./dist && webpack --config ./build/webpack.config.js --progress", 9 | "commit": "commitizen init cz-conventional-changelog --save --save-exact", 10 | "commitmsg": "commitlint -e $GIT_PARAMS" 11 | }, 12 | "bin": { 13 | "paper": "dist/bin/paper.js" 14 | }, 15 | "preferGlobal": true, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/DhyanaChina/simpler-paper.git" 19 | }, 20 | "author": "DhyanaChina", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/DhyanaChina/simpler-paper/issues" 24 | }, 25 | "engines": { 26 | "node": ">= 6.10" 27 | }, 28 | "files": [ 29 | "LICENSE", 30 | "READNE.md", 31 | "dist/", 32 | "templates/" 33 | ], 34 | "homepage": "https://github.com/DhyanaChina/simpler-paper#readme", 35 | "devDependencies": { 36 | "@commitlint/config-angular": "^5.1.1", 37 | "@types/commander": "^2.11.0", 38 | "@types/marked": "^0.3.0", 39 | "@types/node": "^8.0.47", 40 | "@types/promise": "^7.1.30", 41 | "commitlint": "^5.2.5", 42 | "cz-conventional-changelog": "^2.1.0", 43 | "husky": "^0.14.3", 44 | "ts-loader": "^3.1.1", 45 | "tslint": "^5.8.0", 46 | "tslint-loader": "^3.5.3", 47 | "typescript": "^2.6.1", 48 | "webpack": "^3.8.1", 49 | "webpack-dev-server": "^2.9.4", 50 | "webpack-merge": "^4.1.1" 51 | }, 52 | "dependencies": { 53 | "chalk": "^2.3.0", 54 | "commander": "^2.11.0", 55 | "express": "^4.16.2", 56 | "gh-pages": "git://github.com/WittBulter/gh-pages.git#v1.0.0-rc.2", 57 | "highlight.js": "^9.12.0", 58 | "inquirer": "^3.3.0", 59 | "marked": "^0.3.9", 60 | "ora": "^1.3.0", 61 | "serve-static": "^1.13.1", 62 | "simpler-paper-themes": "^0.3.1", 63 | "update-notifier": "^2.3.0", 64 | "util.promisify": "^1.0.0" 65 | }, 66 | "config": { 67 | "commitizen": { 68 | "path": "./node_modules/cz-conventional-changelog" 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/bin/paper-build.ts: -------------------------------------------------------------------------------- 1 | import { checkTheme, findSource, assignConfig } from '../utils/check' 2 | import { compileCatalog, compileMarkdown, copyTheme, copyInlineHtml, copyAssets } from '../compile' 3 | import File from '../utils/file' 4 | import Log from '../utils/log' 5 | import Filter from '../utils/filter' 6 | import { resolve } from 'path' 7 | 8 | const removeDir = async(dir) => { 9 | await File.exists(dir) && await File.exec(`rm -rf ${dir}`) 10 | } 11 | 12 | ;(async() => { 13 | const root = Filter.path(`${__dirname}/../..`) 14 | const templateTargetPath = `${root}/templates/target` 15 | const templateTempPath = `${root}/templates/temp` 16 | 17 | // check path 18 | Log.time.start('check config') 19 | const source: string = await findSource(process.cwd()) 20 | const config: Config = await assignConfig(source) 21 | Log.time.over() 22 | 23 | 24 | // make catalog and html fragment 25 | const targetPath = `${resolve()}/${config.output}` 26 | const catalogs: Catalog[] = await compileCatalog(config) 27 | await compileMarkdown(catalogs, source) 28 | 29 | 30 | Log.time.start('generative assets') 31 | // reset target dir 32 | await removeDir(templateTargetPath) 33 | // await File.mkdir(templateTargetPath) // windows cp error 34 | 35 | // copy themes to target 36 | await checkTheme(config) 37 | await copyTheme(config) 38 | await copyAssets(config) 39 | Log.time.over() 40 | 41 | // copy cache to target, clear cache dir 42 | await File.exec(`cp -r ${templateTempPath}/ ${templateTargetPath}`) 43 | await removeDir(templateTempPath) 44 | 45 | // copy run time script and make index.html 46 | await copyInlineHtml(config, catalogs) 47 | 48 | 49 | // output to user dir 50 | Log.time.start('clear up') 51 | await removeDir(targetPath) 52 | await File.exec(`cp -R ${templateTargetPath}/ ${targetPath}/`) 53 | Log.time.over() 54 | })() 55 | 56 | -------------------------------------------------------------------------------- /src/bin/paper-deploy.ts: -------------------------------------------------------------------------------- 1 | import * as pages from 'gh-pages' 2 | import * as commander from 'commander' 3 | import File from '../utils/file' 4 | import Log from '../utils/log' 5 | import { findSource, assignConfig } from '../utils/check' 6 | import chalk from 'chalk' 7 | 8 | const resetDir = async(path: string) => { 9 | await File.exists(path) && await File.exec(`rm -rf ${path}`) 10 | } 11 | 12 | const checkGit = async(git: string) => { 13 | if (await File.exists(git)) return 14 | console.log(chalk.red('Error: not in the GIT workspace.')) 15 | process.exit(1) 16 | } 17 | 18 | commander 19 | .option('-m, --message', 'server port') 20 | .parse(process.argv) 21 | 22 | const message = commander.args[0] || 'paper update' 23 | ;(async() => { 24 | const __user = process.cwd() 25 | const cachePath = `${__user}/.paper.deploy.cache` 26 | await checkGit(`${__user}/.git`) 27 | 28 | console.log(`deploy message: ${chalk.green(`${message}`)}`) 29 | if (!commander.args[0]) { 30 | console.log(`you can use ${chalk.green('[-m]')} to add information.\n`) 31 | } 32 | 33 | Log.time.start('check config') 34 | const source: string = await findSource(__user) 35 | const config: Config = await assignConfig(source) 36 | const distPath: string = `${__user}/${config.output}` 37 | 38 | if (!await File.exists(distPath) || !await File.exists(`${distPath}/index.html`)) { 39 | console.log(chalk.red('\nError: not found document.')) 40 | console.log(chalk.green('you need to run the [paper build] first.')) 41 | return Log.time.over(false) 42 | } 43 | pages.clean() 44 | Log.time.over() 45 | 46 | Log.time.start('deploy to github') 47 | await resetDir(cachePath) 48 | pages.publish(distPath, { 49 | message, 50 | branch: 'gh-pages', 51 | cache: cachePath, 52 | }, err => { 53 | resetDir(cachePath).then() 54 | if (err) { 55 | console.log(chalk.red(`Error: ${err}`)) 56 | } 57 | Log.time.over(!err) 58 | }) 59 | 60 | 61 | })() 62 | -------------------------------------------------------------------------------- /src/bin/paper-implode.ts: -------------------------------------------------------------------------------- 1 | import * as inquirer from 'inquirer' 2 | import * as Ora from 'ora' 3 | import chalk from 'chalk' 4 | import File from '../utils/file' 5 | 6 | const question = [{ 7 | type: 'input', 8 | name: 'answer', 9 | message: 'continue: Y / N (default)', 10 | }] 11 | 12 | ;(async() => { 13 | new Ora().info('simpler-paper will be removed!') 14 | const { answer } = await inquirer.prompt(question) 15 | const toggle = String(answer).toLowerCase() === 'y' 16 | if (!toggle) return console.log(chalk.yellow('\ncancelled.')) 17 | 18 | File.exec('npm', ['rm', 'simpler-paper', '-g']) 19 | })() 20 | -------------------------------------------------------------------------------- /src/bin/paper-init.ts: -------------------------------------------------------------------------------- 1 | import * as inquirer from 'inquirer' 2 | import chalk from 'chalk' 3 | import File from '../utils/file' 4 | import { defaultConfig } from '../utils/config.default' 5 | const __USER_PATH = process.cwd() 6 | 7 | const createConfig = async(folder: string) => { 8 | const configTarget: string = `${__USER_PATH}/${folder}/paper.config.json` 9 | if (await File.exists(configTarget)) return false 10 | await File.writeFile(configTarget, JSON.stringify(defaultConfig)) 11 | return true 12 | } 13 | 14 | const promps = [{ 15 | type: 'input', 16 | name: 'folder', 17 | message: 'Enter a folder name:', 18 | validate: input => !!input, 19 | }] 20 | const question = [{ 21 | type: 'input', 22 | name: 'answer', 23 | message: 'continue: Y / N(default)', 24 | validate: input => !!input, 25 | }] 26 | 27 | ;(async() => { 28 | const { folder } = await inquirer.prompt(promps) 29 | 30 | if (/\s+|\\|\/|\^|\|/.test(folder)) { 31 | console.log(`\n${chalk.yellow(folder)} contains unsupported characters.`) 32 | return process.exit(1) 33 | } 34 | 35 | if (!await File.exists(folder)) { 36 | await File.exec(`mkdir ${folder}`) 37 | await createConfig(folder) 38 | console.log(chalk.green('the configuration file has been created successfully.')) 39 | return process.exit(0) 40 | } 41 | 42 | console.log(`\nDirectory: ${chalk.yellow(`[${folder}]`)} already existed.`) 43 | const { answer } = await inquirer.prompt(question) 44 | const toggle = String(answer).toLowerCase() === 'y' 45 | if (!toggle) { 46 | console.log(chalk.yellow('cancelled.')) 47 | return process.exit(1) 48 | } 49 | if (!await createConfig(folder)) { 50 | console.log(`\n${chalk.yellow(`[${folder}/paper.config.json]`)} already existed.`) 51 | return process.exit(1) 52 | } 53 | console.log(chalk.green('the configuration file has been created successfully.')) 54 | return process.exit(0) 55 | 56 | })() 57 | -------------------------------------------------------------------------------- /src/bin/paper-server.ts: -------------------------------------------------------------------------------- 1 | import * as commander from 'commander' 2 | import * as express from 'express' 3 | import * as serveStatic from 'serve-static' 4 | import File from '../utils/file' 5 | import chalk from 'chalk' 6 | 7 | // parse path 8 | commander 9 | .option('-p, --port', 'server port') 10 | .parse(process.argv) 11 | const port: number = Number.isNaN(+commander.args[0]) ? 3001 : +commander.args[0] 12 | 13 | ;(async() => { 14 | const __target = `${__dirname}/../../templates/target` 15 | const app = express() 16 | 17 | if (!File.exists(__target)) { 18 | console.log(chalk.red('Error: not found document.')) 19 | console.log(chalk.green('you need to run the [paper build] first.')) 20 | return process.exit(1) 21 | } 22 | 23 | app.use(serveStatic(__target, { 24 | 'index': ['index.html'], 25 | })) 26 | 27 | console.log(`server listening on port: ${chalk.green(`${port}`)}`) 28 | 29 | app.listen(port) 30 | 31 | })() 32 | 33 | -------------------------------------------------------------------------------- /src/bin/paper.ts: -------------------------------------------------------------------------------- 1 | import * as commander from 'commander' 2 | import chalk from 'chalk' 3 | import * as notifier from 'update-notifier' 4 | const pkg = require('../../package.json') 5 | 6 | const v: string = process.version.match(/\d+/g)[0] 7 | if (+v < 5) { 8 | console.log(chalk.yellow('require NodeJS 6+ version.')) 9 | console.log(chalk.yellow('you need to upgrade the NodeJS.\n')) 10 | process.exit(1) 11 | } 12 | 13 | notifier({ pkg, updateCheckInterval: 1 }).notify({ isGlobal: true }) 14 | 15 | commander 16 | .version(pkg.version) 17 | .usage(' [options]') 18 | .command('init', 'init a document folder').alias('i') 19 | .command('build', 'generate document').alias('bd') 20 | .command('server', 'lift the document on the local server').alias('s') 21 | .command('deploy', 'deploy documents in github') 22 | .command('implode ', 'destroy self') 23 | .parse(process.argv) 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/compile.ts: -------------------------------------------------------------------------------- 1 | import File from './utils/file' 2 | import Log from './utils/log' 3 | import Filter from './utils/filter' 4 | import { Stats } from 'fs' 5 | import { appendHighlight, appendHighlightStyle } from './utils/highlight' 6 | 7 | const __app = Filter.path(`${__dirname}/../../templates/app`) 8 | const __target = Filter.path(`${__dirname}/../../templates/target`) 9 | const __temp = Filter.path(`${__dirname}/../../templates/temp`) 10 | const USER_PATH = process.cwd() 11 | 12 | 13 | const parseSuffix = (filePath: string): [string, string, string, string, number] => { 14 | const suffix: string = filePath.split('/').reverse()[0] 15 | // suffix: {number}_{filename}.md 16 | const includeNumberPrefix = /^\d+_/.test(suffix) && !Number.isNaN(+suffix.split('_')[0]) 17 | const weight = includeNumberPrefix ? +suffix.split('_')[0] : 100 18 | const fileName = includeNumberPrefix ? suffix.replace(/^\d+_/, '') : suffix 19 | const path = filePath.replace(suffix, '') 20 | 21 | const showPath = path.replace(/\d+_/g, '') 22 | 23 | return [path, showPath, suffix, fileName, weight] 24 | } 25 | 26 | const generateCatalog = (filePath: string, config: Config, children: Catalog[] = []) => { 27 | const [path, showPath, suffix, fileName, weight] = parseSuffix(filePath) 28 | return { 29 | path, showPath, native: suffix, 30 | name: config.alias[fileName] ? config.alias[fileName] : fileName, 31 | children, 32 | weight, 33 | } 34 | } 35 | 36 | const isMarkFileOrDirectory = (name: string): boolean => name.endsWith('.md') || !name.includes('.') 37 | 38 | const deepEachSource = async(path: string, config: Config): Promise => { 39 | const files: string[] = await File.readdir(`${USER_PATH}/${path}`) 40 | const catalogs: Catalog[] = [] 41 | 42 | for (const name of files) { 43 | if (!isMarkFileOrDirectory(name)) continue 44 | // assets is static dir, skip this 45 | if (name === 'assets') continue 46 | const nextPath: string = `${path}/${name}` 47 | // .replace(/\/.\//g, '/') 48 | // .replace(/\/\//g,'/') 49 | const stat: Stats = await File.stat(nextPath) 50 | if (stat.isFile()) { 51 | catalogs.push(generateCatalog(nextPath, config)) 52 | continue 53 | } 54 | if (stat.isDirectory()) { 55 | catalogs.push(generateCatalog(nextPath, config, await deepEachSource(nextPath, config))) 56 | } 57 | } 58 | return catalogs.sort((pre, next) => pre.weight - next.weight) 59 | } 60 | 61 | export const compileCatalog = async(config: Config) => { 62 | Log.time.start('generate catalog') 63 | const catalogs: Catalog[] = await deepEachSource(config.__user_source_path, config) 64 | Log.time.over() 65 | return catalogs 66 | } 67 | 68 | 69 | const makeTargetPath = (path: string, sourcePath: string): string => { 70 | const sourceFullPath: string = path.split(sourcePath).reverse()[0] 71 | return `${__temp}/static/${sourceFullPath}` 72 | } 73 | 74 | // the markdown is converted to HTML 75 | const createHtml = async(source: string, target: string): Promise => { 76 | const content: string = await File.readFile(source, 'utf-8') 77 | target = target.replace('.md', '.html') 78 | await File.writeFile(target, await File.marked(content), 'utf-8') 79 | } 80 | 81 | const generatePages = async(catalogs: Catalog[], sourcePath: string): Promise => { 82 | for (const unit of catalogs) { 83 | const p: string = makeTargetPath(unit.showPath + unit.name, sourcePath) 84 | if (unit.children && unit.children.length > 0) { 85 | await File.spawnSync('mkdir', [p]) 86 | await generatePages(unit.children, sourcePath) 87 | continue 88 | } 89 | await createHtml(unit.path + unit.native, p) 90 | } 91 | } 92 | 93 | export const compileMarkdown = async(catalogs: Catalog[], sourcePath: string) => { 94 | Log.time.start('compile to html') 95 | await File.exists(__temp) && await File.exec(`rm -rf ${__temp}`) 96 | 97 | await File.mkdir(__temp) 98 | await File.mkdir(`${__temp}/static`) 99 | await generatePages(catalogs, sourcePath) 100 | Log.time.over() 101 | } 102 | 103 | export const copyTheme = async(config: Config): Promise => { 104 | const theme: string = config.theme || 'default' 105 | const p: string = `${__dirname}/../../node_modules/simpler-paper-themes/dist/${theme}.css` 106 | const themeStr: string = await File.readFile(p, 'utf-8') 107 | await File.writeFile(`${__temp}/index.css`, themeStr) 108 | } 109 | 110 | export const copyAssets = async(config: Config): Promise => { 111 | const p: string = `${config.__user_source_path}/assets` 112 | if (!(await File.exists(p))) return 113 | await File.exec(`cp -r ${p} ${__temp}`) 114 | } 115 | 116 | export const copyInlineHtml = async(config: Config, catalogs: Catalog[]): Promise => { 117 | const index: string = await File.readFile(`${__app}/index.html`, 'utf-8') 118 | const indexs: string[] = index.split('') 119 | let scripts: string = ` 120 | 121 | ` 122 | const foot = `${indexs.pop()}` 123 | await File.exec(`cp ${__dirname}/../index.js ${__target}/index.js`) 124 | scripts = await appendHighlight(config.__user_source_path, scripts) 125 | 126 | let inlineHtml: string = indexs.reduce((pre, next) => pre + next, '') + scripts + foot 127 | inlineHtml = inlineHtml.replace('__TITLE__', config.title) 128 | inlineHtml = appendHighlightStyle(inlineHtml) 129 | inlineHtml = inlineHtml.replace(/\n/g, '').replace(/>\s+<') 130 | await File.writeFile(`${__target}/index.html`, inlineHtml, 'utf-8') 131 | } 132 | -------------------------------------------------------------------------------- /src/scripts/event.ts: -------------------------------------------------------------------------------- 1 | type EventRecord = { 2 | type: string, 3 | handle: EventListener, 4 | } 5 | 6 | export class EventHub { 7 | 8 | private source: Text 9 | private eventRecords: EventRecord[] = [] 10 | 11 | constructor() { 12 | this.source = document.createTextNode('') 13 | } 14 | 15 | dispath(eventType: string, detail?: any): void { 16 | const event: CustomEvent = new CustomEvent(eventType, 17 | Object.assign({ 18 | bubbles: true, 19 | cancelable: true, 20 | }, { detail })) 21 | this.source.dispatchEvent(event) 22 | } 23 | 24 | listen(eventType: string, done: EventListener): void { 25 | const record: EventRecord = this.eventRecords.find(record => { 26 | return record.type === eventType && record.handle === done 27 | }) 28 | if (!!record) return 29 | this.source.addEventListener(eventType, done) 30 | this.eventRecords.push({ 31 | type: eventType, 32 | handle: done, 33 | }) 34 | } 35 | 36 | remove(eventType: string, done?: EventListener): void { 37 | // just remove one 38 | if (done) return this.removeOne(eventType, done) 39 | this.eventRecords 40 | .filter(re => re.type === eventType) 41 | .forEach(re => this.source.removeEventListener(re.type, re.handle)) 42 | } 43 | 44 | removeAll(): void { 45 | this.eventRecords 46 | .forEach(re => this.source.removeEventListener(re.type, re.handle)) 47 | } 48 | 49 | private removeOne(eventType: string, done?: EventListener): void { 50 | const record: EventRecord = this.eventRecords.find(record => { 51 | return record.type === eventType && record.handle === done 52 | }) 53 | if (!record) return 54 | this.source.removeEventListener(eventType, done) 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/scripts/generator.ts: -------------------------------------------------------------------------------- 1 | import { BackToTop } from './plugins/back' 2 | import { Highlight } from './plugins/highlight' 3 | import { Indicator } from './plugins/indicator' 4 | import { Responsive } from './plugins/responsive' 5 | 6 | const saveToDefaultRouter = (link: string): void => { 7 | if (window.__paper.router.default) return 8 | window.__paper.router.default = link 9 | } 10 | const removeMarkdownSuffix = (name: string) => name.replace('.md', '') 11 | 12 | const makeList = async(catalogs: Catalog[], path, d: Document) => { 13 | const ul: HTMLElement = d.createElement('ul') 14 | for (const unit of catalogs) { 15 | const li: HTMLElement = d.createElement('li') 16 | const routerLink: string = (unit.showPath + unit.name).replace(path, '') 17 | 18 | // is directory 19 | if (unit.children && unit.children.length > 0) { 20 | li.innerHTML = `

${removeMarkdownSuffix(unit.name)}

` 21 | li.classList.add('sub-list-container') 22 | const subList: HTMLElement = await makeList(unit.children, path, d) 23 | subList.classList.add('sub-list') 24 | li.appendChild(subList) 25 | } else { 26 | // first link 27 | saveToDefaultRouter(routerLink) 28 | li.innerHTML = `` 29 | } 30 | ul.appendChild(li) 31 | } 32 | 33 | return ul 34 | } 35 | 36 | const makeTitle = (config: Config): HTMLElement => { 37 | document.title = config.title 38 | const title: HTMLElement = document.createElement('div') 39 | title.classList.add('side-title') 40 | title.innerHTML = `

${config.title}

` 41 | return title 42 | } 43 | 44 | export const side = async(catalogs: Catalog[], config: Config): Promise => { 45 | const title: HTMLElement = makeTitle(config) 46 | const list: HTMLElement = await makeList(catalogs, config.__user_source_path, document) 47 | list.classList.add('side-list') 48 | return [title, list] 49 | } 50 | 51 | const initSubList = async (config: Config) => { 52 | const containers: NodeListOf = document.querySelectorAll('.sub-list-container') 53 | const subList: NodeListOf = document.querySelectorAll('.sub-list') 54 | const subListArr: Element[] = (>Array.from(subList)) 55 | let baseHeight: number = 37 56 | // correction base height 57 | subListArr.some(sub => { 58 | const li: HTMLElement = sub.querySelector('li') 59 | if (li && li.offsetHeight) { 60 | baseHeight = li.offsetHeight 61 | } 62 | return !!li 63 | }) 64 | 65 | // click directory 66 | const handle: Function = (container: Element, first?: boolean): void => { 67 | const getUlRealHeight: Function = (ul: HTMLElement): number => { 68 | const children: NodeListOf = ul.querySelectorAll('li') 69 | return (Array.from(children).length || 0) * baseHeight 70 | } 71 | const list: HTMLElement = (container.querySelector('.sub-list')) 72 | const height: number = getUlRealHeight(list) 73 | const isClose: boolean = list.offsetHeight > 0 74 | 75 | // is deep directory 76 | let deep: number = 3 77 | const syncParentsHeight: Function = (self: HTMLElement): any => { 78 | if (deep <= 0) return 79 | deep -- 80 | 81 | const parent: HTMLElement = self.parentElement 82 | const isList: boolean = parent.nodeName.toLowerCase() === 'ul' 83 | const isSubList: boolean = parent.classList.contains('sub-list') 84 | if (!isList || !isSubList) return syncParentsHeight(self.parentElement) 85 | 86 | const nativeHeight: number = getUlRealHeight(parent) 87 | parent.style.height = `${isClose ? nativeHeight : nativeHeight + height}px` 88 | deep ++ 89 | syncParentsHeight(self.parentElement) 90 | } 91 | syncParentsHeight(list) 92 | 93 | list.style.height = first ? `${height}px` : `${isClose ? 0 : height}px` 94 | } 95 | Array.from(containers).forEach(con => { 96 | // expand all menu 97 | config.expandAll && handle(con, true) 98 | con.addEventListener('click', () => handle(con)) 99 | }) 100 | subListArr.forEach(sub => { 101 | sub.addEventListener('click', (event: Event) => event.stopPropagation()) 102 | }) 103 | } 104 | 105 | // change document title from location event 106 | const changTitle = (eventHub: any, config: Config) => { 107 | const pathToTitle = (p: string): string => { 108 | let hash: string = p.split('#/').reverse()[0] 109 | hash = hash.replace('static/', '') 110 | .replace('.html', '') 111 | .replace('//', '/') 112 | .replace('//', '/') 113 | return hash.split('/') 114 | .map(path => path.replace(/\//g, '').replace(/^\d+_/g, '')) 115 | .filter(r => !!r) 116 | .map(str => config.alias[str] || str) 117 | .join(' - ') 118 | } 119 | eventHub.listen('container-changed', ({ detail }) => { 120 | document.title = `${decodeURI(pathToTitle(detail))} - ${config.title}` 121 | }) 122 | } 123 | 124 | export const event = async(config: Config, eventHub: any): Promise => { 125 | await initSubList(config) 126 | 127 | config.backToTop && new BackToTop() 128 | config.indicator && new Indicator(eventHub) 129 | new Highlight(eventHub) 130 | new Responsive() 131 | changTitle(eventHub, config) 132 | } 133 | -------------------------------------------------------------------------------- /src/scripts/index.ts: -------------------------------------------------------------------------------- 1 | const config: Config = window.__config 2 | const catalogs: Catalog[] = window.__catalogs 3 | import * as Generator from './generator' 4 | import { init } from './utils' 5 | import { Router } from './router' 6 | import { EventHub } from './event' 7 | 8 | const docker: Function = async(w: Window, d: Document): Promise => { 9 | const eventHub = new EventHub() 10 | const sidebar: HTMLElement = d.getElementById('side') 11 | 12 | const sides: HTMLElement[] = await Generator.side(catalogs, config) 13 | sides.forEach(el => sidebar.appendChild(el)) 14 | 15 | await Generator.event(config, eventHub) 16 | 17 | new Router(d.getElementById('container'), config.docPath) 18 | .listen(eventHub) 19 | } 20 | 21 | window.onload = (): void => { 22 | init() 23 | docker(window, document).then() 24 | console.log('Generate source: [simpler-paper]\nWelcome to try: https://github.com/DhyanaChina/simpler-paper') 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/scripts/plugins/back.ts: -------------------------------------------------------------------------------- 1 | 2 | export class BackToTop { 3 | 4 | static toggleBackButton(btnElement: Element, show: boolean): void { 5 | btnElement.classList.toggle('show', show) 6 | } 7 | 8 | static handleBackButton(container: Element): void { 9 | container.scrollTop = 0 10 | } 11 | 12 | static makeBackButton(d: Document): Element { 13 | const _div: Element = d.createElement('div') 14 | _div.classList.add('back-to-top') 15 | _div.innerHTML = `
Back
` 16 | return _div 17 | } 18 | 19 | constructor() { 20 | this.init() 21 | } 22 | 23 | private init(): void { 24 | const container: Element = document.querySelector('#container-position') 25 | const main: Element = document.querySelector('.main') 26 | const backButton: Element = BackToTop.makeBackButton(document) 27 | main.appendChild(backButton) 28 | 29 | backButton.addEventListener('click', () => { 30 | BackToTop.handleBackButton(container) 31 | }) 32 | container.addEventListener('scroll', (e: Event) => { 33 | BackToTop.toggleBackButton(backButton, (e.target).scrollTop > 300) 34 | }) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/scripts/plugins/highlight.ts: -------------------------------------------------------------------------------- 1 | import { EventHub } from '../event' 2 | 3 | export class Highlight { 4 | 5 | constructor(eventHub: EventHub) { 6 | eventHub.listen('container-changed', this.handle) 7 | } 8 | 9 | handle(): void { 10 | if (!window.hljs) return 11 | const { highlightBlock } = window.hljs 12 | const blocks: NodeListOf = document.querySelectorAll('pre') 13 | Array.from(blocks).forEach(code => highlightBlock(code)) 14 | } 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/scripts/plugins/indicator.ts: -------------------------------------------------------------------------------- 1 | import { EventHub } from '../event' 2 | 3 | export class Indicator { 4 | 5 | private indicatorElement: HTMLElement 6 | 7 | static toggleIndicator(indicatorElement: HTMLElement, show: boolean): void { 8 | if (!indicatorElement) return 9 | indicatorElement.classList.toggle('show', show) 10 | } 11 | 12 | static makeIndicatorElement(d: Document): HTMLElement { 13 | const _div: HTMLElement = d.createElement('div') 14 | _div.classList.add('loading-indicator') 15 | _div.innerHTML = `
Loading
` 16 | return _div 17 | } 18 | 19 | constructor(eventHub: EventHub) { 20 | this.init() 21 | eventHub.listen('container-will-change', () => this.willChange()) 22 | eventHub.listen('container-changed', () => this.changed()) 23 | } 24 | 25 | willChange(): void { 26 | Indicator.toggleIndicator(this.indicatorElement, true) 27 | } 28 | 29 | changed(): void { 30 | Indicator.toggleIndicator(this.indicatorElement, false) 31 | } 32 | 33 | private init(): void { 34 | const main: Element = document.querySelector('.main') 35 | this.indicatorElement = Indicator.makeIndicatorElement(document) 36 | main.appendChild(this.indicatorElement) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/scripts/plugins/responsive.ts: -------------------------------------------------------------------------------- 1 | 2 | export class Responsive { 3 | 4 | private trunks: Element[] = [] 5 | private lastSize: string = '' 6 | 7 | static TrunksClasses(): string[] { 8 | return ['.main', '.side-position', '#side', '.container-position', '#container'] 9 | } 10 | 11 | static MakeSize(width: number): string { 12 | if (width < 540) return 'xs' 13 | if (width < 760) return 'sm' 14 | if (width < 1300) return 'md' 15 | if (width < 1920) return 'lg' 16 | return 'xl' 17 | } 18 | 19 | constructor() { 20 | this.init() 21 | this.initMobileEvent() 22 | } 23 | 24 | private init(): void { 25 | const body: HTMLElement = document.body 26 | this.trunks = Responsive.TrunksClasses() 27 | .map(str => body.querySelector(str)) 28 | .filter(r => !!r) 29 | .concat([body]) 30 | 31 | window.addEventListener('resize', () => this.detector()) 32 | this.detector() 33 | } 34 | 35 | private detector(): void { 36 | const size: string = Responsive.MakeSize(window.innerWidth) 37 | if (size === this.lastSize) return 38 | try { 39 | this.trunks.forEach(el => { 40 | el.classList.add(size) 41 | this.lastSize && el.classList.remove(this.lastSize) 42 | }) 43 | } catch (e) {} 44 | 45 | this.lastSize = size 46 | } 47 | 48 | private initMobileEvent(): void { 49 | const sideTitle: Element = document.querySelector('.side-title') 50 | const sideBar: Element = document.querySelector('#side') 51 | sideTitle.addEventListener('click', () => { 52 | const isMobile: boolean = sideBar.classList.contains('xs') || sideBar.classList.contains('sm') 53 | if (!isMobile) return 54 | sideBar.classList.toggle('active') 55 | }) 56 | 57 | } 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/scripts/router.ts: -------------------------------------------------------------------------------- 1 | import { findHTML } from './utils' 2 | 3 | export class Router { 4 | 5 | private slotElement: HTMLElement 6 | private docPath: string 7 | private links: any[] = [] 8 | private lastLink: HTMLElement 9 | private eventHub: any 10 | private origin: string 11 | 12 | static removeHashTag(hash: string = ''): string { 13 | if (!hash.startsWith('#')) return hash 14 | return hash.substr(1, hash.length) 15 | } 16 | 17 | static removeSlash(path: string): string { 18 | return path.replace(/\/\//g, '/') 19 | } 20 | 21 | static replaceSuffix(name: string): string { 22 | name = name.split('.md')[0] 23 | return `${name}.html` 24 | } 25 | 26 | constructor(slotElement: HTMLElement, docPath: string = '/') { 27 | this.slotElement = slotElement 28 | this.docPath = docPath 29 | this.origin = window.location.origin + window.location.pathname 30 | this.initList() 31 | } 32 | 33 | listen(eventHub: any): void { 34 | this.eventHub = eventHub 35 | window.onhashchange = () => this._parseHash() 36 | this._parseHash() 37 | } 38 | 39 | private closeMenu(): void { 40 | const sideBar: Element = document.querySelector('#side') 41 | const isMobile: boolean = sideBar.classList.contains('xs') || sideBar.classList.contains('sm') 42 | if (!isMobile) return 43 | sideBar.classList.remove('active') 44 | } 45 | 46 | private initList(): void { 47 | const sideList: Element = document.querySelector('.side-list') 48 | const links: NodeListOf = sideList.querySelectorAll('a') 49 | Array.from(links).forEach((link: Element) => { 50 | this.links.push({ 51 | el: link, 52 | href: link.getAttribute('href'), 53 | }) 54 | }) 55 | } 56 | 57 | private toggleList(hash: string): void { 58 | const link = this.links.find(link => link.href === `#${decodeURI(hash)}`) 59 | if (!link) return 60 | this.lastLink && this.lastLink.parentElement.classList.remove('active') 61 | link.el.parentElement.classList.add('active') 62 | this.lastLink = link.el 63 | } 64 | 65 | private _parseHash(): void { 66 | this.eventHub.dispath('container-will-change') 67 | const hash: string = Router.removeHashTag(window.location.hash) 68 | 69 | // update list style and address link 70 | this.toggleList(hash) 71 | 72 | // default router path 73 | let path: string = '/static/' + this.docPath + hash 74 | if (path.endsWith('/')) { 75 | path += window.__paper.router.default 76 | } 77 | const htmlPath: string = Router.replaceSuffix(path) 78 | this._loader(Router.removeSlash(htmlPath)).then() 79 | } 80 | 81 | private async _loader(path: string): Promise { 82 | const res: Response = await findHTML(this.origin + path) 83 | const _div: HTMLElement = document.createElement('div') 84 | _div.classList.add('container-inner') 85 | _div.innerHTML = await res.text() 86 | this.slotElement.innerHTML = '' 87 | this.slotElement.appendChild(_div) 88 | this.slotElement.parentElement.scrollTo(0, 0) 89 | 90 | // emit router event 91 | this.eventHub.dispath('container-changed', path) 92 | // in mobile, close menu side 93 | this.closeMenu() 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/scripts/utils.ts: -------------------------------------------------------------------------------- 1 | const headers = new Headers() 2 | headers.append('Accept', 'text/html,application/xhtml+xml,application/xml') 3 | 4 | export const findHTML = (url: string): Promise => { 5 | return new Promise((r, j) => { 6 | window.fetch(url, { 7 | method: 'GET', 8 | mode: 'no-cors', 9 | cache: 'default', 10 | credentials: 'same-origin', 11 | headers, 12 | }) 13 | .then(res => r(res)) 14 | .catch(e => j(e)) 15 | }) 16 | } 17 | 18 | export const init = (): void => { 19 | window.__paper = { 20 | router: { 21 | default: null, 22 | }, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/check.ts: -------------------------------------------------------------------------------- 1 | import { defaultConfig } from './config.default' 2 | import File from './file' 3 | import Log from './log' 4 | import { Stats } from 'fs' 5 | 6 | export const checkSource = async(path: string = '') => { 7 | if (!await File.exists(path)) { 8 | Log.sourceError(path) 9 | process.exit(1) 10 | } 11 | } 12 | 13 | export const checkConfig = async(path: string = ''): Promise => { 14 | const configPath: string = `${path}/paper.config.json` 15 | if (!await File.exists(configPath)) return {} 16 | const config: Buffer = await File.readFile(`${path}/paper.config.json`) 17 | 18 | let result: any 19 | try { 20 | result = JSON.parse(config.toString() || '{}') 21 | } catch (e) { 22 | Log.configInvalid() 23 | } 24 | return result 25 | } 26 | 27 | export const checkTheme = async(config: Config): Promise => { 28 | const theme: string = config.theme || 'default' 29 | const p: string = `${__dirname}/../../node_modules/simpler-paper-themes/dist/${theme}.css` 30 | if (!await File.exists(p)) { 31 | Log.notFoundTheme(theme) 32 | process.exit(1) 33 | return false 34 | } 35 | return true 36 | } 37 | 38 | export const findSource = async(userPath: string): Promise => { 39 | const files: string[] = await File.readdir(userPath) 40 | const directories: string[] = [] 41 | for (const f of files) { 42 | const stat: Stats = await File.stat(`${userPath}/${f}`) 43 | if (stat.isFile()) continue 44 | if (await File.exists(`${userPath}/${f}/paper.config.json`)) { 45 | directories.push(f) 46 | } 47 | } 48 | if (directories.length > 1) { 49 | Log.configNonUnique(directories) 50 | process.exit(1) 51 | } 52 | if (directories.length === 0) { 53 | Log.configNotFound() 54 | process.exit(1) 55 | } 56 | return directories[0] 57 | } 58 | 59 | export const assignConfig = async(source: string): Promise => { 60 | await checkSource(source) 61 | const userConfig: any = await checkConfig(source) 62 | const config: Config = Object.assign({}, 63 | defaultConfig, 64 | userConfig, 65 | { __user_source_path: source }, 66 | ) 67 | return config 68 | } 69 | -------------------------------------------------------------------------------- /src/utils/config.default.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const defaultConfig: Config = { 4 | alias: {}, 5 | title: 'simpler paper', 6 | docPath: '/', 7 | output: 'dist', 8 | theme: 'plain', 9 | miniMap: false, 10 | backToTop: false, 11 | indicator: true, 12 | expandAll: false, 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/file.ts: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | import * as marked from 'marked' 3 | import * as hljs from 'highlight.js/lib/index.js' 4 | const promisify = require('util.promisify') 5 | const childProcess = require('child_process') 6 | 7 | 8 | /** 9 | * tips grammar 10 | * #> ====> info 11 | * ?> ====> warning 12 | * !> ====> error 13 | */ 14 | const renderer = new marked.Renderer() 15 | const tipsReg = /^(\s*(?:!|#|\?))>\s+/g 16 | const classMap = { '#': 'info', '?': 'warning', '!': 'error' } 17 | const paragraphCopy: (t: string) => string = renderer.paragraph 18 | renderer.paragraph = (text: string): string => { 19 | if (!tipsReg.test(text)) return paragraphCopy(text) 20 | const content: string = text.replace(tipsReg, '') 21 | const typeStr: string = text.match(tipsReg)[0].replace(/\s/g, '') 22 | return `

${content}

` 23 | } 24 | 25 | 26 | marked.setOptions({ 27 | renderer, 28 | gfm: true, 29 | tables: true, 30 | breaks: false, 31 | pedantic: false, 32 | sanitize: false, 33 | smartLists: true, 34 | smartypants: false, 35 | highlight: code => (hljs).highlightAuto(code).value, 36 | }) 37 | 38 | const noErrorPromisifyShim: Function = (func: Function) => (...args: any[]) => new Promise(r => { 39 | func(...args, (...results) => r(...results)) 40 | }) 41 | const makePromisify: Function = (): Function => { 42 | const nativePromisify = require('util').promisify 43 | if (nativePromisify && typeof nativePromisify === 'function') { 44 | return nativePromisify 45 | } 46 | return noErrorPromisifyShim 47 | } 48 | const noErrorPromisify: Function = makePromisify() 49 | 50 | 51 | export default { 52 | readdir: promisify(fs.readdir), 53 | mkdir: promisify(fs.mkdir), 54 | readFile: promisify(fs.readFile), 55 | writeFile: promisify(fs.writeFile), 56 | exists: noErrorPromisify(fs.exists), 57 | stat: promisify(fs.stat), 58 | spawnSync: childProcess.spawnSync, 59 | exec: promisify(childProcess.exec), 60 | marked: promisify(marked), 61 | } 62 | -------------------------------------------------------------------------------- /src/utils/filter.ts: -------------------------------------------------------------------------------- 1 | const pathFormat = path => path.replace(/\\/g, '/') 2 | 3 | export default { 4 | path: pathFormat, 5 | } 6 | -------------------------------------------------------------------------------- /src/utils/highlight.ts: -------------------------------------------------------------------------------- 1 | const USER_PATH = process.cwd() 2 | const __target = `${__dirname}/../../templates/target` 3 | import File from './file' 4 | let includeStyle: boolean = false 5 | 6 | export const appendHighlight = async(source: string, scripts: string) => { 7 | const docPath: string = `${USER_PATH}/${source}` 8 | const files: string[] = await File.readdir(docPath) 9 | let hljs: string = '' 10 | for (const name of files) { 11 | if (name === 'highlight.js') { 12 | await File.exec(`cp ${docPath}/${name} ${__target}`) 13 | hljs += `` 14 | } 15 | if (name === 'highlight.css') { 16 | await File.exec(`cp ${docPath}/${name} ${__target}`) 17 | includeStyle = true 18 | } 19 | } 20 | scripts = hljs + scripts 21 | 22 | return scripts 23 | } 24 | 25 | export const appendHighlightStyle = (inlineHtml: string): string => { 26 | if (!includeStyle) return inlineHtml 27 | return inlineHtml.replace( 28 | '', 29 | '', 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/utils/log.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk' 2 | import * as Ora from 'ora' 3 | import { hrtime } from 'process' 4 | 5 | let startTime: [number, number] 6 | let ora: any 7 | let oraTask: string 8 | 9 | export default { 10 | sourceError: (path?: string) => { 11 | console.log(chalk.red('\nError: the document directory was not found.')) 12 | path && console.log(chalk.red(`PathError: "${path}".`)) 13 | console.log(`try run [${chalk.green('paper build ')}].\n`) 14 | }, 15 | 16 | configInvalid: () => { 17 | console.log(chalk.red('\nError: paper.config.json is not a valid file.\n')) 18 | }, 19 | 20 | configNonUnique: (directories: string[]) => { 21 | console.log(chalk.red('\n\nError: There are multiple configuration files:')) 22 | directories.forEach(dir => console.log(` ${dir}/paper.config.json`)) 23 | console.log('\nsmipler-paper requires only one configuration file.') 24 | }, 25 | 26 | configNotFound: () => { 27 | console.log(chalk.red(`\nError: not found paper.config.json.\n`)) 28 | }, 29 | 30 | notFoundTheme: (theme: string) => { 31 | console.log(chalk.red(`\nError: paper theme [${theme}] is not found.\n`)) 32 | }, 33 | 34 | time: { 35 | start(task: string): void { 36 | startTime = hrtime() 37 | ora = new Ora(task).start() 38 | oraTask = task 39 | }, 40 | over(success: boolean = true): void { 41 | const time: [number, number] = hrtime(startTime) 42 | const show: string = (time[1] / 1000000).toFixed(2) 43 | if (!success) { 44 | ora.fail(oraTask) 45 | return process.exit(1) 46 | } 47 | ora.succeed(oraTask) 48 | console.log(` ${chalk.hex('#44A6BE')(show + ' ms')}\n`) 49 | }, 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /templates/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | __TITLE__ 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2015", "dom"], 4 | "target": "es5", 5 | "declaration": true, 6 | "declarationDir": "./@types", 7 | "sourceMap": true, 8 | "removeComments": true, 9 | "noImplicitAny": false, 10 | "preserveConstEnums": true, 11 | "experimentalDecorators": true, 12 | "emitDecoratorMetadata": true, 13 | "typeRoots": [ 14 | "node_modules/@types", 15 | "typings" 16 | ] 17 | }, 18 | "compileOnSave": false, 19 | "includes": [ 20 | "src/**/*" 21 | ], 22 | "exclude": [ 23 | "node_modules", 24 | "templates", 25 | "dist" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "member-access": [true, "no-public"], 5 | "member-ordering": [ 6 | true, 7 | { 8 | "order": [ 9 | "public-static-field", 10 | "private-static-field", 11 | "protected-static-field", 12 | "public-static-method", 13 | "private-static-method", 14 | "protected-static-method", 15 | "public-instance-field", 16 | "private-instance-field", 17 | "protected-instance-field", 18 | "public-constructor", 19 | "private-constructor", 20 | "protected-constructor", 21 | "private-instance-method", 22 | "public-instance-method" 23 | ] 24 | } 25 | ], 26 | "no-any": false, 27 | "no-non-null-assertion": true, 28 | "no-var-requires": false, 29 | "only-arrow-functions": [ 30 | true, 31 | "allow-declarations" 32 | ], 33 | "prefer-for-of": true, 34 | "typedef": [true, "call-signature", "parameter", "member-variable-declaration"], 35 | "eofline": true, 36 | "indent": "spaces", 37 | "member-ordering": [ 38 | true, 39 | "public-before-private", 40 | "static-before-instance", 41 | "variables-before-functions" 42 | ], 43 | "no-eval": true, 44 | "no-sparse-arrays": true, 45 | "switch-default": true, 46 | "prefer-const": true, 47 | "arrow-return-shorthand": true, 48 | "trailing-comma": [ 49 | true, 50 | { 51 | "multiline": "always", 52 | "singleline": "never" 53 | } 54 | ], 55 | "one-line": [ 56 | true, 57 | "check-open-brace", 58 | "check-catch", 59 | "check-else", 60 | "check-whitespace" 61 | ], 62 | "quotemark": [ 63 | true, 64 | "single" 65 | ], 66 | "semicolon": false, 67 | "triple-equals": [ 68 | true, 69 | "allow-null-check" 70 | ], 71 | "variable-name": false, 72 | "whitespace": [ 73 | true 74 | ] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /typings/paper/index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | interface Config { 3 | alias: any, 4 | title: string, 5 | miniMap: boolean, 6 | backToTop: boolean, 7 | docPath: string, 8 | theme: string, 9 | output: string, 10 | indicator: boolean, 11 | expandAll: boolean, 12 | __user_source_path?: string, 13 | } 14 | 15 | interface Catalog { 16 | // file path 17 | path?: string, 18 | 19 | // file show path 20 | showPath: string, 21 | 22 | // file native name 23 | native: string, 24 | 25 | // file show name 26 | name: string, 27 | 28 | weight: number, 29 | 30 | children?: Catalog[], 31 | } 32 | 33 | 34 | type PaperRouter = { 35 | default?: string, 36 | } 37 | 38 | type Paper = { 39 | router: PaperRouter, 40 | } 41 | 42 | interface Window { 43 | __paper?: Paper, 44 | __config?: Config, 45 | __catalogs?: Catalog[], 46 | hljs?: any, 47 | } 48 | -------------------------------------------------------------------------------- /typings/webpack/index.d.ts: -------------------------------------------------------------------------------- 1 | declare var require: { 2 | (path: string): T 3 | (paths: string[], callback: (...modules: any[]) => void): void 4 | ensure: (paths: string[], callback: (require: (path: string) => T) => void) => void 5 | } 6 | --------------------------------------------------------------------------------