slate/components/core/SlateMediaObjectPreview.js

278 lines
7.7 KiB
JavaScript
Raw Normal View History

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";
import * as Utilities from "~/common/utilities";
2020-09-01 02:09:57 +03:00
import * as SVG from "~/common/svg";
2020-12-09 07:22:17 +03:00
import * as Strings from "~/common/strings";
2020-08-09 01:19:35 +03:00
2020-11-30 08:24:22 +03:00
import { css } from "@emotion/react";
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";
2021-04-08 22:00:09 +03:00
import FontObjectPreview from "~/components/core/FontFrame/Views/FontObjectPreview";
2020-08-09 01:19:35 +03:00
2020-10-01 03:41:53 +03:00
const STYLES_IMAGE_CONTAINER = css`
2020-12-11 05:59:17 +03:00
background-color: ${Constants.system.white};
2020-10-01 03:41:53 +03:00
width: 100%;
height: 100%;
background-size: cover;
background-position: 50% 50%;
2021-01-21 09:26:02 +03:00
@media (max-width: ${Constants.sizes.mobile}px) {
border-radius: 8px;
}
2020-10-01 03:41:53 +03:00
`;
2020-08-09 01:19:35 +03:00
const STYLES_IMAGE = css`
2020-12-11 05:59:17 +03:00
background-color: ${Constants.system.white};
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-12-11 05:59:17 +03:00
max-width: 100%;
max-height: 100%;
2020-08-09 01:19:35 +03:00
`;
2020-08-22 12:32:40 +03:00
const STYLES_ENTITY = css`
2020-12-09 07:22:17 +03:00
position: relative;
2020-08-09 01:19:35 +03:00
height: 100%;
width: 100%;
2021-07-07 22:58:14 +03:00
border: 1px solid ${Constants.semantic.bgLight};
2020-10-05 00:30:28 +03:00
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`
2020-12-09 07:22:17 +03:00
width: calc(100% - 32px);
2020-09-01 02:09:57 +03:00
margin-top: 8px;
overflow: hidden;
2020-12-09 07:22:17 +03:00
text-overflow: ellipsis;
white-space: nowrap;
2021-07-07 22:24:01 +03:00
color: ${Constants.semantic.textGray};
2020-12-09 07:22:17 +03:00
font-size: 16px;
2020-12-06 06:15:26 +03:00
font-family: ${Constants.font.medium};
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%;
overflow: hidden;
`;
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: 70,
2020-09-05 07:45:50 +03:00
};
2020-10-05 00:30:28 +03:00
state = {
showImage: false,
error: false,
};
2020-11-30 02:47:08 +03:00
componentDidMount = () => {
this.setImage();
2020-11-30 02:47:08 +03:00
};
componentDidUpdate = (prevProps) => {
if (prevProps.coverImage?.cid !== this.props.coverImage?.cid) {
this.setImage();
2020-11-30 02:47:08 +03:00
}
};
setImage = () => {
let type = this.props.file.data?.type;
let coverImage = this.props.file.data?.coverImage;
let url;
if (type && Validations.isPreviewableImage(type)) {
url = Strings.getURLfromCID(this.props.file.cid);
} else if (coverImage) {
url = Strings.getURLfromCID(coverImage.cid);
}
if (url) {
const img = new Image();
img.onload = () => this.setState({ showImage: true });
img.src = url;
}
2020-10-05 00:30:28 +03:00
};
2020-08-09 01:19:35 +03:00
render() {
const file = this.props.file;
const type = this.props.file.data?.type;
const coverImage = this.props.file.data?.coverImage;
2021-07-07 23:50:57 +03:00
let url = Utilities.getImageUrlIfExists(file);
2021-07-07 23:50:57 +03:00
2020-11-30 02:47:08 +03:00
if (url) {
const blurhash =
file.data.blurhash && isBlurhashValid(file.data?.blurhash)
? file.data?.blurhash
: coverImage?.data.blurhash && isBlurhashValid(coverImage?.data.blurhash)
? coverImage?.data.blurhash
2020-11-30 02:47:08 +03:00
: null;
if (this.state.error) {
return (
<div
css={STYLES_ENTITY}
style={{
...this.props.imageStyle,
2021-07-07 22:58:14 +03:00
backgroundColor: Constants.semantic.bgLight,
2020-11-30 02:47:08 +03:00
}}
>
<SVG.FileNotFound height="24px" />
{this.props.iconOnly ? null : <div css={STYLES_TITLE}>File not found</div>}
</div>
);
}
2020-10-01 03:41:53 +03:00
if (this.props.centeredImage) {
return (
2020-10-05 00:30:28 +03:00
<React.Fragment>
2021-01-21 04:07:40 +03:00
{this.state.showImage || !blurhash ? (
2020-10-05 00:30:28 +03:00
<div
css={STYLES_IMAGE_CONTAINER}
style={{
backgroundImage: `url(${url})`,
...this.props.imageStyle,
}}
/>
2021-01-21 04:07:40 +03:00
) : (
2020-10-05 00:30:28 +03:00
<div css={STYLES_BLUR_CONTAINER}>
<Blurhash
2020-11-30 02:47:08 +03:00
hash={blurhash}
height="100%"
width="100%"
style={this.props.imageStyle}
2020-10-05 00:30:28 +03:00
resolutionX={32}
resolutionY={32}
punch={1}
/>
</div>
)}
</React.Fragment>
2020-10-01 03:41:53 +03:00
);
}
2020-10-05 00:30:28 +03:00
return (
<React.Fragment>
2021-01-21 04:07:40 +03:00
{this.state.showImage || !blurhash ? (
2020-10-05 00:30:28 +03:00
<img
css={STYLES_IMAGE}
2020-11-30 02:47:08 +03:00
style={{
...this.props.imageStyle,
}}
2020-10-05 00:30:28 +03:00
src={url}
/>
2021-01-21 04:07:40 +03:00
) : (
2020-10-05 00:30:28 +03:00
<Blurhash
2020-11-30 02:47:08 +03:00
hash={blurhash}
width="100%"
height="100%"
2020-10-05 00:30:28 +03:00
resolutionX={32}
resolutionY={32}
punch={1}
/>
)}
</React.Fragment>
);
2020-09-18 06:40:10 +03:00
}
let name = (file.data?.name || file.filename).substring(0, this.charCap);
let extension = Strings.getFileExtension(file.filename);
2020-12-09 07:22:17 +03:00
if (extension && extension.length) {
extension = extension.toUpperCase();
}
2020-11-11 04:44:21 +03:00
let element = (
<FileTypeIcon
2021-07-07 23:50:57 +03:00
file={file}
2020-12-09 07:22:17 +03:00
height={this.props.previewPanel ? "26px" : "20px"}
2021-07-07 22:24:01 +03:00
style={{ color: Constants.semantic.textGray }}
2020-11-11 04:44:21 +03:00
/>
);
2021-05-04 15:31:12 +03:00
if (Validations.isFontFile(file.filename)) {
2021-04-08 22:00:09 +03:00
return (
<article
css={STYLES_ENTITY}
style={{
...this.props.style,
2021-07-07 22:18:11 +03:00
border: this.props.previewPanel ? `1px solid ${Constants.semantic.bgLight}` : "auto",
2021-04-08 22:00:09 +03:00
}}
>
<FontObjectPreview
2021-04-19 22:30:11 +03:00
cid={file.cid}
2021-04-08 22:00:09 +03:00
fallback={
<div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
<img
src="https://slate.textile.io/ipfs/bafkreib5mnvds3cpe7ot7ibrakmrnja2hv5tast3giiarpl5nun7jpdt5m"
alt=""
height={this.props.previewPanel ? "80" : "64"}
/>
<div style={{ position: "absolute" }}>{element}</div>
</div>
}
/>
2021-04-19 22:30:11 +03:00
{name && !this.props.iconOnly && !this.props.previewPanel ? (
2021-04-08 22:00:09 +03:00
<div style={{ position: "absolute", bottom: 16, left: 16, width: "inherit" }}>
2021-04-19 22:30:11 +03:00
<div css={STYLES_TITLE}>{name}</div>
2021-04-08 22:00:09 +03:00
{extension ? (
<div
css={STYLES_TITLE}
style={{
fontSize: 12,
2021-07-07 22:24:01 +03:00
color: Constants.semantic.textGrayLight,
2021-04-08 22:00:09 +03:00
fontFamily: Constants.font.medium,
}}
>
{extension}
</div>
) : null}
</div>
) : null}
</article>
);
}
2020-11-30 02:47:08 +03:00
return (
<article
css={STYLES_ENTITY}
style={{
...this.props.style,
2021-07-07 22:18:11 +03:00
border: this.props.previewPanel ? `1px solid ${Constants.semantic.bgLight}` : "auto",
2020-11-30 02:47:08 +03:00
}}
>
2020-12-09 07:22:17 +03:00
<div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
<img
src="https://slate.textile.io/ipfs/bafkreib5mnvds3cpe7ot7ibrakmrnja2hv5tast3giiarpl5nun7jpdt5m"
alt=""
height={this.props.previewPanel ? "80" : "64"}
/>
<div style={{ position: "absolute" }}>{element}</div>
</div>
{!this.props.iconOnly && !this.props.previewPanel ? (
2020-12-09 07:22:17 +03:00
<div style={{ position: "absolute", bottom: 16, left: 16, width: "inherit" }}>
<div css={STYLES_TITLE}>{name}</div>
2020-12-09 07:22:17 +03:00
{extension ? (
<div
css={STYLES_TITLE}
style={{
fontSize: 12,
2021-07-07 22:24:01 +03:00
color: Constants.semantic.textGrayLight,
2020-12-09 07:22:17 +03:00
fontFamily: Constants.font.medium,
}}
>
{extension}
</div>
) : null}
</div>
2020-11-30 02:47:08 +03:00
) : null}
</article>
);
2020-08-09 01:19:35 +03:00
}
}