mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
node no comments
This commit is contained in:
parent
b4d7bd2c8a
commit
96bdbb0e04
11 changed files with 103 additions and 61 deletions
|
@ -1,16 +1,25 @@
|
|||
import React, { FC } from 'react';
|
||||
import { Comment } from '~/components/node/Comment';
|
||||
import * as styles from './styles.scss';
|
||||
import { Group } from '~/components/containers/Group';
|
||||
import classNames from 'classnames';
|
||||
import { Filler } from '~/components/containers/Filler';
|
||||
import { ERRORS } from '~/constants/errors';
|
||||
import { t } from '~/utils/trans';
|
||||
|
||||
interface IProps {}
|
||||
interface IProps {
|
||||
is_loading: boolean;
|
||||
}
|
||||
|
||||
const NodeNoComments: FC<IProps> = () => (
|
||||
<Group className={styles.wrap}>
|
||||
<Comment is_empty is_loading={false} style={{ height: 94 }} />
|
||||
<Comment is_empty is_loading={false} style={{ height: 104 }} />
|
||||
<Comment is_empty is_loading={false} style={{ height: 100 }} />
|
||||
const NodeNoComments: FC<IProps> = ({ is_loading = false }) => (
|
||||
<>
|
||||
<Group className={classNames(styles.wrap, { is_loading })}>
|
||||
<div className={styles.card} />
|
||||
<div className={styles.card}>{!is_loading && t(ERRORS.NO_COMMENTS)}</div>
|
||||
<div className={styles.card} />
|
||||
</Group>
|
||||
|
||||
<Filler />
|
||||
</>
|
||||
);
|
||||
|
||||
export { NodeNoComments };
|
||||
|
|
|
@ -1,6 +1,43 @@
|
|||
@keyframes fade {
|
||||
0% {
|
||||
opacity: 0.25;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
.wrap {
|
||||
height: 300px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
@include after_shade($node_bg);
|
||||
|
||||
&:global(.is_loading) {
|
||||
.card {
|
||||
animation: fade 0.5s infinite alternate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
opacity: 0.2;
|
||||
border-radius: $radius;
|
||||
height: 96px;
|
||||
background: $comment_bg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
font: $font_18_semibold;
|
||||
color: transparentize(white, 0.5);
|
||||
@include outer_shadow();
|
||||
|
||||
&:nth-child(2) {
|
||||
// animation-delay: -300ms !important;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
// animation-delay: -600ms !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,4 +2,9 @@ export const ERRORS = {
|
|||
NOT_AN_EMAIL: 'Not_An_Email',
|
||||
TOO_SHIRT: 'Is_Too_Shirt',
|
||||
EMPTY_RESPONSE: 'Empty_Response',
|
||||
NO_COMMENTS: 'No_Comments',
|
||||
};
|
||||
|
||||
export const ERROR_LITERAL = {
|
||||
[ERRORS.NO_COMMENTS]: 'Комментариев пока нет',
|
||||
};
|
||||
|
|
|
@ -13,53 +13,7 @@ import { ImageSwitcher } from '~/components/node/ImageSwitcher';
|
|||
|
||||
interface IProps {}
|
||||
|
||||
const ImageExample: FC<IProps> = () => (
|
||||
<Card className={styles.node} seamless>
|
||||
<ImageSwitcher total={5} current={2} onChange={console.log} />
|
||||
|
||||
<div className={styles.image_container}>
|
||||
<img
|
||||
className={styles.image}
|
||||
src="http://37.192.131.144/full/attached/2019/08/e4fb2a1d0a2e20d499aaa1f5f83a7115.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
<NodePanel />
|
||||
|
||||
<Group>
|
||||
<Padder>
|
||||
<Group horizontal className={styles.content}>
|
||||
<Group className={styles.comments}>
|
||||
<NodeNoComments />
|
||||
|
||||
{range(1, 6).map(el => (
|
||||
<Comment key={el} />
|
||||
))}
|
||||
</Group>
|
||||
|
||||
<div className={styles.panel}>
|
||||
<Group style={{ flex: 1 }}>
|
||||
<Tags
|
||||
tags={[
|
||||
{ title: 'Избранный', feature: 'red' },
|
||||
{ title: 'Плейлист', feature: 'green' },
|
||||
{ title: 'Просто' },
|
||||
{ title: '+ фото', feature: 'black' },
|
||||
{ title: '+ с музыкой', feature: 'black' },
|
||||
]}
|
||||
/>
|
||||
|
||||
<NodeRelated title="First album" />
|
||||
|
||||
<NodeRelated title="Second album" />
|
||||
</Group>
|
||||
</div>
|
||||
</Group>
|
||||
</Padder>
|
||||
</Group>
|
||||
</Card>
|
||||
);
|
||||
const ImageExample: FC<IProps> = () => <Card className={styles.node} seamless></Card>;
|
||||
|
||||
export { ImageExample };
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ const NodeLayoutUnconnected: FC<IProps> = ({
|
|||
params: { id },
|
||||
},
|
||||
is_loading,
|
||||
is_loading_comments,
|
||||
comments = [],
|
||||
current: node,
|
||||
nodeLoadNode,
|
||||
}) => {
|
||||
|
@ -50,8 +52,11 @@ const NodeLayoutUnconnected: FC<IProps> = ({
|
|||
<Padder>
|
||||
<Group horizontal className={styles.content}>
|
||||
<Group className={styles.comments}>
|
||||
<NodeNoComments />
|
||||
{is_loading_comments || !comments.length || true ? (
|
||||
<NodeNoComments is_loading={is_loading_comments} />
|
||||
) : (
|
||||
<NodeComments />
|
||||
)}
|
||||
</Group>
|
||||
|
||||
<div className={styles.panel}>
|
||||
|
|
|
@ -23,6 +23,11 @@ export const nodeSetLoading = (is_loading: INodeState['is_loading']) => ({
|
|||
type: NODE_ACTIONS.SET_LOADING,
|
||||
});
|
||||
|
||||
export const nodeSetLoadingComments = (is_loading_comments: INodeState['is_loading_comments']) => ({
|
||||
is_loading_comments,
|
||||
type: NODE_ACTIONS.SET_LOADING_COMMENTS,
|
||||
});
|
||||
|
||||
export const nodeSetCurrent = (current: INodeState['current']) => ({
|
||||
current,
|
||||
type: NODE_ACTIONS.SET_CURRENT,
|
||||
|
|
|
@ -10,6 +10,7 @@ export const NODE_ACTIONS = {
|
|||
|
||||
SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`,
|
||||
SET_LOADING: `${prefix}SET_LOADING`,
|
||||
SET_LOADING_COMMENTS: `${prefix}SET_LOADING_COMMENTS`,
|
||||
SET_CURRENT: `${prefix}SET_CURRENT`,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import assocPath from 'ramda/es/assocPath';
|
||||
import { NODE_ACTIONS } from './constants';
|
||||
import { nodeSetSaveErrors, nodeSetLoading, nodeSetCurrent } from './actions';
|
||||
import {
|
||||
nodeSetSaveErrors,
|
||||
nodeSetLoading,
|
||||
nodeSetCurrent,
|
||||
nodeSetLoadingComments,
|
||||
} from './actions';
|
||||
import { INodeState } from './reducer';
|
||||
|
||||
const setSaveErrors = (state: INodeState, { errors }: ReturnType<typeof nodeSetSaveErrors>) =>
|
||||
|
@ -9,11 +14,17 @@ const setSaveErrors = (state: INodeState, { errors }: ReturnType<typeof nodeSetS
|
|||
const setLoading = (state: INodeState, { is_loading }: ReturnType<typeof nodeSetLoading>) =>
|
||||
assocPath(['is_loading'], is_loading, state);
|
||||
|
||||
const setLoadingComments = (
|
||||
state: INodeState,
|
||||
{ is_loading_comments }: ReturnType<typeof nodeSetLoadingComments>
|
||||
) => assocPath(['is_loading_comments'], is_loading_comments, state);
|
||||
|
||||
const setCurrent = (state: INodeState, { current }: ReturnType<typeof nodeSetCurrent>) =>
|
||||
assocPath(['current'], current, state);
|
||||
|
||||
export const NODE_HANDLERS = {
|
||||
[NODE_ACTIONS.SAVE]: setSaveErrors,
|
||||
[NODE_ACTIONS.SET_LOADING]: setLoading,
|
||||
[NODE_ACTIONS.SET_LOADING_COMMENTS]: setLoadingComments,
|
||||
[NODE_ACTIONS.SET_CURRENT]: setCurrent,
|
||||
};
|
||||
|
|
|
@ -4,12 +4,15 @@ import { EMPTY_NODE } from './constants';
|
|||
import { NODE_HANDLERS } from './handlers';
|
||||
|
||||
export type INodeState = Readonly<{
|
||||
is_loading: boolean;
|
||||
editor: INode;
|
||||
current: Partial<INode>;
|
||||
current: INode;
|
||||
comments: IComment[];
|
||||
|
||||
error: string;
|
||||
errors: Record<string, string>;
|
||||
|
||||
is_loading: boolean;
|
||||
is_loading_comments: boolean;
|
||||
}>;
|
||||
|
||||
const INITIAL_STATE: INodeState = {
|
||||
|
@ -19,9 +22,10 @@ const INITIAL_STATE: INodeState = {
|
|||
blocks: [],
|
||||
files: [],
|
||||
},
|
||||
current: {},
|
||||
current: { ...EMPTY_NODE },
|
||||
comments: [],
|
||||
is_loading: false,
|
||||
is_loading_comments: false,
|
||||
error: null,
|
||||
errors: {},
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
nodeLoadNode,
|
||||
nodeSetLoading,
|
||||
nodeSetCurrent,
|
||||
nodeSetLoadingComments,
|
||||
} from './actions';
|
||||
import { postNode, getNode } from './api';
|
||||
import { reqWrapper } from '../auth/sagas';
|
||||
|
@ -39,6 +40,7 @@ function* onNodeSave({ node }: ReturnType<typeof nodeSave>) {
|
|||
|
||||
function* onNodeLoad({ id, node_type }: ReturnType<typeof nodeLoadNode>) {
|
||||
yield put(nodeSetLoading(true));
|
||||
yield put(nodeSetLoadingComments(true));
|
||||
yield put(nodeSetSaveErrors({}));
|
||||
|
||||
if (node_type) yield put(nodeSetCurrent({ ...EMPTY_NODE, type: node_type }));
|
||||
|
@ -58,6 +60,10 @@ function* onNodeLoad({ id, node_type }: ReturnType<typeof nodeLoadNode>) {
|
|||
yield put(nodeSetSaveErrors({}));
|
||||
yield put(nodeSetCurrent(node));
|
||||
|
||||
// todo: load comments
|
||||
yield delay(500);
|
||||
yield put(nodeSetLoadingComments(false));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
5
src/utils/trans.ts
Normal file
5
src/utils/trans.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { ERRORS, ERROR_LITERAL } from '~/constants/errors';
|
||||
import { ValueOf } from '~/redux/types';
|
||||
|
||||
export const t = (string: ValueOf<typeof ERRORS>): ValueOf<typeof ERROR_LITERAL> =>
|
||||
ERROR_LITERAL[string] || string;
|
Loading…
Add table
Add a link
Reference in a new issue