mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 04:46:40 +07:00
removed obsolete components
This commit is contained in:
parent
eb41e9a8cc
commit
15095b3116
6 changed files with 0 additions and 786 deletions
|
@ -1,35 +0,0 @@
|
||||||
import React, { FC } from 'react';
|
|
||||||
import range from 'ramda/es/range';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import styles from './styles.module.scss';
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
total: number;
|
|
||||||
current: number;
|
|
||||||
loaded?: Record<number, boolean>;
|
|
||||||
onChange: (current: number) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ImageSwitcher: FC<IProps> = ({ total, current, onChange, loaded }) => {
|
|
||||||
if (total <= 1) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.wrap}>
|
|
||||||
<div className={styles.switcher}>
|
|
||||||
{range(0, total).map(item => (
|
|
||||||
<div
|
|
||||||
className={classNames({
|
|
||||||
is_active: item === current,
|
|
||||||
is_loaded: loaded && loaded[item],
|
|
||||||
})}
|
|
||||||
key={item}
|
|
||||||
onClick={() => onChange(item)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { ImageSwitcher };
|
|
|
@ -1,56 +0,0 @@
|
||||||
@import "src/styles/variables";
|
|
||||||
|
|
||||||
.wrap {
|
|
||||||
width: 100%;
|
|
||||||
height: 0;
|
|
||||||
position: relative;
|
|
||||||
z-index: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switcher {
|
|
||||||
position: absolute;
|
|
||||||
// background: darken($content_bg, 2%);
|
|
||||||
background: url('../../../../src/sprites/noise.png') $main_bg_color;
|
|
||||||
display: flex;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
top: -60px;
|
|
||||||
border-radius: 24px;
|
|
||||||
padding: 0 3px;
|
|
||||||
// flex-wrap: wrap;
|
|
||||||
transition: background-color 0.5s;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: opacity 0.25s;
|
|
||||||
opacity: 0.5;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: ' ';
|
|
||||||
display: block;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: inset white 0 0 0 2px;
|
|
||||||
transform: scale(0.5);
|
|
||||||
transition: transform 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:global(.is_active) {
|
|
||||||
&::after {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:global(.is_loaded)::after {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
import React, { FC, useMemo, useState, useEffect, useRef, useCallback } from 'react';
|
|
||||||
import { ImageSwitcher } from '../ImageSwitcher';
|
|
||||||
import styles from './styles.module.scss';
|
|
||||||
import { INode } from '~/redux/types';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { getURL } from '~/utils/dom';
|
|
||||||
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
|
||||||
import { PRESETS } from '~/constants/urls';
|
|
||||||
import * as MODAL_ACTIONS from '~/redux/modal/actions';
|
|
||||||
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
is_loading: boolean;
|
|
||||||
node: INode;
|
|
||||||
layout: {};
|
|
||||||
updateLayout: () => void;
|
|
||||||
modalShowPhotoswipe: typeof MODAL_ACTIONS.modalShowPhotoswipe;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NodeImageBlock: FC<IProps> = ({ node, is_loading, updateLayout, modalShowPhotoswipe }) => {
|
|
||||||
const [is_animated, setIsAnimated] = useState(false);
|
|
||||||
const [current, setCurrent] = useState(0);
|
|
||||||
const [height, setHeight] = useState(window.innerHeight - 150);
|
|
||||||
const [loaded, setLoaded] = useState<Record<number, boolean>>({});
|
|
||||||
const refs = useRef<Record<number, HTMLDivElement>>({});
|
|
||||||
|
|
||||||
const images = useMemo(
|
|
||||||
() =>
|
|
||||||
(node && node.files && node.files.filter(({ type }) => type === UPLOAD_TYPES.IMAGE)) || [],
|
|
||||||
[node]
|
|
||||||
);
|
|
||||||
|
|
||||||
const setRef = useCallback(index => el => (refs.current[index] = el), [refs]);
|
|
||||||
|
|
||||||
const onImageLoad = useCallback(index => () => setLoaded({ ...loaded, [index]: true }), [
|
|
||||||
setLoaded,
|
|
||||||
loaded,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => updateLayout(), [loaded]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!refs || !refs.current[current] || !loaded[current])
|
|
||||||
return setHeight(window.innerHeight - 150);
|
|
||||||
|
|
||||||
const el = refs.current[current];
|
|
||||||
const element_height = el.getBoundingClientRect && el.getBoundingClientRect().height;
|
|
||||||
|
|
||||||
setHeight(element_height);
|
|
||||||
}, [refs, current, loaded]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = setTimeout(() => setIsAnimated(true), 250);
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onOpenPhotoSwipe = useCallback(() => modalShowPhotoswipe(images, current), [
|
|
||||||
modalShowPhotoswipe,
|
|
||||||
images,
|
|
||||||
current,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames(styles.wrap, { is_loading, is_animated })}>
|
|
||||||
<div className={styles.image_container} style={{ height }} onClick={onOpenPhotoSwipe}>
|
|
||||||
{(is_loading || !loaded[0] || !images.length) && (
|
|
||||||
<div className={styles.placeholder}>
|
|
||||||
<LoaderCircle size={72} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{images.map((file, index) => (
|
|
||||||
<div
|
|
||||||
className={classNames(styles.image_wrap, {
|
|
||||||
is_active: index === current && loaded[index],
|
|
||||||
})}
|
|
||||||
ref={setRef(index)}
|
|
||||||
key={file.id}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
className={styles.image}
|
|
||||||
src={getURL(file, PRESETS['1600'])}
|
|
||||||
alt=""
|
|
||||||
key={file.id}
|
|
||||||
onLoad={onImageLoad(index)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ImageSwitcher
|
|
||||||
total={images.length}
|
|
||||||
current={current}
|
|
||||||
onChange={setCurrent}
|
|
||||||
loaded={loaded}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { NodeImageBlock };
|
|
|
@ -1,62 +0,0 @@
|
||||||
@import "src/styles/variables";
|
|
||||||
|
|
||||||
.wrap {
|
|
||||||
padding-bottom: $gap * 2;
|
|
||||||
|
|
||||||
&:global(.is_animated) {
|
|
||||||
.image_container {
|
|
||||||
transition: height 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image_wrap {
|
|
||||||
transition: opacity 0.5s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image_container {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: $panel_radius 0 0 $panel_radius;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
.image {
|
|
||||||
max-height: calc(100vh - 150px);
|
|
||||||
max-width: 100%;
|
|
||||||
opacity: 1;
|
|
||||||
border-radius: $radius;
|
|
||||||
|
|
||||||
@include outer_shadow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image_wrap {
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
touch-action: none;
|
|
||||||
z-index: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&:global(.is_active) {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100vh - 130px);
|
|
||||||
border-radius: $radius;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
|
@ -1,345 +0,0 @@
|
||||||
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
import styles from './styles.module.scss';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
|
||||||
import { INodeComponentProps } from '~/redux/node/constants';
|
|
||||||
import { getURL } from '~/utils/dom';
|
|
||||||
import { PRESETS } from '~/constants/urls';
|
|
||||||
import { throttle } from 'throttle-debounce';
|
|
||||||
import { Icon } from '~/components/input/Icon';
|
|
||||||
import { useArrows } from '~/utils/hooks/keys';
|
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
import { modalShowPhotoswipe } from '~/redux/modal/actions';
|
|
||||||
import { useShallowSelect } from '~/utils/hooks/useShallowSelect';
|
|
||||||
import { selectModal } from '~/redux/modal/selectors';
|
|
||||||
|
|
||||||
interface IProps extends INodeComponentProps {
|
|
||||||
updateLayout?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getX = event =>
|
|
||||||
(event.touches && event.touches.length) || (event.changedTouches && event.changedTouches.length)
|
|
||||||
? (event.touches.length && event.touches[0].clientX) || event.changedTouches[0].clientX
|
|
||||||
: event.clientX;
|
|
||||||
|
|
||||||
const NodeImageSlideBlock: FC<IProps> = ({ node, isLoading, updateLayout = () => {} }) => {
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const { is_shown } = useShallowSelect(selectModal);
|
|
||||||
|
|
||||||
const [current, setCurrent] = useState(0);
|
|
||||||
const [height, setHeight] = useState(window.innerHeight - 143);
|
|
||||||
const [max_height, setMaxHeight] = useState(960);
|
|
||||||
const [loaded, setLoaded] = useState<Record<number, boolean>>({});
|
|
||||||
const refs = useRef<Record<number, HTMLDivElement>>({});
|
|
||||||
const [heights, setHeights] = useState({});
|
|
||||||
|
|
||||||
const [initial_offset, setInitialOffset] = useState(0);
|
|
||||||
const [initial_x, setInitialX] = useState(0);
|
|
||||||
const [offset, setOffset] = useState(0);
|
|
||||||
const [is_dragging, setIsDragging] = useState(false);
|
|
||||||
const [drag_start, setDragStart] = useState(0);
|
|
||||||
|
|
||||||
const slide = useRef<HTMLDivElement>(null);
|
|
||||||
const wrap = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const setHeightThrottled = useCallback(throttle(100, setHeight), [setHeight]);
|
|
||||||
|
|
||||||
const images = useMemo(
|
|
||||||
() =>
|
|
||||||
(node && node.files && node.files.filter(({ type }) => type === UPLOAD_TYPES.IMAGE)) || [],
|
|
||||||
[node.files]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setLoaded({});
|
|
||||||
refs.current = {};
|
|
||||||
}, [images]);
|
|
||||||
|
|
||||||
const updateSizes = useCallback(() => {
|
|
||||||
const values = Object.keys(refs.current).reduce((obj, key) => {
|
|
||||||
const ref = refs.current[key];
|
|
||||||
|
|
||||||
if (!ref || !ref.getBoundingClientRect) return 0;
|
|
||||||
|
|
||||||
return { ...obj, [key]: ref.getBoundingClientRect().height };
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
setHeights(values);
|
|
||||||
}, [refs]);
|
|
||||||
|
|
||||||
const setRef = useCallback(
|
|
||||||
index => el => {
|
|
||||||
refs.current[index] = el;
|
|
||||||
},
|
|
||||||
[refs, heights, setHeights, images]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onImageLoad = useCallback(index => () => setLoaded({ ...loaded, [index]: true }), [
|
|
||||||
setLoaded,
|
|
||||||
loaded,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// update outside hooks
|
|
||||||
useEffect(updateLayout, [loaded, height, images]);
|
|
||||||
useEffect(updateSizes, [refs, current, loaded, images]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const timeout = setTimeout(updateLayout, 300);
|
|
||||||
|
|
||||||
if (!wrap || !wrap.current) return () => clearTimeout(timeout);
|
|
||||||
|
|
||||||
const { width } = wrap.current.getBoundingClientRect();
|
|
||||||
const fallback = window.innerHeight - 143;
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
setHeight(fallback);
|
|
||||||
return () => clearTimeout(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
const selected = Math.abs(-offset / width);
|
|
||||||
|
|
||||||
if (!heights[Math.round(selected)]) {
|
|
||||||
setHeight(fallback);
|
|
||||||
return () => clearTimeout(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
const minimal = Math.min(fallback, 120);
|
|
||||||
|
|
||||||
const prev = Math.max(heights[Math.floor(selected)] || fallback, minimal);
|
|
||||||
const next = Math.max(heights[Math.ceil(selected)] || fallback, minimal);
|
|
||||||
const now = prev - (prev - next) * (selected % 1);
|
|
||||||
|
|
||||||
if (current !== Math.round(selected)) setCurrent(Math.round(selected));
|
|
||||||
|
|
||||||
if (!is_dragging) {
|
|
||||||
setHeight(now);
|
|
||||||
} else {
|
|
||||||
setHeightThrottled(now);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update layout after all manipulations
|
|
||||||
return () => {
|
|
||||||
if (timeout) clearTimeout(timeout);
|
|
||||||
};
|
|
||||||
}, [is_dragging, wrap, offset, heights, max_height, images, isLoading, updateLayout]);
|
|
||||||
|
|
||||||
const onDrag = useCallback(
|
|
||||||
event => {
|
|
||||||
if (
|
|
||||||
!is_dragging ||
|
|
||||||
!slide.current ||
|
|
||||||
!wrap.current ||
|
|
||||||
(event.touches && event.clientY > event.clientX)
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const { width: slide_width } = slide.current.getBoundingClientRect();
|
|
||||||
const { width: wrap_width } = wrap.current.getBoundingClientRect();
|
|
||||||
|
|
||||||
setOffset(
|
|
||||||
Math.min(Math.max(initial_offset + getX(event) - initial_x, wrap_width - slide_width), 0)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[is_dragging, initial_x, setOffset, initial_offset]
|
|
||||||
);
|
|
||||||
|
|
||||||
const normalizeOffset = useCallback(() => {
|
|
||||||
if (!slide.current || !wrap.current) return;
|
|
||||||
|
|
||||||
const { width: wrap_width } = wrap.current.getBoundingClientRect();
|
|
||||||
const { width: slide_width } = slide.current.getBoundingClientRect();
|
|
||||||
|
|
||||||
const shift = (initial_offset - offset) / wrap_width; // percent / 100
|
|
||||||
const diff = initial_offset - (shift > 0 ? Math.ceil(shift) : Math.floor(shift)) * wrap_width;
|
|
||||||
const new_offset =
|
|
||||||
Math.abs(shift) > 0.25
|
|
||||||
? Math.min(Math.max(diff, wrap_width - slide_width), 0) // next or prev slide
|
|
||||||
: Math.round(offset / wrap_width) * wrap_width; // back to this one
|
|
||||||
|
|
||||||
setOffset(new_offset);
|
|
||||||
}, [wrap, offset, initial_offset]);
|
|
||||||
|
|
||||||
const updateMaxHeight = useCallback(() => {
|
|
||||||
if (!wrap.current) return;
|
|
||||||
setMaxHeight(window.innerHeight - 143);
|
|
||||||
normalizeOffset();
|
|
||||||
}, [wrap, setMaxHeight, normalizeOffset]);
|
|
||||||
|
|
||||||
const onOpenPhotoSwipe = useCallback(() => dispatch(modalShowPhotoswipe(images, current)), [
|
|
||||||
dispatch,
|
|
||||||
images,
|
|
||||||
current,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const stopDragging = useCallback(
|
|
||||||
event => {
|
|
||||||
if (!is_dragging) return;
|
|
||||||
|
|
||||||
setIsDragging(false);
|
|
||||||
normalizeOffset();
|
|
||||||
|
|
||||||
if (
|
|
||||||
Math.abs(new Date().getTime() - drag_start) < 200 &&
|
|
||||||
Math.abs(initial_x - getX(event)) < 5
|
|
||||||
) {
|
|
||||||
onOpenPhotoSwipe();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[setIsDragging, is_dragging, normalizeOffset, onOpenPhotoSwipe, drag_start]
|
|
||||||
);
|
|
||||||
|
|
||||||
const startDragging = useCallback(
|
|
||||||
event => {
|
|
||||||
setIsDragging(true);
|
|
||||||
setInitialX(getX(event));
|
|
||||||
setInitialOffset(offset);
|
|
||||||
setDragStart(new Date().getTime());
|
|
||||||
},
|
|
||||||
[setIsDragging, setInitialX, offset, setInitialOffset, setDragStart]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => updateMaxHeight(), [images]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener('resize', updateSizes);
|
|
||||||
window.addEventListener('resize', updateMaxHeight);
|
|
||||||
|
|
||||||
window.addEventListener('mousemove', onDrag);
|
|
||||||
window.addEventListener('touchmove', onDrag);
|
|
||||||
|
|
||||||
window.addEventListener('mouseup', stopDragging);
|
|
||||||
window.addEventListener('touchend', stopDragging);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', updateSizes);
|
|
||||||
window.removeEventListener('resize', updateMaxHeight);
|
|
||||||
|
|
||||||
window.removeEventListener('mousemove', onDrag);
|
|
||||||
window.removeEventListener('touchmove', onDrag);
|
|
||||||
|
|
||||||
window.removeEventListener('mouseup', stopDragging);
|
|
||||||
window.removeEventListener('touchend', stopDragging);
|
|
||||||
};
|
|
||||||
}, [onDrag, stopDragging, updateMaxHeight, updateSizes]);
|
|
||||||
|
|
||||||
const changeCurrent = useCallback(
|
|
||||||
(item: number) => {
|
|
||||||
if (!wrap.current) return;
|
|
||||||
|
|
||||||
const { width } = wrap.current.getBoundingClientRect();
|
|
||||||
setOffset(-1 * item * width);
|
|
||||||
},
|
|
||||||
[wrap]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onPrev = useCallback(() => changeCurrent(current > 0 ? current - 1 : images.length - 1), [
|
|
||||||
changeCurrent,
|
|
||||||
current,
|
|
||||||
images,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const onNext = useCallback(() => changeCurrent(current < images.length - 1 ? current + 1 : 0), [
|
|
||||||
changeCurrent,
|
|
||||||
current,
|
|
||||||
images,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useArrows(onNext, onPrev, is_shown);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setOffset(0);
|
|
||||||
}, [node.id]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.wrap}>
|
|
||||||
<div className={classNames(styles.cutter, { [styles.is_loading]: isLoading })} ref={wrap}>
|
|
||||||
<div
|
|
||||||
className={classNames(styles.image_container, { [styles.is_dragging]: is_dragging })}
|
|
||||||
style={{
|
|
||||||
height,
|
|
||||||
transform: `translate(${offset}px, 0)`,
|
|
||||||
width: `${images.length * 100}%`,
|
|
||||||
}}
|
|
||||||
onMouseDown={startDragging}
|
|
||||||
onTouchStart={startDragging}
|
|
||||||
ref={slide}
|
|
||||||
>
|
|
||||||
{!isLoading &&
|
|
||||||
images.map((file, index) => (
|
|
||||||
<div
|
|
||||||
className={classNames(styles.image_wrap, {
|
|
||||||
[styles.is_active]: index === current,
|
|
||||||
})}
|
|
||||||
ref={setRef(index)}
|
|
||||||
key={`${node?.updated_at || ''} + ${file?.id || ''} + ${index}`}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox={`0 0 ${file?.metadata?.width || 0} ${file?.metadata?.height || 0}`}
|
|
||||||
className={classNames(styles.preview, { [styles.is_loaded]: loaded[index] })}
|
|
||||||
style={{
|
|
||||||
maxHeight: max_height,
|
|
||||||
width: '100%',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<defs>
|
|
||||||
<filter id="f1" x="0" y="0">
|
|
||||||
<feGaussianBlur
|
|
||||||
stdDeviation="5 5"
|
|
||||||
x="0%"
|
|
||||||
y="0%"
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
in="blend"
|
|
||||||
edgeMode="none"
|
|
||||||
result="blur2"
|
|
||||||
/>
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
|
|
||||||
<rect fill="#242222" width="100%" height="100%" stroke="none" rx="8" ry="8" />
|
|
||||||
|
|
||||||
<image
|
|
||||||
xlinkHref={getURL(file, PRESETS['300'])}
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
filter="url(#f1)"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<img
|
|
||||||
className={classNames(styles.image, { [styles.is_loaded]: loaded[index] })}
|
|
||||||
src={getURL(file, PRESETS['1600'])}
|
|
||||||
alt=""
|
|
||||||
key={file.id}
|
|
||||||
onLoad={onImageLoad(index)}
|
|
||||||
style={{ maxHeight: max_height }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{images.length > 1 && (
|
|
||||||
<div className={styles.image_count}>
|
|
||||||
{current + 1}
|
|
||||||
<small> / </small>
|
|
||||||
{images.length}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{images.length > 1 && (
|
|
||||||
<div className={classNames(styles.image_arrow)} onClick={onPrev}>
|
|
||||||
<Icon icon="left" size={40} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{images.length > 1 && (
|
|
||||||
<div className={classNames(styles.image_arrow, styles.image_arrow_right)} onClick={onNext}>
|
|
||||||
<Icon icon="right" size={40} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { NodeImageSlideBlock };
|
|
|
@ -1,187 +0,0 @@
|
||||||
@import "src/styles/variables";
|
|
||||||
|
|
||||||
.wrap {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cutter {
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
min-width: 0;
|
|
||||||
transition: height 0.25s;
|
|
||||||
border-radius: $radius;
|
|
||||||
margin-right: -$gap / 2;
|
|
||||||
margin-left: -$gap / 2;
|
|
||||||
|
|
||||||
.is_loading {
|
|
||||||
.placeholder {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include tablet {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image_container {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: flex-start;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
user-select: none;
|
|
||||||
will-change: transform, height;
|
|
||||||
transition: height 500ms, transform 500ms;
|
|
||||||
padding: 0 0 20px 0;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is_dragging {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image_wrap {
|
|
||||||
width: 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
touch-action: none;
|
|
||||||
z-index: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 0 $gap / 2;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&.is_active {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include tablet {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image_count {
|
|
||||||
position: absolute;
|
|
||||||
color: transparentize(white, 0.5);
|
|
||||||
bottom: $gap * 3;
|
|
||||||
right: 50%;
|
|
||||||
padding: $gap / 3 $gap;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: $content_bg;
|
|
||||||
font: $font_12_semibold;
|
|
||||||
transform: translate(50%, 0);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 0.8em;
|
|
||||||
padding: 0 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image_arrow {
|
|
||||||
position: absolute;
|
|
||||||
left: -$gap;
|
|
||||||
top: 50%;
|
|
||||||
width: 40px;
|
|
||||||
height: 64px;
|
|
||||||
border-radius: $radius;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transform: translate(-100%, -50%);
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.7;
|
|
||||||
transition: opacity 0.5s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_right {
|
|
||||||
right: -$gap;
|
|
||||||
left: auto;
|
|
||||||
transform: translate(100%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: $content_width + 80px + 40px) {
|
|
||||||
background: $content_bg;
|
|
||||||
left: 0;
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
border-radius: 0 $radius $radius 0;
|
|
||||||
|
|
||||||
&_right {
|
|
||||||
right: 0;
|
|
||||||
left: auto;
|
|
||||||
border-radius: $radius 0 0 $radius;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include tablet {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
position: relative;
|
|
||||||
left: -2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: $content_bg;
|
|
||||||
pointer-events: none;
|
|
||||||
touch-action: none;
|
|
||||||
transition: opacity 2s;
|
|
||||||
z-index: 2;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&.is_loading {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
opacity: 0.025;
|
|
||||||
fill: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image, .preview {
|
|
||||||
max-width: 100%;
|
|
||||||
border-radius: $radius;
|
|
||||||
|
|
||||||
@include tablet {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&.is_loaded {
|
|
||||||
opacity: 1;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview {
|
|
||||||
&.is_loaded {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue