nitdoc: full rewrite of the nitdoc engine
authorAlexandre Terrasa <alexandre@moz-code.org>
Fri, 1 Jun 2018 15:05:11 +0000 (11:05 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Sun, 10 Jun 2018 17:26:59 +0000 (13:26 -0400)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

15 files changed:
Makefile
share/nitdoc/css/nitdoc.bootstrap.css
share/nitdoc/css/nitdoc.cards.css [new file with mode: 0644]
share/nitdoc/css/nitdoc.code.css [new file with mode: 0644]
share/nitdoc/css/nitdoc.css
share/nitdoc/css/nitdoc.quicksearch.css [new file with mode: 0644]
share/nitdoc/js/nitdoc.quicksearch.js [new file with mode: 0644]
share/nitdoc/js/nitdoc.utils.js [new file with mode: 0644]
src/doc/static/static.nit [new file with mode: 0644]
src/doc/static/static_base.nit [new file with mode: 0644]
src/doc/static/static_cards.nit [new file with mode: 0644]
src/doc/static/static_html.nit [new file with mode: 0644]
src/doc/static/static_index.nit [new file with mode: 0644]
src/doc/static/static_structure.nit [new file with mode: 0644]
src/nitdoc.nit

index 5029f2a..2f6e274 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -60,9 +60,6 @@ doc/stdlib/index.html: bin/nitdoc bin/nitls
                --custom-brand "<a href=\"http://nitlanguage.org/\">Nitlanguage.org</a>" \
                --custom-overview-text "<p>Documentation for the standard library of Nit<br/>Version $$(git describe)<br/>Date: $$(git show --format="%cd" | head -1)</p>" \
                --custom-footer-text "Nit standard library. Version $$(git describe)." \
-               --github-upstream "nitlang:nit:master" \
-               --github-base-sha1 "$$(git rev-parse HEAD)" \
-               --github-gitdir "." \
                --source "https://github.com/nitlang/nit/blob/$$(git rev-parse HEAD)/%f#L%l-%L" \
                --piwik-tracker "pratchett.info.uqam.ca/piwik/" \
                --piwik-site-id "2" \
@@ -74,9 +71,6 @@ doc/nitc/index.html: bin/nitdoc bin/nitls
                --custom-brand "<a href=\"http://nitlanguage.org/\">Nitlanguage.org</a>" \
                --custom-overview-text "<p>Documentation for the Nit tools<br/>Version $$(git describe)<br/>Date: $$(git show --format="%cd" | head -1)</p>" \
                --custom-footer-text "Nit tools. Version $$(git describe)." \
-               --github-upstream "nitlang:nit:master" \
-               --github-base-sha1 "$$(git rev-parse HEAD)" \
-               --github-gitdir "." \
                --source "https://github.com/nitlang/nit/blob/$$(git rev-parse HEAD)/%f#L%l-%L" \
                --piwik-tracker "pratchett.info.uqam.ca/piwik/" \
                --piwik-site-id "3"
index 0351b6f..fd80998 100644 (file)
@@ -1,13 +1,3 @@
-/*!
- * Bootstrap v3.1.1
- *
- * Copyright 2014 Twitter, Inc
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Designed and built with all the love in the world by @mdo and @fat.
- * BootSwatchr built and provided by @DrewStrickland
- */
 /*! normalize.css v3.0.0 | MIT License | git.io/normalize */
 html {
   font-family: sans-serif;
@@ -275,11 +265,11 @@ html {
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
 }
 body {
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-family: sans-serif;
   font-size: 14px;
   line-height: 1.428571429;
   color: #333333;
-  background-color: #ffffff;
+  background-color: #f2f2f2;
 }
 input,
 button,
@@ -290,12 +280,12 @@ textarea {
   line-height: inherit;
 }
 a {
-  color: #222222;
+  color: #0d8921;
   text-decoration: none;
 }
 a:hover,
 a:focus {
-  color: #0d8921;
+  color: #064310;
   text-decoration: underline;
 }
 a:focus {
@@ -319,14 +309,14 @@ img {
   height: auto;
 }
 .img-rounded {
-  border-radius: 4px;
+  border-radius: 0px;
 }
 .img-thumbnail {
   padding: 4px;
   line-height: 1.428571429;
-  background-color: #ffffff;
+  background-color: #f2f2f2;
   border: 1px solid #dddddd;
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-transition: all 0.2s ease-in-out;
   transition: all 0.2s ease-in-out;
   display: inline-block;
@@ -340,7 +330,7 @@ hr {
   margin-top: 20px;
   margin-bottom: 20px;
   border: 0;
-  border-top: 1px solid #eeeeee;
+  border-top: 1px solid #ddd;
 }
 .sr-only {
   position: absolute;
@@ -364,7 +354,7 @@ h6,
 .h4,
 .h5,
 .h6 {
-  font-family: inherit;
+  font-family: sans-serif;
   font-weight: 500;
   line-height: 1.1;
   color: inherit;
@@ -453,11 +443,11 @@ h2,
 }
 h3,
 .h3 {
-  font-size: 24px;
+  font-size: 23px;
 }
 h4,
 .h4 {
-  font-size: 18px;
+  font-size: 17px;
 }
 h5,
 .h5 {
@@ -465,7 +455,7 @@ h5,
 }
 h6,
 .h6 {
-  font-size: 12px;
+  font-size: 11px;
 }
 p {
   margin: 0 0 10px;
@@ -516,10 +506,10 @@ a.text-success:hover {
   color: #449d44;
 }
 .text-info {
-  color: #6c6c6c;
+  color: #5bc0de;
 }
 a.text-info:hover {
-  color: #525252;
+  color: #31b0d5;
 }
 .text-warning {
   color: #f0ad4e;
@@ -541,28 +531,28 @@ a.bg-primary:hover {
   background-color: #095a16;
 }
 .bg-success {
-  background-color: #eaf6ea;
+  background-color: #dff0d8;
 }
 a.bg-success:hover {
-  background-color: #c7e6c7;
+  background-color: #c1e2b3;
 }
 .bg-info {
-  background-color: #ececec;
+  background-color: #d9edf7;
 }
 a.bg-info:hover {
-  background-color: #d2d2d2;
+  background-color: #afd9ee;
 }
 .bg-warning {
-  background-color: #fef9f3;
+  background-color: #fcf8e3;
 }
 a.bg-warning:hover {
-  background-color: #fae3c4;
+  background-color: #f7ecb5;
 }
 .bg-danger {
-  background-color: #f9e2e2;
+  background-color: #f2dede;
 }
 a.bg-danger:hover {
-  background-color: #f0b9b8;
+  background-color: #e4b9b9;
 }
 .page-header {
   padding-bottom: 9px;
@@ -587,13 +577,15 @@ ol ol {
 .list-inline {
   padding-left: 0;
   list-style: none;
-  margin-left: -5px;
 }
 .list-inline > li {
   display: inline-block;
   padding-left: 5px;
   padding-right: 5px;
 }
+.list-inline > li:first-child {
+  padding-left: 0;
+}
 dl {
   margin-top: 0;
   margin-bottom: 20px;
@@ -692,7 +684,7 @@ code,
 kbd,
 pre,
 samp {
-  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+  font-family: monospace;
 }
 code {
   padding: 2px 4px;
@@ -700,14 +692,14 @@ code {
   color: #c7254e;
   background-color: #f9f2f4;
   white-space: nowrap;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 kbd {
   padding: 2px 4px;
   font-size: 90%;
   color: #ffffff;
   background-color: #333333;
-  border-radius: 2px;
+  border-radius: 0px;
   box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
 }
 pre {
@@ -721,7 +713,7 @@ pre {
   color: #333333;
   background-color: #f5f5f5;
   border: 1px solid #cccccc;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 pre code {
   padding: 0;
@@ -1440,7 +1432,7 @@ th {
   border-top: 2px solid #dddddd;
 }
 .table .table {
-  background-color: #ffffff;
+  background-color: #f2f2f2;
 }
 .table-condensed > thead > tr > th,
 .table-condensed > tbody > tr > th,
@@ -1471,7 +1463,7 @@ th {
 }
 .table-hover > tbody > tr:hover > td,
 .table-hover > tbody > tr:hover > th {
-  background-color: #f5f5f5;
+  background-color: #dbdbdb;
 }
 table col[class*="col-"] {
   position: static;
@@ -1496,13 +1488,13 @@ table th[class*="col-"] {
 .table > thead > tr.active > th,
 .table > tbody > tr.active > th,
 .table > tfoot > tr.active > th {
-  background-color: #f5f5f5;
+  background-color: #dbdbdb;
 }
 .table-hover > tbody > tr > td.active:hover,
 .table-hover > tbody > tr > th.active:hover,
 .table-hover > tbody > tr.active:hover > td,
 .table-hover > tbody > tr.active:hover > th {
-  background-color: #e8e8e8;
+  background-color: #cecece;
 }
 .table > thead > tr > td.success,
 .table > tbody > tr > td.success,
@@ -1516,13 +1508,13 @@ table th[class*="col-"] {
 .table > thead > tr.success > th,
 .table > tbody > tr.success > th,
 .table > tfoot > tr.success > th {
-  background-color: #eaf6ea;
+  background-color: #dff0d8;
 }
 .table-hover > tbody > tr > td.success:hover,
 .table-hover > tbody > tr > th.success:hover,
 .table-hover > tbody > tr.success:hover > td,
 .table-hover > tbody > tr.success:hover > th {
-  background-color: #d8eed8;
+  background-color: #d0e9c6;
 }
 .table > thead > tr > td.info,
 .table > tbody > tr > td.info,
@@ -1536,13 +1528,13 @@ table th[class*="col-"] {
 .table > thead > tr.info > th,
 .table > tbody > tr.info > th,
 .table > tfoot > tr.info > th {
-  background-color: #ececec;
+  background-color: #d9edf7;
 }
 .table-hover > tbody > tr > td.info:hover,
 .table-hover > tbody > tr > th.info:hover,
 .table-hover > tbody > tr.info:hover > td,
 .table-hover > tbody > tr.info:hover > th {
-  background-color: #dfdfdf;
+  background-color: #c4e3f3;
 }
 .table > thead > tr > td.warning,
 .table > tbody > tr > td.warning,
@@ -1556,13 +1548,13 @@ table th[class*="col-"] {
 .table > thead > tr.warning > th,
 .table > tbody > tr.warning > th,
 .table > tfoot > tr.warning > th {
-  background-color: #fef9f3;
+  background-color: #fcf8e3;
 }
 .table-hover > tbody > tr > td.warning:hover,
 .table-hover > tbody > tr > th.warning:hover,
 .table-hover > tbody > tr.warning:hover > td,
 .table-hover > tbody > tr.warning:hover > th {
-  background-color: #fceedb;
+  background-color: #faf2cc;
 }
 .table > thead > tr > td.danger,
 .table > tbody > tr > td.danger,
@@ -1576,13 +1568,13 @@ table th[class*="col-"] {
 .table > thead > tr.danger > th,
 .table > tbody > tr.danger > th,
 .table > tfoot > tr.danger > th {
-  background-color: #f9e2e2;
+  background-color: #f2dede;
 }
 .table-hover > tbody > tr > td.danger:hover,
 .table-hover > tbody > tr > th.danger:hover,
 .table-hover > tbody > tr.danger:hover > td,
 .table-hover > tbody > tr.danger:hover > th {
-  background-color: #f4cecd;
+  background-color: #ebcccc;
 }
 @media (max-width: 767px) {
   .table-responsive {
@@ -1663,6 +1655,7 @@ input[type="checkbox"] {
   margin: 4px 0 0;
   margin-top: 1px \9;
   /* IE8-9 */
+
   line-height: normal;
 }
 input[type="file"] {
@@ -1685,7 +1678,7 @@ input[type="checkbox"]:focus {
 }
 output {
   display: block;
-  padding-top: 3px;
+  padding-top: 7px;
   font-size: 14px;
   line-height: 1.428571429;
   color: #555555;
@@ -1693,25 +1686,25 @@ output {
 .form-control {
   display: block;
   width: 100%;
-  height: 26px;
-  padding: 2px 5px;
+  height: 34px;
+  padding: 6px 12px;
   font-size: 14px;
   line-height: 1.428571429;
   color: #555555;
   background-color: #ffffff;
   background-image: none;
   border: 1px solid #cccccc;
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
   box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
   -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
   transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
 }
 .form-control:focus {
-  border-color: #6c6c6c;
+  border-color: #66afe9;
   outline: 0;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(108, 108, 108, 0.6);
-  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(108, 108, 108, 0.6);
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
 }
 .form-control::-moz-placeholder {
   color: #999999;
@@ -1737,7 +1730,7 @@ input[type="search"] {
   -webkit-appearance: none;
 }
 input[type="date"] {
-  line-height: 26px;
+  line-height: 34px;
 }
 .form-group {
   margin-bottom: 15px;
@@ -1796,30 +1789,30 @@ fieldset[disabled] .checkbox-inline {
   cursor: not-allowed;
 }
 .input-sm {
-  height: 22px;
-  padding: 1px 5px;
+  height: 30px;
+  padding: 5px 10px;
   font-size: 12px;
   line-height: 1.5;
-  border-radius: 2px;
+  border-radius: 0px;
 }
 select.input-sm {
-  height: 22px;
-  line-height: 22px;
+  height: 30px;
+  line-height: 30px;
 }
 textarea.input-sm,
 select[multiple].input-sm {
   height: auto;
 }
 .input-lg {
-  height: 36px;
-  padding: 5px 10px;
+  height: 45px;
+  padding: 10px 16px;
   font-size: 18px;
   line-height: 1.33;
-  border-radius: 4px;
+  border-radius: 0px;
 }
 select.input-lg {
-  height: 36px;
-  line-height: 36px;
+  height: 45px;
+  line-height: 45px;
 }
 textarea.input-lg,
 select[multiple].input-lg {
@@ -1829,16 +1822,16 @@ select[multiple].input-lg {
   position: relative;
 }
 .has-feedback .form-control {
-  padding-right: 32.5px;
+  padding-right: 42.5px;
 }
 .has-feedback .form-control-feedback {
   position: absolute;
   top: 25px;
   right: 0;
   display: block;
-  width: 26px;
-  height: 26px;
-  line-height: 26px;
+  width: 34px;
+  height: 34px;
+  line-height: 34px;
   text-align: center;
 }
 .has-success .help-block,
@@ -1862,7 +1855,7 @@ select[multiple].input-lg {
 .has-success .input-group-addon {
   color: #5cb85c;
   border-color: #5cb85c;
-  background-color: #eaf6ea;
+  background-color: #dff0d8;
 }
 .has-success .form-control-feedback {
   color: #5cb85c;
@@ -1888,7 +1881,7 @@ select[multiple].input-lg {
 .has-warning .input-group-addon {
   color: #f0ad4e;
   border-color: #f0ad4e;
-  background-color: #fef9f3;
+  background-color: #fcf8e3;
 }
 .has-warning .form-control-feedback {
   color: #f0ad4e;
@@ -1914,7 +1907,7 @@ select[multiple].input-lg {
 .has-error .input-group-addon {
   color: #d9534f;
   border-color: #d9534f;
-  background-color: #f9e2e2;
+  background-color: #f2dede;
 }
 .has-error .form-control-feedback {
   color: #d9534f;
@@ -1970,18 +1963,18 @@ select[multiple].input-lg {
 .form-horizontal .checkbox-inline {
   margin-top: 0;
   margin-bottom: 0;
-  padding-top: 3px;
+  padding-top: 7px;
 }
 .form-horizontal .radio,
 .form-horizontal .checkbox {
-  min-height: 23px;
+  min-height: 27px;
 }
 .form-horizontal .form-group {
   margin-left: -15px;
   margin-right: -15px;
 }
 .form-horizontal .form-control-static {
-  padding-top: 3px;
+  padding-top: 7px;
 }
 @media (min-width: 768px) {
   .form-horizontal .control-label {
@@ -2002,18 +1995,17 @@ select[multiple].input-lg {
   background-image: none;
   border: 1px solid transparent;
   white-space: nowrap;
-  padding: 2px 5px;
+  padding: 6px 12px;
   font-size: 14px;
   line-height: 1.428571429;
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-user-select: none;
   -moz-user-select: none;
   -ms-user-select: none;
+  -o-user-select: none;
   user-select: none;
 }
-.btn:focus,
-.btn:active:focus,
-.btn.active:focus {
+.btn:focus {
   outline: thin dotted;
   outline: 5px auto -webkit-focus-ring-color;
   outline-offset: -2px;
@@ -2165,8 +2157,8 @@ fieldset[disabled] .btn-success.active {
 }
 .btn-info {
   color: #ffffff;
-  background-color: #6c6c6c;
-  border-color: #5f5f5f;
+  background-color: #5bc0de;
+  border-color: #46b8da;
 }
 .btn-info:hover,
 .btn-info:focus,
@@ -2174,8 +2166,8 @@ fieldset[disabled] .btn-success.active {
 .btn-info.active,
 .open .dropdown-toggle.btn-info {
   color: #ffffff;
-  background-color: #585858;
-  border-color: #414141;
+  background-color: #39b3d7;
+  border-color: #269abc;
 }
 .btn-info:active,
 .btn-info.active,
@@ -2197,11 +2189,11 @@ fieldset[disabled] .btn-info:active,
 .btn-info.disabled.active,
 .btn-info[disabled].active,
 fieldset[disabled] .btn-info.active {
-  background-color: #6c6c6c;
-  border-color: #5f5f5f;
+  background-color: #5bc0de;
+  border-color: #46b8da;
 }
 .btn-info .badge {
-  color: #6c6c6c;
+  color: #5bc0de;
   background-color: #ffffff;
 }
 .btn-warning {
@@ -2287,7 +2279,7 @@ fieldset[disabled] .btn-danger.active {
   background-color: #ffffff;
 }
 .btn-link {
-  color: #222222;
+  color: #0d8921;
   font-weight: normal;
   cursor: pointer;
   border-radius: 0;
@@ -2308,7 +2300,7 @@ fieldset[disabled] .btn-link {
 }
 .btn-link:hover,
 .btn-link:focus {
-  color: #0d8921;
+  color: #064310;
   text-decoration: underline;
   background-color: transparent;
 }
@@ -2321,24 +2313,24 @@ fieldset[disabled] .btn-link:focus {
 }
 .btn-lg,
 .btn-group-lg > .btn {
-  padding: 5px 10px;
+  padding: 10px 16px;
   font-size: 18px;
   line-height: 1.33;
-  border-radius: 4px;
+  border-radius: 0px;
 }
 .btn-sm,
 .btn-group-sm > .btn {
-  padding: 1px 5px;
+  padding: 5px 10px;
   font-size: 12px;
   line-height: 1.5;
-  border-radius: 2px;
+  border-radius: 0px;
 }
 .btn-xs,
 .btn-group-xs > .btn {
-  padding: 0px 3px;
+  padding: 1px 5px;
   font-size: 12px;
   line-height: 1.5;
-  border-radius: 2px;
+  border-radius: 0px;
 }
 .btn-block {
   display: block;
@@ -2377,8 +2369,8 @@ input[type="button"].btn-block {
 }
 @font-face {
   font-family: 'Glyphicons Halflings';
-  src: url('../fonts/glyphicons-halflings-regular.eot');
-  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+  src: url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.eot');
+  src: url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.woff') format('woff'), url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
 }
 .glyphicon {
   position: relative;
@@ -3022,7 +3014,7 @@ input[type="button"].btn-block {
   background-color: #ffffff;
   border: 1px solid #cccccc;
   border: 1px solid rgba(0, 0, 0, 0.15);
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
   box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
   background-clip: padding-box;
@@ -3049,8 +3041,8 @@ input[type="button"].btn-block {
 .dropdown-menu > li > a:hover,
 .dropdown-menu > li > a:focus {
   text-decoration: none;
-  color: #262626;
-  background-color: #f5f5f5;
+  color: #ffffff;
+  background-color: #0d8921;
 }
 .dropdown-menu > .active > a,
 .dropdown-menu > .active > a:hover,
@@ -3253,12 +3245,12 @@ input[type="button"].btn-block {
   border-radius: 0;
 }
 .btn-group-vertical > .btn:first-child:not(:last-child) {
-  border-top-right-radius: 3px;
+  border-top-right-radius: 0px;
   border-bottom-right-radius: 0;
   border-bottom-left-radius: 0;
 }
 .btn-group-vertical > .btn:last-child:not(:first-child) {
-  border-bottom-left-radius: 3px;
+  border-bottom-left-radius: 0px;
   border-top-right-radius: 0;
   border-top-left-radius: 0;
 }
@@ -3304,8 +3296,6 @@ input[type="button"].btn-block {
   padding-right: 0;
 }
 .input-group .form-control {
-  position: relative;
-  z-index: 2;
   float: left;
   width: 100%;
   margin-bottom: 0;
@@ -3313,17 +3303,17 @@ input[type="button"].btn-block {
 .input-group-lg > .form-control,
 .input-group-lg > .input-group-addon,
 .input-group-lg > .input-group-btn > .btn {
-  height: 36px;
-  padding: 5px 10px;
+  height: 45px;
+  padding: 10px 16px;
   font-size: 18px;
   line-height: 1.33;
-  border-radius: 4px;
+  border-radius: 0px;
 }
 select.input-group-lg > .form-control,
 select.input-group-lg > .input-group-addon,
 select.input-group-lg > .input-group-btn > .btn {
-  height: 36px;
-  line-height: 36px;
+  height: 45px;
+  line-height: 45px;
 }
 textarea.input-group-lg > .form-control,
 textarea.input-group-lg > .input-group-addon,
@@ -3336,17 +3326,17 @@ select[multiple].input-group-lg > .input-group-btn > .btn {
 .input-group-sm > .form-control,
 .input-group-sm > .input-group-addon,
 .input-group-sm > .input-group-btn > .btn {
-  height: 22px;
-  padding: 1px 5px;
+  height: 30px;
+  padding: 5px 10px;
   font-size: 12px;
   line-height: 1.5;
-  border-radius: 2px;
+  border-radius: 0px;
 }
 select.input-group-sm > .form-control,
 select.input-group-sm > .input-group-addon,
 select.input-group-sm > .input-group-btn > .btn {
-  height: 22px;
-  line-height: 22px;
+  height: 30px;
+  line-height: 30px;
 }
 textarea.input-group-sm > .form-control,
 textarea.input-group-sm > .input-group-addon,
@@ -3373,7 +3363,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   vertical-align: middle;
 }
 .input-group-addon {
-  padding: 2px 5px;
+  padding: 6px 12px;
   font-size: 14px;
   font-weight: normal;
   line-height: 1;
@@ -3381,17 +3371,17 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   text-align: center;
   background-color: #eeeeee;
   border: 1px solid #cccccc;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .input-group-addon.input-sm {
-  padding: 1px 5px;
+  padding: 5px 10px;
   font-size: 12px;
-  border-radius: 2px;
+  border-radius: 0px;
 }
 .input-group-addon.input-lg {
-  padding: 5px 10px;
+  padding: 10px 16px;
   font-size: 18px;
-  border-radius: 4px;
+  border-radius: 0px;
 }
 .input-group-addon input[type="radio"],
 .input-group-addon input[type="checkbox"] {
@@ -3459,12 +3449,12 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 .nav > li > a {
   position: relative;
   display: block;
-  padding: 5px 10px;
+  padding: 10px 15px;
 }
 .nav > li > a:hover,
 .nav > li > a:focus {
   text-decoration: none;
-  background-color: #eeeeee;
+  background-color: #dddddd;
 }
 .nav > li.disabled > a {
   color: #999999;
@@ -3479,8 +3469,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 .nav .open > a,
 .nav .open > a:hover,
 .nav .open > a:focus {
-  background-color: #eeeeee;
-  border-color: #222222;
+  background-color: #dddddd;
+  border-color: #0d8921;
 }
 .nav .nav-divider {
   height: 1px;
@@ -3502,7 +3492,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   margin-right: 2px;
   line-height: 1.428571429;
   border: 1px solid transparent;
-  border-radius: 3px 3px 0 0;
+  border-radius: 0px 0px 0 0;
 }
 .nav-tabs > li > a:hover {
   border-color: #eeeeee #eeeeee #dddddd;
@@ -3511,7 +3501,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 .nav-tabs > li.active > a:hover,
 .nav-tabs > li.active > a:focus {
   color: #555555;
-  background-color: #ffffff;
+  background-color: #f2f2f2;
   border: 1px solid #dddddd;
   border-bottom-color: transparent;
   cursor: default;
@@ -3542,7 +3532,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 }
 .nav-tabs.nav-justified > li > a {
   margin-right: 0;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .nav-tabs.nav-justified > .active > a,
 .nav-tabs.nav-justified > .active > a:hover,
@@ -3552,19 +3542,19 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 @media (min-width: 768px) {
   .nav-tabs.nav-justified > li > a {
     border-bottom: 1px solid #dddddd;
-    border-radius: 3px 3px 0 0;
+    border-radius: 0px 0px 0 0;
   }
   .nav-tabs.nav-justified > .active > a,
   .nav-tabs.nav-justified > .active > a:hover,
   .nav-tabs.nav-justified > .active > a:focus {
-    border-bottom-color: #ffffff;
+    border-bottom-color: #f2f2f2;
   }
 }
 .nav-pills > li {
   float: left;
 }
 .nav-pills > li > a {
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .nav-pills > li + li {
   margin-left: 2px;
@@ -3610,7 +3600,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 }
 .nav-tabs-justified > li > a {
   margin-right: 0;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .nav-tabs-justified > .active > a,
 .nav-tabs-justified > .active > a:hover,
@@ -3620,12 +3610,12 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 @media (min-width: 768px) {
   .nav-tabs-justified > li > a {
     border-bottom: 1px solid #dddddd;
-    border-radius: 3px 3px 0 0;
+    border-radius: 0px 0px 0 0;
   }
   .nav-tabs-justified > .active > a,
   .nav-tabs-justified > .active > a:hover,
   .nav-tabs-justified > .active > a:focus {
-    border-bottom-color: #ffffff;
+    border-bottom-color: #f2f2f2;
   }
 }
 .tab-content > .tab-pane {
@@ -3641,13 +3631,13 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 }
 .navbar {
   position: relative;
-  min-height: 30px;
+  min-height: 50px;
   margin-bottom: 20px;
   border: 1px solid transparent;
 }
 @media (min-width: 768px) {
   .navbar {
-    border-radius: 3px;
+    border-radius: 0px;
   }
 }
 @media (min-width: 768px) {
@@ -3738,10 +3728,10 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 }
 .navbar-brand {
   float: left;
-  padding: 5px 15px;
+  padding: 15px 15px;
   font-size: 18px;
   line-height: 20px;
-  height: 30px;
+  height: 50px;
 }
 .navbar-brand:hover,
 .navbar-brand:focus {
@@ -3758,12 +3748,12 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   float: right;
   margin-right: 15px;
   padding: 9px 10px;
-  margin-top: -2px;
-  margin-bottom: -2px;
+  margin-top: 8px;
+  margin-bottom: 8px;
   background-color: transparent;
   background-image: none;
   border: 1px solid transparent;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .navbar-toggle:focus {
   outline: none;
@@ -3783,7 +3773,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   }
 }
 .navbar-nav {
-  margin: 2.5px -15px;
+  margin: 7.5px -15px;
 }
 .navbar-nav > li > a {
   padding-top: 10px;
@@ -3821,8 +3811,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
     float: left;
   }
   .navbar-nav > li > a {
-    padding-top: 5px;
-    padding-bottom: 5px;
+    padding-top: 15px;
+    padding-bottom: 15px;
   }
   .navbar-nav.navbar-right:last-child {
     margin-right: -15px;
@@ -3844,8 +3834,8 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   border-bottom: 1px solid transparent;
   -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
   box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
-  margin-top: 2px;
-  margin-bottom: 2px;
+  margin-top: 8px;
+  margin-bottom: 8px;
 }
 @media (min-width: 768px) {
   .navbar-form .form-group {
@@ -3912,20 +3902,20 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   border-bottom-left-radius: 0;
 }
 .navbar-btn {
-  margin-top: 2px;
-  margin-bottom: 2px;
+  margin-top: 8px;
+  margin-bottom: 8px;
 }
 .navbar-btn.btn-sm {
-  margin-top: 4px;
-  margin-bottom: 4px;
+  margin-top: 10px;
+  margin-bottom: 10px;
 }
 .navbar-btn.btn-xs {
-  margin-top: 4px;
-  margin-bottom: 4px;
+  margin-top: 14px;
+  margin-bottom: 14px;
 }
 .navbar-text {
-  margin-top: 5px;
-  margin-bottom: 5px;
+  margin-top: 15px;
+  margin-bottom: 15px;
 }
 @media (min-width: 768px) {
   .navbar-text {
@@ -3938,33 +3928,33 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   }
 }
 .navbar-default {
-  background-color: #f1f1f1;
-  border-color: #e0e0e0;
+  background-color: #0d8921;
+  border-color: none;
 }
 .navbar-default .navbar-brand {
-  color: #333333;
+  color: #ffffff;
 }
 .navbar-default .navbar-brand:hover,
 .navbar-default .navbar-brand:focus {
-  color: #1a1a1a;
+  color: #e6e6e6;
   background-color: transparent;
 }
 .navbar-default .navbar-text {
-  color: #333333;
+  color: #ffffff;
 }
 .navbar-default .navbar-nav > li > a {
-  color: #333333;
+  color: #ffffff;
 }
 .navbar-default .navbar-nav > li > a:hover,
 .navbar-default .navbar-nav > li > a:focus {
-  color: #0d8921;
+  color: #dddddd;
   background-color: transparent;
 }
 .navbar-default .navbar-nav > .active > a,
 .navbar-default .navbar-nav > .active > a:hover,
 .navbar-default .navbar-nav > .active > a:focus {
   color: #ffffff;
-  background-color: #0d8921;
+  background-color: #0a6b1a;
 }
 .navbar-default .navbar-nav > .disabled > a,
 .navbar-default .navbar-nav > .disabled > a:hover,
@@ -3980,32 +3970,32 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   background-color: #dddddd;
 }
 .navbar-default .navbar-toggle .icon-bar {
-  background-color: #888888;
+  background-color: #ffffff;
 }
 .navbar-default .navbar-collapse,
 .navbar-default .navbar-form {
-  border-color: #e0e0e0;
+  border-color: none;
 }
 .navbar-default .navbar-nav > .open > a,
 .navbar-default .navbar-nav > .open > a:hover,
 .navbar-default .navbar-nav > .open > a:focus {
-  background-color: #0d8921;
+  background-color: #0a6b1a;
   color: #ffffff;
 }
 @media (max-width: 767px) {
   .navbar-default .navbar-nav .open .dropdown-menu > li > a {
-    color: #333333;
+    color: #ffffff;
   }
   .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
   .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
-    color: #0d8921;
+    color: #dddddd;
     background-color: transparent;
   }
   .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
   .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
   .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
     color: #ffffff;
-    background-color: #0d8921;
+    background-color: #0a6b1a;
   }
   .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
   .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
@@ -4015,10 +4005,10 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   }
 }
 .navbar-default .navbar-link {
-  color: #333333;
+  color: #ffffff;
 }
 .navbar-default .navbar-link:hover {
-  color: #0d8921;
+  color: #dddddd;
 }
 .navbar-inverse {
   background-color: #222222;
@@ -4114,13 +4104,13 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   margin-bottom: 20px;
   list-style: none;
   background-color: #f5f5f5;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .breadcrumb > li {
   display: inline-block;
 }
 .breadcrumb > li + li:before {
-  content: "/\00a0";
+  content: "\00a0";
   padding: 0 5px;
   color: #cccccc;
 }
@@ -4131,7 +4121,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   display: inline-block;
   padding-left: 0;
   margin: 20px 0;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .pagination > li {
   display: inline;
@@ -4140,10 +4130,10 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 .pagination > li > span {
   position: relative;
   float: left;
-  padding: 2px 5px;
+  padding: 6px 12px;
   line-height: 1.428571429;
   text-decoration: none;
-  color: #222222;
+  color: #0d8921;
   background-color: #ffffff;
   border: 1px solid #dddddd;
   margin-left: -1px;
@@ -4151,19 +4141,19 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 .pagination > li:first-child > a,
 .pagination > li:first-child > span {
   margin-left: 0;
-  border-bottom-left-radius: 3px;
-  border-top-left-radius: 3px;
+  border-bottom-left-radius: 0px;
+  border-top-left-radius: 0px;
 }
 .pagination > li:last-child > a,
 .pagination > li:last-child > span {
-  border-bottom-right-radius: 3px;
-  border-top-right-radius: 3px;
+  border-bottom-right-radius: 0px;
+  border-top-right-radius: 0px;
 }
 .pagination > li > a:hover,
 .pagination > li > span:hover,
 .pagination > li > a:focus,
 .pagination > li > span:focus {
-  color: #0d8921;
+  color: #064310;
   background-color: #eeeeee;
   border-color: #dddddd;
 }
@@ -4192,33 +4182,33 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
 }
 .pagination-lg > li > a,
 .pagination-lg > li > span {
-  padding: 5px 10px;
+  padding: 10px 16px;
   font-size: 18px;
 }
 .pagination-lg > li:first-child > a,
 .pagination-lg > li:first-child > span {
-  border-bottom-left-radius: 4px;
-  border-top-left-radius: 4px;
+  border-bottom-left-radius: 0px;
+  border-top-left-radius: 0px;
 }
 .pagination-lg > li:last-child > a,
 .pagination-lg > li:last-child > span {
-  border-bottom-right-radius: 4px;
-  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0px;
+  border-top-right-radius: 0px;
 }
 .pagination-sm > li > a,
 .pagination-sm > li > span {
-  padding: 1px 5px;
+  padding: 5px 10px;
   font-size: 12px;
 }
 .pagination-sm > li:first-child > a,
 .pagination-sm > li:first-child > span {
-  border-bottom-left-radius: 2px;
-  border-top-left-radius: 2px;
+  border-bottom-left-radius: 0px;
+  border-top-left-radius: 0px;
 }
 .pagination-sm > li:last-child > a,
 .pagination-sm > li:last-child > span {
-  border-bottom-right-radius: 2px;
-  border-top-right-radius: 2px;
+  border-bottom-right-radius: 0px;
+  border-top-right-radius: 0px;
 }
 .pager {
   padding-left: 0;
@@ -4305,11 +4295,11 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   background-color: #449d44;
 }
 .label-info {
-  background-color: #6c6c6c;
+  background-color: #5bc0de;
 }
 .label-info[href]:hover,
 .label-info[href]:focus {
-  background-color: #525252;
+  background-color: #31b0d5;
 }
 .label-warning {
   background-color: #f0ad4e;
@@ -4331,7 +4321,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn {
   padding: 3px 7px;
   font-size: 12px;
   font-weight: bold;
-  color: #ffffff;
+  color: : #fff;
   line-height: 1;
   vertical-align: baseline;
   white-space: nowrap;
@@ -4358,41 +4348,41 @@ a.badge:focus {
 }
 a.list-group-item.active > .badge,
 .nav-pills > .active > a > .badge {
-  color: #222222;
+  color: #0d8921;
   background-color: #ffffff;
 }
 .nav-pills > li > a > .badge {
   margin-left: 3px;
 }
 .jumbotron {
-  padding: 20px;
-  margin-bottom: 20px;
+  padding: 30px;
+  margin-bottom: 30px;
   color: inherit;
-  background-color: #eeeeee;
+  background-color: #ffffff;
 }
 .jumbotron h1,
 .jumbotron .h1 {
   color: inherit;
 }
 .jumbotron p {
-  margin-bottom: 10px;
-  font-size: 17px;
+  margin-bottom: 15px;
+  font-size: 21px;
   font-weight: 200;
 }
 .container .jumbotron {
-  border-radius: 4px;
+  border-radius: 0px;
 }
 .jumbotron .container {
   max-width: 100%;
 }
 @media screen and (min-width: 768px) {
   .jumbotron {
-    padding-top: 32px;
-    padding-bottom: 32px;
+    padding-top: 48px;
+    padding-bottom: 48px;
   }
   .container .jumbotron {
-    padding-left: 40px;
-    padding-right: 40px;
+    padding-left: 60px;
+    padding-right: 60px;
   }
   .jumbotron h1,
   .jumbotron .h1 {
@@ -4404,9 +4394,9 @@ a.list-group-item.active > .badge,
   padding: 4px;
   margin-bottom: 20px;
   line-height: 1.428571429;
-  background-color: #ffffff;
+  background-color: #f2f2f2;
   border: 1px solid #dddddd;
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-transition: all 0.2s ease-in-out;
   transition: all 0.2s ease-in-out;
 }
@@ -4418,7 +4408,7 @@ a.list-group-item.active > .badge,
 a.thumbnail:hover,
 a.thumbnail:focus,
 a.thumbnail.active {
-  border-color: #222222;
+  border-color: #0d8921;
 }
 .thumbnail .caption {
   padding: 9px;
@@ -4428,7 +4418,7 @@ a.thumbnail.active {
   padding: 15px;
   margin-bottom: 20px;
   border: 1px solid transparent;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .alert h4 {
   margin-top: 0;
@@ -4454,45 +4444,45 @@ a.thumbnail.active {
   color: inherit;
 }
 .alert-success {
-  background-color: #eaf6ea;
-  border-color: #bcdfb5;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
   color: #5cb85c;
 }
 .alert-success hr {
-  border-top-color: #acd7a3;
+  border-top-color: #c9e2b3;
 }
 .alert-success .alert-link {
   color: #449d44;
 }
 .alert-info {
-  background-color: #ececec;
-  border-color: #d2d2d2;
-  color: #6c6c6c;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+  color: #5bc0de;
 }
 .alert-info hr {
-  border-top-color: #c5c5c5;
+  border-top-color: #a6e1ec;
 }
 .alert-info .alert-link {
-  color: #525252;
+  color: #31b0d5;
 }
 .alert-warning {
-  background-color: #fef9f3;
-  border-color: #fadac4;
+  background-color: #fcf8e3;
+  border-color: #fbeed5;
   color: #f0ad4e;
 }
 .alert-warning hr {
-  border-top-color: #f8ccac;
+  border-top-color: #f8e5be;
 }
 .alert-warning .alert-link {
   color: #ec971f;
 }
 .alert-danger {
-  background-color: #f9e2e2;
-  border-color: #f0b8c0;
+  background-color: #f2dede;
+  border-color: #eed3d7;
   color: #d9534f;
 }
 .alert-danger hr {
-  border-top-color: #eba3ad;
+  border-top-color: #e6c1c7;
 }
 .alert-danger .alert-link {
   color: #c9302c;
@@ -4518,7 +4508,7 @@ a.thumbnail.active {
   height: 20px;
   margin-bottom: 20px;
   background-color: #f5f5f5;
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
   box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
 }
@@ -4553,7 +4543,7 @@ a.thumbnail.active {
   background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
 }
 .progress-bar-info {
-  background-color: #6c6c6c;
+  background-color: #5bc0de;
 }
 .progress-striped .progress-bar-info {
   background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
@@ -4614,13 +4604,13 @@ a.thumbnail.active {
   border: 1px solid #dddddd;
 }
 .list-group-item:first-child {
-  border-top-right-radius: 3px;
-  border-top-left-radius: 3px;
+  border-top-right-radius: 0px;
+  border-top-left-radius: 0px;
 }
 .list-group-item:last-child {
   margin-bottom: 0;
-  border-bottom-right-radius: 3px;
-  border-bottom-left-radius: 3px;
+  border-bottom-right-radius: 0px;
+  border-bottom-left-radius: 0px;
 }
 .list-group-item > .badge {
   float: right;
@@ -4655,11 +4645,11 @@ a.list-group-item.active:focus .list-group-item-heading {
 a.list-group-item.active .list-group-item-text,
 a.list-group-item.active:hover .list-group-item-text,
 a.list-group-item.active:focus .list-group-item-text {
-  color: #71f185;
+  color: #cccccc;
 }
 .list-group-item-success {
   color: #5cb85c;
-  background-color: #eaf6ea;
+  background-color: #dff0d8;
 }
 a.list-group-item-success {
   color: #5cb85c;
@@ -4670,7 +4660,7 @@ a.list-group-item-success .list-group-item-heading {
 a.list-group-item-success:hover,
 a.list-group-item-success:focus {
   color: #5cb85c;
-  background-color: #d8eed8;
+  background-color: #d0e9c6;
 }
 a.list-group-item-success.active,
 a.list-group-item-success.active:hover,
@@ -4680,30 +4670,30 @@ a.list-group-item-success.active:focus {
   border-color: #5cb85c;
 }
 .list-group-item-info {
-  color: #6c6c6c;
-  background-color: #ececec;
+  color: #5bc0de;
+  background-color: #d9edf7;
 }
 a.list-group-item-info {
-  color: #6c6c6c;
+  color: #5bc0de;
 }
 a.list-group-item-info .list-group-item-heading {
   color: inherit;
 }
 a.list-group-item-info:hover,
 a.list-group-item-info:focus {
-  color: #6c6c6c;
-  background-color: #dfdfdf;
+  color: #5bc0de;
+  background-color: #c4e3f3;
 }
 a.list-group-item-info.active,
 a.list-group-item-info.active:hover,
 a.list-group-item-info.active:focus {
   color: #fff;
-  background-color: #6c6c6c;
-  border-color: #6c6c6c;
+  background-color: #5bc0de;
+  border-color: #5bc0de;
 }
 .list-group-item-warning {
   color: #f0ad4e;
-  background-color: #fef9f3;
+  background-color: #fcf8e3;
 }
 a.list-group-item-warning {
   color: #f0ad4e;
@@ -4714,7 +4704,7 @@ a.list-group-item-warning .list-group-item-heading {
 a.list-group-item-warning:hover,
 a.list-group-item-warning:focus {
   color: #f0ad4e;
-  background-color: #fceedb;
+  background-color: #faf2cc;
 }
 a.list-group-item-warning.active,
 a.list-group-item-warning.active:hover,
@@ -4725,7 +4715,7 @@ a.list-group-item-warning.active:focus {
 }
 .list-group-item-danger {
   color: #d9534f;
-  background-color: #f9e2e2;
+  background-color: #f2dede;
 }
 a.list-group-item-danger {
   color: #d9534f;
@@ -4736,7 +4726,7 @@ a.list-group-item-danger .list-group-item-heading {
 a.list-group-item-danger:hover,
 a.list-group-item-danger:focus {
   color: #d9534f;
-  background-color: #f4cecd;
+  background-color: #ebcccc;
 }
 a.list-group-item-danger.active,
 a.list-group-item-danger.active:hover,
@@ -4757,7 +4747,7 @@ a.list-group-item-danger.active:focus {
   margin-bottom: 20px;
   background-color: #ffffff;
   border: 1px solid transparent;
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
   box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
 }
@@ -4767,8 +4757,8 @@ a.list-group-item-danger.active:focus {
 .panel-heading {
   padding: 10px 15px;
   border-bottom: 1px solid transparent;
-  border-top-right-radius: 2px;
-  border-top-left-radius: 2px;
+  border-top-right-radius: -1px;
+  border-top-left-radius: -1px;
 }
 .panel-heading > .dropdown .dropdown-toggle {
   color: inherit;
@@ -4786,8 +4776,8 @@ a.list-group-item-danger.active:focus {
   padding: 10px 15px;
   background-color: #f5f5f5;
   border-top: 1px solid #dddddd;
-  border-bottom-right-radius: 2px;
-  border-bottom-left-radius: 2px;
+  border-bottom-right-radius: -1px;
+  border-bottom-left-radius: -1px;
 }
 .panel > .list-group {
   margin-bottom: 0;
@@ -4796,15 +4786,19 @@ a.list-group-item-danger.active:focus {
   border-width: 1px 0;
   border-radius: 0;
 }
-.panel > .list-group:first-child .list-group-item:first-child {
+.panel > .list-group .list-group-item:first-child {
   border-top: 0;
-  border-top-right-radius: 2px;
-  border-top-left-radius: 2px;
 }
-.panel > .list-group:last-child .list-group-item:last-child {
+.panel > .list-group .list-group-item:last-child {
   border-bottom: 0;
-  border-bottom-right-radius: 2px;
-  border-bottom-left-radius: 2px;
+}
+.panel > .list-group:first-child .list-group-item:first-child {
+  border-top-right-radius: -1px;
+  border-top-left-radius: -1px;
+}
+.panel > .list-group:last-child .list-group-item:last-child {
+  border-bottom-right-radius: -1px;
+  border-bottom-left-radius: -1px;
 }
 .panel-heading + .list-group .list-group-item:first-child {
   border-top-width: 0;
@@ -4813,11 +4807,6 @@ a.list-group-item-danger.active:focus {
 .panel > .table-responsive > .table {
   margin-bottom: 0;
 }
-.panel > .table:first-child,
-.panel > .table-responsive:first-child > .table:first-child {
-  border-top-right-radius: 2px;
-  border-top-left-radius: 2px;
-}
 .panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
 .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
 .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
@@ -4826,7 +4815,7 @@ a.list-group-item-danger.active:focus {
 .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
 .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
 .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
-  border-top-left-radius: 2px;
+  border-top-left-radius: -1px;
 }
 .panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
 .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
@@ -4836,12 +4825,7 @@ a.list-group-item-danger.active:focus {
 .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
 .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
 .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
-  border-top-right-radius: 2px;
-}
-.panel > .table:last-child,
-.panel > .table-responsive:last-child > .table:last-child {
-  border-bottom-right-radius: 2px;
-  border-bottom-left-radius: 2px;
+  border-top-right-radius: -1px;
 }
 .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
 .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
@@ -4851,7 +4835,7 @@ a.list-group-item-danger.active:focus {
 .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
 .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
 .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
-  border-bottom-left-radius: 2px;
+  border-bottom-left-radius: -1px;
 }
 .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
 .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
@@ -4861,7 +4845,7 @@ a.list-group-item-danger.active:focus {
 .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
 .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
 .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
-  border-bottom-right-radius: 2px;
+  border-bottom-right-radius: -1px;
 }
 .panel > .panel-body + .table,
 .panel > .panel-body + .table-responsive {
@@ -4932,7 +4916,7 @@ a.list-group-item-danger.active:focus {
 }
 .panel-group .panel {
   margin-bottom: 0;
-  border-radius: 3px;
+  border-radius: 0px;
   overflow: hidden;
 }
 .panel-group .panel + .panel {
@@ -4979,60 +4963,60 @@ a.list-group-item-danger.active:focus {
   border-bottom-color: #0d8921;
 }
 .panel-success {
-  border-color: #bcdfb5;
+  border-color: #d6e9c6;
 }
 .panel-success > .panel-heading {
   color: #5cb85c;
-  background-color: #eaf6ea;
-  border-color: #bcdfb5;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
 }
 .panel-success > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #bcdfb5;
+  border-top-color: #d6e9c6;
 }
 .panel-success > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #bcdfb5;
+  border-bottom-color: #d6e9c6;
 }
 .panel-info {
-  border-color: #d2d2d2;
+  border-color: #bce8f1;
 }
 .panel-info > .panel-heading {
-  color: #6c6c6c;
-  background-color: #ececec;
-  border-color: #d2d2d2;
+  color: #5bc0de;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
 }
 .panel-info > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #d2d2d2;
+  border-top-color: #bce8f1;
 }
 .panel-info > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #d2d2d2;
+  border-bottom-color: #bce8f1;
 }
 .panel-warning {
-  border-color: #fadac4;
+  border-color: #fbeed5;
 }
 .panel-warning > .panel-heading {
   color: #f0ad4e;
-  background-color: #fef9f3;
-  border-color: #fadac4;
+  background-color: #fcf8e3;
+  border-color: #fbeed5;
 }
 .panel-warning > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #fadac4;
+  border-top-color: #fbeed5;
 }
 .panel-warning > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #fadac4;
+  border-bottom-color: #fbeed5;
 }
 .panel-danger {
-  border-color: #f0b8c0;
+  border-color: #eed3d7;
 }
 .panel-danger > .panel-heading {
   color: #d9534f;
-  background-color: #f9e2e2;
-  border-color: #f0b8c0;
+  background-color: #f2dede;
+  border-color: #eed3d7;
 }
 .panel-danger > .panel-heading + .panel-collapse .panel-body {
-  border-top-color: #f0b8c0;
+  border-top-color: #eed3d7;
 }
 .panel-danger > .panel-footer + .panel-collapse .panel-body {
-  border-bottom-color: #f0b8c0;
+  border-bottom-color: #eed3d7;
 }
 .well {
   min-height: 20px;
@@ -5040,7 +5024,7 @@ a.list-group-item-danger.active:focus {
   margin-bottom: 20px;
   background-color: #f5f5f5;
   border: 1px solid #e3e3e3;
-  border-radius: 3px;
+  border-radius: 0px;
   -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
   box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
 }
@@ -5050,11 +5034,11 @@ a.list-group-item-danger.active:focus {
 }
 .well-lg {
   padding: 24px;
-  border-radius: 4px;
+  border-radius: 0px;
 }
 .well-sm {
   padding: 9px;
-  border-radius: 2px;
+  border-radius: 0px;
 }
 .close {
   float: right;
@@ -5121,7 +5105,7 @@ button.close {
   background-color: #ffffff;
   border: 1px solid #999999;
   border: 1px solid rgba(0, 0, 0, 0.2);
-  border-radius: 4px;
+  border-radius: 0px;
   -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
   box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
   background-clip: padding-box;
@@ -5231,7 +5215,7 @@ button.close {
   text-align: center;
   text-decoration: none;
   background-color: #000000;
-  border-radius: 3px;
+  border-radius: 0px;
 }
 .tooltip-arrow {
   position: absolute;
@@ -5305,7 +5289,7 @@ button.close {
   background-clip: padding-box;
   border: 1px solid #cccccc;
   border: 1px solid rgba(0, 0, 0, 0.2);
-  border-radius: 4px;
+  border-radius: 0px;
   -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
   box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
   white-space: normal;
@@ -5570,8 +5554,8 @@ button.close {
   text-shadow: none;
 }
 @media screen and (min-width: 768px) {
-  .carousel-control .glyphicon-chevron-left,
-  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .glyphicons-chevron-left,
+  .carousel-control .glyphicons-chevron-right,
   .carousel-control .icon-prev,
   .carousel-control .icon-next {
     width: 30px;
diff --git a/share/nitdoc/css/nitdoc.cards.css b/share/nitdoc/css/nitdoc.cards.css
new file mode 100644 (file)
index 0000000..fc3e5ef
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* cards */
+
+.card.active {
+       border: 1px solid #1E9431;
+}
+
+.card-heading {
+    margin-top: 0;
+    margin-bottom: 5px;
+}
+
+.card {
+       display: table;
+       width: 100%;
+       background: #fff;
+       border: 1px solid #eee;
+       margin-top: 10px;
+       box-shadow: -1px -1px 3px rgba(0,0,0,.06), 1px 1px 3px rgba(0,0,0,.12);
+}
+
+.card-body, .card-left, .card-right {
+       display: table-cell;
+       padding: 15px;
+}
+
+.card-body {
+       padding: 15px 0;
+       width: 100%
+}
+
+.card-body:first-child {
+       padding-left: 15px;
+}
+
+.card-body:last-child {
+       padding-right: 15px;
+}
+
+.card-list {
+       margin-top: 10px;
+}
+
+.card-list > .card:first-child {
+       border-top: 1px solid #ddd;
+}
+
+.card-list > .card {
+       margin-top: 0;
+       border-top: none;
+}
+
+.card-title {
+    margin-top: 0;
+}
diff --git a/share/nitdoc/css/nitdoc.code.css b/share/nitdoc/css/nitdoc.code.css
new file mode 100644 (file)
index 0000000..2a944aa
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Code Highlighting */
+
+.nitcode a { color: inherit; text-decoration: inherit; } /* hide links */
+.nitcode a:hover { text-decoration: underline; } /* underline links */
+
+/* lexical raw tokens. independent of usage or semantic: */
+.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
+.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
+.nitcode .nc_k { font-weight: bold; } /* keyword */
+.nitcode .nc_o {} /* operator */
+.nitcode .nc_i {} /* standard identifier */
+.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
+.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
+.nitcode .nc_l { color: #009999; } /* char and number literal */
+.nitcode .nc_s { color: #8F1546; } /* string literal */
+
+/* syntactic token usage. added because of their position in the AST */
+.nitcode .nc_ast { color: blue; } /* assert label */
+.nitcode .nc_la { color: blue; } /* break/continue label */
+.nitcode .nc_m { color: #445588; } /* module name */
+
+/* syntactic groups */
+.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
+.nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
+.nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
+.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
+.nitcode .nc_cdef {} /* A whole class definition */
+.nitcode .nc_pdef {} /* A whole property definition */
+
+/* semantic token usage */
+.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
+.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
+.nitcode .nc_error { border: 1px red solid;} /* not used */
index 01da471..81153c7 100644 (file)
 /*
- * Global
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
-body {
-       text-align: justify;
-}
-
-a:hover {
-       text-decoration: none;
-}
-
-ul li .label {
-       padding: 1px 4px;
-       font-size: 70%;
-       vertical-align: middle;
-       border-radius: .25em;
-       margin: 3px;
-       font-family: monospace;
-}
-
-code {
-       color: #333;
-       border: 1px solid #ddd;
-}
+/* Top menu */
 
-pre code {
-       border: none;
+.navbar-fixed-top {
+       background-color: #1E9431;
+       box-shadow: 0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28);
 }
 
-.navbar-default .navbar-toggle {
-       margin-top: 2px;
-       padding: 5px 10px;
+.navbar-brand > a {
+       color: #fff;
 }
 
-h3 {
-       margin: 10px 0;
+.container > .navbar-header, .container-fluid > .navbar-header, .container > .navbar-collapse, .container-fluid > .navbar-collapse {
+    margin-right: auto;
+    margin-left: auto;
 }
 
-article {
-       padding: 10px 0px;
+.navbar-default .navbar-collapse, .navbar-default .navbar-form {
+       border-color: transparent;
 }
 
-article.nospace {
-       padding: 0;
-       margin: 0;
+.navbar-toggle {
+       float: left;
 }
 
-/*
- * Sidebar
- */
+/* Body */
 
-#sidebar .panel {
-       margin-top: 15px;
-       box-shadow: none;
-}
-
-#sidebar .panel-heading {
-       padding: 3px 0 0 0;
-       font-size: 16px;
-}
-
-#sidebar .panel-body {
-       padding: 0;
-}
-
-#sidebar .panel-body ul>li>a {
-       padding: 0;
-}
-
-#sidebar .panel-body ul>li {
-       padding: 0 0 0 15px;
-       font-size: 15px;
-       color: #333;
+body {
+       background: #f2f2f2;
+       margin-top: 70px;
+       margin-bottom: 70px;
 }
 
-#sidebar .panel-body ul ul>li,
-#sidebar .panel-body ul ul>li a {
-       padding: 0 0 0 0;
-       font-size: 14px;
+h1, h2, h3, h4, h5, h6 {
        color: #666;
 }
 
-#sidebar .panel-body ul ul ul>li {
-       font-size: 13px;
-       color: #999;
+.page-header {
+    margin-top: 0;
+    border: none;
 }
 
-#sidebar .panel-heading a:hover, #sidebar .panel ul a:hover {
-       color: #0d8921;
-       background-color: transparent;
-}
-
-#sidebar .summary .nav>li>a {
-       padding: 3px 0 0 10px;
-       font-size: 15px;
-       border-left: 2px solid transparent;
-       color: #333;
-}
+#sidebar { margin-top: 15px; }
 
-#sidebar .summary .nav .nav>li>a {
-       padding-top: 2px;
-       padding-left: 15px;
-       font-size: 14px;
-       color: #666;
+pre {
+       white-space: pre-wrap;
 }
 
-#sidebar .summary .nav .nav .nav>li>a {
-       padding-left: 20px;
-       font-size: 13px;
+.footer {
        color: #999;
+       text-align: center;
+       padding: 10px;
+       margin: 20px 0;
 }
 
-#sidebar .summary .nav .nav .nav .nav>li>a {
-       font-size: 12px;
-       color: #CCC;
-}
-
-#sidebar .summary .nav>.active>a,
-#sidebar .summary .nav>.active>a:hover,
-#sidebar .summary .nav>li>a:hover {
-       color: #0d8921;
-       background-color: transparent;
-}
-
-#sidebar .summary .nav>.active>a,
-#sidebar .summary .nav>.active>a:hover,
-#sidebar .summary .nav .nav>.active>a,
-#sidebar .summary .nav .nav>.active>a:hover,
-#sidebar .summary .nav .nav .nav>.active>a,
-#sidebar .summary .nav .nav .nav>.active>a:hover {
-       color: #0d8921;
-       border-left: 2px solid #0d8921;
-       margin-left: 0px;
-}
-
-#sidebar .summary .nav>li>a:hover,
-#sidebar .summary .nav .nav>li>a:hover,
-#sidebar .summary .nav .nav .nav>li>a:hover {
-       color: #0d8921;
-       border-left: 1px solid #0d8921;
-       margin-left: 1px;
-       background-color: transparent;
-}
-
-/*
- * Content
- */
-
-#content {
-       position: fixed;
-       top: 30px;
-       bottom: 0;
-       left: 10px;
-       right: 15px;
-}
-
-#content>.col {
-       height: 100%;
-       overflow-y: scroll;
-}
-
-#content>.col::-webkit-scrollbar-thumb {
-       background: transparent;
-}
+/* ui */
 
-#content>.col:hover::-webkit-scrollbar-thumb {
-       background: #CCC;
-       -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.10),inset 0 -1px 0 rgba(0,0,0,0.07);
-}
+.btn-bar { margin-top: -5px; float: right }
+.btn-bar .btn { padding: 5px 10px; }
 
-#content>.col::-webkit-scrollbar {
-    width: 7px;
-       height: 7px;
-}
+/* Doc */
 
-#content>.col::-webkit-scrollbar-thumb:hover {
-       background: #999;
+.nitdoc > *:first-child {
+       margin-top: 0;
 }
 
-#content>.col::-webkit-scrollbar-corner {
-       background: transparent;
+.signature {
+       color: #777;
+       font-family: monospace;
 }
 
-#content>.col::-webkit-scrollbar-button {
-       width: 0;
-       height: 0;
-       display: none;
+.signature .name {
+       font-weight: bold;
 }
 
-#content article:target {
-       padding-left: 10px;
-       margin-left: -10px;
-       border-left: 2px solid #0d8921;
+.page-header .signature .name, .signature .signature .name {
+       font-weight: normal;
 }
 
+/* Summary */
 
-.pull-right .dropdown-toggle {
-       padding: 0 5px;
-}
-
-/* Hide the "..." link */
+.summary h1 { font-size: 14px; margin: 10px 0 5px 0;   font-weight: bold; }
+.summary h2 { font-size: 13px; margin:  9px 0 5px 5px; font-weight: bold; }
+.summary h3 { font-size: 12px; margin:  8px 0 5px 10px; }
+.summary h4 { font-size: 11px; margin:  7px 0 5px 15px; }
+.summary h5 { font-size: 10px; margin:  6px 0 5px 20px; }
+.summary h6 { font-size:  9px; margin:  5px 0 5px 25px; }
 
-article .dropdown, article .dropdown {
-       visibility: hidden;
-}
-article:hover .dropdown, article:target .dropdown {
-       visibility: visible;
-}
+.summary a, .summary a:hover { color: #666; }
 
 /*
- * Page parts
+ * Nit
  */
 
-.footer {
-       padding: 10px;
-       margin: 20px 0;
-}
-
-.subtitle {
-       margin-bottom: 10px;
-}
-
-.label:empty {
-       display:inline;
-}
-
-.label.intro:before {
-       content: "I";
-}
-.label.redef:before {
-       content: "R";
-}
-.label.inherit:before {
-       content: "H";
-}
-
-.signature span.glyphicon {
-       margin: 0 10px 5px 0;
-       font-size: 55%;
-       vertical-align: middle;
-}
-
-.signature a, .list-definition a, .info.signature a {
-       color: #0d8921;
-}
-
-.info {
-       color: #888;
-}
-
-.info a {
-       color: #666;
-}
-
-.info a:hover {
+.nitdoc h1, .nitdoc h2, .nitdoc h3, .nitdoc h4, .nitdoc h5, .nitdoc h6 {
        color: #333;
 }
 
-.graph {
-       text-align: center;
-}
-
 .nitdoc .synopsys {
-       margin: 5px 0;
-       font-size: 16px;
-       font-weight: bold;
-       line-height: 1.4;
+       margin-top: 0;
 }
 
 .public {
@@ -279,41 +124,3 @@ article:hover .dropdown, article:target .dropdown {
 .private {
        color: #a94442;
 }
-
-.list-definition .list-definition {
-       margin-left: 30px;
-}
-
-/*
- * Code Highlighting
- */
-
-.nitcode a { color: inherit; text-decoration: inherit; } /* hide links */
-.nitcode a:hover { text-decoration: underline; } /* underline links */
-.nitcode span[title]:hover { text-decoration: underline; } /* underline titles */
-/* lexical raw tokens. independent of usage or semantic: */
-.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
-.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
-.nitcode .nc_k { font-weight: bold; } /* keyword */
-.nitcode .nc_o {} /* operator */
-.nitcode .nc_i {} /* standard identifier */
-.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
-.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
-.nitcode .nc_l { color: #009999; } /* char and number literal */
-.nitcode .nc_s { color: #8F1546; } /* string literal */
-/* syntactic token usage. added because of their position in the AST */
-.nitcode .nc_ast { color: blue; } /* assert label */
-.nitcode .nc_la { color: blue; } /* break/continue label */
-.nitcode .nc_m { color: #445588; } /* module name */
-/* syntactic groups */
-.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
-.nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
-.nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
-.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
-.nitcode .nc_cdef {} /* A whole class definition */
-.nitcode .nc_pdef {} /* A whole property definition */
-/* semantic token usage */
-.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
-.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
-.nitcode .nc_error { border: 1px red solid;} /* not used */
-
diff --git a/share/nitdoc/css/nitdoc.quicksearch.css b/share/nitdoc/css/nitdoc.quicksearch.css
new file mode 100644 (file)
index 0000000..3e306c3
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Nitdoc Quick Search JS module */
+
+.has-icon {
+    position: relative;
+}
+
+.has-icon .form-control {
+       padding-left: 35px;
+}
+
+.form-control-icon {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 2;
+    display: block;
+    width: 34px;
+    height: 34px;
+    line-height: 34px;
+    text-align: center;
+    pointer-events: none;
+}
+
+.navbar-fixed-top .form-control:hover, .navbar-fixed-top .form-control:focus {
+       background: rgba(255, 255, 255, 0.2);
+}
+
+.navbar-fixed-top .form-control {
+       background: rgba(255, 255, 255, 0.1);
+    border: none;
+    color: #fff;
+    box-shadow: none;
+}
+
+.navbar-fixed-top .form-control-icon {
+       color: #fff;
+}
+
+.navbar-fixed-top .form-group {
+       margin-top: 8px;
+       margin-bottom: 0px;
+}
+
+.navbar-fixed-top *::-webkit-input-placeholder { color: #fff; }
+.navbar-fixed-top *:-moz-placeholder { color: #fff; }
+.navbar-fixed-top *::-moz-placeholder { color: #fff; }
+.navbar-fixed-top *:-ms-input-placeholder { color: #fff; }
+
+.search-input {
+       width: 100%;
+}
+
+#nitdoc-qs-popup {
+       background-color: #FFFFFF;
+       border: 1px solid #E0E0E0;
+       z-index: 1000;
+       -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
+       -moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
+       box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
+}
+
+.qs-card {
+       cursor: pointer;
+       padding: 5px;
+       border-bottom: 1px solid #F0F0F0;
+       overflow: hidden;
+}
+
+.qs-card h1 {
+       color: #0D8921;
+       font-size: 1.2em;
+       margin-top: 5px;
+       margin-bottom: 0;
+}
+
+.qs-info {
+       color: #6C6C6C;
+       font-size: smaller;
+}
+
+.qs-noresult {
+       color: #6C6C6C;
+       font-size: small;
+}
+
+.qs-overflow {
+       text-align: center;
+       font-size:      x-small;
+       color: #6C6C6C;
+       -webkit-touch-callout: none;
+       -webkit-user-select: none;
+       -khtml-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+}
+
+.qs-overflow-active {
+       color: #0D8921;
+       cursor: pointer;
+}
+
+.qs-overflow-active:hover {
+       background-color: #E0E0E0;
+}
+
+.qs-active {
+       background: #EEE;
+}
diff --git a/share/nitdoc/js/nitdoc.quicksearch.js b/share/nitdoc/js/nitdoc.quicksearch.js
new file mode 100644 (file)
index 0000000..746d2e6
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Nitdoc QuickSearch widget */
+
+$.widget("nitdoc.quicksearch", {
+
+       options: {
+               list: {}, // List of raw results generated by nitdoc tool
+               fieldAttrs: {
+                       autocomplete: "off",
+               },
+               maxSize: 10
+       },
+
+       _create: function() {
+               // set widget options
+               this.element.attr(this.options.fieldAttrs);
+               // event dispatch
+               this._on(this.element, {
+                       "keydown": this._doKeyDown,
+                       "keyup": this._doKeyUp,
+                       "input": this._doInput
+               });
+               // add result table element once
+               this._popup = $("<div/>")
+                       .attr("id", "nitdoc-qs-popup")
+                       .css("position", "absolute")
+                       .css("z-index", 10000)
+                       .hide();
+               $("body").append(this._popup);
+               // make table disappear when a click occurs outside
+               $(document).click($.proxy(this.close, this));
+               this._autosizeTable();
+       },
+
+       /* events */
+
+       _doKeyDown: function(event) {
+               switch(event.keyCode) {
+                       case 38: // Up
+                               this._selectPrev();
+                               return false;
+                       case 40: // Down
+                               this._selectNext();
+                               return false;
+                       default:
+                               return true;
+                }
+       },
+
+       _doKeyUp: function(event) {
+               switch(event.keyCode) {
+                       case 38: // Up
+                       case 40: // Down
+                               break;
+                       case 13: // Enter
+                               this._loadResult();
+                               return false;
+                       case 27: // Escape
+                               this.element.blur();
+                               this.close();
+                               return true;
+                       default: // Other keys
+                               return true;
+               }
+       },
+
+       _doInput: function(event) {
+               Utils.delayEvent($.proxy(this.search, this));
+       },
+
+       /* Result lookup */
+
+       _getResults: function(query) {
+               var results = [];
+
+               // Prefix matches
+               var prefix_matches = [];
+               for(var entry in this.options.list) {
+                       if(!entry.startsWith(query, true)) {
+                               continue;
+                       }
+                       var cat = {
+                               name: entry,
+                               entries: this.options.list[entry]
+                       };
+                       prefix_matches.push(cat);
+
+                       if(entry == query) {
+                               cat.rank = 10;
+                       } else if(entry.toUpperCase() == query.toUpperCase()) {
+                               cat.rank = 5;
+                       } else if(entry[0] == query[0]) {
+                               cat.rank = 1.1 + query.dice(entry);
+                       } else {
+                               cat.rank = 1 + query.dice(entry);
+                       }
+               }
+               if(prefix_matches.length > 0) {
+                       prefix_matches.sort(this._rankSorter);
+                       for(var i in prefix_matches) {
+                               var cat = prefix_matches[i];
+                               for(var j in cat.entries) {
+                                       var entry = cat.entries[j];
+                                       entry.name = cat.name;
+                                       results.push(entry);
+                               }
+                       }
+                       return results;
+               }
+
+               // Partial matches
+               var partial_matches = [];
+               for(var entry in this.options.list) {
+                       var cat = {
+                               name: entry,
+                               entries: this.options.list[entry]
+                       }
+                       cat.rank = query.dice(entry);
+                       if(cat.rank > 0) {
+                               partial_matches.push(cat);
+                       }
+               }
+               if(partial_matches.length > 0) {
+                       partial_matches.sort(this._rankSorter);
+                       for(var i in partial_matches) {
+                               var cat = partial_matches[i];
+                               for(var j in cat.entries) {
+                                       var entry = cat.entries[j];
+                                       entry.name = cat.name;
+                                       results.push(entry);
+                               }
+                       }
+               }
+
+               return results;
+       },
+
+       _rankSorter: function(a, b){
+               if(a.rank < b.rank) {
+                       return 1;
+               } else if(a.rank > b.rank) {
+                       return -1;
+               }
+               return 0;
+       },
+
+       /* Results table */
+
+       search: function() {
+               var query = this.element.val();
+               if(query) {
+                       var results = this._getResults(query);
+                       this.open(query, results);
+               }
+       },
+
+       open: function(query, results) {
+               this._popup.empty();
+               this._cards = [];
+               this._index = -1;
+
+               if(results.length == 0) {
+                       this.addNoResultCard();
+               }
+
+               if(results.length >= this.options.maxSize) {
+                       this.addOverflowUp(false);
+               }
+
+               for(var i in results) {
+                       var result = results[i];
+                       this.addCard(result.name, result.txt, result.url, this.options.rowCatClass)
+               }
+
+               if(results.length >= this.options.maxSize) {
+                       this.addOverflowDown(true);
+               }
+
+               if(results.length > 0) {
+                       this._setIndex(0);
+               }
+
+               this._popup.show();
+               this._autosizeTable();
+       },
+
+       close: function(target) {
+               if(target != this.element && target != this._popup) {
+                       this._popup.hide();
+               }
+       },
+
+       addCard: function(name, txt, url, cls) {
+               var card = $("<div/>")
+                       .addClass("qs-card")
+                       .addClass("qs-result")
+                       .data("searchDetails", {name: name, url: url})
+                       .data("index", this._cards.length)
+                       .append(
+                               $("<h1/>")
+                               .html(name)
+                               .addClass(cls)
+                       )
+                       .append(
+                               $("<span/>")
+                               .html(txt)
+                               .addClass("qs-info")
+                       )
+                       .mouseover($.proxy(this._mouseOverRow, this))
+                       .click($.proxy(this._clickRow, this))
+               this._cards.push(card);
+               if(this._cards.length >= this.options.maxSize) {
+                       card.hide();
+               }
+               this._popup.append(card);
+       },
+
+       addOverflowUp: function(active) {
+               this._popup.append(
+                       $("<div/>")
+                       .addClass("qs-overflow")
+                       .addClass("qs-overflow-up")
+                       .addClass(active ? "qs-overflow-active": "")
+                       .html("&#x25B2;")
+                       .click($.proxy(this._clickPrev, this))
+               );
+       },
+
+       addOverflowDown: function(active) {
+               this._popup.append(
+                       $("<div/>")
+                       .addClass("qs-overflow")
+                       .addClass("qs-overflow-down")
+                       .addClass(active ? "qs-overflow-active": "")
+                       .html("&#x25BC;")
+                       .click($.proxy(this._clickNext, this))
+               );
+       },
+
+       addNoResultCard: function() {
+               var card = $("<div/>")
+                       .addClass("qs-card qs-noresult")
+                       .html("Sorry, there is no match...");
+               this._popup.append(card);
+       },
+
+       _autosizeTable: function() {
+               this._popup.position({
+                       my: "left top",
+                       at: "left bottom",
+                       of: this.element
+               });
+               this._popup
+                       .css("min-width", this.element.outerWidth())
+                       .css("max-width", this.element.outerWidth());
+       },
+
+       _hasIndex: function(index) {
+               return index >= 0 && index < this._cards.length;
+       },
+
+       _hasPrev: function(index) {
+               return index - 1 >= 0;
+       },
+
+       _hasNext: function(index) {
+               return index + 1 < this._cards.length;
+       },
+
+       _setIndex: function(index) {
+               if(this._hasIndex(this._index)) {
+                       this._cards[this._index].removeClass("qs-active");
+               }
+               this._index = index;
+               if(this._hasIndex(this._index)) {
+                       this._cards[this._index].addClass("qs-active");
+               }
+       },
+
+       _selectPrev: function() {
+               if(this._hasPrev(this._index)) {
+                       this._setIndex(this._index - 1);
+                       if(!this._cards[this._index].is(":visible")) {
+                               this._popup.find(".qs-result:visible").last().hide();
+                               this._popup.find(".qs-overflow-down").addClass("qs-overflow-active");
+                               this._cards[this._index].show();
+                               if(!this._hasPrev(this._index)) {
+                                       this._popup.find(".qs-overflow-up").removeClass("qs-overflow-active");
+                               }
+                       }
+               } else {
+               }
+       },
+
+       _selectNext: function() {
+               if(this._hasNext(this._index)) {
+                       this._setIndex(this._index + 1);
+                       if(!this._cards[this._index].is(":visible")) {
+                               this._popup.find(".qs-result:visible").first().hide();
+                               this._popup.find(".qs-overflow-up").addClass("qs-overflow-active");
+                               this._cards[this._index].show();
+                               if(!this._hasNext(this._index)) {
+                                       this._popup.find(".qs-overflow-down").removeClass("qs-overflow-active");
+                               }
+                       }
+               }
+       },
+
+       // Load selected search result page
+       _loadResult: function() {
+               if(this._index > -1) {
+                       window.location = this._cards[this._index].data("searchDetails").url;
+                       return;
+               }
+               if(this.element.val().length == 0) { return; }
+
+               window.location = this.options.gotoPage + "#q=" + this.element.val();
+               if(window.location.href.indexOf(this.options.gotoPage) > -1) {
+                       location.reload();
+               }
+       },
+
+       /* table events */
+
+       _clickNext: function(event) {
+               event.stopPropagation();
+               this._selectNext();
+       },
+
+       _clickPrev: function(event) {
+               event.stopPropagation();
+               this._selectPrev();
+       },
+
+       _clickRow: function(event) {
+               window.location = $(event.currentTarget).data("searchDetails")["url"];
+       },
+
+       _mouseOverRow: function(event) {
+               this._setIndex($(event.currentTarget).data("index"));
+       }
+});
+
+var searchField = $("<input/>")
+.addClass("form-control search-input")
+.attr({
+       id: "nitdoc-qs-field",
+       type: "text",
+       placeholder: "Search..."
+})
+
+$("#search-placeholder").append(
+       $("<form>")
+       .addClass("navbar-form navbar-right")
+       .on("submit", function() { return false; })
+       .css("margin-bottom", 0)
+       .css("margin-top", 0)
+       .append(
+               $("<div>")
+               .addClass("form-group has-icon")
+               .append(searchField)
+               .append(
+                       $("<span>")
+                       .addClass("glyphicon glyphicon-search form-control-icon text-muted")
+               )
+       )
+);
+
+searchField.quicksearch({
+       list: this.nitdocQuickSearchRawList
+});
diff --git a/share/nitdoc/js/nitdoc.utils.js b/share/nitdoc/js/nitdoc.utils.js
new file mode 100644 (file)
index 0000000..ac19c29
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Utils module */
+
+String.prototype.startsWith = function(prefix, caseSensitive) {
+       if(caseSensitive) {
+               return this.toUpperCase().indexOf(prefix.toUpperCase()) === 0;
+       }
+       return this.indexOf(prefix) === 0;
+}
+
+// Compare two strings using Sorensen-Dice Coefficient
+// see: http://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient
+String.prototype.dice = function(other) {
+       var length1 = this.length - 1;
+       var length2 = other.length - 1;
+       if(length1 < 1 || length2 < 1) return 0;
+
+       var bigrams2 = [];
+       for(var i = 0; i < length2; i++) {
+               bigrams2.push(other.substr(i, 2));
+       }
+
+       var intersection = 0;
+       for(var i = 0; i < length1; i++) {
+               var bigram1 = this.substr(i, 2);
+               for(var j = 0; j < length2; j++) {
+                       if(bigram1 == bigrams2[j]) {
+                               intersection++;
+                               bigrams2[j] = null;
+                               break;
+                       }
+               }
+       }
+       return (2.0 * intersection) / (length1 + length2);
+}
+
+var Utils = {
+       delayEvent: function(handler, event) {
+               if(this.delayEvent.timeout) {
+                       clearTimeout(this.delayEvent.timeout);
+               }
+               this.delayEvent.timeout = setTimeout(function() {
+                   handler.call(event);
+               }, 100);
+       },
+
+       scrollTo: function(target) {
+               var element = $(target);
+               if(element[0]) {
+                       $("body, html").animate({
+                               scrollTop: element.offset().top - 60
+                       });
+               }
+       },
+
+       openTab: function(e) {
+               // Open tab
+               var url = document.location.toString();
+               if (url.match('#')) {
+                       var hash = url.split('#')[1];
+                       var element = $('.nav-tabs a[href="#' + hash + '"]');
+                       if(element[0]) {
+                               element.tab('show');
+                       } else {
+                               Utils.scrollTo('#' + hash);
+                       }
+               }
+
+               // Jump to id
+               var obj = new URL(url);
+               var arg = obj.searchParams.get("def");
+               if(arg) {
+                       var def = '#' + arg;
+                       $('.card.active').removeClass('active');
+                       $(def).addClass('active');
+                       $(def).find('.collapse').collapse();
+                       Utils.scrollTo(def);
+               }
+       }
+};
+
+Utils.openTab();
+
+window.addEventListener("hashchange", Utils.openTab, false);
+
+// Scroll on hash click
+$('.summary a[href*=#]').on('click', function(e) {
+       e.preventDefault();
+       Utils.scrollTo(e.currentTarget.hash);
+       history.pushState({}, '', e.currentTarget.hash);
+});
+
+// Change hash for page-reload
+$('.nav-tabs a[href]').on('shown.bs.tab', function (e) {
+       history.pushState({}, '', e.target.hash)
+});
diff --git a/src/doc/static/static.nit b/src/doc/static/static.nit
new file mode 100644 (file)
index 0000000..c1a51f5
--- /dev/null
@@ -0,0 +1,19 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Nitdoc generation framework
+module static
+
+import static::static_html
+import static::static_index
diff --git a/src/doc/static/static_base.nit b/src/doc/static/static_base.nit
new file mode 100644 (file)
index 0000000..a7ae6bb
--- /dev/null
@@ -0,0 +1,352 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Base entities shared by all the nitdoc code
+module static_base
+
+import static_cards
+import modelize
+
+intrude import markdown::wikilinks
+
+# The model of a Nitdoc documentation
+class DocModel
+
+       # Model used to select entities
+       var model: Model
+
+       # Mainmodule to resolve linearization
+       var mainmodule: MModule
+
+       # ModelBuilder used to retrieve AST nodes
+       var modelbuilder: ModelBuilder
+
+       # Catalog for building the homepage
+       var catalog: Catalog
+
+       # Model filters applied to the whole documentation
+       var filter: ModelFilter
+
+       # Specific Markdown processor to use within Nitdoc
+       var md_processor: MarkdownProcessor is lazy do
+               var parser = new CommandParser(model, mainmodule, modelbuilder, catalog)
+               var proc = new CmdMarkdownProcessor(parser)
+               proc.decorator = new CmdDecorator(model)
+               return proc
+       end
+
+       # Specific Markdown processor to use within Nitdoc
+       var inline_processor: MarkdownProcessor is lazy do
+               var parser = new CommandParser(model, mainmodule, modelbuilder, catalog)
+               var proc = new CmdMarkdownProcessor(parser)
+               proc.decorator = new CmdInlineDecorator(model)
+               return proc
+       end
+
+       # Do not generate dot graphs
+       var no_dot = false is writable
+
+       # Do not generate higlighted code
+       var no_code = false is writable
+
+       # Url to code when `no_code` is true
+       var code_url: nullable String = null is writable
+
+       # Url to assets
+       var share_url: nullable String = null is writable
+
+       # Custom menu brand
+       var custom_brand: nullable String = null is writable
+
+       # Custom homepage title
+       var custom_title: nullable String = null is writable
+
+       # Custom page footer
+       var custom_footer: nullable String = null is writable
+
+       # Custom homepage intro text
+       var custom_intro: nullable String = null is writable
+
+       # Optional tracker url
+       var tracker_url: nullable String = null is writable
+
+       # Optional tracker site id
+       var piwik_site_id: nullable String = null is writable
+
+       # Used to sort sidebar elements by name.
+       var name_sorter = new MEntityNameSorter
+end
+
+# Documentation pages
+
+# A documentation page abstraction
+class DocPage
+
+       # Title of this page
+       var title: String is writable
+
+       # Page tab panels
+       #
+       # Nitdoc pages are tabulated.
+       # If a page has only one tab, it is presented as a single page.
+       # With more than one tab, the HTML rendering process adds tab headers and
+       # links.
+       var tabs: Array[DocTab] = [main_tab] is lazy
+
+       # The page main tab
+       #
+       # For most pages this tab is suffisent.
+       # Subclasses can add more tabs.
+       var main_tab = new DocTab("main", "Main")
+
+       redef fun to_s do return title
+end
+
+# The Nitdoc overview page that displays the nit packages catalog
+class PageHome
+       super DocPage
+end
+
+# A DocPage documenting a MEntity
+abstract class PageMEntity
+       super DocPage
+       autoinit mentity
+
+       new(mentity: MEntity) do
+               if mentity isa MPackage then
+                       return new PageMPackage(mentity)
+               else if mentity isa MGroup then
+                       return new PageMGroup(mentity)
+               else if mentity isa MModule then
+                       return new PageMModule(mentity)
+               else if mentity isa MClass then
+                       return new PageMClass(mentity)
+               else if mentity isa MProperty then
+                       return new PageMProperty(mentity)
+               else
+                       print "Not yet implemented: Page for {mentity.full_name} ({mentity.class_name})"
+                       abort
+               end
+       end
+
+       # Type of MEntity documented by this page
+       type MENTITY: MEntity
+
+       # MEntity documented by this page
+       var mentity: MENTITY
+
+       # For mentities the main tab is the doc tab
+       redef var main_tab = new DocTab("doc", "Doc", true, "book")
+
+       # API tab
+       #
+       # Where the MEntity API (groups, modules, classes, props) is displayed
+       var api_tab = new DocTab("api", "API", false, "list")
+
+       # Dependencies tab
+       #
+       # Where the MEntity importation or inheritance is displayed
+       var dep_tab = new DocTab("inh", "Dependencies", false, "object-align-vertical")
+
+       # Code tab
+       #
+       # Since all mentities does not have code, this tab in not in the `tabs` list
+       # by default.
+       var code_tab = new DocTab("code", "Code", false, "console")
+
+       # Lienarization tab
+       #
+       # Since all mentities does not have a linearization, this tab in not in the
+       # `tabs` list by default.
+       var lin_tab = new DocTab("lin", "Linearization", false, "arrow-down")
+
+       redef var tabs = [main_tab, api_tab, dep_tab] is lazy
+       redef var title is lazy do return mentity.name
+end
+
+# A documentation page for a MPackage
+class PageMPackage
+       super PageMEntity
+
+       redef type MENTITY: MPackage
+       redef var api_tab = new DocTab("api", "Groups & Modules", false, "list")
+end
+
+# A documentation page about a MGroup
+class PageMGroup
+       super PageMEntity
+
+       redef type MENTITY: MGroup
+       redef var api_tab = new DocTab("api", "Subgroups & Modules", false, "list")
+end
+
+# A documentation page about a MModule
+class PageMModule
+       super PageMEntity
+
+       redef type MENTITY: MModule
+       redef var api_tab = new DocTab("api", "Classes", false, "list")
+       redef var dep_tab = new DocTab("inh", "Importation", false, "object-align-vertical")
+       redef var tabs = [main_tab, api_tab, dep_tab, code_tab] is lazy
+end
+
+# A documentation page about a MClass
+class PageMClass
+       super PageMEntity
+
+       redef type MENTITY: MClass
+       redef var api_tab = new DocTab("api", "All properties", false, "list")
+       redef var dep_tab = new DocTab("inh", "Inheritance", false, "object-align-vertical")
+       redef var tabs = [main_tab, api_tab, dep_tab, lin_tab] is lazy
+end
+
+# A documentation page about a MProperty
+class PageMProperty
+       super PageMEntity
+
+       redef type MENTITY: MProperty
+       redef var tabs = [main_tab, lin_tab] is lazy
+end
+
+# A page that lists the packages maintained and contributed by a person
+class PagePerson
+       super DocPage
+       autoinit person
+
+       # Person displayed in this page
+       var person: Person
+
+       redef var title is lazy do return person.name
+end
+
+# A page that lists the packages related to a tab
+class PageTag
+       super DocPage
+       autoinit tag
+
+       # Tag displayed in this page
+       var tag: String
+
+       redef var title is lazy do return tag
+end
+
+# Breadcrumbs
+
+redef class MEntity
+       # MEntities composing the breadcrumbs of a nitdoc page
+       fun nitdoc_breadcrumbs: Array[MEntity] is abstract
+end
+
+redef class MPackage
+       redef var nitdoc_breadcrumbs = [self: MEntity] is lazy
+end
+
+redef class MGroup
+       redef var nitdoc_breadcrumbs is lazy do
+               var parent = self.parent
+               if parent != null then
+                       return parent.nitdoc_breadcrumbs + [self]
+               end
+               return mpackage.nitdoc_breadcrumbs
+       end
+end
+
+redef class MModule
+       redef var nitdoc_breadcrumbs is lazy do
+               var mgroup = self.mgroup
+               if mgroup != null then
+                       return mgroup.nitdoc_breadcrumbs + [self]
+               end
+               return [self]
+       end
+end
+
+redef class MClass
+       redef var nitdoc_breadcrumbs is lazy do
+               return intro_mmodule.nitdoc_breadcrumbs + [self]
+       end
+end
+
+redef class MClassDef
+       redef var nitdoc_breadcrumbs is lazy do
+               var res = new Array[MEntity].from(mmodule.nitdoc_breadcrumbs)
+               res.add self
+               return res
+       end
+end
+
+redef class MProperty
+       redef var nitdoc_breadcrumbs is lazy do
+               var res = new Array[MEntity].from(intro_mclassdef.mclass.nitdoc_breadcrumbs)
+               res.add self
+               return res
+       end
+end
+
+redef class MPropDef
+       redef var nitdoc_breadcrumbs is lazy do
+               var res = new Array[MEntity].from(mclassdef.nitdoc_breadcrumbs)
+               res.add self
+               return res
+       end
+end
+
+# Documentation base elements
+
+# A documentation tabulated view
+class DocTab
+
+       # Tab uniq id in the page
+       var id: String is writable
+
+       # Table title
+       var title: String is writable
+
+       # Is this tab displayed by default?
+       var is_active = false is optional, writable
+
+       # Tab header icon
+       var icon: nullable String = null is optional, writable
+
+       # Tab content
+       var content = new Array[StaticCard]
+
+       # Tab sidebar
+       var sidebar = new DocSidebar
+
+       # Tab metadata sidebar
+       var metadata = new DocSidebar
+
+       # Is this tab empty?
+       fun is_empty: Bool do return content.is_empty
+end
+
+# A fictive tab used to display a link
+class DocTabLink
+       super DocTab
+       autoinit(id, title, icon, url)
+
+       # Link to open when the tab is clicked
+       var url: String
+end
+
+# Nitdoc sidebar abstraction
+class DocSidebar
+
+       # A sidebar contains `StaticCard`
+       var cards = new Array[StaticCard]
+
+       # Is this sidebar empty?
+       fun is_empty: Bool do return cards.is_empty
+end
diff --git a/src/doc/static/static_cards.nit b/src/doc/static/static_cards.nit
new file mode 100644 (file)
index 0000000..e589ca6
--- /dev/null
@@ -0,0 +1,667 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Cards templates for the static documentation
+module static_cards
+
+import doc::commands::commands_graph
+import doc::commands::commands_catalog
+import doc::commands::commands_docdown
+import templates_html
+
+# A card that can be rendered to HTML
+#
+# Basically, these cards are templates with additionnal data and behavior.
+abstract class StaticCard
+       super Template
+
+       # Card title
+       var title: String is writable
+
+       # Card id
+       var id: String is writable
+end
+
+# A list of cards
+class CardList
+       super StaticCard
+
+       # Cards contained in this list
+       var cards = new Array[StaticCard] is writable
+
+       redef fun rendering do
+               addn "<div id='{id}' class='card-list'>"
+               for card in cards do
+                       addn card
+               end
+               addn "</div>"
+       end
+end
+
+# Doc elements
+
+# A card that display custom text data
+class CardText
+       super StaticCard
+       autoinit(content)
+
+       # Custom content from options
+       var content: nullable String is writable
+
+       redef var id = "home"
+       redef var title = "Home"
+
+       redef fun rendering do
+               var content = self.content
+               if content == null then return
+               addn "<div>"
+               addn content
+               addn "</div>"
+               addn "<hr/>"
+       end
+end
+
+# A heading section
+#
+# It displays an heading at a specific level from 1 to 6.
+class CardSection
+       super StaticCard
+       autoinit(level, title, subtitle)
+
+       # Section heading level
+       var level: Int is writable
+
+       # Section subtitle
+       var subtitle: nullable String is writable
+
+       redef var id = title.to_cmangle is lazy
+
+       redef fun rendering do
+               addn "<h{level} id='{id}'>{title}</h{level}>"
+       end
+end
+
+# A page header
+class CardPageHeader
+       super CardSection
+       autoinit(title, subtitle)
+
+       redef var level = 2
+
+       redef fun rendering do
+               addn "<div class='page-header'>"
+               super
+               var subtitle = self.subtitle
+               if subtitle != null then
+                       addn "<p class='text-muted'>"
+                       addn subtitle
+                       addn "</p>"
+               end
+               addn "</div>"
+       end
+end
+
+# A card that displays a summary of a list of cards
+class CardSummary
+       super CardList
+       autoinit(no_title)
+
+       redef var id = "summary"
+       redef var title = "Summary"
+
+       # Show the summary title
+       var no_title: Bool = false is optional, writable
+
+       redef fun rendering do
+               if not no_title then
+                       addn "<h4>Summary</h4>"
+               end
+               addn "<div class='summary'>"
+               addn " <ul class='list-unstyled'>"
+               var sections = new Array[CardSection]
+               for card in cards do
+                       if card isa CardSection then
+                               while sections.not_empty and sections.last.level >= card.level do
+                                       sections.pop
+                               end
+                               sections.add card
+                       end
+                       var level = if sections.is_empty then 1 else sections.last.level
+                       if not card isa CardSection then level += 1
+                       addn "<li><a href='#{card.id}'><h{level}>{card.title}</h{level}></a></li>"
+               end
+               addn " </ul>"
+               addn "</div>"
+       end
+end
+
+# A card that displays the summary of a Markdown document
+class CardMdSummary
+       super CardMDoc
+       autoinit(md_processor, headlines)
+
+       # Markdown processor used to extract and render the content
+       var md_processor: MarkdownProcessor is writable
+
+       # Headlines found in the document
+       var headlines: ArrayMap[String, HeadLine] is writable
+
+       redef var id = "summary"
+       redef var title = "Summary"
+
+       redef fun rendering do
+               addn "<h4>Summary</h4>"
+               addn "<div class='summary'>"
+               addn " <ul class='list-unstyled'>"
+               for id, headline in headlines do
+                       var level = headline.level
+                       var title = md_processor.process(headline.title)
+                       addn "<li><a href='#{id}'><h{level}>{title}</h{level}></a></li>"
+               end
+               addn " </ul>"
+               addn "</div>"
+       end
+end
+
+# MEntity related cards
+
+# A card about a mentity
+#
+# It displays the documentation about the model entity.
+class CardMEntity
+       super StaticCard
+       autoinit(mentity, full_doc)
+
+       # MEntity displayed in this card
+       var mentity: MEntity is writable
+
+       # Render the mentity full documentation?
+       var full_doc = false is optional, writable
+
+       redef var id = mentity.html_id is lazy
+       redef var title = mentity.html_name is lazy
+
+       redef fun rendering do
+               addn """
+               <div id='{{{id}}}' class='card'>
+                       <div class='card-left text-center'>
+                       {{{mentity.html_icon.write_to_string}}}
+                       </div>
+                       <div class='card-body'>
+                               <h5 class='card-heading'>
+                                       {{{mentity.html_declaration.write_to_string}}}
+                               </h5>
+                               <p><small>{{{mentity.html_namespace.write_to_string}}}</small></p>"""
+               var mdoc = mentity.mdoc_or_fallback
+               if mdoc != null then
+                       if full_doc then
+                               addn mdoc.html_documentation
+                       else
+                               addn mdoc.html_synopsis
+                       end
+               end
+               addn """
+                       </div>
+               </div>"""
+       end
+end
+
+# A card that displays the content of a MDoc
+class CardMDoc
+       super CardMEntity
+       autoinit(mentity, mdoc, full_doc)
+
+       # MDoc to display in this card
+       var mdoc: nullable MDoc is writable
+
+       redef fun rendering do
+               var mdoc = self.mdoc
+               if mdoc == null then return
+               addn "<div id='{id}' class='card'>"
+               addn " <div class='card-body nitdoc'>"
+               addn mdoc.html_documentation
+               addn " </div>"
+               addn "</div>"
+       end
+end
+
+# A card about the inheritance of a MEntity
+class CardInheritance
+       super CardMEntity
+
+       # Ancestors list
+       var ancestors: nullable Array[MEntity] is writable
+
+       # Parents list
+       var parents: nullable Array[MEntity] is writable
+
+       # Children list
+       var children: nullable Array[MEntity] is writable
+
+       # Descendants list
+       var descendants: nullable Array[MEntity] is writable
+
+       redef var id = "inh_{super}" is lazy
+       redef var title = "Inheritance" is lazy
+
+       redef fun rendering do
+               var ancestors = self.ancestors
+               var descendants = self.descendants
+               if ancestors == null and parents == null and
+                       children == null and descendants == null then return
+
+               addn "<div id='{id}' class='card'>"
+               addn " <div class='card-body'>"
+               if ancestors != null and ancestors.length <= 10 then
+                       render_list("Ancestors", ancestors)
+               else
+                       render_list("Parents", parents)
+               end
+               if descendants != null and descendants.length <= 10 then
+                       render_list("Descendants", descendants)
+               else
+                       render_list("Children", children)
+               end
+               addn " </div>"
+               addn "</div>"
+       end
+
+       private fun render_list(title: String, mentities: nullable Array[MEntity]) do
+               if mentities == null or mentities.is_empty then return
+               addn "<h4 id='{id}'>{title}</h4>"
+               addn "<ul class='list-unstyled'>"
+               for mentity in mentities do
+                       addn mentity.html_list_item
+               end
+               addn "</ul>"
+       end
+end
+
+# A card about the linearization of a MEntity
+class CardLinearizationList
+       super CardMEntity
+
+       # Linearization cards contained in this list
+       var cards = new Array[CardLinearizationDef] is writable
+
+       redef var id = "lin_{super}" is lazy
+       redef var title = "Linearization" is lazy
+
+       redef fun rendering do
+               if cards.is_empty then return
+
+               addn "<div id='{id}'>"
+               for card in cards do
+                       addn card
+                       if card == cards.last then break
+                       addn "<h4 class='text-muted text-center'>"
+                       addn " <span class='glyphicon glyphicon-chevron-up'></span>"
+                       addn "</h4>"
+               end
+               addn "</div>"
+       end
+end
+
+# A card about a definition in a linearization list
+class CardLinearizationDef
+       super CardCode
+
+       # Is this card displayed by default?
+       var is_active: Bool = false is optional, writable
+
+       # Link to external code repository
+       #
+       # Used if `node` is null
+       var url: nullable String = null is optional, writable
+
+       redef var id = "def_{super}" is lazy
+       redef var title = mentity.full_name is lazy
+
+       redef fun rendering do
+               var url = self.url
+
+               var cin = if is_active then "in" else ""
+               var active = if is_active then "active" else ""
+               addn """
+               <div class='card {{{active}}}' id='{{{id}}}'>
+                       <div class='card-body'>
+                               <h5>
+                                       {{{mentity.html_icon.write_to_string}}}
+                                       {{{mentity.html_namespace.write_to_string}}}"""
+               if node != null then
+                       addn """
+                                       <div class='btn-bar'>
+                                               <button class='btn btn-link' data-toggle='collapse'
+                                                 data-target='#{{{mentity.html_id}}}'>
+                                                       <span class='glyphicon glyphicon-console' title='Show code' />
+                                               </button>
+                                       </div>"""
+               else if url != null then
+                       addn """
+                                       <div class='btn-bar'>
+                                               <a class='btn btn-link' href='{{{url}}}'>
+                                                       <span class='glyphicon glyphicon-console' title='Show code' />
+                                               </a>
+                                       </div>"""
+                       var mdoc = mentity.mdoc
+                       if mdoc != null then
+                               addn "<br/><br/>"
+                               addn mdoc.html_documentation
+                       end
+               end
+               addn "</h5>"
+               if node != null then
+                       addn """
+                               <div id='{{{mentity.html_id}}}' class='collapse {{{cin}}}'>
+                                       <pre>"""
+                       render_code
+                       addn """</pre>
+                                       <span class='text-muted'>{{{mentity.location.to_s}}}</span>
+                               </div>"""
+               end
+               addn """
+                       </div>
+               </div>"""
+       end
+end
+
+# A card that displays the code of a MEntity
+class CardCode
+       super CardMEntity
+       autoinit(mentity, node)
+
+       # AST node to display in this card
+       var node: nullable ANode is writable
+
+       redef var id = "code_{super}" is lazy
+       redef var title = "Code"
+
+       redef fun rendering do
+               addn "<div id='{id}' class='card'>"
+               addn " <div class='card-body'>"
+
+               if node != null then
+                       addn "<pre>"
+                       render_code
+                       addn "</pre>"
+               end
+               addn "<span class='text-muted'>{mentity.location}</span>"
+
+               addn " </div>"
+               addn "</div>"
+       end
+
+       private fun render_code do
+               var node = self.node
+               if node == null then return
+               var hl = new HtmlightVisitor
+               hl.show_infobox = false
+               hl.highlight_node node
+               addn hl.html
+       end
+end
+
+# A card that displays a graph
+class CardGraph
+       super CardMEntity
+       autoinit(mentity, graph)
+
+       # Graph to display in this card
+       var graph: InheritanceGraph is writable
+
+       redef var id = "graph_{super}" is lazy
+       redef var title = "Graph"
+
+       redef fun rendering do
+               addn "<div id='{id}' class='card'>"
+               addn " <div class='card-body'>"
+               addn "  <div class='text-center'>"
+               addn graph.graph.to_svg
+               addn "  </div>"
+               addn " </div>"
+               addn "</div>"
+       end
+end
+
+# Catalog related cards
+
+# A card that displays Nit catalog related data
+abstract class CardCatalog
+       super StaticCard
+       autoinit(catalog)
+
+       # Catalog used to extract the data
+       var catalog: Catalog is writable
+end
+
+# A card that displays statistics about a Nit catalog
+class CardCatalogStats
+       super CardCatalog
+
+       redef var id = "catalog_stats"
+       redef var title = "Stats"
+
+       redef fun rendering do
+               addn "<div id='{id}' class='container-fluid'>"
+               for key, value in catalog.catalog_stats.to_map do
+                       addn "<span class='text-muted small'>"
+                       addn " <strong>{value}</strong>&nbsp;<span>{key}</span>&nbsp;"
+                       addn "</span>"
+               end
+               addn "</div>"
+               addn "<hr/>"
+       end
+end
+
+# A card that displays a list of tags
+class CardCatalogTags
+       super CardCatalog
+
+       redef var id = "catalog_tags"
+       redef var title = "Tags"
+
+       # Sorter to sort tags alphabetically
+       var tags_sorter = new CatalogTagsSorter is writable
+
+       redef fun rendering do
+               var tags = catalog.tag2proj.keys.to_a
+               if tags.is_empty then return
+               tags_sorter.sort(tags)
+
+               addn "<h2 id='{id}'>Tags</h2>"
+               addn "<div class='container-fluid'>"
+               for tag in tags do
+                       addn "<div class='col-xs-6 col-sm-3 col-md-2'>"
+                       addn " <span class='badge'>{catalog.tag2proj[tag].length}</span>"
+                       addn " <a href='tag_{tag.to_cmangle}.html'>{tag}</a>"
+                       addn "</div>"
+               end
+               addn "</div>"
+               addn "<hr/>"
+       end
+end
+
+# A card that displays a package from a Nit catalog
+class CardCatalogPackage
+       super CardCatalog
+       super CardMEntity
+       autoinit(catalog, mentity)
+
+       redef var id = "package_{super}" is lazy
+
+       redef fun rendering do
+               var mpackage = self.mentity
+               if not mpackage isa MPackage then return
+
+               addn """
+                       <div id='{{{id}}}' class='card'>
+                        <div class='card-left text-center'>{{{mpackage.html_icon.write_to_string}}}</div>
+                        <div class='card-body' style='width: 75%'>
+                         <h5 class='card-heading'>
+                               {{{mentity.html_declaration.write_to_string}}}
+                               <small>&nbsp;"""
+               for tag in mpackage.metadata.tags do
+                       add "<span>"
+                       add "<a href='tag_{tag.to_cmangle}.html' class='text-muted'>{tag}</a>"
+                       if tag != mpackage.metadata.tags.last then addn ", "
+                       add "</span>"
+               end
+               addn """</small>
+                               </h5>"""
+               var mdoc = mentity.mdoc_or_fallback
+               if mdoc != null then
+                       if full_doc then
+                               addn mdoc.html_documentation
+                       else
+                               addn mdoc.html_synopsis
+                       end
+               end
+               addn " </div>"
+               addn " <div class='card-right' style='width: 25%'>"
+               for maintainer in mpackage.metadata.maintainers do
+                       addn maintainer.to_html
+               end
+               addn " <br>"
+               var license = mpackage.metadata.license
+               if license != null then
+                       addn """
+                                <span class='text-muted'>
+                                 <a href='http://opensource.org/licenses/{{{license}}}' class='text-muted'>
+                                  {{{license}}}
+                                 </a>
+                               </span>"""
+               end
+               addn " </div>"
+               addn "</div>"
+       end
+end
+
+# A card that displays the metadata about a package in the Nit catalog
+class CardMetadata
+       super CardMEntity
+       autoinit(mentity, metadata, stats, deps, clients)
+
+       # Package metadata to display
+       var metadata: MPackageMetadata is writable
+
+       # Package stats
+       var stats: MPackageStats is writable
+
+       # Package dependencies
+       var deps: Array[MPackage] is writable
+
+       # Package clients
+       var clients: Array[MPackage] is writable
+
+       redef var id = "metadata_{super}" is lazy
+       redef var title = "Metadata"
+
+       redef fun rendering do
+               for maintainer in metadata.maintainers do
+                       addn """
+                               <p class='lead'>
+                                       {{{maintainer.to_html}}}
+                               </p>"""
+               end
+               var license = metadata.license
+               if license != null then
+                       addn """
+                               <span class='text-muted'>
+                                       <a href='http://opensource.org/licenses/{{{license}}}'>{{{license}}}</a>
+                                       license
+                               </span>"""
+               end
+
+               var homepage = metadata.homepage
+               var browse = metadata.browse
+               var issues = metadata.issues
+               if homepage != null or browse != null or issues != null then
+                       addn """
+                               <h4>Links</h4>
+                               <ul class='list-unstyled'>"""
+                       if homepage != null then addn "<li><a href='{homepage}'>Homepage</a></li>"
+                       if browse != null then addn "<li><a href='{browse}'>Source Code</a></li>"
+                       if issues != null then addn "<li><a href='{issues}'>Issues</a></li>"
+                       addn "</ul>"
+               end
+
+               var git = metadata.git
+               var last_date = metadata.last_date
+               var first_date = metadata.first_date
+               if git != null then
+                       addn """
+                               <h4>Git</h4>
+                               <ul class='list-unstyled'>
+                                       <li><a href='{{{git}}}'>{{{git}}}</a></li>
+                               </ul>
+                               <span class='text-muted'><b>{{{stats.commits}}}</b> commits</span>
+                               <br>"""
+                       if last_date != null then
+                               addn """<b class=text-muted>Last:</b> {{{last_date}}}<br>"""
+                       end
+                       if first_date != null then
+                               addn """<b class=text-muted>First:</b> {{{first_date}}}"""
+                       end
+               end
+
+               addn """
+                       <h4>Quality</h4>
+                       <ul class='list-unstyled'>
+                               <li>{{{stats.documentation_score}}}% documented</li>
+                       </ul>"""
+
+               if metadata.tags.not_empty then
+                       addn "<h4>Tags</h4>"
+                       for tag in metadata.tags do
+                               addn " <a href='tag_{tag.to_cmangle}.html'>{tag}</a>"
+                               if tag != metadata.tags.last then add ", "
+                       end
+               end
+
+               if deps.not_empty then
+                       addn "<h4>Dependencies</h4>"
+                       for dep in deps do
+                               add dep.html_link
+                               if dep != deps.last then add ", "
+                       end
+               end
+
+               if clients.not_empty then
+                       addn "<h4>Clients</h4>"
+                       for client in clients do
+                               add client.html_link
+                               if client != clients.last then add ", "
+                       end
+               end
+
+               if metadata.contributors.not_empty then
+                       addn """
+                               <h4>Contributors</h4>
+                               <ul class='list-unstyled'>"""
+                       for contrib in metadata.contributors do
+                               addn """<li>{{{contrib.to_html}}}</li>"""
+                       end
+                       addn "</ul>"
+               end
+
+               addn """
+                       <h4>Stats</h4>
+                       <ul class='list-unstyled'>
+                               <li>{{{stats.mmodules}}} modules</li>
+                               <li>{{{stats.mclasses}}} classes</li>
+                               <li>{{{stats.mmethods}}} methods</li>
+                               <li>{{{stats.loc}}} loc</li>
+                       </ul>"""
+       end
+end
diff --git a/src/doc/static/static_html.nit b/src/doc/static/static_html.nit
new file mode 100644 (file)
index 0000000..eb2834f
--- /dev/null
@@ -0,0 +1,412 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Render documentation pages as HTML
+module static_html
+
+import static::static_structure
+import json
+
+redef class DocPage
+       super Template
+
+       # Page url
+       var html_url: String is writable, noinit
+
+       # Directory where css, js and other assets can be found
+       var shareurl: String is writable, noinit
+
+       # Top menu template if any
+       var topmenu: DocTopMenu is writable, noinit
+
+       # Footer content if any
+       var footer: nullable Writable = null is writable
+
+       # Render the page as a html template
+       fun render(doc: DocModel): Writable do
+               # init page options
+               self.shareurl = doc.share_url or else "."
+               self.footer = doc.custom_footer
+
+               # build page
+               init_title(doc)
+               init_topmenu(doc)
+
+               # piwik tracking
+               var tracker_url = doc.tracker_url
+               var site_id = doc.piwik_site_id
+               if tracker_url != null and site_id != null then
+                       piwik_script = new PiwikScript(tracker_url, site_id)
+               end
+               return self
+       end
+
+       # Build page title string
+       fun init_title(doc: DocModel) do end
+
+       # Build top menu template if any
+       fun init_topmenu(doc: DocModel) do
+               topmenu = new DocTopMenu
+
+               var home = new Link("index.html", "Nitdoc")
+
+               var custom_brand = doc.custom_brand
+               if custom_brand != null then
+                       topmenu.brand = new Link("index.html", custom_brand)
+                       topmenu.items.add new ListItem(home)
+               else
+                       topmenu.brand = home
+               end
+       end
+
+       # Renders the html `<head>`
+       private fun render_head do
+               var css = (self.shareurl / "css").html_escape
+               var vendors = (self.shareurl / "vendors").html_escape
+
+               addn "<!DOCTYPE html>"
+               addn "<head>"
+               addn " <meta charset='utf-8'/>"
+               addn " <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
+               addn " <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
+               addn " <link rel='stylesheet' href='{css}/nitdoc.cards.css'/>"
+               addn " <link rel='stylesheet' href='{css}/nitdoc.code.css'/>"
+               addn " <link rel='stylesheet' href='{css}/nitdoc.css'/>"
+               addn " <link rel='stylesheet' href='{css}/nitdoc.quicksearch.css'/>"
+               addn " <title>{title.html_escape}</title>"
+               addn "</head>"
+               add "<body>"
+       end
+
+       # Renders the footer and content
+       private fun render_content do
+               if tabs.is_empty then return
+               if tabs.length == 1 then
+                       addn tabs.first
+                       return
+               end
+               addn "<ul class='nav nav-tabs'>"
+               for tab in tabs do
+                       if tab.is_empty and not tab isa DocTabLink then continue
+                       addn tab.tab_link
+               end
+               addn "</ul>"
+               addn "<div class='tab-content'>"
+               for tab in tabs do
+                       if tab.is_empty then continue
+                       addn tab
+               end
+               addn "</div>"
+       end
+
+       # Piwik script to append in the page scripts
+       var piwik_script: nullable PiwikScript = null is writable
+
+       # Render JS scripts
+       private fun render_footer do
+               if footer != null then
+                       addn "<div class='footer'>"
+                       add footer.as(not null)
+                       addn "</div>"
+               end
+               var vendors = (self.shareurl / "vendors").html_escape
+               var js = (self.shareurl / "js").html_escape
+
+               addn "<script src='quicksearch-list.js'></script>"
+               addn "<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
+               addn "<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
+               addn "<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
+               addn "<script src='{js}/nitdoc.utils.js'></script>"
+               addn "<script src='{js}/nitdoc.quicksearch.js'></script>"
+
+               var piwik_script = self.piwik_script
+               if piwik_script != null then
+                       add piwik_script
+               end
+               addn "</body>"
+               addn "</html>"
+       end
+
+       # Render the whole page
+       redef fun rendering do
+               render_head
+               add topmenu
+               addn "<div class='container-fluid'>"
+               render_content
+               addn "</div>"
+               render_footer
+       end
+end
+
+redef class PageHome
+       redef var html_url = "index.html"
+
+       redef fun render(doc) do
+               main_tab.show_sidebar = false
+               return super
+       end
+
+       redef fun init_title(doc) do
+               title = doc.custom_title or else "Nitdoc"
+       end
+
+       redef fun render_content do
+               addn "<div class='container'>"
+               if tabs.not_empty then
+                       addn tabs.first
+               end
+               addn "</div>"
+       end
+end
+
+redef class PageMEntity
+       redef var html_url is lazy do return mentity.html_url
+       redef fun init_title(doc) do title = mentity.html_name
+
+       redef fun render_content do
+               addn new CardPageHeader(
+                       mentity.html_declaration.write_to_string,
+                       mentity.html_namespace.write_to_string)
+               super
+       end
+
+       redef fun init_topmenu(doc) do
+               super
+               for m in mentity.nitdoc_breadcrumbs do
+                       topmenu.add_li new ListItem(new Link(m.html_url, m.html_name))
+               end
+               topmenu.active_item = topmenu.items.last
+       end
+end
+
+redef class PagePerson
+       redef var html_url is lazy do return person.html_url
+end
+
+redef class PageTag
+       redef var html_url is lazy do return "tag_{tag.to_cmangle}.html"
+end
+
+redef class HtmlightVisitor
+       redef fun hrefto(mentity) do return mentity.html_url
+end
+
+redef class DocTab
+       super Template
+
+       # Show sidebar for this page?
+       var show_sidebar = true is writable
+
+       # Tab link for tab headers
+       fun tab_link: Template do
+               var tpl = new Template
+               tpl.addn "<li class='{if is_active then "active" else ""}'>"
+               tpl.addn " <a data-toggle='tab' href='#{id}'>"
+
+               var icon = self.icon
+               if icon != null then
+                       tpl.addn "  <span class='glyphicon glyphicon-{icon}'></span>"
+               end
+               tpl.addn " {title}"
+               tpl.addn " </a>"
+               tpl.addn "</li>"
+               return tpl
+       end
+
+       redef fun rendering do
+               var has_left = show_sidebar and sidebar.cards.not_empty
+               var has_right = metadata.cards.not_empty
+
+               addn "<div class='tab-pane {if is_active then "active" else ""}' id='{id}'>"
+               if has_left then
+                       addn " <div class='col-sm-3'>"
+                       addn sidebar
+                       addn " </div>"
+               end
+               var cols = 12
+               if has_left then cols -= 3
+               if has_right then cols -= 3
+               addn " <div class='col-sm-{cols}'>"
+               for card in content do addn card
+               addn " </div>"
+               if has_right then
+                       addn " <div class='col-sm-3'>"
+                       addn metadata
+                       addn " </div>"
+               end
+               addn "</div>"
+       end
+end
+
+redef class DocTabLink
+
+       redef fun tab_link do
+               var tpl = new Template
+               tpl.addn "<li class='{if is_active then "active" else ""}'>"
+               tpl.addn " <a href='{url.html_escape}'>"
+
+               var icon = self.icon
+               if icon != null then
+                       tpl.addn "  <span class='glyphicon glyphicon-{icon}'></span>"
+               end
+               tpl.addn " {title}"
+               tpl.addn " </a>"
+               tpl.addn "</li>"
+               return tpl
+       end
+
+       redef fun rendering do end
+end
+
+# Top menu bar template
+class DocTopMenu
+       super UnorderedList
+
+       # Brand link to display in first position of the top menu
+       #
+       # This is where you want to put your logo.
+       var brand: nullable Link is noinit, writable
+
+       # Active menu item
+       #
+       # Depends on the current page, this allows to hilighted the current item.
+       var active_item: nullable ListItem is noinit, writable
+
+       redef fun rendering do
+               addn "<nav class='navbar navbar-default navbar-fixed-top'>"
+               addn " <div class='container-fluid'>"
+               addn "  <div class='navbar-header'>"
+               add  "   <button type='button' class='navbar-toggle' "
+               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
+               addn "    <span class='sr-only'>Toggle menu</span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "   </button>"
+               var brand = self.brand
+               if brand != null then
+                       add "<span class='navbar-brand'>"
+                       add brand
+                       add "</span>"
+               end
+               addn "  </div>"
+               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
+               addn "   <ul class='nav navbar-nav'>"
+               for item in items do
+                       if item == active_item then item.css_classes.add "active"
+                       add item.write_to_string
+               end
+               addn "   </ul>"
+               addn "   <div id='search-placeholder'>"
+               addn "   </div>"
+               addn "  </div>"
+               addn " </div>"
+               addn "</nav>"
+       end
+end
+
+redef class DocSidebar
+       super Template
+
+       redef fun rendering do
+               if cards.is_empty then return
+               addn "<div id='sidebar'>"
+               for card in cards do addn card
+               addn "</div>"
+       end
+end
+
+# JS script for Piwik Tracker
+class PiwikScript
+       super Template
+
+       # Piwik URL to use for this tracker
+       var tracker_url: String
+
+       # Site ID used on Piwik system
+       var site_id: String
+
+       redef fun rendering do
+               addn "<script>"
+
+               var site_id = self.site_id.to_json
+               var tracker_url = self.tracker_url.trim
+               if tracker_url.chars.last != '/' then tracker_url += "/"
+               tracker_url = "://{tracker_url}".to_json
+
+               addn "<!-- Piwik -->"
+               addn "var _paq = _paq || [];"
+               addn " _paq.push([\"trackPageView\"]);"
+               addn " _paq.push([\"enableLinkTracking\"]);"
+               addn "(function() \{"
+               addn " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + {tracker_url};"
+               addn " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
+               addn " _paq.push([\"setSiteId\", {site_id}]);"
+               addn " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
+               addn " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
+               addn "\})();"
+
+               addn "</script>"
+       end
+end
+
+# Model redefs
+
+redef class MEntity
+       redef fun to_dot_node do
+               var node = super
+               node["URL"] = html_url
+               return node
+       end
+
+       redef var html_url = "{html_id}.html" is lazy
+end
+
+redef class MPackage
+       redef var html_url is lazy do return "package_{super}"
+end
+
+redef class MGroup
+       redef var html_url is lazy do return "group_{super}"
+end
+
+redef class MModule
+       redef var html_url is lazy do return "module_{super}"
+end
+
+redef class MClass
+       redef var html_url is lazy do return "class_{super}"
+end
+
+redef class MClassDef
+       redef var html_url is lazy do
+               if is_intro then return mclass.html_url
+               return "{mclass.html_url}?def=def_code_{html_id}#lin"
+       end
+end
+
+redef class MProperty
+       redef var html_url is lazy do return "property_{super}"
+end
+
+redef class MPropDef
+       redef var html_url is lazy do
+               if is_intro then return mproperty.html_url
+               return "{mproperty.html_url}?def=def_code_{html_id}#lin"
+       end
+end
+
+redef class Person
+       redef var html_url = "person_{html_id}.html" is lazy
+end
diff --git a/src/doc/static/static_index.nit b/src/doc/static/static_index.nit
new file mode 100644 (file)
index 0000000..699a480
--- /dev/null
@@ -0,0 +1,82 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Manage indexing of Nit model for Nitdoc QuickSearch.
+module static_index
+
+import static::static_html
+import json
+
+# Generate the index for then Nitdoc QuickSearch field.
+#
+# Create a JSON object containing links to:
+#  * mpackages
+#  * modules
+#  * mclasses
+#  * mpropdefs
+# All entities are grouped by name to make the research easier.
+#
+# TODO Merge with model_index
+redef class DocModel
+
+       # Build the nitdoc quick search index
+       fun create_index_file(file: String) do
+               var table = new QuickSearchTable(self)
+               var tpl = new Template
+               tpl.add "var nitdocQuickSearchRawList="
+               tpl.add table.to_json
+               tpl.add ";"
+               tpl.write_to_file(file)
+       end
+end
+
+# The result map for QuickSearch.
+private class QuickSearchTable
+       super HashMap[String, Array[QuickSearchResult]]
+
+       var doc: DocModel
+
+       init do
+               var model = doc.model
+               var filter = doc.filter
+
+               index_mentities model.collect_mpackages(filter)
+               index_mentities model.collect_mmodules(filter)
+               index_mentities model.collect_mclasses(filter)
+               index_mentities model.collect_mproperties(filter)
+       end
+
+       fun index_mentities(mentities: Collection[MEntity]) do
+               for mentity in mentities do index_mentity mentity
+       end
+
+       fun index_mentity(mentity: MEntity) do
+               var key = mentity.name
+               if not has_key(key) then
+                       self[key] = new Array[QuickSearchResult]
+               end
+               self[key].add new QuickSearchResult(mentity.full_name, mentity.html_url)
+       end
+end
+
+# A QuickSearch result.
+private class QuickSearchResult
+       serialize
+
+       # The text of the link.
+       var txt: String
+
+       # The destination of the link.
+       var url: String
+end
diff --git a/src/doc/static/static_structure.nit b/src/doc/static/static_structure.nit
new file mode 100644 (file)
index 0000000..8afe591
--- /dev/null
@@ -0,0 +1,439 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Composes the pages of the static documentation
+module static_structure
+
+import static::static_base
+
+redef class DocPage
+
+       # Create the structure of this page
+       fun apply_structure(doc: DocModel) do end
+end
+
+redef class PageHome
+       redef fun apply_structure(doc) do
+               var title = doc.custom_title or else "Welcome to Nitdoc!"
+               var intro = doc.custom_intro
+
+               if intro != null then
+                       main_tab.content.add new CardPageHeader(title)
+                       main_tab.content.add new CardText(intro)
+               else
+                       main_tab.content.add new CardPageHeader(title, "The Nit API documentation.")
+               end
+
+               main_tab.content.add new CardCatalogStats(doc.catalog)
+               main_tab.content.add new CardCatalogTags(doc.catalog)
+
+               main_tab.content.add new CardSection(2, "Packages")
+               var mpackages_sorter = new CatalogScoreSorter(doc.catalog)
+
+               var mpackages = doc.catalog.mpackages.values.to_a
+               mpackages_sorter.sort mpackages
+               var list = new CardList("packages", "Packages")
+               for mpackage in mpackages do
+                       list.cards.add new CardCatalogPackage(doc.catalog, mpackage)
+               end
+               # TODO pagination?
+               main_tab.content.add list
+       end
+end
+
+redef class PageMEntity
+       # Concerns to display in this page.
+       var concerns: nullable ConcernsTree = null
+
+       redef fun apply_structure(doc) do
+               build_main(doc)
+               build_api(doc)
+               build_dependencies(doc)
+       end
+
+       # Build the main tab (the one that contains the MDoc)
+       fun build_main(doc: DocModel) do
+               var mentity = self.mentity
+
+               var sq = new CmdSummary(doc.model, doc.filter, mentity,
+                       markdown_processor = doc.inline_processor)
+               sq.init_command
+
+               main_tab.content.add new CardMDoc(mentity, mentity.mdoc_or_fallback)
+
+               var summary = sq.summary
+               if summary != null then
+                       main_tab.sidebar.cards.add new CardMdSummary(headlines = summary, md_processor = doc.inline_processor)
+               end
+       end
+
+       # Build the API tab
+       fun build_api(doc: DocModel) do
+               var summary = new CardSummary
+
+               var title = "All definitions"
+               if mentity isa MPackage then title = "All groups and modules"
+               if mentity isa MGroup then title = "All subgroups and modules"
+               if mentity isa MModule then title = "All class definitions"
+               if mentity isa MClass or mentity isa MClassDef then title = "All properties"
+
+               var section = new CardSection(2, title)
+               api_tab.content.add section
+               summary.cards.add section
+
+               var dq = new CmdFeatures(doc.model, doc.filter, mentity)
+               dq.init_command
+               var mentities = dq.results
+               if mentities == null then return
+
+               var list = new CardList("api", "API")
+               for m in mentities do
+                       var card = new CardMEntity(m)
+                       card.id = "api_{card.id}" # avoid id conflicts with main tab
+                       list.cards.add card
+                       summary.cards.add card
+               end
+               api_tab.content.add list
+
+               if summary.cards.not_empty then
+                       api_tab.sidebar.cards.add summary
+               end
+       end
+
+       # Build the dependencies tab
+       fun build_dependencies(doc: DocModel) do
+               var summary = new CardSummary
+
+               var model = doc.model
+               var mainmodule = doc.mainmodule
+               var filter = doc.filter
+
+               if not doc.no_dot then
+                       var gq = new CmdInheritanceGraph(model, mainmodule, filter, mentity)
+                       gq.init_command
+                       var graph = gq.graph
+                       if graph != null then
+                               graph.draw(2, 2)
+                               dep_tab.content.add new CardGraph(mentity, graph)
+                       end
+               end
+
+               # No inheritance lists for `Object`
+               if mentity isa MClass and mentity.name == "Object" then return
+
+               var inh = new HashMap[String, CmdEntityList]
+               inh["Ancestors"] = new CmdAncestors(model, mainmodule, filter, mentity, parents = false)
+               inh["Parents"] = new CmdParents(model, mainmodule, filter, mentity)
+               inh["Children"] = new CmdChildren(model, mainmodule, filter, mentity)
+               inh["Descendants"] = new CmdDescendants(model, mainmodule, filter, mentity, children = false)
+
+               for title, cmd in inh do
+                       cmd.init_command
+                       var results = cmd.results
+                       if results == null or results.is_empty then continue
+                       var section = new CardSection(3, title)
+                       dep_tab.content.add section
+                       summary.cards.add section
+
+                       var list = new CardList("inh", "Inheritance")
+                       for mentity in results do
+                               var card = new CardMEntity(mentity)
+                               list.cards.add card
+                               summary.cards.add card
+                       end
+                       dep_tab.content.add list
+               end
+
+               if summary.cards.not_empty then
+                       dep_tab.sidebar.cards.add summary
+               end
+       end
+
+       # Build the code panel
+       fun build_code(doc: DocModel) do
+               var code_url = doc.code_url
+
+               if not doc.no_code then
+                       var cq = new CmdEntityCode(doc.model, doc.modelbuilder, doc.filter, mentity)
+                       cq.init_command
+
+                       var code = cq.node
+                       if code == null then return
+                       code_tab.content.add new CardCode(mentity, code)
+               else if doc.code_url != null then
+                       code_tab = new DocTabLink("code", "Code", "console", mentity.source_url(code_url))
+               end
+       end
+
+       # Build the linearization panel
+       fun build_linearization(doc: DocModel) do
+               var summary = new CardSummary
+
+               var lq = new CmdLinearization(doc.model, doc.mainmodule, doc.filter, mentity)
+               lq.init_command
+
+               var mentities = lq.results
+               if mentities == null then return
+
+               if mentity isa MClass or mentity isa MClassDef then
+                       if mentity.name == "Object" then return # No linearization for `Object`
+                       if mentity.name == "Sys" then return # No linearization for `Sys`
+                       var section = new CardSection(2, "Class definitions")
+                       lin_tab.content.add section
+                       summary.cards.add section
+               else if mentity isa MProperty or mentity isa MPropDef then
+                       if mentity.name == "init" then return # No linearization for `init`
+                       if mentity.name == "SELF" then return # No linearization for `SELF`
+                       if mentity.name == "to_s" then return # No linearization for `to_s`
+                       var section = new CardSection(2, "Property definitions")
+                       lin_tab.content.add section
+                       summary.cards.add section
+               end
+
+               var list = new CardLinearizationList(mentity)
+               for m in mentities do
+                       var url = mentity.source_url(doc.code_url)
+                       var node = doc.modelbuilder.mentity2node(m)
+                       if node == null then continue
+                       if doc.no_code then node = null
+                       if m == mentity or
+                         (m isa MClassDef and m.is_intro) or
+                         (m isa MPropDef and m.is_intro) then
+                               var card = new CardLinearizationDef(m, node, is_active = true, url)
+                               list.cards.add card
+                               summary.cards.add card
+                       else
+                               var card = new CardLinearizationDef(m, node, is_active = false, url)
+                               list.cards.add card
+                               summary.cards.add card
+                       end
+               end
+               lin_tab.content.add list
+
+               if summary.cards.not_empty then
+                       lin_tab.sidebar.cards.add summary
+               end
+       end
+end
+
+redef class PageMPackage
+       redef fun build_main(doc) do
+               super
+               main_tab.metadata.cards.add new CardMetadata(mentity, mentity.metadata,
+                       doc.catalog.mpackages_stats[mentity],
+                       doc.catalog.deps[mentity].direct_greaters.to_a,
+                       doc.catalog.deps[mentity].direct_smallers.to_a)
+       end
+end
+
+redef class PageMModule
+       redef fun apply_structure(doc) do
+               super
+               build_code(doc)
+       end
+
+       redef fun build_main(doc) do
+               super
+
+               var summary = new CardSummary(no_title = true)
+
+               # Intros
+               var cmd: CmdEntities = new CmdIntros(doc.model, doc.mainmodule, doc.filter, mentity)
+               cmd.init_command
+               var intros = cmd.results
+               if intros != null and intros.not_empty then
+                       var section = new CardSection(3, "Introduced classes")
+                       main_tab.content.add section
+                       summary.cards.add section
+                       var cards = new CardList("intros", "Intros")
+                       for intro in intros do
+                               var card = new CardMEntity(intro)
+                               summary.cards.add card
+                               cards.cards.add card
+                       end
+                       main_tab.content.add cards
+               end
+
+               # Redefs
+               cmd = new CmdRedefs(doc.model, doc.mainmodule, doc.filter, mentity)
+               cmd.init_command
+               var redefs = cmd.results
+               if redefs != null and redefs.not_empty then
+                       var section = new CardSection(3, "Redefined classes")
+                       main_tab.content.add section
+                       summary.cards.add section
+                       var cards = new CardList("redefs", "Redefs")
+                       for prop in redefs do
+                               var card = new CardMEntity(prop)
+                               summary.cards.add card
+                               cards.cards.add card
+                       end
+                       main_tab.content.add cards
+               end
+
+               main_tab.sidebar.cards.add summary
+       end
+end
+
+redef class PageMClass
+       redef fun apply_structure(doc) do
+               super
+               build_code(doc)
+               build_linearization(doc)
+       end
+
+       redef fun build_main(doc) do
+               super
+
+               var summary = new CardSummary(no_title = true)
+
+               # Intros
+               var cmd: CmdEntities = new CmdIntros(doc.model, doc.mainmodule, doc.filter, mentity)
+               cmd.init_command
+               var intros = cmd.results
+               if intros != null and intros.not_empty then
+                       var section = new CardSection(3, "Introduced properties")
+                       main_tab.content.add section
+                       summary.cards.add section
+                       var cards = new CardList("intros", "Intros")
+                       for intro in intros do
+                               var card = new CardMEntity(intro)
+                               summary.cards.add card
+                               cards.cards.add card
+                       end
+                       main_tab.content.add cards
+               end
+
+               # Redefs
+               cmd = new CmdRedefs(doc.model, doc.mainmodule, doc.filter, mentity)
+               cmd.init_command
+               var redefs = cmd.results
+               if redefs != null and redefs.not_empty then
+                       var section = new CardSection(3, "Redefined properties")
+                       main_tab.content.add section
+                       summary.cards.add section
+                       var cards = new CardList("redefs", "Redefs")
+                       for prop in redefs do
+                               var card = new CardMEntity(prop)
+                               summary.cards.add card
+                               cards.cards.add card
+                       end
+                       main_tab.content.add cards
+               end
+
+               # Expand summary
+               main_tab.sidebar.cards.add summary
+       end
+
+       redef fun build_api(doc) do
+               var summary = new CardSummary
+
+               var section = new CardSection(2, "All properties")
+               api_tab.content.add section
+               summary.cards.add section
+
+               var dq = new CmdAllProps(doc.model, doc.mainmodule, doc.filter, mentity)
+               dq.init_command
+               var mentities = dq.results
+               if mentities == null then return
+
+               var list = new CardList("api", "API")
+               for m in mentities do
+                       var card = new CardMEntity(m)
+                       list.cards.add card
+                       summary.cards.add card
+               end
+               api_tab.content.add list
+
+               if summary.cards.not_empty then
+                       api_tab.sidebar.cards.add summary
+               end
+       end
+end
+
+redef class PageMProperty
+       redef fun apply_structure(doc) do
+               super
+               build_code(doc)
+               build_linearization(doc)
+       end
+end
+
+redef class PagePerson
+       redef fun apply_structure(doc) do
+               var mpackages_sorter = new CatalogScoreSorter(doc.catalog)
+               main_tab.content.add new CardPageHeader(person.name, person.email)
+
+               var maint = doc.catalog.maint2proj[person]
+               mpackages_sorter.sort maint
+               var mlist = new CardList("maintained", "Maintained")
+               for mpackage in maint do
+                       mlist.cards.add new CardCatalogPackage(doc.catalog, mpackage)
+               end
+
+               # TODO pagination?
+               if maint.not_empty then
+                       main_tab.content.add new CardSection(3, "{maint.length} maintained packages")
+                       main_tab.content.add mlist
+               end
+
+               var contrib = doc.catalog.contrib2proj[person]
+               mpackages_sorter.sort contrib
+               var clist = new CardList("contribs", "Contributed")
+               for mpackage in contrib do
+                       clist.cards.add new CardCatalogPackage(doc.catalog, mpackage)
+               end
+
+               # TODO pagination?
+               if contrib.not_empty then
+                       main_tab.content.add new CardSection(3, "{contrib.length} contributed packages")
+                       main_tab.content.add clist
+               end
+       end
+end
+
+redef class PageTag
+       redef fun apply_structure(doc) do
+               var mpackages_sorter = new CatalogScoreSorter(doc.catalog)
+               main_tab.content.add new CardPageHeader(tag)
+
+               var mpackages = doc.catalog.tag2proj[tag]
+               mpackages_sorter.sort mpackages
+               var list = new CardList("packages", "Packages")
+               for mpackage in mpackages do
+                       list.cards.add new CardCatalogPackage(doc.catalog, mpackage)
+               end
+
+               # TODO pagination?
+               main_tab.content.add new CardSection(3, "{mpackages.length} packages")
+               main_tab.content.add list
+       end
+end
+
+redef class MEntity
+       # Render a HTML link for the MEntity location
+       private fun source_url(url_pattern: nullable String): String do
+               var location = self.location
+               var file = location.file
+
+               if file == null then return location.to_s
+               if url_pattern == null then return file.filename.simplify_path
+
+               var url = url_pattern
+               url = url.replace("%f", file.filename.simplify_path)
+               url = url.replace("%l", location.line_start.to_s)
+               url = url.replace("%L", location.line_end.to_s)
+               return url.simplify_path
+       end
+end
index 94132ff..65227b3 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Documentation generator for the nit language.
+# Generator of static API documentation for the Nit language
 #
-# Generate API documentation in HTML format from nit source code.
+# Generate API documentation in HTML format from Nit source code.
 module nitdoc
 
-import modelbuilder
-import doc
+import doc::static
 
 redef class ToolContext
-       # Nitdoc generation phase.
+
+       # Nitdoc generation phase
        var docphase: Phase = new Nitdoc(self, null)
 
-       # Do not generate documentation for attributes.
+       # Directory where the Nitdoc is rendered
+       var opt_dir = new OptionString("Output directory", "-d", "--dir")
+
+       # Do not generate documentation for attributes
        var opt_no_attributes = new OptionBool("Ignore the attributes", "--no-attributes")
 
-       # Do not generate documentation for private properties.
+       # Do not generate documentation for private properties
        var opt_private = new OptionBool("Also generate private API", "--private")
 
+       # Use a shareurl instead of copy shared files
+       #
+       # This is usefull if you don't want to store the Nitdoc templates with your
+       # documentation.
+       var opt_shareurl = new OptionString("Use shareurl instead of copy shared files", "--shareurl")
+
+       # Use a custom title for the homepage
+       var opt_custom_title = new OptionString("Custom title for homepage", "--custom-title")
+
+       # Display a custom brand or logo in the documentation top menu
+       var opt_custom_brand = new OptionString("Custom link to external site", "--custom-brand")
+
+       # Display a custom introduction text before the packages overview
+       var opt_custom_intro = new OptionString("Custom intro text for homepage", "--custom-overview-text")
+
+       # Display a custom footer on each documentation page
+       #
+       # Generally used to display the documentation or product version.
+       var opt_custom_footer = new OptionString("Custom footer text", "--custom-footer-text")
+
+       # Piwik tracker URL
+       #
+       # If you want to monitor your visitors.
+       var opt_piwik_tracker = new OptionString("Piwik tracker URL (ex: `nitlanguage.org/piwik/`)", "--piwik-tracker")
+
+       # Piwik tracker site id
+       var opt_piwik_site_id = new OptionString("Piwik site ID", "--piwik-site-id")
+
+       # Do not generate dot/graphviz diagrams
+       var opt_nodot = new OptionBool("Do not generate graphs with graphviz", "--no-dot")
+
+       # Do not include highlighted code
+       var opt_nocode = new OptionBool("Do not generate code with nitlight", "--no-code")
+
+       # File pattern used to link documentation to source code.
+       var opt_source = new OptionString("Format to link source code (%f for filename, " +
+               "%l for first line, %L for last line) only works with option --no-code", "--source")
+
+       # Disable HTML rendering
+       var opt_norender = new OptionBool("DO not render any HTML", "--no-render")
+
+       # Test mode
+       #
+       # Display test data and remove the progress bar
+       var opt_test = new OptionBool("Output test data", "--test")
+
        redef init do
                super
-               option_context.add_option(opt_no_attributes, opt_private)
+               option_context.add_option(
+                       opt_dir, opt_no_attributes, opt_private,
+                       opt_share_dir, opt_shareurl, opt_custom_title,
+                       opt_custom_footer, opt_custom_intro, opt_custom_brand,
+                       opt_piwik_tracker, opt_piwik_site_id,
+                       opt_nodot, opt_nocode, opt_source, opt_norender, opt_test)
+       end
+end
+
+redef class DocModel
+
+       # Generate a documentation page
+       fun gen_page(page: DocPage, output_dir: String) do
+               page.apply_structure(self)
+               page.render(self).write_to_file("{output_dir}/{page.html_url}")
        end
 end
 
-# Nitdoc phase explores the model and generate pages for each mentities found
+# Nitdoc phase explores the model and generate pages for each mentity found
 private class Nitdoc
        super Phase
+
        redef fun process_mainmodule(mainmodule, mmodules)
        do
+               var modelbuilder = toolcontext.modelbuilder
+               var model = modelbuilder.model
+
                var min_visibility = private_visibility
                if not toolcontext.opt_private.value then min_visibility = protected_visibility
                var accept_attribute = true
                if toolcontext.opt_no_attributes.value then accept_attribute = false
 
-               var filters = new ModelFilter(
+               var catalog = new Catalog(toolcontext.modelbuilder)
+               catalog.build_catalog(mainmodule.model.mpackages)
+
+               var filter = new ModelFilter(
                        min_visibility,
                        accept_attribute = accept_attribute,
-                       accept_fictive = false)
-               var doc = new DocModel(toolcontext.modelbuilder.model, mainmodule, filters)
-
-               var phases = [
-                       new IndexingPhase(toolcontext, doc),
-                       new MakePagePhase(toolcontext, doc),
-                       new POSetPhase(toolcontext, doc),
-                       new ConcernsPhase(toolcontext, doc),
-                       new StructurePhase(toolcontext, doc),
-                       new InheritanceListsPhase(toolcontext, doc),
-                       new IntroRedefListPhase(toolcontext, doc),
-                       new LinListPhase(toolcontext, doc),
-                       new GraphPhase(toolcontext, doc),
-                       new ReadmePhase(toolcontext, doc),
-                       new RenderHTMLPhase(toolcontext, doc),
-                       new DocTestPhase(toolcontext, doc): DocPhase]
-
-               for phase in phases do
-                       toolcontext.info("# {phase.class_name}", 1)
-                       phase.apply
+                       accept_fictive = true,
+                       accept_generated = true,
+                       accept_test = false,
+                       accept_redef = true,
+                       accept_extern = true,
+                       accept_empty_doc = true,
+                       accept_example = true,
+                       accept_broken = false)
+
+               var doc = new DocModel(model, mainmodule, modelbuilder, catalog, filter)
+
+               model.nitdoc_md_processor = doc.md_processor
+               doc.no_dot = toolcontext.opt_nodot.value
+               doc.no_code = toolcontext.opt_nocode.value
+               doc.code_url = toolcontext.opt_source.value
+               doc.share_url = toolcontext.opt_shareurl.value
+               doc.custom_brand = toolcontext.opt_custom_brand.value
+               doc.custom_title = toolcontext.opt_custom_title.value
+               doc.custom_footer = toolcontext.opt_custom_footer.value
+               doc.custom_intro = toolcontext.opt_custom_intro.value
+               doc.tracker_url = toolcontext.opt_piwik_tracker.value
+               doc.piwik_site_id = toolcontext.opt_piwik_site_id.value
+
+               # Prepare output dir
+               var test_mode = toolcontext.opt_test.value
+               var no_render = toolcontext.opt_norender.value
+               var output_dir = toolcontext.opt_dir.value or else "doc"
+
+               if not no_render then
+                       output_dir.mkdir
+
+                       # Copy assets
+                       var share_dir = toolcontext.opt_share_dir.value or else "{toolcontext.share_dir}/nitdoc"
+                       sys.system("cp -r -- {share_dir.escape_to_sh}/* {output_dir.escape_to_sh}/")
+               end
+
+               # Collect model to document
+               var mpackages = model.collect_mpackages(filter)
+               var mgroups = model.collect_mgroups(filter)
+               var nmodules = model.collect_mmodules(filter)
+               var mclasses = model.collect_mclasses(filter)
+               var mprops = model.collect_mproperties(filter)
+
+               var mentities = new Array[MEntity]
+               mentities.add_all mpackages
+               mentities.add_all mgroups
+               mentities.add_all nmodules
+               mentities.add_all mclasses
+               mentities.add_all mprops
+
+               var persons = doc.catalog.persons
+               var tags = doc.catalog.tag2proj.keys
+
+               # Prepare progress bar
+               var count = 0
+               var pages = 1 # count homepage
+               pages += mentities.length
+               pages += persons.length
+               pages += tags.length
+
+               print "Generating documentation pages..."
+               var progress = new TermProgress(pages, 0)
+               if not test_mode then progress.display
+
+               # Make pages
+               count += 1
+               if not test_mode then progress.update(count, "homepage")
+               if not no_render then doc.gen_page(new PageHome("Overview"), output_dir)
+
+               for mentity in mentities do
+                       count += 1
+                       if not test_mode then progress.update(count, "page {count}/{pages}")
+                       if not no_render then doc.gen_page(new PageMEntity(mentity), output_dir)
+               end
+               for name, person in persons do
+                       count += 1
+                       if not test_mode then progress.update(count, "page {count}/{pages}")
+                       if not no_render then doc.gen_page(new PagePerson(person), output_dir)
+               end
+               for tag in tags do
+                       count += 1
+                       if not test_mode then progress.update(count, "page {count}/{pages}")
+                       if not no_render then doc.gen_page(new PageTag(tag), output_dir)
+               end
+
+               if not test_mode then  print "" # finalise progress
+               if not no_render then
+                       doc.create_index_file("{output_dir}/quicksearch-list.js")
+                       print "Documentation produced in `{output_dir}`"
+               end
+
+               if test_mode then
+                       print "Generated {count}/{pages} pages"
+                       print " PageHome: 1"
+                       print " PageMPackage: {mpackages.length}"
+                       print " PageMGroup: {mgroups.length}"
+                       print " PageMModule: {nmodules.length}"
+                       print " PageMClass: {mclasses.length}"
+                       print " PageMProperty: {mprops.length}"
+                       print " PagePerson: {persons.length}"
+                       print " PageTag: {tags.length}"
+               end
+       end
+end
+
+redef class Catalog
+
+       # Build the catalog from `mpackages`
+       fun build_catalog(mpackages: Array[MPackage]) do
+               # Compute the poset
+               for p in mpackages do
+                       var g = p.root
+                       assert g != null
+                       modelbuilder.scan_group(g)
+
+                       deps.add_node(p)
+                       for gg in p.mgroups do for m in gg.mmodules do
+                               for im in m.in_importation.direct_greaters do
+                                       var ip = im.mpackage
+                                       if ip == null or ip == p then continue
+                                       deps.add_edge(p, ip)
+                               end
+                       end
+               end
+               # Build the catalog
+               for mpackage in mpackages do
+                       package_page(mpackage)
+                       git_info(mpackage)
+                       mpackage_stats(mpackage)
                end
        end
 end
@@ -91,5 +270,6 @@ var mmodules = mbuilder.parse_full(arguments)
 
 # process
 if mmodules.is_empty then return
+print "Parsing code..."
 mbuilder.run_phases
 toolcontext.run_global_phases(mmodules)