From d0c52d84c7e00ff00b993a80e478d24f489d7089 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Mon, 15 Aug 2022 15:44:46 +0200 Subject: [PATCH] Add a custom spinner icon --- ts/WoltLabSuite/Core/Ajax/Status.ts | 5 +- ts/WoltLabSuite/WebComponent/fa-icon.ts | 63 ++++++++++++++++++- .../files/js/WoltLabSuite/Core/Ajax/Status.js | 5 +- .../js/WoltLabSuite/WebComponent/fa-icon.js | 60 +++++++++++++++++- 4 files changed, 125 insertions(+), 8 deletions(-) diff --git a/ts/WoltLabSuite/Core/Ajax/Status.ts b/ts/WoltLabSuite/Core/Ajax/Status.ts index 02ab23359d..80542deb57 100644 --- a/ts/WoltLabSuite/Core/Ajax/Status.ts +++ b/ts/WoltLabSuite/Core/Ajax/Status.ts @@ -19,8 +19,9 @@ class AjaxStatus { this._overlay.classList.add("spinner"); this._overlay.setAttribute("role", "status"); - const icon = document.createElement("span"); - icon.className = "icon icon48 fa-spinner"; + const icon = document.createElement("fa-icon"); + icon.size = 48; + icon.setIcon("spinner", true); this._overlay.appendChild(icon); const title = document.createElement("span"); diff --git a/ts/WoltLabSuite/WebComponent/fa-icon.ts b/ts/WoltLabSuite/WebComponent/fa-icon.ts index f83c754694..fb52d65ccf 100644 --- a/ts/WoltLabSuite/WebComponent/fa-icon.ts +++ b/ts/WoltLabSuite/WebComponent/fa-icon.ts @@ -95,8 +95,67 @@ const root = this.getShadowRoot(); root.childNodes[0]?.remove(); - const [codepoint] = window.getFontAwesome6IconMetadata(this.name)!; - root.append(codepoint); + if (this.name === "spinner") { + root.append(this.createSpinner()); + } else { + const [codepoint] = window.getFontAwesome6IconMetadata(this.name)!; + root.append(codepoint); + } + } + + private createSpinner(): HTMLElement { + // Based upon the work of Fabio Ottaviani + // https://codepen.io/supah/pen/BjYLdW + const container = document.createElement("div"); + container.innerHTML = ` + + + + `; + + const style = document.createElement("style"); + style.textContent = ` + div, + svg { + height: var(--font-size); + width: var(--font-size); + } + + .spinner { + animation: rotate 2s linear infinite; + } + + .path { + animation: dash 1.5s ease-in-out infinite; + stroke: currentColor; + stroke-linecap: round; + } + + @keyframes rotate { + 100% { + transform: rotate(360deg); + } + } + + @keyframes dash { + 0% { + stroke-dasharray: 1, 150; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -35; + } + 100% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -124; + } + } + `; + + container.append(style); + + return container; } get solid(): boolean { diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Status.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Status.js index ae3e0a34ac..2cab0c4255 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Status.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Status.js @@ -18,8 +18,9 @@ define(["require", "exports", "tslib", "../Language"], function (require, export this._overlay = document.createElement("div"); this._overlay.classList.add("spinner"); this._overlay.setAttribute("role", "status"); - const icon = document.createElement("span"); - icon.className = "icon icon48 fa-spinner"; + const icon = document.createElement("fa-icon"); + icon.size = 48; + icon.setIcon("spinner", true); this._overlay.appendChild(icon); const title = document.createElement("span"); title.textContent = Language.get("wcf.global.loading"); diff --git a/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js b/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js index dcf6ebfea1..2514e10fd8 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js +++ b/wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js @@ -78,8 +78,64 @@ var _a; const root = this.getShadowRoot(); (_a = root.childNodes[0]) === null || _a === void 0 ? void 0 : _a.remove(); - const [codepoint] = window.getFontAwesome6IconMetadata(this.name); - root.append(codepoint); + if (this.name === "spinner") { + root.append(this.createSpinner()); + } + else { + const [codepoint] = window.getFontAwesome6IconMetadata(this.name); + root.append(codepoint); + } + } + createSpinner() { + // Based upon the work of Fabio Ottaviani + // https://codepen.io/supah/pen/BjYLdW + const container = document.createElement("div"); + container.innerHTML = ` + + + + `; + const style = document.createElement("style"); + style.textContent = ` + div, + svg { + height: var(--font-size); + width: var(--font-size); + } + + .spinner { + animation: rotate 2s linear infinite; + } + + .path { + animation: dash 1.5s ease-in-out infinite; + stroke: currentColor; + stroke-linecap: round; + } + + @keyframes rotate { + 100% { + transform: rotate(360deg); + } + } + + @keyframes dash { + 0% { + stroke-dasharray: 1, 150; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -35; + } + 100% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -124; + } + } + `; + container.append(style); + return container; } get solid() { return this.hasAttribute("solid"); -- 2.20.1