1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-05-01 15:46:40 +07:00

made tags panel

This commit is contained in:
Fedor Katurov 2020-10-31 15:06:08 +07:00
parent f2289f4530
commit c4f60f3d81
31 changed files with 552 additions and 75 deletions
src/components
containers/InfiniteScroll
flow/FlowRecentItem
node
sidebar/TagSidebarList

View file

@ -0,0 +1,42 @@
import React, { FC, HTMLAttributes, useCallback, useEffect, useRef } from 'react';
import styles from './styles.module.scss';
interface IProps extends HTMLAttributes<HTMLDivElement> {
hasMore: boolean;
scrollReactPx?: number;
loadMore: () => void;
}
const InfiniteScroll: FC<IProps> = ({ children, hasMore, scrollReactPx, loadMore, ...props }) => {
const ref = useRef<HTMLDivElement>(null);
const onScrollEnd = useCallback(
(entries: IntersectionObserverEntry[]) => {
if (!hasMore || !entries[0].isIntersecting) return;
loadMore();
},
[hasMore, loadMore]
);
useEffect(() => {
if (!ref.current) return;
const observer = new IntersectionObserver(onScrollEnd, {
root: null,
rootMargin: '200px',
threshold: 1.0,
});
observer.observe(ref.current);
return () => observer.disconnect();
}, [ref.current, onScrollEnd]);
return (
<div {...props}>
{children}
{hasMore && <div className={styles.more} ref={ref} />}
</div>
);
};
export { InfiniteScroll };

View file

@ -0,0 +1,2 @@
.more {
}

View file

@ -54,4 +54,7 @@
font: $font_12_regular;
margin-top: 4px;
opacity: 0.5;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

View file

@ -6,10 +6,13 @@ interface IProps {
is_editable?: boolean;
tags: ITag[];
onChange?: (tags: string[]) => void;
onTagClick?: (tag: Partial<ITag>) => void;
}
const NodeTags: FC<IProps> = memo(({ is_editable, tags, onChange }) => (
<Tags tags={tags} is_editable={is_editable} onTagsChange={onChange} />
));
const NodeTags: FC<IProps> = memo(({ is_editable, tags, onChange, onTagClick }) => {
return (
<Tags tags={tags} is_editable={is_editable} onTagsChange={onChange} onTagClick={onTagClick} />
);
});
export { NodeTags };

View file

@ -1,4 +1,4 @@
import React, { ChangeEventHandler, FC, FocusEventHandler, KeyboardEventHandler } from 'react';
import React, { ChangeEventHandler, FC, FocusEventHandler, KeyboardEventHandler, useCallback, } from 'react';
import * as styles from './styles.scss';
import { ITag } from '~/redux/types';
import classNames = require('classnames');
@ -11,6 +11,7 @@ const getTagFeature = (tag: Partial<ITag>) => {
interface IProps {
tag: Partial<ITag>;
size?: 'normal' | 'big';
is_hoverable?: boolean;
is_editing?: boolean;
@ -18,32 +19,51 @@ interface IProps {
onInput?: ChangeEventHandler<HTMLInputElement>;
onKeyUp?: KeyboardEventHandler;
onBlur?: FocusEventHandler<HTMLInputElement>;
onClick?: (tag: Partial<ITag>) => void;
}
const Tag: FC<IProps> = ({ tag, is_hoverable, is_editing, onInput, onKeyUp, onBlur }) => (
<div
className={classNames(styles.tag, getTagFeature(tag), {
is_hoverable,
is_editing,
input: !!onInput,
})}
>
<div className={styles.hole} />
<div className={styles.title}>{tag.title}</div>
const Tag: FC<IProps> = ({
tag,
is_hoverable,
is_editing,
size = 'normal',
onInput,
onKeyUp,
onBlur,
onClick,
}) => {
const onClickHandler = useCallback(() => {
if (!onClick) return;
onClick(tag);
}, [tag, onClick]);
{onInput && (
<input
type="text"
value={tag.title}
size={1}
placeholder="Добавить"
maxLength={24}
onChange={onInput}
onKeyUp={onKeyUp}
onBlur={onBlur}
/>
)}
</div>
);
return (
<div
className={classNames(styles.tag, getTagFeature(tag), size, {
is_hoverable,
is_editing,
input: !!onInput,
clickable: !!onClick,
})}
onClick={onClickHandler}
>
<div className={styles.hole} />
<div className={styles.title}>{tag.title}</div>
{onInput && (
<input
type="text"
value={tag.title}
size={1}
placeholder="Добавить"
maxLength={24}
onChange={onInput}
onKeyUp={onKeyUp}
onBlur={onBlur}
/>
)}
</div>
);
};
export { Tag };

View file

@ -1,6 +1,9 @@
$big: 1.2;
.tag {
@include outer_shadow();
cursor: default;
height: $tag_height;
background: $tag_bg;
display: flex;
@ -14,6 +17,17 @@
margin: 0 $gap $gap 0;
position: relative;
&:global(.big) {
height: $tag_height * $big;
font: $font_16_semibold;
border-radius: ($tag_height * $big / 2) 3px 3px ($tag_height * $big / 2);
.hole {
width: $tag_height * $big;
height: $tag_height * $big;
}
}
&:global(.is_hoverable) {
cursor: pointer;
}
@ -56,6 +70,10 @@
min-width: 100px;
}
&:global(.clickable) {
cursor: pointer;
}
input {
background: none;
border: none;
@ -80,7 +98,6 @@
width: $tag_height;
height: $tag_height;
display: flex;
// padding-right: 0px;
align-items: center;
justify-content: center;
flex: 0 0 $tag_height;

View file

@ -1,13 +1,13 @@
import React, {
ChangeEvent,
FC,
HTMLAttributes,
useState,
KeyboardEvent,
useCallback,
useEffect,
KeyboardEvent,
ChangeEvent,
useRef,
useMemo,
useRef,
useState,
} from 'react';
import { TagField } from '~/components/containers/TagField';
import { ITag } from '~/redux/types';
@ -18,9 +18,10 @@ type IProps = HTMLAttributes<HTMLDivElement> & {
tags: Partial<ITag>[];
is_editable?: boolean;
onTagsChange?: (tags: string[]) => void;
onTagClick?: (tag: Partial<ITag>) => void;
};
export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, ...props }) => {
export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, onTagClick, ...props }) => {
const [input, setInput] = useState('');
const [data, setData] = useState([]);
const timer = useRef(null);
@ -98,11 +99,11 @@ export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, ...props })
return (
<TagField {...props}>
{catTags.map(tag => (
<Tag key={tag.title} tag={tag} />
<Tag key={tag.title} tag={tag} onClick={onTagClick} />
))}
{ordinaryTags.map(tag => (
<Tag key={tag.title} tag={tag} />
<Tag key={tag.title} tag={tag} onClick={onTagClick} />
))}
{data.map(tag => (

View file

@ -0,0 +1,18 @@
import React, { FC } from 'react';
import { INode } from '~/redux/types';
import styles from './styles.module.scss';
import { FlowRecentItem } from '~/components/flow/FlowRecentItem';
interface IProps {
nodes: INode[];
}
const TagSidebarList: FC<IProps> = ({ nodes }) => (
<div className={styles.list}>
{nodes.map(node => (
<FlowRecentItem node={node} key={node.id} />
))}
</div>
);
export { TagSidebarList };

View file

@ -0,0 +1,4 @@
.list {
flex: 1;
flex-direction: column;
}