Skip to content

Commit ab80ea1

Browse files
Merge pull request matrix-org#4842 from matrix-org/anoa/new_spinner
Add a new spinner design behind a labs flag
2 parents 113dfc5 + 77b618e commit ab80ea1

File tree

13 files changed

+87
-62
lines changed

13 files changed

+87
-62
lines changed

res/css/_common.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,10 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus {
428428
border-radius: 8px;
429429
padding: 0px;
430430
box-shadow: none;
431+
432+
/* Don't show scroll-bars on spinner dialogs */
433+
overflow-x: hidden;
434+
overflow-y: hidden;
431435
}
432436

433437
// TODO: Review mx_GeneralButton usage to see if it can use a different class

res/css/views/elements/_InlineSpinner.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ limitations under the License.
1818
display: inline;
1919
}
2020

21-
.mx_InlineSpinner img {
21+
.mx_InlineSpinner_spin img {
2222
margin: 0px 6px;
2323
vertical-align: -3px;
2424
}

res/css/views/elements/_Spinner.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ limitations under the License.
2323
flex: 1;
2424
}
2525

26+
.mx_Spinner_spin img {
27+
animation: spin 1s linear infinite;
28+
}
29+
30+
@keyframes spin {
31+
100% {
32+
transform: rotate(360deg);
33+
}
34+
}
35+
2636
.mx_MatrixChat_middlePanel .mx_Spinner {
2737
height: auto;
2838
}

res/img/spinner.svg

Lines changed: 3 additions & 0 deletions
Loading

src/components/views/elements/AppTile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { _t } from '../../../languageHandler';
2929
import * as sdk from '../../../index';
3030
import AppPermission from './AppPermission';
3131
import AppWarning from './AppWarning';
32-
import MessageSpinner from './MessageSpinner';
32+
import Spinner from './Spinner';
3333
import WidgetUtils from '../../../utils/WidgetUtils';
3434
import dis from '../../../dispatcher/dispatcher';
3535
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
@@ -740,7 +740,7 @@ export default class AppTile extends React.Component {
740740
if (this.props.show) {
741741
const loadingElement = (
742742
<div className="mx_AppLoading_spinner_fadeIn">
743-
<MessageSpinner msg='Loading...' />
743+
<Spinner message={_t("Loading...")} />
744744
</div>
745745
);
746746
if (!this.state.hasPermissionToLoad) {

src/components/views/elements/InlineSpinner.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ limitations under the License.
1616

1717
import React from "react";
1818
import createReactClass from 'create-react-class';
19+
import {_t} from "../../../languageHandler";
20+
import SettingsStore from "../../../settings/SettingsStore";
1921

2022
export default createReactClass({
2123
displayName: 'InlineSpinner',
@@ -25,9 +27,25 @@ export default createReactClass({
2527
const h = this.props.h || 16;
2628
const imgClass = this.props.imgClassName || "";
2729

30+
let divClass;
31+
let imageSource;
32+
if (SettingsStore.isFeatureEnabled('feature_new_spinner')) {
33+
divClass = "mx_InlineSpinner mx_Spinner_spin";
34+
imageSource = require("../../../../res/img/spinner.svg");
35+
} else {
36+
divClass = "mx_InlineSpinner";
37+
imageSource = require("../../../../res/img/spinner.gif");
38+
}
39+
2840
return (
29-
<div className="mx_InlineSpinner">
30-
<img src={require("../../../../res/img/spinner.gif")} width={w} height={h} className={imgClass} />
41+
<div className={divClass}>
42+
<img
43+
src={imageSource}
44+
width={w}
45+
height={h}
46+
className={imgClass}
47+
aria-label={_t("Loading...")}
48+
/>
3149
</div>
3250
);
3351
},

src/components/views/elements/MessageSpinner.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/components/views/elements/Spinner.js

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,39 @@ limitations under the License.
1616
*/
1717

1818
import React from "react";
19-
import createReactClass from 'create-react-class';
19+
import PropTypes from "prop-types";
20+
import {_t} from "../../../languageHandler";
21+
import SettingsStore from "../../../settings/SettingsStore";
2022

21-
export default createReactClass({
22-
displayName: 'Spinner',
23+
const Spinner = ({w = 32, h = 32, imgClassName, message}) => {
24+
let divClass;
25+
let imageSource;
26+
if (SettingsStore.isFeatureEnabled('feature_new_spinner')) {
27+
divClass = "mx_Spinner mx_Spinner_spin";
28+
imageSource = require("../../../../res/img/spinner.svg");
29+
} else {
30+
divClass = "mx_Spinner";
31+
imageSource = require("../../../../res/img/spinner.gif");
32+
}
2333

24-
render: function() {
25-
const w = this.props.w || 32;
26-
const h = this.props.h || 32;
27-
const imgClass = this.props.imgClassName || "";
28-
return (
29-
<div className="mx_Spinner">
30-
<img src={require("../../../../res/img/spinner.gif")} width={w} height={h} className={imgClass} />
31-
</div>
32-
);
33-
},
34-
});
34+
return (
35+
<div className={divClass}>
36+
{ message && <React.Fragment><div className="mx_Spinner_Msg">{ message}</div>&nbsp;</React.Fragment> }
37+
<img
38+
src={imageSource}
39+
width={w}
40+
height={h}
41+
className={imgClassName}
42+
aria-label={_t("Loading...")}
43+
/>
44+
</div>
45+
);
46+
};
47+
Spinner.propTypes = {
48+
w: PropTypes.number,
49+
h: PropTypes.number,
50+
imgClassName: PropTypes.string,
51+
message: PropTypes.node,
52+
};
53+
54+
export default Spinner;

src/components/views/messages/MAudioBody.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import MFileBody from './MFileBody';
2222
import {MatrixClientPeg} from '../../../MatrixClientPeg';
2323
import { decryptFile } from '../../../utils/DecryptFile';
2424
import { _t } from '../../../languageHandler';
25+
import InlineSpinner from '../elements/InlineSpinner';
2526

2627
export default class MAudioBody extends React.Component {
2728
constructor(props) {
@@ -94,7 +95,7 @@ export default class MAudioBody extends React.Component {
9495
// Not sure how tall the audio player is so not sure how tall it should actually be.
9596
return (
9697
<span className="mx_MAudioBody">
97-
<img src={require("../../../../res/img/spinner.gif")} alt={content.body} width="16" height="16" />
98+
<InlineSpinner />
9899
</span>
99100
);
100101
}

src/components/views/messages/MImageBody.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { decryptFile } from '../../../utils/DecryptFile';
2626
import { _t } from '../../../languageHandler';
2727
import SettingsStore from "../../../settings/SettingsStore";
2828
import MatrixClientContext from "../../../contexts/MatrixClientContext";
29+
import InlineSpinner from '../elements/InlineSpinner';
2930

3031
export default class MImageBody extends React.Component {
3132
static propTypes = {
@@ -365,12 +366,7 @@ export default class MImageBody extends React.Component {
365366

366367
// e2e image hasn't been decrypted yet
367368
if (content.file !== undefined && this.state.decryptedUrl === null) {
368-
placeholder = <img
369-
src={require("../../../../res/img/spinner.gif")}
370-
alt={content.body}
371-
width="32"
372-
height="32"
373-
/>;
369+
placeholder = <InlineSpinner w={32} h={32} />;
374370
} else if (!this.state.imgLoaded) {
375371
// Deliberately, getSpinner is left unimplemented here, MStickerBody overides
376372
placeholder = this.getPlaceholder();

0 commit comments

Comments
 (0)