diff --git a/js/src/common/components/LoadingIndicator.js b/js/src/common/components/LoadingIndicator.js
deleted file mode 100644
index 918c6f820..000000000
--- a/js/src/common/components/LoadingIndicator.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import Component from '../Component';
-import { Spinner } from 'spin.js';
-
-/**
- * The `LoadingIndicator` component displays a loading spinner with spin.js.
- *
- * ### Attrs
- *
- * - `size` The spin.js size preset to use. Defaults to 'small'.
- *
- * All other attrs will be assigned as attributes on the DOM element.
- */
-export default class LoadingIndicator extends Component {
- view() {
- const attrs = Object.assign({}, this.attrs);
-
- attrs.className = 'LoadingIndicator ' + (attrs.className || '');
- delete attrs.size;
-
- return
{m.trust(' ')}
;
- }
-
- oncreate(vnode) {
- super.oncreate(vnode);
-
- const options = { zIndex: 'auto', color: this.$().css('color') };
-
- switch (this.attrs.size) {
- case 'large':
- Object.assign(options, { lines: 10, length: 8, width: 4, radius: 8 });
- break;
-
- case 'tiny':
- Object.assign(options, { lines: 8, length: 2, width: 2, radius: 3 });
- break;
-
- default:
- Object.assign(options, { lines: 8, length: 4, width: 3, radius: 5 });
- }
-
- new Spinner(options).spin(this.element);
- }
-}
diff --git a/js/src/common/components/LoadingIndicator.tsx b/js/src/common/components/LoadingIndicator.tsx
new file mode 100644
index 000000000..f781f6d1f
--- /dev/null
+++ b/js/src/common/components/LoadingIndicator.tsx
@@ -0,0 +1,61 @@
+import Component, { ComponentAttrs } from '../Component';
+import classList from '../utils/classList';
+
+export interface LoadingIndicatorAttrs extends ComponentAttrs {
+ /**
+ * Custom classes fro the loading indicator's container.
+ */
+ className?: string;
+ /**
+ * Custom classes for the loading indicator's container.
+ */
+ containerClassName?: string;
+ /**
+ * Optional size to specify for the loading indicator.
+ */
+ size?: 'large' | 'medium' | 'small';
+ /**
+ * Optional attributes to apply to the loading indicator's container.
+ */
+ containerAttrs?: Partial;
+}
+
+/**
+ * The `LoadingIndicator` component displays a simple CSS-based loading spinner.
+ *
+ * To set a custom color, use the CSS `color` property.
+ *
+ * To increase spacing around the spinner, use the CSS `height` property on the
+ * spinner's **container**.
+ *
+ * To apply a custom size to the loading indicator, set the `--size` and
+ * `--thickness` custom properties on the loading indicator itself.
+ *
+ * If you really want to change how this looks as part of your custom theme,
+ * you can override the `border-radius` and `border` then set either a
+ * background image, or use `content: "\"` (e.g. `content: "\f1ce"`)
+ * and `font-family: 'Font Awesome 5 Free'` to set an FA icon if you'd rather.
+ *
+ * ### Attrs
+ *
+ * - `containerClassName` Class name(s) to apply to the indicator's parent
+ * - `className` Class name(s) to apply to the indicator itself
+ * - `size` Size of the loading indicator
+ * - `containerAttrs` Optional attrs to be applied to the container DOM element
+ *
+ * All other attrs will be assigned as attributes on the DOM element.
+ */
+export default class LoadingIndicator extends Component {
+ view() {
+ const { size, ...attrs } = this.attrs;
+
+ attrs.className = classList({ LoadingIndicator: true, [attrs.className || '']: true });
+ attrs.containerClassName = classList({ 'LoadingIndicator-container': true, [attrs.containerClassName || '']: true });
+
+ return (
+
+ );
+ }
+}
diff --git a/less/common/Checkbox.less b/less/common/Checkbox.less
index 1b1b29613..a7dbac58b 100644
--- a/less/common/Checkbox.less
+++ b/less/common/Checkbox.less
@@ -15,13 +15,9 @@
float: left;
margin-left: -65px;
margin-top: -4px;
-
- .LoadingIndicator {
- display: inline-block;
- margin-left: 20px;
- }
}
}
+
.Checkbox--switch .Checkbox-display {
width: 50px;
height: 28px;
@@ -31,8 +27,28 @@
background: @control-bg;
.transition(background-color 0.2s);
+ .LoadingIndicator {
+ --size: 22px !important;
+
+ &-container {
+ height: 22px;
+ }
+ }
+
.on& {
background: #58a400;
+
+ .LoadingIndicator-container {
+ // Show loading indicator over the switch button
+ justify-content: flex-end;
+ }
+ }
+
+ .off& {
+ .LoadingIndicator-container {
+ // Show loading indicator over the switch button
+ justify-content: flex-start;
+ }
}
&:before {
diff --git a/less/common/LoadingIndicator.less b/less/common/LoadingIndicator.less
index 3f53505a3..0446e5f1a 100644
--- a/less/common/LoadingIndicator.less
+++ b/less/common/LoadingIndicator.less
@@ -2,13 +2,58 @@
// Loading Indicators
.LoadingIndicator {
- position: relative;
- color: @muted-color;
+ @spin-time: 750ms;
+ --size: 24px;
+ --thickness: 2px;
+
+ &-container[data-size="large"] & {
+ --size: 32px;
+ --thickness: 3px;
+ }
+
+ &-container[data-size="tiny"] & {
+ --size: 18px;
+ }
+
+ // Use the value of `color` to maintain backwards compatibility
+ border-color: currentColor;
+ border-width: var(--thickness);
+ border-style: solid;
+ border-top-color: transparent;
+ border-radius: 50%;
+
+ width: var(--size);
+ height: var(--size);
+
+ animation: spin @spin-time linear infinite;
+
+ // container around the spinner
+ // Used for positioning
+ &-container {
+ color: @muted-color;
+
+ // Center vertically and horizontally
+ // Allows people to set `height` and it'll stay centered within the new height
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &--block {
+ height: 100px;
+ }
+
+ &--inline {
+ display: inline-block;
+ }
+ }
}
-.LoadingIndicator--inline {
- display: inline-block;
- width: 25px;
-}
-.LoadingIndicator--block {
- height: 100px;
+
+@keyframes spin {
+ from {
+ transform: rotate(0);
+ }
+
+ to {
+ transform: rotate(1turn);
+ }
}
diff --git a/less/forum/ActivityPage.less b/less/forum/ActivityPage.less
index feea2b20a..d051c753e 100644
--- a/less/forum/ActivityPage.less
+++ b/less/forum/ActivityPage.less
@@ -2,7 +2,7 @@
text-align: center;
margin-top: 10px;
- .LoadingIndicator {
+ .LoadingIndicator-container {
height: 46px;
}
}
diff --git a/less/forum/DiscussionList.less b/less/forum/DiscussionList.less
index f6a0d768d..2ca828234 100644
--- a/less/forum/DiscussionList.less
+++ b/less/forum/DiscussionList.less
@@ -10,9 +10,10 @@
.DiscussionList-loadMore {
text-align: center;
margin-top: 10px;
-}
-.DiscussionList-loadMore .LoadingIndicator {
- height: 46px;
+
+ .LoadingIndicator-container {
+ height: 46px;
+ }
}
@media @phone {