1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 12:56:41 +07:00

Merge branch 'develop'

This commit is contained in:
Fedor Katurov 2020-04-24 14:39:09 +07:00
commit ad2c8dca80
8 changed files with 89 additions and 71 deletions

View file

@ -18,6 +18,7 @@
height: 100%; height: 100%;
animation: fadeIn 2s; animation: fadeIn 2s;
will-change: transform, opacity; will-change: transform, opacity;
filter: blur(10px);
&::after { &::after {
content: ' '; content: ' ';
@ -26,7 +27,7 @@
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: url(~/sprites/stripes.svg) rgba(0, 0, 0, 0.3); background: url(~/sprites/stripes.svg) transparentize($content_bg, 0.2);
} }
@include tablet { @include tablet {

View file

@ -2,25 +2,23 @@
width: 100%; width: 100%;
height: 0; height: 0;
position: relative; position: relative;
z-index: 2; z-index: 4;
} }
.switcher { .switcher {
position: absolute; position: absolute;
background: transparentize(black, 0.5); // background: darken($content_bg, 2%);
background: url('../../../../src/sprites/noise.png') $main_bg_color;
display: flex; display: flex;
left: 50%; left: 50%;
top: -60px; transform: translate(-50%, 0);
top: -5px;
border-radius: 24px; border-radius: 24px;
padding: 0 3px; padding: 0 3px;
flex-wrap: wrap; // flex-wrap: wrap;
transition: background-color 0.5s; transition: background-color 0.5s;
transform: translate(-50%, 0); transform: translate(-50%, 0);
&:hover {
background: transparentize(black, 0.2);
}
& > div { & > div {
width: 30px; width: 30px;
height: 30px; height: 30px;
@ -29,19 +27,14 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
opacity: 0.5;
transition: opacity 0.25s; transition: opacity 0.25s;
opacity: 0.5;
&:hover {
opacity: 1;
}
&::after { &::after {
content: ' '; content: ' ';
display: block; display: block;
width: 14px; width: 14px;
height: 14px; height: 14px;
// background: white;
border-radius: 8px; border-radius: 8px;
box-shadow: inset white 0 0 0 2px; box-shadow: inset white 0 0 0 2px;
transform: scale(0.5); transform: scale(0.5);

View file

@ -7,6 +7,7 @@ import { getURL } from '~/utils/dom';
import { UPLOAD_TYPES } from '~/redux/uploads/constants'; import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import { PRESETS } from '~/constants/urls'; import { PRESETS } from '~/constants/urls';
import * as MODAL_ACTIONS from '~/redux/modal/actions'; import * as MODAL_ACTIONS from '~/redux/modal/actions';
import { LoaderCircle } from '~/components/input/LoaderCircle';
interface IProps { interface IProps {
is_loading: boolean; is_loading: boolean;
@ -19,7 +20,7 @@ interface IProps {
const NodeImageBlock: FC<IProps> = ({ node, is_loading, updateLayout, modalShowPhotoswipe }) => { const NodeImageBlock: FC<IProps> = ({ node, is_loading, updateLayout, modalShowPhotoswipe }) => {
const [is_animated, setIsAnimated] = useState(false); const [is_animated, setIsAnimated] = useState(false);
const [current, setCurrent] = useState(0); const [current, setCurrent] = useState(0);
const [height, setHeight] = useState(320); const [height, setHeight] = useState(window.innerHeight - 150);
const [loaded, setLoaded] = useState<Record<number, boolean>>({}); const [loaded, setLoaded] = useState<Record<number, boolean>>({});
const refs = useRef<Record<number, HTMLDivElement>>({}); const refs = useRef<Record<number, HTMLDivElement>>({});
@ -30,23 +31,19 @@ const NodeImageBlock: FC<IProps> = ({ node, is_loading, updateLayout, modalShowP
); );
const setRef = useCallback(index => el => (refs.current[index] = el), [refs]); const setRef = useCallback(index => el => (refs.current[index] = el), [refs]);
const onImageLoad = useCallback(index => () => setLoaded({ ...loaded, [index]: true }), [ const onImageLoad = useCallback(index => () => setLoaded({ ...loaded, [index]: true }), [
setLoaded, setLoaded,
loaded, loaded,
]); ]);
const onOpenPhotoSwipe = useCallback(
(index: number) => () => modalShowPhotoswipe(images, index),
[modalShowPhotoswipe, images]
);
useEffect(() => updateLayout(), [loaded]); useEffect(() => updateLayout(), [loaded]);
useEffect(() => { useEffect(() => {
if (!refs || !refs.current[current] || !loaded[current]) return setHeight(320); if (!refs || !refs.current[current] || !loaded[current])
return setHeight(window.innerHeight - 150);
const el = refs.current[current]; const el = refs.current[current];
const element_height = el.getBoundingClientRect && el.getBoundingClientRect().height; const element_height = el.getBoundingClientRect && el.getBoundingClientRect().height;
setHeight(element_height); setHeight(element_height);
@ -57,18 +54,20 @@ const NodeImageBlock: FC<IProps> = ({ node, is_loading, updateLayout, modalShowP
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, []); }, []);
const onOpenPhotoSwipe = useCallback(() => modalShowPhotoswipe(images, current), [
modalShowPhotoswipe,
images,
current,
]);
return ( return (
<div className={classNames(styles.wrap, { is_loading, is_animated })}> <div className={classNames(styles.wrap, { is_loading, is_animated })}>
<div> <div className={styles.image_container} style={{ height }} onClick={onOpenPhotoSwipe}>
<ImageSwitcher {(is_loading || !loaded[0] || !images.length) && (
total={images.length} <div className={styles.placeholder}>
current={current} <LoaderCircle size={72} />
onChange={setCurrent} </div>
loaded={loaded} )}
/>
<div className={styles.image_container} style={{ height }}>
{(is_loading || !loaded[0] || !images.length) && <div className={styles.placeholder} />}
{images.map((file, index) => ( {images.map((file, index) => (
<div <div
@ -88,7 +87,13 @@ const NodeImageBlock: FC<IProps> = ({ node, is_loading, updateLayout, modalShowP
</div> </div>
))} ))}
</div> </div>
</div>
<ImageSwitcher
total={images.length}
current={current}
onChange={setCurrent}
loaded={loaded}
/>
</div> </div>
); );
}; };

View file

@ -1,4 +1,6 @@
.wrap { .wrap {
padding-bottom: $gap * 2;
&:global(.is_animated) { &:global(.is_animated) {
.image_container { .image_container {
transition: height 0.5s; transition: height 0.5s;
@ -12,7 +14,6 @@
.image_container { .image_container {
width: 100%; width: 100%;
background: $node_image_bg;
border-radius: $panel_radius 0 0 $panel_radius; border-radius: $panel_radius 0 0 $panel_radius;
display: flex; display: flex;
align-items: center; align-items: center;
@ -22,10 +23,12 @@
user-select: none; user-select: none;
.image { .image {
max-height: 960px; max-height: calc(100vh - 150px);
max-width: 100%; max-width: 100%;
opacity: 1; opacity: 1;
border-radius: $radius $radius 0 0; border-radius: $radius;
@include outer_shadow();
} }
} }
@ -48,6 +51,10 @@
} }
.placeholder { .placeholder {
background: red; width: 100%;
height: 320px; height: calc(100vh - 130px);
border-radius: $radius;
display: flex;
align-items: center;
justify-content: center;
} }

View file

@ -47,7 +47,8 @@ const NodePanel: FC<IProps> = memo(
return ( return (
<div className={styles.place} ref={ref}> <div className={styles.place} ref={ref}>
{stack && {/*
stack &&
createPortal( createPortal(
<NodePanelInner <NodePanelInner
node={node} node={node}
@ -62,7 +63,8 @@ const NodePanel: FC<IProps> = memo(
stack stack
/>, />,
document.body document.body
)} )
*/}
<NodePanelInner <NodePanelInner
node={node} node={node}

View file

@ -36,8 +36,9 @@
@include tablet { @include tablet {
border-radius: 0; border-radius: 0;
flex-direction: column; // flex-direction: column;
align-items: flex-start; // align-items: flex-start;
height: 128px;
} }
@include can_backdrop { @include can_backdrop {

View file

@ -12,7 +12,7 @@ import { NodeNoComments } from '~/components/node/NodeNoComments';
import { NodeRelated } from '~/components/node/NodeRelated'; import { NodeRelated } from '~/components/node/NodeRelated';
import { NodeComments } from '~/components/node/NodeComments'; import { NodeComments } from '~/components/node/NodeComments';
import { NodeTags } from '~/components/node/NodeTags'; import { NodeTags } from '~/components/node/NodeTags';
import { NODE_COMPONENTS, NODE_INLINES } from '~/redux/node/constants'; import { NODE_COMPONENTS, NODE_INLINES, NODE_HEADS } from '~/redux/node/constants';
import { selectUser } from '~/redux/auth/selectors'; import { selectUser } from '~/redux/auth/selectors';
import pick from 'ramda/es/pick'; import pick from 'ramda/es/pick';
import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder'; import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder';
@ -97,8 +97,9 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
const can_like = useMemo(() => canLikeNode(node, user), [node, user]); const can_like = useMemo(() => canLikeNode(node, user), [node, user]);
const can_star = useMemo(() => canStarNode(node, user), [node, user]); const can_star = useMemo(() => canStarNode(node, user), [node, user]);
const head = node && node.type && NODE_HEADS[node.type];
const block = node && node.type && NODE_COMPONENTS[node.type]; const block = node && node.type && NODE_COMPONENTS[node.type];
const inline_block = node && node.type && NODE_INLINES[node.type]; const inline = node && node.type && NODE_INLINES[node.type];
const onEdit = useCallback(() => nodeEdit(node.id), [nodeEdit, node]); const onEdit = useCallback(() => nodeEdit(node.id), [nodeEdit, node]);
const onLike = useCallback(() => nodeLike(node.id), [nodeLike, node]); const onLike = useCallback(() => nodeLike(node.id), [nodeLike, node]);
@ -112,11 +113,14 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
}, [nodeSetCoverImage, node.cover]); }, [nodeSetCoverImage, node.cover]);
return ( return (
<div className={styles.node}> <>
{head &&
createElement(head, { node, is_loading, updateLayout, layout, modalShowPhotoswipe })}
<Card className={styles.node} seamless>
{block && {block &&
createElement(block, { node, is_loading, updateLayout, layout, modalShowPhotoswipe })} createElement(block, { node, is_loading, updateLayout, layout, modalShowPhotoswipe })}
<Card seamless>
<NodePanel <NodePanel
node={pick( node={pick(
['title', 'user', 'is_liked', 'is_heroic', 'deleted_at', 'created_at'], ['title', 'user', 'is_liked', 'is_heroic', 'deleted_at', 'created_at'],
@ -140,9 +144,9 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
<Padder> <Padder>
<Group horizontal className={styles.content}> <Group horizontal className={styles.content}>
<Group className={styles.comments}> <Group className={styles.comments}>
{inline_block && ( {inline && (
<div className={styles.inline_block}> <div className={styles.inline}>
{createElement(inline_block, { {createElement(inline, {
node, node,
is_loading, is_loading,
updateLayout, updateLayout,
@ -152,7 +156,7 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
</div> </div>
)} )}
{is_loading || is_loading_comments || (!comments.length && !inline_block) ? ( {is_loading || is_loading_comments || (!comments.length && !inline) ? (
<NodeNoComments is_loading={is_loading_comments || is_loading} /> <NodeNoComments is_loading={is_loading_comments || is_loading} />
) : ( ) : (
<NodeComments <NodeComments
@ -212,7 +216,7 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
<Footer /> <Footer />
</Card> </Card>
</div> </>
); );
} }
); );

View file

@ -14,6 +14,7 @@ import { EditorAudioUploadButton } from '~/components/editors/EditorAudioUploadB
import { EditorUploadCoverButton } from '~/components/editors/EditorUploadCoverButton'; import { EditorUploadCoverButton } from '~/components/editors/EditorUploadCoverButton';
import { Filler } from '~/components/containers/Filler'; import { Filler } from '~/components/containers/Filler';
import { modalShowPhotoswipe } from '../modal/actions'; import { modalShowPhotoswipe } from '../modal/actions';
import { NodeImageBlock } from '~/components/node/NodeImageBlock';
const prefix = 'NODE.'; const prefix = 'NODE.';
export const NODE_ACTIONS = { export const NODE_ACTIONS = {
@ -87,8 +88,12 @@ type INodeComponents = Record<
}> }>
>; >;
export const NODE_HEADS: INodeComponents = {
[NODE_TYPES.IMAGE]: NodeImageBlock,
};
export const NODE_COMPONENTS: INodeComponents = { export const NODE_COMPONENTS: INodeComponents = {
[NODE_TYPES.IMAGE]: NodeImageSlideBlock, // [NODE_TYPES.IMAGE]: NodeImageSlideBlock,
[NODE_TYPES.VIDEO]: NodeVideoBlock, [NODE_TYPES.VIDEO]: NodeVideoBlock,
[NODE_TYPES.AUDIO]: NodeAudioImageBlock, [NODE_TYPES.AUDIO]: NodeAudioImageBlock,
}; };