2020-08-09 01:19:35 +03:00
|
|
|
import * as React from "react";
|
|
|
|
import * as Constants from "~/common/constants";
|
2020-11-11 04:44:21 +03:00
|
|
|
import * as Validations from "~/common/validations";
|
2020-09-01 02:09:57 +03:00
|
|
|
import * as SVG from "~/common/svg";
|
2020-08-09 01:19:35 +03:00
|
|
|
|
2020-11-04 20:55:48 +03:00
|
|
|
import { css } from "@emotion/core";
|
2020-09-18 07:28:32 +03:00
|
|
|
import { FileTypeIcon } from "~/components/core/FileTypeIcon";
|
2020-10-05 00:30:28 +03:00
|
|
|
import { Blurhash } from "react-blurhash";
|
|
|
|
import { isBlurhashValid } from "blurhash";
|
2020-08-09 01:19:35 +03:00
|
|
|
|
2020-10-01 03:41:53 +03:00
|
|
|
const STYLES_IMAGE_CONTAINER = css`
|
|
|
|
background-color: ${Constants.system.foreground};
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
background-size: cover;
|
|
|
|
background-position: 50% 50%;
|
|
|
|
`;
|
|
|
|
|
2020-08-09 01:19:35 +03:00
|
|
|
const STYLES_IMAGE = css`
|
2020-09-10 06:28:48 +03:00
|
|
|
background-color: ${Constants.system.foreground};
|
2020-08-09 01:19:35 +03:00
|
|
|
display: block;
|
2020-08-22 20:30:03 +03:00
|
|
|
pointer-events: none;
|
2020-08-27 07:24:49 +03:00
|
|
|
transition: 200ms ease all;
|
2020-08-09 01:19:35 +03:00
|
|
|
`;
|
|
|
|
|
2020-08-22 12:32:40 +03:00
|
|
|
const STYLES_ENTITY = css`
|
2020-08-09 01:19:35 +03:00
|
|
|
height: 100%;
|
|
|
|
width: 100%;
|
2020-10-05 00:30:28 +03:00
|
|
|
border: 1px solid ${Constants.system.gray};
|
|
|
|
background-color: ${Constants.system.white};
|
2020-08-09 01:19:35 +03:00
|
|
|
font-size: 24px;
|
|
|
|
display: flex;
|
2020-09-01 02:09:57 +03:00
|
|
|
flex-direction: column;
|
2020-08-09 01:19:35 +03:00
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
cursor: pointer;
|
2020-08-22 20:30:03 +03:00
|
|
|
pointer-events: none;
|
2020-09-01 02:09:57 +03:00
|
|
|
padding: 8px;
|
2020-09-04 07:16:19 +03:00
|
|
|
font-size: 0.9rem;
|
2020-09-01 02:09:57 +03:00
|
|
|
`;
|
|
|
|
|
|
|
|
const STYLES_TITLE = css`
|
|
|
|
width: 100%;
|
|
|
|
text-align: center;
|
|
|
|
margin-top: 8px;
|
|
|
|
overflow: hidden;
|
|
|
|
word-break: break-all;
|
2020-09-05 07:45:50 +03:00
|
|
|
text-overflow: break-word;
|
2020-08-09 01:19:35 +03:00
|
|
|
`;
|
|
|
|
|
2020-10-05 00:30:28 +03:00
|
|
|
const STYLES_BLUR_CONTAINER = css`
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
border-radius: 8px;
|
|
|
|
overflow: hidden;
|
|
|
|
`;
|
|
|
|
|
|
|
|
let preload = (url) =>
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
const img = new Image();
|
|
|
|
img.onload = resolve(img);
|
|
|
|
img.onerror = reject;
|
|
|
|
img.src = url.replace("https://undefined", "https://");
|
|
|
|
});
|
|
|
|
|
2020-08-09 01:19:35 +03:00
|
|
|
export default class SlateMediaObjectPreview extends React.Component {
|
2020-09-05 07:45:50 +03:00
|
|
|
static defaultProps = {
|
|
|
|
charCap: 30,
|
|
|
|
};
|
|
|
|
|
2020-10-05 00:30:28 +03:00
|
|
|
state = {
|
|
|
|
showImage: false,
|
|
|
|
error: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
componentDidMount = async () => {
|
2020-11-11 04:44:21 +03:00
|
|
|
if (this.props.type && Validations.isPreviewableImage(this.props.type)) {
|
2020-10-05 00:30:28 +03:00
|
|
|
try {
|
|
|
|
let img = await preload(this.props.url);
|
|
|
|
if (!img.height && !img.width) {
|
|
|
|
this.setState({ showImage: false, error: true });
|
|
|
|
}
|
|
|
|
this.setState({ showImage: true, error: false });
|
|
|
|
} catch (error) {
|
|
|
|
this.setState({ showImage: false, error: true });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-09 01:19:35 +03:00
|
|
|
render() {
|
2020-08-25 21:39:14 +03:00
|
|
|
// NOTE(jim):
|
|
|
|
// This is a hack to catch this undefined case I don't want to track down yet.
|
|
|
|
const url = this.props.url.replace("https://undefined", "https://");
|
2020-10-05 00:30:28 +03:00
|
|
|
|
2020-09-01 02:09:57 +03:00
|
|
|
const title =
|
2020-09-05 07:45:50 +03:00
|
|
|
this.props.title && this.props.title.length > this.props.charCap
|
|
|
|
? this.props.title.substring(0, this.props.charCap) + "..."
|
2020-09-01 02:09:57 +03:00
|
|
|
: this.props.title;
|
2020-08-25 21:39:14 +03:00
|
|
|
|
2020-11-11 04:44:21 +03:00
|
|
|
if (this.props.type && Validations.isPreviewableImage(this.props.type)) {
|
2020-11-04 20:55:48 +03:00
|
|
|
let blurhash = this.props.blurhash && isBlurhashValid(this.props.blurhash);
|
2020-10-01 03:41:53 +03:00
|
|
|
if (this.props.centeredImage) {
|
|
|
|
return (
|
2020-10-05 00:30:28 +03:00
|
|
|
<React.Fragment>
|
|
|
|
{this.state.error ? (
|
|
|
|
<div
|
|
|
|
css={STYLES_ENTITY}
|
|
|
|
style={{
|
|
|
|
...this.props.imageStyle,
|
|
|
|
backgroundColor: Constants.system.foreground,
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<SVG.FileNotFound height="24px" />
|
2020-11-04 20:55:48 +03:00
|
|
|
{this.props.iconOnly ? null : <div css={STYLES_TITLE}>File not found</div>}
|
2020-10-05 00:30:28 +03:00
|
|
|
</div>
|
|
|
|
) : this.state.showImage ? (
|
|
|
|
<div
|
|
|
|
css={STYLES_IMAGE_CONTAINER}
|
|
|
|
style={{
|
|
|
|
backgroundImage: `url(${url})`,
|
|
|
|
...this.props.imageStyle,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
) : blurhash ? (
|
|
|
|
<div css={STYLES_BLUR_CONTAINER}>
|
|
|
|
<Blurhash
|
|
|
|
hash={this.props.blurhash}
|
|
|
|
style={{
|
|
|
|
height: "100%",
|
|
|
|
width: "100%",
|
|
|
|
...this.props.imageStyle,
|
|
|
|
}}
|
|
|
|
resolutionX={32}
|
|
|
|
resolutionY={32}
|
|
|
|
punch={1}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div css={STYLES_IMAGE_CONTAINER} style={this.props.imageStyle} />
|
|
|
|
)}
|
|
|
|
</React.Fragment>
|
2020-10-01 03:41:53 +03:00
|
|
|
);
|
|
|
|
}
|
2020-10-05 00:30:28 +03:00
|
|
|
return (
|
|
|
|
<React.Fragment>
|
|
|
|
{this.state.error ? (
|
|
|
|
<div
|
|
|
|
css={STYLES_ENTITY}
|
|
|
|
style={{ ...this.props.imageStyle, backgroundColor: "#F2F2F2" }}
|
|
|
|
>
|
|
|
|
<SVG.FileNotFound height="24px" />
|
2020-11-04 20:55:48 +03:00
|
|
|
{this.props.iconOnly ? null : <div css={STYLES_TITLE}>File not found</div>}
|
2020-10-05 00:30:28 +03:00
|
|
|
</div>
|
|
|
|
) : this.state.showImage ? (
|
|
|
|
<img
|
|
|
|
css={STYLES_IMAGE}
|
2020-11-12 00:13:40 +03:00
|
|
|
style={{ maxHeight: "100%", maxWidth: "100%", ...this.props.imageStyle }}
|
2020-10-05 00:30:28 +03:00
|
|
|
src={url}
|
|
|
|
/>
|
|
|
|
) : blurhash ? (
|
|
|
|
<Blurhash
|
|
|
|
hash={this.props.blurhash}
|
|
|
|
style={{
|
|
|
|
height: "100%",
|
|
|
|
width: "100%",
|
|
|
|
...this.props.imageStyle,
|
|
|
|
}}
|
|
|
|
resolutionX={32}
|
|
|
|
resolutionY={32}
|
|
|
|
punch={1}
|
|
|
|
/>
|
|
|
|
) : (
|
2020-11-12 00:13:40 +03:00
|
|
|
<div
|
|
|
|
css={STYLES_IMAGE}
|
|
|
|
style={{ maxHeight: "100%", maxWidth: "100%", ...this.props.imageStyle }}
|
|
|
|
/>
|
2020-10-05 00:30:28 +03:00
|
|
|
)}
|
|
|
|
</React.Fragment>
|
|
|
|
);
|
2020-09-18 06:40:10 +03:00
|
|
|
}
|
|
|
|
|
2020-11-11 04:44:21 +03:00
|
|
|
let element = (
|
|
|
|
<FileTypeIcon
|
|
|
|
type={this.props.type}
|
|
|
|
height={this.props.previewPanel ? "80px" : "24px"}
|
|
|
|
style={this.props.previewPanel ? { color: "#bfbfbf" } : null}
|
|
|
|
/>
|
|
|
|
);
|
2020-09-18 06:40:10 +03:00
|
|
|
|
|
|
|
return (
|
2020-11-11 04:44:21 +03:00
|
|
|
<article
|
|
|
|
css={STYLES_ENTITY}
|
|
|
|
style={{
|
|
|
|
...this.props.style,
|
|
|
|
border: this.props.previewPanel ? `1px solid ${Constants.system.bgGray}` : "auto",
|
|
|
|
}}
|
|
|
|
>
|
2020-09-18 06:40:10 +03:00
|
|
|
<div>{element}</div>
|
2020-11-11 04:44:21 +03:00
|
|
|
{this.props.title && !this.props.iconOnly && !this.props.previewPanel ? (
|
|
|
|
<div css={STYLES_TITLE}>{title}</div>
|
|
|
|
) : null}
|
2020-08-31 21:19:46 +03:00
|
|
|
</article>
|
|
|
|
);
|
2020-08-09 01:19:35 +03:00
|
|
|
}
|
|
|
|
}
|