mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
refactored media components
This commit is contained in:
parent
b551fc44ea
commit
d757b74fd0
9 changed files with 6 additions and 210 deletions
|
@ -1,135 +0,0 @@
|
||||||
import { FC, MouseEventHandler, useCallback, useMemo, useState } from 'react';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import { Icon } from '~/components/common/Icon';
|
|
||||||
import { ImageWithSSRLoad } from '~/components/common/ImageWithSSRLoad';
|
|
||||||
import { LoaderCircle } from '~/components/common/LoaderCircle';
|
|
||||||
import { DEFAULT_DOMINANT_COLOR } from '~/constants/node';
|
|
||||||
import { imagePresets } from '~/constants/urls';
|
|
||||||
import { useResizeHandler } from '~/hooks/dom/useResizeHandler';
|
|
||||||
import { IFile } from '~/types';
|
|
||||||
import { getURL } from '~/utils/dom';
|
|
||||||
|
|
||||||
import styles from './styles.module.scss';
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
file: IFile;
|
|
||||||
color?: string;
|
|
||||||
onLoad?: () => void;
|
|
||||||
onClick?: MouseEventHandler;
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_WIDTH = 1920;
|
|
||||||
const DEFAULT_HEIGHT = 1020;
|
|
||||||
|
|
||||||
const ImagePreloader: FC<IProps> = ({
|
|
||||||
file,
|
|
||||||
color,
|
|
||||||
onLoad,
|
|
||||||
onClick,
|
|
||||||
className,
|
|
||||||
}) => {
|
|
||||||
const [maxHeight, setMaxHeight] = useState(0);
|
|
||||||
const [loaded, setLoaded] = useState(false);
|
|
||||||
const [hasError, setHasError] = useState(false);
|
|
||||||
|
|
||||||
const onImageLoad = useCallback(() => {
|
|
||||||
setLoaded(true);
|
|
||||||
setHasError(false);
|
|
||||||
|
|
||||||
if (onLoad) {
|
|
||||||
onLoad();
|
|
||||||
}
|
|
||||||
}, [setLoaded, onLoad]);
|
|
||||||
|
|
||||||
const onResize = useCallback(() => {
|
|
||||||
setMaxHeight(window.innerHeight - 140);
|
|
||||||
}, [setMaxHeight]);
|
|
||||||
|
|
||||||
const onError = useCallback(() => {
|
|
||||||
setHasError(true);
|
|
||||||
}, [setHasError]);
|
|
||||||
|
|
||||||
const [width, height] = useMemo(
|
|
||||||
() => [
|
|
||||||
file?.metadata?.width || DEFAULT_WIDTH,
|
|
||||||
file?.metadata?.height || DEFAULT_HEIGHT,
|
|
||||||
],
|
|
||||||
[file],
|
|
||||||
);
|
|
||||||
|
|
||||||
useResizeHandler(onResize);
|
|
||||||
|
|
||||||
const estimatedWidth = (width * maxHeight) / height;
|
|
||||||
const fill = color && color !== DEFAULT_DOMINANT_COLOR ? color : '#222222';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<svg
|
|
||||||
viewBox={`0 0 ${width} ${height}`}
|
|
||||||
className={classNames(styles.preview, { [styles.is_loaded]: loaded })}
|
|
||||||
style={{
|
|
||||||
maxHeight: maxHeight,
|
|
||||||
width: estimatedWidth,
|
|
||||||
}}
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
<defs>
|
|
||||||
<filter id="f1" x="0" y="0">
|
|
||||||
<feGaussianBlur in="SourceGraphic" stdDeviation="30" />
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
|
|
||||||
<g filter="url(#f1)">
|
|
||||||
<rect
|
|
||||||
fill={fill}
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
stroke="none"
|
|
||||||
rx="8"
|
|
||||||
ry="8"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{!hasError && (
|
|
||||||
<image
|
|
||||||
xlinkHref={getURL(file, imagePresets['300'])}
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
onLoad={onLoad}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<ImageWithSSRLoad
|
|
||||||
className={classNames(
|
|
||||||
styles.image,
|
|
||||||
{ [styles.is_loaded]: loaded },
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
src={getURL(file, imagePresets['1600'])}
|
|
||||||
alt=""
|
|
||||||
key={file.id}
|
|
||||||
onLoad={onImageLoad}
|
|
||||||
style={{ maxHeight }}
|
|
||||||
onClick={onClick}
|
|
||||||
onError={onError}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{!loaded && !hasError && (
|
|
||||||
<LoaderCircle className={styles.icon} size={64} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasError && (
|
|
||||||
<div className={styles.error}>
|
|
||||||
<div className={styles.error__text}>Не удалось получить картинку</div>
|
|
||||||
<Icon icon="warn" size={64} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { ImagePreloader };
|
|
|
@ -1,67 +0,0 @@
|
||||||
@import 'src/styles/variables.scss';
|
|
||||||
|
|
||||||
img.image {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
|
|
||||||
&.is_loaded {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
opacity: 1;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview {
|
|
||||||
border-radius: $radius;
|
|
||||||
|
|
||||||
&.is_loaded {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: absolute;
|
|
||||||
right: 30px;
|
|
||||||
bottom: 40px;
|
|
||||||
opacity: 0.4;
|
|
||||||
|
|
||||||
@include tablet {
|
|
||||||
right: 5px;
|
|
||||||
bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
fill: currentColor;
|
|
||||||
|
|
||||||
@include tablet {
|
|
||||||
transform: scale(0.6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
position: absolute;
|
|
||||||
right: 30px;
|
|
||||||
bottom: 40px;
|
|
||||||
opacity: 0.4;
|
|
||||||
color: $color_offline;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
max-width: 200px;
|
|
||||||
text-align: right;
|
|
||||||
margin-right: $gap;
|
|
||||||
font: $font_16_semibold;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
|
||||||
import { AudioPlayer } from '~/components/media/AudioPlayer';
|
import { AudioPlayer } from '~/components/common/AudioPlayer';
|
||||||
import { NodeComponentProps } from '~/constants/node';
|
import { NodeComponentProps } from '~/constants/node';
|
||||||
import { useNodeAudios } from '~/hooks/node/useNodeAudios';
|
import { useNodeAudios } from '~/hooks/node/useNodeAudios';
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,15 @@ const SettingsMenu: VFC<SettingsMenuProps> = () => (
|
||||||
<Group>
|
<Group>
|
||||||
<VerticalMenu className={styles.menu}>
|
<VerticalMenu className={styles.menu}>
|
||||||
<Link href={URLS.SETTINGS.BASE} passHref>
|
<Link href={URLS.SETTINGS.BASE} passHref>
|
||||||
<VerticalMenu.Item onClick={console.log}>Настройки</VerticalMenu.Item>
|
<VerticalMenu.Item>Настройки</VerticalMenu.Item>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link href={URLS.SETTINGS.NOTES} passHref>
|
<Link href={URLS.SETTINGS.NOTES} passHref>
|
||||||
<VerticalMenu.Item onClick={console.log}>Заметки</VerticalMenu.Item>
|
<VerticalMenu.Item>Заметки</VerticalMenu.Item>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link href={URLS.SETTINGS.TRASH} passHref>
|
<Link href={URLS.SETTINGS.TRASH} passHref>
|
||||||
<VerticalMenu.Item onClick={console.log}>
|
<VerticalMenu.Item>Удалённые посты</VerticalMenu.Item>
|
||||||
Удалённые посты
|
|
||||||
</VerticalMenu.Item>
|
|
||||||
</Link>
|
</Link>
|
||||||
</VerticalMenu>
|
</VerticalMenu>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { FC, useMemo } from 'react';
|
import { FC, useMemo } from 'react';
|
||||||
|
|
||||||
import { AudioPlayer } from '~/components/media/AudioPlayer';
|
import { AudioPlayer } from '~/components/common/AudioPlayer';
|
||||||
import { AudioUpload } from '~/components/upload/AudioUpload';
|
import { AudioUpload } from '~/components/upload/AudioUpload';
|
||||||
import { UploadStatus } from '~/store/uploader/UploaderStore';
|
import { UploadStatus } from '~/store/uploader/UploaderStore';
|
||||||
import { IFile } from '~/types';
|
import { IFile } from '~/types';
|
||||||
|
|
|
@ -10,8 +10,8 @@ import {
|
||||||
|
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import { AudioPlayer } from '~/components/common/AudioPlayer';
|
||||||
import { Group } from '~/components/common/Group';
|
import { Group } from '~/components/common/Group';
|
||||||
import { AudioPlayer } from '~/components/media/AudioPlayer';
|
|
||||||
import { UploadType } from '~/constants/uploads';
|
import { UploadType } from '~/constants/uploads';
|
||||||
import { IComment, IFile } from '~/types';
|
import { IComment, IFile } from '~/types';
|
||||||
import { formatCommentText, getPrettyDate } from '~/utils/dom';
|
import { formatCommentText, getPrettyDate } from '~/utils/dom';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue