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:
parent
1472d647f8
commit
c989d50277
2 changed files with 96 additions and 93 deletions
|
@ -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 };
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue