├── .gitignore ├── LICENSE ├── README.md ├── app.js ├── bin └── index.js ├── collaborators.md ├── components ├── content.css ├── content.js ├── main.css ├── main.js ├── menu.css ├── menu.js ├── sidebar.css └── sidebar.js ├── examples ├── browser │ ├── 200.html │ ├── bundle.js │ ├── contents.js │ ├── index.html │ ├── index.js │ ├── logo.svg │ ├── markdown │ │ ├── about.md │ │ ├── pig.md │ │ ├── puppy.md │ │ └── sheep.md │ └── package.json ├── cli-full-html │ ├── contents.js │ ├── docs │ │ ├── about.md │ │ └── pizza.md │ ├── package.json │ └── style.css ├── cli-images │ ├── assets │ │ ├── baby.jpg │ │ ├── doodie.jpg │ │ ├── storycat.jpg │ │ ├── trouble.jpg │ │ └── wizard.jpg │ ├── contents.js │ ├── docs │ │ └── about.md │ └── package.json └── cli │ ├── contents.js │ ├── docs │ ├── about.md │ └── pizza.md │ ├── package.json │ └── style.css ├── index.js ├── lib ├── create-assets.js ├── create-css.js ├── create-html.js ├── create-js.js ├── create-output-dir.js ├── create-pushstate-file.js ├── parse-contents.js ├── parse-docs.js ├── parse-markdown.js └── parse-options.js ├── package.json ├── parse.js ├── styles ├── base.css ├── fonts.css ├── github-markdown.css ├── highlighting │ ├── tomorrow-night.css │ └── tomorrow.css └── index.css ├── tests ├── app.js ├── cli.js ├── fixtures │ ├── .DS_Store │ ├── browser │ │ ├── app.js │ │ ├── contents.js │ │ └── docs │ │ │ ├── a.md │ │ │ ├── b.md │ │ │ └── c.md │ └── cli │ │ ├── contents.js │ │ └── docs │ │ ├── a.md │ │ ├── b.md │ │ └── c.md ├── index.js ├── node.js └── parse-options.js └── transform.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | example/bundle.js 36 | site 37 | tmp 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jeremy Freeman 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 | # minidocs 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![js-standard-style][standard-image]][standard-url] 5 | 6 | > build a minimalist site for your documentation 7 | 8 | This module generates a documentation site from two simple components: 9 | 10 | 1. A collection of markdown documents 11 | 2. A hierarchical object specifying your table of contents 12 | 13 | This module is intentionally simpler and more opinionated than something like [Jekyll](https://jekyllrb.com/) or [Sphinx](http://www.sphinx-doc.org/en/stable/). Depending on what you're looking for, that might be good, because it's easier to reason about, or bad, because it's less flexible! It'll probably be most useful if your documentation already consists entirely of markdown files, and it composes well with any tools that generate markdown, for example [`ecosystem-docs`](https://github.com/hughsk/ecosystem-docs), which pulls README files from a collection of GitHub repositories. 14 | 15 | Sites can be built using a command-line tool, or using the library as a module with browserify. There are options for specifying a project logo, custom css, and other basic formatting. Support for themes coming soon! PRs welcome! 16 | 17 | Here is a [**simple example site**](http://minidocs-example.surge.sh) built with `minidocs` 18 | 19 | ## install 20 | 21 | ### command-line 22 | 23 | Install as a command-line tool 24 | 25 | ``` 26 | npm install -g minidocs 27 | ``` 28 | 29 | ### library 30 | 31 | Add to your project with 32 | 33 | ``` 34 | npm install --save minidocs 35 | ``` 36 | 37 | ## examples 38 | 39 | ### using minidocs on the command-line 40 | 41 | Just specify the location of your markdown files, the table of contents, the output location, and build the site 42 | 43 | ``` 44 | minidocs docs/ --contents contents.json --output site/ 45 | ``` 46 | 47 | The folder `site` will now contain the `html`, `js`, and `css` for your site. 48 | 49 | **Have a images or other files you'd like to include?** You can copy a directory into the build of your site with the `--assets` option: 50 | 51 | ``` 52 | minidocs docs/ --contents contents.json --output site/ --assets images 53 | ``` 54 | 55 | **Want to change the styles?** Use the `--css` option to include a custom stylesheet. 56 | 57 | ``` 58 | minidocs docs/ --contents contents.json --output site/ --css style.css 59 | ``` 60 | 61 | **[See all other cli options.](https://github.com/freeman-lab/minidocs#command-line-1)** 62 | 63 | ### using minidocs as a JS module 64 | 65 | Create a table of contents in a file named `contents.json`: 66 | 67 | ```json 68 | { 69 | "overview": { 70 | "about": "about.md" 71 | }, 72 | "animals": { 73 | "furry": { 74 | "sheep": "sheep.md" 75 | }, 76 | "pink": { 77 | "pig": "pig.md" 78 | } 79 | } 80 | } 81 | ``` 82 | 83 | Then build the site and add it to the page with 84 | 85 | ```javascript 86 | var minidocs = require('minidocs') 87 | 88 | var app = minidocs({ 89 | contents: './contents.json', 90 | markdown: './markdown',, 91 | logo: './logo.svg' 92 | }) 93 | 94 | var tree = app.start() 95 | document.body.appendChild(tree) 96 | ``` 97 | 98 | This assumes you have the files `about.md`, `sheep.md`, and `pig.md` inside a local folder `markdown`. 99 | 100 | To run this in the browser you'll need to use the minidocs transform with browserify or budo: 101 | 102 | **browserify example:** 103 | 104 | ``` 105 | browserify index.js -t minidocs/transform > bundle.js 106 | ``` 107 | 108 | **budo example:** 109 | 110 | ``` 111 | budo index.js:bundle.js -P -- -t minidocs/transform 112 | ``` 113 | 114 | You can also add transforms to your project by adding a `browserify` field to the `package.json` file with a `transform` array: 115 | 116 | ```js 117 | "browserify": { 118 | "transform": [ 119 | "minidocs/transform" 120 | ] 121 | } 122 | ``` 123 | 124 | ### about the minidocs transform 125 | 126 | Packaged with minidocs is a transform that takes care of reading the contents file, the markdown files, highlighting code in the markdown, and bundling the JS and CSS. 127 | 128 | The minidocs transform is only necessary when using minidocs as a JS module, not when using the minidocs cli tool. 129 | 130 | 131 | ## run the example 132 | 133 | To run a full example, clone this repository, go into the folder [`example`](example) then call 134 | 135 | ``` 136 | npm install 137 | npm start 138 | ``` 139 | 140 | ## usage 141 | 142 | ### command-line 143 | 144 | ``` 145 | Usage: 146 | minidocs {sourceDir} -c {contents.json} -o {buildDir} 147 | 148 | Options: 149 | * --contents, -c JSON file that defines the table of contents 150 | * --output, -o Directory for built site [site] 151 | * --title, -t Project name [name of current directory] 152 | * --logo, -l Project logo 153 | * --css, -s Optional stylesheet 154 | * --assets, -a Directory of assets to be copied to the built site 155 | * --initial, -i Page to use for root url 156 | * --pushstate, -p Create a 200.html file for hosting services like surge.sh 157 | * --basedir, -b Base directory of the site 158 | * --full-html, -f Create HTML files for all routes. Useful for GitHub Pages. [false] 159 | * --help, -h Show this help message 160 | ``` 161 | 162 | ### library 163 | 164 | #### `var minidocs = require('minidocs')` 165 | 166 | #### `var app = minidocs(opts)` 167 | 168 | Where `opts` is an object that can specify the following options 169 | 170 | - `contents` the path to a JSON file or JS module with the table of contents, required 171 | - `markdown` the path to the directory of markdown files 172 | - `styles` a stylesheet, if not required will only use base styles 173 | - `logo` relative file path to a logo file, if unspecified will not include a logo 174 | - `initial` which document to show on load, if unspecified will load the first document 175 | - `root` a DOM node to append to, if unspecified will append to `document.body` 176 | - `basedir` the base route of the minidocs app (useful if published as a project on github pages) 177 | 178 | #### `var tree = app.start(rootId?, opts)` 179 | The `start` method accepts the same options as [choo's `start` method](https://github.com/yoshuawuyts/choo#tree--appstartrootid-opts). 180 | 181 | This generates the html tree of the application that can be added to the DOM like this: 182 | 183 | ```js 184 | var tree = app.start() 185 | document.body.appendChild(tree) 186 | ``` 187 | 188 | #### `var html = app.toString(route, state)` 189 | The `toString` method accepts the same options as [choo's `toString` method](https://github.com/yoshuawuyts/choo#html--apptostringroute-state) 190 | 191 | We use this in the command-line tool to generate the static files of the site. 192 | 193 | ## deploying minidocs 194 | 195 | ### surge.sh 196 | 197 | [surge.sh](https://surge.sh) supports HTML5 pushstate if you have a 200.html file in your built site. You can either create that file yourself when using minidocs as a JS module, or you can build the site with the minidocs cli tool and the `--pushstate` option: 198 | 199 | ```sh 200 | minidocs docs/ -c contents.json --pushstate -o site/ 201 | ``` 202 | 203 | ##### Deploy with the `surge` command 204 | 205 | You can use the [`surge`](https://www.npmjs.com/package/surge) module to push the built site to the [surge.sh service](https://surge.sh). 206 | 207 | Install `surge`: 208 | 209 | ```sh 210 | npm install --save-dev surge 211 | ``` 212 | 213 | Create a `deploy` npm script: 214 | 215 | ```js 216 | "scripts": { 217 | "deploy": "surge dist" 218 | } 219 | ``` 220 | 221 | Publish your site: 222 | 223 | ```sh 224 | npm run deploy 225 | ``` 226 | 227 | ### github pages 228 | 229 | GitHub Pages doesn't support HTML5 pushstate, so you have two options: 230 | 231 | ##### 1. Generate the site with the minidocs cli 232 | 233 | Build a minidocs site with the cli and the `--full-html` option: 234 | 235 | ```sh 236 | minidocs path/to/docs/dir -c contents.json -o site --full-html 237 | ``` 238 | 239 | This creates an HTML file for each route of the site, so that on initial page load all content is sent from the server, and once the JS is loaded the minidocs app takes over all routing. 240 | 241 | ##### 2. Use hash routing with the JS module 242 | 243 | To use hash routing, start the app with the `{ hash: true }` option in the `minidocs.start` method: 244 | 245 | ```js 246 | var tree = app.start({ hash: true }) 247 | document.body.appendChild(tree) 248 | ``` 249 | 250 | ##### Deploy with the `gh-pages` command 251 | 252 | You can use the [`gh-pages`](https://www.npmjs.com/package/gh-pages) module to push the built site to the gh-pages branch of your repo. 253 | 254 | > Note: if you're deploying a project at a basedir like username.github.io/project-name, you'll want to use the `--basedir /project-name` option 255 | 256 | Install `gh-pages`: 257 | 258 | ```sh 259 | npm install --save-dev gh-pages 260 | ``` 261 | 262 | Create a `deploy` npm script: 263 | 264 | ```js 265 | "scripts": { 266 | "deploy": "gh-pages -d dist" 267 | } 268 | ``` 269 | 270 | Publish your site: 271 | 272 | ```sh 273 | npm run deploy 274 | ``` 275 | 276 | ## license 277 | 278 | [MIT](LICENSE) 279 | 280 | [npm-image]: https://img.shields.io/npm/v/minidocs.svg?style=flat-square 281 | [npm-url]: https://npmjs.org/package/minidocs 282 | [standard-image]: https://img.shields.io/badge/code%20style-standard-lightgray.svg?style=flat-square 283 | [standard-url]: https://github.com/feross/standard 284 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var choo = require('choo') 2 | 3 | var main = require('./components/main') 4 | 5 | module.exports = function (opts) { 6 | opts.basedir = (opts.basedir || '').replace(/\/$/, '') 7 | var app = choo() 8 | 9 | app.model({ 10 | state: { 11 | title: opts.title, 12 | logo: opts.logo, 13 | contents: opts.contents, 14 | html: opts.html, 15 | routes: opts.routes, 16 | current: opts.initial, 17 | basedir: opts.basedir 18 | }, 19 | reducers: {}, 20 | subscriptions: [ 21 | function catchLinks (send, done) { 22 | window.onclick = function (e) { 23 | var node = (function traverse (node) { 24 | if (!node) return 25 | if (node.localName !== 'a') return traverse(node.parentNode) 26 | if (node.href === undefined) return traverse(node.parentNode) 27 | if (window.location.host !== node.host) return traverse(node.parentNode) 28 | return node 29 | })(e.target) 30 | 31 | if (!node) return 32 | e.preventDefault() 33 | var href = node.href 34 | 35 | if (window.location.pathname !== node.pathname) { 36 | send('location:setLocation', { location: href }, done) 37 | window.history.pushState(null, null, href) 38 | document.body.scrollTop = 0 39 | } else { 40 | window.location.hash = node.hash 41 | var el = document.querySelector(node.hash) 42 | window.scrollTo(0, el.offsetTop) 43 | } 44 | } 45 | } 46 | ] 47 | }) 48 | 49 | app.model({ 50 | namespace: 'menu', 51 | state: { 52 | open: false, 53 | size: 'small' 54 | }, 55 | reducers: { 56 | set: function (data, state) { 57 | return data 58 | }, 59 | size: function (data, state) { 60 | return data 61 | } 62 | }, 63 | subscriptions: [ 64 | checkSize, 65 | function (send, done) { 66 | window.onresize = function () { 67 | checkSize(send, done) 68 | } 69 | } 70 | ] 71 | }) 72 | 73 | function checkSize (send, done) { 74 | var size = window.innerWidth > 600 ? 'large' : 'small' 75 | send('menu:size', { size: size }, done) 76 | } 77 | 78 | app.router(function (route) { 79 | var routes = [ 80 | route('/', main), 81 | route('/:page', main) 82 | ] 83 | 84 | if (opts.basedir) { 85 | return route(opts.basedir, routes) 86 | } 87 | 88 | return routes 89 | }) 90 | 91 | return app 92 | } 93 | -------------------------------------------------------------------------------- /bin/index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | var path = require('path') 4 | var assert = require('assert') 5 | var parsePath = require('parse-filepath') 6 | var minimist = require('minimist') 7 | var apply = require('async.applyeachseries') 8 | var exit = require('exit') 9 | 10 | var minidocs = require('../app') 11 | var parseOptions = require('../lib/parse-options') 12 | var createCSS = require('../lib/create-css') 13 | var createHTML = require('../lib/create-html') 14 | var createAssets = require('../lib/create-assets') 15 | var createJS = require('../lib/create-js') 16 | var createOutputDir = require('../lib/create-output-dir') 17 | var createPushstateFile = require('../lib/create-pushstate-file') 18 | 19 | var cwd = process.cwd() 20 | var cwdParsed = parsePath(cwd) 21 | var projectdir = cwdParsed.name 22 | var argv = minimist(process.argv.slice(2), { 23 | alias: { 24 | c: 'contents', 25 | o: 'output', 26 | t: 'title', 27 | l: 'logo', 28 | s: 'css', 29 | i: 'initial', 30 | a: 'assets', 31 | p: 'pushstate', 32 | b: 'basedir', 33 | f: 'full-html', 34 | h: 'help' 35 | }, 36 | default: { 37 | output: 'site', 38 | title: projectdir, 39 | basedir: '', 40 | 'full-html': false 41 | } 42 | }) 43 | 44 | var outputDir = path.resolve(cwd, argv.output) 45 | 46 | if (argv.help) { 47 | usage() 48 | } 49 | 50 | if (argv._[0]) { 51 | var source = path.resolve(cwd, argv._[0]) 52 | } else { 53 | error('\nError:\nsource markdown directory is required', { usage: true }) 54 | } 55 | 56 | if (argv.contents) { 57 | var contentsPath = path.resolve(cwd, argv.contents) 58 | } else { 59 | error('\nError:\n--contents/-c option is required', { usage: true }) 60 | } 61 | 62 | if (argv.logo) { 63 | var logoSource = path.resolve(cwd, argv.logo) 64 | var logo = path.parse(argv.logo).base 65 | } 66 | 67 | var state = { 68 | title: argv.title, 69 | logo: logo, 70 | logoSource: logoSource, 71 | contents: contentsPath, 72 | markdown: source, 73 | initial: argv.initial, 74 | basedir: argv.basedir, 75 | dir: cwd 76 | } 77 | 78 | var parsedState = parseOptions(state) 79 | var app = minidocs(parsedState) 80 | 81 | build({ 82 | argv: argv, 83 | state: parsedState, 84 | outputDir: outputDir 85 | }, function (err) { 86 | if (err) return error(err) 87 | exit() 88 | }) 89 | 90 | function build (options) { 91 | assert.ok(options) 92 | assert.ok(options.outputDir) 93 | assert.ok(options.argv) 94 | assert.ok(options.state) 95 | 96 | var tasks = [ 97 | createOutputDir, 98 | createJS, 99 | createCSS, 100 | createHTML, 101 | createAssets 102 | ] 103 | 104 | if (options.argv.pushstate) { 105 | tasks.push(createPushstateFile) 106 | } 107 | 108 | apply(tasks, app, options, function (err) { 109 | if (err) return error(err) 110 | }) 111 | } 112 | 113 | function error (err, opts) { 114 | console.log(err) 115 | if (opts && opts.usage) usage(1) 116 | } 117 | 118 | function usage (exitcode) { 119 | console.log(` 120 | Usage: 121 | minidocs {sourceDir} -c {contents.json} -o {buildDir} 122 | 123 | Options: 124 | * --contents, -c JSON file that defines the table of contents 125 | * --output, -o Directory for built site [site] 126 | * --title, -t Project name [name of current directory] 127 | * --logo, -l Project logo 128 | * --css, -s Optional stylesheet 129 | * --assets, -a Directory of assets to be copied to the built site 130 | * --initial, -i Page to use for root url 131 | * --pushstate, -p Create a 200.html file for hosting services like surge.sh 132 | * --basedir, -b Base directory of the site 133 | * --full-html, -f Create HTML files for all routes. Useful for GitHub Pages. [false] 134 | * --help, -h Show this help message 135 | `) 136 | exit(exitcode || 0) 137 | } 138 | -------------------------------------------------------------------------------- /collaborators.md: -------------------------------------------------------------------------------- 1 | # collaborators 2 | 3 | minidocs is only possible due to the excellent work of the following collaborators: 4 | 5 | 6 | 7 | 8 | 9 | 10 |
freeman-labGitHub/freeman-lab
fraserxuGitHub/fraserxu
sethvincentGitHub/sethvincent
11 | -------------------------------------------------------------------------------- /components/content.css: -------------------------------------------------------------------------------- 1 | a.markdown-link { 2 | color: rgb(173,173,173); 3 | background: rgb(240,240,240); 4 | display: inline-block; 5 | position: absolute; 6 | margin-top: -50px; 7 | padding: 3px 5px; 8 | text-decoration: none; 9 | } 10 | 11 | a.markdown-link:hover { 12 | color: rgb(130,130,130); 13 | background: rgb(225,225,225); 14 | } 15 | 16 | img.contributor { 17 | border: none; 18 | vertical-align: top; 19 | } 20 | 21 | div.contributor-wrapper { 22 | width: 30px; 23 | height: 30px; 24 | display: inline-block; 25 | text-align: center; 26 | margin-right: 5px; 27 | opacity: 0.8; 28 | cursor: pointer; 29 | border: 3px solid rgb(225, 225, 225); 30 | } 31 | 32 | div.contributor-wrapper:hover { 33 | background: rgb(205,205,205); 34 | opacity: 0.95; 35 | } 36 | 37 | div.contributor-container { 38 | width: 60%; 39 | right: 40px; 40 | margin-top: -50px; 41 | position: relative; 42 | display: inline-block; 43 | text-align: right; 44 | float: right; 45 | } 46 | 47 | @media (min-width: 600px) { 48 | div.contributor-wrapper { 49 | width: 50px; 50 | height: 50px; 51 | } 52 | div.contributor-container { 53 | right: 0px; 54 | } 55 | } -------------------------------------------------------------------------------- /components/content.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var css = require('sheetify') 3 | var avatar = require('github-avatar-url') 4 | 5 | module.exports = function (state, prev, send) { 6 | var currentPage = state.params.page || state.current 7 | var page = state.html[currentPage] 8 | var pageData = state.contents.filter(function (item) { 9 | return item.key === currentPage 10 | })[0] 11 | 12 | var prefix = css('./content.css') 13 | 14 | var contentWrapper = html`
` 15 | contentWrapper.innerHTML = page 16 | 17 | var link = pageData.source ? html`source` : '' 18 | 19 | function contributors (items) { 20 | return items.map(function (item) { 21 | if (!item) return 22 | var user = item.replace('@', '') 23 | var img = html`` 24 | img.style.opacity = 0 25 | avatar(user, function (err, url) { 26 | if (err) { 27 | // TODO: handle requests in effects, send error messages to state 28 | console.log(err) 29 | } 30 | img.src = url 31 | img.onload = function () { 32 | img.style.opacity = 1 33 | } 34 | }) 35 | return html`
36 | 37 | ${img} 38 | 39 |
` 40 | }) 41 | } 42 | 43 | if (pageData.contributors) { 44 | var contributorWrapper = html`
45 | ${contributors(pageData.contributors)} 46 |
` 47 | } 48 | 49 | return html`
50 | ${link} 51 | ${contributorWrapper} 52 | ${contentWrapper} 53 |
` 54 | } 55 | -------------------------------------------------------------------------------- /components/main.css: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 100%; 3 | padding: 40px; 4 | vertical-align: top; 5 | display: inline-block; 6 | box-sizing: border-box; 7 | } 8 | 9 | @media (min-width: 600px) { 10 | :host { 11 | position: absolute; 12 | right: 0; 13 | width: 73%; 14 | padding: 125.9px 8% 70.6px 8%; 15 | vertical-align: top; 16 | display: inline-block; 17 | } 18 | } 19 | 20 | @media (min-width: 900px) { 21 | :host { 22 | width: 77%; 23 | padding: 125.9px 6% 70.6px 6%; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /components/main.js: -------------------------------------------------------------------------------- 1 | var html = require('choo/html') 2 | var css = require('sheetify') 3 | var sidebar = require('./sidebar') 4 | var content = require('./content') 5 | 6 | module.exports = function (state, prev, send) { 7 | var prefix = css('./main.css') 8 | 9 | return html`
10 | ${sidebar(state, prev, send)} 11 |
12 |
13 | ${content(state, prev, send)} 14 |
15 |
16 |
` 17 | } 18 | -------------------------------------------------------------------------------- /components/menu.css: -------------------------------------------------------------------------------- 1 | :host { 2 | 3 | } 4 | 5 | .h2 { 6 | display: block; 7 | font-size: 1.5em; 8 | font-weight: bold; 9 | margin-top: 12px; 10 | margin-bottom: 12px; 11 | } 12 | 13 | .minidocs-menu, .minidocs-menu.menu-closed { 14 | display: none; 15 | z-index: 1000; 16 | } 17 | 18 | .minidocs-menu.menu-open.menu-small { 19 | display: block; 20 | background-color: rgb(240,240,240); 21 | position: fixed; 22 | width: 100%; 23 | top: 0; 24 | height: 100%; 25 | padding: 50px; 26 | margin-bottom: 0px; 27 | box-sizing: border-box; 28 | } 29 | 30 | .minidocs-menu.menu-open.menu-small .minidocs-menu-wrapper { 31 | height: 100%; 32 | overflow-y: auto; 33 | } 34 | 35 | a.content-link { 36 | padding: 6px 8px 6px 5px; 37 | margin-bottom: 1px; 38 | cursor: pointer; 39 | text-decoration: none; 40 | color: #505050; 41 | display: block; 42 | border-left: 3px solid #eee; 43 | } 44 | 45 | a.content-link.active { 46 | background-color: #fff; 47 | border-left: 3px solid rgb(200,200,200); 48 | } 49 | 50 | a.content-link:hover { 51 | background-color: #fff; 52 | border-left: 3px solid rgb(200,200,200); 53 | } 54 | 55 | .minidocs-menu-toggle { 56 | display: block; 57 | position: absolute; 58 | top: 10px; 59 | left: 10px; 60 | border: 0px; 61 | background: transparent; 62 | padding-left: 20px; 63 | line-height: 0.9; 64 | z-index: 2000; 65 | cursor: pointer; 66 | font-size: 16px; 67 | } 68 | 69 | .minidocs-menu-toggle:before { 70 | content: ""; 71 | position: absolute; 72 | left: 0; 73 | top: 0.25em; 74 | width: 1em; 75 | height: 0.15em; 76 | background: black; 77 | box-shadow: 78 | 0 0.25em 0 0 black, 79 | 0 0.5em 0 0 black; 80 | } 81 | 82 | .minidocs-menu-toc { 83 | margin-top:-2px; 84 | background-color: #f8f8f8; 85 | border-left: 3px solid rgb(200,200,200); 86 | } 87 | 88 | .minidocs-menu-toc a.content-link { 89 | border-left:0px; 90 | padding: 4px 0px 4px 10px; 91 | } 92 | 93 | @media (min-width: 600px) { 94 | .minidocs-menu { 95 | display: block; 96 | margin-bottom: 25px; 97 | } 98 | 99 | .minidocs-menu-toggle { 100 | display: none; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /components/menu.js: -------------------------------------------------------------------------------- 1 | var url = require('url') 2 | var css = require('sheetify') 3 | var html = require('choo/html') 4 | 5 | module.exports = function (state, prev, send) { 6 | var contents = state.contents 7 | var prefix = css('./menu.css') 8 | 9 | function createMenu (contents) { 10 | return contents.map(function (item) { 11 | // TODO: figure out a better way to get current page in state based on link click 12 | var current 13 | var location 14 | 15 | if (state.location && state.location.pathname) { 16 | location = url.parse(state.location.pathname) 17 | var sliceBy = state.basedir.length + 1 18 | current = location.pathname.slice(sliceBy) 19 | } 20 | 21 | if (!current || current.length <= 1) { 22 | current = state.current 23 | } 24 | 25 | function onclick (e) { 26 | send('menu:set', { open: false }) 27 | } 28 | 29 | function createTocItem (tocItem) { 30 | if (tocItem.level === 1) return '' // Don't put title 31 | var depth = item.depth + (tocItem.level - 1) 32 | return html`${tocItem.title}` 33 | } 34 | 35 | if (isActive(current, item.key) && item.toc.length > 1) { 36 | return html` 37 |
38 | ${item.name} 39 |
40 | ${item.toc.map(function (tocItem) { 41 | return (tocItem.level === 2) ? createTocItem(tocItem) : '' 42 | })} 43 |
44 |
45 | ` 46 | } 47 | 48 | if (item.link) { 49 | return html`
${item.name}
` 50 | } 51 | 52 | return html`
${item.name}
` 53 | }) 54 | } 55 | 56 | function isActive (current, item) { 57 | return current === item ? 'active' : '' 58 | } 59 | 60 | function isOpen () { 61 | if (typeof window !== 'undefined' && window.innerWidth > 600) return 'menu-open' 62 | return state.menu.open ? 'menu-open' : 'menu-closed' 63 | } 64 | 65 | function onclick (e) { 66 | send('menu:set', { open: !state.menu.open }) 67 | } 68 | 69 | return html`
70 | 71 | 76 |
` 77 | } 78 | -------------------------------------------------------------------------------- /components/sidebar.css: -------------------------------------------------------------------------------- 1 | :host { 2 | width: 100%; 3 | } 4 | 5 | .minidocs-logo { 6 | width: 100%; 7 | } 8 | 9 | .minidocs-header { 10 | width: 40%; 11 | max-width: 250px; 12 | margin: 0px auto; 13 | } 14 | 15 | .h1 { 16 | display: block; 17 | font-size: 2em; 18 | font-weight: bold; 19 | margin-top: 16px; 20 | margin-bottom: 16px; 21 | } 22 | 23 | .h1:before { 24 | content: '# ' 25 | } 26 | 27 | h1 a { 28 | color: #505050; 29 | text-decoration: none; 30 | } 31 | 32 | h1 a:hover { 33 | color: #222; 34 | } 35 | 36 | @media (min-width: 600px) { 37 | :host { 38 | width: 21%; 39 | padding: 0px 20px 20px 35px; 40 | display: inline-block; 41 | padding-bottom: 3%; 42 | overflow-y: scroll; 43 | background: rgb(240,240,240); 44 | height: 100%; 45 | position: fixed; 46 | top: 0; 47 | bottom: 0; 48 | } 49 | 50 | .minidocs-header { 51 | width: 100%; 52 | max-width: 250px; 53 | margin: 0px auto; 54 | } 55 | 56 | .minidocs-logo { 57 | width: 100%; 58 | max-width: 250px; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /components/sidebar.js: -------------------------------------------------------------------------------- 1 | var css = require('sheetify') 2 | var html = require('choo/html') 3 | 4 | var menu = require('./menu') 5 | 6 | module.exports = function (state, prev, send) { 7 | var prefix = css('./sidebar.css') 8 | 9 | function createHeader () { 10 | if (state.logo) { 11 | return html` 12 | 13 | ` 14 | } 15 | return state.title 16 | } 17 | 18 | return html`
19 |
20 |

${createHeader()}

21 |
22 | ${menu(state, prev, send)} 23 |
` 24 | } 25 | -------------------------------------------------------------------------------- /examples/browser/200.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/browser/contents.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'overview': { 3 | 'about': { 4 | file: 'about.md', 5 | link: 'http://github.com/freeman-lab/minidocs', 6 | contributors: ['@sethvincent', '@yoshuawuyts', '@freeman-lab', '@fraserxu'] 7 | } 8 | }, 9 | 'animals': { 10 | 'furry': { 11 | 'sheep': 'sheep.md', 12 | 'puppy': 'puppy.md' 13 | }, 14 | 'pink': { 15 | 'pig': 'pig.md' 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/browser/index.js: -------------------------------------------------------------------------------- 1 | var minidocs = require('minidocs') 2 | 3 | var app = minidocs({ 4 | contents: './contents.js', 5 | markdown: './markdown', 6 | logo: './logo.svg' 7 | }) 8 | 9 | var tree = app.start() 10 | document.body.appendChild(tree) 11 | -------------------------------------------------------------------------------- /examples/browser/markdown/about.md: -------------------------------------------------------------------------------- 1 | # about 2 | 3 | Hello! This is an introduction to an example site built with [`minidocs`](https://github.com/freeman-lab/minidocs). 4 | 5 | ## doing the how it works thing 6 | 7 | ### how it works 8 | 9 | Just make a folder of markdown files, and specify an object describing the table of contents 10 | 11 | ```javascript 12 | var contents = { 13 | 'overview': { 14 | 'about': 'about.md' 15 | }, 16 | 'animals': { 17 | 'furry': { 18 | 'sheep': 'sheep.md', 19 | 'puppy': 'puppy.md' 20 | }, 21 | 'pink': { 22 | 'pig': 'pig.md' 23 | } 24 | } 25 | } 26 | ``` 27 | 28 | Then build the site with `require('minidocs')(contents, {logo: 'logo.svg'})` 29 | 30 |

Have fun with minidocs!

31 | -------------------------------------------------------------------------------- /examples/browser/markdown/pig.md: -------------------------------------------------------------------------------- 1 | # pig 2 | 3 | i am a pig, i say oink! 4 | 5 | test 6 | 7 | test 8 | 9 | test 10 | 11 | test 12 | test 13 | 14 | test 15 | test 16 | 17 | test 18 | test 19 | 20 | test 21 | test 22 | 23 | test 24 | test 25 | 26 | test 27 | test 28 | 29 | test 30 | test 31 | 32 | test 33 | test 34 | 35 | test 36 | test 37 | 38 | test 39 | test 40 | 41 | test 42 | test 43 | 44 | test 45 | test 46 | 47 | test 48 | test 49 | 50 | test 51 | test 52 | 53 | test 54 | test 55 | 56 | ## pigs like pizza 57 | 58 | test 59 | test 60 | 61 | test 62 | test 63 | 64 | test 65 | test 66 | 67 | test 68 | test 69 | 70 | test 71 | 72 | [about minidocs](/about) 73 | -------------------------------------------------------------------------------- /examples/browser/markdown/puppy.md: -------------------------------------------------------------------------------- 1 | # puppy 2 | 3 | i am a puppy, i say woof! -------------------------------------------------------------------------------- /examples/browser/markdown/sheep.md: -------------------------------------------------------------------------------- 1 | # sheep 2 | 3 | i am a sheep, i say bahhhhhh! -------------------------------------------------------------------------------- /examples/browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minidocs-example", 3 | "version": "0.0.0", 4 | "description": "example for minidocs", 5 | "main": "index.js", 6 | "scripts": { 7 | "bundle": "browserify index.js -o bundle.js", 8 | "start": "budo index.js:bundle.js --pushstate" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/freeman-lab/minidocs.git" 13 | }, 14 | "keywords": [ 15 | "minidocs", 16 | "example", 17 | "documentation" 18 | ], 19 | "browserify": { 20 | "transform": [ 21 | "minidocs/transform" 22 | ] 23 | }, 24 | "author": "freeman-lab", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/freeman-lab/minidocs/issues" 28 | }, 29 | "homepage": "https://github.com/freeman-lab/minidocs#readme", 30 | "dependencies": {}, 31 | "devDependencies": { 32 | "browserify": "^13.1.0", 33 | "budo": "^8.1.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/cli-full-html/contents.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | overview: { 3 | about: { 4 | file: 'about.md', 5 | link: 'http://github.com/freeman-lab/minidocs' 6 | } 7 | }, 8 | examples: { 9 | pizza: 'pizza.md' 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/cli-full-html/docs/about.md: -------------------------------------------------------------------------------- 1 | # about 2 | 3 | this is the about page -------------------------------------------------------------------------------- /examples/cli-full-html/docs/pizza.md: -------------------------------------------------------------------------------- 1 | # pizza 2 | 3 | this is the pizza page 4 | -------------------------------------------------------------------------------- /examples/cli-full-html/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minidocs-example-cli", 3 | "version": "0.0.0", 4 | "description": "example for minidocs", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm link minidocs && minidocs docs -c contents.js --css style.css --full-html -o site", 8 | "start": "npm run build && budo --dir site --pushstate" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/freeman-lab/minidocs.git" 13 | }, 14 | "keywords": [ 15 | "minidocs", 16 | "example", 17 | "documentation" 18 | ], 19 | "browserify": {}, 20 | "author": "freeman-lab", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/freeman-lab/minidocs/issues" 24 | }, 25 | "homepage": "https://github.com/freeman-lab/minidocs#readme", 26 | "dependencies": {}, 27 | "devDependencies": { 28 | "budo": "^8.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/cli-full-html/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /examples/cli-images/assets/baby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeman-lab/minidocs/44a9929c27595a6bea83dddec6f2ca45287bac70/examples/cli-images/assets/baby.jpg -------------------------------------------------------------------------------- /examples/cli-images/assets/doodie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeman-lab/minidocs/44a9929c27595a6bea83dddec6f2ca45287bac70/examples/cli-images/assets/doodie.jpg -------------------------------------------------------------------------------- /examples/cli-images/assets/storycat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeman-lab/minidocs/44a9929c27595a6bea83dddec6f2ca45287bac70/examples/cli-images/assets/storycat.jpg -------------------------------------------------------------------------------- /examples/cli-images/assets/trouble.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeman-lab/minidocs/44a9929c27595a6bea83dddec6f2ca45287bac70/examples/cli-images/assets/trouble.jpg -------------------------------------------------------------------------------- /examples/cli-images/assets/wizard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeman-lab/minidocs/44a9929c27595a6bea83dddec6f2ca45287bac70/examples/cli-images/assets/wizard.jpg -------------------------------------------------------------------------------- /examples/cli-images/contents.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | overview: { 3 | about: { 4 | file: 'about.md', 5 | link: 'http://github.com/freeman-lab/minidocs' 6 | } 7 | }, 8 | examples: { 9 | pizza: 'pizza.md' 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/cli-images/docs/about.md: -------------------------------------------------------------------------------- 1 | # about 2 | 3 | here's some cats that's the about have a nice time. 4 | 5 | ![baby](/assets/baby.jpg) 6 | 7 | ![doodie](/assets/doodie.jpg) 8 | 9 | ![storycat](/assets/storycat.jpg) 10 | 11 | ![trouble](/assets/trouble.jpg) 12 | 13 | ![wizard](/assets/wizard.jpg) 14 | -------------------------------------------------------------------------------- /examples/cli-images/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minidocs-example-cli", 3 | "version": "0.0.0", 4 | "description": "example for minidocs", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm link minidocs && minidocs docs -c contents.js --assets assets -o site", 8 | "start": "npm run build && budo --dir site --pushstate" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/freeman-lab/minidocs.git" 13 | }, 14 | "keywords": [ 15 | "minidocs", 16 | "example", 17 | "documentation" 18 | ], 19 | "browserify": {}, 20 | "author": "freeman-lab", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/freeman-lab/minidocs/issues" 24 | }, 25 | "homepage": "https://github.com/freeman-lab/minidocs#readme", 26 | "dependencies": {}, 27 | "devDependencies": { 28 | "budo": "^8.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/cli/contents.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | overview: { 3 | about: { 4 | file: 'about.md', 5 | link: 'http://github.com/freeman-lab/minidocs' 6 | } 7 | }, 8 | examples: { 9 | pizza: 'pizza.md' 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/cli/docs/about.md: -------------------------------------------------------------------------------- 1 | # about 2 | 3 | this is the about page -------------------------------------------------------------------------------- /examples/cli/docs/pizza.md: -------------------------------------------------------------------------------- 1 | # pizza 2 | 3 | this is the pizza page 4 | -------------------------------------------------------------------------------- /examples/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minidocs-example-cli", 3 | "version": "0.0.0", 4 | "description": "example for minidocs", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm link minidocs && minidocs docs -c contents.js --css style.css -o site", 8 | "start": "npm run build && budo --dir site --pushstate" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/freeman-lab/minidocs.git" 13 | }, 14 | "keywords": [ 15 | "minidocs", 16 | "example", 17 | "documentation" 18 | ], 19 | "browserify": {}, 20 | "author": "freeman-lab", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/freeman-lab/minidocs/issues" 24 | }, 25 | "homepage": "https://github.com/freeman-lab/minidocs#readme", 26 | "dependencies": {}, 27 | "devDependencies": { 28 | "budo": "^8.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/cli/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var css = require('sheetify') 2 | var insertCSS = require('insert-css') 3 | var minidocs = require('./app') 4 | 5 | module.exports = function (opts, callback) { 6 | var app = minidocs(opts) 7 | 8 | css('./styles/base.css', { global: true }) 9 | css('./styles/fonts.css', { global: true }) 10 | css('./styles/github-markdown.css', { global: true }) 11 | css('./styles/highlighting/tomorrow.css', { global: true }) 12 | 13 | return { 14 | app: app, 15 | start: function (id, opts) { 16 | if (typeof id === 'object') { 17 | opts = id 18 | id = null 19 | } 20 | if (!opts) opts = {} 21 | opts.href = opts.href || false 22 | return app.start(id, opts) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/create-assets.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var assert = require('assert') 4 | var tar = require('tar-fs') 5 | 6 | module.exports = function createAssets (app, options, callback) { 7 | assert.ok(options) 8 | assert.ok(options.argv) 9 | assert.ok(options.outputDir) 10 | 11 | var argv = options.argv 12 | var state = options.state 13 | var outputDir = options.outputDir 14 | var logoSource = state.logoSource 15 | var assets = argv.assets || '' 16 | var assetsPath = path.parse(assets) 17 | 18 | function copyLogo (fn) { 19 | var stream = fs.createReadStream(state.logoSource) 20 | var logopath = path.join(outputDir, state.logo) 21 | var writelogo = fs.createWriteStream(logopath) 22 | stream.pipe(writelogo) 23 | stream.on('end', fn) 24 | } 25 | 26 | function copyAssets (fn) { 27 | var pack = tar.pack(assets) 28 | var extract = tar.extract(path.join(outputDir, assetsPath.name)) 29 | pack.pipe(extract).on('finish', fn) 30 | } 31 | 32 | if (logoSource && assets) { 33 | copyLogo(function () { 34 | copyAssets(callback) 35 | }) 36 | } else if (logoSource) { 37 | copyLogo(callback) 38 | } else if (assets) { 39 | copyAssets(callback) 40 | } else { 41 | callback() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/create-css.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var assert = require('assert') 4 | 5 | module.exports = function createCSS (app, options, callback) { 6 | assert.ok(options) 7 | assert.ok(options.argv) 8 | assert.ok(options.outputDir) 9 | 10 | var argv = options.argv 11 | var state = options.state 12 | var outputDir = options.outputDir 13 | var customStylePath = argv.css ? path.join(state.dir, argv.css) : null 14 | 15 | if (argv.css) { 16 | var customStylePath = path.join(state.dir, argv.css) 17 | fs.createReadStream(customStylePath) 18 | .pipe(fs.createWriteStream(path.join(outputDir, 'style.css'))) 19 | .on('close', callback) 20 | } else { 21 | callback() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/create-html.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var assert = require('assert') 4 | var createHTML = require('create-html') 5 | var each = require('each-async') 6 | 7 | module.exports = function (app, options, callback) { 8 | assert.ok(options) 9 | assert.ok(options.argv) 10 | assert.ok(options.state) 11 | assert.ok(options.outputDir) 12 | 13 | var argv = options.argv 14 | var state = options.state 15 | var outputDir = options.outputDir 16 | 17 | assert.ok(state.title) 18 | assert.ok(state.routes) 19 | 20 | function createFile (route, filepath, callback) { 21 | var page = app.toString(state.basedir + route, state) 22 | 23 | var opts = { 24 | title: state.title, 25 | head: '', 26 | body: page, 27 | script: argv.basedir + '/bundle.js', 28 | css: argv.basedir + '/bundle.css' 29 | } 30 | 31 | if (argv.css) opts.head += `\n` 32 | var html = createHTML(opts) 33 | fs.writeFile(filepath, html, callback) 34 | } 35 | 36 | if (argv['full-html']) { 37 | each(Object.keys(state.routes), function (key, i, next) { 38 | var route = state.routes[key] 39 | var filepath = path.join(outputDir, key + '.html') 40 | state.current = key === 'index' ? state.initial : key 41 | createFile(route, filepath, next) 42 | }, callback) 43 | } else { 44 | var filepath = path.join(outputDir, 'index.html') 45 | state.current = state.initial 46 | createFile('/', filepath, callback) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/create-js.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var assert = require('assert') 4 | var browserify = require('browserify') 5 | 6 | module.exports = function buildJS (app, options, callback) { 7 | assert.ok(options) 8 | assert.ok(options.argv) 9 | assert.ok(options.state) 10 | assert.ok(options.outputDir) 11 | 12 | var argv = options.argv 13 | var state = options.state 14 | var outputDir = options.outputDir 15 | var indexpath = path.join(outputDir, 'index.js') 16 | 17 | var js = ` 18 | var minidocs = require('minidocs') 19 | var app = minidocs(${JSON.stringify(state)}) 20 | app.start('#choo-root') 21 | ` 22 | 23 | fs.writeFile(indexpath, js, function (err) { 24 | if (err) return callback(err) 25 | browserify(indexpath, { paths: [path.join(__dirname, '..', 'node_modules')] }) 26 | .plugin(require('css-extract'), { out: path.join(outputDir, 'bundle.css') }) 27 | .bundle(function (err, src) { 28 | if (err) return callback(err) 29 | var bundlepath = path.join(outputDir, 'bundle.js') 30 | fs.writeFile(bundlepath, src, function (err) { 31 | if (err) return callback(err) 32 | fs.unlink(indexpath, callback) 33 | }) 34 | }) 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /lib/create-output-dir.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var mkdir = require('mkdirp') 3 | var rm = require('rimraf') 4 | 5 | module.exports = function createOutputDir (app, options, callback) { 6 | assert.ok(options) 7 | assert.ok(options.outputDir) 8 | 9 | rm(options.outputDir, function (err) { 10 | if (err) return callback(err) 11 | mkdir(options.outputDir, callback) 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /lib/create-pushstate-file.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var assert = require('assert') 4 | var createHTML = require('create-html') 5 | 6 | module.exports = function createPushstateFile (app, options, callback) { 7 | assert.ok(options) 8 | assert.ok(options.state) 9 | assert.ok(options.outputDir) 10 | 11 | var state = options.state 12 | var outputDir = options.outputDir 13 | 14 | assert.ok(state.title) 15 | assert.ok(state.routes) 16 | 17 | var page = app.toString(state.basedir + '/', state) 18 | var pushstatefile = path.join(outputDir, '200.html') 19 | 20 | var html = createHTML({ 21 | title: state.title, 22 | body: page, 23 | script: state.basedir + '/bundle.js', 24 | css: state.basedir + '/bundle.css' 25 | }) 26 | 27 | fs.writeFile(pushstatefile, html, callback) 28 | } 29 | -------------------------------------------------------------------------------- /lib/parse-contents.js: -------------------------------------------------------------------------------- 1 | var parsePath = require('parse-filepath') 2 | var isobject = require('lodash.isobject') 3 | var isarray = require('lodash.isarray') 4 | var map = require('lodash.map') 5 | 6 | module.exports = function parseContents (options) { 7 | var contents = options.contents 8 | options.basedir = options.basedir || '' 9 | var depth = 0 10 | var menu = [] 11 | 12 | function iterate (contents, depth) { 13 | return map(contents, function (value, key, obj) { 14 | return level(contents, key, value, depth + 1) 15 | })[0] 16 | } 17 | 18 | function level (contents, key, value, depth) { 19 | var obj = { depth: depth, name: key } 20 | 21 | if (isobject(value) && value.link) { 22 | obj.source = value.link 23 | } 24 | 25 | if (isobject(value) && value.contributors) { 26 | obj.contributors = isarray(value.contributors) ? value.contributors : [value.contributors] 27 | } 28 | 29 | if (isobject(value) && !value.file) { 30 | menu.push(obj) 31 | iterate(value, depth) 32 | } else { 33 | if (isobject(value)) { 34 | obj.source = value.link 35 | if (value.contributors) { 36 | obj.contributors = value.contributors && isarray(value.contributors) ? value.contributors : [value.contributors] 37 | } 38 | value = value.file 39 | } 40 | var parsed = parsePath(value) 41 | obj.key = parsed.name 42 | obj.link = options.basedir + '/' + obj.key 43 | menu.push(obj) 44 | } 45 | return menu 46 | } 47 | 48 | return iterate(contents, depth) 49 | } 50 | -------------------------------------------------------------------------------- /lib/parse-docs.js: -------------------------------------------------------------------------------- 1 | var parseContents = require('./parse-contents') 2 | var parseMarkdown = require('./parse-markdown') 3 | 4 | module.exports = function (options) { 5 | if (!options || !options.contents || !options.markdown) { 6 | throw new Error('options object with contents and markdown properties is required') 7 | } 8 | 9 | var initial = options.initial 10 | var markdown = options.markdown 11 | var contents = parseContents(options) 12 | var html = {} 13 | 14 | var routes = { index: '/' } 15 | contents.forEach(function (item) { 16 | if (item.key) { 17 | if (!initial) initial = item.key 18 | routes[item.key] = `/${item.key}/` 19 | var parsed = parseMarkdown(markdown[item.key]) 20 | html[item.key] = parsed.html 21 | item.toc = parsed.toc 22 | } 23 | }) 24 | 25 | return { 26 | initial: initial, 27 | contents: contents, 28 | routes: routes, 29 | html: html 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/parse-markdown.js: -------------------------------------------------------------------------------- 1 | var marked = require('marked') 2 | var hl = require('highlight.js') 3 | var slugify = require('slug') 4 | var renderer = new marked.Renderer() 5 | 6 | var toc = [] 7 | 8 | renderer.heading = function(text, level, raw) { 9 | var slug = slugify(raw, {lower: true}) 10 | toc.push({ 11 | level: level, 12 | slug: slug, 13 | title: raw 14 | }) 15 | return "" + text + "" 16 | } 17 | 18 | marked.setOptions({ 19 | renderer: renderer, 20 | highlight: function (code, lang) { 21 | try { 22 | return highlight(code, lang) 23 | } catch (e) { 24 | console.error(e) 25 | } 26 | } 27 | }) 28 | 29 | function highlight (code, lang) { 30 | var out = lang ? hl.highlight(lang, code) : hl.highlightAuto(code) 31 | return out.value 32 | } 33 | 34 | module.exports = function parseMarkdown (markdown) { 35 | if (!markdown) return {html: '', toc: []} 36 | toc = [] 37 | return { 38 | html: marked(markdown), 39 | toc: toc 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/parse-options.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var xtend = require('xtend') 3 | var read = require('read-directory') 4 | var parseDocs = require('./parse-docs') 5 | 6 | module.exports = function (options) { 7 | options.dir = options.dir || process.cwd() 8 | 9 | if (typeof options.contents === 'object' && options.html && typeof options.html === 'object' && options.routes) { 10 | return options 11 | } 12 | 13 | var contentsPath = path.resolve(options.dir, options.contents) 14 | var markdownPath = path.resolve(options.dir, options.markdown) 15 | var contents = require(contentsPath) 16 | var markdown = read.sync(markdownPath, { extensions: false, filter: '**/*.md' }) 17 | 18 | var docs = parseDocs(xtend(options, { 19 | markdown: markdown, 20 | contents: contents 21 | })) 22 | 23 | return xtend(options, docs) 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minidocs", 3 | "version": "4.2.3", 4 | "description": "build a simple site for your documentation", 5 | "main": "index.js", 6 | "style": "components/styles/index.css", 7 | "scripts": { 8 | "link:minidocs": "npm link && npm link minidocs", 9 | "start": "npm run link:minidocs && budo --dir examples/browser/ examples/browser/index.js:bundle.js --pushstate --live", 10 | "lint": "standard", 11 | "test": "npm run link:minidocs && tape tests/*.js | tap-spec", 12 | "build:example": "cd example && browserify index.js -p yo-yoify -o bundle.js", 13 | "deploy:example": "surge example minidocs-example.surge.sh", 14 | "build": "browserify docs/index.js -p yo-yoify -o docs/bundle.js", 15 | "deploy": "npm run build && surge site minidocs.surge.sh" 16 | }, 17 | "bin": { 18 | "minidocs": "bin/index.js" 19 | }, 20 | "browserify": { 21 | "transform": [ 22 | "./transform.js", 23 | "sheetify/transform" 24 | ] 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/freeman-lab/minidocs.git" 29 | }, 30 | "keywords": [ 31 | "docs", 32 | "documentation", 33 | "site", 34 | "build", 35 | "component" 36 | ], 37 | "author": "freeman-lab", 38 | "license": "MIT", 39 | "bugs": { 40 | "url": "https://github.com/freeman-lab/minidocs/issues" 41 | }, 42 | "homepage": "https://github.com/freeman-lab/minidocs#readme", 43 | "dependencies": { 44 | "async.applyeachseries": "^0.5.2", 45 | "browserify": "^13.0.1", 46 | "choo": "^3.0.1", 47 | "create-html": "^1.0.0", 48 | "css-extract": "^1.1.0", 49 | "debug": "^2.2.0", 50 | "each-async": "^1.1.1", 51 | "execspawn": "^1.0.1", 52 | "exit": "^0.1.2", 53 | "github-avatar-url": "^1.0.0", 54 | "highlight.js": "^9.2.0", 55 | "insert-css": "^1.0.0", 56 | "is-absolute": "^0.2.5", 57 | "lodash.isarray": "^4.0.0", 58 | "lodash.isobject": "^3.0.2", 59 | "lodash.map": "^4.4.0", 60 | "marked": "^0.3.5", 61 | "minimist": "^1.2.0", 62 | "mkdirp": "^0.5.1", 63 | "parse-filepath": "^1.0.1", 64 | "read-directory": "^1.2.0", 65 | "rimraf": "^2.5.2", 66 | "sheetify": "^5.0.2", 67 | "sheetify-cssnext": "^1.0.7", 68 | "slug": "^0.9.1", 69 | "static-module": "^1.3.1", 70 | "tar": "^2.2.1", 71 | "tar-fs": "^1.13.2", 72 | "through2": "^2.0.1", 73 | "xtend": "^4.0.1", 74 | "yo-yoify": "^2.0.1" 75 | }, 76 | "devDependencies": { 77 | "budo": "^8.1.0", 78 | "debug": "^2.2.0", 79 | "standard": "^6.0.8", 80 | "tap-spec": "^4.1.1", 81 | "tape": "^4.6.0", 82 | "tape-run": "^2.1.4" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /parse.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/parse-options') 2 | -------------------------------------------------------------------------------- /styles/base.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'clear_sans_thinregular'; 3 | color: rgb(80,80,80); 4 | margin: 0px; 5 | padding: 0px; 6 | overflow-y: scroll; 7 | } 8 | 9 | .contents-link { 10 | padding-left: 2%; 11 | cursor: pointer; 12 | padding-bottom: 2px; 13 | padding-right: 10px; 14 | } 15 | 16 | .contents-link:hover { 17 | background: rgb(255,255,255); 18 | } 19 | 20 | .contents-link-selected { 21 | background: rgb(255,255,255); 22 | } 23 | 24 | ::-webkit-scrollbar { 25 | width: 10px; 26 | } 27 | 28 | ::-webkit-scrollbar-track { 29 | background-color: white; 30 | } 31 | 32 | ::-webkit-scrollbar-thumb { 33 | background-color: rgba(0, 0, 0, 0.125); 34 | height: 20px; 35 | } 36 | 37 | ::-webkit-scrollbar-thumb:hover { 38 | background-color: rgba(0, 0, 0, 0.25); 39 | } 40 | 41 | ::-webkit-scrollbar-button { 42 | background-color: rgb(200,200,200); 43 | } 44 | 45 | ::-webkit-scrollbar-corner { 46 | background-color: black; 47 | } 48 | -------------------------------------------------------------------------------- /styles/github-markdown.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: octicons-link; 3 | src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff'); 4 | } 5 | 6 | .markdown-body { 7 | -webkit-text-size-adjust: 100%; 8 | text-size-adjust: 100%; 9 | color: rgb(80,80,80); 10 | font-size: 16px; 11 | line-height: 1.6; 12 | word-wrap: break-word; 13 | } 14 | 15 | .markdown-body a { 16 | background-color: transparent; 17 | } 18 | 19 | .markdown-body a:active, 20 | .markdown-body a:hover { 21 | outline: 0; 22 | } 23 | 24 | .markdown-body strong { 25 | font-weight: bold; 26 | } 27 | 28 | .markdown-body h1 { 29 | font-size: 2em; 30 | margin: 0.67em 0; 31 | } 32 | 33 | .markdown-body img { 34 | border: 0; 35 | } 36 | 37 | .markdown-body hr { 38 | box-sizing: content-box; 39 | height: 0; 40 | } 41 | 42 | .markdown-body pre { 43 | overflow: auto; 44 | } 45 | 46 | .markdown-body code, 47 | .markdown-body kbd, 48 | .markdown-body pre { 49 | font-family: monospace, monospace; 50 | font-size: 1em; 51 | } 52 | 53 | .markdown-body input { 54 | color: inherit; 55 | font: inherit; 56 | margin: 0; 57 | } 58 | 59 | .markdown-body html input[disabled] { 60 | cursor: default; 61 | } 62 | 63 | .markdown-body input { 64 | line-height: normal; 65 | } 66 | 67 | .markdown-body input[type="checkbox"] { 68 | box-sizing: border-box; 69 | padding: 0; 70 | } 71 | 72 | .markdown-body table { 73 | border-collapse: collapse; 74 | border-spacing: 0; 75 | } 76 | 77 | .markdown-body td, 78 | .markdown-body th { 79 | padding: 0; 80 | } 81 | 82 | .markdown-body * { 83 | box-sizing: border-box; 84 | } 85 | 86 | .markdown-body input { 87 | font: 13px / 1.4 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 88 | } 89 | 90 | .markdown-body a { 91 | color: #4078c0; 92 | text-decoration: none; 93 | } 94 | 95 | .markdown-body a:hover, 96 | .markdown-body a:active { 97 | text-decoration: underline; 98 | } 99 | 100 | .markdown-body hr { 101 | height: 0; 102 | margin: 15px 0; 103 | overflow: hidden; 104 | background: transparent; 105 | border: 0; 106 | border-bottom: 1px solid #ddd; 107 | } 108 | 109 | .markdown-body hr:before { 110 | display: table; 111 | content: ""; 112 | } 113 | 114 | .markdown-body hr:after { 115 | display: table; 116 | clear: both; 117 | content: ""; 118 | } 119 | 120 | .markdown-body h1, 121 | .markdown-body h2, 122 | .markdown-body h3, 123 | .markdown-body h4, 124 | .markdown-body h5, 125 | .markdown-body h6 { 126 | margin-top: 15px; 127 | line-height: 1.1; 128 | } 129 | 130 | .markdown-body h1 { 131 | font-size: 30px; 132 | } 133 | 134 | .markdown-body h2 { 135 | font-size: 21px; 136 | } 137 | 138 | .markdown-body h3 { 139 | font-size: 16px; 140 | } 141 | 142 | .markdown-body h4 { 143 | font-size: 14px; 144 | } 145 | 146 | .markdown-body h5 { 147 | font-size: 12px; 148 | } 149 | 150 | .markdown-body h6 { 151 | font-size: 11px; 152 | } 153 | 154 | .markdown-body blockquote { 155 | margin: 0; 156 | } 157 | 158 | .markdown-body ul, 159 | .markdown-body ol { 160 | padding: 0; 161 | margin-top: 0; 162 | margin-bottom: 0; 163 | } 164 | 165 | .markdown-body ol ol, 166 | .markdown-body ul ol { 167 | list-style-type: lower-roman; 168 | } 169 | 170 | .markdown-body ul ul ol, 171 | .markdown-body ul ol ol, 172 | .markdown-body ol ul ol, 173 | .markdown-body ol ol ol { 174 | list-style-type: lower-alpha; 175 | } 176 | 177 | .markdown-body dd { 178 | margin-left: 0; 179 | } 180 | 181 | .markdown-body code { 182 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 183 | font-size: 12px; 184 | } 185 | 186 | .markdown-body pre { 187 | margin-top: 0; 188 | margin-bottom: 0; 189 | font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace; 190 | } 191 | 192 | .markdown-body .select::-ms-expand { 193 | opacity: 0; 194 | } 195 | 196 | .markdown-body .octicon { 197 | font: normal normal normal 16px/1 octicons-link; 198 | display: inline-block; 199 | text-decoration: none; 200 | text-rendering: auto; 201 | -webkit-font-smoothing: antialiased; 202 | -moz-osx-font-smoothing: grayscale; 203 | -webkit-user-select: none; 204 | -moz-user-select: none; 205 | -ms-user-select: none; 206 | user-select: none; 207 | } 208 | 209 | .markdown-body .octicon-link:before { 210 | content: '\f05c'; 211 | } 212 | 213 | .markdown-body:before { 214 | display: table; 215 | content: ""; 216 | } 217 | 218 | .markdown-body:after { 219 | display: table; 220 | clear: both; 221 | content: ""; 222 | } 223 | 224 | .markdown-body>*:first-child { 225 | margin-top: 0 !important; 226 | } 227 | 228 | .markdown-body>*:last-child { 229 | margin-bottom: 0 !important; 230 | } 231 | 232 | .markdown-body a:not([href]) { 233 | color: inherit; 234 | text-decoration: none; 235 | } 236 | 237 | .markdown-body .anchor { 238 | display: inline-block; 239 | padding-right: 2px; 240 | margin-left: -18px; 241 | } 242 | 243 | .markdown-body .anchor:focus { 244 | outline: none; 245 | } 246 | 247 | .markdown-body h1, 248 | .markdown-body h2, 249 | .markdown-body h3, 250 | .markdown-body h4, 251 | .markdown-body h5, 252 | .markdown-body h6 { 253 | margin-top: 1em; 254 | margin-bottom: 16px; 255 | font-weight: bold; 256 | line-height: 1.4; 257 | } 258 | 259 | .markdown-body h1 .octicon-link, 260 | .markdown-body h2 .octicon-link, 261 | .markdown-body h3 .octicon-link, 262 | .markdown-body h4 .octicon-link, 263 | .markdown-body h5 .octicon-link, 264 | .markdown-body h6 .octicon-link { 265 | color: #000; 266 | vertical-align: middle; 267 | visibility: hidden; 268 | } 269 | 270 | .markdown-body h1:hover .anchor, 271 | .markdown-body h2:hover .anchor, 272 | .markdown-body h3:hover .anchor, 273 | .markdown-body h4:hover .anchor, 274 | .markdown-body h5:hover .anchor, 275 | .markdown-body h6:hover .anchor { 276 | text-decoration: none; 277 | } 278 | 279 | .markdown-body h1:hover .anchor .octicon-link, 280 | .markdown-body h2:hover .anchor .octicon-link, 281 | .markdown-body h3:hover .anchor .octicon-link, 282 | .markdown-body h4:hover .anchor .octicon-link, 283 | .markdown-body h5:hover .anchor .octicon-link, 284 | .markdown-body h6:hover .anchor .octicon-link { 285 | visibility: visible; 286 | } 287 | 288 | .markdown-body h1 { 289 | padding-bottom: 0.3em; 290 | font-size: 2.25em; 291 | line-height: 1.2; 292 | margin-top: 15px; 293 | } 294 | 295 | .markdown-body h1 .anchor { 296 | line-height: 1; 297 | } 298 | 299 | .markdown-body h2 { 300 | padding-bottom: 0.3em; 301 | font-size: 1.75em; 302 | line-height: 1.225; 303 | } 304 | 305 | .markdown-body h2 .anchor { 306 | line-height: 1; 307 | } 308 | 309 | .markdown-body h3 { 310 | font-size: 1.5em; 311 | line-height: 1.43; 312 | } 313 | 314 | .markdown-body h3 .anchor { 315 | line-height: 1.2; 316 | } 317 | 318 | .markdown-body h4 { 319 | font-size: 1.25em; 320 | } 321 | 322 | .markdown-body h4 .anchor { 323 | line-height: 1.2; 324 | } 325 | 326 | .markdown-body h5 { 327 | font-size: 1em; 328 | } 329 | 330 | .markdown-body h5 .anchor { 331 | line-height: 1.1; 332 | } 333 | 334 | .markdown-body h6 { 335 | font-size: 1em; 336 | color: #777; 337 | } 338 | 339 | .markdown-body h6 .anchor { 340 | line-height: 1.1; 341 | } 342 | 343 | .markdown-body p, 344 | .markdown-body blockquote, 345 | .markdown-body ul, 346 | .markdown-body ol, 347 | .markdown-body dl, 348 | .markdown-body table, 349 | .markdown-body pre { 350 | margin-top: 0; 351 | margin-bottom: 16px; 352 | } 353 | 354 | .markdown-body hr { 355 | height: 4px; 356 | padding: 0; 357 | margin: 16px 0; 358 | background-color: #e7e7e7; 359 | border: 0 none; 360 | } 361 | 362 | .markdown-body ul, 363 | .markdown-body ol { 364 | padding-left: 2em; 365 | } 366 | 367 | .markdown-body ul ul, 368 | .markdown-body ul ol, 369 | .markdown-body ol ol, 370 | .markdown-body ol ul { 371 | margin-top: 0; 372 | margin-bottom: 0; 373 | } 374 | 375 | .markdown-body li>p { 376 | margin-top: 16px; 377 | } 378 | 379 | .markdown-body dl { 380 | padding: 0; 381 | } 382 | 383 | .markdown-body dl dt { 384 | padding: 0; 385 | margin-top: 16px; 386 | font-size: 1em; 387 | font-style: italic; 388 | font-weight: bold; 389 | } 390 | 391 | .markdown-body dl dd { 392 | padding: 0 16px; 393 | margin-bottom: 16px; 394 | } 395 | 396 | .markdown-body blockquote { 397 | padding: 0 15px; 398 | color: #777; 399 | border-left: 4px solid #ddd; 400 | } 401 | 402 | .markdown-body blockquote>:first-child { 403 | margin-top: 0; 404 | } 405 | 406 | .markdown-body blockquote>:last-child { 407 | margin-bottom: 0; 408 | } 409 | 410 | .markdown-body table { 411 | display: block; 412 | width: 100%; 413 | overflow: auto; 414 | word-break: normal; 415 | word-break: keep-all; 416 | } 417 | 418 | .markdown-body table th { 419 | font-weight: bold; 420 | } 421 | 422 | .markdown-body table th, 423 | .markdown-body table td { 424 | padding: 6px 13px; 425 | border: 1px solid #ddd; 426 | } 427 | 428 | .markdown-body table tr { 429 | background-color: #fff; 430 | border-top: 1px solid #ccc; 431 | } 432 | 433 | .markdown-body table tr:nth-child(2n) { 434 | background-color: #f8f8f8; 435 | } 436 | 437 | .markdown-body img { 438 | max-width: 100%; 439 | box-sizing: content-box; 440 | background-color: #fff; 441 | } 442 | 443 | .markdown-body code { 444 | padding: 0; 445 | padding-top: 0.2em; 446 | padding-bottom: 0.2em; 447 | margin: 0; 448 | font-size: 85%; 449 | background-color: rgba(0,0,0,0.04); 450 | border-radius: 3px; 451 | } 452 | 453 | .markdown-body code:before, 454 | .markdown-body code:after { 455 | letter-spacing: -0.2em; 456 | content: "\00a0"; 457 | } 458 | 459 | .markdown-body pre>code { 460 | padding: 0; 461 | margin: 0; 462 | font-size: 100%; 463 | word-break: normal; 464 | white-space: pre; 465 | background: transparent; 466 | border: 0; 467 | } 468 | 469 | .markdown-body .highlight { 470 | margin-bottom: 16px; 471 | } 472 | 473 | .markdown-body .highlight pre, 474 | .markdown-body pre { 475 | padding: 16px; 476 | overflow: auto; 477 | font-size: 85%; 478 | line-height: 1.45; 479 | background-color: #f7f7f7; 480 | border-radius: 3px; 481 | } 482 | 483 | .markdown-body .highlight pre { 484 | margin-bottom: 0; 485 | word-break: normal; 486 | } 487 | 488 | .markdown-body pre { 489 | word-wrap: normal; 490 | } 491 | 492 | .markdown-body pre code { 493 | display: inline; 494 | max-width: initial; 495 | padding: 0; 496 | margin: 0; 497 | overflow: initial; 498 | line-height: inherit; 499 | word-wrap: normal; 500 | background-color: transparent; 501 | border: 0; 502 | } 503 | 504 | .markdown-body pre code:before, 505 | .markdown-body pre code:after { 506 | content: normal; 507 | } 508 | 509 | .markdown-body kbd { 510 | display: inline-block; 511 | padding: 3px 5px; 512 | font-size: 11px; 513 | line-height: 10px; 514 | color: #555; 515 | vertical-align: middle; 516 | background-color: #fcfcfc; 517 | border: solid 1px #ccc; 518 | border-bottom-color: #bbb; 519 | border-radius: 3px; 520 | box-shadow: inset 0 -1px 0 #bbb; 521 | } 522 | 523 | .markdown-body .pl-c { 524 | color: #969896; 525 | } 526 | 527 | .markdown-body .pl-c1, 528 | .markdown-body .pl-s .pl-v { 529 | color: #0086b3; 530 | } 531 | 532 | .markdown-body .pl-e, 533 | .markdown-body .pl-en { 534 | color: #795da3; 535 | } 536 | 537 | .markdown-body .pl-s .pl-s1, 538 | .markdown-body .pl-smi { 539 | color: #333; 540 | } 541 | 542 | .markdown-body .pl-ent { 543 | color: #63a35c; 544 | } 545 | 546 | .markdown-body .pl-k { 547 | color: #a71d5d; 548 | } 549 | 550 | .markdown-body .pl-pds, 551 | .markdown-body .pl-s, 552 | .markdown-body .pl-s .pl-pse .pl-s1, 553 | .markdown-body .pl-sr, 554 | .markdown-body .pl-sr .pl-cce, 555 | .markdown-body .pl-sr .pl-sra, 556 | .markdown-body .pl-sr .pl-sre { 557 | color: #183691; 558 | } 559 | 560 | .markdown-body .pl-v { 561 | color: #ed6a43; 562 | } 563 | 564 | .markdown-body .pl-id { 565 | color: #b52a1d; 566 | } 567 | 568 | .markdown-body .pl-ii { 569 | background-color: #b52a1d; 570 | color: #f8f8f8; 571 | } 572 | 573 | .markdown-body .pl-sr .pl-cce { 574 | color: #63a35c; 575 | font-weight: bold; 576 | } 577 | 578 | .markdown-body .pl-ml { 579 | color: #693a17; 580 | } 581 | 582 | .markdown-body .pl-mh, 583 | .markdown-body .pl-mh .pl-en, 584 | .markdown-body .pl-ms { 585 | color: #1d3e81; 586 | font-weight: bold; 587 | } 588 | 589 | .markdown-body .pl-mq { 590 | color: #008080; 591 | } 592 | 593 | .markdown-body .pl-mi { 594 | color: #333; 595 | font-style: italic; 596 | } 597 | 598 | .markdown-body .pl-mb { 599 | color: #333; 600 | font-weight: bold; 601 | } 602 | 603 | .markdown-body .pl-md { 604 | background-color: #ffecec; 605 | color: #bd2c00; 606 | } 607 | 608 | .markdown-body .pl-mi1 { 609 | background-color: #eaffea; 610 | color: #55a532; 611 | } 612 | 613 | .markdown-body .pl-mdr { 614 | color: #795da3; 615 | font-weight: bold; 616 | } 617 | 618 | .markdown-body .pl-mo { 619 | color: #1d3e81; 620 | } 621 | 622 | .markdown-body kbd { 623 | display: inline-block; 624 | padding: 3px 5px; 625 | font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; 626 | line-height: 10px; 627 | color: #555; 628 | vertical-align: middle; 629 | background-color: #fcfcfc; 630 | border: solid 1px #ccc; 631 | border-bottom-color: #bbb; 632 | border-radius: 3px; 633 | box-shadow: inset 0 -1px 0 #bbb; 634 | } 635 | 636 | .markdown-body .task-list-item { 637 | list-style-type: none; 638 | } 639 | 640 | .markdown-body .task-list-item+.task-list-item { 641 | margin-top: 3px; 642 | } 643 | 644 | .markdown-body .task-list-item input { 645 | margin: 0 0.35em 0.25em -1.6em; 646 | vertical-align: middle; 647 | } 648 | 649 | .markdown-body :checked+.radio-label { 650 | z-index: 1; 651 | position: relative; 652 | border-color: #4078c0; 653 | } 654 | -------------------------------------------------------------------------------- /styles/highlighting/tomorrow-night.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Night Theme */ 2 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 3 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 4 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 5 | 6 | /* Tomorrow Comment */ 7 | .hljs-comment, 8 | .hljs-quote { 9 | color: #969896; 10 | } 11 | 12 | /* Tomorrow Red */ 13 | .hljs-variable, 14 | .hljs-template-variable, 15 | .hljs-tag, 16 | .hljs-name, 17 | .hljs-selector-id, 18 | .hljs-selector-class, 19 | .hljs-regexp, 20 | .hljs-deletion { 21 | color: #cc6666; 22 | } 23 | 24 | /* Tomorrow Orange */ 25 | .hljs-number, 26 | .hljs-built_in, 27 | .hljs-builtin-name, 28 | .hljs-literal, 29 | .hljs-type, 30 | .hljs-params, 31 | .hljs-meta, 32 | .hljs-link { 33 | color: #de935f; 34 | } 35 | 36 | /* Tomorrow Yellow */ 37 | .hljs-attribute { 38 | color: #f0c674; 39 | } 40 | 41 | /* Tomorrow Green */ 42 | .hljs-string, 43 | .hljs-symbol, 44 | .hljs-bullet, 45 | .hljs-addition { 46 | color: #b5bd68; 47 | } 48 | 49 | /* Tomorrow Blue */ 50 | .hljs-title, 51 | .hljs-section { 52 | color: #81a2be; 53 | } 54 | 55 | /* Tomorrow Purple */ 56 | .hljs-keyword, 57 | .hljs-selector-tag { 58 | color: #b294bb; 59 | } 60 | 61 | .hljs { 62 | display: block; 63 | overflow-x: auto; 64 | background: #1d1f21; 65 | color: #c5c8c6; 66 | padding: 0.5em; 67 | } 68 | 69 | .hljs-emphasis { 70 | font-style: italic; 71 | } 72 | 73 | .hljs-strong { 74 | font-weight: bold; 75 | } 76 | -------------------------------------------------------------------------------- /styles/highlighting/tomorrow.css: -------------------------------------------------------------------------------- 1 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 2 | 3 | /* Tomorrow Comment */ 4 | .hljs-comment, 5 | .hljs-quote { 6 | color: #8e908c; 7 | } 8 | 9 | /* Tomorrow Red */ 10 | .hljs-variable, 11 | .hljs-template-variable, 12 | .hljs-tag, 13 | .hljs-name, 14 | .hljs-selector-id, 15 | .hljs-selector-class, 16 | .hljs-regexp, 17 | .hljs-deletion { 18 | color: #c82829; 19 | } 20 | 21 | /* Tomorrow Orange */ 22 | .hljs-number, 23 | .hljs-built_in, 24 | .hljs-builtin-name, 25 | .hljs-literal, 26 | .hljs-type, 27 | .hljs-params, 28 | .hljs-meta, 29 | .hljs-link { 30 | color: #f5871f; 31 | } 32 | 33 | /* Tomorrow Yellow */ 34 | .hljs-attribute { 35 | color: #eab700; 36 | } 37 | 38 | /* Tomorrow Green */ 39 | .hljs-string, 40 | .hljs-symbol, 41 | .hljs-bullet, 42 | .hljs-addition { 43 | color: #718c00; 44 | } 45 | 46 | /* Tomorrow Blue */ 47 | .hljs-title, 48 | .hljs-section { 49 | color: #4271ae; 50 | } 51 | 52 | /* Tomorrow Purple */ 53 | .hljs-keyword, 54 | .hljs-selector-tag { 55 | color: #8959a8; 56 | } 57 | 58 | .hljs { 59 | display: block; 60 | overflow-x: auto; 61 | background: white; 62 | color: #4d4d4c; 63 | padding: 0.5em; 64 | } 65 | 66 | .hljs-emphasis { 67 | font-style: italic; 68 | } 69 | 70 | .hljs-strong { 71 | font-weight: bold; 72 | } 73 | -------------------------------------------------------------------------------- /styles/index.css: -------------------------------------------------------------------------------- 1 | @import "./base.css"; 2 | @import "./fonts.css"; 3 | @import "./github-markdown.css"; 4 | @import "./highlighting/tomorrow.css"; -------------------------------------------------------------------------------- /tests/app.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var test = require('tape') 3 | 4 | var createApp = require('../app') 5 | var parseOptions = require('../lib/parse-options') 6 | 7 | test('app.js returns choo app', function (t) { 8 | var app = createApp(parseOptions({ 9 | contents: path.join(__dirname, 'fixtures/browser/contents.js'), 10 | markdown: path.join(__dirname, 'fixtures/browser/docs'), 11 | dir: __dirname 12 | })) 13 | t.ok(app) 14 | t.ok(app.start) 15 | t.ok(app.toString) 16 | t.end() 17 | }) 18 | 19 | test('app.toString() returns html', function (t) { 20 | var options = parseOptions({ 21 | contents: path.join(__dirname, 'fixtures/browser/contents.js'), 22 | markdown: path.join(__dirname, 'fixtures/browser/docs'), 23 | dir: __dirname 24 | }) 25 | 26 | var app = createApp(options) 27 | var html = app.toString('/', options) 28 | t.ok(html) 29 | t.end() 30 | }) 31 | -------------------------------------------------------------------------------- /tests/cli.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var test = require('tape') 4 | var exec = require('execspawn') 5 | var each = require('each-async') 6 | 7 | test('basic cli usage', function (t) { 8 | t.plan(1) 9 | 10 | var cmd = exec('minidocs ./fixtures/cli/docs -c ./fixtures/cli/contents.js -o site/', { 11 | cwd: __dirname 12 | }) 13 | 14 | cmd.on('close', function () { 15 | check(['bundle.css', 'bundle.js', 'index.html'], function (err) { 16 | t.notOk(err) 17 | t.end() 18 | }) 19 | }) 20 | }) 21 | 22 | function check (filepaths, done) { 23 | each(filepaths, function (item, i, next) { 24 | var filepath = path.join(__dirname, 'site', item) 25 | fs.stat(filepath, function (err, stats) { 26 | if (err) return next(err) 27 | next() 28 | }) 29 | }, done) 30 | } 31 | -------------------------------------------------------------------------------- /tests/fixtures/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freeman-lab/minidocs/44a9929c27595a6bea83dddec6f2ca45287bac70/tests/fixtures/.DS_Store -------------------------------------------------------------------------------- /tests/fixtures/browser/app.js: -------------------------------------------------------------------------------- 1 | var minidocs = require('minidocs') 2 | 3 | var app = minidocs({ 4 | contents: './contents.js', 5 | markdown: './markdown' 6 | }) 7 | 8 | var tree = app.start() 9 | document.body.appendChild(tree) 10 | -------------------------------------------------------------------------------- /tests/fixtures/browser/contents.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | a: 'markdown/a.md', 3 | b: 'markdown/b.md', 4 | c: 'markdown/c.md' 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/browser/docs/a.md: -------------------------------------------------------------------------------- 1 | a -------------------------------------------------------------------------------- /tests/fixtures/browser/docs/b.md: -------------------------------------------------------------------------------- 1 | b -------------------------------------------------------------------------------- /tests/fixtures/browser/docs/c.md: -------------------------------------------------------------------------------- 1 | c -------------------------------------------------------------------------------- /tests/fixtures/cli/contents.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | a: 'markdown/a.md', 3 | b: 'markdown/b.md', 4 | c: 'markdown/c.md' 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/cli/docs/a.md: -------------------------------------------------------------------------------- 1 | a -------------------------------------------------------------------------------- /tests/fixtures/cli/docs/b.md: -------------------------------------------------------------------------------- 1 | b -------------------------------------------------------------------------------- /tests/fixtures/cli/docs/c.md: -------------------------------------------------------------------------------- 1 | c -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | require('./parse-options') 2 | require('./node') 3 | require('./app') 4 | require('./cli') 5 | -------------------------------------------------------------------------------- /tests/node.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | 3 | var createApp = require('../app') 4 | var parseOptions = require('../lib/parse-options') 5 | 6 | test('app.js returns choo app', function (t) { 7 | var options = parseOptions({ 8 | contents: './fixtures/browser/contents.js', 9 | markdown: './fixtures/browser/docs', 10 | dir: __dirname 11 | }) 12 | 13 | var app = createApp(options) 14 | t.ok(app) 15 | t.ok(app.start) 16 | t.ok(app.toString) 17 | t.end() 18 | }) 19 | 20 | test('app.toString() returns html', function (t) { 21 | var options = parseOptions({ 22 | contents: './fixtures/browser/contents.js', 23 | markdown: './fixtures/browser/docs', 24 | dir: __dirname 25 | }) 26 | 27 | var app = createApp(options) 28 | var html = app.toString('/', options) 29 | t.ok(html) 30 | t.end() 31 | }) 32 | -------------------------------------------------------------------------------- /tests/parse-options.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | var parseOptions = require('../lib/parse-options') 3 | 4 | test('parseOptions returns contents, routes, html', function (t) { 5 | var options = parseOptions({ 6 | contents: './fixtures/browser/contents.js', 7 | markdown: './fixtures/browser/docs', 8 | dir: __dirname 9 | }) 10 | 11 | t.ok(options) 12 | t.ok(options.html) 13 | t.ok(options.contents) 14 | t.ok(options.routes) 15 | t.ok(options.routes.index) 16 | t.ok(options.routes.a) 17 | t.equal(options.html.a, '

a

\n') 18 | t.end() 19 | }) 20 | -------------------------------------------------------------------------------- /transform.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var through = require('through2') 3 | var staticModule = require('static-module') 4 | 5 | var parseOptions = require('./lib/parse-options') 6 | 7 | module.exports = function minidocsTransform (filename) { 8 | if (/\.json$/.test(filename)) return through() 9 | var basedir = path.dirname(filename) 10 | 11 | var vars = { 12 | __filename: filename, 13 | __dirname: basedir 14 | } 15 | 16 | var sm = staticModule({ 17 | minidocs: function (options) { 18 | options.dir = basedir 19 | var parsedOptions = parseOptions(options) 20 | var stream = through() 21 | stream.push(`require('minidocs')(${JSON.stringify(parsedOptions)})`) 22 | stream.push(null) 23 | return stream 24 | } 25 | }, { vars: vars, varModules: {} }) 26 | 27 | return sm 28 | } 29 | --------------------------------------------------------------------------------