Browse Source

Merge branch 'feature-sass'

n1474335 8 years ago
parent
commit
77e47e3fa4
36 changed files with 1505 additions and 569 deletions
  1. 1 1
      .travis.yml
  2. 12 4
      Gruntfile.js
  3. 6 2
      package.json
  4. 15 0
      postcss.config.js
  5. 0 2
      src/core/config/OperationConfig.js
  6. 17 0
      src/web/App.js
  7. 2 2
      src/web/ControlsWaiter.js
  8. 1 0
      src/web/Manager.js
  9. 10 0
      src/web/OptionsWaiter.js
  10. 0 18
      src/web/css/index.js
  11. 0 356
      src/web/css/structure/layout.css
  12. 0 113
      src/web/css/structure/overrides.css
  13. 0 37
      src/web/css/structure/utils.css
  14. 0 23
      src/web/css/themes/classic.css
  15. 29 8
      src/web/html/index.html
  16. 3 2
      src/web/index.js
  17. 22 0
      src/web/stylesheets/components/_alert.css
  18. 13 0
      src/web/stylesheets/components/_button.css
  19. 43 0
      src/web/stylesheets/components/_list.css
  20. 196 0
      src/web/stylesheets/components/_operation.css
  21. 30 0
      src/web/stylesheets/components/_pane.css
  22. 34 0
      src/web/stylesheets/index.css
  23. 18 0
      src/web/stylesheets/index.js
  24. 28 0
      src/web/stylesheets/layout/_banner.css
  25. 65 0
      src/web/stylesheets/layout/_controls.css
  26. 109 0
      src/web/stylesheets/layout/_io.css
  27. 80 0
      src/web/stylesheets/layout/_modals.css
  28. 32 0
      src/web/stylesheets/layout/_operations.css
  29. 18 0
      src/web/stylesheets/layout/_recipe.css
  30. 58 0
      src/web/stylesheets/layout/_structure.css
  31. 135 0
      src/web/stylesheets/preloader.css
  32. 116 0
      src/web/stylesheets/themes/_classic.css
  33. 115 0
      src/web/stylesheets/themes/_dark.css
  34. 73 0
      src/web/stylesheets/utils/_general.css
  35. 223 0
      src/web/stylesheets/utils/_overrides.css
  36. 1 1
      src/web/stylesheets/vendors/bootstrap.less

+ 1 - 1
.travis.yml

@@ -9,7 +9,7 @@ script:
   - grunt test
   - grunt docs
   - grunt node
-  - grunt prod
+  - grunt prod --msg="$COMPILE_MSG"
 before_deploy:
   - grunt copy:ghPages
 deploy:

+ 12 - 4
Gruntfile.js

@@ -54,7 +54,7 @@ module.exports = function (grunt) {
 
 
     // Project configuration
-    const compileTime = grunt.template.today("dd/mm/yyyy HH:MM:ss") + " UTC",
+    const compileTime = grunt.template.today("UTC:dd/mm/yyyy HH:MM:ss") + " UTC",
         banner = "/**\n" +
             "* CyberChef - The Cyber Swiss Army Knife\n" +
             "*\n" +
@@ -74,7 +74,8 @@ module.exports = function (grunt) {
             "* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
             "* See the License for the specific language governing permissions and\n" +
             "* limitations under the License.\n" +
-            "*/\n";
+            "*/\n",
+        pkg = grunt.file.readJSON("package.json");
 
     /**
      * Compiles a production build of CyberChef into a single, portable web page.
@@ -182,7 +183,10 @@ module.exports = function (grunt) {
                         {
                             test: /\.css$/,
                             use: ExtractTextPlugin.extract({
-                                use: "css-loader?minimize"
+                                use: [
+                                    { loader: "css-loader?minimize" },
+                                    { loader: "postcss-loader" },
+                                ]
                             })
                         },
                         {
@@ -190,6 +194,7 @@ module.exports = function (grunt) {
                             use: ExtractTextPlugin.extract({
                                 use: [
                                     { loader: "css-loader?minimize" },
+                                    { loader: "postcss-loader" },
                                     { loader: "less-loader" }
                                 ]
                             })
@@ -235,7 +240,8 @@ module.exports = function (grunt) {
                     new HtmlWebpackPlugin({
                         filename: "index.html",
                         template: "./src/web/html/index.html",
-                        compileTime: compileTime
+                        compileTime: compileTime,
+                        version: pkg.version,
                     })
                 ],
                 watch: true
@@ -261,6 +267,7 @@ module.exports = function (grunt) {
                         filename: "index.html",
                         template: "./src/web/html/index.html",
                         compileTime: compileTime,
+                        version: pkg.version,
                         minify: {
                             removeComments: true,
                             collapseWhitespace: true,
@@ -272,6 +279,7 @@ module.exports = function (grunt) {
                         filename: "cyberchef.htm",
                         template: "./src/web/html/index.html",
                         compileTime: compileTime,
+                        version: pkg.version,
                         inline: true,
                         minify: {
                             removeComments: true,

+ 6 - 2
package.json

@@ -34,6 +34,7 @@
     "babel-loader": "^6.4.0",
     "babel-polyfill": "^6.23.0",
     "babel-preset-env": "^1.2.2",
+    "bootstrap": "^3.3.7",
     "css-loader": "^0.27.3",
     "exports-loader": "^0.6.4",
     "extract-text-webpack-plugin": "^2.1.0",
@@ -53,15 +54,18 @@
     "ink-docstrap": "^1.1.4",
     "jsdoc-babel": "^0.3.0",
     "less": "^2.7.2",
-    "less-loader": "^4.0.2",
+    "less-loader": "^4.0.3",
+    "postcss-css-variables": "^0.7.0",
+    "postcss-import": "^10.0.0",
+    "postcss-loader": "^2.0.5",
     "style-loader": "^0.15.0",
     "url-loader": "^0.5.8",
     "web-resource-inliner": "^4.1.0",
     "webpack": "^2.2.1"
   },
   "dependencies": {
-    "bootstrap": "^3.3.7",
     "bootstrap-colorpicker": "^2.5.1",
+    "bootstrap-sass": "^3.3.7",
     "bootstrap-switch": "^3.3.4",
     "crypto-api": "^0.6.2",
     "crypto-js": "^3.1.9-1",

+ 15 - 0
postcss.config.js

@@ -0,0 +1,15 @@
+module.exports = {
+    plugins: [
+        require("postcss-import"),
+        require("autoprefixer")({
+            browsers: [
+                "Chrome >= 40",
+                "Firefox >= 35",
+                "Edge >= 14"
+            ]
+        }),
+        require("postcss-css-variables")({
+            preserve: true
+        }),
+    ]
+};

+ 0 - 2
src/core/config/OperationConfig.js

@@ -922,7 +922,6 @@ const OperationConfig = {
                 type: "toggleString",
                 value: "",
                 toggleValues: Cipher.IO_FORMAT1
-
             },
             {
                 name: "Salt",
@@ -969,7 +968,6 @@ const OperationConfig = {
                 type: "toggleString",
                 value: "",
                 toggleValues: Cipher.IO_FORMAT1
-
             },
             {
                 name: "Salt",

+ 17 - 0
src/web/App.js

@@ -53,6 +53,23 @@ App.prototype.setup = function() {
     this.resetLayout();
     this.setCompileMessage();
     this.loadURIParams();
+    this.loaded();
+};
+
+
+/**
+ * Fires once all setup activities have completed.
+ */
+App.prototype.loaded = function() {
+    // Trigger CSS animations to remove preloader
+    document.body.classList.add("loaded");
+
+    // Wait for animations to complete then remove the preloader and loaded style
+    // so that the animations for existing elements don't play again.
+    setTimeout(function() {
+        document.getElementById("loader-wrapper").remove();
+        document.body.classList.remove("loaded");
+    }, 1000);
 };
 
 

+ 2 - 2
src/web/ControlsWaiter.js

@@ -106,11 +106,11 @@ ControlsWaiter.prototype.autoBakeChange = function() {
     this.app.autoBake_ = autoBakeCheckbox.checked;
 
     if (autoBakeCheckbox.checked) {
-        autoBakeLabel.classList.remove("btn-default");
         autoBakeLabel.classList.add("btn-success");
+        autoBakeLabel.classList.remove("btn-default");
     } else {
-        autoBakeLabel.classList.remove("btn-success");
         autoBakeLabel.classList.add("btn-default");
+        autoBakeLabel.classList.remove("btn-success");
     }
 };
 

+ 1 - 0
src/web/Manager.js

@@ -154,6 +154,7 @@ Manager.prototype.initialiseEventListeners = function() {
     this.addDynamicListener(".option-item input[type=number]", "keyup", this.options.numberChange, this.options);
     this.addDynamicListener(".option-item input[type=number]", "change", this.options.numberChange, this.options);
     this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
+    document.getElementById("theme").addEventListener("change", this.options.themeChange.bind(this.options));
 
     // Misc
     document.getElementById("alert-close").addEventListener("click", this.app.alertCloseClick.bind(this.app));

+ 10 - 0
src/web/OptionsWaiter.js

@@ -132,4 +132,14 @@ OptionsWaiter.prototype.setWordWrap = function() {
     }
 };
 
+
+/**
+ * Changes the theme by setting the class of the <html> element.
+ */
+OptionsWaiter.prototype.themeChange = function (e) {
+    const themeClass = e.target.value;
+
+    document.querySelector(":root").className = themeClass;
+};
+
 export default OptionsWaiter;

+ 0 - 18
src/web/css/index.js

@@ -1,18 +0,0 @@
-/**
- * CSS index
- *
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2017
- * @license Apache-2.0
- */
-
-import "google-code-prettify/src/prettify.css";
-
-import "./lib/bootstrap.less";
-import "bootstrap-switch/src/less/bootstrap3/build.less";
-import "bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css";
-
-import "./structure/overrides.css";
-import "./structure/layout.css";
-import "./structure/utils.css";
-import "./themes/classic.css";

File diff suppressed because it is too large
+ 0 - 356
src/web/css/structure/layout.css


+ 0 - 113
src/web/css/structure/overrides.css

@@ -1,113 +0,0 @@
-/* Bootstrap */
-
-button,
-a:focus {
-    outline: none;
-    -moz-outline-style: none;
-}
-
-.btn-default {
-    border-color: #ddd;
-}
-
-.btn-default:focus {
-    background-color: #fff;
-    border-color: #adadad;
-}
-
-.btn-default:hover,
-.btn-default:active {
-    background-color: #ebebeb;
-    border-color: #adadad;
-}
-
-.btn,
-.btn-lg,
-.nav-tabs>li>a,
-.form-control,
-.popover,
-.alert,
-.modal-content,
-.tooltip-inner,
-.dropdown-menu {
-    border-radius: 0 !important;
-}
-
-input[type="search"] {
-    -webkit-appearance: searchfield;
-    box-shadow: none;
-}
-
-input[type="search"]::-webkit-search-cancel-button {
-    -webkit-appearance: searchfield-cancel-button;
-}
-
-.modal {
-    overflow-y: auto;
-}
-
-.form-control {
-    background-color: transparent;
-}
-
-code {
-    border: 0;
-    white-space: pre-wrap;
-    font-family: Consolas, monospace;
-}
-
-pre {
-    border-radius: 0 !important;
-}
-
-blockquote {
-    font-size: inherit;
-}
-
-blockquote a {
-    cursor: pointer;
-}
-
-optgroup {
-    font-weight: bold;
-}
-
-.panel-body:before,
-.panel-body:after {
-    content: "";
-}
-
-.table-nonfluid {
-    width: auto !important;
-}
-
-
-/* Bootstrap-switch */
-
-.bootstrap-switch,
-.bootstrap-switch-container,
-.bootstrap-switch-handle-on,
-.bootstrap-switch-handle-off,
-.bootstrap-switch-label {
-    border-radius: 0 !important;
-}
-
-
-/* Sortable */
-
-.sortable-ghost {
-    opacity: 0.6;
-}
-
-
-/* Bootstrap Colorpicker */
-
-.colorpicker-element {
-    float: left;
-    margin-right: 15px;
-}
-
-.colorpicker-color,
-.colorpicker-color div {
-    height: 100px;
-}

+ 0 - 37
src/web/css/structure/utils.css

@@ -1,37 +0,0 @@
-.word-wrap {
-    white-space: pre !important;
-    word-wrap: normal !important;
-    overflow-x: scroll !important;
-}
-
-.clearfix {
-    clear: both;
-    height: 0;
-}
-
-.blur {
-    color: transparent !important;
-    text-shadow: rgba(0, 0, 0, 0.95) 0 0 10px !important;
-}
-
-.no-select { 
-    -webkit-touch-callout: none;
-    -webkit-user-select: none;
-    -khtml-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-}
-
-.konami {
-    -ms-transform: rotate(180deg);
-    -webkit-transform: rotate(180deg);
-    transform: rotate(180deg);
-    -moz-transform: rotate(180deg);
-}
-
-.hl1, .hlyellow { background-color: #fff000; }
-.hl2, .hlblue   { background-color: #95dfff; }
-.hl3, .hlred    { background-color: #ffb6b6; } /* Half-Life 3 confirmed :O */
-.hl4, .hlorange { background-color: #fcf8e3; }
-.hl5, .hlgreen  { background-color: #8de768; }

File diff suppressed because it is too large
+ 0 - 23
src/web/css/themes/classic.css


+ 29 - 8
src/web/html/index.html

@@ -20,7 +20,7 @@
 -->
 <!-- htmlmin:ignore -->
 <!DOCTYPE html>
-<html lang="en">
+<html lang="en" class="classic">
     <head>
         <meta charset="UTF-8">
         <title>CyberChef</title>
@@ -30,15 +30,25 @@
         <meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip,  md5, sha1, aes, des, blowfish, xor" />
 
         <link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
+
+        <script type="application/javascript">
+            // Load theme before the preloader is shown
+            document.querySelector(":root").className = JSON.parse(localStorage.getItem("options")).theme;
+        </script>
     </head>
     <body>
+        <!-- Preloader overlay -->
+        <div id="loader-wrapper">
+            <div id="preloader"></div>
+        </div>
+        <!-- End preloader overlay -->
         <span id="edit-favourites" class="btn btn-default btn-sm"><img aria-hidden="true" src="<%- require('../static/images/favourite-16x16.png') %>" alt="Star Icon"/> Edit</span>
         <div id="alert" class="alert alert-danger">
             <button type="button" class="close" id="alert-close">&times;</button>
             <span id="alert-content"></span>
         </div>
         <div id="content-wrapper">
-            <div id="banner" class="green">
+            <div id="banner">
                 <% if (htmlWebpackPlugin.options.inline) { %>
                     <span style="float: left; margin-left: 10px;">Compile time: <%= htmlWebpackPlugin.options.compileTime %></span>
                 <% } else { %>
@@ -57,17 +67,17 @@
                 <a href="#" id="support" class="banner-right" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a>
                 <a href="#" id="options" class="banner-right">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a>
             </div>
-            <div id="wrapper">
+            <div id="workspace-wrapper">
                 <div id="operations" class="split split-horizontal no-select">
                     <div class="title no-select">Operations</div>
-                    <input type="search" class="form-control" id="search" placeholder="Search..." autocomplete="off">
-                    <ul class="op-list" id="search-results"></ul>
-                    <div class="panel-group no-select" id="categories"></div>
+                    <input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off">
+                    <ul id="search-results" class="op-list"></ul>
+                    <div id="categories" class="panel-group no-select"></div>
                 </div>
                 
                 <div id="recipe" class="split split-horizontal no-select">
                     <div class="title no-select">Recipe</div>
-                    <ul id="rec-list" class="no-select"></ul>
+                    <ul id="rec-list" class="list-area no-select"></ul>
                     
                     <div id="controls" class="no-select">
                         <div id="operational-controls">
@@ -165,6 +175,7 @@
                                 <input type="checkbox" id="save-link-recipe-checkbox" checked> <label for="save-link-recipe-checkbox"> Include recipe </label>
                                 <input type="checkbox" id="save-link-input-checkbox" checked> <label for="save-link-input-checkbox"> Include input </label>
                             </div>
+                            <br>
                             <a id="save-link" style="word-wrap: break-word;"></a>
                         </div>
                     </div>
@@ -207,6 +218,13 @@
                     </div>
                     <div class="modal-body" id="options-body">
                         <p style="font-weight: bold">Please note that these options will persist between sessions.</p>
+                        <div class="option-item">
+                            <select option="theme" id="theme">
+                                <option value="classic">Classic</option>
+                                <option value="dark">Dark</option>
+                            </select>
+                            <label for="theme"> Theme (only supported in modern browsers)</label>
+                        </div>
                         <div class="option-item">
                             <input type="checkbox" option="update_url" id="update_url" checked />
                             <label for="update_url"> Update the URL when the input or recipe changes </label>
@@ -280,7 +298,10 @@
                     </div>
                     <div class="modal-body">
                         <img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png') %>" alt="CyberChef Logo"/>
-                        <p class="subtext">Compile time: <%= htmlWebpackPlugin.options.compileTime %></p>
+                        <p class="subtext">
+                            Version <%=  htmlWebpackPlugin.options.version %><br>
+                            Compile time: <%= htmlWebpackPlugin.options.compileTime %>
+                        </p>
                         <p>&copy Crown Copyright 2016.</p>
                         <p>Licenced under the Apache Licence, Version 2.0.</p>
                         <br>

+ 3 - 2
src/web/index.js

@@ -4,8 +4,8 @@
  * @license Apache-2.0
  */
 
-// CSS
-import "./css/index.js";
+// Styles
+import "./stylesheets/index.js";
 
 // Libs
 import "babel-polyfill";
@@ -46,6 +46,7 @@ function main() {
         errorTimeout      : 4000,
         autoBakeThreshold : 200,
         attemptHighlight  : true,
+        theme             : "classic",
     };
 
     document.removeEventListener("DOMContentLoaded", main, false);

+ 22 - 0
src/web/stylesheets/components/_alert.css

@@ -0,0 +1,22 @@
+/**
+ * Alert styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+#alert {
+    position: fixed;
+    width: 30%;
+    margin: 30px auto;
+    top: 10px;
+    left: 0;
+    right: 0;
+    z-index: 2000;
+    display: none;
+}
+
+#alert a {
+    text-decoration: underline;
+}

+ 13 - 0
src/web/stylesheets/components/_button.css

@@ -0,0 +1,13 @@
+/**
+ * Button styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+button img,
+span.btn img {
+    margin-right: 3px;
+    margin-bottom: 1px;
+}

+ 43 - 0
src/web/stylesheets/components/_list.css

@@ -0,0 +1,43 @@
+/**
+ * Operation list styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+.op-list {
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+}
+
+.category-title {
+    display: block;
+    padding: 10px;
+    background-color: var(--secondary-background-colour);
+    border-bottom: 1px solid var(--secondary-border-colour);
+    font-weight: var(--title-weight);
+}
+
+.category-title[href='#catFavourites'] {
+    border-bottom-color: var(--primary-border-colour);
+}
+
+.category-title[aria-expanded=true] {
+    border-bottom-color: var(--primary-border-colour);
+}
+
+.category-title.collapsed {
+    border-bottom-color: var(--secondary-border-colour);
+}
+
+.category-title:hover {
+    color: var(--op-list-operation-font-colour);
+}
+
+.category {
+    margin: 0 !important;
+    border-radius: 0 !important;
+    border: none;
+}

+ 196 - 0
src/web/stylesheets/components/_operation.css

@@ -0,0 +1,196 @@
+/**
+ * Operation styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+.operation {
+    cursor: pointer;
+    padding: 10px;
+    list-style-type: none;
+    position: relative;
+    border-width: 1px;
+    border-style: solid;
+    border-top: none;
+    border-left: none;
+    border-right: none;
+}
+
+.arg-group {
+    display: table;
+    width: 100%;
+    margin-top: 10px;
+}
+
+.arg-group-text {
+    display: block;
+}
+
+.inline-args {
+    float: left;
+    width: auto;
+    margin-right: 30px;
+    height: 34px;
+}
+
+.inline-args input[type="checkbox"] {
+    margin-top: 10px;
+}
+
+.inline-args input[type="number"] {
+    width: 100px;
+}
+
+.arg-title {
+    font-weight: var(--arg-title-font-weight);
+}
+
+.arg-input {
+    display: table-cell;
+    width: 100%;
+    padding: 6px 12px;
+    vertical-align: middle;
+    height: var(--arg-input-height);
+    font-size: var(--arg-input-font-size);
+    line-height: var(--arg-input-line-height);
+    color: var(--arg-font-colour);
+    background-color: var(--arg-background);
+    border: 1px solid var(--arg-border-colour);
+    font-family: var(--fixed-width-font-family);
+}
+
+.short-string {
+    width: 150px;
+}
+
+select {
+    display: block;
+    padding: 6px 8px;
+    height: 34px;
+    border: 1px solid var(--arg-border-colour);
+    background-color: var(--arg-background);
+    color: var(--arg-font-colour);
+}
+
+.arg[disabled] {
+    cursor: not-allowed;
+    opacity: 1;
+    background-color: var(--arg-disabled-background);
+}
+
+textarea.arg {
+    width: 100%;
+    min-height: 50px;
+    height: 70px;
+    margin-top: 5px;
+    border: 1px solid var(--arg-border-colour);
+    resize: vertical;
+    color: var(--arg-font-colour);
+    background-color: var(--arg-background);
+    font-family: var(--fixed-width-font-family);
+}
+
+.arg-label {
+    display: table-cell;
+    width: 1px;
+    padding-right: 10px;
+    font-weight: normal;
+    vertical-align: middle;
+    white-space: pre;
+}
+
+.editable-option {
+    position: relative;
+    display: inline-block;
+}
+
+.editable-option-select {
+    min-width: 250px;
+}
+
+.editable-option-input {
+    position: absolute;
+    top: 1px;
+    left: 1px;
+    width: calc(100% - 20px);
+    height: calc(100% - 2px) !important;
+    border: none !important;
+}
+
+button.dropdown-toggle {
+    background-color: var(--secondary-background-colour);
+}
+
+.op-icon {
+    float: right;
+    margin-left: 10px;
+    margin-top: 3px;
+}
+
+.recip-icons {
+    position: absolute;
+    top: 13px;
+    right: 10px;
+    height: 16px;
+}
+
+.recip-icon {
+    margin-right: 10px;
+    vertical-align: baseline;
+    float: right;
+}
+
+.disable-icon {
+    width: 16px;
+    height: 16px;
+    margin-top: -1px;
+    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAACfElEQVQ4y6WTPWgTYRjHf8nlfVvuoDVIP4Yuki4WHKoUqggFRUTsUEGkVG2hmCq6OnTwIxYHB+eijZOKdLNDW1pKKyGigh8dBHUJElxyBgx3vEnukvdyDrUhRXDxGR+e/+/583xEwjDkfyIGwNVTzURm4tYAMA6MAoN/0tvAMrA48uL+l2bx4w0iYRjSuHKC6OnTZLqHk8CcaZq9bW1tSCkBqNVq+L5PpVIpAHdGfr5LN9bXiT7Z2nGgteb1/qFkLBJZ6OjowHEc8vk8pVIJgHg8TldXF52dnb2u6y5s7R/iuF5JSyAKkLl4eyAMwznLsrBtm1wu99Z13amk+BFJih8R13WXANrb27EsizAM5zIXbw+wC9Baj0spe5VSFAqFt4ZhXJ6ufXuK55E5cDKVSCTGenp6yGazKKWQUvZqrcebgCAIRqWUOI6DEOLR1K8POapVMgfPpoC7u2LLspYcx0FKSRAEo60OBg3DwPd9Jr5vPqWvj8zh83vEwL2J75vnfN/HMAy01oPNNQZBQBAEO1OvVsl0D/8lTuZfpYDd7gRBQKuD7XK5jGmarB679PIv8deVFJUKq8cuTZqmSblcRmu93QpYVkohhMCyrLE94n2/UlSrbJy5kRBCXBNCoJRCa73cClh0XbfgeR6WZZHNZunv719KvnmeYnWVVxdmJ2Ox2DMhxFHP83Bdt6C1XgR2LvHzQDvvb84npZQL8Xgc0zSJRqN7br7RaFCpVCiVStRqtZmhh9fTh754TQdMr82nPc+bsW27UCwWUUpRr9ep1+sopSgWi9i2XfA8b2Z6bT6ttabp4GMi0uz0aXbhn890+MFM85mO5MIdwP/Eb1pMUCdctYRzAAAAAElFTkSuQmCC') no-repeat;
+}
+
+.disable-icon-selected {
+    background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACFUlEQVR4XqWTP0tbURjGn9zY3mjBwsUhBQtS6XKxiNypIGZJ6SKYUYdaKWg7OrrE3pYO+Qit3dpFuuQO6lI7Z4nESQdjlJbkJh0MksSb3Jvk9H0gjZFu9YWH83LO7zn/3nNCSincJobAeP1sEDBFi6J50UyPy4l2RNuioz756Ts0tt1OB4jH2a52Ne2HGh9PwrJm2EcxZx/HyPRYMDgB2u02/N3d1c7w8BZMM1ptNJBPp3GwsUExB/s4RoYsPf0JOkFgdoH34YkJ/D48xC/HyTTOzl5ayWSIktwxqlVo0SjIkKWnP0Hg+4swjGitVMJFNpu5o+svptfXv6DZBDIZezoWS3Db3A0ZsvRcH8H354dGR9EoFHA3EvlorqycwvOAXM4G8Pav+f7YmEOGLD1gsIzl54+V+vBK/Yw9ZAv1LQW1FrdFSnKVfQTK5liPUfRI9I8ArqiPjLAF9vcHVybyzlpasgcZeq7voNXKNSsV3DMMXB4fp/8xLyzYuLri2DIZsvQM3sFOzXURiUR4zsQNcyrFleFVKpNyP2/IkKVnsArbF65bbkqplJSJZrl5x5qbs7G3h3artSyV+arr+lMyZOnpP2Wp6ZFos3R+vvUgCGDNzgKalkA4rECIr07662J2i0X4nrfJJ33jJT6Zmvpcr9XWCicn5WI+j7rrAmKgmLOPY2TI0sPgb8TBZOi/PpN1qnDr7/wH3jxgB/FKIXkAAAAASUVORK5CYII=') no-repeat;
+}
+
+.breakpoint {
+    float: right;
+    width: 14px;
+    height: 14px;
+    background-color: #eee;
+    border: 1px solid #aaa;
+}
+
+.breakpoint-selected {
+    background: #eee url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAXVBMVEXIUkvzUVHzTEzzn5785eXrbW24BgbzWVnze3vzVVXzY2Pyion509PzbW3zXV1UMxj0l5f1srKbRTRgOxzJDg796ur74ODfIyP5zs6LLx3pNTXYGxuxdkVZNhn////sCC1eAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAABWSURBVBjTnc+7EoAgDERRTOQVxMEZFAf//z8FjAUFDbfb060QU2FwxngimxnCea3bjegSgz+0tguAfBgIy64QGfZQdg91dgAtqUZgnfz6IacYVWvu2AvR4wNAv0nxrAAAAABJRU5ErkJggg==') no-repeat -2px -2px;
+}
+
+.break {
+    color: var(--breakpoint-font-colour) !important;
+    background-color: var(--breakpoint-bg-colour) !important;
+    border-color: var(--breakpoint-border-colour) !important;
+}
+
+.selected-op {
+    color: var(--selected-operation-font-color) !important;
+    background-color: var(--selected-operation-bg-colour) !important;
+    border-color: var(--selected-operation-border-colour) !important;
+}
+
+.flow-control-op {
+    color: var(--fc-operation-font-colour) !important;
+    background-color: var(--fc-operation-bg-colour) !important;
+    border-color: var(--fc-operation-border-colour) !important;
+}
+
+.flow-control-op.break {
+    color: var(--fc-breakpoint-operation-font-colour) !important;
+    background-color: var(--fc-breakpoint-operation-bg-colour) !important;
+    border-color: var(--fc-breakpoint-operation-border-colour) !important;
+}
+
+.disabled {
+    color: var(--disabled-font-colour) !important;
+    background-color: var(--disabled-bg-colour) !important;
+    border-color: var(--disabled-border-colour) !important;
+}

+ 30 - 0
src/web/stylesheets/components/_pane.css

@@ -0,0 +1,30 @@
+/**
+ * Workspace pane styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+:root {
+    --title-height: 43px;
+}
+
+.title {
+    padding: 10px;
+    height: var(--title-height);
+    border-bottom: 1px solid var(--primary-border-colour);
+    font-weight: var(--title-weight);
+    color: var(--title-colour);
+    background-color: var(--title-background-colour);
+}
+
+.list-area {
+    position: absolute;
+    top: var(--title-height);
+    bottom: 0;
+    width: 100%;
+    list-style-type: none;
+    margin: 0;
+    padding: 0;
+}

+ 34 - 0
src/web/stylesheets/index.css

@@ -0,0 +1,34 @@
+/**
+ * CyberChef styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+/* Themes */
+@import "./themes/_classic.css";
+@import "./themes/_dark.css";
+
+/* Utilities */
+@import "./utils/_overrides.css";
+@import "./utils/_general.css";
+
+/* Preloader styles */
+@import "./preloader.css";
+
+/* Components */
+@import "./components/_alert.css";
+@import "./components/_button.css";
+@import "./components/_list.css";
+@import "./components/_operation.css";
+@import "./components/_pane.css";
+
+/* Layout */
+@import "./layout/_banner.css";
+@import "./layout/_controls.css";
+@import "./layout/_io.css";
+@import "./layout/_modals.css";
+@import "./layout/_operations.css";
+@import "./layout/_recipe.css";
+@import "./layout/_structure.css";

+ 18 - 0
src/web/stylesheets/index.js

@@ -0,0 +1,18 @@
+/**
+ * Styles index
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+/* Libraries */
+import "google-code-prettify/src/prettify.css";
+
+/* Frameworks */
+import "./vendors/bootstrap.less";
+import "bootstrap-switch/dist/css/bootstrap3/bootstrap-switch.css";
+import "bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css";
+
+/* CyberChef styles */
+import "./index.css";

+ 28 - 0
src/web/stylesheets/layout/_banner.css

@@ -0,0 +1,28 @@
+/**
+ * Banner area styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+#banner {
+    position: absolute;
+    height: 30px;
+    width: 100%;
+    text-align: center;
+    line-height: 30px;
+    border-bottom: 1px solid var(--primary-border-colour);
+    color: var(--banner-font-colour);
+    background-color: var(--banner-bg-colour);
+}
+
+.banner-right {
+    float: right;
+    margin-right: 10px;
+}
+
+#banner img {
+    margin-bottom: 2px;
+    margin-left: 8px;
+}

+ 65 - 0
src/web/stylesheets/layout/_controls.css

@@ -0,0 +1,65 @@
+/**
+ * Controls area styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+:root {
+    --controls-height: 120px;
+    --controls-division: 65%;
+}
+
+#controls {
+    position: absolute;
+    width: 100%;
+    height: var(--controls-height);
+    bottom: 0;
+    padding: 10px;
+    border-top: 1px solid var(--primary-border-colour);
+    background-color: var(--secondary-background-colour);
+}
+
+#operational-controls {
+    width: var(--controls-division);
+    float: left;
+    text-align: center;
+}
+
+#bake-group {
+    display: table;
+    width: 100%;
+}
+
+#bake {
+    display: table-cell;
+    width: 100%;
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+
+#auto-bake-label {
+    display: table-cell;
+    padding: 1px;
+    line-height: 1.35;
+    width: 60px;
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+    border-left: 1px solid var(--btn-success-bg-colour);
+}
+
+#auto-bake-label:hover {
+    border-left-color: var(--btn-success-hover-border-colour);
+}
+
+#auto-bake-label div {
+    font-size: 10px;
+    padding: 2px;
+}
+
+#extra-controls {
+    float: right;
+    width: calc(100% - var(--controls-division));
+    padding-left: 10px;
+}

+ 109 - 0
src/web/stylesheets/layout/_io.css

@@ -0,0 +1,109 @@
+/**
+ * Input/Output area styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+#input-text,
+#output-text,
+#output-html {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 3px;
+    -moz-padding-start: 3px;
+    -moz-padding-end: 3px;
+    border: none;
+    border-width: 0px;
+    resize: none;
+    background-color: transparent;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+}
+
+#output-html {
+    display: none;
+    overflow-y: auto;
+    -moz-padding-start: 1px; /* Fixes bug in Firefox */
+}
+
+.textarea-wrapper {
+    position: absolute;
+    top: 43px;
+    bottom: 0;
+    width: 100%;
+    overflow: hidden;
+}
+
+.textarea-wrapper textarea,
+.textarea-wrapper div {
+    font-family: var(--fixed-width-font-family);
+    font-size: var(--fixed-width-font-size);
+    color: var(--fixed-width-font-colour);
+}
+
+#input-highlighter,
+#output-highlighter {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    padding: 3px;
+    margin: 0;
+    overflow: hidden;
+    letter-spacing: normal;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+    color: #fff;
+    background-color: transparent;
+    border: none;
+}
+
+.io-btn-group {
+    float: right;
+    margin-top: -4px;
+}
+
+.io-info {
+    margin-right: 20px;
+    margin-top: -4px;
+    float: right;
+    height: 30px;
+    text-align: right;
+    line-height: 10px;
+    font-family: var(--fixed-width-font-family);
+    font-weight: normal;
+    font-size: 8pt;
+}
+
+#input-info {
+    line-height: 15px;
+}
+
+.dropping-file {
+    border: 5px dashed var(--drop-file-border-colour) !important;
+}
+
+@keyframes spinner {
+    from {
+        transform:rotate(0deg);
+    }
+    to {
+        transform:rotate(359deg);
+    }
+}
+
+.loading-icon::before {
+    content: "\21bb";
+}
+
+.loading-icon {
+    animation-name: spinner;
+    animation-duration: 1000ms;
+    animation-iteration-count: infinite;
+    animation-timing-function: linear;
+}

+ 80 - 0
src/web/stylesheets/layout/_modals.css

@@ -0,0 +1,80 @@
+/**
+ * Modal layout styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+.option-item .bootstrap-switch {
+    margin: 15px 10px;
+}
+
+.option-item button {
+    margin: 10px;
+}
+
+.option-item input[type=number] {
+    margin: 15px 10px;
+    width: 80px;
+    height: 28px;
+    padding: 3px 10px;
+    vertical-align: middle;
+    font-size: calc(var(--arg-input-font-size) - 1px);
+    line-height: var(--arg-input-line-height);
+    color: var(--arg-font-colour);
+    background-color: var(--arg-background);
+    border: 1px solid var(--primary-border-colour);
+}
+
+.option-item select {
+    margin: 10px;
+    display: inline-block;
+}
+
+#edit-favourites-list {
+    margin: 10px;
+    border: 1px solid var(--op-list-operation-border-colour);
+}
+
+#edit-favourites-list .operation {
+    border-left: none;
+    border-right: none;
+}
+
+#edit-favourites-list .operation:last-child {
+    border-bottom: none;
+}
+
+.about-img-left {
+    float: left;
+    margin: 10px 20px 20px 0;
+}
+
+.about-img-right {
+    float: right;
+    margin: 10px 0 20px 20px;
+}
+
+.save-link-options {
+    float: right;
+}
+
+.save-link-options input{
+    margin-left: 10px;
+}
+
+#save-footer {
+    border-top: none;
+    margin-top: 0;
+    border-bottom: 1px solid var(--primary-border-colour);
+}
+
+#support-modal textarea {
+    font-family: var(--primary-font-family);
+}
+
+#save-text,
+#load-text {
+    font-family: var(--fixed-width-font-family);
+}

+ 32 - 0
src/web/stylesheets/layout/_operations.css

@@ -0,0 +1,32 @@
+/**
+ * Operation area styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+.op-list .operation {
+    color: var(--op-list-operation-font-colour);
+    background-color: var(--op-list-operation-bg-colour);
+    border-color: var(--op-list-operation-border-colour);
+}
+
+#search {
+    border-radius: 0;
+    border: none;
+    border-bottom: 1px solid var(--primary-border-colour);
+    color: var(--primary-font-colour);
+}
+
+#edit-favourites {
+    float: right;
+    margin-top: -5px;
+}
+
+.favourites-hover {
+    color: var(--rec-list-operation-font-colour);
+    background-color: var(--rec-list-operation-bg-colour);
+    border: 2px dashed var(--rec-list-operation-font-colour) !important;
+    padding: 8px 8px 9px 8px;
+}

+ 18 - 0
src/web/stylesheets/layout/_recipe.css

@@ -0,0 +1,18 @@
+/**
+ * Recipe area styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+#rec-list {
+    bottom: var(--controls-height);
+    overflow: auto;
+}
+
+#rec-list .operation {
+    color: var(--rec-list-operation-font-colour);
+    background-color: var(--rec-list-operation-bg-colour);
+    border-color: var(--rec-list-operation-border-colour);
+}

File diff suppressed because it is too large
+ 58 - 0
src/web/stylesheets/layout/_structure.css


+ 135 - 0
src/web/stylesheets/preloader.css

@@ -0,0 +1,135 @@
+/**
+ * Preloader styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+#loader-wrapper {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    z-index: 1000;
+    background-color: var(--secondary-border-colour);
+}
+
+#preloader {
+    display: block;
+    position: relative;
+    left: 50%;
+    top: 50%;
+    width: 150px;
+    height: 150px;
+    margin: -75px 0 0 -75px;
+
+    border: 3px solid transparent;
+    border-top-color: #3498db;
+    border-radius: 50%;
+    z-index: 1500;
+
+    animation: spin 2s linear infinite;
+}
+
+#preloader:before,
+#preloader:after {
+    content: "";
+    position: absolute;
+    top: 5px;
+    left: 5px;
+    right: 5px;
+    bottom: 5px;
+    border: 3px solid transparent;
+    border-radius: 50%;
+}
+
+#preloader:before {
+    border-top-color: #e74c3c;
+    animation: spin 3s linear infinite;
+}
+
+#preloader:after {
+    border-top-color: #f9c922;
+    animation: spin 1.5s linear infinite;
+}
+
+
+/* Loaded */
+.loaded #preloader {
+    opacity: 0;
+    transition: all 0.3s ease-out;
+}
+
+.loaded #loader-wrapper {
+    opacity: 0;
+    transition: all 0.5s 0.3s ease-out;
+}
+
+.loaded #rec-list li {
+	animation: bump 0.7s cubic-bezier(0.7, 0, 0.3, 1) both;
+}
+
+.loaded #content-wrapper {
+	animation-delay: 0.10s;
+}
+
+.loaded #rec-list li:first-child {
+	animation-delay: 0.20s;
+}
+
+.loaded #rec-list li:nth-child(2) {
+	animation-delay: 0.25s;
+}
+
+.loaded #rec-list li:nth-child(3) {
+	animation-delay: 0.30s;
+}
+
+.loaded #rec-list li:nth-child(4) {
+	animation-delay: 0.35s;
+}
+
+.loaded #rec-list li:nth-child(5) {
+	animation-delay: 0.40s;
+}
+
+.loaded #rec-list li:nth-child(6) {
+	animation-delay: 0.45s;
+}
+
+.loaded #rec-list li:nth-child(7) {
+	animation-delay: 0.50s;
+}
+
+.loaded #rec-list li:nth-child(8) {
+	animation-delay: 0.55s;
+}
+
+.loaded #rec-list li:nth-child(9) {
+	animation-delay: 0.60s;
+}
+
+.loaded #rec-list li:nth-child(10) {
+	animation-delay: 0.65s;
+}
+
+
+/* Animations */
+
+@keyframes spin {
+    0%   {
+        transform: rotate(0deg);
+    }
+    100% {
+        transform: rotate(360deg);
+    }
+}
+
+@keyframes bump {
+	from {
+        opacity: 0;
+        transform: translate3d(0, 200px, 0);
+    }
+}

+ 116 - 0
src/web/stylesheets/themes/_classic.css

@@ -0,0 +1,116 @@
+/**
+ * Classic theme definitions
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+:root,
+:root.classic {
+    --primary-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+    --primary-font-colour: #333;
+    --primary-font-size: 14px;
+    --primary-line-height: 20px;
+
+    --fixed-width-font-family: "Consolas", monospace;
+    --fixed-width-font-colour: inherit;
+    --fixed-width-font-size: inherit;
+
+    --subtext-font-colour: #999;
+    --subtext-font-size: 13px;
+
+    --primary-background-colour: #fff;
+    --secondary-background-colour: #fafafa;
+
+    --primary-border-colour: #ddd;
+    --secondary-border-colour: #eee;
+
+    --title-colour: #424242;
+    --title-weight: bold;
+    --title-background-colour: #fafafa;
+
+    --banner-font-colour: #468847;
+    --banner-bg-colour: #dff0d8;
+
+
+    /* Operation colours */
+    --op-list-operation-font-colour: #3a87ad;
+    --op-list-operation-bg-colour: #d9edf7;
+    --op-list-operation-border-colour: #bce8f1;
+
+    --rec-list-operation-font-colour: #468847;
+    --rec-list-operation-bg-colour: #dff0d8;
+    --rec-list-operation-border-colour: #d6e9c6;
+
+    --selected-operation-font-color: #c09853;
+    --selected-operation-bg-colour: #fcf8e3;
+    --selected-operation-border-colour: #fbeed5;
+
+    --breakpoint-font-colour: #b94a48;
+    --breakpoint-bg-colour: #f2dede;
+    --breakpoint-border-colour: #eed3d7;
+
+    --disabled-font-colour: #999;
+    --disabled-bg-colour: #dfdfdf;
+    --disabled-border-colour: #cdcdcd;
+
+    --fc-operation-font-colour: #396f3a;
+    --fc-operation-bg-colour: #c7e4ba;
+    --fc-operation-border-colour: #b3dba2;
+
+    --fc-breakpoint-operation-font-colour: #94312f;
+    --fc-breakpoint-operation-bg-colour: #eabfbf;
+    --fc-breakpoint-operation-border-colour: #e2aeb5;
+
+
+    /* Operation arguments */
+    --arg-title-font-weight: bold;
+    --arg-input-height: 34px;
+    --arg-input-line-height: 20px;
+    --arg-input-font-size: 15px;
+    --arg-font-colour: #424242;
+    --arg-background: #fff;
+    --arg-border-colour: #ddd;
+    --arg-disabled-background: #eee;
+
+
+    /* Buttons */
+    --btn-default-font-colour: #333;
+    --btn-default-bg-colour: #fff;
+    --btn-default-border-colour: #ddd;
+
+    --btn-default-hover-font-colour: #333;
+    --btn-default-hover-bg-colour: #ebebeb;
+    --btn-default-hover-border-colour: #adadad;
+
+    --btn-success-font-colour: #fff;
+    --btn-success-bg-colour: #5cb85c;
+    --btn-success-border-colour: #4cae4c;
+
+    --btn-success-hover-font-colour: #fff;
+    --btn-success-hover-bg-colour: #449d44;
+    --btn-success-hover-border-colour: #398439;
+
+
+    /* Highlighter colours */
+    --hl1: #fff000;
+    --hl2: #95dfff;
+    --hl3: #ffb6b6;
+    --hl4: #fcf8e3;
+    --hl5: #8de768;
+
+
+    /* Scrollbar */
+    --scrollbar-track: var(--secondary-background-colour);
+    --scrollbar-thumb: #ccc;
+    --scrollbar-hover: #bbb;
+
+
+    /* Misc. */
+    --drop-file-border-colour: #3a87ad;
+    --popover-background: #fff;
+    --popover-border-colour: #ccc;
+    --code-background: #f9f2f4;
+    --code-font-colour: #c7254e;
+}

+ 115 - 0
src/web/stylesheets/themes/_dark.css

@@ -0,0 +1,115 @@
+/**
+ * Dark theme definitions
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+:root.dark {
+    --primary-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+    --primary-font-colour: #c5c5c5;
+    --primary-font-size: 14px;
+    --primary-line-height: 20px;
+
+    --fixed-width-font-family: "Monaco", "Droid Sans Mono", "Consolas", monospace;
+    --fixed-width-font-colour: inherit;
+    --fixed-width-font-size: inherit;
+
+    --subtext-font-colour: #999;
+    --subtext-font-size: 13px;
+
+    --primary-background-colour: #1e1e1e;
+    --secondary-background-colour: #252525;
+
+    --primary-border-colour: #444;
+    --secondary-border-colour: #3c3c3c;
+
+    --title-colour: #fff;
+    --title-weight: bold;
+    --title-background-colour: #333;
+
+    --banner-font-colour: #c5c5c5;
+    --banner-bg-colour: #252525;
+
+
+    /* Operation colours */
+    --op-list-operation-font-colour: #c5c5c5;
+    --op-list-operation-bg-colour: #333;
+    --op-list-operation-border-colour: #444;
+
+    --rec-list-operation-font-colour: #c5c5c5;
+    --rec-list-operation-bg-colour: #252525;
+    --rec-list-operation-border-colour: #444;
+
+    --selected-operation-font-color: #c5c5c5;
+    --selected-operation-bg-colour: #3f3f3f;
+    --selected-operation-border-colour: #444;
+
+    --breakpoint-font-colour: #ddd;
+    --breakpoint-bg-colour: #073655;
+    --breakpoint-border-colour: #444;
+
+    --disabled-font-colour: #666;
+    --disabled-bg-colour: #444;
+    --disabled-border-colour: #444;
+
+    --fc-operation-font-colour: #c5c5c5;
+    --fc-operation-bg-colour: #2d2d2d;
+    --fc-operation-border-colour: #444;
+
+    --fc-breakpoint-operation-font-colour: #ddd;
+    --fc-breakpoint-operation-bg-colour: #072b49;
+    --fc-breakpoint-operation-border-colour: #444;
+
+
+    /* Operation arguments */
+    --arg-title-font-weight: bold;
+    --arg-input-height: 34px;
+    --arg-input-line-height: 20px;
+    --arg-input-font-size: 15px;
+    --arg-font-colour: #bbb;
+    --arg-background: #3c3c3c;
+    --arg-border-colour: #3c3c3c;
+    --arg-disabled-background: #4f4f4f;
+
+
+    /* Buttons */
+    --btn-default-font-colour: #c5c5c5;
+    --btn-default-bg-colour: #2d2d2d;
+    --btn-default-border-colour: #3c3c3c;
+
+    --btn-default-hover-font-colour: #c5c5c5;
+    --btn-default-hover-bg-colour: #2d2d2d;
+    --btn-default-hover-border-colour: #205375;
+
+    --btn-success-font-colour: #fff;
+    --btn-success-bg-colour: #073655;
+    --btn-success-border-colour: #0e639c;
+
+    --btn-success-hover-font-colour: #fff;
+    --btn-success-hover-bg-colour: #0e639c;
+    --btn-success-hover-border-colour: #0e639c;
+
+
+    /* Highlighter colours */
+    --hl1: #264f78;
+    --hl2: #675351;
+    --hl3: #ffb6b6;
+    --hl4: #fcf8e3;
+    --hl5: #8de768;
+
+
+    /* Scrollbar */
+    --scrollbar-track: #1e1e1e;
+    --scrollbar-thumb: #424242;
+    --scrollbar-hover: #4e4e4e;
+
+
+    /* Misc. */
+    --drop-file-border-colour: #0e639c;
+    --popover-background: #444;
+    --popover-border-colour: #555;
+    --code-background: #0e639c;
+    --code-font-colour: #fff;
+}

+ 73 - 0
src/web/stylesheets/utils/_general.css

@@ -0,0 +1,73 @@
+/**
+ * General styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+body {
+    font-family: var(--primary-font-family);
+    font-size: var(--primary-font-size);
+    line-height: var(--primary-line-height);
+    color: var(--primary-font-colour);
+    background-color: var(--primary-background-colour);
+}
+
+.subtext {
+    font-style: italic;
+    font-size: var(--subtext-font-size);
+    color: var(--subtext-font-colour);
+}
+
+.word-wrap {
+    white-space: pre !important;
+    word-wrap: normal !important;
+    overflow-x: scroll !important;
+}
+
+.clearfix {
+    clear: both;
+    height: 0;
+}
+
+.blur {
+    color: transparent !important;
+    text-shadow: rgba(0, 0, 0, 0.95) 0 0 10px !important;
+}
+
+.no-select { 
+    user-select: none;
+}
+
+.konami {
+    transform: rotate(180deg);
+}
+
+::-webkit-scrollbar {
+    width: 10px;
+    height: 10px;
+}
+
+::-webkit-scrollbar-track {
+    background-color: var(--scrollbar-track);
+}
+
+::-webkit-scrollbar-thumb {
+    background-color: var(--scrollbar-thumb);
+}
+
+::-webkit-scrollbar-thumb:hover {
+    background-color: var(--scrollbar-hover);
+}
+
+::-webkit-scrollbar-corner {
+    background-color: var(--scrollbar-track);
+}
+
+/* Highlighters */
+.hl1 { background-color: var(--hl1); }
+.hl2 { background-color: var(--hl2); }
+.hl3 { background-color: var(--hl3); } /* Half-Life 3 confirmed :O */
+.hl4 { background-color: var(--hl4); }
+.hl5 { background-color: var(--hl5); }

+ 223 - 0
src/web/stylesheets/utils/_overrides.css

@@ -0,0 +1,223 @@
+/**
+ * Overrides for vendor styles
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+
+/* Bootstrap */
+
+button,
+a:focus {
+    outline: none;
+}
+
+.btn-default {
+    color: var(--btn-default-font-colour);
+    background-color: var(--btn-default-bg-colour);
+    border-color: var(--btn-default-border-colour);
+}
+
+.btn-default:hover,
+.btn-default:active,
+.btn-default:hover:active,
+.open>.dropdown-toggle.btn-default {
+    color: var(--btn-default-hover-font-colour);
+    background-color: var(--btn-default-hover-bg-colour);
+    border-color: var(--btn-default-hover-border-colour);
+}
+
+.btn-default:focus,
+.open>.dropdown-toggle.btn-default:hover,
+.open>.dropdown-toggle.btn-default:focus {
+    color: var(--btn-default-font-colour);
+    background-color: var(--btn-default-bg-colour);
+    border-color: var(--btn-default-hover-border-colour);
+}
+
+.btn-default[disabled]:hover {
+    background-color: var(--primary-background-colour);
+    border-color: var(--primary-border-colour);
+}
+
+.btn-success {
+    color: var(--btn-success-font-colour);
+    background-color: var(--btn-success-bg-colour);
+    border-color: var(--btn-success-border-colour);
+}
+
+.btn-success:hover,
+.btn-success:active,
+.btn-success:focus,
+.btn-success:hover:active {
+    color: var(--btn-success-hover-font-colour);
+    background-color: var(--btn-success-hover-bg-colour);
+    border-color: var(--btn-success-hover-border-colour);
+}
+
+.btn,
+.btn-lg,
+.nav-tabs>li>a,
+.form-control,
+.popover,
+.alert,
+.modal-content,
+.tooltip-inner,
+.dropdown-menu {
+    border-radius: 0 !important;
+}
+
+.btn.dropdown-toggle {
+    height: 34px;
+}
+
+input[type="search"] {
+    -webkit-appearance: searchfield;
+    box-shadow: none;
+}
+
+input[type="search"]::-webkit-search-cancel-button {
+    -webkit-appearance: searchfield-cancel-button;
+}
+
+.modal {
+    overflow-y: auto;
+}
+
+.modal-content {
+    background-color: var(--primary-background-colour);
+}
+
+.modal-header,
+.modal-footer {
+    border-color: var(--primary-border-colour);
+}
+
+.form-control {
+    background-color: transparent;
+    border-color: var(--primary-border-colour);
+    color: var(--primary-font-colour);
+}
+
+code {
+    border: 0;
+    white-space: pre-wrap;
+    font-family: var(--fixed-width-font-family);
+    background-color: var(--code-background);
+    color: var(--code-font-colour);
+}
+
+pre {
+    border-radius: 0 !important;
+    background-color: var(--secondary-background-colour);
+    border-color: var(--secondary-border-colour);
+    color: var(--fixed-width-font-colour);
+}
+
+blockquote {
+    font-size: inherit;
+    border-left-color: var(--secondary-border-colour);
+}
+
+blockquote a {
+    cursor: pointer;
+}
+
+optgroup {
+    font-weight: bold;
+}
+
+.panel-body:before,
+.panel-body:after {
+    content: "";
+}
+
+.table-nonfluid {
+    width: auto !important;
+}
+
+.popover {
+    background-color: var(--popover-background);
+    border-color: var(--popover-border-colour);
+}
+
+
+.popover.right>.arrow {
+    border-right-color: var(--popover-border-colour);
+}
+
+.popover.right>.arrow:after {
+    border-right-color: var(--popover-background);
+}
+
+.nav-tabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover {
+    background-color: var(--primary-background-colour);
+    border-color: var(--primary-border-colour);
+    border-bottom-color: transparent;
+    color: var(--primary-font-colour);
+}
+
+.nav-tabs {
+    border-color: var(--primary-border-colour);
+}
+
+.nav>li>a:focus, .nav>li>a:hover {
+    background-color: var(--secondary-border-colour);
+}
+
+.nav-tabs>li>a:hover {
+    border-color: var(--secondary-border-colour) var(--secondary-border-colour) var(--primary-border-colour);
+}
+
+.dropdown-menu {
+    background-color: var(--primary-background-colour);
+}
+
+.dropdown-menu>li>a {
+    color: var(--primary-font-colour);
+}
+
+.dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover {
+    background-color: var(--secondary-background-colour);
+    color: var(--primary-font-colour);
+}
+
+
+/* Bootstrap-switch */
+
+.bootstrap-switch,
+.bootstrap-switch-container,
+.bootstrap-switch-handle-on,
+.bootstrap-switch-handle-off,
+.bootstrap-switch-label {
+    border-radius: 0 !important;
+}
+
+.bootstrap-switch .bootstrap-switch-label {
+    background-color: transparent;
+}
+
+.bootstrap-switch {
+    border-color: var(--primary-border-colour);
+}
+
+
+/* Sortable */
+
+.sortable-ghost {
+    opacity: 0.6;
+}
+
+
+/* Bootstrap Colorpicker */
+
+.colorpicker-element {
+    float: left;
+    margin-right: 15px;
+}
+
+.colorpicker-color,
+.colorpicker-color div {
+    height: 100px;
+}

+ 1 - 1
src/web/css/lib/bootstrap.less → src/web/stylesheets/vendors/bootstrap.less

@@ -55,4 +55,4 @@
 
 // Utility classes
 @import "~bootstrap/less/utilities.less";
-// @import "~bootstrap/less/responsive-utilities.less";
+// @import "~bootstrap/less/responsive-utilities.less";

Some files were not shown because too many files changed in this diff