--- /dev/null
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+
+import PngPlayer from './PngPlayer';
+
+const PngDialog = ({ onHide, show, src, title }) => <Modal onHide={onHide} show={show} size="lg">
+ {title ?
+ <Modal.Header closeButton>
+ <Modal.Title>
+ {title}
+ </Modal.Title>
+ </Modal.Header>
+ : null}
+ <Modal.Body>
+ <PngPlayer src={src} />
+ </Modal.Body>
+</Modal>;
+
+PngDialog.propTypes = {
+ onHide: PropTypes.func,
+ show: PropTypes.bool,
+ src: PropTypes.string,
+ title: PropTypes.string,
+};
+
+export default PngDialog;
import React from 'react';
import { useNavigate } from 'react-router-dom';
+import PngDialog from './PngDialog';
+
+const isApng = el => el.nodeName === 'IMG' && el.getAttribute('type') === 'image/apng';
+
+const isLink = el => el.nodeName === 'A';
+
+const canClick = el => {
+ if (isLink(el)) return true;
+ if (isApng(el)) return true;
+ return false;
+};
+
const RawHTML = ({ html }) => {
const navigate = useNavigate();
+ const [apng, setApng] = React.useState(null);
+ const [show, setShow] = React.useState(false);
+ const [title, setTitle] = React.useState(null);
const onClick = e => {
if (e.defaultPrevented) return;
if (e.button !== 0) return;
let el = e.target;
- while (el && el.nodeName !== 'A') {
+ while (el && !canClick(el)) {
el = el.parentNode;
}
if (!el) return;
- if (el.target && el.target !== '_self') return;
- if (el.attributes.download) return;
- if (el.rel && /(?:^|\s+)external(?:\s+|$)/.test(el.rel)) return;
+ if (isLink(el)) {
+ if (el.target && el.target !== '_self') return;
+ if (el.attributes.download) return;
+ if (el.rel && /(?:^|\s+)external(?:\s+|$)/.test(el.rel)) return;
+
+ const href = el.getAttribute('href');
- const href = el.getAttribute('href');
+ if (href.startsWith('#')) return;
+ if (href.startsWith('http')) return;
+ if (href.startsWith('mailto')) return;
+ if (href.startsWith('tel')) return;
- if (href.startsWith('#')) return;
- if (href.startsWith('http')) return;
- if (href.startsWith('mailto')) return;
- if (href.startsWith('tel')) return;
+ el.blur();
+ e.preventDefault();
- el.blur();
- e.preventDefault();
+ setTimeout(() => {
+ // scroll to top on location change
+ scrollTo({ top: 0, behavior: 'smooth' });
+ }, 50);
- setTimeout(() => {
- // scroll to top on location change
- scrollTo({ top: 0, behavior: 'smooth' });
- }, 50);
+ navigate(href);
+ return;
+ }
- navigate(href);
+ if (isApng(el)) {
+ setApng(el.getAttribute('src'));
+ setShow(true);
+ setTitle(el.getAttribute('alt'));
+ }
};
- return <div onClick={onClick} dangerouslySetInnerHTML={{ __html: html }} />;
+ return <>
+ <div className="raw-html" onClick={onClick} dangerouslySetInnerHTML={{ __html: html }} />
+ <PngDialog onHide={() => setShow(false)} show={show} src={apng} title={title} />
+ </>;
};
RawHTML.propTypes = {