From b4b138e90f80a0f932a96a6cc650955da29fa391 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Wed, 21 Apr 2021 12:58:44 +0700 Subject: [PATCH] added placeholders --- src/components/lab/LabAudioBlock/index.tsx | 12 +++ src/components/lab/LabBottomPanel/index.tsx | 42 ++++++----- src/components/lab/LabDescription/index.tsx | 9 ++- src/components/lab/LabImage/index.tsx | 73 ++++++++++--------- src/components/lab/LabNode/index.tsx | 4 +- src/components/lab/LabNodeTitle/index.tsx | 26 ++++--- src/components/lab/LabText/index.tsx | 9 ++- src/components/lab/LabVideo/index.tsx | 12 +++ .../placeholders/Paragraph/index.tsx | 35 +++++++++ .../placeholders/Paragraph/styles.module.scss | 12 +++ .../ParagraphPlaceholder/index.tsx | 28 ------- .../ParagraphPlaceholder/styles.module.scss | 12 --- .../placeholders/Placeholder/index.tsx | 25 ++++++- .../Placeholder/styles.module.scss | 23 ++++++ src/containers/lab/LabGrid/index.tsx | 28 ++++++- src/redux/node/constants.ts | 6 +- 16 files changed, 239 insertions(+), 117 deletions(-) create mode 100644 src/components/lab/LabAudioBlock/index.tsx create mode 100644 src/components/lab/LabVideo/index.tsx create mode 100644 src/components/placeholders/Paragraph/index.tsx create mode 100644 src/components/placeholders/Paragraph/styles.module.scss delete mode 100644 src/components/placeholders/ParagraphPlaceholder/index.tsx delete mode 100644 src/components/placeholders/ParagraphPlaceholder/styles.module.scss diff --git a/src/components/lab/LabAudioBlock/index.tsx b/src/components/lab/LabAudioBlock/index.tsx new file mode 100644 index 00000000..ddbbf792 --- /dev/null +++ b/src/components/lab/LabAudioBlock/index.tsx @@ -0,0 +1,12 @@ +import React, { FC } from 'react'; +import { INodeComponentProps } from '~/redux/node/constants'; +import { Placeholder } from '~/components/placeholders/Placeholder'; +import { NodeAudioBlock } from '~/components/node/NodeAudioBlock'; + +const LabAudio: FC = ({ node, isLoading }) => ( + + + +); + +export { LabAudio }; diff --git a/src/components/lab/LabBottomPanel/index.tsx b/src/components/lab/LabBottomPanel/index.tsx index 8b2eac52..134ec27c 100644 --- a/src/components/lab/LabBottomPanel/index.tsx +++ b/src/components/lab/LabBottomPanel/index.tsx @@ -9,6 +9,7 @@ import classNames from 'classnames'; import { Grid } from '~/components/containers/Grid'; import { useHistory } from 'react-router'; import { URLS } from '~/constants/urls'; +import { Placeholder } from '~/components/placeholders/Placeholder'; type Props = { node: INode; @@ -17,31 +18,38 @@ type Props = { commentCount: number; }; -const LabBottomPanel: FC = ({ node, hasNewComments, commentCount }) => { +const LabBottomPanel: FC = ({ node, hasNewComments, commentCount, isLoading }) => { const history = useHistory(); const onClick = useCallback(() => history.push(URLS.NODE_URL(node.id)), [node.id]); return ( -
{getPrettyDate(node.created_at)}
+
+ {getPrettyDate(node.created_at)} +
+ - {commentCount > 0 && ( - - - {commentCount} - - )} + + {commentCount > 0 && ( + + + {commentCount} + + )} + - {!!node.like_count && node.like_count > 0 && ( - - - {node.like_count} - - )} + + {!!node.like_count && node.like_count > 0 && ( + + + {node.like_count} + + )} +
); }; diff --git a/src/components/lab/LabDescription/index.tsx b/src/components/lab/LabDescription/index.tsx index 3883eeba..05a0c537 100644 --- a/src/components/lab/LabDescription/index.tsx +++ b/src/components/lab/LabDescription/index.tsx @@ -4,15 +4,20 @@ import styles from './styles.module.scss'; import { Markdown } from '~/components/containers/Markdown'; import { formatText } from '~/utils/dom'; import { useGotoNode } from '~/utils/hooks/node/useGotoNode'; +import { Paragraph } from '~/components/placeholders/Paragraph'; -const LabDescription: FC = ({ node }) => { +const LabDescription: FC = ({ node, isLoading }) => { const onClick = useGotoNode(node.id); if (!node.description) { return null; } - return ( + return isLoading ? ( +
+ +
+ ) : ( = ({ node }) => { +const LabImage: FC = ({ node, isLoading }) => { const [controlledSwiper, setControlledSwiper] = useState(undefined); const images = useNodeImages(node); @@ -52,44 +53,46 @@ const LabImage: FC = ({ node }) => { const onClick = useGotoNode(node.id); - if (!images?.length) { + if (!images?.length && !isLoading) { return null; } return ( -
- 1 ? 1.1 : 1} - onSwiper={setControlledSwiper} - spaceBetween={10} - grabCursor - autoHeight - breakpoints={breakpoints} - observeSlideChildren - observeParents - resizeObserver - watchOverflow - updateOnImagesReady - onInit={resetSwiper} - keyboard={{ - enabled: true, - onlyInViewport: false, - }} - > - {images.map(file => ( - - {node.title} - - ))} - -
+ +
+ 1 ? 1.1 : 1} + onSwiper={setControlledSwiper} + spaceBetween={10} + grabCursor + autoHeight + breakpoints={breakpoints} + observeSlideChildren + observeParents + resizeObserver + watchOverflow + updateOnImagesReady + onInit={resetSwiper} + keyboard={{ + enabled: true, + onlyInViewport: false, + }} + > + {images.map(file => ( + + {node.title} + + ))} + +
+
); }; diff --git a/src/components/lab/LabNode/index.tsx b/src/components/lab/LabNode/index.tsx index 94dc699d..8572a4ee 100644 --- a/src/components/lab/LabNode/index.tsx +++ b/src/components/lab/LabNode/index.tsx @@ -13,7 +13,7 @@ interface IProps { } const LabNode: FC = ({ node, isLoading, lastSeen, commentCount }) => { - const { lab } = useNodeBlocks(node, false); + const { lab } = useNodeBlocks(node, !!isLoading); const hasNewComments = useMemo( () => @@ -26,7 +26,7 @@ const LabNode: FC = ({ node, isLoading, lastSeen, commentCount }) => { {lab} diff --git a/src/components/lab/LabNodeTitle/index.tsx b/src/components/lab/LabNodeTitle/index.tsx index 7ac09c5e..45e37624 100644 --- a/src/components/lab/LabNodeTitle/index.tsx +++ b/src/components/lab/LabNodeTitle/index.tsx @@ -5,26 +5,28 @@ import { Group } from '~/components/containers/Group'; import { Icon } from '~/components/input/Icon'; import Tippy from '@tippy.js/react'; import { useGotoNode } from '~/utils/hooks/node/useGotoNode'; +import { INodeComponentProps } from '~/redux/node/constants'; +import { Placeholder } from '~/components/placeholders/Placeholder'; -interface IProps { - node: INode; -} - -const LabNodeTitle: FC = ({ node }) => { +const LabNodeTitle: FC = ({ node, isLoading }) => { const onClick = useGotoNode(node.id); if (!node.title) return null; return ( -
{node.title || '...'}
+
+ {node.title || '...'} +
- {node.is_heroic && ( - -
- -
-
+ {(node.is_heroic || isLoading) && ( + + +
+ +
+
+
)}
); diff --git a/src/components/lab/LabText/index.tsx b/src/components/lab/LabText/index.tsx index b9b709a2..4755ab87 100644 --- a/src/components/lab/LabText/index.tsx +++ b/src/components/lab/LabText/index.tsx @@ -5,15 +5,20 @@ import { formatTextParagraphs } from '~/utils/dom'; import { path } from 'ramda'; import styles from './styles.module.scss'; import { useGotoNode } from '~/utils/hooks/node/useGotoNode'; +import { Paragraph } from '~/components/placeholders/Paragraph'; -const LabText: FC = ({ node }) => { +const LabText: FC = ({ node, isLoading }) => { const content = useMemo(() => formatTextParagraphs(path(['blocks', 0, 'text'], node) || ''), [ node.blocks, ]); const onClick = useGotoNode(node.id); - return ( + return isLoading ? ( +
+ +
+ ) : ( = ({ node, isLoading }) => ( + + + +); + +export { LabVideo }; diff --git a/src/components/placeholders/Paragraph/index.tsx b/src/components/placeholders/Paragraph/index.tsx new file mode 100644 index 00000000..f7777390 --- /dev/null +++ b/src/components/placeholders/Paragraph/index.tsx @@ -0,0 +1,35 @@ +import React, { FC, useMemo } from 'react'; +import { Placeholder, PlaceholderProps } from '~/components/placeholders/Placeholder'; +import styles from './styles.module.scss'; +import { Group } from '~/components/containers/Group'; + +type Props = PlaceholderProps & { + lines?: number; + wordsLimit?: number; +}; + +const Paragraph: FC = ({ lines = 3, wordsLimit = 12, ...props }) => { + const iters = useMemo( + () => + [...new Array(lines)].map(() => + [...new Array(Math.ceil(Math.random() * wordsLimit))].map((_, i) => i) + ), + [lines, wordsLimit] + ); + + console.log({ iters }); + + return ( + + {iters.map(words => ( +
+ {words.map(word => ( + + ))} +
+ ))} +
+ ); +}; + +export { Paragraph }; diff --git a/src/components/placeholders/Paragraph/styles.module.scss b/src/components/placeholders/Paragraph/styles.module.scss new file mode 100644 index 00000000..302b031a --- /dev/null +++ b/src/components/placeholders/Paragraph/styles.module.scss @@ -0,0 +1,12 @@ +@import "src/styles/variables"; + +.para { + display: flex; + flex-wrap: wrap; + + div { + display: inline-flex; + margin-right: $gap; + margin-top: $gap; + } +} diff --git a/src/components/placeholders/ParagraphPlaceholder/index.tsx b/src/components/placeholders/ParagraphPlaceholder/index.tsx deleted file mode 100644 index 3bbabab8..00000000 --- a/src/components/placeholders/ParagraphPlaceholder/index.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React, { FC } from 'react'; -import { Placeholder } from '~/components/placeholders/Placeholder'; -import styles from './styles.module.scss'; -import { Group } from '~/components/containers/Group'; - -const ParagraphPlaceholder = ({}) => ( - -
- - - - - - -
- -
- - - - - - -
-
-); - -export { ParagraphPlaceholder }; diff --git a/src/components/placeholders/ParagraphPlaceholder/styles.module.scss b/src/components/placeholders/ParagraphPlaceholder/styles.module.scss deleted file mode 100644 index a5373213..00000000 --- a/src/components/placeholders/ParagraphPlaceholder/styles.module.scss +++ /dev/null @@ -1,12 +0,0 @@ -@import "src/styles/variables"; - -.para { - display: grid; - grid-template-columns: auto; - grid-auto-columns: auto; - grid-template-rows: 1fr; - grid-column-gap: $gap; - grid-auto-flow: column; - - div { display: inline-flex; margin-right: $gap; } -} diff --git a/src/components/placeholders/Placeholder/index.tsx b/src/components/placeholders/Placeholder/index.tsx index a5d3be7c..2686f21d 100644 --- a/src/components/placeholders/Placeholder/index.tsx +++ b/src/components/placeholders/Placeholder/index.tsx @@ -1,14 +1,31 @@ import React, { FC } from 'react'; import styles from './styles.module.scss'; +import classNames from 'classnames'; -interface IProps { +export interface PlaceholderProps { width?: string; height?: number; color?: string; + active?: boolean; + loading?: boolean; } -const Placeholder: FC = ({ width = '120px', height, color }) => ( -
-); +const Placeholder: FC = ({ + width = '120px', + height, + color, + active, + children, + loading = true, +}) => { + return active ? ( +
+ ) : ( + <>{children} + ); +}; export { Placeholder }; diff --git a/src/components/placeholders/Placeholder/styles.module.scss b/src/components/placeholders/Placeholder/styles.module.scss index 83a97bd0..1492f8d9 100644 --- a/src/components/placeholders/Placeholder/styles.module.scss +++ b/src/components/placeholders/Placeholder/styles.module.scss @@ -1,8 +1,31 @@ @import "src/styles/variables"; +@keyframes fade { + 0% { + opacity: 0; + } + + 100% { + opacity: 0.05; + } +} .placeholder { height: 1em; width: 120px; background: $placeholder_bg; border-radius: 1em; + position: relative; + overflow: hidden; + + &::after { + content: ' '; + width: 200%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background: white; + animation: fade 0.5s infinite alternate; + border-radius: 1em; + } } diff --git a/src/containers/lab/LabGrid/index.tsx b/src/containers/lab/LabGrid/index.tsx index a075ea7a..0b6bce0e 100644 --- a/src/containers/lab/LabGrid/index.tsx +++ b/src/containers/lab/LabGrid/index.tsx @@ -2,12 +2,38 @@ import React, { FC } from 'react'; import { useShallowSelect } from '~/utils/hooks/useShallowSelect'; import styles from './styles.module.scss'; import { LabNode } from '~/components/lab/LabNode'; -import { selectLabListNodes } from '~/redux/lab/selectors'; +import { selectLabList, selectLabListNodes } from '~/redux/lab/selectors'; +import { EMPTY_NODE, NODE_TYPES } from '~/redux/node/constants'; +import { values } from 'ramda'; interface IProps {} +const getRandomNodeType = () => + values(NODE_TYPES)[Math.floor(Math.random() * values(NODE_TYPES).length)]; + +const LoadingNode = () => ( + +); + const LabGrid: FC = () => { const nodes = useShallowSelect(selectLabListNodes); + const { is_loading } = useShallowSelect(selectLabList); + + if (is_loading) { + return ( +
+ + + + +
+ ); + } return (
diff --git a/src/redux/node/constants.ts b/src/redux/node/constants.ts index 3c71e80b..0b6e0f2f 100644 --- a/src/redux/node/constants.ts +++ b/src/redux/node/constants.ts @@ -20,6 +20,8 @@ import { LabText } from '~/components/lab/LabText'; import { LabImage } from '~/components/lab/LabImage'; import { LabPad } from '~/components/lab/LabPad'; import { LabDescription } from '~/components/lab/LabDescription'; +import { LabVideo } from '~/components/lab/LabVideo'; +import { LabAudio } from '~/components/lab/LabAudioBlock'; const prefix = 'NODE.'; export const NODE_ACTIONS = { @@ -90,8 +92,8 @@ export type INodeComponents = Record, FC[]> = { [NODE_TYPES.IMAGE]: [LabImage, LabPad, LabNodeTitle, LabDescription], - [NODE_TYPES.VIDEO]: [NodeVideoBlock, LabPad, LabNodeTitle, LabDescription], - [NODE_TYPES.AUDIO]: [LabPad, LabNodeTitle, LabPad, NodeAudioImageBlock, NodeAudioBlock, LabPad], + [NODE_TYPES.VIDEO]: [LabVideo, LabPad, LabNodeTitle, LabDescription], + [NODE_TYPES.AUDIO]: [LabPad, LabNodeTitle, LabPad, NodeAudioImageBlock, LabAudio, LabPad], [NODE_TYPES.TEXT]: [LabPad, LabNodeTitle, LabPad, LabText, LabPad], };