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

Merge branch 'master' into feature/8-image-preloader

This commit is contained in:
Fedor Katurov 2020-11-06 21:27:42 +07:00
commit 3a59e5789e
267 changed files with 1471 additions and 425 deletions

View file

@ -1,5 +1,5 @@
import React, { FC, useCallback } from 'react';
import styles from './styles.scss';
import styles from './styles.module.scss';
import { Button } from '~/components/input/Button';
import { nodeLockComment } from '~/redux/node/actions';
import { IComment } from '~/redux/types';

View file

@ -2,7 +2,7 @@ import React, { FC, HTMLAttributes, memo } from 'react';
import { CommentWrapper } from '~/components/containers/CommentWrapper';
import { ICommentGroup, IComment } from '~/redux/types';
import { CommentContent } from '~/components/node/CommentContent';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { nodeLockComment, nodeEditComment } from '~/redux/node/actions';
import { INodeState } from '~/redux/node/reducer';
import { CommentForm } from '../CommentForm';

View file

@ -3,7 +3,7 @@ import { IComment, IFile } from '~/redux/types';
import path from 'ramda/es/path';
import { formatCommentText, getURL, getPrettyDate } from '~/utils/dom';
import { Group } from '~/components/containers/Group';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import assocPath from 'ramda/es/assocPath';
import append from 'ramda/es/append';

View file

@ -1,6 +1,6 @@
import React, { FC, KeyboardEventHandler, memo, useCallback, useEffect, useMemo } from 'react';
import { Textarea } from '~/components/input/Textarea';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { Filler } from '~/components/containers/Filler';
import { Button } from '~/components/input/Button';
import assocPath from 'ramda/es/assocPath';

View file

@ -1,5 +1,5 @@
import React, { FC, useState, useCallback } from 'react';
import styles from './styles.scss';
import styles from './styles.module.scss';
interface IProps {
onEdit: () => void;

View file

@ -2,7 +2,7 @@ import React, { FC } from 'react';
import range from 'ramda/es/range';
import classNames from 'classnames';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
interface IProps {
total: number;

View file

@ -1,5 +1,5 @@
import React, { FC } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group';
import { Filler } from '~/components/containers/Filler';

View file

@ -2,7 +2,7 @@ import React, { FC, useMemo } from 'react';
import { INode } from '~/redux/types';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import { AudioPlayer } from '~/components/media/AudioPlayer';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { INodeComponentProps } from '~/redux/node/constants';
interface IProps extends INodeComponentProps {}

View file

@ -1,6 +1,6 @@
import React, { FC, useMemo } from 'react';
import { INode } from '~/redux/types';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import path from 'ramda/es/path';
import { getURL } from '~/utils/dom';

View file

@ -1,7 +1,7 @@
import React, { FC, useCallback, KeyboardEventHandler, useEffect, useMemo } from 'react';
import { Textarea } from '~/components/input/Textarea';
import { CommentWrapper } from '~/components/containers/CommentWrapper';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { Filler } from '~/components/containers/Filler';
import { Button } from '~/components/input/Button';
import assocPath from 'ramda/es/assocPath';

View file

@ -2,7 +2,7 @@ import React, { FC, useMemo, memo } from 'react';
import { Comment } from '../Comment';
import { Filler } from '~/components/containers/Filler';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { ICommentGroup, IComment } from '~/redux/types';
import { groupCommentsByUser } from '~/utils/fn';
import { IUser } from '~/redux/auth/types';

View file

@ -1,5 +1,5 @@
import React, { FC } from 'react';
import styles from './styles.scss';
import styles from './styles.module.scss';
interface IProps {}

View file

@ -1,6 +1,6 @@
import React, { FC, useMemo, useState, useEffect, useRef, useCallback } from 'react';
import { ImageSwitcher } from '../ImageSwitcher';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { INode } from '~/redux/types';
import classNames from 'classnames';
import { getURL } from '~/utils/dom';

View file

@ -1,5 +1,5 @@
import React, { FC } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { LoaderCircle } from '~/components/input/LoaderCircle';
const NodeImageBlockPlaceholder: FC<{}> = () => (

View file

@ -1,5 +1,5 @@
import React, { FC, useMemo, useState, useEffect, useRef, useCallback } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import classNames from 'classnames';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import { INodeComponentProps } from '~/redux/node/constants';

View file

@ -1,5 +1,5 @@
import React, { FC, useMemo } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group';
import classNames from 'classnames';
import { Filler } from '~/components/containers/Filler';

View file

@ -1,5 +1,5 @@
import React, { FC, useCallback, useEffect, useRef, useState, memo } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { INode } from '~/redux/types';
import { createPortal } from 'react-dom';
import { NodePanelInner } from '~/components/node/NodePanelInner';

View file

@ -1,5 +1,5 @@
import React, { FC, memo } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group';
import { Filler } from '~/components/containers/Filler';
import { Icon } from '~/components/input/Icon';

View file

@ -1,11 +1,11 @@
import React, { FC } from 'react';
import * as styles from './styles.scss';
import React, { FC, ReactElement } from 'react';
import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group';
import { INode } from '~/redux/types';
import { NodeRelatedItem } from '~/components/node/NodeRelatedItem';
interface IProps {
title: string;
title: ReactElement | string;
items: Partial<INode>[];
}

View file

@ -1,6 +1,6 @@
import React, { FC, memo } from "react";
import styles from "./styles.scss";
import cell_style from "~/components/node/NodeRelatedItem/styles.scss";
import styles from './styles.module.scss';
import cell_style from "~/components/node/NodeRelatedItem/styles.module.scss";
import { Group } from "~/components/containers/Group";
import { Placeholder } from "~/components/placeholders/Placeholder";
import range from "ramda/es/range";

View file

@ -20,6 +20,11 @@
.title {
@include title_with_line();
a {
text-decoration: none;
color: inherit;
}
}
.text {

View file

@ -1,5 +1,5 @@
import React, { FC, memo, useCallback, useState, useMemo } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import classNames from 'classnames';
import { INode } from '~/redux/types';
import { URLS, PRESETS } from '~/constants/urls';

View file

@ -1,15 +1,18 @@
import React, { FC, memo } from 'react';
import { Tags } from '../Tags';
import { ITag } from '~/redux/types';
import { Tags } from '~/components/tags/Tags';
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,17 +0,0 @@
import React, { FC, memo } from "react";
import { Tags } from "../Tags";
import { ITag } from "~/redux/types";
interface IProps {
is_editable?: boolean;
tags: ITag[];
onChange?: (tags: string[]) => void;
}
const NodeTagsPlaceholder: FC<IProps> = memo(
({ is_editable, tags, onChange }) => (
<Tags tags={tags} is_editable={is_editable} onTagsChange={onChange} />
)
);
export { NodeTagsPlaceholder };

View file

@ -0,0 +1,15 @@
import React, { FC, memo } from 'react';
import { ITag } from '~/redux/types';
import { Tags } from '~/components/tags/Tags';
interface IProps {
is_editable?: boolean;
tags: ITag[];
onChange?: (tags: string[]) => void;
}
const NodeTagsPlaceholder: FC<IProps> = memo(({ is_editable, tags, onChange }) => (
<Tags tags={tags} is_editable={is_editable} onTagsChange={onChange} />
));
export { NodeTagsPlaceholder };

View file

@ -2,7 +2,7 @@ import React, { FC } from 'react';
import { INode } from '~/redux/types';
import path from 'ramda/es/path';
import { formatTextParagraphs } from '~/utils/dom';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import { INodeComponentProps } from '~/redux/node/constants';
interface IProps extends INodeComponentProps {}

View file

@ -1,5 +1,5 @@
import React, { FC, useMemo } from 'react';
import * as styles from './styles.scss';
import styles from './styles.module.scss';
import path from 'ramda/es/path';
import { INodeComponentProps } from '~/redux/node/constants';

View file

@ -1,49 +0,0 @@
import React, { ChangeEventHandler, FC, FocusEventHandler, KeyboardEventHandler } from 'react';
import * as styles from './styles.scss';
import { ITag } from '~/redux/types';
import classNames = require('classnames');
const getTagFeature = (tag: Partial<ITag>) => {
if (tag.title.substr(0, 1) === '/') return 'green';
return '';
};
interface IProps {
tag: Partial<ITag>;
is_hoverable?: boolean;
is_editing?: boolean;
onInput?: ChangeEventHandler<HTMLInputElement>;
onKeyUp?: KeyboardEventHandler;
onBlur?: FocusEventHandler<HTMLInputElement>;
}
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>
{onInput && (
<input
type="text"
value={tag.title}
size={1}
placeholder="Добавить"
maxLength={24}
onChange={onInput}
onKeyUp={onKeyUp}
onBlur={onBlur}
/>
)}
</div>
);
export { Tag };

View file

@ -1,103 +0,0 @@
.tag {
@include outer_shadow();
height: $tag_height;
background: $tag_bg;
display: flex;
flex-direction: row;
align-items: center;
justify-content: stretch;
border-radius: ($tag_height / 2) 3px 3px ($tag_height / 2);
font: $font_14_semibold;
align-self: flex-start;
padding: 0 8px 0 0;
margin: 0 $gap $gap 0;
position: relative;
&:global(.is_hoverable) {
cursor: pointer;
}
&:global(.is_editing) {
cursor: pointer;
background-color: lighten($tag_bg, 10%);
}
&:global(.red) {
background: $red_gradient;
}
&:global(.blue) {
background: $blue_gradient;
}
&:global(.green) {
background: $green_gradient;
}
&:global(.olive) {
background: $olive;
color: transparentize(black, 0.4);
}
&:global(.black) {
background: transparentize(black, 0.7);
box-shadow: none;
color: transparentize(white, 0.6);
font: $font_14_medium;
.hole::after {
background: transparentize(white, 0.98);
}
}
&:global(.input) {
color: transparent !important;
min-width: 100px;
}
input {
background: none;
border: none;
color: white;
outline: none;
display: inline-flex;
position: absolute;
font: inherit;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 100%;
padding-left: $tag_height;
padding-right: 5px;
box-sizing: border-box;
}
}
.hole {
width: $tag_height;
height: $tag_height;
display: flex;
// padding-right: 0px;
align-items: center;
justify-content: center;
flex: 0 0 $tag_height;
&::after {
content: ' ';
position: absolute;
background: transparentize(black, 0.7);
width: 14px;
height: 14px;
border-radius: 14px;
}
}
.title {
white-space: nowrap;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}

View file

@ -1,117 +0,0 @@
import React, {
FC,
HTMLAttributes,
useState,
useCallback,
useEffect,
KeyboardEvent,
ChangeEvent,
useRef,
useMemo,
} from 'react';
import { TagField } from '~/components/containers/TagField';
import { ITag } from '~/redux/types';
import { Tag } from '~/components/node/Tag';
import uniq from 'ramda/es/uniq';
type IProps = HTMLAttributes<HTMLDivElement> & {
tags: Partial<ITag>[];
is_editable?: boolean;
onTagsChange?: (tags: string[]) => void;
};
export const Tags: FC<IProps> = ({ tags, is_editable, onTagsChange, ...props }) => {
const [input, setInput] = useState('');
const [data, setData] = useState([]);
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]],
[[], []]
),
[tags]
);
const onInput = useCallback(
({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
clearTimeout(timer.current);
setInput(value);
},
[setInput, timer]
);
const onKeyUp = useCallback(
({ key }: KeyboardEvent) => {
if (key === 'Backspace' && input === '' && data.length) {
setData(data.slice(0, data.length - 1));
setInput(data[data.length - 1].title);
}
if (key === 'Enter' || key === ',' || key === 'Comma') {
setData(
uniq([
...data,
...input
.split(',')
.map((title: string) =>
title
.trim()
.substr(0, 32)
.toLowerCase()
)
.filter(el => el.length > 0)
.filter(el => !tags.some(tag => tag.title.trim() === el.trim()))
.map(title => ({
title,
})),
])
);
setInput('');
}
},
[input, setInput, data, setData]
);
const onSubmit = useCallback(() => {
const title = input && input.trim();
const items = (title ? [...data, { title }] : data)
.filter(tag => tag.title.length > 0)
.map(tag => ({
...tag,
title: tag.title.toLowerCase(),
}));
if (!items.length) return;
setData(items);
setInput('');
onTagsChange(uniq([...tags, ...items]).map(tag => tag.title));
}, [tags, data, onTagsChange, input, setInput]);
useEffect(() => {
setData(data.filter(({ title }) => !tags.some(tag => tag.title.trim() === title.trim())));
}, [tags]);
return (
<TagField {...props}>
{catTags.map(tag => (
<Tag key={tag.title} tag={tag} />
))}
{ordinaryTags.map(tag => (
<Tag key={tag.title} tag={tag} />
))}
{data.map(tag => (
<Tag key={tag.title} tag={tag} is_editing />
))}
{is_editable && (
<Tag tag={{ title: input }} onInput={onInput} onKeyUp={onKeyUp} onBlur={onSubmit} />
)}
</TagField>
);
};