[Glitch] Replace repetitive blurhash code with component (#14267)
Port 61c07c3731 to glitch-soc
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
			
			
This commit is contained in:
		
				
					committed by
					
						
						Thibaut Girka
					
				
			
			
				
	
			
			
			
						parent
						
							5054462759
						
					
				
				
					commit
					042c32ea3b
				
			
							
								
								
									
										61
									
								
								app/javascript/flavours/glitch/components/blurhash.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								app/javascript/flavours/glitch/components/blurhash.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
// @ts-check
 | 
			
		||||
 | 
			
		||||
import { decode } from 'blurhash';
 | 
			
		||||
import React, { useRef, useEffect } from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef BlurhashPropsBase
 | 
			
		||||
 * @property {string} hash Hash to render
 | 
			
		||||
 * @property {number} width
 | 
			
		||||
 * Width of the blurred region in pixels. Defaults to 32
 | 
			
		||||
 * @property {number} [height]
 | 
			
		||||
 * Height of the blurred region in pixels. Defaults to width
 | 
			
		||||
 * @property {boolean} [dummy]
 | 
			
		||||
 * Whether dummy mode is enabled. If enabled, nothing is rendered
 | 
			
		||||
 * and canvas left untouched
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** @typedef {JSX.IntrinsicElements['canvas'] & BlurhashPropsBase} BlurhashProps */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that is used to render blurred of blurhash string
 | 
			
		||||
 *
 | 
			
		||||
 * @param {BlurhashProps} param1 Props of the component
 | 
			
		||||
 * @returns Canvas which will render blurred region element to embed
 | 
			
		||||
 */
 | 
			
		||||
function Blurhash({
 | 
			
		||||
  hash,
 | 
			
		||||
  width = 32,
 | 
			
		||||
  height = width,
 | 
			
		||||
  dummy = false,
 | 
			
		||||
  ...canvasProps
 | 
			
		||||
}) {
 | 
			
		||||
  const canvasRef = /** @type {import('react').MutableRefObject<HTMLCanvasElement>} */ (useRef());
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const { current: canvas } = canvasRef;
 | 
			
		||||
    canvas.width = canvas.width; // resets canvas
 | 
			
		||||
 | 
			
		||||
    if (dummy) return;
 | 
			
		||||
 | 
			
		||||
    const pixels = decode(hash, width, height);
 | 
			
		||||
    const ctx = canvas.getContext('2d');
 | 
			
		||||
    const imageData = new ImageData(pixels, width, height);
 | 
			
		||||
 | 
			
		||||
    ctx.putImageData(imageData, 0, 0);
 | 
			
		||||
  }, [dummy, hash, width, height]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <canvas {...canvasProps} ref={canvasRef} width={width} height={height} />
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Blurhash.propTypes = {
 | 
			
		||||
  hash: PropTypes.string.isRequired,
 | 
			
		||||
  width: PropTypes.number,
 | 
			
		||||
  height: PropTypes.number,
 | 
			
		||||
  dummy: PropTypes.bool,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default React.memo(Blurhash);
 | 
			
		||||
@@ -7,8 +7,8 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
			
		||||
import { isIOS } from 'flavours/glitch/util/is_mobile';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/util/initial_state';
 | 
			
		||||
import { decode } from 'blurhash';
 | 
			
		||||
import { debounce } from 'lodash';
 | 
			
		||||
import Blurhash from 'flavours/glitch/components/blurhash';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  hidden: {
 | 
			
		||||
@@ -94,36 +94,6 @@ 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 () {
 | 
			
		||||
    if (!useBlurhash) return;
 | 
			
		||||
 | 
			
		||||
    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 });
 | 
			
		||||
  }
 | 
			
		||||
@@ -186,7 +156,11 @@ class Item extends React.PureComponent {
 | 
			
		||||
      return (
 | 
			
		||||
        <div className={classNames('media-gallery__item', { standalone })} key={attachment.get('id')} style={{ left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }}>
 | 
			
		||||
          <a className='media-gallery__item-thumbnail' href={attachment.get('remote_url') || attachment.get('url')} style={{ cursor: 'pointer' }} title={attachment.get('description')} target='_blank' rel='noopener noreferrer'>
 | 
			
		||||
            <canvas width={32} height={32} ref={this.setCanvasRef} className='media-gallery__preview' />
 | 
			
		||||
            <Blurhash
 | 
			
		||||
              hash={attachment.get('blurhash')}
 | 
			
		||||
              className='media-gallery__preview'
 | 
			
		||||
              dummy={!useBlurhash}
 | 
			
		||||
            />
 | 
			
		||||
          </a>
 | 
			
		||||
        </div>
 | 
			
		||||
      );
 | 
			
		||||
@@ -253,7 +227,13 @@ class Item extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className={classNames('media-gallery__item', { standalone, letterbox })} key={attachment.get('id')} style={{ left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }}>
 | 
			
		||||
        <canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && this.state.loaded })} />
 | 
			
		||||
        <Blurhash
 | 
			
		||||
          hash={attachment.get('blurhash')}
 | 
			
		||||
          dummy={!useBlurhash}
 | 
			
		||||
          className={classNames('media-gallery__preview', {
 | 
			
		||||
            'media-gallery__preview--hidden': visible && this.state.loaded,
 | 
			
		||||
          })}
 | 
			
		||||
        />
 | 
			
		||||
        {visible && thumbnail}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user