![]()
diff --git a/app/helpers/icon_helper.rb b/app/helpers/icon_helper.rb
index fe7346986..2e53b6961 100644
--- a/app/helpers/icon_helper.rb
+++ b/app/helpers/icon_helper.rb
@@ -81,7 +81,7 @@ module IconHelper
end
def spinner_icon(**options)
- icon_tag("fas fa-spinner fa-spin", **options)
+ svg_icon_tag("spinner-icon", "M304 48C304 74.51 282.5 96 256 96C229.5 96 208 74.51 208 48C208 21.49 229.5 0 256 0C282.5 0 304 21.49 304 48zM304 464C304 490.5 282.5 512 256 512C229.5 512 208 490.5 208 464C208 437.5 229.5 416 256 416C282.5 416 304 437.5 304 464zM0 256C0 229.5 21.49 208 48 208C74.51 208 96 229.5 96 256C96 282.5 74.51 304 48 304C21.49 304 0 282.5 0 256zM512 256C512 282.5 490.5 304 464 304C437.5 304 416 282.5 416 256C416 229.5 437.5 208 464 208C490.5 208 512 229.5 512 256zM74.98 437C56.23 418.3 56.23 387.9 74.98 369.1C93.73 350.4 124.1 350.4 142.9 369.1C161.6 387.9 161.6 418.3 142.9 437C124.1 455.8 93.73 455.8 74.98 437V437zM142.9 142.9C124.1 161.6 93.73 161.6 74.98 142.9C56.24 124.1 56.24 93.73 74.98 74.98C93.73 56.23 124.1 56.23 142.9 74.98C161.6 93.73 161.6 124.1 142.9 142.9zM369.1 369.1C387.9 350.4 418.3 350.4 437 369.1C455.8 387.9 455.8 418.3 437 437C418.3 455.8 387.9 455.8 369.1 437C350.4 418.3 350.4 387.9 369.1 369.1V369.1z", viewbox: "0 0 512 512", **options)
end
def external_link_icon(**options)
diff --git a/app/javascript/src/javascripts/file_upload_component.js b/app/javascript/src/javascripts/file_upload_component.js
index e1752f1a7..66981c1c0 100644
--- a/app/javascript/src/javascripts/file_upload_component.js
+++ b/app/javascript/src/javascripts/file_upload_component.js
@@ -92,11 +92,22 @@ export default class FileUploadComponent {
this.pollStatus(upload);
}
+ loadingStart() {
+ this.$component.find(".spinner-icon").removeClass("hidden");
+ this.$component.find("input").attr("disabled", "disabled");
+ this.$component.find("form").addClass("pointer-events-none cursor-wait opacity-50");
+ }
+
+ loadingStop() {
+ this.$component.find(".spinner-icon").addClass("hidden");
+ this.$component.find("input").removeAttr("disabled");
+ this.$component.find("form").removeClass("pointer-events-none cursor-wait opacity-50");
+ }
+
// Called after the upload is submitted via AJAX. Polls the upload until it
// is complete, then redirects to the upload page.
async pollStatus(upload) {
- this.$component.find("progress").removeClass("hidden");
- this.$component.find("input").attr("disabled", "disabled");
+ this.loadingStart();
while (upload.media_asset_count <= 1 && upload.status !== "completed" && upload.status !== "error") {
await Utility.delay(FileUploadComponent.POLL_DELAY);
@@ -105,8 +116,7 @@ export default class FileUploadComponent {
if (upload.status === "error") {
this.$dropzone.removeClass("success");
- this.$component.find("progress").addClass("hidden");
- this.$component.find("input").removeAttr("disabled");
+ this.loadingStop();
Utility.error(`Upload failed: ${upload.error}.`);
} else {
diff --git a/app/javascript/src/styles/common/utilities.scss b/app/javascript/src/styles/common/utilities.scss
index 35b2ed496..79686c1b5 100644
--- a/app/javascript/src/styles/common/utilities.scss
+++ b/app/javascript/src/styles/common/utilities.scss
@@ -16,6 +16,7 @@ $spacer: 0.25rem; /* 4px */
.cursor-pointer { cursor: pointer; }
.cursor-zoom-in { cursor: zoom-in; }
.cursor-zoom-out { cursor: zoom-out; }
+.cursor-wait { cursor: wait; }
.hidden { display: none !important; }
.inline-block { display: inline-block; }
@@ -48,6 +49,8 @@ $spacer: 0.25rem; /* 4px */
.pointer-events-none { pointer-events: none; }
.select-none { user-select: none; }
+.opacity-50 { opacity: 0.5; }
+
.leading-none { line-height: 1; }
.leading-normal { line-height: 1.5; }
@@ -59,6 +62,8 @@ $spacer: 0.25rem; /* 4px */
.left-0\.5 { left: 0.5 * $spacer; }
.right-0\.5 { right: 0.5 * $spacer; }
+.inset-0 { top: 0; right: 0; bottom: 0; left: 0 }
+
.border, %border { border-width: 1px; }
.border-b { border-bottom-width: 1px; }
@@ -79,6 +84,7 @@ $spacer: 0.25rem; /* 4px */
.object-contain { object-fit: contain; }
+.m-auto { margin: auto; }
.m-0 { margin: 0; }
.m-px { margin: 1px; }
.m-0\.5 { margin: 0.5 * $spacer; }
@@ -199,6 +205,8 @@ $spacer: 0.25rem; /* 4px */
.grid-cols-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); }
.grid-cols-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); }
+.link-color { color: var(--link-color); }
+
.card {
@extend %border;
@extend %rounded-lg;
@@ -259,6 +267,20 @@ $spacer: 0.25rem; /* 4px */
}
}
+.animate-spin {
+ animation: animate-spin 1s linear infinite;
+}
+
+@keyframes animate-spin {
+ from {
+ transform: rotate(0deg);
+ }
+
+ to {
+ transform: rotate(360deg);
+ }
+}
+
@media screen and (min-width: 660px) {
.md\:inline-block { display: inline-block; }
.md\:block { display: block; }