Add a custom spinner icon
authorAlexander Ebert <ebert@woltlab.com>
Mon, 15 Aug 2022 13:44:46 +0000 (15:44 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 15 Aug 2022 13:44:46 +0000 (15:44 +0200)
ts/WoltLabSuite/Core/Ajax/Status.ts
ts/WoltLabSuite/WebComponent/fa-icon.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Status.js
wcfsetup/install/files/js/WoltLabSuite/WebComponent/fa-icon.js

index 02ab23359d50d247a428c3ff58e027d8da28ac9a..80542deb57aca4566278f6b2d0406e759a5e5ff6 100644 (file)
@@ -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");
index f83c7546948a947d9d6a1b7a36bf7040e8b4f8cb..fb52d65ccf4df0090aa156593d02d63ffe439e18 100644 (file)
       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 = `
+        <svg class="spinner" viewBox="0 0 50 50">
+          <circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
+        </svg>
+      `;
+
+      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 {
index ae3e0a34ace447afdaa6442050a66dc13186c241..2cab0c4255a6618ded56ea00ee5cd61f8e2ffecd 100644 (file)
@@ -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");
index dcf6ebfea1a06f436f5564602d1c921df8e3445d..2514e10fd8e33be80383d249324311cd78c40888 100644 (file)
             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 = `
+        <svg class="spinner" viewBox="0 0 50 50">
+          <circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
+        </svg>
+      `;
+            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");