Compare commits

...

35 Commits

Author SHA1 Message Date
Aaron O'Mullan 6bce93d893 Bump version to 0.2.3 2014-04-18 11:53:18 -07:00
Aaron O'Mullan c9db068227 Refactor navigation generation to be functional
This makes it a lot less error prone and far more robust. As well as a
lot easier to understand
2014-04-18 11:49:55 -07:00
Samy Pessé 8a6d36ac4d Improve stability of mixpanel tracking 2014-04-18 20:42:18 +02:00
Samy Pessé 64622c5945 Load css before content 2014-04-18 20:19:45 +02:00
Samy Pessé 837813edb0 Add warning about theme 2014-04-18 20:16:21 +02:00
Aaron O'Mullan 0d9d62f1a9 Merge pull request #117 from GitbookIO/fix/99
Fix #99
2014-04-18 10:17:20 -07:00
Samy Pessé f7e9abf984 Fix quiz interractivity 2014-04-18 19:10:13 +02:00
Samy Pessé dd0579b60d Update tests for relative images 2014-04-18 17:23:33 +02:00
Samy Pessé b5bb953e47 Fix image path calcul 2014-04-18 17:15:03 +02:00
Samy Pessé ef4a8ea1b6 Fix #116: update url before updating html content 2014-04-18 15:49:53 +02:00
Samy Pessé 49cde96ee7 Add contributors to package.json and change homepage 2014-04-18 15:00:40 +02:00
Samy Pessé 627be20e48 Add editor and twitter links in the readme 2014-04-18 14:48:03 +02:00
Samy Pessé e45bb84b02 Fix navigation on chrome for iOS: disable pushState 2014-04-18 13:09:16 +02:00
Aaron O'Mullan 4e8876c725 Update README.md 2014-04-17 16:39:06 -07:00
Aaron O'Mullan 6d5be15ec9 Bump version to 0.2.2 2014-04-17 15:31:57 -07:00
Samy Pessé 1a8db646f2 Improve styling for pdf and ebook 2014-04-17 12:15:28 +02:00
Samy Pessé d3aba2c906 Fix state update after navigation 2014-04-17 11:48:04 +02:00
Samy Pessé 457a83282f Improve style for pdf and ebook 2014-04-17 11:27:21 +02:00
Samy Pessé 48e94c937d Remove useless caracter from page format 2014-04-17 11:17:40 +02:00
Samy Pessé 6e613e9f71 Fix #107: Render all the page in single page format 2014-04-17 11:16:18 +02:00
Aaron O'Mullan b698d43d7d Bump version to 0.2.1 2014-04-17 01:10:11 -07:00
Aaron O'Mullan a36b9a6088 Normalize code language before highlighting 2014-04-17 01:09:26 -07:00
Samy Pessé 20acd89c8a Merge pull request #104 from GitbookIO/fix/auto_highlighting
Disable automatic highlighting
2014-04-17 09:24:56 +02:00
Aaron O'Mullan 7bed9a257d Merge pull request #105 from ptagell/master
Removed duplicate line of readme
2014-04-16 14:38:49 -07:00
Paul Tagell 19c83aa5a8 Removed duplicate line of readme 2014-04-17 07:35:28 +10:00
Aaron O'Mullan 52610d7d61 Disable automatic highlighting
Fallback to no highlighting rather that potentially funky highlighting
2014-04-16 13:15:35 -07:00
Aaron O'Mullan 9e4b393b7a In parse/page remove global marked settings
Highlighter settings were global, moved them to the render function
(where they should have been)
2014-04-16 13:07:35 -07:00
Samy Pessé a0ae34a3b7 Fix #100: fix section test isQuiz 2014-04-16 17:16:18 +02:00
Samy Pessé 413dc5d004 Add more test for quiz (related to #100) 2014-04-16 17:15:45 +02:00
Aaron O'Mullan c9eb27bfe7 Do not pass SUMMARY.md to generator, fixes #93
We want to parse SUMMARY.md but not generate a file from it, thus it
should be removed from the list of files to be processed by the
generator
2014-04-16 00:18:35 -07:00
Aaron O'Mullan b78505c290 Ignore .gitignore file by default in fs.list
Partial fix of #93
2014-04-16 00:11:54 -07:00
Samy Pessé 95f9ae83d0 Fix #97: keep scroll position during page changement 2014-04-15 17:42:46 +02:00
Samy Pessé 9304289315 Fix progress display when page change 2014-04-14 23:00:40 +02:00
Samy Pessé 1b726ca293 Update preview 2014-04-14 22:35:10 +02:00
Samy Pessé 656ca18929 Improve languages list design 2014-04-14 21:29:26 +02:00
29 changed files with 387 additions and 194 deletions
-4
View File
@@ -35,7 +35,6 @@ module.exports = function (grunt) {
"lodash": 'vendors/lodash',
"requireLib": 'vendors/require',
"Mousetrap": 'vendors/mousetrap',
"mixpanel": 'vendors/mixpanel',
"lunr": path.join(__dirname, "node_modules/lunr/lunr")
},
shim: {
@@ -48,9 +47,6 @@ module.exports = function (grunt) {
'Mousetrap': {
exports: 'Mousetrap'
},
'mixpanel': {
exports: 'mixpanel'
},
'lunr': {
exports: 'lunr'
}
+3 -2
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/).
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.
![Image](https://raw.github.com/GitbookIO/gitbook/master/preview.png)
@@ -35,11 +35,12 @@ Options for commands `build` and `serve` are:
-g, --github <repo_path> ID of github repo like : username/repo
-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
-i, --intro <intro> Description of the book to generate
--githubHost <url> The url of the github host (defaults to https://github.com/)
--theme <path> Path to theme directory
```
You can publish your books to our index by visiting [GitBook.io](http://www.gitbook.io)
## Output Formats
GitBook can generate your book in the following formats:
+2 -1
View File
@@ -16,7 +16,8 @@ var getFiles = function(path) {
// Add extra rules to ignore common folders
ig.addIgnoreRules([
'.git/'
'.git/',
'.gitignore',
], '__custom_stuff');
// Push each file to our list
+11 -2
View File
@@ -129,6 +129,15 @@ var generate = function(options) {
});
})
// Skip processing some files
.then(function() {
files = _.filter(files, function (file) {
return !(
file === 'SUMMARY.md'
);
});
})
// Copy file and replace markdown file
.then(function() {
return Q.all(
@@ -177,7 +186,7 @@ var generateFile = function(options) {
return Q.nfcall(tmp.dir)
.then(function(tmpDir) {
return generate(
_.extend({},
_.extend({},
options,
{
output: tmpDir
@@ -195,7 +204,7 @@ var generateFile = function(options) {
_outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+"_"+lang+path.extname(_outputFile);
_tmpDir = path.join(_tmpDir, lang);
}
return fs.copy(
path.join(_tmpDir, "index."+ext),
_outputFile
+1 -1
View File
@@ -56,7 +56,7 @@ function isQuiz(nodes) {
if(
// List of questions
listIdx !== -1 && isQuizNode(quizNodes[listIdx + 1]) &&
listIdx !== -1 && isQuizNode(quizNodes[listIdx + 1]) ||
// Table of questions
(
+30 -49
View File
@@ -6,6 +6,12 @@ function clean(obj) {
return obj && _.omit(obj, ['articles']);
}
function flattenChapters(chapters) {
return _.reduce(chapters, function(accu, chapter) {
return accu.concat([clean(chapter)].concat(chapter.articles));
}, []);
}
// Returns from a summary a map of
/*
{
@@ -20,62 +26,37 @@ function navigation(summary, files) {
// Support single files as well as list
files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);
// Mapping of prev/next for a give path
var mapping = {};
// Special README nav
var README_NAV = {
path: 'README.md',
title: 'Introduction',
};
// Walk the chapter/article tree and create navigation entires
_.each(summary.chapters, function(chapter, idx, chapters) {
// Skip if no path
if(!chapter.path) return;
var currentChapter = clean(chapter);
var prevChapter = (idx-1 < 0) ? README_NAV : chapters[idx-1];
var nextChapter = (idx+1 >= chapters.length) ? null : chapters[idx+1];
var prev = (!prevChapter || _.isEmpty(prevChapter.articles)) ?
prevChapter : _.last(prevChapter.articles);
var next = (!chapter || _.isEmpty(chapter.articles)) ?
nextChapter : _.first(chapter.articles);
// Add chapter mapping
mapping[chapter.path] = {
title: chapter.title,
prev: clean(prev),
next: clean(next),
level: (idx+1).toString(),
};
// Check a chapter's articles
_.each(chapter.articles, function(article, _idx, articles) {
// Skip if no path
if(!article.path) return;
var prev = (_idx-1 < 0) ? currentChapter : clean(articles[_idx-1]);
var next = (_idx+1 >= articles.length) ? nextChapter : clean(articles[_idx+1]);
mapping[article.path] = {
title: article.title,
prev: clean(prev),
next: clean(next),
level: [idx+1, _idx+1].join('.'),
};
});
});
// Hack for README.html
mapping['README.md'] = {
title: README_NAV.title,
prev: null,
next: clean(summary.chapters[0]),
level: '0',
};
// List of all navNodes
var navNodes = [README_NAV].concat(flattenChapters(summary.chapters));
var prevNodes = [null].concat(navNodes.slice(0, -1));
var nextNodes = navNodes.slice(1).concat([null]);
// Mapping of prev/next for a give path
var mapping = _.chain(_.zip(navNodes, prevNodes, nextNodes))
.map(function(nodes) {
var current = nodes[0], prev = nodes[1], next = nodes[2];
// Skip if no path
if(!current.path) return null;
return [current.path, {
title: current.title,
prev: prev,
next: next,
level: current.level,
}];
})
.filter()
.object()
.value();
// Filter for only files we want
if(files) {
return _.pick(mapping, files);
+15 -12
View File
@@ -8,17 +8,6 @@ var renderer = require('./renderer');
var lnormalize = require('../utils/lang').normalize;
// Synchronous highlighting with highlight.js
marked.setOptions({
highlight: function (code, lang) {
try {
return hljs.highlight(lang, code).value;
} catch(e) {
return hljs.highlightAuto(code).value;
}
}
});
// Render a section using our custom renderer
function render(section, _options) {
@@ -30,7 +19,21 @@ function render(section, _options) {
// Build options using defaults and our custom renderer
var options = _.extend({}, marked.defaults, {
renderer: renderer(null, _options)
renderer: renderer(null, _options),
// Synchronous highlighting with highlight.js
highlight: function (code, lang) {
if(!lang) return code;
// Normalize lang
lang = lnormalize(lang);
try {
return hljs.highlight(lang, code).value;
} catch(e) { }
return code;
}
});
return marked.parser(section, options);
+8 -2
View File
@@ -79,8 +79,14 @@ GitBookRenderer.prototype.image = function(href, title, text) {
// Relative image, rewrite it depending output
if(!parsed.protocol && parsed.path && parsed.path[0] != '/' && o && o.dir && o.outdir) {
var outdir = o.outdir.charAt(o.outdir.length - 1) === '/' ? o.outdir : o.outdir + '/';
_href = url.resolve(outdir, [o.dir, href].join('/'));
// o.dir: directory parent of the file currently in rendering process
// o.outdir: directory parent from the html output
// Absolute file in source
_href = path.join(o.dir, _href);
// make it relative to output
_href = path.relative(o.outdir, _href);
}
return GitBookRenderer.super_.prototype.image.call(this, _href, title, text);
+14 -3
View File
@@ -1,6 +1,7 @@
{
"name": "gitbook",
"version": "0.2.0",
"version": "0.2.3",
"homepage": "http://www.gitbook.io/",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
"dependencies": {
@@ -39,9 +40,19 @@
"book",
"gitbook"
],
"author": "Aaron O'Mullan <aaron.omullan@friendco.de>",
"author": "FriendCode <contact@friendco.de>",
"license": "Apache 2",
"bugs": {
"url": "https://github.com/GitbookIO/gitbook/issues"
}
},
"contributors": [
{
"name": "Aaron O'Mullan",
"email": "aaron.omullan@gmail.com"
},
{
"name": "Samy Pessé",
"email": "samypesse@gmail.com"
}
]
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 164 KiB

+12
View File
@@ -0,0 +1,12 @@
# Images Test
This is a test for images path calculation. It supposed this fiel is in a syntax/ folder
### #
[![Screen](./preview.png)](./preview.png)
### 2
[![Screen](../preview2.png)](./preview2.png)
+15
View File
@@ -31,3 +31,18 @@ Some more nice content ....
[Cool stuff](http://gitbook.io)
[Link to another Markdown file](./xyz/file.md)
---
Quiz test 2: What does Gitbook support?
- [x] Table-based questions with radio buttons
- [x] Table-based questions with checkboxes
- [ ] Telepathy
- [x] List-based questions with checkboxes
- [x] List-based questions with radio buttons
- [ ] Moon-on-a-stick
> Gitbook supports table and list based quiz questions using either radio buttons or checkboxes.
---
+31 -4
View File
@@ -28,6 +28,7 @@ describe('Page parsing', function() {
assert.equal(QUIZ_LEXED[0].type, 'normal');
assert.equal(QUIZ_LEXED[1].type, 'quiz');
assert.equal(QUIZ_LEXED[2].type, 'normal');
assert.equal(QUIZ_LEXED[3].type, 'quiz');
});
it('should gen content for normal sections', function() {
@@ -35,10 +36,6 @@ describe('Page parsing', function() {
assert(LEXED[2].content);
});
it('should make image URLs relative', function() {
assert(LEXED[2].content.indexOf('_book/assets/my-pretty-picture.png') !== -1);
});
it('should gen code and content for exercise sections', function() {
assert(LEXED[1].content);
assert(LEXED[1].code);
@@ -93,3 +90,33 @@ describe('Relative links', function() {
assert(LEXED[0].content.indexOf('https://github.com/GitBookIO/javascript/blob/src/something.cpp') !== -1);
});
});
describe('Relative images', function() {
it('should keep image relative with considering output directory in site format', function() {
var LEXED = loadPage('IMAGES', {
// GitHub repo ID
repo: 'GitBookIO/javascript',
// Imaginary folder of markdown file
dir: 'syntax',
outdir: 'syntax'
});
assert(LEXED[0].content.indexOf('"preview.png"') !== -1);
assert(LEXED[0].content.indexOf('"../preview2.png"') !== -1);
});
it('should keep image relative with considering output directory in page format', function() {
var LEXED = loadPage('IMAGES', {
// GitHub repo ID
repo: 'GitBookIO/javascript',
// Imaginary folder of markdown file
dir: 'syntax',
outdir: './'
});
assert(LEXED[0].content.indexOf('"syntax/preview.png"') !== -1);
assert(LEXED[0].content.indexOf('"preview2.png"') !== -1);
});
});
+2
View File
@@ -3,3 +3,5 @@
For creating a theme for GitBook, just copy this folder. The theme folder should at least contains two folders: `assets` and `templates`.
The theme can be changed using the option ```--theme=<path>```
#### Warning! Theme system is going to change before version 1.0.0
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+13 -4
View File
@@ -10,12 +10,14 @@ define([
var prev, next;
var githubCountStars, githubCountWatch;
var usePushState = !navigator.userAgent.match('CriOS') && (typeof history.pushState !== "undefined");
var updateHistory = function(url, title) {
history.pushState({ path: url }, title, url);
};
var handleNavigation = function(url, push) {
if (typeof history.pushState === "undefined") {
if (!usePushState) {
// Refresh the page to the new URL if pushState not supported
location.href = url;
return
@@ -23,6 +25,8 @@ define([
return $.get(url)
.done(function (html) {
if (push) updateHistory(url, null);
html = html.replace( /<(\/?)(html|head|body)([^>]*)>/ig, function(a,b,c,d){
return '<' + b + 'div' + ( b ? '' : ' data-element="' + c + '"' ) + d + '>';
});
@@ -38,12 +42,17 @@ define([
});
$("head").html(headContent);
// Update header, body and summary
// Update header, body
$('.book-header').html($page.find('.book-header').html());
$('.book-body').html($page.find('.book-body').html());
$('.book-summary').html($page.find('.book-summary').html());
if (push) updateHistory(url, null);
// Update summary
var scrollPosition = $('.book-summary .summary').scrollTop();
$('.book-summary').html($page.find('.book-summary').html());
$('.book-summary .summary').scrollTop(scrollPosition);
// Update state
state.update($("html"));
preparePage();
})
.fail(function () {
+5 -2
View File
@@ -20,8 +20,11 @@ define([
$quiz.find(".question").each(function(q) {
var result = true;
var $answers = $quiz.find(".question-answers").slice(q).find("input[type=radio], input[type=checkbox]");
$(this).find("input[type=radio],input[type=checkbox]").each(function(i) {
var $questions = $(this).find(".question-content").find("input[type=radio], input[type=checkbox]");
var $answers = $(this).find(".question-answers").find("input[type=radio], input[type=checkbox]");
$questions.each(function(i) {
var correct = $(this).is(":checked") === $answers.slice(i).first().is(":checked");
result = result && correct;
if (!correct) {
+12 -7
View File
@@ -1,14 +1,19 @@
define([
"jQuery"
], function() {
var $book = $(".book");
var state = {};
return {
'$book': $book,
state.update = function(dom) {
var $book = $(dom.find(".book"));
'githubId': $book.data("github"),
'level': $book.data("level"),
'basePath': $book.data("basepath"),
'revision': $book.data("revision")
state.$book = $book;
state.githubId = $book.data("github");
state.level = $book.data("level");
state.basePath = $book.data("basepath");
state.revision = $book.data("revision");
};
state.update($);
return state;
});
+13 -10
View File
@@ -1,13 +1,6 @@
define([
"lodash",
"mixpanel"
], function(_, mixpanel) {
mixpanel.init("01eb2b950ae09a5fdb15a98dcc5ff20e", {
loaded: function() {
track("page.start");
}
});
"lodash"
], function(_) {
var isAvailable = function() {
return (
typeof mixpanel !== "undefined" &&
@@ -15,9 +8,14 @@ define([
);
};
var track = function(e, data) {
var track = function(e, data, t) {
if (!isAvailable()) {
console.warn("tracking not available!");
t = t || 500;
setTimeout(function() {
console.log(" -> retest tracking");
track(e, data, t*2);
}, t);
return;
}
console.log("track", e);
@@ -26,6 +24,11 @@ define([
}));
};
setTimeout(function() {
mixpanel.init("01eb2b950ae09a5fdb15a98dcc5ff20e");
track("page.start");
}, 0);
return {
isAvailable: isAvailable,
track: track
-2
View File
@@ -1,2 +0,0 @@
(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.track_charge people.clear_charges people.delete_user".split(" ");
for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src=("https:"===e.location.protocol?"https:":"http:")+'//cdn.mxpnl.com/libs/mixpanel-2.2.min.js';f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
-2
View File
@@ -37,8 +37,6 @@
padding: 10px 5px;
font-size: 16px;
border-bottom: 1px solid #eee;
a {
}
+1 -6
View File
@@ -5,8 +5,7 @@
@import "variables.less";
@import "fonts.less";
@import "highlight.less";
@import "book/highlight.less";
@import "book/languages.less";
@import "book/header.less";
@import "book/summary.less";
@@ -25,10 +24,6 @@
-webkit-font-smoothing: antialiased;
}
.form-control {
.box-shadow(none);
}
html, body {
height: 100%;
}
+90
View File
@@ -0,0 +1,90 @@
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Tomorrow Comment */
.hljs-comment,
.hljs-title {
color: #8e908c;
}
/* Tomorrow Red */
.hljs-variable,
.hljs-attribute,
.hljs-tag,
.hljs-regexp,
.ruby .hljs-constant,
.xml .hljs-tag .hljs-title,
.xml .hljs-pi,
.xml .hljs-doctype,
.html .hljs-doctype,
.css .hljs-id,
.css .hljs-class,
.css .hljs-pseudo {
color: #c82829;
}
/* Tomorrow Orange */
.hljs-number,
.hljs-preprocessor,
.hljs-pragma,
.hljs-built_in,
.hljs-literal,
.hljs-params,
.hljs-constant {
color: #f5871f;
}
/* Tomorrow Yellow */
.ruby .hljs-class .hljs-title,
.css .hljs-rules .hljs-attribute {
color: #eab700;
}
/* Tomorrow Green */
.hljs-string,
.hljs-value,
.hljs-inheritance,
.hljs-header,
.ruby .hljs-symbol,
.xml .hljs-cdata {
color: #718c00;
}
/* Tomorrow Aqua */
.css .hljs-hexcolor {
color: #3e999f;
}
/* Tomorrow Blue */
.hljs-function,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-function .hljs-title,
.ruby .hljs-title .hljs-keyword,
.perl .hljs-sub,
.javascript .hljs-title,
.coffeescript .hljs-title {
color: #4271ae;
}
/* Tomorrow Purple */
.hljs-keyword,
.javascript .hljs-function {
color: #8959a8;
}
.hljs {
display: block;
background: white;
color: #4d4d4c;
padding: 0.5em;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.5;
}
+55 -21
View File
@@ -1,8 +1,47 @@
h1, h2 {
@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;
@@ -26,41 +65,36 @@ section {
}
&#summary {
text-align: center;
margin: 1.5cm;
ul {
font-size: 0.5cm;
line-height: 1.8em;
padding: 0px;
margin: 0px;
list-style: none;
h1 {
text-align: center;
}
> ul {
> li {
margin-bottom: 1cm;
ol {
list-style: none;
padding: 0px;
margin: 0px;
margin-left: 1cm;
}
> a {
font-size: 0.6cm;
}
> ol {
> li {
}
}
}
article {
margin: 1.5cm;
/* Big centered title */
margin-bottom: 1.5cm;
&.new-chapter {
page-break-after: always;
font-size: 0.6cm;
text-align: center;
padding: 3cm 0cm;
border-top: 1px solid #ccc;
@media print {
border: none;
h1 {
font-size: floor(@font-size-base * 2.7);
}
}
+4 -1
View File
@@ -35,11 +35,14 @@
{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
{% block style %}
<link rel="stylesheet" href="{{ staticBase }}/style.css">
{% endblock %}
{% block content %}{% endblock %}
{% block javascript %}
<script type="text/javascript">(function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.track_charge people.clear_charges people.delete_user".split(" ");
for(g=0;g<i.length;g++)f(c,i[g]);b._i.push([a,e,d])};b.__SV=1.2;a=e.createElement("script");a.type="text/javascript";a.async=!0;a.src=("https:"===e.location.protocol?"https:":"http:")+'//cdn.mxpnl.com/libs/mixpanel-2.2.min.js';f=e.getElementsByTagName("script")[0];f.parentNode.insertBefore(a,f)}})(document,window.mixpanel||[]);
</script>
<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>
+47 -56
View File
@@ -3,10 +3,32 @@
{% block title %}{{ title }}{% endblock %}
{% block style %}
{% parent %}
<link rel="stylesheet" href="{{ staticBase }}/print.css">
{% endblock %}
{% macro articleContent(content) %}
{% for section in content %}
{% if section.type == "normal" %}
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% elif section.type == "exercise" %}
<div class="exercise">
<div class="exercise-header">Exercise #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
<pre><code>{% autoescape false %}{{ section.code.base|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.base }}{% endautoescape %}
{% set exercise = exercise + 1 %}
</div>
{% endif %}
{% endfor %}
{% endmacro %}
{% set exercise = 1 %}
{% block content %}
{# Cover #}
@@ -19,87 +41,56 @@
{# Summary #}
<section id="summary">
<h1>Summary</h1>
<ul class="summary">
<h1>Table of Contents</h1>
<ol>
<li>
<a href="#README.md">Introduction</a>
<a href="#README.md">
<h2>Introduction</h2>
</a>
</li>
{% for item in summary.chapters %}
<li>
<a href="#{{ item.path }}">{{ item.level }}) {{ item.title }}</a>
<h2><span>{{ item.level }}.</span> <a href="#{{ item.path }}">{{ item.title }}</a></h2>
{% if item.articles.length > 0 %}
<ul>
<ol>
{% for article in item.articles %}
<li>
<a href="#{{ article.path }}">{{ article.level }}) {{ article.title }}</a>
<span>{{ article.level }}</span> <a href="#{{ article.path }}">{{ article.title }}</a>
</li>
{% endfor %}
</ul>
</ol>
{% endif %}
</li>
{% endfor %}
</ul>
</ol>
</section>
{# Pages content #}
<section>
<article id="README.md">
{% for section in pages["README.md"].content %}
{% if section.type == "normal" %}
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% elif section.type == "exercise" %}
<div class="exercise">
<div class="exercise-header">Exercise #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
<pre><code>{% autoescape false %}{{ section.code.base|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.base }}{% endautoescape %}
{% set exercise = exercise + 1 %}
</div>
{% endif %}
{% endfor %}
{{ articleContent(pages["README.md"].content) }}
</article>
</section>
{% for item in summary.chapters %}
{% if item.articles.length > 0 %}
<section>
<article id="{{ item.path }}" class="new-chapter">
<h1>{{ item.title }}</h1>
</article>
{% for article in item.articles %}
{% if pages[article.path] %}
<article id="{{ article.path }}">
{% for section in pages[article.path].content %}
{% if section.type == "normal" %}
{% autoescape false %}{{ section.content }}{% endautoescape %}
{% elif section.type == "exercise" %}
<div class="exercise">
<div class="exercise-header">Exercise #{{ exercise }}</div>
{% autoescape false %}{{ section.content }}{% endautoescape %}
<pre><code>{% autoescape false %}{{ section.code.base|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.base }}{% endautoescape %}
{% set exercise = exercise + 1 %}
</div>
{% endif %}
{% endfor %}
</article>
{% endif %}
{% endfor %}
<article>
{{ articleContent(pages[item.path].content) }}
</article>
{% 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>
{% endif %}
{% endfor %}