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

sort category tags before others

This commit is contained in:
Fedor Katurov 2020-03-16 17:44:01 +07:00
parent 1472d647f8
commit c989d50277
2 changed files with 96 additions and 93 deletions

View file

@ -1,4 +1,4 @@
import React, { FC } from 'react'; import React, { FC, memo } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { Group } from '~/components/containers/Group'; import { Group } from '~/components/containers/Group';
import { Filler } from '~/components/containers/Filler'; import { Filler } from '~/components/containers/Filler';
@ -24,77 +24,79 @@ interface IProps {
onLock: () => void; onLock: () => void;
} }
const NodePanelInner: FC<IProps> = ({ const NodePanelInner: FC<IProps> = memo(
node: { title, user, is_liked, is_heroic, deleted_at, created_at }, ({
stack, node: { title, user, is_liked, is_heroic, deleted_at, created_at },
stack,
can_star, can_star,
can_edit, can_edit,
can_like, can_like,
is_loading, is_loading,
onStar, onStar,
onEdit, onEdit,
onLike, onLike,
onLock, onLock,
}) => { }) => {
return ( return (
<div className={classNames(styles.wrap, { stack })}> <div className={classNames(styles.wrap, { stack })}>
<div className={styles.content}> <div className={styles.content}>
<Group horizontal className={styles.panel}> <Group horizontal className={styles.panel}>
<Filler> <Filler>
<div className={styles.title}> <div className={styles.title}>
{is_loading ? <Placeholder width="40%" /> : title || '...'} {is_loading ? <Placeholder width="40%" /> : title || '...'}
</div> </div>
{user && user.username && ( {user && user.username && (
<div className={styles.name}> <div className={styles.name}>
{is_loading ? ( {is_loading ? (
<Placeholder width="100px" /> <Placeholder width="100px" />
) : (
`~${user.username}, ${getPrettyDate(created_at)}`
)}
</div>
)}
</Filler>
</Group>
<div className={styles.buttons}>
{can_star && (
<div className={classNames(styles.star, { is_heroic })}>
{is_heroic ? (
<Icon icon="star_full" size={24} onClick={onStar} />
) : ( ) : (
`~${user.username}, ${getPrettyDate(created_at)}` <Icon icon="star" size={24} onClick={onStar} />
)} )}
</div> </div>
)} )}
</Filler>
</Group>
<div className={styles.buttons}> {can_edit && (
{can_star && ( <>
<div className={classNames(styles.star, { is_heroic })}> <div>
{is_heroic ? ( <Icon icon={deleted_at ? 'locked' : 'unlocked'} size={24} onClick={onLock} />
<Icon icon="star_full" size={24} onClick={onStar} /> </div>
) : (
<Icon icon="star" size={24} onClick={onStar} />
)}
</div>
)}
{can_edit && ( <div>
<> <Icon icon="edit" size={24} onClick={onEdit} />
<div> </div>
<Icon icon={deleted_at ? 'locked' : 'unlocked'} size={24} onClick={onLock} /> </>
)}
{can_like && (
<div className={classNames(styles.like, { is_liked })}>
{is_liked ? (
<Icon icon="heart_full" size={24} onClick={onLike} />
) : (
<Icon icon="heart" size={24} onClick={onLike} />
)}
</div> </div>
)}
<div> </div>
<Icon icon="edit" size={24} onClick={onEdit} />
</div>
</>
)}
{can_like && (
<div className={classNames(styles.like, { is_liked })}>
{is_liked ? (
<Icon icon="heart_full" size={24} onClick={onLike} />
) : (
<Icon icon="heart" size={24} onClick={onLike} />
)}
</div>
)}
</div> </div>
</div> </div>
</div> );
); }
}; );
export { NodePanelInner }; export { NodePanelInner };

View file

@ -6,12 +6,13 @@ import React, {
useEffect, useEffect,
KeyboardEvent, KeyboardEvent,
ChangeEvent, ChangeEvent,
useRef useRef,
} from "react"; useMemo,
import { TagField } from "~/components/containers/TagField"; } from 'react';
import { ITag } from "~/redux/types"; import { TagField } from '~/components/containers/TagField';
import { Tag } from "~/components/node/Tag"; import { ITag } from '~/redux/types';
import uniq from "ramda/es/uniq"; import { Tag } from '~/components/node/Tag';
import uniq from 'ramda/es/uniq';
type IProps = HTMLAttributes<HTMLDivElement> & { type IProps = HTMLAttributes<HTMLDivElement> & {
tags: Partial<ITag>[]; tags: Partial<ITag>[];
@ -19,16 +20,21 @@ type IProps = HTMLAttributes<HTMLDivElement> & {
onTagsChange?: (tags: string[]) => void; onTagsChange?: (tags: string[]) => void;
}; };
export const Tags: FC<IProps> = ({ export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, ...props }) => {
tags, const [input, setInput] = useState('');
is_editable,
onTagsChange,
...props
}) => {
const [input, setInput] = useState("");
const [data, setData] = useState([]); const [data, setData] = useState([]);
const timer = useRef(null); const timer = useRef(null);
const [catTags, ordinaryTags] = useMemo(
() =>
tags.reduce(
(obj, tag) =>
tag.title.substr(0, 1) === '/' ? [[...obj[0], tag], obj[1]] : [obj[0], [...obj[1], tag]],
[[], []]
),
[]
);
const onInput = useCallback( const onInput = useCallback(
({ target: { value } }: ChangeEvent<HTMLInputElement>) => { ({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
clearTimeout(timer.current); clearTimeout(timer.current);
@ -39,17 +45,17 @@ export const Tags: FC<IProps> = ({
const onKeyUp = useCallback( const onKeyUp = useCallback(
({ key }: KeyboardEvent) => { ({ key }: KeyboardEvent) => {
if (key === "Backspace" && input === "" && data.length) { if (key === 'Backspace' && input === '' && data.length) {
setData(data.slice(0, data.length - 1)); setData(data.slice(0, data.length - 1));
setInput(data[data.length - 1].title); setInput(data[data.length - 1].title);
} }
if (key === "Enter" || key === "," || key === "Comma") { if (key === 'Enter' || key === ',' || key === 'Comma') {
setData( setData(
uniq([ uniq([
...data, ...data,
...input ...input
.split(",") .split(',')
.map((title: string) => .map((title: string) =>
title title
.trim() .trim()
@ -59,11 +65,11 @@ export const Tags: FC<IProps> = ({
.filter(el => el.length > 0) .filter(el => el.length > 0)
.filter(el => !tags.some(tag => tag.title.trim() === el.trim())) .filter(el => !tags.some(tag => tag.title.trim() === el.trim()))
.map(title => ({ .map(title => ({
title title,
})) })),
]) ])
); );
setInput(""); setInput('');
} }
}, },
[input, setInput, data, setData] [input, setInput, data, setData]
@ -75,21 +81,21 @@ export const Tags: FC<IProps> = ({
if (!items.length) return; if (!items.length) return;
setData(items); setData(items);
setInput(""); setInput('');
onTagsChange(uniq([...tags, ...items]).map(tag => tag.title)); onTagsChange(uniq([...tags, ...items]).map(tag => tag.title));
}, [tags, data, onTagsChange, input, setInput]); }, [tags, data, onTagsChange, input, setInput]);
useEffect(() => { useEffect(() => {
setData( setData(data.filter(({ title }) => !tags.some(tag => tag.title.trim() === title.trim())));
data.filter(
({ title }) => !tags.some(tag => tag.title.trim() === title.trim())
)
);
}, [tags]); }, [tags]);
return ( return (
<TagField {...props}> <TagField {...props}>
{tags.map(tag => ( {catTags.map(tag => (
<Tag key={tag.title} tag={tag} />
))}
{ordinaryTags.map(tag => (
<Tag key={tag.title} tag={tag} /> <Tag key={tag.title} tag={tag} />
))} ))}
@ -98,12 +104,7 @@ export const Tags: FC<IProps> = ({
))} ))}
{is_editable && ( {is_editable && (
<Tag <Tag tag={{ title: input }} onInput={onInput} onKeyUp={onKeyUp} onBlur={onSubmit} />
tag={{ title: input }}
onInput={onInput}
onKeyUp={onKeyUp}
onBlur={onSubmit}
/>
)} )}
</TagField> </TagField>
); );