1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

#23 added labs layout

This commit is contained in:
Fedor Katurov 2021-03-12 12:04:10 +07:00
parent 8316b46efe
commit 18ec220a4e
14 changed files with 135 additions and 65 deletions

View file

@ -1,42 +1,15 @@
import React, { DetailsHTMLAttributes, FC, useEffect, useRef } from 'react';
import styles from './styles.module.scss';
import React, { DetailsHTMLAttributes, FC } from 'react';
import StickyBox from 'react-sticky-box/dist/esnext';
import ResizeSensor from 'resize-sensor';
(window as any).ResizeSensor = ResizeSensor;
import StickySidebar from 'sticky-sidebar';
(window as any).StickySidebar = StickySidebar;
import classnames from 'classnames';
interface IProps extends DetailsHTMLAttributes<HTMLDivElement> {}
const Sticky: FC<IProps> = ({ children }) => {
const ref = useRef(null);
const sb = useRef<StickySidebar>(null);
useEffect(() => {
if (!ref.current) return;
sb.current = new StickySidebar(ref.current, {
resizeSensor: true,
topSpacing: 72,
bottomSpacing: 10,
});
return () => sb.current?.destroy();
}, [ref.current, sb.current, children]);
if (sb) {
sb.current?.updateSticky();
}
interface IProps extends DetailsHTMLAttributes<HTMLDivElement> {
offsetTop?: number;
}
const Sticky: FC<IProps> = ({ children, offsetTop = 65 }) => {
return (
<div className={classnames(styles.wrap, 'sidebar_container')}>
<div className="sidebar" ref={ref}>
<div className={classnames(styles.sticky, 'sidebar__inner')}>{children}</div>
</div>
</div>
<StickyBox offsetTop={offsetTop} offsetBottom={10}>
{children}
</StickyBox>
);
};

View file

@ -1,17 +0,0 @@
@import "src/styles/variables";
.wrap {
height: 100%;
width: 100%;
position: relative;
:global(.sidebar) {
will-change: min-height;
}
:global(.sidebar__inner) {
transform: translate(0, 0); /* For browsers don't support translate3d. */
transform: translate3d(0, 0, 0);
will-change: position, transform;
}
}

View file

@ -82,6 +82,15 @@ const HeaderUnconnected: FC<IProps> = memo(
<Filler />
<div className={styles.plugs}>
{is_user && (
<Link
className={classNames(styles.item, { [styles.is_active]: pathname === URLS.BASE })}
to={URLS.LAB}
>
ЛАБ
</Link>
)}
<Link
className={classNames(styles.item, { [styles.is_active]: pathname === URLS.BASE })}
to={URLS.BASE}
@ -122,9 +131,6 @@ const HeaderUnconnected: FC<IProps> = memo(
}
);
const Header = connect(
mapStateToProps,
mapDispatchToProps
)(HeaderUnconnected);
const Header = connect(mapStateToProps, mapDispatchToProps)(HeaderUnconnected);
export { Header };

View file

@ -4,14 +4,12 @@ import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import { AudioPlayer } from '~/components/media/AudioPlayer';
import styles from './styles.module.scss';
import { INodeComponentProps } from '~/redux/node/constants';
import { useNodeAudios } from '~/utils/hooks/node/useNodeAudios';
interface IProps extends INodeComponentProps {}
const NodeAudioBlock: FC<IProps> = ({ node }) => {
const audios = useMemo(
() => node.files.filter(file => file && file.type === UPLOAD_TYPES.AUDIO),
[node.files]
);
const audios = useNodeAudios(node);
return (
<div className={styles.wrap}>

View file

@ -6,14 +6,12 @@ import { path } from 'ramda';
import { getURL } from '~/utils/dom';
import { PRESETS } from '~/constants/urls';
import { INodeComponentProps } from '~/redux/node/constants';
import { useNodeImages } from '~/utils/hooks/node/useNodeImages';
interface IProps extends INodeComponentProps {}
const NodeAudioImageBlock: FC<IProps> = ({ node }) => {
const images = useMemo(
() => node.files.filter(file => file && file.type === UPLOAD_TYPES.IMAGE),
[node.files]
);
const images = useNodeImages(node);
if (images.length === 0) return null;

View file

@ -2,6 +2,7 @@ import { INode } from '~/redux/types';
export const URLS = {
BASE: '/',
LAB: '/lab',
BORIS: '/boris',
AUTH: {
LOGIN: '/auth/login',

View file

@ -0,0 +1,21 @@
import React, { FC } from 'react';
import { useShallowSelect } from '~/utils/hooks/useShallowSelect';
import { selectFlowNodes } from '~/redux/flow/selectors';
import styles from './styles.module.scss';
import { LabNode } from '~/containers/lab/LabNode';
interface IProps {}
const LabGrid: FC<IProps> = () => {
const nodes = useShallowSelect(selectFlowNodes);
return (
<div className={styles.wrap}>
{nodes.map(node => (
<LabNode node={node} key={node.id} />
))}
</div>
);
};
export { LabGrid };

View file

@ -0,0 +1,8 @@
@import "~/styles/variables.scss";
.wrap {
display: grid;
grid-auto-flow: row;
grid-auto-rows: auto;
grid-row-gap: $gap;
}

View file

@ -0,0 +1,27 @@
import React, { FC } from 'react';
import styles from './styles.module.scss';
import { Card } from '~/components/containers/Card';
import { Sticky } from '~/components/containers/Sticky';
import { Container } from '~/containers/main/Container';
import { LabGrid } from '~/containers/lab/LabGrid';
interface IProps {}
const LabLayout: FC<IProps> = () => (
<div>
<Container>
<div className={styles.wrap}>
<div className={styles.content}>
<LabGrid />
</div>
<div className={styles.panel}>
<Sticky>
<Card>Test</Card>
</Sticky>
</div>
</div>
</Container>
</div>
);
export { LabLayout };

View file

@ -0,0 +1,11 @@
@import "~/styles/variables.scss";
.wrap {
display: grid;
grid-template-columns: 3fr 1fr;
column-gap: $gap;
}
.panel {
margin-top: -7px;
}

View file

@ -0,0 +1,34 @@
import React, { FC } from 'react';
import { INode } from '~/redux/types';
import { NodePanelInner } from '~/components/node/NodePanelInner';
import { useNodeBlocks } from '~/utils/hooks/node/useNodeBlocks';
interface IProps {
node: INode;
}
const LabNode: FC<IProps> = ({ node }) => {
const { inline, block, head } = useNodeBlocks(node, false);
return (
<div>
<NodePanelInner
node={node}
canEdit
canLike
canStar
isLoading={false}
onEdit={console.log}
onLike={console.log}
onStar={console.log}
onLock={console.log}
/>
{inline}
{block}
{head}
</div>
);
};
export { LabNode };

View file

@ -6,6 +6,7 @@ import { BorisLayout } from '~/containers/node/BorisLayout';
import { ErrorNotFound } from '~/containers/pages/ErrorNotFound';
import { ProfilePage } from '~/containers/profile/ProfilePage';
import { Redirect, Route, Switch, useLocation } from 'react-router';
import { LabLayout } from '~/containers/lab/LabLayout';
interface IProps {}
@ -15,6 +16,7 @@ const MainRouter: FC<IProps> = () => {
return (
<Switch location={location}>
<Route exact path={URLS.BASE} component={FlowLayout} />
<Route exact path={URLS.LAB} component={LabLayout} />
<Route path={URLS.NODE_URL(':id')} component={NodeLayout} />
<Route path={URLS.BORIS} component={BorisLayout} />
<Route path={URLS.ERRORS.NOT_FOUND} component={ErrorNotFound} />

View file

@ -3,6 +3,10 @@ import { useMemo } from 'react';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
export const useNodeAudios = (node: INode) => {
if (!node?.files) {
return [];
}
return useMemo(() => node.files.filter(file => file && file.type === UPLOAD_TYPES.AUDIO), [
node.files,
]);

View file

@ -3,6 +3,10 @@ import { useMemo } from 'react';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
export const useNodeImages = (node: INode) => {
if (!node?.files) {
return [];
}
return useMemo(() => node.files.filter(file => file && file.type === UPLOAD_TYPES.IMAGE), [
node.files,
]);