about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/javascript/mastodon/features/ui/components/image_loader.js45
-rw-r--r--app/javascript/mastodon/features/ui/components/media_modal.js4
-rw-r--r--app/javascript/styles/components.scss15
-rw-r--r--package.json1
-rw-r--r--yarn.lock4
5 files changed, 57 insertions, 12 deletions
diff --git a/app/javascript/mastodon/features/ui/components/image_loader.js b/app/javascript/mastodon/features/ui/components/image_loader.js
new file mode 100644
index 000000000..af2870517
--- /dev/null
+++ b/app/javascript/mastodon/features/ui/components/image_loader.js
@@ -0,0 +1,45 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class ImageLoader extends React.PureComponent {
+
+  static propTypes = {
+    src: PropTypes.string.isRequired,
+  }
+
+  state = {
+    loading: true,
+    error: false,
+  }
+
+  componentWillMount() {
+    this.loadImage(this.props.src);
+  }
+
+  componentWillReceiveProps(props) {
+    this.loadImage(props.src);
+  }
+
+  loadImage(src) {
+    const image = new Image();
+    image.onerror = () => this.setState({loading: false, error: true});
+    image.onload = () => this.setState({loading: false, error: false});
+    image.src = src;
+    this.lastSrc = src;
+    this.setState({loading: true});
+  }
+
+  render() {
+    const { src } = this.props;
+    const { loading, error } = this.state;
+
+    // TODO: handle image error state
+
+    const imageClass = `image-loader__img ${loading ? 'image-loader__img-loading' : ''}`;
+
+    return <img className={imageClass} src={src} />; // eslint-disable-line jsx-a11y/img-has-alt
+  }
+
+}
+
+export default ImageLoader;
diff --git a/app/javascript/mastodon/features/ui/components/media_modal.js b/app/javascript/mastodon/features/ui/components/media_modal.js
index a8912841b..effa0aea3 100644
--- a/app/javascript/mastodon/features/ui/components/media_modal.js
+++ b/app/javascript/mastodon/features/ui/components/media_modal.js
@@ -3,10 +3,10 @@ import LoadingIndicator from '../../../components/loading_indicator';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import ExtendedVideoPlayer from '../../../components/extended_video_player';
-import ImageLoader from 'react-imageloader';
 import { defineMessages, injectIntl } from 'react-intl';
 import IconButton from '../../../components/icon_button';
 import ImmutablePureComponent from 'react-immutable-pure-component';
+import ImageLoader from './image_loader';
 
 const messages = defineMessages({
   close: { id: 'lightbox.close', defaultMessage: 'Close' },
@@ -73,7 +73,7 @@ class MediaModal extends ImmutablePureComponent {
     }
 
     if (attachment.get('type') === 'image') {
-      content = <ImageLoader src={url} imgProps={{ style: { display: 'block' } }} />;
+      content = <ImageLoader src={url} />;
     } else if (attachment.get('type') === 'gifv') {
       content = <ExtendedVideoPlayer src={url} muted={true} controls={false} />;
     }
diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/components.scss
index 4afbd12cf..e396f04cc 100644
--- a/app/javascript/styles/components.scss
+++ b/app/javascript/styles/components.scss
@@ -1137,13 +1137,13 @@
   }
 }
 
-.transparent-background,
-.imageloader {
-  background: url('../images/void.png');
+.image-loader__img {
+  transition: opacity 0.3s linear;
+  opacity: 1;
 }
 
-.imageloader {
-  display: block;
+.image-loader__img-loading {
+  opacity: 0.7;
 }
 
 .navigation-bar {
@@ -2852,6 +2852,11 @@ button.icon-button.active i.fa-retweet {
     max-width: 80vw;
     max-height: 80vh;
   }
+
+  img {
+    display: block;
+    background: url('../images/void.png') repeat;
+  }
 }
 
 .media-modal__close {
diff --git a/package.json b/package.json
index 92221d8e4..c686e99e7 100644
--- a/package.json
+++ b/package.json
@@ -81,7 +81,6 @@
     "react-addons-perf": "^15.4.2",
     "react-addons-shallow-compare": "^15.5.2",
     "react-dom": "^15.5.4",
-    "react-imageloader": "^2.1.0",
     "react-immutable-proptypes": "^2.1.0",
     "react-immutable-pure-component": "^0.0.4",
     "react-intl": "^2.3.0",
diff --git a/yarn.lock b/yarn.lock
index d3317f59c..5bef1e0b9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5436,10 +5436,6 @@ react-fuzzy@^0.3.3:
     classnames "^2.2.3"
     fuse.js "^2.2.0"
 
-react-imageloader@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/react-imageloader/-/react-imageloader-2.1.0.tgz#a58401970b3282386aeb810c43175165634f6308"
-
 react-immutable-proptypes@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz#023d6f39bb15c97c071e9e60d00d136eac5fa0b4"