Create single-page HTML output, prepares the terrain for PDF/ePub output

This commit is contained in:
Stéphane Goetz 2015-11-06 22:44:34 +01:00
parent 975f7fdee3
commit 295aee5f77
24 changed files with 2478 additions and 93 deletions

BIN
daux.phar

Binary file not shown.

View File

@ -69,32 +69,16 @@ Daux.io is extendable and comes by default with two export formats:
## Feature Matrix
<table>
<tr>
<th>Feature</th><th>HTML</th><th>Confluence</th>
</tr>
<tr>
<td>Landing Pages</td><td></td><td>X</td>
</tr>
<tr>
<td>Index Pages</td><td></td><td></td>
</tr>
<tr>
<td>Internal Links</td><td></td><td></td>
</tr>
<tr>
<td>Code Highlight</td><td></td><td>√ (Using macros)</td>
</tr>
<tr>
<td>Live Mode</td><td></td><td>X</td>
</tr>
<tr>
<td>Ordering Pages</td><td></td><td>X (API Limitation)</td>
</tr>
<tr>
<td>Google / Piwik analytics</td><td></td><td>X</td>
</tr>
</table>
Feature | HTML | Single Page HTML | Confluence
--------------:|:----:|:----------------:|:----------:
Multilanguage | √ | X (Soon) | X
Landing Pages | √ | X | X
Index Pages | √ | √ | √
Internal Links | √ | X (Soon) | √
Code Highlight | √ | X (Soon) | √ (Using macros)
Live Mode | √ | X | X
Pages Ordering | √ | √ | X (API Limitation)
Google / Piwik analytics | √ | √ | √ (Configured on Conflence)
## Folders

View File

@ -11,7 +11,8 @@ var resources = {
daux_blue:{source: "themes/daux/less/theme-blue.less", dest: "themes/daux/css/"},
daux_green:{source: "themes/daux/less/theme-green.less", dest: "themes/daux/css/"},
daux_navy:{source: "themes/daux/less/theme-navy.less", dest: "themes/daux/css/"},
daux_red:{source: "themes/daux/less/theme-red.less", dest: "themes/daux/css/"}
daux_red:{source: "themes/daux/less/theme-red.less", dest: "themes/daux/css/"},
daux_singlepage:{source: "themes/daux_singlepage/less/main.less", dest: "themes/daux_singlepage/css/"}
};
var unusedRules = [

View File

@ -185,7 +185,8 @@ class Daux
$this->finalizeTree($this->tree);
}
public function sortTree(Directory $current) {
public function sortTree(Directory $current)
{
$current->sort();
foreach ($current->getEntries() as $entry) {
if ($entry instanceof Directory) {
@ -282,6 +283,7 @@ class Daux
{
$default = [
'confluence' => '\Todaymade\Daux\Format\Confluence\Generator',
'html-file' => '\Todaymade\Daux\Format\HTMLFile\Generator',
'html' => '\Todaymade\Daux\Format\HTML\Generator',
];

View File

@ -0,0 +1,82 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: onigoetz
* Date: 06/11/15
* Time: 20:27
*/
namespace Todaymade\Daux\Format\Base;
use DOMDocument;
use Todaymade\Daux\DauxHelper;
use Todaymade\Daux\Tree\Content;
use Todaymade\Daux\Tree\Root;
class EmbedImages
{
protected $tree;
public function __construct(Root $tree)
{
$this->tree = $tree;
}
public function embed($page, Content $file, $callback)
{
return preg_replace_callback(
"/<img\\s+[^>]*src=['\"]([^\"]*)['\"][^>]*>/",
function ($matches) use ($file, $callback) {
if ($result = $this->findImage($matches[1], $matches[0], $file, $callback)) {
return $result;
}
return $matches[0];
},
$page
);
}
private function getAttributes($tag)
{
$dom = new DOMDocument();
$dom->loadHTML($tag);
$img = $dom->getElementsByTagName('img')->item(0);
$attributes = ['align', 'class', 'title', 'style', 'alt', 'height', 'width'];
$used = [];
foreach ($attributes as $attr) {
if ($img->attributes->getNamedItem($attr)) {
$used[$attr] = $img->attributes->getNamedItem($attr)->value;
}
}
return $used;
}
private function findImage($src, $tag, Content $file, $callback)
{
//for protocol relative or http requests : keep the original one
if (substr($src, 0, strlen("http")) === "http" || substr($src, 0, strlen("//")) === "//") {
return $src;
}
//Get the path to the file, relative to the root of the documentation
$url = DauxHelper::getCleanPath(dirname($file->getUrl()) . '/' . $src);
//Get any file corresponding to the right one
$file = DauxHelper::getFile($this->tree, $url);
if ($file === false) {
return false;
}
$result = $callback($src, $this->getAttributes($tag), $file);
return $result ?: $src;
}
}

View File

@ -1,7 +1,7 @@
<?php namespace Todaymade\Daux\Format\Confluence;
use DOMDocument;
use Todaymade\Daux\DauxHelper;
use Todaymade\Daux\Format\Base\EmbedImages;
use Todaymade\Daux\Tree\Raw;
class ContentPage extends \Todaymade\Daux\Format\Base\ContentPage
{
@ -9,68 +9,25 @@ class ContentPage extends \Todaymade\Daux\Format\Base\ContentPage
protected function generatePage()
{
$page = parent::generatePage();
$content = parent::generatePage();
//Embed images
// We do it after generation so we can catch the images that were in html already
$page = preg_replace_callback(
"/<img\\s+[^>]*src=['\"]([^\"]*)['\"][^>]*>/",
function($matches) {
$content = (new EmbedImages($this->params['tree']))
->embed(
$content,
$this->file,
function ($src, array $attributes, Raw $file) {
$filename = basename($file->getPath());
if ($result = $this->findImage($matches[1], $matches[0])) {
return $result;
//Add the attachment for later upload
$this->attachments[] = ['filename' => $filename, 'file' => $file];
return $this->createImageTag($filename, $attributes);
}
);
return $matches[0];
},
$page
);
return $page;
}
private function findImage($src, $tag)
{
//for protocol relative or http requests : keep the original one
if (substr($src, 0, strlen("http")) === "http" || substr($src, 0, strlen("//")) === "//") {
return $src;
}
//Get the path to the file, relative to the root of the documentation
$url = DauxHelper::getCleanPath(dirname($this->file->getUrl()) . '/' . $src);
//Get any file corresponding to the right one
$file = DauxHelper::getFile($this->params['tree'], $url);
if ($file === false) {
return false;
}
$filename = basename($file->getPath());
//Add the attachment for later upload
$this->attachments[] = ['filename' => $filename, 'file' => $file];
return $this->createImageTag($filename, $this->getAttributes($tag));
}
private function getAttributes($tag)
{
$dom = new DOMDocument();
$dom->loadHTML($tag);
$img = $dom->getElementsByTagName('img')[0];
$attributes = ['align', 'class', 'title', 'style', 'alt', 'height', 'width'];
$used = [];
foreach ($attributes as $attr) {
if ($img->attributes->getNamedItem($attr)) {
$used[$attr] = $img->attributes->getNamedItem($attr)->value;
}
}
return $used;
return $content;
}
private function createImageTag($filename, $attributes)

View File

@ -17,11 +17,11 @@ class ImageRenderer extends \League\CommonMark\Inline\Renderer\ImageRenderer
{
// External Images need special handling
if (strpos($inline->getUrl(), 'http') === 0) {
return new HtmlElement(
'ac:image',
[],
new HtmlElement('ri:url', ['ri:value' => $inline->getUrl()])
);
return new HtmlElement(
'ac:image',
[],
new HtmlElement('ri:url', ['ri:value' => $inline->getUrl()])
);
}
return parent::render($inline, $htmlRenderer);

View File

@ -96,7 +96,7 @@ class Template
foreach ($tree->getEntries() as $node) {
$url = $node->getUri();
if ($node instanceof Content) {
if (in_array($node->getName(), ['index', '_index'])) {
if ($node->isIndex()) {
continue;
}

View File

@ -0,0 +1,142 @@
<?php namespace Todaymade\Daux\Format\HTMLFile;
use RuntimeException;
use Todaymade\Daux\Tree\Content;
use Todaymade\Daux\Tree\Directory;
class Book
{
protected $cover;
protected $tree;
protected $pages = [];
public function __construct(Directory $tree, $cover)
{
$this->tree = $tree;
$this->cover = $cover;
}
protected function getStyles()
{
// TODO :: un-hardcode that
return '<style>' . file_get_contents('themes/daux_singlepage/css/main.min.css') . '</style>';
}
protected function getSectionId(Content $node)
{
foreach ($this->pages as $id => $page) {
if ($page['page'] == $node) {
return $id;
}
}
throw new RuntimeException("Could not find the content page");
}
protected function buildNavigation(Directory $tree)
{
$nav = [];
foreach ($tree->getEntries() as $node) {
if ($node instanceof Content) {
if ($node->isIndex()) {
continue;
}
$nav[] = [
'title' => $node->getTitle(),
'href' => '#section_' . $this->getSectionId($node),
];
} elseif ($node instanceof Directory) {
if (!$node->hasContent()) {
continue;
}
$page_index = ($index = $node->getIndexPage())? $index : $node->getFirstPage();
$nav[] = [
'title' => $node->getTitle(),
'href' => "#section_" . $this->getSectionId($page_index),
'children' => $this->buildNavigation($node)
];
}
}
return $nav;
}
private function renderNavigation($entries)
{
$nav = "";
foreach ($entries as $entry) {
if (array_key_exists('children', $entry)) {
if (array_key_exists('href', $entry)) {
$link = '<a href="' . $entry['href'] . '" class="folder">' . $entry['title'] . '</a>';
} else {
$link = '<a href="#" class="aj-nav folder">' . $entry['title'] . '</a>';
}
$link .= $this->renderNavigation($entry['children']);
} else {
$link = '<a href="' . $entry['href'] . '">' . $entry['title'] . '</a>';
}
$nav .= "<li>$link</li>";
}
return "<ul>$nav</ul>";
}
protected function generateTOC()
{
return "<h1>Table of Contents</h1>" .
$this->renderNavigation($this->buildNavigation($this->tree)) .
"</div><div class=\"page-break\">&nbsp;</div>";
}
protected function generateCover()
{
return "<div style='margin:4em 30% 4em 0;'>" .
"<h1 style='font-size:40pt; margin-bottom:0;'>{$this->cover['title']}</h1>" .
"<p><strong>{$this->cover['subject']}</strong> by {$this->cover['author']}</p>" .
"</div><div class=\"page-break\">&nbsp;</div>";
}
protected function generatePages()
{
$content = '';
foreach ($this->pages as $section => $page) {
$content .= '<a id="section_' . $section . '"></a>';
$content .= '<h1>' . $page['page']->getTitle() . '</h1>';
$content .= '<section class="content">' . $page['content'] . '</section>';
$content .= '<div class="page-break">&nbsp;</div>';
}
return $content;
}
public function addPage($page, $content)
{
$this->pages[] = ['page' => $page, 'content' => $content];
}
public function generateHead()
{
$head = [
"<title>{$this->cover['title']}</title>",
"<meta name='description' content='{$this->cover['subject']}' />",
"<meta name='author' content='{$this->cover['author']}'>",
"<meta charset='UTF-8'>",
$this->getStyles(),
];
return '<head>' . implode('', $head) . '</head>';
}
public function generateBody()
{
return '<body>' . $this->generateCover() . $this->generateTOC() . $this->generatePages() . '</body>';
}
public function generate()
{
return "<!DOCTYPE html><html>" . $this->generateHead() . $this->generateBody() . "</html>";
}
}

View File

@ -0,0 +1,34 @@
<?php namespace Todaymade\Daux\Format\HTMLFile;
use Todaymade\Daux\Format\Base\EmbedImages;
use Todaymade\Daux\Tree\Raw;
class ContentPage extends \Todaymade\Daux\Format\Base\ContentPage
{
public $attachments = [];
protected function generatePage()
{
$content = parent::generatePage();
//Embed images
// We do it after generation so we can catch the images that were in html already
$content = (new EmbedImages($this->params['tree']))
->embed(
$content,
$this->file,
function ($src, array $attributes, Raw $file) {
$content = base64_encode(file_get_contents($file->getPath()));
$attr = '';
foreach ($attributes as $name => $value) {
$attr .= ' ' .$name . '="' . htmlentities($value, ENT_QUOTES, 'UTF-8', false) . '"';
}
return "<img $attr src=\"data:image/png;base64,$content\"/>";
}
);
return $content;
}
}

View File

@ -0,0 +1,103 @@
<?php namespace Todaymade\Daux\Format\HTMLFile;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Todaymade\Daux\Console\RunAction;
use Todaymade\Daux\ContentTypes\Markdown\ContentType;
use Todaymade\Daux\Daux;
class Generator implements \Todaymade\Daux\Format\Base\Generator
{
use RunAction;
/** @var Daux */
protected $daux;
/**
* @param Daux $daux
*/
public function __construct(Daux $daux)
{
$this->daux = $daux;
}
/**
* @return array
*/
public function getContentTypes()
{
return [
'markdown' => new ContentType($this->daux->getParams())
];
}
protected function initPDF()
{
// create new PDF document
$pdf = new Book(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$params = $this->daux->getParams();
// set document information
$pdf->SetCreator(PDF_CREATOR);
// set default header data
$pdf->SetHeaderData('', 0, $params['title'], $params['tagline']);
// set header and footer fonts
$pdf->setHeaderFont(array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
// set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
// set auto page breaks
$pdf->SetAutoPageBreak(true, PDF_MARGIN_BOTTOM);
// set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
// set font
$pdf->SetFont('helvetica', '', 10);
return $pdf;
}
/**
* {@inheritdoc}
*/
public function generateAll(InputInterface $input, OutputInterface $output, $width)
{
$params = $this->daux->getParams();
$data = ['author' => $params['author'], 'title' => $params['title'], 'subject' => $params['tagline']];
$book = new Book($this->daux->tree, $data);
$current = $this->daux->tree->getIndexPage();
while ($current) {
$this->runAction(
"Generating " . $current->getTitle(),
$output,
$width,
function () use ($book, $current, $params) {
$contentType = $this->daux->getContentTypeHandler()->getType($current);
$content = ContentPage::fromFile($current, $params, $contentType)->getContent();
$book->addPage($current, $content);
}
);
$current = $current->getNext();
}
$content = $book->generate();
file_put_contents($input->getOption('destination') . '/file.html', $content);
}
}

View File

@ -69,6 +69,11 @@ class Content extends Entry
$this->next = $next;
}
public function isIndex()
{
return $this->name == 'index' || $this->name == '_index';
}
public function dump()
{
$dump = parent::dump();

View File

@ -64,7 +64,8 @@ class Directory extends Entry
$this->children = $final;
}
private function sortBucket($bucket, $final) {
private function sortBucket($bucket, $final)
{
uasort($bucket, function(Entry $a, Entry $b) {
return strcasecmp($a->getName(), $b->getName());
});

1
themes/daux_singlepage/css/main.min.css vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,303 @@
section.content {
padding: 25px;
padding-top: 15px;
background-color: white;
& > *:first-child {
margin-top: 0 !important; }
& > *:last-child {
margin-bottom: 0 !important; }
a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }
h1, h2, h3, h4, h5, h6 {
line-height: 1.7;
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }
h1 tt, h1 code {
font-size: inherit; }
h2 tt, h2 code {
font-size: inherit; }
h3 tt, h3 code {
font-size: inherit; }
h4 tt, h4 code {
font-size: inherit; }
h5 tt, h5 code {
font-size: inherit; }
h6 tt, h6 code {
font-size: inherit; }
h1 {
font-size: 28px;
color: black; }
h2 {
font-size: 24px;
border-bottom: 1px solid #eee;
color: black; }
h3 {
font-size: 18px; }
h4 {
font-size: 16px; }
h5 {
font-size: 14px; }
h6 {
color: #777777;
font-size: 14px; }
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0; }
hr {
}
body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }
li p.first {
display: inline-block; }
ul, ol {
padding-left: 30px; }
ul :first-child, ol :first-child {
margin-top: 0; }
ul :last-child, ol :last-child {
margin-bottom: 0; }
ul p {
margin: 0px;
}
ul ul {
margin: 0px;
}
dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }
blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777;
p {
font-size: inherit;
}
}
blockquote > :first-child {
margin-top: 0;
}
blockquote > :last-child {
margin-bottom: 0; }
table {
width: 100%;
padding: 0;
}
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
img {
max-width: 100%;
display: block;
margin: 0px auto;
}
span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left;
& span {
margin: 13px 0 0;
}
}
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right;
& > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right;
}
}
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
.highlight pre {
color: hsl(204, 40%, 80%);
background-color: hsl(204, 30%, 10%);
border: 1px solid hsl(204, 30%, 10%);
font-size: 16px;
line-height: 1.5em;
overflow: auto;
padding: 20px;
margin: 0 -20px;
border-radius: 3px;
}
pre {
color: hsl(204, 40%, 80%);
background-color: hsl(204, 30%, 10%);
border: 1px solid hsl(204, 30%, 10%);
font-size: 16px;
line-height: 1.5em;
overflow: auto;
padding: 20px;
margin: 0 -20px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}
}

View File

@ -0,0 +1,144 @@
@font-face {
font-family: 'EB Garamond';
font-style: normal;
font-weight: 400;
src: local('EB Garamond 12 Regular'),url(//brick.a.ssl.fastly.net/fonts/ebgaramond/400.woff) format('woff');
}
@font-face {
font-family: 'EB Garamond';
font-style: italic;
font-weight: 400i;
src: local('EB Garamond 12 Italic'),url(//brick.a.ssl.fastly.net/fonts/ebgaramond/400i.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 250;
src: local('Merriweather Light'),url(//brick.a.ssl.fastly.net/fonts/merriweather/250.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 250i;
src: local('Merriweather Light Italic'),url(//brick.a.ssl.fastly.net/fonts/merriweather/250i.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
src: local('Merriweather'),url(//brick.a.ssl.fastly.net/fonts/merriweather/400.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 400i;
src: local('Merriweather Italic'),url(//brick.a.ssl.fastly.net/fonts/merriweather/400i.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 600;
src: local(''),url(//brick.a.ssl.fastly.net/fonts/merriweather/600.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 600i;
src: local(''),url(//brick.a.ssl.fastly.net/fonts/merriweather/600i.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
src: local('Merriweather Bold'),url(//brick.a.ssl.fastly.net/fonts/merriweather/700.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 700i;
src: local('Merriweather Bold Italic'),url(//brick.a.ssl.fastly.net/fonts/merriweather/700i.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 900;
src: local('Merriweather Heavy'),url(//brick.a.ssl.fastly.net/fonts/merriweather/900.woff) format('woff');
}
@font-face {
font-family: 'Merriweather';
font-style: italic;
font-weight: 900i;
src: local('Merriweather Heavy Italic'),url(//brick.a.ssl.fastly.net/fonts/merriweather/900i.woff) format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: normal;
font-weight: 400;
src: local('Anonymous Pro'),url(//brick.a.ssl.fastly.net/fonts/anonymouspro/400.woff) format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: italic;
font-weight: 400i;
src: local('Anonymous Pro Italic'),url(//brick.a.ssl.fastly.net/fonts/anonymouspro/400i.woff) format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: normal;
font-weight: 700;
src: local('Anonymous Pro Bold'),url(//brick.a.ssl.fastly.net/fonts/anonymouspro/700.woff) format('woff');
}
@font-face {
font-family: 'Anonymous Pro';
font-style: italic;
font-weight: 700i;
src: local('Anonymous Pro Bold Italic'),url(//brick.a.ssl.fastly.net/fonts/anonymouspro/700i.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'),url(//brick.a.ssl.fastly.net/fonts/opensans/300.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300i;
src: local('Open Sans Light Italic'),url(//brick.a.ssl.fastly.net/fonts/opensans/300i.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans Regular'),url(//brick.a.ssl.fastly.net/fonts/opensans/400.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400i;
src: local('Open Sans Italic'),url(//brick.a.ssl.fastly.net/fonts/opensans/400i.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: local('Open Sans Semibold'),url(//brick.a.ssl.fastly.net/fonts/opensans/600.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 600i;
src: local('Open Sans Semibold Italic'),url(//brick.a.ssl.fastly.net/fonts/opensans/600i.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: local('Open Sans Bold'),url(//brick.a.ssl.fastly.net/fonts/opensans/700.woff) format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700i;
src: local('Open Sans Bold Italic'),url(//brick.a.ssl.fastly.net/fonts/opensans/700i.woff) format('woff');
}

View File

@ -0,0 +1,90 @@
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Tomorrow Comment */
.hljs-comment {
color: hsl(207, 35%, 35%);
}
/* 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-constant,
.hljs-function .hljs-title {
color: hsl(50, 100%, 60%);
}
/* 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: hsl(0, 100%, 70%);
}
/* Tomorrow Aqua */
.css .hljs-hexcolor {
color: #3e999f;
}
/* Tomorrow Blue */
.hljs-function .keyword,
.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: hsl(207, 70%, 60%);
}
/* Tomorrow Purple */
.hljs-keyword,
.javascript .hljs-function {
color: hsl(207, 95%, 70%);
}
.hljs {
display: block;
background: white;
color: #4d4d4c;
padding: 0.5em;
font-family: "Anonymous Pro", "Inconsolata", "Monaco", monospace;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.5;
}

View File

@ -0,0 +1,47 @@
// Core variables and mixins
@import "vendors/bootstrap/variables.less";
@import "vendors/bootstrap/normalize.less";
@import "vendors/bootstrap/scaffolding.less";
@import "vendors/bootstrap/type.less";
@import "variables.less";
@import "fonts.less";
@import "highlight.less";
@import "book/markdown.less";
* {
-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;
}
img {
max-width: 100% !important;
}
.page-break { display: none; }
@media screen {
body {
margin:1em;
}
}
@media print {
@import "print.less";
}

View File

@ -0,0 +1,36 @@
* {
text-shadow: none !important;
color: #000 !important; // Black prints faster: h5bp.com/s
background: transparent !important;
box-shadow: none !important;
}
.page-break { display:block; page-break-before:always; }
h1, h2 {
page-break-after:avoid;
page-break-before:auto;
}
pre, blockquote {
border:1px solid #999;
page-break-inside:avoid;
}
img {
page-break-inside:avoid;
}
a,
a:visited {
text-decoration: underline;
}
a[href]:after {
content: " (" attr(href) ")";
}
abbr[title]:after {
content: " (" attr(title) ")";
}

View File

@ -0,0 +1,85 @@
@staticPath: "./";
// Sizes
@mobileMaxWidth: 1240px;
// Header
@header-height: 50px;
@header-color: hsl(194, 5%, 52%);
@header-background: white;
@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-color: hsl(207, 15%, 80%);
@sidebar-background: hsl(207, 15%, 95%);
@sidebar-nested-padding: 10px;
@sidebar-search-padding: 6px;
@sidebar-search-background: hsl(207, 15%, 80%);
@sidebar-search-border-color: hsl(207, 15%, 80%);
@sidebar-divider-color: hsl(207, 15%, 85%);
@sidebar-link-color: hsl(207, 15%, 50%);
@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-weight: normal;
// Page
@page-background: white;
// Progress Bar
@chapter-display: none;
@chapter-size: 16px;
@progress-height: 0px;
@bar-height: 2px;
@bar-left: @sidebar-width;
@bar-right: 0;
@bar-top: 50px;
@bar-position: fixed;
@bar-background: white;
@bar-progress-background: hsl(120, 60%, 50%);
// Basics of a navbar
@navbar-height: 50px;
@navbar-margin-bottom: @line-height-computed;
@navbar-default-border: #d5d5d5;
@navbar-border-radius: 0px;
@navbar-padding-horizontal: floor(@grid-gutter-width / 2);
@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
// Navbar brand label
@navbar-default-color: #333;
@navbar-default-link-color: #333;
@navbar-default-brand-color: @navbar-default-link-color;
@navbar-default-brand-hover-color: @navbar-default-link-color;
@navbar-default-brand-hover-bg: transparent;
// Border Radius
@border-radius-base: 1px;
@border-radius-large: 3px;
@border-radius-small: 1px;
// Fonts
@font-family-serif: Merriweather, "EB Garamond", Georgia, serif;
@font-family-sans: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-base: @font-family-serif;
@FontPath: '@{staticPath}/gitbook/fonts';
@fa-font-path: "@{FontPath}/fontawesome";

View File

@ -0,0 +1,396 @@
/*! normalize.css v2.1.0 | MIT License | git.io/normalize */
// ==========================================================================
// HTML5 display definitions
// ==========================================================================
//
// Correct `block` display not defined in IE 8/9.
//
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
//
// Correct `inline-block` display not defined in IE 8/9.
//
audio,
canvas,
video {
display: inline-block;
}
//
// Prevent modern browsers from displaying `audio` without controls.
// Remove excess height in iOS 5 devices.
//
audio:not([controls]) {
display: none;
height: 0;
}
//
// Address styling not present in IE 8/9.
//
[hidden] {
display: none;
}
// ==========================================================================
// Base
// ==========================================================================
//
// 1. Set default font family to sans-serif.
// 2. Prevent iOS text size adjust after orientation change, without disabling
// user zoom.
//
html {
font-family: sans-serif; // 1
-webkit-text-size-adjust: 100%; // 2
-ms-text-size-adjust: 100%; // 2
}
//
// Remove default margin.
//
body {
margin: 0;
}
// ==========================================================================
// Links
// ==========================================================================
//
// Address `outline` inconsistency between Chrome and other browsers.
//
a:focus {
outline: thin dotted;
}
//
// Improve readability when focused and also mouse hovered in all browsers.
//
a:active,
a:hover {
outline: 0;
}
// ==========================================================================
// Typography
// ==========================================================================
//
// Address variable `h1` font-size and margin within `section` and `article`
// contexts in Firefox 4+, Safari 5, and Chrome.
//
h1 {
font-size: 2em;
margin: 0.67em 0;
}
//
// Address styling not present in IE 8/9, Safari 5, and Chrome.
//
abbr[title] {
border-bottom: 1px dotted;
}
//
// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
//
b,
strong {
font-weight: bold;
}
//
// Address styling not present in Safari 5 and Chrome.
//
dfn {
font-style: italic;
}
//
// Address differences between Firefox and other browsers.
//
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
//
// Address styling not present in IE 8/9.
//
mark {
background: #ff0;
color: #000;
}
//
// Correct font family set oddly in Safari 5 and Chrome.
//
code,
kbd,
pre,
samp {
font-family: monospace, serif;
font-size: 1em;
}
//
// Improve readability of pre-formatted text in all browsers.
//
pre {
white-space: pre-wrap;
}
//
// Set consistent quote types.
//
q {
quotes: "\201C" "\201D" "\2018" "\2019";
}
//
// Address inconsistent and variable font size in all browsers.
//
small {
font-size: 80%;
}
//
// Prevent `sub` and `sup` affecting `line-height` in all browsers.
//
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
// ==========================================================================
// Embedded content
// ==========================================================================
//
// Remove border when inside `a` element in IE 8/9.
//
img {
border: 0;
}
//
// Correct overflow displayed oddly in IE 9.
//
svg:not(:root) {
overflow: hidden;
}
// ==========================================================================
// Figures
// ==========================================================================
//
// Address margin not present in IE 8/9 and Safari 5.
//
figure {
margin: 0;
}
// ==========================================================================
// Forms
// ==========================================================================
//
// Define consistent border, margin, and padding.
//
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
//
// 1. Correct `color` not being inherited in IE 8/9.
// 2. Remove padding so people aren't caught out if they zero out fieldsets.
//
legend {
border: 0; // 1
padding: 0; // 2
}
//
// 1. Correct font family not being inherited in all browsers.
// 2. Correct font size not being inherited in all browsers.
// 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
//
button,
input,
select,
textarea {
font-family: inherit; // 1
font-size: 100%; // 2
margin: 0; // 3
}
//
// Address Firefox 4+ setting `line-height` on `input` using `!important` in
// the UA stylesheet.
//
button,
input {
line-height: normal;
}
//
// Address inconsistent `text-transform` inheritance for `button` and `select`.
// All other form control elements do not inherit `text-transform` values.
// Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
// Correct `select` style inheritance in Firefox 4+ and Opera.
//
button,
select {
text-transform: none;
}
//
// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
// and `video` controls.
// 2. Correct inability to style clickable `input` types in iOS.
// 3. Improve usability and consistency of cursor style between image-type
// `input` and others.
//
button,
html input[type="button"], // 1
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; // 2
cursor: pointer; // 3
}
//
// Re-set default cursor for disabled elements.
//
button[disabled],
html input[disabled] {
cursor: default;
}
//
// 1. Address box sizing set to `content-box` in IE 8/9.
// 2. Remove excess padding in IE 8/9.
//
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; // 1
padding: 0; // 2
}
//
// 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
// 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
// (include `-moz` to future-proof).
//
input[type="search"] {
-webkit-appearance: textfield; // 1
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; // 2
box-sizing: content-box;
}
//
// Remove inner padding and search cancel button in Safari 5 and Chrome
// on OS X.
//
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
//
// Remove inner padding and border in Firefox 4+.
//
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
//
// 1. Remove default vertical scrollbar in IE 8/9.
// 2. Improve readability and alignment in all browsers.
//
textarea {
overflow: auto; // 1
vertical-align: top; // 2
}
// ==========================================================================
// Tables
// ==========================================================================
//
// Remove most spacing between table cells.
//
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,105 @@
//
// Scaffolding
// --------------------------------------------------
// Reset the box-sizing
*,
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
// Body reset
html {
font-size: 62.5%;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
body {
font-family: @font-family-base;
font-size: @font-size-base;
line-height: @line-height-base;
color: @text-color;
background-color: @body-bg;
}
// Reset fonts for relevant elements
input,
button,
select,
textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
// Reset unusual Firefox-on-Android default style.
//
// See https://github.com/necolas/normalize.css/issues/214
button,
input,
select[multiple],
textarea {
background-image: none;
}
// Links
a {
color: @link-color;
text-decoration: none;
&:hover,
&:focus {
color: @link-hover-color;
text-decoration: underline;
}
&:focus {
// Default
outline: thin dotted #333;
// Webkit
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
}
// Images
img {
vertical-align: middle;
}
// Horizontal rules
hr {
margin-top: @line-height-computed;
margin-bottom: @line-height-computed;
border: 0;
border-top: 1px solid @hr-border;
}
// Only display content to screen readers
//
// See: http://a11yproject.com/posts/how-to-hide-content/
.sr-only {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
border: 0;
}

View File

@ -0,0 +1,247 @@
//
// Typography
// --------------------------------------------------
// Body text
// -------------------------
p {
margin: 0 0 (@line-height-computed / 2);
}
.lead {
margin-bottom: @line-height-computed;
font-size: (@font-size-base * 1.15);
font-weight: 200;
line-height: 1.4;
@media (min-width: 768px) {
font-size: (@font-size-base * 1.5);
}
}
// Emphasis & misc
// -------------------------
// Ex: 14px base font * 85% = about 12px
small { font-size: 85%; }
// Undo browser default styling
cite { font-style: normal; }
// Contextual emphasis
.text-muted { color: @text-muted; }
.text-primary { color: @brand-primary; }
.text-warning { color: @state-warning-text; }
.text-danger { color: @state-danger-text; }
.text-success { color: @state-success-text; }
.text-info { color: @state-info-text; }
// Alignment
.text-left { text-align: left; }
.text-right { text-align: right; }
.text-center { text-align: center; }
// Headings
// -------------------------
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
font-family: @headings-font-family;
font-weight: @headings-font-weight;
line-height: @headings-line-height;
small {
font-weight: normal;
line-height: 1;
color: @headings-small-color;
}
}
h1,
h2,
h3 {
margin-top: @line-height-computed;
margin-bottom: (@line-height-computed / 2);
}
h4,
h5,
h6 {
margin-top: (@line-height-computed / 2);
margin-bottom: (@line-height-computed / 2);
}
h1, .h1 { font-size: floor(@font-size-base * 2.60); } // ~36px
h2, .h2 { font-size: floor(@font-size-base * 2.15); } // ~30px
h3, .h3 { font-size: ceil(@font-size-base * 1.70); } // ~24px
h4, .h4 { font-size: ceil(@font-size-base * 1.25); } // ~18px
h5, .h5 { font-size: @font-size-base; }
h6, .h6 { font-size: ceil(@font-size-base * 0.85); } // ~12px
h1 small, .h1 small { font-size: ceil(@font-size-base * 1.70); } // ~24px
h2 small, .h2 small { font-size: ceil(@font-size-base * 1.25); } // ~18px
h3 small, .h3 small,
h4 small, .h4 small { font-size: @font-size-base; }
// Page header
// -------------------------
.page-header {
padding-bottom: ((@line-height-computed / 2) - 1);
margin: (@line-height-computed * 2) 0 @line-height-computed;
border-bottom: 1px solid @page-header-border-color;
}
// Lists
// --------------------------------------------------
// Unordered and Ordered lists
ul,
ol {
margin-top: 0;
margin-bottom: (@line-height-computed / 2);
ul,
ol{
margin-bottom: 0;
}
}
// List options
// Unstyled keeps list items block level, just removes default browser padding and list-style
.list-unstyled {
padding-left: 0;
list-style: none;
}
// Inline turns list items into inline-block
.list-inline {
.list-unstyled();
> li {
display: inline-block;
padding-left: 5px;
padding-right: 5px;
}
}
// Description Lists
dl {
margin-bottom: @line-height-computed;
}
dt,
dd {
line-height: @line-height-base;
}
dt {
font-weight: bold;
}
dd {
margin-left: 0; // Undo browser default
}
// Horizontal description lists
//
// Defaults to being stacked without any of the below styles applied, until the
// grid breakpoint is reached (default of ~768px).
@media (min-width: @grid-float-breakpoint) {
.dl-horizontal {
dt {
float: left;
width: (@component-offset-horizontal - 20);
clear: left;
text-align: right;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
dd {
margin-left: @component-offset-horizontal;
&:before,
&:after {
content: " "; /* 1 */
display: table; /* 2 */
}
&:after {
clear: both;
}
}
}
}
// MISC
// ----
// Abbreviations and acronyms
abbr[title],
// Added data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
abbr[data-original-title] {
cursor: help;
border-bottom: 1px dotted @abbr-border-color;
}
abbr.initialism {
font-size: 90%;
text-transform: uppercase;
}
// Blockquotes
blockquote {
padding: (@line-height-computed / 2) @line-height-computed;
margin: 0 0 @line-height-computed;
border-left: 5px solid @blockquote-border-color;
p {
font-size: (@font-size-base * 1.25);
font-weight: 300;
line-height: 1.25;
}
p:last-child {
margin-bottom: 0;
}
small {
display: block;
line-height: @line-height-base;
color: @blockquote-small-color;
&:before {
content: '\2014 \00A0';// EM DASH, NBSP
}
}
// Float right with text-align: right
&.pull-right {
padding-right: 15px;
padding-left: 0;
border-right: 5px solid @blockquote-border-color;
border-left: 0;
p,
small {
text-align: right;
}
small {
&:before {
content: '';
}
&:after {
content: '\00A0 \2014';// NBSP, EM DASH
}
}
}
}
// Quotes
q:before,
q:after,
blockquote:before,
blockquote:after {
content: "";
}
// Addresses
address {
display: block;
margin-bottom: @line-height-computed;
font-style: normal;
line-height: @line-height-base;
}

View File

@ -0,0 +1,620 @@
//
// Variables
// --------------------------------------------------
// Global values
// --------------------------------------------------
// Grays
// -------------------------
@gray-darker: lighten(#000, 13.5%); // #222
@gray-dark: lighten(#000, 20%); // #333
@gray: lighten(#000, 33.5%); // #555
@gray-light: lighten(#000, 60%); // #999
@gray-lighter: lighten(#000, 93.5%); // #eee
// Brand colors
// -------------------------
@brand-primary: #428bca;
@brand-success: #5cb85c;
@brand-warning: #f0ad4e;
@brand-danger: #d9534f;
@brand-info: #5bc0de;
// Scaffolding
// -------------------------
@body-bg: #fff;
@text-color: @gray-dark;
// Links
// -------------------------
@link-color: @brand-primary;
@link-hover-color: darken(@link-color, 15%);
// Typography
// -------------------------
@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-serif: Georgia, "Times New Roman", Times, serif;
@font-family-monospace: Monaco, Menlo, Consolas, "Courier New", monospace;
@font-family-base: @font-family-sans-serif;
@font-size-base: 14px;
@font-size-large: ceil(@font-size-base * 1.25); // ~18px
@font-size-small: ceil(@font-size-base * 0.85); // ~12px
@line-height-base: 1.428571429; // 20/14
@line-height-computed: floor(@font-size-base * @line-height-base); // ~20px
@headings-font-family: @font-family-base;
@headings-font-weight: 500;
@headings-line-height: 1.1;
// Iconography
// -------------------------
@icon-font-path: "../fonts/";
@icon-font-name: "glyphicons-halflings-regular";
// Components
// -------------------------
// Based on 14px font-size and 1.428 line-height (~20px to start)
@padding-base-vertical: 6px;
@padding-base-horizontal: 12px;
@padding-large-vertical: 10px;
@padding-large-horizontal: 16px;
@padding-small-vertical: 5px;
@padding-small-horizontal: 10px;
@line-height-large: 1.33;
@line-height-small: 1.5;
@border-radius-base: 4px;
@border-radius-large: 6px;
@border-radius-small: 3px;
@component-active-bg: @brand-primary;
@caret-width-base: 4px;
@caret-width-large: 5px;
// Tables
// -------------------------
@table-cell-padding: 8px;
@table-condensed-cell-padding: 5px;
@table-bg: transparent; // overall background-color
@table-bg-accent: #f9f9f9; // for striping
@table-bg-hover: #f5f5f5;
@table-bg-active: @table-bg-hover;
@table-border-color: #ddd; // table and cell border
// Buttons
// -------------------------
@btn-font-weight: normal;
@btn-default-color: #333;
@btn-default-bg: #fff;
@btn-default-border: #ccc;
@btn-primary-color: #fff;
@btn-primary-bg: @brand-primary;
@btn-primary-border: darken(@btn-primary-bg, 5%);
@btn-success-color: #fff;
@btn-success-bg: @brand-success;
@btn-success-border: darken(@btn-success-bg, 5%);
@btn-warning-color: #fff;
@btn-warning-bg: @brand-warning;
@btn-warning-border: darken(@btn-warning-bg, 5%);
@btn-danger-color: #fff;
@btn-danger-bg: @brand-danger;
@btn-danger-border: darken(@btn-danger-bg, 5%);
@btn-info-color: #fff;
@btn-info-bg: @brand-info;
@btn-info-border: darken(@btn-info-bg, 5%);
@btn-link-disabled-color: @gray-light;
// Forms
// -------------------------
@input-bg: #fff;
@input-bg-disabled: @gray-lighter;
@input-color: @gray;
@input-border: #ccc;
@input-border-radius: @border-radius-base;
@input-border-focus: #66afe9;
@input-color-placeholder: @gray-light;
@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
@input-height-large: (floor(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
@legend-color: @gray-dark;
@legend-border-color: #e5e5e5;
@input-group-addon-bg: @gray-lighter;
@input-group-addon-border-color: @input-border;
// Dropdowns
// -------------------------
@dropdown-bg: #fff;
@dropdown-border: rgba(0,0,0,.15);
@dropdown-fallback-border: #ccc;
@dropdown-divider-bg: #e5e5e5;
@dropdown-link-active-color: #fff;
@dropdown-link-active-bg: @component-active-bg;
@dropdown-link-color: @gray-dark;
@dropdown-link-hover-color: #fff;
@dropdown-link-hover-bg: @dropdown-link-active-bg;
@dropdown-link-disabled-color: @gray-light;
@dropdown-header-color: @gray-light;
@dropdown-caret-color: #000;
// COMPONENT VARIABLES
// --------------------------------------------------
// Z-index master list
// -------------------------
// Used for a bird's eye view of components dependent on the z-axis
// Try to avoid customizing these :)
@zindex-navbar: 1000;
@zindex-dropdown: 1000;
@zindex-popover: 1010;
@zindex-tooltip: 1030;
@zindex-navbar-fixed: 1030;
@zindex-modal-background: 1040;
@zindex-modal: 1050;
// Media queries breakpoints
// --------------------------------------------------
// Extra small screen / phone
@screen-xs: 480px;
@screen-phone: @screen-xs;
// Small screen / tablet
@screen-sm: 768px;
@screen-tablet: @screen-sm;
// Medium screen / desktop
@screen-md: 992px;
@screen-desktop: @screen-md;
// Large screen / wide desktop
@screen-lg: 1200px;
@screen-lg-desktop: @screen-lg;
// So media queries don't overlap when required, provide a maximum
@screen-xs-max: (@screen-sm - 1);
@screen-sm-max: (@screen-md - 1);
@screen-md-max: (@screen-lg - 1);
// Grid system
// --------------------------------------------------
// Number of columns in the grid system
@grid-columns: 12;
// Padding, to be divided by two and applied to the left and right of all columns
@grid-gutter-width: 30px;
// Point at which the navbar stops collapsing
@grid-float-breakpoint: @screen-tablet;
// Navbar
// -------------------------
// Basics of a navbar
@navbar-height: 50px;
@navbar-margin-bottom: @line-height-computed;
@navbar-default-color: #777;
@navbar-default-bg: #f8f8f8;
@navbar-default-border: darken(@navbar-default-bg, 6.5%);
@navbar-border-radius: @border-radius-base;
@navbar-padding-horizontal: floor(@grid-gutter-width / 2);
@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
// Navbar links
@navbar-default-link-color: #777;
@navbar-default-link-hover-color: #333;
@navbar-default-link-hover-bg: transparent;
@navbar-default-link-active-color: #555;
@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
@navbar-default-link-disabled-color: #ccc;
@navbar-default-link-disabled-bg: transparent;
// Navbar brand label
@navbar-default-brand-color: @navbar-default-link-color;
@navbar-default-brand-hover-color: darken(@navbar-default-link-color, 10%);
@navbar-default-brand-hover-bg: transparent;
// Navbar toggle
@navbar-default-toggle-hover-bg: #ddd;
@navbar-default-toggle-icon-bar-bg: #ccc;
@navbar-default-toggle-border-color: #ddd;
// Inverted navbar
//
// Reset inverted navbar basics
@navbar-inverse-color: @gray-light;
@navbar-inverse-bg: #222;
@navbar-inverse-border: darken(@navbar-inverse-bg, 10%);
// Inverted navbar links
@navbar-inverse-link-color: @gray-light;
@navbar-inverse-link-hover-color: #fff;
@navbar-inverse-link-hover-bg: transparent;
@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
@navbar-inverse-link-disabled-color: #444;
@navbar-inverse-link-disabled-bg: transparent;
// Inverted navbar brand label
@navbar-inverse-brand-color: @navbar-inverse-link-color;
@navbar-inverse-brand-hover-color: #fff;
@navbar-inverse-brand-hover-bg: transparent;
// Inverted navbar search
// Normal navbar needs no special styles or vars
@navbar-inverse-search-bg: lighten(@navbar-inverse-bg, 25%);
@navbar-inverse-search-bg-focus: #fff;
@navbar-inverse-search-border: @navbar-inverse-bg;
@navbar-inverse-search-placeholder-color: #ccc;
// Inverted navbar toggle
@navbar-inverse-toggle-hover-bg: #333;
@navbar-inverse-toggle-icon-bar-bg: #fff;
@navbar-inverse-toggle-border-color: #333;
// Navs
// -------------------------
@nav-link-padding: 10px 15px;
@nav-link-hover-bg: @gray-lighter;
@nav-disabled-link-color: @gray-light;
@nav-disabled-link-hover-color: @gray-light;
@nav-open-link-hover-color: #fff;
@nav-open-caret-border-color: #fff;
// Tabs
@nav-tabs-border-color: #ddd;
@nav-tabs-link-hover-border-color: @gray-lighter;
@nav-tabs-active-link-hover-bg: @body-bg;
@nav-tabs-active-link-hover-color: @gray;
@nav-tabs-active-link-hover-border-color: #ddd;
@nav-tabs-justified-link-border-color: #ddd;
@nav-tabs-justified-active-link-border-color: @body-bg;
// Pills
@nav-pills-active-link-hover-bg: @component-active-bg;
@nav-pills-active-link-hover-color: #fff;
// Pagination
// -------------------------
@pagination-bg: #fff;
@pagination-border: #ddd;
@pagination-hover-bg: @gray-lighter;
@pagination-active-bg: @brand-primary;
@pagination-active-color: #fff;
@pagination-disabled-color: @gray-light;
// Pager
// -------------------------
@pager-border-radius: 15px;
@pager-disabled-color: @gray-light;
// Jumbotron
// -------------------------
@jumbotron-padding: 30px;
@jumbotron-color: inherit;
@jumbotron-bg: @gray-lighter;
@jumbotron-heading-color: inherit;
// Form states and alerts
// -------------------------
@state-warning-text: #c09853;
@state-warning-bg: #fcf8e3;
@state-warning-border: darken(spin(@state-warning-bg, -10), 3%);
@state-danger-text: #b94a48;
@state-danger-bg: #f2dede;
@state-danger-border: darken(spin(@state-danger-bg, -10), 3%);
@state-success-text: #468847;
@state-success-bg: #dff0d8;
@state-success-border: darken(spin(@state-success-bg, -10), 5%);
@state-info-text: #3a87ad;
@state-info-bg: #d9edf7;
@state-info-border: darken(spin(@state-info-bg, -10), 7%);
// Tooltips
// -------------------------
@tooltip-max-width: 200px;
@tooltip-color: #fff;
@tooltip-bg: #000;
@tooltip-arrow-width: 5px;
@tooltip-arrow-color: @tooltip-bg;
// Popovers
// -------------------------
@popover-bg: #fff;
@popover-max-width: 276px;
@popover-border-color: rgba(0,0,0,.2);
@popover-fallback-border-color: #ccc;
@popover-title-bg: darken(@popover-bg, 3%);
@popover-arrow-width: 10px;
@popover-arrow-color: #fff;
@popover-arrow-outer-width: (@popover-arrow-width + 1);
@popover-arrow-outer-color: rgba(0,0,0,.25);
@popover-arrow-outer-fallback-color: #999;
// Labels
// -------------------------
@label-default-bg: @gray-light;
@label-primary-bg: @brand-primary;
@label-success-bg: @brand-success;
@label-info-bg: @brand-info;
@label-warning-bg: @brand-warning;
@label-danger-bg: @brand-danger;
@label-color: #fff;
@label-link-hover-color: #fff;
// Modals
// -------------------------
@modal-inner-padding: 20px;
@modal-title-padding: 15px;
@modal-title-line-height: @line-height-base;
@modal-content-bg: #fff;
@modal-content-border-color: rgba(0,0,0,.2);
@modal-content-fallback-border-color: #999;
@modal-backdrop-bg: #000;
@modal-header-border-color: #e5e5e5;
@modal-footer-border-color: @modal-header-border-color;
// Alerts
// -------------------------
@alert-padding: 15px;
@alert-border-radius: @border-radius-base;
@alert-link-font-weight: bold;
@alert-success-bg: @state-success-bg;
@alert-success-text: @state-success-text;
@alert-success-border: @state-success-border;
@alert-info-bg: @state-info-bg;
@alert-info-text: @state-info-text;
@alert-info-border: @state-info-border;
@alert-warning-bg: @state-warning-bg;
@alert-warning-text: @state-warning-text;
@alert-warning-border: @state-warning-border;
@alert-danger-bg: @state-danger-bg;
@alert-danger-text: @state-danger-text;
@alert-danger-border: @state-danger-border;
// Progress bars
// -------------------------
@progress-bg: #f5f5f5;
@progress-bar-color: #fff;
@progress-bar-bg: @brand-primary;
@progress-bar-success-bg: @brand-success;
@progress-bar-warning-bg: @brand-warning;
@progress-bar-danger-bg: @brand-danger;
@progress-bar-info-bg: @brand-info;
// List group
// -------------------------
@list-group-bg: #fff;
@list-group-border: #ddd;
@list-group-border-radius: @border-radius-base;
@list-group-hover-bg: #f5f5f5;
@list-group-active-color: #fff;
@list-group-active-bg: @component-active-bg;
@list-group-active-border: @list-group-active-bg;
@list-group-link-color: #555;
@list-group-link-heading-color: #333;
// Panels
// -------------------------
@panel-bg: #fff;
@panel-inner-border: #ddd;
@panel-border-radius: @border-radius-base;
@panel-footer-bg: #f5f5f5;
@panel-default-text: @gray-dark;
@panel-default-border: #ddd;
@panel-default-heading-bg: #f5f5f5;
@panel-primary-text: #fff;
@panel-primary-border: @brand-primary;
@panel-primary-heading-bg: @brand-primary;
@panel-success-text: @state-success-text;
@panel-success-border: @state-success-border;
@panel-success-heading-bg: @state-success-bg;
@panel-warning-text: @state-warning-text;
@panel-warning-border: @state-warning-border;
@panel-warning-heading-bg: @state-warning-bg;
@panel-danger-text: @state-danger-text;
@panel-danger-border: @state-danger-border;
@panel-danger-heading-bg: @state-danger-bg;
@panel-info-text: @state-info-text;
@panel-info-border: @state-info-border;
@panel-info-heading-bg: @state-info-bg;
// Thumbnails
// -------------------------
@thumbnail-padding: 4px;
@thumbnail-bg: @body-bg;
@thumbnail-border: #ddd;
@thumbnail-border-radius: @border-radius-base;
@thumbnail-caption-color: @text-color;
@thumbnail-caption-padding: 9px;
// Wells
// -------------------------
@well-bg: #f5f5f5;
// Badges
// -------------------------
@badge-color: #fff;
@badge-link-hover-color: #fff;
@badge-bg: @gray-light;
@badge-active-color: @link-color;
@badge-active-bg: #fff;
@badge-font-weight: bold;
@badge-line-height: 1;
@badge-border-radius: 10px;
// Breadcrumbs
// -------------------------
@breadcrumb-bg: #f5f5f5;
@breadcrumb-color: #ccc;
@breadcrumb-active-color: @gray-light;
// Carousel
// ------------------------
@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
@carousel-control-color: #fff;
@carousel-control-width: 15%;
@carousel-control-opacity: .5;
@carousel-control-font-size: 20px;
@carousel-indicator-active-bg: #fff;
@carousel-indicator-border-color: #fff;
@carousel-caption-color: #fff;
// Close
// ------------------------
@close-color: #000;
@close-font-weight: bold;
@close-text-shadow: 0 1px 0 #fff;
// Code
// ------------------------
@code-color: #c7254e;
@code-bg: #f9f2f4;
@pre-bg: #f5f5f5;
@pre-color: @gray-dark;
@pre-border-color: #ccc;
@pre-scrollable-max-height: 340px;
// Type
// ------------------------
@text-muted: @gray-light;
@abbr-border-color: @gray-light;
@headings-small-color: @gray-light;
@blockquote-small-color: @gray-light;
@blockquote-border-color: @gray-lighter;
@page-header-border-color: @gray-lighter;
// Miscellaneous
// -------------------------
// Hr border color
@hr-border: @gray-lighter;
// Horizontal forms & lists
@component-offset-horizontal: 180px;
// Container sizes
// --------------------------------------------------
// Small screen / tablet
@container-tablet: ((720px + @grid-gutter-width));
// Medium screen / desktop
@container-desktop: ((940px + @grid-gutter-width));
// Large screen / wide desktop
@container-lg-desktop: ((1140px + @grid-gutter-width));