diff --git a/src/web/App.mjs b/src/web/App.mjs index 1dab16e6..453fba22 100755 --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -51,10 +51,12 @@ class App { */ setup() { document.dispatchEvent(this.manager.appstart); + this.initialiseSplitter(); this.loadLocalStorage(); this.populateOperationsList(); this.manager.setup(); + this.manager.output.saveBombe(); this.resetLayout(); this.setCompileMessage(); diff --git a/src/web/OutputWaiter.mjs b/src/web/OutputWaiter.mjs index 7203a16f..39d6e51b 100755 --- a/src/web/OutputWaiter.mjs +++ b/src/web/OutputWaiter.mjs @@ -334,24 +334,55 @@ class OutputWaiter { /** - * Shows or hides the loading icon. + * Save bombe object before it is removed so that it can be used later + */ + saveBombe() { + this.bombeEl = document.getElementById("bombe").cloneNode(); + this.bombeEl.setAttribute("width", "100%"); + this.bombeEl.setAttribute("height", "100%"); + } + + + /** + * Shows or hides the output loading screen. + * The animated Bombe SVG, whilst quite aesthetically pleasing, is reasonably CPU + * intensive, so we remove it from the DOM when not in use. We only show it if the + * recipe is taking longer than 200ms. We add it to the DOM just before that so that + * it is ready to fade in without stuttering. * - * @param {boolean} value + * @param {boolean} value - true == show loader */ toggleLoader(value) { + clearTimeout(this.appendBombeTimeout); + clearTimeout(this.outputLoaderTimeout); + const outputLoader = document.getElementById("output-loader"), - outputElement = document.getElementById("output-text"); + outputElement = document.getElementById("output-text"), + loader = outputLoader.querySelector(".loader"); if (value) { this.manager.controls.hideStaleIndicator(); - this.bakingStatusTimeout = setTimeout(function() { + + // Start a timer to add the Bombe to the DOM just before we make it + // visible so that there is no stuttering + this.appendBombeTimeout = setTimeout(function() { + loader.appendChild(this.bombeEl); + }.bind(this), 150); + + // Show the loading screen + this.outputLoaderTimeout = setTimeout(function() { outputElement.disabled = true; outputLoader.style.visibility = "visible"; outputLoader.style.opacity = 1; this.manager.controls.toggleBakeButtonFunction(true); }.bind(this), 200); } else { - clearTimeout(this.bakingStatusTimeout); + // Remove the Bombe from the DOM to save resources + this.outputLoaderTimeout = setTimeout(function () { + try { + loader.removeChild(this.bombeEl); + } catch (err) {} + }.bind(this), 500); outputElement.disabled = false; outputLoader.style.opacity = 0; outputLoader.style.visibility = "hidden"; diff --git a/src/web/html/index.html b/src/web/html/index.html index f03590ab..a1f915b6 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -81,7 +81,11 @@ if (!el.classList.contains("loading")) el.classList.add("loading"); // Causes CSS transition on first message el.innerHTML = msg; - } catch (err) {} // Ignore errors if DOM not yet ready + } catch (err) { + // This error was likely caused by the DOM not being ready yet, + // so we wait another second and then try again. + setTimeout(changeLoadingMsg, 1000); + } } changeLoadingMsg(); @@ -138,7 +142,9 @@
-
+
+ +
diff --git a/src/web/static/images/bombe.svg b/src/web/static/images/bombe.svg new file mode 100644 index 00000000..40857bdf --- /dev/null +++ b/src/web/static/images/bombe.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + Z + Y + X + W + V + U + T + S + R + Q + P + O + N + M + L + K + J + I + H + G + F + E + D + C + B + A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/web/stylesheets/layout/_io.css b/src/web/stylesheets/layout/_io.css index 5b0433f6..0a1e4ec4 100755 --- a/src/web/stylesheets/layout/_io.css +++ b/src/web/stylesheets/layout/_io.css @@ -73,6 +73,28 @@ background-color: var(--primary-background-colour); visibility: hidden; opacity: 0; + display: flex; + justify-content: center; + align-items: center; + + transition: all 0.5s ease; +} + +#output-loader .loader { + width: 60%; + height: 60%; + left: unset; + top: 10%; +} + +#output-loader .loading-msg { + opacity: 1; + font-family: var(--primary-font-family); + line-height: var(--primary-line-height); + color: var(--primary-font-colour); + left: unset; + top: 30%; + position: relative; transition: all 0.5s ease; } @@ -138,16 +160,6 @@ margin-bottom: 5px; } -#output-loader .loading-msg { - opacity: 1; - font-family: var(--primary-font-family); - line-height: var(--primary-line-height); - color: var(--primary-font-colour); - top: 50%; - - transition: all 0.5s ease; -} - #magic { opacity: 1; visibility: visibile; diff --git a/src/web/stylesheets/preloader.css b/src/web/stylesheets/preloader.css index 702d04a6..bce0cd03 100755 --- a/src/web/stylesheets/preloader.css +++ b/src/web/stylesheets/preloader.css @@ -16,57 +16,28 @@ background-color: var(--secondary-border-colour); } +#loader-wrapper div { + animation: fadeIn 1s ease-in 0s; +} + .loader { 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%; - - animation: spin 2s linear infinite; -} - -.loader:before, -.loader:after { - content: ""; position: absolute; - border: 3px solid transparent; - border-radius: 50%; -} - -.loader:before { - top: 5px; - left: 5px; - right: 5px; - bottom: 5px; - border-top-color: #e74c3c; - animation: spin 3s linear infinite; -} - -.loader:after { - top: 13px; - left: 13px; - right: 13px; - bottom: 13px; - border-top-color: #f9c922; - animation: spin 1.5s linear infinite; + left: calc(50% - 200px); + top: calc(50% - 160px); + width: 400px; + height: 260px; } .loading-msg { display: block; - position: relative; + position: absolute; width: 400px; left: calc(50% - 200px); - top: calc(50% + 50px); + top: calc(50% + 110px); text-align: center; - margin-top: 50px; opacity: 0; + font-size: 18px; } .loading-msg.loading { @@ -145,18 +116,18 @@ /* Animations */ -@keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - @keyframes bump { from { opacity: 0; transform: translate3d(0, 200px, 0); } } + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +}