diff --git a/frontend/assets/github.png b/frontend/assets/github.png
new file mode 100644
index 000000000..c61ab9d05
Binary files /dev/null and b/frontend/assets/github.png differ
diff --git a/frontend/assets/moz-fav-bw-rgb.png b/frontend/assets/moz-fav-bw-rgb.png
new file mode 100644
index 000000000..b0521009c
Binary files /dev/null and b/frontend/assets/moz-fav-bw-rgb.png differ
diff --git a/frontend/assets/moz-logo-black.png b/frontend/assets/moz-logo-black.png
new file mode 100644
index 000000000..81cf0eef6
Binary files /dev/null and b/frontend/assets/moz-logo-black.png differ
diff --git a/frontend/package.json b/frontend/package.json
index ddd531ac6..c1fc6fd09 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -36,13 +36,16 @@
"eslint-plugin-mozilla": "^2.1.0",
"eslint-plugin-no-unsanitized": "^3.0.2",
"eslint-plugin-prettier": "^3.1.0",
+ "file-loader": "^4.2.0",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
+ "node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"prettier": "1.18.2",
+ "sass-loader": "^8.0.0",
"standard": "^14.1.0",
"terser-webpack-plugin": "^2.0.1",
- "webpack": "^4.35.3",
+ "webpack": "^4.40.2",
"webpack-cli": "^3.3.6",
"webpack-dev-server": "^3.7.2",
"webpack-merge": "^4.2.1"
@@ -50,6 +53,7 @@
"dependencies": {
"chartist": "^0.11.3",
"mustache": "^3.0.1",
+ "normalize.css": "^8.0.1",
"prismjs": "^1.16.0"
}
}
diff --git a/frontend/src/base.html b/frontend/src/base.html
index 980e97508..4bc6db6e0 100755
--- a/frontend/src/base.html
+++ b/frontend/src/base.html
@@ -3,10 +3,11 @@
mozilla-central coverage
+
-
-
+
Loading...
@@ -146,9 +157,12 @@
diff --git a/frontend/src/common.js b/frontend/src/common.js
index 152c56284..7e514c3f2 100644
--- a/frontend/src/common.js
+++ b/frontend/src/common.js
@@ -364,7 +364,7 @@ export function message(cssClass, message) {
const box = document.getElementById("message");
box.className = "message " + cssClass;
box.textContent = message;
- box.style.display = "block";
+ box.style.display = "inherit";
}
export function hide(id) {
@@ -382,7 +382,7 @@ export function show(id, node) {
}
const box = document.getElementById(id);
- box.style.display = "block";
+ box.style.display = "inherit";
if (node) {
box.replaceWith(node);
}
@@ -400,6 +400,6 @@ export function render(template, data, target) {
// eslint-disable-next-line no-unsanitized/property
box.innerHTML = output;
- box.style.display = "block";
+ box.style.display = "inherit";
return box;
}
diff --git a/frontend/src/index.js b/frontend/src/index.js
index 4ef25afef..d31172837 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -18,7 +18,8 @@ import {
zeroCoverageDisplay,
zeroCoverageMenu
} from "./zero_coverage_report.js";
-import "./style.css";
+import "normalize.css/normalize.css";
+import "./style.scss";
import Prism from "prismjs";
import Chartist from "chartist";
import "chartist/dist/chartist.css";
@@ -112,6 +113,10 @@ async function showDirectory(dir, revision, files) {
file.route = buildRoute({
path: file.path
});
+
+ // Calc decimal range to make a nice coloration
+ file.coveragePercent = Math.floor(file.coveragePercent);
+ file.range = parseInt(file.coveragePercent / 10) * 10;
return file;
}),
revision: revision || REV_LATEST,
@@ -120,7 +125,7 @@ async function showDirectory(dir, revision, files) {
return dir ? this.path.substring(dir.length + 1) : this.path;
}
};
- render("browser", context, "output");
+ render("file_browser", context, "output");
}
async function showFile(file, revision) {
@@ -148,7 +153,7 @@ async function showFile(file, revision) {
lines: source.split("\n").map((line, nb) => {
const coverage = file.coverage[nb];
let cssClass = "";
- if (coverage !== -1) {
+ if (coverage && coverage !== -1) {
cssClass = coverage > 0 ? "covered" : "uncovered";
}
return {
diff --git a/frontend/src/style.css b/frontend/src/style.css
deleted file mode 100644
index cf8e9c454..000000000
--- a/frontend/src/style.css
+++ /dev/null
@@ -1,200 +0,0 @@
-body {
- font-family: sans-serif;
- background-color:#eff7fc;
- color: #262626;
- line-height: 1.3em;
- margin: 1em 0;
- text-align: center;
-}
-
-a {
- text-decoration: none;
- color: #0081ad;
-}
-
-a:hover {
- color: #00a7e0;
-}
-label {
- padding-right: 2em;
-}
-
-header #browser input {
- min-width: 350px;
- font-family: monospace;
-}
-
-#main {
- background-color: white;
- border-top: 1px solid darkgray;
- border-bottom: 1px solid darkgray;
- margin: auto;
- text-align: left;
-}
-
-#main div.message {
- padding: 10px;
- color: white;
- width: 40%;
- margin: 30px auto;
-}
-
-#main div.message.loading {
- border: 1px solid blue;
- background: #209cee;
-}
-
-#main div.message.warning {
- border: 1px solid orange;
- background: #c48404;
-}
-
-#main div.message.error {
- border: 1px solid red;
- background: #ff3860;
-}
-
-/* Directory navigation */
-#output.directory, #output > .directory {
- padding: 1em 20%;
-}
-
-#output .table {
- display: table;
- width: 100%;
-}
-
-#output .table div {
- display: table-row;
- height: 1.5em;
-}
-
-#output .table div > :first-child {
- text-align: left;
-}
-
-#output .table div > :last-child {
- text-align: right;
-}
-
-#output .table span {
- text-align: center;
- height: 1.5em;
-}
-
-#output .table .row span, #output .table .header span {
- display: table-cell;
-}
-
-#output .table .row:nth-child(2n+3) {
- background: AliceBlue;
-}
-
-#output .table .row:hover {
- background-color: #d8dfe5;
-}
-
-#output h2 {
- width: 100%;
- display: block;
- font-size: 1.3em;
-}
-
-#output h2 * {
- display: inline-block;
- margin-right: 3px;
-}
-
-/* File coverage */
-#output > .file, #output > .file table {
- width: 100%;
-}
-
-#output > .file nav {
- margin: 5px;
-}
-
-#output .filename {
- text-align: left;
-}
-
-#output .header {
- font-weight: bold;
-}
-
-
-#output .file table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-#output tr * {
- padding: 0;
- margin: 0;
-}
-
-#output tr pre {
- padding: 0 2px;
-}
-
-#output tr td:first-child {
- color: grey;
- font-size: 1em;
- vertical-align: middle;
- border-right: 1px solid #CCC;
- font-family: monospace;
- background: #f5f2f0;
- padding: 0 2px;
-}
-
-#output tr.covered td {
- background: #c3fca2;
-}
-
-#output tr.covered pre {
- background: #e7ffd9;
-}
-
-#output tr.uncovered td {
- background: #ff8870;
-}
-
-#output tr.uncovered pre {
- background: #ffc8bd;
-}
-
-/* Breadcrumb navigation */
-nav {
- margin-right: 5px;
-}
-
-nav a:not(:last-child)::after {
- content: "/";
- color: #CCC;
- margin: 0 2px;
-}
-
-/* History graph */
-#history, #history svg {
- width: 100%;
- height: 35%;
-}
-
-#history .ct-point {
- stroke: #6fc0f2;
- cursor: pointer;
-}
-
-#history .ct-line {
- stroke: #ccf2ff;
-}
-
-#history .ct-point:hover {
- stroke: #d91e44;
-}
-
-#history #history_details {
- color: darkgrey;
- margin-right: 20px;
- float: right;
-}
diff --git a/frontend/src/style.scss b/frontend/src/style.scss
new file mode 100644
index 000000000..b14f0ec56
--- /dev/null
+++ b/frontend/src/style.scss
@@ -0,0 +1,360 @@
+// Configuration
+$default_color: #4a4a4a;
+$link_color: #0081ad;
+$background_color: #eff7fc;
+$row_height: 1.8em;
+$header_height: 50px;
+$footer_height: 60px;
+$coverage_low: #d91a47;
+$coverage_warn: #ff9a36;
+$coverage_good: #438718;
+$small_screen: 1900px;
+
+body {
+ // Setup base typography
+ color: $default_color;
+ font-size: 1em;
+ font-weight: 400;
+ line-height: 1.5;
+ text-rendering: optimizeLegibility;
+ font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+
+ background-color: white;
+
+ // For footer
+ display: flex;
+ min-height: 100vh;
+ flex-direction: column;
+}
+
+a {
+ text-decoration: none;
+ color: $link_color;
+
+ &:hover {
+ color: lighten($link_color, 10%);
+ }
+}
+
+header {
+ background-color: $background_color;
+ border-bottom: 1px solid darkgray;
+ min-height: $header_height;
+
+ div.logo {
+ display: inline-block;
+ img {
+ margin: $header_height * 0.1;
+ max-height: $header_height * 0.8;
+ }
+ a {
+ color: $default_color;
+ line-height: $header_height;
+ font-size: $header_height * 0.6;
+ vertical-align: top;
+ }
+
+ // On smaller screens, hide "Code coverage" link & display a smaller logo
+ @media only screen and (max-width: $small_screen) {
+ img {
+ max-height: $header_height * 0.6;
+ }
+ a {
+ display: none;
+ }
+ }
+ }
+
+ div#menu {
+ float: right;
+ height: $header_height;
+ line-height: $header_height;
+ margin-right: 10px;
+ }
+
+ input.revision {
+ width: 170px;
+ font-family: monospace;
+ }
+}
+
+footer {
+ text-align: center;
+ background: darken($background_color, 60%);
+ min-height: $footer_height;
+ line-height: $footer_height;
+ border-top: 1px solid darkgray;
+
+ img {
+ //padding-top: 0.2 * $footer_height;
+ vertical-align: middle;
+ max-height: 0.75 * $footer_height;
+ }
+
+ a {
+ color: lighten($link_color, 50%);
+ }
+}
+
+#main {
+ // Main element on flex display
+ flex: 1;
+
+ div.message {
+ border-radius: 5px;
+ padding: 10px;
+ color: white;
+ width: 40%;
+ margin: 30px auto;
+
+ &.loading {
+ background: #209cee;
+ }
+
+ &.warning {
+ background: #c48404;
+ }
+
+ &.error {
+ background: #ff3860;
+ }
+ }
+}
+
+// Breadcrumb navigation
+nav {
+ margin-right: 5px;
+
+ a:not(:last-child)::after {
+ content: "/";
+ color: #CCC;
+ margin: 0 2px;
+ }
+}
+
+// Directory navigation
+#browser {
+ margin: 1em 20%;
+
+ // On smaller screens, display table on full width
+ @media only screen and (max-width: $small_screen) {
+ margin: 0.5em;
+ }
+
+ .table {
+ display: table;
+ width: 100%;
+
+ div {
+ display: table-row;
+ height: $row_height;
+ line-height: $row_height;
+
+ > {
+ :first-child {
+ text-align: left;
+ }
+
+ :last-child {
+ text-align: right;
+ }
+ }
+
+ &.header {
+ span {
+ font-weight: bold;
+ }
+ }
+
+ span {
+ padding: 0 3px;
+ text-align: center;
+ height: $row_height;
+ line-height: $row_height;
+ display: table-cell;
+
+ &.coverage_0 {
+ color: $coverage_low;
+ }
+ &.coverage_10 {
+ color: lighten($coverage_low, 10%);
+ }
+ &.coverage_20 {
+ color: lighten($coverage_low, 20%);
+ }
+ &.coverage_30 {
+ color: lighten($coverage_low, 30%);
+ }
+ &.coverage_40 {
+ color: darken($coverage_warn, 10%);
+ }
+ &.coverage_50 {
+ color: $coverage_warn;
+ }
+ &.coverage_60 {
+ color: lighten($coverage_warn, 10%);
+ }
+ &.coverage_70 {
+ color: lighten($coverage_good, 30%);
+ }
+ &.coverage_80 {
+ color: lighten($coverage_good, 20%);
+ }
+ &.coverage_90 {
+ color: lighten($coverage_good, 10%);
+ }
+ &.coverage_100 {
+ color: $coverage_good;
+ }
+ }
+
+ &.row {
+ &:nth-child(2n+3) {
+ background: hsl(0, 0%, 98%);
+ }
+
+ &:hover {
+ background-color: hsl(0, 0%, 96%);
+ }
+ }
+ }
+ }
+
+ // Navbar with stats
+ h2 {
+ width: 100%;
+
+ nav, span {
+ display: inline-block;
+ margin-right: 3px;
+ }
+ }
+}
+
+// File coverage
+$covered_color: #e7ffd9;
+$uncovered_color: #ffc8bd;
+$no_data_color: hsl(0, 0%, 98%);
+$samp_size: 20px;
+#file {
+ div.help {
+ position: fixed;
+ top: 70px;
+ right: 20px;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 5px;
+ height: 2 * $samp_size;
+ line-height: 2 * $samp_size;
+
+ p {
+ display: inline-block;
+ margin: 0 6px;
+ padding: 0;
+
+ span {
+ margin-left: 2px;
+ vertical-align: top;
+ }
+
+ samp {
+ display: inline-block;
+ margin-top: $samp_size / 2;
+ width: $samp_size;
+ height: $samp_size;
+ border: 1px solid darkgray;
+ }
+
+ &.no_data samp {
+ background: $no_data_color;
+ }
+ &.uncovered samp {
+ background: $uncovered_color;
+ }
+ &.covered samp {
+ background: $covered_color;
+ }
+ }
+ }
+
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+
+ tr {
+ * {
+ padding: 0;
+ margin: 0;
+ }
+
+ td {
+ font-size: 0.9em;
+ }
+
+ pre {
+ padding: 1px 2px;
+
+ // To override prism settings
+ border-radius: 0px 0px;
+ background: $no_data_color;
+ }
+
+ td:first-child {
+ color: grey;
+ font-size: 1em;
+ vertical-align: middle;
+ border-right: 1px solid #CCC;
+ font-family: monospace;
+ background: #f5f2f0;
+ padding: 0 2px;
+ }
+
+ &.covered {
+ td {
+ background: darken($covered_color, 10%);
+ }
+
+ pre {
+ background: $covered_color;
+ }
+ }
+
+ &.uncovered {
+ td {
+ background: darken($uncovered_color, 10%);
+ }
+
+ pre {
+ background: $uncovered_color;
+ }
+ }
+ }
+ }
+}
+
+// History graph
+#history {
+ .ct-chart {
+ width: 100%;
+ height: 200px;
+ }
+
+ .ct-point {
+ stroke: #6fc0f2;
+ cursor: pointer;
+ }
+
+ .ct-line {
+ stroke: #ccf2ff;
+ }
+
+ .ct-point:hover {
+ stroke: #d91e44;
+ }
+
+ #history_details {
+ color: darkgrey;
+ margin-right: 20px;
+ float: right;
+ }
+}
diff --git a/frontend/webpack.common.js b/frontend/webpack.common.js
index c48db7b7b..fbd69591c 100644
--- a/frontend/webpack.common.js
+++ b/frontend/webpack.common.js
@@ -41,10 +41,24 @@ module.exports = {
}
}
},
+ {
+ test: /\.s[ac]ss$/i,
+ use: [
+ MiniCssExtractPlugin.loader,
+ 'css-loader',
+ 'sass-loader',
+ ],
+ },
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
+ {
+ test: /\.(png|svg|jpg|gif)$/,
+ use: [
+ 'file-loader'
+ ]
+ },
],
},
devServer: {
@@ -55,6 +69,7 @@ module.exports = {
resolve: {
modules: [
path.join(__dirname, 'node_modules'),
+ path.join(__dirname, 'assets'),
path.join(__dirname, 'src'),
],
},