Compare commits

...

103 Commits

Author SHA1 Message Date
Aaron O'Mullan 6ee17c32ae Bump version to 0.5.3 2014-06-15 22:39:18 -07:00
Aaron O'Mullan bf7ffe6d4c Skip extra files and folders in copy phase of generation 2014-06-15 22:37:15 -07:00
Aaron O'Mullan ec7bc6b347 Add link to gitbook.io in readme 2014-06-15 22:36:51 -07:00
Aaron O'Mullan b425db0979 Allow external links in summary, fixes #300 2014-06-08 12:31:52 -07:00
Samy Pessé 30c6d1c9de Remove useless log 2014-06-08 02:21:05 +02:00
Samy Pessé cee1d90fc6 Bump version to 0.5.2 2014-06-08 01:09:51 +02:00
Samy Pessé 522342667c Fix font size for mono font on pdf output 2014-06-08 00:27:18 +02:00
Samy Pessé d1c1277bb9 Fix cover picture for multilangs book convertion to ebook 2014-06-08 00:11:50 +02:00
Aaron O'Mullan 9a66f56c79 Bump version to 0.5.1 2014-06-07 11:42:37 -07:00
Samy Pessé 087ca28ca2 Fix style for main languages index page 2014-06-07 16:30:11 +02:00
Samy Pessé 3d5281ff3a Fix GitbookIO/gitbook.io#69: copy cover files at multi-langs root 2014-06-07 16:27:40 +02:00
Samy Pessé f62cf340c5 Fix title and description for pages in website 2014-06-07 16:04:03 +02:00
Samy Pessé 7e12bd3588 Don't use cdn for ace 2014-06-07 16:02:02 +02:00
Samy Pessé 4dbdb95ebe Show quiz inside ebook 2014-06-06 22:20:02 +02:00
Samy Pessé 2c5ddbcd8f Use base style for ebook instead of bootstrap 2014-06-06 21:47:59 +02:00
Samy Pessé be4fd74f90 Improve navigation links design 2014-06-06 20:06:03 +02:00
Samy Pessé 57491e3a8b Improve meta tags for books 2014-06-06 20:00:38 +02:00
Samy Pessé f7a442d297 Improve font sizes and spacing on content 2014-06-06 19:33:41 +02:00
Samy Pessé cfebdc6f6b Fix #296: fix static links on windows 2014-06-06 18:37:35 +02:00
Samy Pessé 65319e8fd6 Bump version to 0.5.0 2014-06-03 22:30:42 +02:00
Samy Pessé 55db44a3b4 Fix #289: center images on ebook 2014-06-03 22:20:51 +02:00
Samy Pessé 13b6045300 Font Merriweather 600 doesn't exists 2014-06-03 20:45:55 +02:00
Samy Pessé b7ff879c31 Remove fonts Anonymous Pro and EB Garamond 2014-06-03 20:43:47 +02:00
Samy Pessé 57ade87fe1 Fix #275: fix emphasized font path 2014-06-03 20:30:04 +02:00
Samy Pessé 907e9ea5a7 Improve font on title
Set sans-serif as default
2014-06-03 20:14:44 +02:00
Samy Pessé 215488dc45 Improve design (more flat) 2014-06-03 18:43:13 +02:00
Samy Pessé a195b3eac2 Improve less files organisation 2014-06-03 18:11:03 +02:00
Samy Pessé 77c6f0e967 Merge pull request #291 from bebraw/book.js
Allow book.js to be used in addition to book.json
2014-06-03 17:20:26 +02:00
Juho Vepsalainen f0e18afec1 In case there's no config file, do not fail 2014-06-03 17:59:26 +03:00
Juho Vepsalainen b6d11d88b7 Allow book.js to be used in addition to book.json
Now it's possible to comment configuration properly and do some dynamic
things if needed.

Closes #287.
2014-06-03 17:42:30 +03:00
Samy Pessé c803270af8 Add option pdf.pageNumber
Fix GitbookIO/editor#38
2014-06-03 16:24:35 +02:00
Samy Pessé 5d51263a58 Remove mixpanel as a default addon 2014-06-03 15:29:15 +02:00
Samy Pessé 7e30720b2c Merge pull request #292 from bebraw/typofix
Fix build success message typo
2014-06-03 15:07:29 +02:00
Juho Vepsalainen 771c5e8b68 Fix build success message typo 2014-06-03 15:58:22 +03:00
Samy Pessé 8f53afab6b Fix #286: fix doc about formats 2014-06-02 20:12:56 +02:00
Samy Pessé 0ad0403d41 Merge pull request #283 from GitbookIO/feature/pdfoptions
Add more options for PDF
2014-06-02 18:22:07 +02:00
Samy Pessé 2515c1dd73 Remove useless command "gitbook ebook" 2014-06-02 18:17:02 +02:00
Samy Pessé 7dfcd102dd Fix calcul of output format for ebook 2014-06-02 18:16:44 +02:00
Samy Pessé a91245d575 Add options paperSize and margin for pdf 2014-06-02 17:57:47 +02:00
Samy Pessé 5f207f5e14 Add options pdf.toc and pdf.fontSize 2014-06-02 17:49:05 +02:00
Samy Pessé 718692de3b Langs index page now use direct link to html file 2014-06-02 14:49:40 +02:00
Samy Pessé 9856a51255 Fix #282: stop generation of langs index for page format 2014-06-02 14:13:52 +02:00
Samy Pessé 58eaaf5514 Fix error when plugin don't extend book 2014-06-02 12:51:22 +02:00
Samy Pessé c0ae0138f8 Improve documentation about book.json 2014-06-02 11:41:16 +02:00
Samy Pessé b1b9dc5b0a Fix error during generation 2014-06-02 11:37:25 +02:00
Samy Pessé f85c5a6498 Add error message when generator is invalid
Fixes #276, #277
2014-06-02 11:32:09 +02:00
Aaron O'Mullan 32eafefc45 Bump version to 0.4.8 2014-05-29 16:36:56 -07:00
Aaron O'Mullan 336999a34e Set default pdf font size to 12 2014-05-29 15:57:56 -07:00
Samy Pessé 1bf5f3b984 Force paper format to A4 fro pdf 2014-05-30 00:33:35 +02:00
Samy Pessé c76d070237 Merge pull request #274 from emmanuel-keller/patch-1
Adding a new plugin (Piwik Open Analytics plugin)
2014-05-30 00:11:38 +02:00
Emmanuel Keller 8c7da1351f Adding a new plugin.
I Just published a first version of the Piwik Open Analytics plugin, on both GIT and NPM.
2014-05-29 23:31:38 +02:00
Samy Pessé 34588c6092 Add margin on pdf output 2014-05-29 18:53:08 +02:00
Samy Pessé 9f00bf8060 Add toc at the end of pdf 2014-05-29 18:33:05 +02:00
Samy Pessé f4a17b182f Improve ebook generation (toc, ...) 2014-05-29 18:28:09 +02:00
Samy Pessé 5c3b345fa6 Generate valid first level table of content for ebook 2014-05-29 17:28:18 +02:00
Samy Pessé 46321fffd9 Use ebook-convert for pdf generation 2014-05-29 17:07:03 +02:00
Aaron O'Mullan 89ba17de84 Bump version to 0.4.7 2014-05-26 12:14:32 -07:00
Aaron O'Mullan 115fba837c Merge pull request #265 from GitbookIO/feature/levels
More than two section level in summary
2014-05-26 11:27:27 -07:00
Samy Pessé 4df51546b2 Remove command log in ebook convert 2014-05-26 18:02:32 +02:00
Samy Pessé f68aaf7ff9 Fix cover option for ebook 2014-05-26 18:02:09 +02:00
Samy Pessé e3d1746ba3 Fix use of cover.jpg in ebook 2014-05-26 17:58:08 +02:00
Samy Pessé a0d5646034 Adapt navigation parsing to third and more levels in summary 2014-05-26 17:42:05 +02:00
Samy Pessé 2f8af5f136 Improve design of summary for deep articles 2014-05-26 17:33:10 +02:00
Samy Pessé 8b7abbd6f4 Render articles of level > 2 in summary 2014-05-26 17:31:35 +02:00
Samy Pessé f228f646eb Remove useless method parseArticle 2014-05-26 17:23:19 +02:00
Samy Pessé 45891d80c7 Parse more than two level in summary 2014-05-26 17:21:23 +02:00
Samy Pessé ac900aa37f Merge pull request #263 from jpoesen/patch-1
Minor typo, grammar and style corrections.
2014-05-26 10:44:25 +02:00
Joeri Poesen 422cbed796 Minor typo, grammar and style corrections. 2014-05-26 08:13:35 +02:00
Samy Pessé 38cbbe46aa Fix cache manifest generation 2014-05-25 20:47:57 +02:00
Aaron O'Mullan c1b57a387b Bump version to 0.4.6 2014-05-23 16:35:44 -07:00
Samy Pessé aaa9ae8bb7 Fix loading button display on navigation 2014-05-24 01:32:39 +02:00
Samy Pessé 6340a64cff Fix #235: search after navigation to another page 2014-05-23 22:28:36 +02:00
Samy Pessé 96bcfa4e20 Fix #218: keep state of font settings 2014-05-23 22:20:36 +02:00
Samy Pessé af0f56b26b Change position of menu action in header 2014-05-23 21:49:11 +02:00
Samy Pessé aed5befa48 Fix display of divider in lateral menu 2014-05-23 21:48:04 +02:00
Samy Pessé 8e37da672d Minor css improvements 2014-05-23 21:43:47 +02:00
Samy Pessé c0f68c45e2 Fix #249: fix links.toAbsolute on windows 2014-05-23 21:10:58 +02:00
Samy Pessé 47fdd73791 Fix cache manifest in the html tag
Serve command disable cache
2014-05-23 17:45:46 +02:00
Samy Pessé 7c0b88cf2e Plugins can extend html 2014-05-23 17:00:37 +02:00
Samy Pessé bf21633b6c Support multi-languages book in json format 2014-05-23 16:35:34 +02:00
Samy Pessé ad9b1fd6f7 Fix order of progress for level superior to x.9
Related to GitbookIO/gitbook.io#23
2014-05-21 23:31:57 +02:00
Samy Pessé d245895085 Add link to documentation 2014-05-21 20:22:28 +02:00
Samy Pessé c7439d12f7 Add livereload as default plugins only for serve 2014-05-21 17:34:36 +02:00
Samy Pessé 8d6923ce2c Merge pull request #234 from davidagraf/livereload
Livereload
2014-05-21 17:17:08 +02:00
David Graf b21fb24a82 gitbook-plugin-livereload dependency to npm 2014-05-21 16:35:55 +02:00
David Graf e7be132194 Merge branch 'master' into livereload 2014-05-21 16:24:07 +02:00
Samy Pessé 0e1717f4bb Improve grammar (thanks to @theoutlander ) 2014-05-21 10:46:26 +02:00
Aaron O'Mullan 276dbe29c7 Bump version to 0.4.5 2014-05-20 23:29:39 -07:00
Aaron O'Mullan 21fd5924b8 Fix generate failing on README parsing
Failed if no title or description could be extracted
2014-05-20 23:29:06 -07:00
Aaron O'Mullan 443def6cfd Bump version to 0.4.4 2014-05-20 22:59:26 -07:00
Samy Pessé 75464574d7 For multi-langs, run build one by one 2014-05-21 00:09:40 +02:00
Samy Pessé 86f05c68c5 Improve parsing of readme (extraction of title and description as plain text and not markdown) 2014-05-20 23:45:35 +02:00
Samy Pessé 8dd407eaa8 Fix merge of output for multi-languages books 2014-05-20 23:31:22 +02:00
Samy Pessé ea7ad10e8a Add support for multi-languages books in JSON format 2014-05-20 23:21:12 +02:00
Samy Pessé 62ec695dc8 Extract title and description from readme before switching to multi-languages handling 2014-05-20 23:07:41 +02:00
Samy Pessé ca37ac73a9 Add more infos about gitbook.io 2014-05-20 14:40:22 +02:00
Samy Pessé 96edd50c8f Add norm for small cover 2014-05-20 01:23:49 +02:00
Samy Pessé 3993c1e35a Change advised ratio for cover 2014-05-19 21:47:41 +02:00
David Graf 7c65adc9b2 disable cache manifest import if cache is disabled 2014-05-15 12:07:51 +02:00
David Graf 9b96ef9bae added livereload dependency 2014-05-15 11:41:59 +02:00
David Graf e97d1941dc Introducing livereload server 2014-05-15 08:09:02 +02:00
David Graf 0b0ac46e34 Introducing option to disable cache manifest generation 2014-05-15 08:07:24 +02:00
David Graf 622bbcb8ea ignore vim swap files 2014-05-15 07:43:59 +02:00
68 changed files with 810 additions and 685 deletions
+4 -1
View File
@@ -24,4 +24,7 @@ build/Release
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
node_modules
theme/javascript/vendors
theme/javascript/vendors
# vim swapfile
*.swp
+4 -3
View File
@@ -24,8 +24,8 @@ module.exports = function (grunt) {
optimization: 2
},
files: {
"theme/assets/style.css": "theme/stylesheets/main.less",
"theme/assets/print.css": "theme/stylesheets/print.less"
"theme/assets/style.css": "theme/stylesheets/website.less",
"theme/assets/print.css": "theme/stylesheets/ebook.less"
}
}
},
@@ -44,7 +44,8 @@ module.exports = function (grunt) {
"requireLib": 'vendors/requirejs/require',
"Mousetrap": 'vendors/mousetrap/mousetrap',
"lunr": 'vendors/lunr.js/lunr',
"URI": 'vendors/URIjs/src/URI'
"URI": 'vendors/URIjs/src/URI',
"ace": 'vendors/ace-builds/src-noconflict/'
},
shim: {
'jQuery': {
+67 -25
View File
@@ -3,7 +3,7 @@ GitBook
[![Build Status](https://travis-ci.org/GitbookIO/gitbook.png?branch=master)](https://travis-ci.org/GitbookIO/gitbook)
GitBook is a command line tool (and Node.js library) for building beautiful programming books and exercises using GitHub/Git and Markdown. You can see an example: [Learn Javascript](http://gitbookio.github.io/javascript/). An [editor](https://github.com/GitbookIO/editor) is available for Windows, Mac and Linux. You can follow [@GitBookIO](https://twitter.com/GitBookIO) on Twitter.
GitBook is a command line tool (and Node.js library) for building beautiful books and exercises using GitHub/Git and Markdown. Here is an example: [Learn Javascript](https://www.gitbook.io/book/GitBookIO/javascript). You can publish book easily online using [gitbook.io](https://www.gitbook.io) and an [editor](https://github.com/GitbookIO/editor) is available for Windows, Mac and Linux. You can follow [@GitBookIO](https://twitter.com/GitBookIO) on Twitter. Complete documentation is available at [help.gitbook.io](http://help.gitbook.io/).
![Image](https://raw.github.com/GitbookIO/gitbook/master/preview.png)
@@ -31,27 +31,37 @@ Options for commands `build` and `serve` are:
```
-o, --output <directory> Path to output directory, defaults to ./_book
-f, --format <name> Change generation format, defaults to site, availables are: site, page, pdf, json
--config <config file> Configuration file to use, defaults to book.json
-f, --format <name> Change generation format, defaults to site, availables are: site, page, ebook, json
--config <config file> Configuration file to use, defaults to book.js or book.json
```
GitBook load the default configuration from a `book.json` file in the repository if it exists.
GitBook loads the default configuration from a `book.json` file in the repository if it exists.
Here are the options that can be stored in this file:
```
```js
{
// Folders to use for output (caution: it override the value from the command line)
// Folders to use for output
// Caution: it overrides the value from the command line
// It's not advised this option in the book.json
"output": null,
// Generator to use for building (caution: it override the value from the command line)
// Generator to use for building
// Caution: it overrides the value from the command line
// It's not advised this option in the book.json
"generator": "site",
// Book title and description (defaults are extracted from the README)
"title": null,
"description": null,
// GitHub informations (defaults are extracted using git)
// For ebook format, the extension to use for generation (default is detected from output extension)
// "epub", "pdf", "mobi"
// Caution: it overrides the value from the command line
// It's not advised this option in the book.json
"extension": null,
// GitHub information (defaults are extracted using git)
"github": null,
"githubHost": "https://github.com/",
@@ -67,9 +77,9 @@ Here are the options that can be stored in this file:
}
},
// set another theme with your own layout
// it's recommended to use plugins or add more options for default theme, though
// see https://github.com/GitbookIO/gitbook/issues/209
// Set another theme with your own layout
// It's recommended to use plugins or add more options for default theme, though
// See https://github.com/GitbookIO/gitbook/issues/209
"theme": "./localtheme",
// Links in template (null: default, false: remove, string: new value)
@@ -88,6 +98,32 @@ Here are the options that can be stored in this file:
"facebook": null,
"twitter": null
}
},
// Options for PDF generation
"pdf": {
// Add toc at the end of the file
"toc": true,
// Add page numbers to the bottom of every page
"pageNumbers": false,
// Font size for the fiel content
"fontSize": 12,
// Paper size for the pdf
// Choices are [u’a0’, u’a1’, u’a2’, u’a3’, u’a4’, u’a5’, u’a6’, u’b0’, u’b1’, u’b2’, u’b3’, u’b4’, u’b5’, u’b6’, u’legal’, u’letter’]
"paperSize": "a4",
// Margin (in pts)
// Note: 72 pts equals 1 inch
"margin": {
"right": 62,
"left": 62,
"top": 36,
"bottom": 36
}
}
}
```
@@ -98,19 +134,18 @@ You can publish your books to our index by visiting [GitBook.io](http://www.gitb
GitBook can generate your book in the following formats:
* **Static Website**: This is the default format, it generates a complete interactive static website that can be for example hosted on GitHub Pages.
* **PDF**: A complete PDF book with exercise solutions at the end of the book. Generate to this format using: ```gitbook pdf ./myrepo```, you need to have [gitbook-pdf](https://github.com/GitbookIO/gitbook-pdf) installed.
* **eBook**: A complete eBook with exercise solutions at the end of the book. Generate to this format using: ```gitbook ebook ./myrepo```, you need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed.
* **Single Page**: The book will be stored in a single printable HTML page, this format is used for conversion to PDF or eBook. Generate to this format using: ```gitbook build ./myrepo -f page```.
* **JSON**: This format is used for debugging or extracting metadata from a book. Generate to this format using: ```gitbook build ./myrepo -f json```.
* **Static Website**: This is the default format. It generates a complete interactive static website that can be, for example, hosted on GitHub Pages.
* **eBook**: A complete eBook with exercise solutions at the end of the book. Generate this format using: ```gitbook ebook ./myrepo```. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. The output format could be **PDF**, **ePub** or **MOBI**.
* **Single Page**: The book will be stored in a single printable HTML page. This format is used for conversion to PDF or eBook. Generate this format using: ```gitbook build ./myrepo -f page```.
* **JSON**: This format is used for debugging or extracting metadata from a book. Generate this format using: ```gitbook build ./myrepo -f json```.
## Book Format
A book is a GitHub repository containing at least 2 files: `README.md` and `SUMMARY.md`.
A book is a Git repository containing at least 2 files: `README.md` and `SUMMARY.md`.
#### README.md
As usual, it should contains an introduction for your book. It will be automatically added to the final summary.
Typically, this should be the introduction for your book. It will be automatically added to the final summary.
#### SUMMARY.md
@@ -130,11 +165,11 @@ This is the summary of my book.
* [example 1](section2/example1.md)
```
Files that are not included in the `SUMMARY.md` will not be processed by `gitbook`.
Files that are not included in `SUMMARY.md` will not be processed by `gitbook`.
#### Exercises
A book can contain interactive exercises (currently only in Javascript but Python and Ruby are coming soon ;) ). An exercise is a code challenge provided to the reader, which is given a code editor to write a solution which is checked against the book author's validation code.
A book can contain interactive exercises (currently only in Javascript but Python and Ruby are coming soon ;) ). An exercise is a code challenge provided to the reader, who is given a code editor to write a solution which is checked against the book author's validation code.
An exercise is defined by 4 simple parts:
@@ -143,7 +178,7 @@ An exercise is defined by 4 simple parts:
* **Solution** code, being a correct solution to the exercise
* **Validation** code that tests the correctness of the user's input
Exercises need to start and finish with a separation bar (```---``` or ```***```). It should contain 3 code elements (**base**, **solution** and **validation**). It can contain a 4th element that provides **context** code (functions, imports of libraries etc ... that shouldn't be displayed to the user).
Exercises need to start and finish with a separation bar (```---``` or ```***```). It should contain 3 code elements (**base**, **solution** and **validation**). It can contain a 4th element that provides **context** code (functions, imports of libraries, etc which shouldn't be displayed to the user).
---
@@ -185,16 +220,22 @@ You can see a complete example with the [Learn Git](https://github.com/GitbookIO
#### Ignoring files & folders
GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a list of files and folders to skip. (The format inside those files, follows the same convention as `.gitignore`)
GitBook will read the `.gitignore`, `.bookignore` and `.ignore` files to get a list of files and folders to skip. (The format inside those files follows the same convention as `.gitignore`)
#### Cover
A cover image can be set by creating a file: **/cover.jpg** or **cover.png**.
The best resolution is **1600x2400**. The generation of the cover can be done automatically using the plugin [autocover](https://github.com/GitbookIO/plugin-autocover).
A cover image can be set by creating a file: **/cover.jpg**.
The best resolution is **1800x2360**. The generation of the cover can be done automatically using the plugin [autocover](https://github.com/GitbookIO/plugin-autocover).
A small version of the cover can also be set by creating a file: **/cover_small.jpg**.
#### Publish your book
The platform [GitBook.io](https://www.gitbook.io/) is like an "Heroku for books": you can create a book on it (public, paid, or private) and update it using **git push**.
#### Plugins
Plugins can used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for gitbook.
Plugins can used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for GitBook.
##### Default plugins:
@@ -211,3 +252,4 @@ Plugins can used to extend your book's functionality. Read [GitbookIO/plugin](ht
* [Revealable sections](https://github.com/mrpotes/gitbook-plugin-reveal): Reveal sections of the page using buttons made from the first title in each section
* [Markdown within HTML](https://github.com/mrpotes/gitbook-plugin-nestedmd): Process markdown within HTML blocks - allows custom layout options for individual pages
* [Bootstrap JavaScript plugins](https://github.com/mrpotes/gitbook-plugin-bootstrapjs): Use the [Bootstrap JavaScript plugins](http://getbootstrap.com/javascript) in your online GitBook
* [Piwik Open Analytics](https://github.com/emmanuel-keller/gitbook-plugin-piwik): Piwik Open Analytics tracking for your book
+9 -3
View File
@@ -12,10 +12,15 @@ var buildCommand = function(command) {
return command
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('--config <config file>', 'Configuration file to use, defualt to book.json')
.option('--config <config file>', 'Configuration file to use, defaults to book.js or book.json')
};
var buildEbookCommand = function(command) {
return buildCommand(command)
.option('-c, --cover <path>', 'Cover image, default is cover.jpg if exists');
};
var makeBuildFunc = function(converter) {
return function(dir, options) {
dir = dir || process.cwd();
@@ -31,7 +36,7 @@ var makeBuildFunc = function(converter) {
})
)
.then(function(output) {
console.log("Successfuly built !");
console.log("Successfully built!");
return output;
}, utils.logError)
.fail(function() {
@@ -43,5 +48,6 @@ var makeBuildFunc = function(converter) {
module.exports = {
folder: makeBuildFunc(generate.folder),
file: makeBuildFunc(generate.file),
command: buildCommand
command: buildCommand,
commandEbook: buildEbookCommand
};
+35 -10
View File
@@ -4,6 +4,7 @@ var Q = require('q');
var _ = require('lodash');
var path = require('path');
var prog = require('commander');
var tinylr = require('tiny-lr-fork');
var pkg = require('../package.json');
var generators = require("../lib/generate").generators;
@@ -29,12 +30,24 @@ build.command(prog.command('serve [source_dir]'))
.action(function(dir, options) {
var server = new Server();
// init livereload server
var lrOptions = {port: 35729};
var lrServer = tinylr(lrOptions);
var lrPath = undefined;
lrServer.listen(lrOptions.port, function(err) {
if (err) { return console.log(err); }
console.log('Live reload server started on port: ' + lrOptions.port);
});
var generate = function() {
if (server.isRunning()) console.log("Stopping server");
server.stop()
.then(function() {
return build.folder(dir, options);
return build.folder(dir, _.extend(options || {}, {
cache: false,
defaultsPlugins: ["livereload"]
}));
})
.then(function(_options) {
console.log();
@@ -43,9 +56,16 @@ build.command(prog.command('serve [source_dir]'))
.then(function() {
console.log('Serving book on http://localhost:'+options.port);
if (lrPath) {
// trigger livereload
lrServer.changed({body:{files:[lrPath]}})
}
if (!options.watch) return;
return utils.watch(_options.input)
.then(function(filepath) {
// set livereload path
lrPath = filepath;
console.log("Restart after change in files");
console.log('');
return generate();
@@ -60,24 +80,29 @@ build.command(prog.command('serve [source_dir]'))
generate();
});
build.command(prog.command('pdf [source_dir]'))
build.commandEbook(prog.command('pdf [source_dir]'))
.description('Build a gitbook as a PDF')
.option('-pf, --paperformat <format>', 'PDF paper format (default is A4): "5in*7.5in", "10cm*20cm", "A4", "Letter"')
.action(function(dir, options) {
build.file(dir, _.extend(options, {
extension: "pdf",
format: "pdf"
format: "ebook"
}));
});
build.command(prog.command('ebook [source_dir]'))
.description('Build a gitbook as a eBook')
.option('-c, --cover <path>', 'Cover image, default is cover.png if exists')
build.commandEbook(prog.command('epub [source_dir]'))
.description('Build a gitbook as a ePub book')
.action(function(dir, options) {
var ext = options.output ? path.extname(options.output) : "epub";
build.file(dir, _.extend(options, {
extension: ext,
extension: "epub",
format: "ebook"
}));
});
build.commandEbook(prog.command('mobi [source_dir]'))
.description('Build a gitbook as a Mobi book')
.action(function(dir, options) {
build.file(dir, _.extend(options, {
extension: "mobi",
format: "ebook"
}));
});
+2 -1
View File
@@ -7,6 +7,7 @@
"requirejs": "2.1.11",
"URIjs": "1.13.1",
"mousetrap": "1.4.6",
"lunr.js": "0.5.2"
"lunr.js": "0.5.2",
"ace-builds": "1.1.3"
}
}
+42 -19
View File
@@ -7,6 +7,7 @@ var exec = require('child_process').exec;
var fs = require("fs");
var parse = require("../../parse");
var BaseGenerator = require("../page");
var stringUtils = require("../../utils/string");
/*
* This generator inherits from the single page generator
@@ -14,15 +15,6 @@ var BaseGenerator = require("../page");
*/
var Generator = function() {
BaseGenerator.apply(this, arguments);
// Options for eBook generation
this.options = _.defaults(this.options, {
extension: "epub"
});
if (!this.options.cover && fs.existsSync(path.join(this.options.input, "cover.png"))) {
this.options.cover = path.join(this.options.input, "cover.png")
}
};
util.inherits(Generator, BaseGenerator);
@@ -32,23 +24,54 @@ Generator.prototype.finish = function() {
return BaseGenerator.prototype.finish.apply(this)
.then(function() {
var d = Q.defer();
var format = that.options.extension || path.extname(that.options.output).replace("\.", "") || "pdf";
if (!that.options.cover && fs.existsSync(path.join(that.options.output, "cover.jpg"))) {
that.options.cover = path.join(that.options.output, "cover.jpg");
}
var _options = {
"--cover": that.options.cover
"--cover": that.options.cover,
"--title": that.options.title,
"--comments": that.options.description,
"--authors": that.options.author,
"--level1-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-1 ')]",
"--level2-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-2 ')]",
"--level3-toc": "descendant-or-self::*[contains(concat(' ', normalize-space(@class), ' '), ' book-chapter-3 ')]"
};
if (format == "pdf") {
var pdfOptions = _.defaults(that.options.pdf || {}, {
"fontSize": 12,
"toc": true,
"pageNumbers": false,
"paperSize": "a4",
"margin": {
"right": 62,
"left": 62,
"top": 36,
"bottom": 36
}
});
_.extend(_options, {
"--margin-left": String(pdfOptions.margin.left),
"--margin-right": String(pdfOptions.margin.right),
"--margin-top": String(pdfOptions.margin.top),
"--margin-bottom": String(pdfOptions.margin.bottom),
"--pdf-add-toc": Boolean(pdfOptions.toc),
"--pdf-default-font-size": String(pdfOptions.fontSize),
"--pdf-mono-font-size": String(pdfOptions.fontSize),
"--paper-size": String(pdfOptions.paperSize),
"--pdf-page-numbers": Boolean(pdfOptions.pageNumbers)
});
}
var command = [
"ebook-convert",
path.join(that.options.output, "index.html"),
path.join(that.options.output, "index."+that.options.extension),
_.chain(_options)
.map(function(value, key) {
if (value == null) return null;
return key+"="+value;
})
.compact()
.value()
.join(" ")
path.join(that.options.output, "index."+format),
stringUtils.optionsToShellArgs(_options)
].join(" ");
exec(command, function (error, stdout, stderr) {
+12 -1
View File
@@ -16,9 +16,20 @@ var getFiles = function(path) {
// Add extra rules to ignore common folders
ig.addIgnoreRules([
// Skip Git stuff
'.git/',
'.gitignore',
'.DS_Store'
// Skip OS X meta data
'.DS_Store',
// Skip stuff installed by plugins
'node_modules',
// Skip book outputs
'*.pdf',
'*.epub',
'*.mobi',
], '__custom_stuff');
// Push each file to our list
+22
View File
@@ -9,6 +9,7 @@ var BaseGenerator = function(options) {
this.options = options;
this.options.plugins = Plugin.normalizeNames(this.options.plugins);
this.options.plugins = _.union(this.options.plugins, this.options.defaultsPlugins);
this.plugins = [];
};
@@ -44,6 +45,27 @@ BaseGenerator.prototype.transferFolder = function(input) {
);
};
BaseGenerator.prototype.copyCover = function() {
var that = this;
return Q.all([
fs.copy(path.join(this.options.input, "cover.jpg"), path.join(this.options.output, "cover.jpg")),
fs.copy(path.join(this.options.input, "cover_small.jpg"), path.join(this.options.output, "cover_small.jpg"))
])
.fail(function() {
// If orignally from multi-lang, try copy from originalInput
if (!that.options.originalInput) return;
return Q.all([
fs.copy(path.join(that.options.originalInput, "cover.jpg"), path.join(that.options.output, "cover.jpg")),
fs.copy(path.join(that.options.originalInput, "cover_small.jpg"), path.join(that.options.output, "cover_small.jpg"))
]);
})
.fail(function(err) {
return Q();
});
};
BaseGenerator.prototype.langsIndex = function(langs) {
return Q.reject(new Error("Langs index is not supported in this generator"));
};
+82 -46
View File
@@ -1,9 +1,9 @@
var Q = require("q");
var _ = require("lodash");
var path = require("path");
var swig = require('swig');
var tmp = require('tmp');
var swig = require('./template');
var fs = require("./fs");
var parse = require("../parse");
var Plugin = require("./plugin");
@@ -11,7 +11,6 @@ var Plugin = require("./plugin");
var generators = {
"site": require("./site"),
"page": require("./page"),
"pdf": require("./pdf"),
"ebook": require("./ebook"),
"json": require("./json")
};
@@ -26,13 +25,23 @@ var containsFiles = function(dir, files) {
.then(_.all);
};
// TEst if generator exists
var checkGenerator = function(options) {
if (!generators[options.generator]) {
return Q.reject(new Error("Invalid generator (availables are: "+_.keys(generators).join(", ")+")"));
}
return Q();
};
// Create the generator and load plugins
var loadGenerator = function(options) {
var generator = new generators[options.generator](options);
return checkGenerator(options)
.then(function() {
var generator = new generators[options.generator](options);
return generator.loadPlugins()
.then(_.constant(generator));
return generator.loadPlugins()
.then(_.constant(generator));
});
};
@@ -45,7 +54,7 @@ var generate = function(options) {
"output": null,
// Config file (relative to input)
"configFile": "book.json",
"configFile": "book",
// Output generator
"generator": "site",
@@ -64,6 +73,7 @@ var generate = function(options) {
// Plugins
"plugins": [],
"pluginsConfig": {},
"defaultsPlugins": [], // Default plugins that can't be set in book.json
// Links
"links": {
@@ -78,13 +88,38 @@ var generate = function(options) {
return Q.reject(new Error("Need option input (book input directory)"));
}
// Ensure generator exists
if (!generators[options.generator]) {
return Q.reject(new Error("Invalid generator (availables are: "+_.keys(generators).join(", ")));
}
// Check files to get folder type (book, multilanguage book or neither)
return containsFiles(options.input, ['LANGS.md'])
return checkGenerator(options)
// Read config file
.then(function() {
try {
var _config = require(path.resolve(options.input, options.configFile));
_.extend(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins'));
}
catch(err) {
// No config file: not a big deal
return Q();
}
})
// Read readme
.then(function() {
return fs.readFile(path.join(options.input, "README.md"), "utf-8")
.then(function(_readme) {
_readme = parse.readme(_readme);
options.title = options.title || _readme.title;
options.description = options.description || _readme.description || defaultDescription;
});
})
// Detect multi-languages book
.then(function() {
return containsFiles(options.input, ['LANGS.md'])
})
.then(function(isMultiLang) {
// Multi language book
if(isMultiLang) {
@@ -98,24 +133,40 @@ var generate = function(options) {
var generateMultiLang = function(options) {
var langsSummary;
options.output = options.output || path.join(options.input, "_book");
return checkGenerator(options)
// Multi-languages book
return fs.readFile(path.join(options.input, "LANGS.md"), "utf-8")
.then(function() {
return fs.readFile(path.join(options.input, "LANGS.md"), "utf-8")
})
// Clean output folder
.then(function(_langsSummary) {
langsSummary = _langsSummary;
return fs.remove(options.output);
})
.then(function() {
return fs.mkdirp(options.output);
})
// Generate sub-books
.then(function(_langsSummary) {
options.langsSummary = parse.langs(_langsSummary);
.then(function() {
options.langsSummary = parse.langs(langsSummary);
// Generated a book for each valid entry
return Q.all(
_.map(options.langsSummary.list, function(entry) {
return _.reduce(options.langsSummary.list, function(prev, entry) {
return prev.then(function() {
return generate(_.extend({}, options, {
input: path.join(options.input, entry.path),
output: path.join(options.output, entry.path)
output: path.join(options.output, entry.path),
originalInput: options.input,
originalOutput: options.output
}));
})
);
}, Q());
})
.then(function() {
@@ -127,6 +178,17 @@ var generateMultiLang = function(options) {
return generator.langsIndex(options.langsSummary);
})
// Copy cover file
.then(function() {
return Q.all([
fs.copy(path.join(options.input, "cover.jpg"), path.join(options.output, "cover.jpg")),
fs.copy(path.join(options.input, "cover_small.jpg"), path.join(options.output, "cover_small.jpg"))
])
.fail(function() {
return Q();
})
})
// Return options to caller
.then(_.constant(options));
};
@@ -150,21 +212,6 @@ var generateBook = function(options) {
}
})
// Read config file
.then(function() {
return fs.readFile(path.resolve(options.input, options.configFile))
.then(function(_config) {
// Extend current config
_config = JSON.parse(_config);
_config = _.omit(_config, 'input', 'configFile');
_.extend(options, _config);
}, function() {
// No config file: not a big deal
return Q();
});
})
// Clean output folder
.then(function() {
return fs.remove(options.output);
@@ -210,22 +257,11 @@ var generateBook = function(options) {
return loadGenerator(options);
})
// Detect multi-languages book
// Convert files
.then(function(generator) {
// Generate the book
return Q()
// Read readme
.then(function() {
return fs.readFile(path.join(options.input, "README.md"), "utf-8")
.then(function(_readme) {
_readme = parse.readme(_readme);
options.title = options.title || _readme.title;
options.description = options.description || _readme.description || defaultDescription;
});
})
// Get summary
.then(function() {
return fs.readFile(path.join(options.input, "SUMMARY.md"), "utf-8")
+30
View File
@@ -1,6 +1,7 @@
var util = require("util");
var path = require("path");
var Q = require("q");
var _ = require("lodash");
var fs = require("../fs");
var parse = require("../../parse");
@@ -40,6 +41,35 @@ Generator.prototype.convertFile = function(content, input) {
});
};
// Generate languages index
// Contains the first languages readme and langs infos
Generator.prototype.langsIndex = function(langs) {
var that = this;
if (langs.list.length == 0) return Q.reject("Need at least one language");
var mainLang = _.first(langs.list).lang;
console.log("Main language is", mainLang);
return Q()
.then(function() {
return fs.readFile(
path.join(that.options.output, mainLang, "README.json")
);
})
.then(function(content) {
var json = JSON.parse(content);
_.extend(json, {
langs: langs.list
});
return fs.writeFile(
path.join(that.options.output, "README.json"),
JSON.stringify(json, null, 4)
);
});
};
Generator.prototype.finish = function() {
// ignore
};
+14 -11
View File
@@ -2,22 +2,12 @@ var _ = require("lodash");
var util = require("util");
var path = require("path");
var Q = require("q");
var swig = require('swig');
var hljs = require('highlight.js');
var swig = require("../template");
var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../site");
// Swig filter: highlight coloration
swig.setFilter('code', function(code, lang) {
try {
return hljs.highlight(lang, code).value;
} catch(e) {
return hljs.highlightAuto(code).value;
}
});
/*
* This generator will generate a simple index.html which can be converted as a PDF
@@ -61,22 +51,35 @@ Generator.prototype.convertFile = function(content, input) {
});
};
// Generate languages index
Generator.prototype.langsIndex = function(langs) {
return Q();
};
Generator.prototype.finish = function() {
var that = this;
var basePath = ".";
var output = path.join(this.options.output, "index.html");
var progress = parse.progress(this.options.navigation, "README.md");
return Q()
// Generate html
.then(function(pages) {
return that._writeTemplate(that.template, {
pages: that.pages,
progress: progress,
basePath: basePath,
staticBase: path.join(basePath, "gitbook"),
}, output);
})
// Copy cover
.then(function() {
return that.copyCover();
})
// Copy assets
.then(function() {
return fs.copy(
-56
View File
@@ -1,56 +0,0 @@
var util = require("util");
var path = require("path");
var Q = require("q");
var _ = require("lodash");
var exec = require('child_process').exec;
var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../page");
/*
* This generator inherits from the single page generator
* and convert the page output to pdf using gitbook-pdf
*/
var Generator = function() {
BaseGenerator.apply(this, arguments);
// Options for PDF generation
this.options = _.defaults(this.options, {
paperformat: "A4"
});
};
util.inherits(Generator, BaseGenerator);
Generator.prototype.finish = function() {
var that = this;
return BaseGenerator.prototype.finish.apply(this)
.then(function() {
var d = Q.defer();
var command = [
"gitbook-pdf",
"generate",
path.join(that.options.output, "index.html"),
path.join(that.options.output, "index.pdf"),
"--format="+that.options.paperformat
].join(" ");
exec(command, function (error, stdout, stderr) {
if (error) {
if (error.code == 127) {
error.message = "Need to install gitbook-pdf using: npm install gitbook-pdf -g";
} else {
error.message = error.message + " "+stdout;
}
return d.reject(error);
}
d.resolve();
});
return d.promise;
});
};
module.exports = Generator;
+17 -2
View File
@@ -160,6 +160,17 @@ Plugin.fromList = function(names, root) {
})
.object()
.value();
resources.html = {}
_.each(plugins, function(plugin) {
if (!plugin.infos.book || !plugin.infos.book.html) return;
var html = plugin.infos.book.html || {};
_.each(html, function(code, key) {
if (!_.isFunction(code)) code = _.constant(code);
if (!resources.html[key]) resources.html[key] = [];
resources.html[key].push(code);
})
});
return Q({
'list': plugins,
@@ -179,14 +190,18 @@ Plugin.fromList = function(names, root) {
if (!withTpl) return null;
return withTpl.resolveFile(withTpl.infos.templates[name]);
},
'html': function(tag, context, options) {
return _.map(resources.html[tag] || [], function(code) {
return code.call(context, options);
}).join("\n");
}
});
};
// Default plugins
Plugin.defaults = [
"mixpanel",
"mathjax"
];
module.exports = Plugin;
module.exports = Plugin;
+14 -18
View File
@@ -2,26 +2,16 @@ var util = require("util");
var path = require("path");
var Q = require("q");
var _ = require("lodash");
var swig = require('swig');
var swig = require("../template");
var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../generator");
var links = require("../../utils/links");
var indexer = require('./search_indexer');
var Manifest = require('../manifest');
// Swig filter for returning the count of lines in a code section
swig.setFilter('lines', function(content) {
return content.split('\n').length;
});
// Swig filter for returning a link to the associated html file of a markdown file
swig.setFilter('mdLink', function(link) {
var link = link.replace(".md", ".html");
if (link == "README.html") link = "index.html";
return link;
});
var Generator = function() {
BaseGenerator.apply(this, arguments);
@@ -63,7 +53,6 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
var that = this;
interpolate = interpolate || _.identity;
return Q()
.then(function(sections) {
return tpl(_.extend({
@@ -81,6 +70,7 @@ Generator.prototype._writeTemplate = function(tpl, options, output, interpolate)
plugins: that.plugins,
pluginsConfig: JSON.stringify(that.options.pluginsConfig),
htmlSnippet: _.partialRight(that.plugins.html, that, options),
options: that.options
}, options));
@@ -162,7 +152,7 @@ Generator.prototype.convertFile = function(content, _input) {
content: page.sections,
basePath: basePath,
staticBase: path.join(basePath, "gitbook"),
staticBase: links.join(basePath, "gitbook"),
}, output, function(html) {
page.content = html;
@@ -198,7 +188,7 @@ Generator.prototype.copyAssets = function() {
path.join(that.options.output, "gitbook")
)
// Add to cach manifest
// Add to cache manifest
.then(function() {
return that.manifest.addFolder(path.join(that.options.output, "gitbook"), "gitbook");
})
@@ -237,9 +227,15 @@ Generator.prototype.writeCacheManifest = function() {
};
Generator.prototype.finish = function() {
return this.copyAssets()
.then(this.writeSearchIndex)
.then(this.writeCacheManifest);
var deferred = this.copyAssets()
.then(this.copyCover)
.then(this.writeSearchIndex);
if (this.options.cache !== false) {
deferred = deferred.then(this.writeCacheManifest);
}
return deferred;
};
module.exports = Generator;
+52
View File
@@ -0,0 +1,52 @@
var path = require("path");
var swig = require('swig');
var hljs = require('highlight.js');
var links = require('../utils/').links;
var pkg = require('../../package.json');
swig.setDefaults({
locals: {
gitbook: {
version: pkg.version
}
}
});
// Swig filter for returning the count of lines in a code section
swig.setFilter('lines', function(content) {
return content.split('\n').length;
});
// Swig filter for returning a link to the associated html file of a markdown file
swig.setFilter('mdLink', function(link) {
var link = link.replace(".md", ".html");
if (link == "README.html") link = "index.html";
return link;
});
// Swig filter: highlight coloration
swig.setFilter('code', function(code, lang) {
try {
return hljs.highlight(lang, code).value;
} catch(e) {
return hljs.highlightAuto(code).value;
}
});
// Convert a level into a deep level
swig.setFilter('lvl', function(lvl) {
return lvl.split(".").length;
});
// Join path
swig.setFilter('pathJoin', function(base, _path) {
return path.join(base, _path);
});
// Is a link an absolute link
swig.setFilter('isExternalLink', function(link) {
return links.isExternal(link);
});
module.exports = swig;
+1 -1
View File
@@ -8,7 +8,7 @@ function clean(obj) {
function flattenChapters(chapters) {
return _.reduce(chapters, function(accu, chapter) {
return accu.concat([clean(chapter)].concat(chapter.articles));
return accu.concat([clean(chapter)].concat(flattenChapters(chapter.articles)));
}, []);
}
+2 -2
View File
@@ -12,7 +12,7 @@ var calculProgress = function(navigation, current) {
return nav;
})
.sortBy(function(nav) {
return nav.level;
return parseFloat(nav.level);
})
.map(function(nav, i) {
// Calcul percent
@@ -27,7 +27,7 @@ var calculProgress = function(navigation, current) {
} else if (done) {
prevPercent = nav.percent;
}
return nav;
})
.value();
+18 -5
View File
@@ -1,5 +1,6 @@
var _ = require('lodash');
var marked = require('marked');
var textRenderer = require('marked-text-renderer');
function extractFirstNode(nodes, nType) {
return _.chain(nodes)
@@ -14,16 +15,28 @@ function extractFirstNode(nodes, nType) {
function parseReadme(src) {
var nodes, title, description;
var renderer = textRenderer();
// Parse content
nodes = marked.lexer(src);
var title = extractFirstNode(nodes, "heading");
var description = extractFirstNode(nodes, "paragraph");
title = extractFirstNode(nodes, "heading") || '';
description = extractFirstNode(nodes, "paragraph") || '';
var convert = _.compose(
function(text) {
return _.unescape(text.replace(/(\r\n|\n|\r)/gm, ""));
},
function(text) {
return marked.parse(text, _.extend({}, marked.defaults, {
renderer: renderer
}));
}
);
return {
title: title,
description: description
title: convert(title),
description: convert(description)
};
}
+8 -8
View File
@@ -86,13 +86,11 @@ function parseTitle(src, nums) {
};
}
function parseArticle(chapterNum, nodes, idx) {
return parseTitle(_.first(nodes).text, [chapterNum, idx+1]);
}
function parseChapter(nodes, idx) {
return _.extend(parseTitle(_.first(nodes).text, [idx+1]), {
articles: _.map(listSplit(filterList(nodes), 'list_item_start', 'list_item_end'), parseArticle.bind(null, idx+1))
function parseChapter(nodes, nums) {
return _.extend(parseTitle(_.first(nodes).text, nums), {
articles: _.map(listSplit(filterList(nodes), 'list_item_start', 'list_item_end'), function(nodes, i) {
return parseChapter(nodes, nums.concat(i + 1));
})
});
}
@@ -104,7 +102,9 @@ function parseSummary(src) {
// Split out chapter sections
var chapters = _.chain(listSplit(chapterList, 'list_item_start', 'list_item_end'))
.map(parseChapter)
.map(function(nodes, i) {
return parseChapter(nodes, [i + 1]);
})
.value();
return {
+25 -2
View File
@@ -1,6 +1,11 @@
var url = require('url');
var path = require('path');
// Is the link an external link
var isExternal = function(href) {
return Boolean(url.parse(href).protocol);
};
// Return true if the link is relative
var isRelative = function(href) {
var parsed = url.parse(href);
@@ -19,11 +24,29 @@ var toAbsolute = function(_href, dir, outdir) {
// make it relative to output
_href = path.relative(outdir, _href);
if (process.platform === 'win32') {
_href = _href.replace(/\\/g, '/');
}
return _href;
};
// Join links
var join = function() {
var _href = path.join.apply(path, arguments);
if (process.platform === 'win32') {
_href = _href.replace(/\\/g, '/');
}
return _href;
};
module.exports = {
isRelative: isRelative,
toAbsolute: toAbsolute
};
isExternal: isExternal,
toAbsolute: toAbsolute,
join: join
};
+26
View File
@@ -0,0 +1,26 @@
var _ = require("lodash");
function escapeShellArg(arg) {
var ret = '';
ret = arg.replace(/"/g, '\\"');
return "\"" + ret + "\"";
}
function optionsToShellArgs(options) {
return _.chain(options)
.map(function(value, key) {
if (value == null || value == false) return null;
if (value == true) return key;
return key+"="+escapeShellArg(value);
})
.compact()
.value()
.join(" ");
}
module.exports = {
escapeShellArg: escapeShellArg,
optionsToShellArgs: optionsToShellArgs
};
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "gitbook",
"version": "0.4.3",
"version": "0.5.3",
"homepage": "http://www.gitbook.io/",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
@@ -20,10 +20,10 @@
"semver": "2.2.1",
"gaze": "~0.5.1",
"resolve": "0.6.3",
"tiny-lr-fork": "0.0.5",
"gitbook-plugin": "0.0.2",
"gitbook-plugin-mixpanel": "0.0.2",
"gitbook-plugin-mathjax": "0.0.3"
"gitbook-plugin-mathjax": "0.0.3",
"gitbook-plugin-livereload": "0.0.1"
},
"devDependencies": {
"mocha": "1.18.2",
+2
View File
@@ -3,6 +3,8 @@
* [Chapter 1](chapter-1/README.md)
* [Article 1](chapter-1/ARTICLE1.md)
* [Article 2](chapter-1/ARTICLE2.md)
* [article 1.2.1](chapter-1/ARTICLE-1-2-1.md)
* [article 1.2.2](chapter-1/ARTICLE-1-2-2.md)
* [Chapter 2](chapter-2/README.md)
* [Chapter 3](chapter-3/README.md)
* [Chapter 4](chapter-4/README.md)
+12 -2
View File
@@ -18,6 +18,8 @@ describe('Summary navigation', function() {
'chapter-1/ARTICLE1.md',
'chapter-1/ARTICLE2.md',
'chapter-2/README.md',
'chapter-1/ARTICLE-1-2-1.md',
'chapter-1/ARTICLE-1-2-2.md'
]);
// Make sure it found the files we gave it
@@ -26,6 +28,8 @@ describe('Summary navigation', function() {
assert(nav['chapter-1/ARTICLE1.md']);
assert(nav['chapter-1/ARTICLE2.md']);
assert(nav['chapter-2/README.md']);
assert(nav['chapter-1/ARTICLE-1-2-1.md']);
assert(nav['chapter-1/ARTICLE-1-2-2.md']);
assert.equal(nav['README.md'].prev, null);
@@ -38,9 +42,15 @@ describe('Summary navigation', function() {
assert.equal(nav['chapter-1/ARTICLE1.md'].next.path, 'chapter-1/ARTICLE2.md');
assert.equal(nav['chapter-1/ARTICLE2.md'].prev.path, 'chapter-1/ARTICLE1.md');
assert.equal(nav['chapter-1/ARTICLE2.md'].next.path, 'chapter-2/README.md');
assert.equal(nav['chapter-1/ARTICLE2.md'].next.path, 'chapter-1/ARTICLE-1-2-1.md');
assert.equal(nav['chapter-2/README.md'].prev.path, 'chapter-1/ARTICLE2.md');
assert.equal(nav['chapter-1/ARTICLE-1-2-1.md'].prev.path, 'chapter-1/ARTICLE2.md');
assert.equal(nav['chapter-1/ARTICLE-1-2-1.md'].next.path, 'chapter-1/ARTICLE-1-2-2.md');
assert.equal(nav['chapter-1/ARTICLE-1-2-2.md'].prev.path, 'chapter-1/ARTICLE-1-2-1.md');
assert.equal(nav['chapter-1/ARTICLE-1-2-2.md'].next.path, 'chapter-2/README.md');
assert.equal(nav['chapter-2/README.md'].prev.path, 'chapter-1/ARTICLE-1-2-2.md');
assert.equal(nav['chapter-2/README.md'].next.path, 'chapter-3/README.md');
});
+1
View File
@@ -50,5 +50,6 @@ describe('Summary parsing', function () {
assert.equal(c[0].articles[0].level, '1.1');
assert.equal(c[0].articles[1].level, '1.2');
assert.equal(c[0].articles[1].articles[0].level, '1.2.1');
});
});
+1 -1
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5 -1
View File
@@ -1,9 +1,13 @@
define([
"jQuery",
"ace/ace",
"ace/theme-tomorrow",
"ace/mode-javascript",
"utils/execute",
"core/events",
"core/state"
], function($, execute, events, state){
], function($, _ace, _aceTheme, _aceMode, execute, events, state){
// Bind an exercise
var prepareExercise = function($exercise) {
var codeSolution = $exercise.find(".code-solution").text();
+22 -27
View File
@@ -30,40 +30,23 @@ define([
};
var enlargeFontSize = function(e){
var $bookBody = $(".book-body");
if (fontState.size < 4){
$bookBody.toggleClass("font-size-"+fontState.size, false);
fontState.size++;
$bookBody.toggleClass("font-size-"+fontState.size, true);
fontState.save();
}
};
var reduceFontSize = function(e){
var $bookBody = $(".book-body");
if (fontState.size > 0){
$bookBody.toggleClass("font-size-"+fontState.size);
fontState.size--;
$bookBody.toggleClass("font-size-"+fontState.size);
fontState.save();
}
};
var changeFontFamily = function(){
var $bookBody = $(".book-body");
var index = $(this).data("font");
$bookBody.toggleClass("font-family-"+fontState.family);
$(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")")
.removeClass("active");
fontState.family = index;
$bookBody.toggleClass("font-family-"+fontState.family);
$(this).addClass("active");
fontState.save();
};
@@ -81,6 +64,22 @@ define([
fontState.save();
};
var update = function() {
var $book = $(".book");
$(".font-settings .font-family-list li").removeClass("active");
$(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")").addClass("active");
$book[0].className = $book[0].className.replace(/\bfont-\S+/g, '');
$book.addClass("font-size-"+fontState.size);
$book.addClass("font-family-"+fontState.family);
if(fontState.theme !== 0) {
$book[0].className = $book[0].className.replace(/\bcolor-theme-\S+/g, '');
$book.addClass("color-theme-"+fontState.theme);
}
};
var init = function(config) {
var $toggle, $bookBody, $dropdown, $book;
@@ -92,21 +91,16 @@ define([
// Instantiate font state object
fontState = storage.get("fontState", {
size: config.size || 1,
family: FAMILY[config.family || "serif"],
size: config.size || 2,
family: FAMILY[config.family || "sans"],
theme: THEMES[config.theme || "white"]
});
fontState.save = function(){
storage.set("fontState",fontState);
update();
};
$bookBody.addClass("font-size-"+fontState.size);
$bookBody.addClass("font-family-"+fontState.family);
$(".font-settings .font-family-list li:nth-child("+(fontState.family+1)+")").addClass("active");
if(fontState.theme !== 0)
$book.addClass("color-theme-"+fontState.theme);
update();
//Add event listeners
$(document).on('click', "#enlarge-font-size", enlargeFontSize);
@@ -121,6 +115,7 @@ define([
};
return {
init: init
init: init,
update: update
}
});
+2 -4
View File
@@ -2,11 +2,9 @@ define([
"jQuery"
], function($) {
var showLoading = function(p) {
var $book = $(".book");
$book.addClass("is-loading");
$(".book").addClass("is-loading");
p.always(function() {
$book.removeClass("is-loading");
$(".book").removeClass("is-loading");
});
return p;
+3 -5
View File
@@ -3,12 +3,11 @@ define([
"utils/url",
"core/events",
"core/state",
"core/search",
"core/progress",
"core/exercise",
"core/quiz",
"core/loading"
], function($, URL, events, state, search, progress, exercises, quiz, loading) {
], function($, URL, events, state, progress, exercises, quiz, loading) {
var prev, next;
var githubCountStars, githubCountWatch;
@@ -47,10 +46,12 @@ define([
$("head").html(headContent);
// Merge body
var bodyClass = $(".book").attr("class");
var scrollPosition = $('.book-summary .summary').scrollTop();
$pageBody.toggleClass("with-summary", $(".book").hasClass("with-summary"))
$(".book").replaceWith($pageBody);
$(".book").attr("class", bodyClass);
$('.book-summary .summary').scrollTop(scrollPosition);
// Update state
@@ -94,9 +95,6 @@ define([
// Focus on content
$pageWrapper.focus();
// Prepare search bar
search.prepare();
// Update GitHub count
if (state.githubId) {
if (githubCountStars) {
+5 -8
View File
@@ -67,12 +67,10 @@ define([
e.preventDefault();
toggleSearch();
});
};
var prepare = function() {
var $searchInput = $(".book-search input");
$searchInput.keyup(function(e) {
// Type in search bar
$(document).on("keyup", ".book-search input", function(e) {
var key = (e.keyCode ? e.keyCode : e.which);
var q = $(this).val();
@@ -89,13 +87,12 @@ define([
_.pluck(results, "path")
);
}
});
}
})
};
return {
init: init,
search: search,
toggle: toggleSearch,
prepare: prepare
toggle: toggleSearch
};
});
+4 -4
View File
@@ -1,11 +1,10 @@
define([
"jQuery",
"lodash",
"utils/storage",
"utils/platform",
"core/state"
], function(_, storage, platform, state) {
var $summary = state.$book.find(".book-summary");
], function($, _, storage, platform, state) {
// Toggle sidebar with or withour animation
var toggleSidebar = function(_state, animation) {
if (state != null && isOpen() == _state) return;
@@ -38,6 +37,8 @@ define([
// Filter summary with a list of path
var filterSummary = function(paths) {
var $summary = $(".book-summary");
$summary.find("li").each(function() {
var path = $(this).data("path");
var st = paths == null || _.contains(paths, path);
@@ -48,7 +49,6 @@ define([
};
return {
$el: $summary,
init: init,
toggle: toggleSidebar,
filter: filterSummary
+43
View File
@@ -0,0 +1,43 @@
@import "mixins.less";
@import "ebook/variables.less";
@import "ebook/highlight.less";
.book-chapter {
display: none;
}
article {
page-break-after: always;
}
pre, blockquote {
border: 1px solid #999;
page-break-inside: avoid;
background: #f1f1f1;
padding: 8px;
}
img {
max-width: 100% !important;
page-break-inside: avoid;
margin: 0px auto;
}
.exercise, .quiz {
margin: 1cm 0cm;
padding: 0.4cm;
page-break-inside: avoid;
border: 3px solid #ddd;
.exercise-header {
margin-bottom: 0.4cm;
padding-bottom: 0.2cm;
border-bottom: 1px solid #ddd;
}
.question {
margin-top: 0.4cm;
}
}
+1
View File
@@ -0,0 +1 @@
@font-size-base: 13px;
+1 -1
View File
@@ -4,4 +4,4 @@
&:hover, &:focus {
color: inherit;
}
}
}
-115
View File
@@ -1,115 +0,0 @@
@import "vendors/bootstrap/bootstrap.less";
@import "vendors/fontawesome/font-awesome.less";
@import "mixins.less";
@import "variables.less";
@import "fonts.less";
@import "page/highlight.less";
@font-size-base: 13px;
* {
-webkit-overflow-scrolling: touch;
-webkit-tap-highlight-color: transparent;
-webkit-text-size-adjust: none;
-webkit-touch-callout: none;
-webkit-font-smoothing: antialiased;
}
html, body {
height: 100%;
}
body {
text-rendering: optimizeLegibility;
font-smoothing: antialiased;
font-family: @font-family-base;
}
h1, h2, h3 {
page-break-after: avoid;
page-break-before: auto;
}
h1 { font-size: floor(@font-size-base * 2.15); }
h2 { font-size: floor(@font-size-base * 1.70); }
h3 { font-size: ceil(@font-size-base * 1.25); }
h4 { font-size: ceil(@font-size-base * 1); }
h5 { font-size: ceil(@font-size-base * 0.85); }
h6 { font-size: ceil(@font-size-base * 0.65); }
pre, blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
img {
max-width: 100% !important;
page-break-inside: avoid;
}
section {
page-break-after: always;
&#cover {
padding: 3cm 0cm;
text-align: center;
h1 {
font-size: 1.5cm;
}
}
&#summary {
margin: 1.5cm;
h1 {
text-align: center;
}
ol {
list-style: none;
padding: 0px;
margin: 0px;
margin-left: 1cm;
}
> ol {
> li {
}
}
}
article {
margin-bottom: 1.5cm;
&.new-chapter {
page-break-after: always;
font-size: 0.6cm;
text-align: center;
padding: 3cm 0cm;
h1 {
font-size: floor(@font-size-base * 2.7);
}
}
.exercise {
margin: 1cm 0cm;
padding: 0.4cm;
page-break-inside: avoid;
border: 3px solid #ddd;
.exercise-header {
margin-bottom: 0.4cm;
padding-bottom: 0.2cm;
border-bottom: 1px solid #ddd;
}
}
}
}
@@ -2,19 +2,19 @@
@import "vendors/fontawesome/font-awesome.less";
@import "mixins.less";
@import "variables.less";
@import "fonts.less";
@import "book/languages.less";
@import "book/header.less";
@import "book/summary.less";
@import "book/font-settings.less";
@import "book/body.less";
@import "book/exercise.less";
@import "book/quiz.less";
@import "book/markdown.less";
@import "book/progress.less";
@import "book/navigation.less";
@import "website/fonts.less";
@import "website/variables.less";
@import "website/languages.less";
@import "website/header.less";
@import "website/summary.less";
@import "website/font-settings.less";
@import "website/body.less";
@import "website/exercise.less";
@import "website/quiz.less";
@import "website/markdown.less";
@import "website/progress.less";
@import "website/navigation.less";
* {
-webkit-overflow-scrolling: touch;
@@ -37,7 +37,8 @@
background: @page-background;
border-radius: 2px;
line-height: 1.5em;
line-height: @content-line-height;
font-size: @default-font-size;
}
.btn-group {
@@ -59,28 +60,6 @@
min-height: calc(~"100% - 57px")
}
}
&.font-size-0{
font-size:@s-font-size;
}
&.font-size-1{
font-size:@m-font-size;
}
&.font-size-2{
font-size:@l-font-size;
}
&.font-size-3{
font-size:@xl-font-size;
}
&.font-size-4{
font-size:@xxl-font-size;
}
&.font-family-0{
font-family: @font-family-serif;
}
&.font-family-1{
font-family: @font-family-sans;
}
}
&.with-summary {
@@ -122,4 +101,37 @@
}
}
}
&.font-size-0 {
.book-body {
font-size:@s-font-size;
}
}
&.font-size-1 {
.book-body {
font-size:@m-font-size;
}
}
&.font-size-2 {
.book-body {
font-size:@l-font-size;
}
}
&.font-size-3 {
.book-body {
font-size:@xl-font-size;
}
}
&.font-size-4 {
.book-body {
font-size:@xxl-font-size;
}
}
&.font-family-0{
font-family: @font-family-serif;
}
&.font-family-1{
font-family: @font-family-sans;
}
}
@@ -1,7 +1,7 @@
.book .book-body .page-wrapper .page-inner {
section.exercise {
padding: 0px;
margin: 20px 0px;
margin: 20px 15px;
border: 3px solid #2f8cde;
.header {
+8 -56
View File
@@ -1,15 +1,3 @@
@font-face {
font-family: 'EB Garamond';
font-style: normal;
font-weight: 400;
src: local('EB Garamond 12 Regular'),url('@{FontPath}/ebgaramond/400.woff') format('woff');
}
@font-face {
font-family: 'EB Garamond';
font-style: italic;
font-weight: 400i;
src: local('EB Garamond 12 Italic'),url('@{FontPath}/ebgaramond/400i.woff') format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
@@ -19,7 +7,7 @@
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 250i;
font-weight: 250;
src: local('Merriweather Light Italic'),url('@{FontPath}/merriweather/250i.woff') format('woff');
}
@font-face {
@@ -31,21 +19,9 @@
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 400i;
font-weight: 400;
src: local('Merriweather Italic'),url('@{FontPath}/merriweather/400i.woff') format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 600;
src: local(''),url('@{FontPath}/merriweather/600.woff') format('woff');
}
/*@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 600i;
src: local(''),url('@{FontPath}/merriweather/600i.woff') format('woff');
}*/
@font-face {
font-family: 'Merriweather';
font-style: normal;
@@ -55,7 +31,7 @@
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 700i;
font-weight: 700;
src: local('Merriweather Bold Italic'),url('@{FontPath}/merriweather/700i.woff') format('woff');
}
@font-face {
@@ -67,33 +43,9 @@
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 900i;
font-weight: 900;
src: local('Merriweather Heavy Italic'),url('@{FontPath}/merriweather/900i.woff') format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: normal;
font-weight: 400;
src: local('Anonymous Pro'),url('@{FontPath}/anonymouspro/400.woff') format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: italic;
font-weight: 400i;
src: local('Anonymous Pro Italic'),url('@{FontPath}/anonymouspro/400i.woff') format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: normal;
font-weight: 700;
src: local('Anonymous Pro Bold'),url('@{FontPath}/anonymouspro/700.woff') format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: italic;
font-weight: 700i;
src: local('Anonymous Pro Bold Italic'),url('@{FontPath}/anonymouspro/700i.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
@@ -103,7 +55,7 @@
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300i;
font-weight: 300;
src: local('Open Sans Light Italic'),url('@{FontPath}/opensans/300i.woff') format('woff');
}
@font-face {
@@ -115,7 +67,7 @@
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400i;
font-weight: 400;
src: local('Open Sans Italic'),url('@{FontPath}/opensans/400i.woff') format('woff');
}
@font-face {
@@ -127,7 +79,7 @@
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 600i;
font-weight: 600;
src: local('Open Sans Semibold Italic'),url('@{FontPath}/opensans/600i.woff') format('woff');
}
@font-face {
@@ -139,6 +91,6 @@
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700i;
font-weight: 700;
src: local('Open Sans Bold Italic'),url('@{FontPath}/opensans/700i.woff') format('woff');
}
@@ -13,7 +13,7 @@
font-size: 0.85em;
color: @header-color;
background: @header-background;
box-shadow: 0 1px 2px hsla(200,10%,80%,0.6);
border-bottom: 1px solid @header-border;
.btn {
display: block;
@@ -24,6 +24,7 @@
padding-bottom: 25px;
padding-top: 15px;
color:@page-color;
letter-spacing: 0.01rem;
& > *:first-child {
margin-top: 0 !important; }
@@ -13,15 +13,15 @@
flex-direction: column;
font-size: 40px;
color: rgba(0,0,0,0.5);
color: rgba(0, 0, 0, 0.2);
text-align: center;
.transition(all 350ms ease);
&:hover {
background-color: @body-pagination-background;
text-decoration: none;
color: rgba(0, 0, 0, 0.6);
}
&.navigation-next {
@@ -50,11 +50,9 @@
}
.book.color-theme-1 .book-body {
.navigation:hover{
background-color: @body-pagination-background-1;
}
}
.book.color-theme-2 .book-body {
.navigation:hover{
background-color: @body-pagination-background-2;
}
}
@@ -1,7 +1,7 @@
.book .book-body .page-wrapper .page-inner {
section.quiz {
padding: 0px;
margin: 20px 0px;
margin: 20px 15px;
border: 3px solid #2f8cde;
.header {
@@ -11,7 +11,7 @@
width: @sidebar-width;
color: @sidebar-color;
background: @sidebar-background;
box-shadow: inset -1px 0 5px hsla(0, 0%, 0%, 0.1);
border-right: 1px solid @sidebar-border;
.transition(all 0.5s ease);
@@ -57,7 +57,6 @@
margin: 7px 0;
overflow: hidden;
background: @sidebar-divider-color;
box-shadow: 0 1px rgba(255,255,255,0.7);
}
i.fa-check {
@@ -90,7 +89,6 @@
overflow: hidden;
white-space: nowrap;
position: relative;
padding-left: 25px;
}
span {
+36 -33
View File
@@ -7,40 +7,44 @@
@header-height: 50px;
@header-color: hsl(194, 5%, 52%);
@header-background: white;
@header-border: rgba(0, 0, 0, 0.07);
@header-button-color: hsl(194, 5%, 52%);
@header-button-hover-color: #151515;
@header-button-hover-background: hsl(207, 15%, 95%);
// Body
@body-background: white;
@body-pagination-background: hsl(207, 15%, 95%);
// Sidebar
@sidebar-width: 250px;
@sidebar-breakpoint: 600px;
@sidebar-color: hsl(207, 15%, 80%);
@sidebar-background: hsl(207, 15%, 95%);
@sidebar-background: @body-background;
@sidebar-border: @header-border;
@sidebar-nested-padding: 10px;
@sidebar-nested-padding: 20px;
@sidebar-search-padding: 6px;
@sidebar-search-background: transparent;
@sidebar-search-input-border-color: hsl(207, 15%, 80%);
@sidebar-search-input-border-color: @sidebar-border;
@sidebar-divider-color: hsl(207, 15%, 85%);
@sidebar-divider-color: @sidebar-border;
@sidebar-link-color: hsl(207, 15%, 50%);
@sidebar-link-color: hsl(207, 15%, 25%);
@sidebar-link-background: transparent;
@sidebar-link-hover-color: hsl(207, 100%, 50%);
@sidebar-link-hover-background: transparent;
@sidebar-icon-color: @bar-progress-background;
@sidebar-link-completed: hsl(207, 15%, 25%);
@sidebar-link-completed: @sidebar-link-color;
@sidebar-link-completed-weight: normal;
// Page
@page-color: black;
@page-background: white;
@page-color: black;
@page-background: @body-background;
// Content
@content-line-height: 1.6em;
// Progress Bar
@chapter-display: none;
@@ -77,26 +81,27 @@
@border-radius-small: 1px;
// Fonts
@font-family-serif: Merriweather, "EB Garamond", Georgia, serif;
@font-family-serif: "Merriweather", Georgia, serif;
@font-family-sans: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-base: @font-family-serif;
@font-family-base: @font-family-sans;
@headings-font-family: inherit;
@FontPath: '@{staticPath}/fonts';
@fa-font-path: "@{FontPath}/fontawesome";
@s-font-size: 1.2rem;
@m-font-size: 1.4rem;
@l-font-size: 1.6rem;
@xl-font-size: 2.2rem;
@xxl-font-size: 4.0rem;
@s-font-size: 1.2rem;
@m-font-size: 1.4rem;
@l-font-size: 1.6rem;
@xl-font-size: 2.2rem;
@xxl-font-size: 4.0rem;
@default-font-size: @l-font-size;
/*
,--------.,--.
'--. .--'| ,---. ,---. ,--,--,--. ,---. ,---. .--.
| | | .-. || .-. :| || .-. :( .-' '--'
| | | | | |\ --.| | | |\ --..-' `).--.
`--' `--' `--' `----'`--`--`--' `----'`----' '--'
/*
,--------.,--.
'--. .--'| ,---. ,---. ,--,--,--. ,---. ,---. .--.
| | | .-. || .-. :| || .-. :( .-' '--'
| | | | | |\ --.| | | |\ --..-' `).--.
`--' `--' `--' `----'`--`--`--' `----'`----' '--'
*/
// Header
@header-color-1: #AFA790;
@@ -113,21 +118,19 @@
// Body
@body-background-1: #F3EACB;
@body-background-2: #1d1f21;
@body-pagination-background-1: #FFFAEA;
@body-pagination-background-2: #33404D;
// Sidebar
@sidebar-color-1: #AFA790;
@sidebar-color-2: hsl(207, 15%, 80%);
@sidebar-background-1: #F3EACB;
@sidebar-background-2: #111111;
@sidebar-background-1: @body-background-1;
@sidebar-background-2: @body-background-2;
@sidebar-search-background-1: transparent;
@sidebar-search-background-2: transparent;
@sidebar-search-input-border-color-1: #D6CFBA;
@sidebar-search-input-border-color-2: #c4cdd4;
@sidebar-search-input-border-color-2: #000;
@sidebar-divider-color-1: hsl(207, 15%, 85%);
@sidebar-divider-color-1: @sidebar-divider-color;
@sidebar-divider-color-2: #1d1f21;
@sidebar-link-color-1: #877F6A;
@@ -141,14 +144,14 @@
@sidebar-icon-color-1: @bar-progress-background;
@sidebar-icon-color-2: @bar-progress-background;
@sidebar-link-completed-1: hsl(207, 15%, 25%);
@sidebar-link-completed-2: hsl(207, 15%, 25%);
@sidebar-link-completed-1: @sidebar-link-color-1;
@sidebar-link-completed-2: @sidebar-link-color-2;
@sidebar-link-completed-weight-1: normal;
@sidebar-link-completed-weight-2: normal;
// Page
@page-color-1: #704214;
@page-color-2: #a4b1b1;
@page-color-1: #704214;
@page-color-2: #a4b1b1;
@page-background-1: #F3EACB;
@page-background-2: #1d1f21;
+1 -1
View File
@@ -1,9 +1,9 @@
<div class="book-header">
<!-- Actions Left -->
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
{% if options.links.home !== false and (options.links.home != null or githubId) %}
<a href="{{ options.links.home|default(githubHost+githubId) }}" target="_blank" class="btn pull-left home-bookmark" aria-label="GitHub home"><i class="fa fa-bookmark-o"></i></a>
{% endif %}
<a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
<a href="#" class="btn pull-left toggle-search" aria-label="Toggle search"><i class="fa fa-search"></i></a>
<span id="font-settings-wrapper">
<a href="#" class="btn pull-left toggle-font-settings" aria-label="Toggle font settings"><i class="fa fa-font"></i>
+32 -27
View File
@@ -1,59 +1,64 @@
{% macro articles(_articles) %}
{% for item in _articles %}
{% set externalLink = item.path|isExternalLink %}
<li class="chapter {% if item._path == _input %}active{% endif %}" data-level="{{ item.level }}" {% if item.path && !externalLink %}data-path="{{ item.path|mdLink }}"{% endif %}>
{% if item.path %}
{% if !externalLink %}
<a href="{{ basePath }}/{{ item.path|mdLink }}">
<i class="fa fa-check"></i> <b>{{ item.level }}.</b> {{ item.title }}
</a>
{% else %}
<a target="_blank" href="{{ item.path }}">
<i class="fa fa-check"></i> <b>{{ item.level }}.</b> {{ item.title }}
</a>
{% endif %}
{% else %}
<span><b>{{ item.level }}.</b> {{ item.title }}</span>
{% endif %}
{% if item.articles.length > 0 %}
<ul class="articles">
{{ articles(item.articles) }}
</ul>
{% endif %}
</li>
{% endfor %}
{% endmacro %}
<div class="book-summary">
<div class="book-search">
<input type="text" placeholder="Search" class="form-control" />
</div>
<ul class="summary">
{% set _divider = false %}
{% if options.links.about !== false && (options.links.about || githubId) %}
{% set _divider = true %}
<li>
<a href="{{ options.links.about|default(githubHost+githubAuthor) }}" target="blank" class="author-link">About the author</a>
</li>
{% endif %}
{% if options.links.issues !== false && (options.links.issues || githubId) %}
{% set _divider = true %}
<li>
<a href="{{ options.links.issues|default(githubHost+githubId+"/issues") }}" target="blank"class="issues-link">Questions and Issues</a>
</li>
{% endif %}
{% if options.links.contribute !== false && (options.links.contribute || githubId) %}
{% set _divider = true %}
<li>
<a href="{{ options.links.contribute|default(githubHost+githubId+"/edit/master/"+_input) }}" target="blank" class="contribute-link">Edit and Contribute</a>
</li>
{% endif %}
{% if options.links.contribute || options.links.issues || options.links.about %}
{% if _divider %}
<li class="divider"></li>
{% endif %}
<li data-level="0" data-path="index.html">
<a href="{{ basePath }}/"><i class="fa fa-check"></i> Introduction</a>
</li>
{% for item in summary.chapters %}
<li class="chapter {% if item._path == _input %}active{% endif %}" data-level="{{ item.level }}" {% if item.path %}data-path="{{ item.path|mdLink }}"{% endif %}>
{% if item.path %}
<a href="{{ basePath }}/{{ item.path|mdLink }}">
<i class="fa fa-check"></i> <b>{{ item.level }}.</b> {{ item.title }}
</a>
{% else %}
<span><b>{{ item.level }}.</b> {{ item.title }}</span>
{% endif %}
{% if item.articles.length > 0 %}
<ul class="articles">
{% for article in item.articles %}
<li {% if article._path == _input %}class="active"{% endif %} data-level="{{ article.level }}" {% if article.path %}data-path="{{ article.path|mdLink }}"{% endif %}>
{% if article.path %}
<a href="{{ basePath }}/{{ article.path|mdLink }}">
<i class="fa fa-check"></i> <b>{{ article.level }}.</b> {{ article.title }}
</a>
{% else %}
<span><b>{{ article.level }}.</b> {{ article.title }}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
{{ articles(summary.chapters) }}
{% if options.links.gitbook !== false %}
<li class="divider"></li>
+5 -1
View File
@@ -2,6 +2,10 @@
{% block title %}{{ title }}{% endblock %}
{% block style %}
<link rel="stylesheet" href="{{ staticBase }}/style.css">
{% endblock %}
{% block content %}
<div class="book-langs-index">
<div class="inner">
@@ -10,7 +14,7 @@
<ul class="languages">
{% for lang in langs %}
<li>
<a href="{{ basePath}}/{{ lang.path }}">{{ lang.title }}</a>
<a href="{{ basePath}}/{{ lang.path|pathJoin("/index.html") }}">{{ lang.title }}</a>
</li>
{% endfor %}
</ul>
+14 -36
View File
@@ -1,49 +1,27 @@
<!DOCTYPE HTML>
<html lang="en-US" {% block htmlTag %}{% endblock %}>
<head prefix="og: http://ogp.me/ns# book: http://ogp.me/ns/book#">
{% block head %}
{{ htmlSnippet("html:start")|default("") }}
<head>
{{ htmlSnippet("head:start")|default("") }}
<meta charset="UTF-8">
<title>{% block title %} | {{ title }}{% endblock %}</title>
<title>{% block title %}{% endblock %}</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="robots" content="index, follow">
<meta name="author" content="{{ githubAuthor }}">
<meta name="description" content="{{ description }}">
<meta name="keywords" content="gitbook,github" >
<meta name="generator" content="www.gitbook.io">
{% if progress.current.next and progress.current.next.path %}
<link rel="next" href="{{ basePath }}/{{ progress.current.next.path|mdLink }}" />
{% endif %}
{% if progress.current.prev and progress.current.prev.path %}
<link rel="prev" href="{{ basePath }}/{{ progress.current.prev.path|mdLink }}" />
{% endif %}
<meta property="og:title" content="{% block title %} | {{ title }}{% endblock %}">
<meta property="og:site_name" content="{{ title }}">
<meta property="og:type" content="book">
<meta property="og:locale" content="en_US">
<meta property="book:author" content="{{ githubHost }}{{ githubAuthor }}">
<meta property="book:tag" content="GitBook">
<meta name="description" content="{% block description %}{% endblock %}">
<meta name="generator" content="GitBook {{ gitbook.version }}">
<meta name="HandheldFriendly" content="true"/>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="shortcut icon" href="{{ staticBase }}/images/favicon.ico" type="image/x-icon">
{% endblock %}
{% block head %}{% endblock %}
{{ htmlSnippet("head:end")|default("") }}
</head>
<body>
{% block style %}
<link rel="stylesheet" href="{{ staticBase }}/style.css">
{% endblock %}
{{ htmlSnippet("body:start")|default("") }}
{% block style %}{% endblock %}
{% block content %}{% endblock %}
{% block javascript %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/mode-javascript.js"></script>
<script src="{{ staticBase }}/jsrepl/jsrepl.js" id="jsrepl-script"></script>
<script src="{{ staticBase }}/app.js"></script>
{% endblock %}
{% block javascript %}{% endblock %}
{{ htmlSnippet("body:end")|default("") }}
</body>
{{ htmlSnippet("html:end")|default("") }}
</html>
+45 -94
View File
@@ -20,10 +20,15 @@
</div>
{% elif section.type == "quiz" %}
<div class="quiz">
<div class="exercise-header">Exercise #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% autoescape false %}{{ section.quiz.base }}{% endautoescape %}
{% set exercise = exercise + 1 %}
<div class="exercise-header">Quiz #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% for quiz in section.quiz %}
<div class="question">
<div class="question-header">Question {{ loop.index }} of {{ section.quiz.length }}</div>
{% autoescape false %}{{ quiz.base }}{% endautoescape %}
</div>
{% endfor %}
{% set exercise = exercise + 1 %}
</div>
{% endif %}
{% endfor %}
@@ -31,104 +36,50 @@
{% set exercise = 1 %}
{% block content %}
{# Cover #}
<section id="cover">
<h1>{{ title }}</h1>
{% if githubId %}
<h2>By <a href="{{ githubHost }}{{ githubAuthor }}">@{{ githubAuthor }}</a></h2>
{% endif %}
</section>
{# Summary #}
<section id="summary">
<h1>Table of Contents</h1>
<ol>
<li>
<a href="#README.md">
<h2>Introduction</h2>
</a>
</li>
{% for item in summary.chapters %}
<li>
<h2><span>{{ item.level }}.</span> <a href="#{{ item.path }}">{{ item.title }}</a></h2>
{% if item.articles.length > 0 %}
<ol>
{% for article in item.articles %}
<li>
<span>{{ article.level }}</span> <a href="#{{ article.path }}">{{ article.title }}</a>
</li>
{% endfor %}
</ol>
{% endif %}
</li>
{% endfor %}
</ol>
</section>
{# Pages content #}
<section>
<article id="README.md">
{{ articleContent(pages["README.md"].content) }}
</article>
</section>
{% for item in summary.chapters %}
<section>
<article id="{{ item.path }}" class="new-chapter">
<h1>{{ item.title }}</h1>
</article>
{% if pages[item.path] %}
<article>
{{ articleContent(pages[item.path].content) }}
</article>
{% endif %}
{% if item.articles.length > 0 %}
{% for article in item.articles %}
{% if pages[article.path] %}
<article id="{{ article.path }}">
{{ articleContent(pages[article.path].content) }}
</article>
{% endif %}
{% endfor %}
{% endif %}
</section>
{% for item in progress.chapters %}
<article id="{{ article.path }}">
<h1 class="book-chapter book-chapter-{{ item.level|lvl }}">{{ item.title }}</h1>
{% if pages[item.path] %}
{{ articleContent(pages[item.path].content) }}
{% endif %}
</article>
{% endfor %}
{# Exercise solutions #}
{% if exercise > 1 %}
{% set exercise = 1 %}
<section>
<article class="new-chapter">
<h1>Exercise Solutions</h1>
</article>
<article>
{% for item in summary.chapters %}
{% for article in item.articles %}
{% if pages[article.path] %}
{% for section in pages[article.path].content %}
{% if section.type == "exercise" %}
<div class="exercise">
<div class="exercise-header">Exercise #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
<pre><code>{% autoescape false %}{{ section.code.solution|code }}{% endautoescape %}</code></pre>
{% set exercise = exercise + 1 %}
</div>
{% elif section.type == "quiz" %}
<div class="quiz">
<div class="exercise-header">Exercise #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% autoescape false %}{{ section.quiz.solution }}{% endautoescape %}
{% set exercise = exercise + 1 %}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
<article>
<h1 class="book-chapter book-chapter-1">Exercise Solutions</h1>
{% for item in progress.chapters %}
{% if pages[item.path] %}
{% for section in pages[item.path].content %}
{% if section.type == "exercise" %}
<div class="exercise">
<div class="exercise-header">Exercise #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
<pre><code>{% autoescape false %}{{ section.code.solution|code }}{% endautoescape %}</code></pre>
{% set exercise = exercise + 1 %}
</div>
{% elif section.type == "quiz" %}
<div class="quiz">
<div class="exercise-header">Quiz #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% for quiz in section.quiz %}
<div class="question">
<div class="question-header">Question {{ loop.index }} of {{ section.quiz.length }}</div>
{% autoescape false %}{{ quiz.solution }}{% endautoescape %}
</div>
{% endfor %}
{% set exercise = exercise + 1 %}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</article>
</section>
</article>
{% endif %}
{% endblock %}
+21 -4
View File
@@ -1,7 +1,23 @@
{% extends "layout.html" %}
{% block htmlTag %}manifest="{{ basePath }}/manifest.appcache"{% endblock %}
{% block title %}{{ progress.current.title }}{% parent %}{% endblock %}
{% block htmlTag %}{% if options.cache !== false %}manifest="{{ basePath }}/manifest.appcache"{% endif %}{% endblock %}
{% block head %}
{% parent %}
{% if githubAuthor %}
<meta name="author" content="{{ githubAuthor }}">
{% endif %}
{% if progress.current.next and progress.current.next.path %}
<link rel="next" href="{{ basePath }}/{{ progress.current.next.path|mdLink }}" />
{% endif %}
{% if progress.current.prev and progress.current.prev.path %}
<link rel="prev" href="{{ basePath }}/{{ progress.current.prev.path|mdLink }}" />
{% endif %}
{% endblock %}
{% block title %}{{ progress.current.title }} | {{ title }}{% endblock %}
{% block description %}{% if progress.current.level == "0" %}{{ description }}{% endif %}{% endblock %}
{% block content %}
<div class="book" {% if githubId %}data-github="{{ githubId }}"{% endif %} data-level="{{ progress.current.level }}" data-basepath="{{ basePath }}" data-revision="{{ revision }}">
{% include "includes/book/header.html" %}
@@ -38,7 +54,8 @@
{% endblock %}
{% block javascript %}
{% parent %}
<script src="{{ staticBase }}/jsrepl/jsrepl.js" id="jsrepl-script"></script>
<script src="{{ staticBase }}/app.js"></script>
{% for resource in plugins.resources.js %}
{% if resource.url %}
<script src="{{ resource.url }}"></script>
@@ -55,7 +72,7 @@ require(["gitbook"], function(gitbook) {
{% endblock %}
{% block style %}
{% parent %}
<link rel="stylesheet" href="{{ staticBase }}/style.css">
{% for resource in plugins.resources.css %}
{% if resource.url %}
<link rel="stylesheet" href="{{ resource.url }}">