diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js
index b7360bae47..d1dde45b1a 100644
--- a/app/javascript/flavours/glitch/components/media_gallery.js
+++ b/app/javascript/flavours/glitch/components/media_gallery.js
@@ -7,6 +7,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { isIOS } from 'flavours/glitch/util/is_mobile';
import classNames from 'classnames';
import { autoPlayGif, displayMedia } from 'flavours/glitch/util/initial_state';
+import { decode } from 'blurhash';
const messages = defineMessages({
hidden: {
@@ -41,6 +42,7 @@ class Item extends React.PureComponent {
letterbox: PropTypes.bool,
onClick: PropTypes.func.isRequired,
displayWidth: PropTypes.number,
+ visible: PropTypes.bool.isRequired,
};
static defaultProps = {
@@ -49,6 +51,10 @@ class Item extends React.PureComponent {
size: 1,
};
+ state = {
+ loaded: false,
+ };
+
handleMouseEnter = (e) => {
if (this.hoverToPlay()) {
e.target.play();
@@ -82,8 +88,40 @@ class Item extends React.PureComponent {
e.stopPropagation();
}
+ componentDidMount () {
+ if (this.props.attachment.get('blurhash')) {
+ this._decode();
+ }
+ }
+
+ componentDidUpdate (prevProps) {
+ if (prevProps.attachment.get('blurhash') !== this.props.attachment.get('blurhash') && this.props.attachment.get('blurhash')) {
+ this._decode();
+ }
+ }
+
+ _decode () {
+ const hash = this.props.attachment.get('blurhash');
+ const pixels = decode(hash, 32, 32);
+
+ if (pixels) {
+ const ctx = this.canvas.getContext('2d');
+ const imageData = new ImageData(pixels, 32, 32);
+
+ ctx.putImageData(imageData, 0, 0);
+ }
+ }
+
+ setCanvasRef = c => {
+ this.canvas = c;
+ }
+
+ handleImageLoad = () => {
+ this.setState({ loaded: true });
+ }
+
render () {
- const { attachment, index, size, standalone, letterbox, displayWidth } = this.props;
+ const { attachment, index, size, standalone, letterbox, displayWidth, visible } = this.props;
let width = 50;
let height = 100;
@@ -136,12 +174,20 @@ class Item extends React.PureComponent {
let thumbnail = '';
- if (attachment.get('type') === 'image') {
+ if (attachment.get('type') === 'unknown') {
+ return (
+
+ );
+ } else if (attachment.get('type') === 'image') {
const previewUrl = attachment.get('preview_url');
const previewWidth = attachment.getIn(['meta', 'small', 'width']);
- const originalUrl = attachment.get('url');
- const originalWidth = attachment.getIn(['meta', 'original', 'width']);
+ const originalUrl = attachment.get('url');
+ const originalWidth = attachment.getIn(['meta', 'original', 'width']);
const hasSize = typeof originalWidth === 'number' && typeof previewWidth === 'number';
@@ -168,6 +214,7 @@ class Item extends React.PureComponent {
alt={attachment.get('description')}
title={attachment.get('description')}
style={{ objectPosition: letterbox ? null : `${x}% ${y}%` }}
+ onLoad={this.handleImageLoad}
/>
);
@@ -197,7 +244,8 @@ class Item extends React.PureComponent {
return (
- {thumbnail}
+
+ {visible && thumbnail}
);
}
@@ -257,6 +305,7 @@ export default class MediaGallery extends React.PureComponent {
this.node = node;
if (node && node.offsetWidth && node.offsetWidth != this.state.width) {
if (this.props.cacheWidth) this.props.cacheWidth(node.offsetWidth);
+
this.setState({
width: node.offsetWidth,
});
@@ -275,7 +324,7 @@ export default class MediaGallery extends React.PureComponent {
const width = this.state.width || defaultWidth;
- let children;
+ let children, spoilerButton;
const style = {};
@@ -289,40 +338,32 @@ export default class MediaGallery extends React.PureComponent {
return ();
}
- if (!visible) {
- let warning = ;
+ if (this.isStandaloneEligible()) {
+ children = ;
+ } else {
+ children = media.take(4).map((attachment, i) => );
+ }
- children = (
-