diff --git a/package.json b/package.json index 7332d17b..ce7d74c9 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "resolve-url-loader": "^3.0.1", "style-loader": "^0.21.0", "ts-node": "^8.4.1", - "typescript": "^3.6.4", + "typescript": "^3.7.2", "uglifyjs-webpack-plugin": "^1.3.0", "webpack": "^4.41.2", "webpack-cli": "^3.3.9", @@ -56,6 +56,7 @@ "license": "MIT", "dependencies": { "@hot-loader/react-dom": "^16.10.2", + "@popperjs/core": "^2.5.4", "@typescript-eslint/eslint-plugin": "^1.13.0", "@typescript-eslint/parser": "^1.13.0", "autosize": "^4.0.2", @@ -95,6 +96,7 @@ "react-dom": "^16.13.0", "react-hot-loader": "^4.12.15", "react-packery-component": "^1.0.2", + "react-popper": "^2.2.3", "react-redux": "^6.0.1", "react-router": "^5.1.2", "react-router-dom": "^5.1.2", diff --git a/src/components/bars/PlayerBar/index.tsx b/src/components/bars/PlayerBar/index.tsx index 3770ebd3..c6b0d5ec 100644 --- a/src/components/bars/PlayerBar/index.tsx +++ b/src/components/bars/PlayerBar/index.tsx @@ -1,7 +1,6 @@ -import React, { FC, useCallback, useState, useEffect } from 'react'; -import * as styles from './styles.scss'; +import React, { FC, useCallback, useEffect, useState } from 'react'; +import styles from './styles.module.scss'; import { Icon } from '~/components/input/Icon'; -import { Filler } from '~/components/containers/Filler'; import { PLAYER_STATES } from '~/redux/player/constants'; import { connect } from 'react-redux'; import pick from 'ramda/es/pick'; diff --git a/src/components/bars/PlayerBar/styles.scss b/src/components/bars/PlayerBar/styles.module.scss similarity index 100% rename from src/components/bars/PlayerBar/styles.scss rename to src/components/bars/PlayerBar/styles.module.scss diff --git a/src/components/bars/SubmitBar/index.tsx b/src/components/bars/SubmitBar/index.tsx index 6ed41060..de0b2ecd 100644 --- a/src/components/bars/SubmitBar/index.tsx +++ b/src/components/bars/SubmitBar/index.tsx @@ -4,7 +4,7 @@ import { Icon } from '~/components/input/Icon'; import * as NODE_ACTIONS from '~/redux/node/actions'; import { DIALOGS } from '~/redux/modal/constants'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { NODE_TYPES } from '~/redux/node/constants'; const mapStateToProps = null; diff --git a/src/components/bars/SubmitBar/styles.scss b/src/components/bars/SubmitBar/styles.module.scss similarity index 100% rename from src/components/bars/SubmitBar/styles.scss rename to src/components/bars/SubmitBar/styles.module.scss diff --git a/src/components/comment/CommentEmbedBlock/index.tsx b/src/components/comment/CommentEmbedBlock/index.tsx index e973cd2e..46bdd08a 100644 --- a/src/components/comment/CommentEmbedBlock/index.tsx +++ b/src/components/comment/CommentEmbedBlock/index.tsx @@ -1,6 +1,6 @@ import React, { FC, memo, useMemo, useEffect } from 'react'; import { ICommentBlockProps } from '~/constants/comment'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { getYoutubeThumb } from '~/utils/dom'; import { selectPlayer } from '~/redux/player/selectors'; import { connect } from 'react-redux'; diff --git a/src/components/comment/CommentEmbedBlock/styles.scss b/src/components/comment/CommentEmbedBlock/styles.module.scss similarity index 100% rename from src/components/comment/CommentEmbedBlock/styles.scss rename to src/components/comment/CommentEmbedBlock/styles.module.scss diff --git a/src/components/comment/CommentTextBlock/index.tsx b/src/components/comment/CommentTextBlock/index.tsx index 81714657..930eb96a 100644 --- a/src/components/comment/CommentTextBlock/index.tsx +++ b/src/components/comment/CommentTextBlock/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { ICommentBlockProps } from '~/constants/comment'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps extends ICommentBlockProps {} diff --git a/src/components/comment/CommentTextBlock/styles.scss b/src/components/comment/CommentTextBlock/styles.module.scss similarity index 100% rename from src/components/comment/CommentTextBlock/styles.scss rename to src/components/comment/CommentTextBlock/styles.module.scss diff --git a/src/components/containers/BlurWrapper/index.tsx b/src/components/containers/BlurWrapper/index.tsx index e7e7a0a3..f62cdf09 100644 --- a/src/components/containers/BlurWrapper/index.tsx +++ b/src/components/containers/BlurWrapper/index.tsx @@ -1,5 +1,5 @@ import React, { AllHTMLAttributes, FC } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import classNames from 'classnames'; type IProps = AllHTMLAttributes & { is_blurred: boolean }; diff --git a/src/components/containers/BlurWrapper/styles.scss b/src/components/containers/BlurWrapper/styles.module.scss similarity index 100% rename from src/components/containers/BlurWrapper/styles.scss rename to src/components/containers/BlurWrapper/styles.module.scss diff --git a/src/components/containers/Card/index.tsx b/src/components/containers/Card/index.tsx index f9c76a45..94b48f8d 100644 --- a/src/components/containers/Card/index.tsx +++ b/src/components/containers/Card/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import classNames from 'classnames'; diff --git a/src/components/containers/Card/styles.scss b/src/components/containers/Card/styles.module.scss similarity index 100% rename from src/components/containers/Card/styles.scss rename to src/components/containers/Card/styles.module.scss diff --git a/src/components/containers/CellGrid/index.tsx b/src/components/containers/CellGrid/index.tsx index 0f9e964e..e712bb76 100644 --- a/src/components/containers/CellGrid/index.tsx +++ b/src/components/containers/CellGrid/index.tsx @@ -1,5 +1,5 @@ import React, { FC, HTMLAttributes } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import classNames = require('classnames'); diff --git a/src/components/containers/CellGrid/styles.scss b/src/components/containers/CellGrid/styles.module.scss similarity index 100% rename from src/components/containers/CellGrid/styles.scss rename to src/components/containers/CellGrid/styles.module.scss diff --git a/src/components/containers/CommentWrapper/index.tsx b/src/components/containers/CommentWrapper/index.tsx index 1a7de34c..80c84eed 100644 --- a/src/components/containers/CommentWrapper/index.tsx +++ b/src/components/containers/CommentWrapper/index.tsx @@ -1,7 +1,7 @@ import React, { FC, HTMLAttributes } from 'react'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Card } from '../Card'; import { IUser } from '~/redux/auth/types'; import { getURL } from '~/utils/dom'; diff --git a/src/components/containers/CommentWrapper/styles.scss b/src/components/containers/CommentWrapper/styles.module.scss similarity index 100% rename from src/components/containers/CommentWrapper/styles.scss rename to src/components/containers/CommentWrapper/styles.module.scss diff --git a/src/components/containers/CoverBackdrop/index.tsx b/src/components/containers/CoverBackdrop/index.tsx index 3d8e12b0..2e491137 100644 --- a/src/components/containers/CoverBackdrop/index.tsx +++ b/src/components/containers/CoverBackdrop/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useState, useCallback, useEffect, useRef } from "react"; import { IUser } from "~/redux/auth/types"; -import styles from "./styles.scss"; +import styles from './styles.module.scss'; import { getURL } from "~/utils/dom"; import { PRESETS } from "~/constants/urls"; import classNames from "classnames"; diff --git a/src/components/containers/CoverBackdrop/styles.scss b/src/components/containers/CoverBackdrop/styles.module.scss similarity index 100% rename from src/components/containers/CoverBackdrop/styles.scss rename to src/components/containers/CoverBackdrop/styles.module.scss diff --git a/src/components/containers/Filler/index.tsx b/src/components/containers/Filler/index.tsx index 3af36783..4eb3fe88 100644 --- a/src/components/containers/Filler/index.tsx +++ b/src/components/containers/Filler/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; type IProps = React.HTMLAttributes; diff --git a/src/components/containers/Filler/styles.scss b/src/components/containers/Filler/styles.module.scss similarity index 100% rename from src/components/containers/Filler/styles.scss rename to src/components/containers/Filler/styles.module.scss diff --git a/src/components/containers/Grid/index.tsx b/src/components/containers/Grid/index.tsx index 830e404d..5f6a3e7d 100644 --- a/src/components/containers/Grid/index.tsx +++ b/src/components/containers/Grid/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; type IProps = React.HTMLAttributes & { horizontal?: boolean; diff --git a/src/components/containers/Grid/styles.scss b/src/components/containers/Grid/styles.module.scss similarity index 100% rename from src/components/containers/Grid/styles.scss rename to src/components/containers/Grid/styles.module.scss diff --git a/src/components/containers/Group/index.tsx b/src/components/containers/Group/index.tsx index 04576533..08099e28 100644 --- a/src/components/containers/Group/index.tsx +++ b/src/components/containers/Group/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; type IProps = React.HTMLAttributes & { horizontal?: boolean; diff --git a/src/components/containers/Group/styles.scss b/src/components/containers/Group/styles.module.scss similarity index 100% rename from src/components/containers/Group/styles.scss rename to src/components/containers/Group/styles.module.scss diff --git a/src/components/containers/InfiniteScroll/index.tsx b/src/components/containers/InfiniteScroll/index.tsx new file mode 100644 index 00000000..70db3103 --- /dev/null +++ b/src/components/containers/InfiniteScroll/index.tsx @@ -0,0 +1,42 @@ +import React, { FC, HTMLAttributes, useCallback, useEffect, useRef } from 'react'; +import styles from './styles.module.scss'; + +interface IProps extends HTMLAttributes { + hasMore: boolean; + scrollReactPx?: number; + loadMore: () => void; +} + +const InfiniteScroll: FC = ({ children, hasMore, scrollReactPx, loadMore, ...props }) => { + const ref = useRef(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 ( +
+ {children} + {hasMore &&
} +
+ ); +}; + +export { InfiniteScroll }; diff --git a/src/components/containers/InfiniteScroll/styles.module.scss b/src/components/containers/InfiniteScroll/styles.module.scss new file mode 100644 index 00000000..9fd1a252 --- /dev/null +++ b/src/components/containers/InfiniteScroll/styles.module.scss @@ -0,0 +1,2 @@ +.more { +} diff --git a/src/components/containers/Padder/index.tsx b/src/components/containers/Padder/index.tsx index 2a1a05d8..da9547f4 100644 --- a/src/components/containers/Padder/index.tsx +++ b/src/components/containers/Padder/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import classNames = require('classnames'); diff --git a/src/components/containers/Padder/styles.scss b/src/components/containers/Padder/styles.module.scss similarity index 100% rename from src/components/containers/Padder/styles.scss rename to src/components/containers/Padder/styles.module.scss diff --git a/src/components/containers/PageCover/index.tsx b/src/components/containers/PageCover/index.tsx index af7fdaed..e5154978 100644 --- a/src/components/containers/PageCover/index.tsx +++ b/src/components/containers/PageCover/index.tsx @@ -1,5 +1,5 @@ import React, { FC, memo } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { createPortal } from 'react-dom'; import { selectNode } from '~/redux/node/selectors'; import { connect } from 'react-redux'; diff --git a/src/components/containers/PageCover/styles.scss b/src/components/containers/PageCover/styles.module.scss similarity index 100% rename from src/components/containers/PageCover/styles.scss rename to src/components/containers/PageCover/styles.module.scss diff --git a/src/components/containers/Panel/index.tsx b/src/components/containers/Panel/index.tsx index 87c919f5..356cbe6c 100644 --- a/src/components/containers/Panel/index.tsx +++ b/src/components/containers/Panel/index.tsx @@ -1,5 +1,5 @@ import React, { FC, HTMLAttributes } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import classNames = require('classnames'); diff --git a/src/components/containers/Panel/styles.scss b/src/components/containers/Panel/styles.module.scss similarity index 100% rename from src/components/containers/Panel/styles.scss rename to src/components/containers/Panel/styles.module.scss diff --git a/src/components/containers/Scroll/index.tsx b/src/components/containers/Scroll/index.tsx index 07ea0dfd..ce5c4e74 100644 --- a/src/components/containers/Scroll/index.tsx +++ b/src/components/containers/Scroll/index.tsx @@ -1,7 +1,7 @@ import React, { MouseEventHandler, useEffect, useState } from 'react'; import { Scrollbars } from 'tt-react-custom-scrollbars'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps { children: Element | React.ReactChild; diff --git a/src/components/containers/Scroll/styles.scss b/src/components/containers/Scroll/styles.module.scss similarity index 100% rename from src/components/containers/Scroll/styles.scss rename to src/components/containers/Scroll/styles.module.scss diff --git a/src/components/containers/Sticky/index.tsx b/src/components/containers/Sticky/index.tsx index e70d6727..19956a34 100644 --- a/src/components/containers/Sticky/index.tsx +++ b/src/components/containers/Sticky/index.tsx @@ -1,5 +1,5 @@ import React, { FC, ReactComponentElement, DetailsHTMLAttributes, useEffect, useRef } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import StickySidebar from 'sticky-sidebar'; import classnames from 'classnames'; import ResizeSensor from 'resize-sensor'; diff --git a/src/components/containers/Sticky/styles.scss b/src/components/containers/Sticky/styles.module.scss similarity index 100% rename from src/components/containers/Sticky/styles.scss rename to src/components/containers/Sticky/styles.module.scss diff --git a/src/components/containers/TagField/index.tsx b/src/components/containers/TagField/index.tsx index 2fbdde5d..8490208f 100644 --- a/src/components/containers/TagField/index.tsx +++ b/src/components/containers/TagField/index.tsx @@ -1,5 +1,5 @@ import React, { FC, HTMLAttributes } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; type IProps = HTMLAttributes & {} diff --git a/src/components/containers/TagField/styles.scss b/src/components/containers/TagField/styles.module.scss similarity index 71% rename from src/components/containers/TagField/styles.scss rename to src/components/containers/TagField/styles.module.scss index f65e12d0..18edac3e 100644 --- a/src/components/containers/TagField/styles.scss +++ b/src/components/containers/TagField/styles.module.scss @@ -3,4 +3,8 @@ align-items: flex-start; justify-content: flex-start; flex-wrap: wrap; + + &> * { + margin: 0 $gap $gap 0; + } } diff --git a/src/components/dialogs/DialogTitle/index.tsx b/src/components/dialogs/DialogTitle/index.tsx index 875440dd..d74c5912 100644 --- a/src/components/dialogs/DialogTitle/index.tsx +++ b/src/components/dialogs/DialogTitle/index.tsx @@ -1,5 +1,5 @@ import React, { FC, ReactNode } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps { children: ReactNode; diff --git a/src/components/dialogs/DialogTitle/styles.scss b/src/components/dialogs/DialogTitle/styles.module.scss similarity index 100% rename from src/components/dialogs/DialogTitle/styles.scss rename to src/components/dialogs/DialogTitle/styles.module.scss diff --git a/src/components/editors/AudioEditor/index.tsx b/src/components/editors/AudioEditor/index.tsx index efa12941..a51c300d 100644 --- a/src/components/editors/AudioEditor/index.tsx +++ b/src/components/editors/AudioEditor/index.tsx @@ -7,7 +7,7 @@ import { AudioGrid } from '../AudioGrid'; import { selectUploads } from '~/redux/uploads/selectors'; import * as UPLOAD_ACTIONS from '~/redux/uploads/actions'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; const mapStateToProps = selectUploads; const mapDispatchToProps = { diff --git a/src/components/editors/AudioEditor/styles.scss b/src/components/editors/AudioEditor/styles.module.scss similarity index 100% rename from src/components/editors/AudioEditor/styles.scss rename to src/components/editors/AudioEditor/styles.module.scss diff --git a/src/components/editors/AudioGrid/index.tsx b/src/components/editors/AudioGrid/index.tsx index 40593006..7f2451a2 100644 --- a/src/components/editors/AudioGrid/index.tsx +++ b/src/components/editors/AudioGrid/index.tsx @@ -5,7 +5,7 @@ import { IUploadStatus } from '~/redux/uploads/reducer'; import { moveArrItem } from '~/utils/fn'; import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps { files: IFile[]; diff --git a/src/components/editors/AudioGrid/styles.scss b/src/components/editors/AudioGrid/styles.module.scss similarity index 100% rename from src/components/editors/AudioGrid/styles.scss rename to src/components/editors/AudioGrid/styles.module.scss diff --git a/src/components/editors/EditorPanel/index.tsx b/src/components/editors/EditorPanel/index.tsx index bbcec349..c91a41d6 100644 --- a/src/components/editors/EditorPanel/index.tsx +++ b/src/components/editors/EditorPanel/index.tsx @@ -1,5 +1,5 @@ import React, { FC, createElement } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { INode } from '~/redux/types'; import { NODE_PANEL_COMPONENTS } from '~/redux/node/constants'; diff --git a/src/components/editors/EditorPanel/styles.scss b/src/components/editors/EditorPanel/styles.module.scss similarity index 100% rename from src/components/editors/EditorPanel/styles.scss rename to src/components/editors/EditorPanel/styles.module.scss diff --git a/src/components/editors/EditorUploadButton/index.tsx b/src/components/editors/EditorUploadButton/index.tsx index c25acf68..49dad45e 100644 --- a/src/components/editors/EditorUploadButton/index.tsx +++ b/src/components/editors/EditorUploadButton/index.tsx @@ -1,5 +1,5 @@ import React, { FC, useCallback, useEffect } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Icon } from '~/components/input/Icon'; import { IFileWithUUID, INode, IFile } from '~/redux/types'; import uuid from 'uuid4'; diff --git a/src/components/editors/EditorUploadButton/styles.scss b/src/components/editors/EditorUploadButton/styles.module.scss similarity index 100% rename from src/components/editors/EditorUploadButton/styles.scss rename to src/components/editors/EditorUploadButton/styles.module.scss diff --git a/src/components/editors/EditorUploadCoverButton/index.tsx b/src/components/editors/EditorUploadCoverButton/index.tsx index aa2db3ca..a6f410ee 100644 --- a/src/components/editors/EditorUploadCoverButton/index.tsx +++ b/src/components/editors/EditorUploadCoverButton/index.tsx @@ -1,7 +1,7 @@ import React, { FC, useCallback, useEffect, useState } from 'react'; import { IFileWithUUID } from '~/redux/types'; import uuid from 'uuid4'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { UPLOAD_SUBJECTS, UPLOAD_TARGETS, UPLOAD_TYPES } from '~/redux/uploads/constants'; import path from 'ramda/es/path'; import { connect } from 'react-redux'; diff --git a/src/components/editors/EditorUploadCoverButton/styles.scss b/src/components/editors/EditorUploadCoverButton/styles.module.scss similarity index 100% rename from src/components/editors/EditorUploadCoverButton/styles.scss rename to src/components/editors/EditorUploadCoverButton/styles.module.scss diff --git a/src/components/editors/ImageEditor/index.tsx b/src/components/editors/ImageEditor/index.tsx index 0e9ead80..5dfe29e8 100644 --- a/src/components/editors/ImageEditor/index.tsx +++ b/src/components/editors/ImageEditor/index.tsx @@ -4,7 +4,7 @@ import { INode, IFile } from '~/redux/types'; import * as UPLOAD_ACTIONS from '~/redux/uploads/actions'; import { selectUploads } from '~/redux/uploads/selectors'; import { ImageGrid } from '~/components/editors/ImageGrid'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; const mapStateToProps = selectUploads; const mapDispatchToProps = { diff --git a/src/components/editors/ImageEditor/styles.scss b/src/components/editors/ImageEditor/styles.module.scss similarity index 100% rename from src/components/editors/ImageEditor/styles.scss rename to src/components/editors/ImageEditor/styles.module.scss diff --git a/src/components/editors/ImageGrid/index.tsx b/src/components/editors/ImageGrid/index.tsx index 3b97b7af..378b23e1 100644 --- a/src/components/editors/ImageGrid/index.tsx +++ b/src/components/editors/ImageGrid/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; import { SortEnd } from 'react-sortable-hoc'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { IFile } from '~/redux/types'; import { IUploadStatus } from '~/redux/uploads/reducer'; import { moveArrItem } from '~/utils/fn'; diff --git a/src/components/editors/ImageGrid/styles.scss b/src/components/editors/ImageGrid/styles.module.scss similarity index 100% rename from src/components/editors/ImageGrid/styles.scss rename to src/components/editors/ImageGrid/styles.module.scss diff --git a/src/components/editors/SortableAudioGrid/index.tsx b/src/components/editors/SortableAudioGrid/index.tsx index cb919d95..5ae04e1a 100644 --- a/src/components/editors/SortableAudioGrid/index.tsx +++ b/src/components/editors/SortableAudioGrid/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { SortableContainer } from 'react-sortable-hoc'; import { AudioUpload } from '~/components/upload/AudioUpload'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { SortableAudioGridItem } from '~/components/editors/SortableAudioGridItem'; import { IFile } from '~/redux/types'; import { IUploadStatus } from '~/redux/uploads/reducer'; diff --git a/src/components/editors/SortableAudioGrid/styles.scss b/src/components/editors/SortableAudioGrid/styles.module.scss similarity index 100% rename from src/components/editors/SortableAudioGrid/styles.scss rename to src/components/editors/SortableAudioGrid/styles.module.scss diff --git a/src/components/editors/SortableAudioGridItem/index.tsx b/src/components/editors/SortableAudioGridItem/index.tsx index f55d5194..463e0312 100644 --- a/src/components/editors/SortableAudioGridItem/index.tsx +++ b/src/components/editors/SortableAudioGridItem/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { SortableElement } from 'react-sortable-hoc'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; const SortableAudioGridItem = SortableElement(({ children }) => (
{children}
diff --git a/src/components/editors/SortableAudioGridItem/styles.scss b/src/components/editors/SortableAudioGridItem/styles.module.scss similarity index 100% rename from src/components/editors/SortableAudioGridItem/styles.scss rename to src/components/editors/SortableAudioGridItem/styles.module.scss diff --git a/src/components/editors/SortableImageGrid/index.tsx b/src/components/editors/SortableImageGrid/index.tsx index 79eae46c..edfc4ea7 100644 --- a/src/components/editors/SortableImageGrid/index.tsx +++ b/src/components/editors/SortableImageGrid/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { SortableContainer } from 'react-sortable-hoc'; import { ImageUpload } from '~/components/upload/ImageUpload'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { SortableImageGridItem } from '~/components/editors/SortableImageGridItem'; import { IFile } from '~/redux/types'; import { IUploadStatus } from '~/redux/uploads/reducer'; diff --git a/src/components/editors/SortableImageGrid/styles.scss b/src/components/editors/SortableImageGrid/styles.module.scss similarity index 100% rename from src/components/editors/SortableImageGrid/styles.scss rename to src/components/editors/SortableImageGrid/styles.module.scss diff --git a/src/components/editors/SortableImageGridItem/index.tsx b/src/components/editors/SortableImageGridItem/index.tsx index 6fb94e6e..01f650cd 100644 --- a/src/components/editors/SortableImageGridItem/index.tsx +++ b/src/components/editors/SortableImageGridItem/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { SortableElement } from 'react-sortable-hoc'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; const SortableImageGridItem = SortableElement(({ children }) => (
{children}
diff --git a/src/components/editors/SortableImageGridItem/styles.scss b/src/components/editors/SortableImageGridItem/styles.module.scss similarity index 100% rename from src/components/editors/SortableImageGridItem/styles.scss rename to src/components/editors/SortableImageGridItem/styles.module.scss diff --git a/src/components/editors/TextEditor/index.tsx b/src/components/editors/TextEditor/index.tsx index 539045f1..c183ca9a 100644 --- a/src/components/editors/TextEditor/index.tsx +++ b/src/components/editors/TextEditor/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; import { INode } from '~/redux/types'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Textarea } from '~/components/input/Textarea'; import path from 'ramda/es/path'; diff --git a/src/components/editors/TextEditor/styles.scss b/src/components/editors/TextEditor/styles.module.scss similarity index 100% rename from src/components/editors/TextEditor/styles.scss rename to src/components/editors/TextEditor/styles.module.scss diff --git a/src/components/editors/VideoEditor/index.tsx b/src/components/editors/VideoEditor/index.tsx index 5d2ac72a..b0bac6da 100644 --- a/src/components/editors/VideoEditor/index.tsx +++ b/src/components/editors/VideoEditor/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback, useMemo } from 'react'; import { INode } from '~/redux/types'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import path from 'ramda/es/path'; import { InputText } from '~/components/input/InputText'; import classnames from 'classnames'; diff --git a/src/components/editors/VideoEditor/styles.scss b/src/components/editors/VideoEditor/styles.module.scss similarity index 100% rename from src/components/editors/VideoEditor/styles.scss rename to src/components/editors/VideoEditor/styles.module.scss diff --git a/src/components/flow/Cell/index.tsx b/src/components/flow/Cell/index.tsx index 07b5a323..75523ffa 100644 --- a/src/components/flow/Cell/index.tsx +++ b/src/components/flow/Cell/index.tsx @@ -1,9 +1,9 @@ -import React, { FC, useState, useCallback, useEffect, useRef, useMemo } from 'react'; +import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { INode } from '~/redux/types'; -import { getURL, formatCellText } from '~/utils/dom'; +import { formatCellText, getURL } from '~/utils/dom'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Icon } from '~/components/input/Icon'; import { flowSetCellView } from '~/redux/flow/actions'; import { PRESETS } from '~/constants/urls'; @@ -109,6 +109,16 @@ const Cell: FC = ({ return getURL({ url: thumbnail }, preset); }, [thumbnail, flow]); + const titleSize = useMemo(() => { + if (title.length > 100) { + return styles.small; + } else if (title.length > 64) { + return styles.medium; + } else { + return; + } + }, [title]); + return (
{is_visible && ( @@ -134,7 +144,7 @@ const Cell: FC = ({
- {!text &&
{title || '...'}
} + {!text &&
{title || '...'}
} {!!text && !!thumbnail && (
diff --git a/src/components/flow/Cell/styles.scss b/src/components/flow/Cell/styles.module.scss similarity index 96% rename from src/components/flow/Cell/styles.scss rename to src/components/flow/Cell/styles.module.scss index 8f215692..72a6ed00 100644 --- a/src/components/flow/Cell/styles.scss +++ b/src/components/flow/Cell/styles.module.scss @@ -95,10 +95,21 @@ opacity: 1; transform: translate(0, 0); transition: opacity 0.5s, transform 1s; + + &.small { + @include clamp(8, 1.25em); + font-size: 24px; + } + + &.medium{ + @include clamp(6, 1.25em); + font-size: 28px; + } } .text_title { margin-bottom: $gap / 2; + @include clamp(3, 1.25em) } .horizontal, diff --git a/src/components/flow/FlowGrid/styles.scss b/src/components/flow/FlowGrid/styles.module.scss similarity index 100% rename from src/components/flow/FlowGrid/styles.scss rename to src/components/flow/FlowGrid/styles.module.scss diff --git a/src/components/flow/FlowHero/index.tsx b/src/components/flow/FlowHero/index.tsx index 2f0c36b8..409b2d5c 100644 --- a/src/components/flow/FlowHero/index.tsx +++ b/src/components/flow/FlowHero/index.tsx @@ -2,116 +2,94 @@ import React, { FC, useState, useCallback, useEffect, useRef, useMemo } from 're import { IFlowState } from '~/redux/flow/reducer'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { getURL } from '~/utils/dom'; -import { withRouter, RouteComponentProps } from 'react-router'; +import { withRouter, RouteComponentProps, useHistory } from 'react-router'; import { URLS, PRESETS } from '~/constants/urls'; import { Icon } from '~/components/input/Icon'; +import { INode } from "~/redux/types"; type IProps = RouteComponentProps & { heroes: IFlowState['heroes']; }; -const FlowHeroUnconnected: FC = ({ heroes, history }) => { - const [limit, setLimit] = useState(Math.min(heroes.length, 6)); +const FlowHeroUnconnected: FC = ({ heroes }) => { + const preset = useMemo(() => (window.innerWidth <= 768 ? PRESETS.cover : PRESETS.small_hero), []); + const [limit, setLimit] = useState(6); const [current, setCurrent] = useState(0); - const [loaded, setLoaded] = useState([]); + const [loaded, setLoaded] = useState[]>([]); + const timer = useRef(null) + const history = useHistory(); - const timer = useRef(null); - const onLoad = useCallback(id => () => setLoaded([...loaded, id]), [setLoaded, loaded]); - const onNext = useCallback(() => { - clearTimeout(timer.current); + const onLoad = useCallback((i: number) => { + setLoaded([...loaded, heroes[i]]) + }, [heroes, loaded, setLoaded]) - if (loaded.length <= 1) return; - - const index = loaded.findIndex(el => el === current); - - setCurrent(index > loaded.length - 2 ? loaded[0] : loaded[index + 1]); - }, [loaded, current, setCurrent, timer]); - - const onNextPress = useCallback(() => { - setLimit(Math.min(heroes.length, limit + 1)); - onNext(); - }, [onNext, heroes, limit, setLimit]); - - const onPrevious = useCallback(() => { - clearTimeout(timer.current); - - if (loaded.length <= 1) return; - - const index = loaded.findIndex(el => el === current); - - setCurrent(index > 0 ? loaded[index - 1] : loaded[loaded.length - 1]); - }, [loaded, current, setCurrent, timer]); - - useEffect(() => { - timer.current = setTimeout(onNext, 5000); - }, [current, onNext]); - - useEffect(() => { - if (current === 0 && loaded.length > 0) setCurrent(loaded[0]); - }, [loaded]); - - useEffect(() => { - setLimit(limit > 0 ? Math.min(heroes.length, limit) : heroes.length); - }, [heroes, limit]); - - const stopSliding = useCallback(() => { - clearTimeout(timer.current); - timer.current = setTimeout(onNext, 5000); - }, [timer, onNext]); - - const onClick = useCallback(() => { - if (!current) return; - - history.push(URLS.NODE_URL(current)); - }, [current]); + const items = Math.min(heroes.length, limit) const title = useMemo(() => { - if (loaded.length === 0) return null; - - const item = heroes.find(hero => hero.id === current); - - if (!item || !item.title) return null; - - return item.title; + return loaded[current]?.title || ''; }, [loaded, current, heroes]); - const preset = useMemo(() => (window.innerWidth <= 768 ? PRESETS.cover : PRESETS.small_hero), []); + const onNext = useCallback(() => { + if (heroes.length > limit) setLimit(limit + 1) + setCurrent(current < items - 1 ? current + 1 : 0) + }, [current, items, limit, heroes.length]) + const onPrev = useCallback(() => setCurrent(current > 0 ? current - 1 : items - 1), [current, items]) + + const goToNode = useCallback(() => { + history.push(URLS.NODE_URL(loaded[current].id)) + }, [current, loaded]); + + useEffect(() => { + timer.current = setTimeout(onNext, 5000) + return () => clearTimeout(timer.current) + }, [current, timer.current]) + + useEffect(() => { + if (loaded.length === 1) onNext() + }, [loaded]) return ( -
- {loaded && loaded.length > 0 && ( +
+
+ { + heroes.slice(0, items).map((hero, i) => ( + onLoad(i)} /> + )) + } +
+ + {loaded.length > 0 && (
{title}
-
+
-
+
)} - {heroes.slice(0, limit).map(hero => ( + {loaded.slice(0, limit).map((hero, index) => (
{hero.thumbnail}
))} diff --git a/src/components/flow/FlowHero/styles.scss b/src/components/flow/FlowHero/styles.module.scss similarity index 88% rename from src/components/flow/FlowHero/styles.scss rename to src/components/flow/FlowHero/styles.module.scss index f7f9865b..62a8500f 100644 --- a/src/components/flow/FlowHero/styles.scss +++ b/src/components/flow/FlowHero/styles.module.scss @@ -109,25 +109,11 @@ } } -// .title { -// flex: 0; -// height: 48px; -// display: flex; -// align-items: center; -// justify-content: center; -// padding: 0 $gap 0 0; -// background: red; -// border-radius: $radius; -// font: $font_hero_title; -// text-transform: uppercase; -// } - .buttons { display: flex; align-items: center; justify-content: center; height: 48px; - // background: rgba(0, 0, 0, 0.7); flex-direction: row; width: 96px; border-radius: $radius; @@ -145,3 +131,18 @@ } } } + +.loaders { + position: absolute; + top: 0; + left: 0; + opacity: 0; + pointer-events: none; + touch-action: none; + + img { + position: absolute; + left: 0; + top: 0; + } +} diff --git a/src/components/flow/FlowRecent/styles.scss b/src/components/flow/FlowRecent/styles.module.scss similarity index 100% rename from src/components/flow/FlowRecent/styles.scss rename to src/components/flow/FlowRecent/styles.module.scss diff --git a/src/components/flow/FlowRecentItem/index.tsx b/src/components/flow/FlowRecentItem/index.tsx index 471718e2..16192e69 100644 --- a/src/components/flow/FlowRecentItem/index.tsx +++ b/src/components/flow/FlowRecentItem/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { INode } from '~/redux/types'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { URLS } from '~/constants/urls'; import { NodeRelatedItem } from '~/components/node/NodeRelatedItem'; import { getPrettyDate } from '~/utils/dom'; diff --git a/src/components/flow/FlowRecentItem/styles.scss b/src/components/flow/FlowRecentItem/styles.module.scss similarity index 93% rename from src/components/flow/FlowRecentItem/styles.scss rename to src/components/flow/FlowRecentItem/styles.module.scss index d103d429..42381a98 100644 --- a/src/components/flow/FlowRecentItem/styles.scss +++ b/src/components/flow/FlowRecentItem/styles.module.scss @@ -54,4 +54,7 @@ font: $font_12_regular; margin-top: 4px; opacity: 0.5; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } diff --git a/src/components/flow/FlowSearchResults/index.tsx b/src/components/flow/FlowSearchResults/index.tsx index 2b5e9925..b159ff40 100644 --- a/src/components/flow/FlowSearchResults/index.tsx +++ b/src/components/flow/FlowSearchResults/index.tsx @@ -1,5 +1,5 @@ import React, { FC, useCallback } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { IFlowState } from '~/redux/flow/reducer'; import { LoaderCircle } from '~/components/input/LoaderCircle'; import { FlowRecentItem } from '../FlowRecentItem'; diff --git a/src/components/flow/FlowSearchResults/styles.scss b/src/components/flow/FlowSearchResults/styles.module.scss similarity index 100% rename from src/components/flow/FlowSearchResults/styles.scss rename to src/components/flow/FlowSearchResults/styles.module.scss diff --git a/src/components/flow/FlowStamp/index.tsx b/src/components/flow/FlowStamp/index.tsx index da5a6bd3..04005887 100644 --- a/src/components/flow/FlowStamp/index.tsx +++ b/src/components/flow/FlowStamp/index.tsx @@ -4,7 +4,7 @@ import { InputText } from '~/components/input/InputText'; import { FlowRecent } from '../FlowRecent'; import classnames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import * as FLOW_ACTIONS from '~/redux/flow/actions'; import { FlowSearchResults } from '../FlowSearchResults'; import { Icon } from '~/components/input/Icon'; diff --git a/src/components/flow/FlowStamp/styles.scss b/src/components/flow/FlowStamp/styles.module.scss similarity index 100% rename from src/components/flow/FlowStamp/styles.scss rename to src/components/flow/FlowStamp/styles.module.scss diff --git a/src/components/input/ArcProgress/index.tsx b/src/components/input/ArcProgress/index.tsx index 374fd3df..f9db81ea 100644 --- a/src/components/input/ArcProgress/index.tsx +++ b/src/components/input/ArcProgress/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { describeArc } from '~/utils/dom'; interface IProps { diff --git a/src/components/input/ArcProgress/styles.scss b/src/components/input/ArcProgress/styles.module.scss similarity index 100% rename from src/components/input/ArcProgress/styles.scss rename to src/components/input/ArcProgress/styles.module.scss diff --git a/src/components/input/Button/index.tsx b/src/components/input/Button/index.tsx index 0346b3e7..7b9d8a8c 100644 --- a/src/components/input/Button/index.tsx +++ b/src/components/input/Button/index.tsx @@ -1,6 +1,6 @@ import classnames from 'classnames'; import React, { ButtonHTMLAttributes, DetailedHTMLProps, FC, createElement, memo } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Icon } from '~/components/input/Icon'; import { IIcon } from '~/redux/types'; diff --git a/src/components/input/Button/styles.scss b/src/components/input/Button/styles.module.scss similarity index 100% rename from src/components/input/Button/styles.scss rename to src/components/input/Button/styles.module.scss diff --git a/src/components/input/ButtonGroup/index.tsx b/src/components/input/ButtonGroup/index.tsx index 72c993f3..6a82b590 100644 --- a/src/components/input/ButtonGroup/index.tsx +++ b/src/components/input/ButtonGroup/index.tsx @@ -1,5 +1,5 @@ import React, { HTMLAttributes } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; type IProps = HTMLAttributes & {}; diff --git a/src/components/input/ButtonGroup/styles.scss b/src/components/input/ButtonGroup/styles.module.scss similarity index 100% rename from src/components/input/ButtonGroup/styles.scss rename to src/components/input/ButtonGroup/styles.module.scss diff --git a/src/components/input/InputText/index.tsx b/src/components/input/InputText/index.tsx index eae62ab5..caf00ceb 100644 --- a/src/components/input/InputText/index.tsx +++ b/src/components/input/InputText/index.tsx @@ -1,6 +1,6 @@ import React, { FC, ChangeEvent, useCallback, useState, useEffect, LegacyRef } from 'react'; import classNames from 'classnames'; -import * as styles from '~/styles/inputs.scss'; +import * as styles from '~/styles/common/inputs.module.scss'; import { Icon } from '~/components/input/Icon'; import { IInputTextProps } from '~/redux/types'; import { LoaderCircle } from '~/components/input/LoaderCircle'; diff --git a/src/components/input/LoaderCircle/index.tsx b/src/components/input/LoaderCircle/index.tsx index 49c2fbe6..c555f568 100644 --- a/src/components/input/LoaderCircle/index.tsx +++ b/src/components/input/LoaderCircle/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { describeArc } from '~/utils/dom'; import classNames from 'classnames'; diff --git a/src/components/input/LoaderCircle/styles.scss b/src/components/input/LoaderCircle/styles.module.scss similarity index 100% rename from src/components/input/LoaderCircle/styles.scss rename to src/components/input/LoaderCircle/styles.module.scss diff --git a/src/components/input/TextInput/index.tsx b/src/components/input/TextInput/index.tsx index e05e2ad7..187cba81 100644 --- a/src/components/input/TextInput/index.tsx +++ b/src/components/input/TextInput/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; interface ITextInputProps { type?: 'text' | 'password'; diff --git a/src/components/input/TextInput/styles.scss b/src/components/input/TextInput/styles.module.scss similarity index 100% rename from src/components/input/TextInput/styles.scss rename to src/components/input/TextInput/styles.module.scss diff --git a/src/components/input/Textarea/index.tsx b/src/components/input/Textarea/index.tsx index 0d40aa22..15818bfd 100644 --- a/src/components/input/Textarea/index.tsx +++ b/src/components/input/Textarea/index.tsx @@ -11,7 +11,7 @@ import React, { import classNames from 'classnames'; import autosize from 'autosize'; -import * as styles from '~/styles/inputs.scss'; +import * as styles from '~/styles/common/inputs.module.scss'; import { Icon } from '../Icon'; type IProps = TextareaHTMLAttributes & { diff --git a/src/components/main/Footer/index.tsx b/src/components/main/Footer/index.tsx index 0ae17a29..5f494000 100644 --- a/src/components/main/Footer/index.tsx +++ b/src/components/main/Footer/index.tsx @@ -1,5 +1,5 @@ import React, { FC, memo } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps {} diff --git a/src/components/main/Footer/styles.scss b/src/components/main/Footer/styles.module.scss similarity index 100% rename from src/components/main/Footer/styles.scss rename to src/components/main/Footer/styles.module.scss diff --git a/src/components/main/Header/style.scss b/src/components/main/Header/style.scss index f3108962..45e99be5 100644 --- a/src/components/main/Header/style.scss +++ b/src/components/main/Header/style.scss @@ -1,6 +1,6 @@ .wrap { height: $header_height; - z-index: 5; + z-index: 25; position: fixed; top: 0; left: 0; diff --git a/src/components/main/Notifications/index.tsx b/src/components/main/Notifications/index.tsx index 34b1f415..6d1ac576 100644 --- a/src/components/main/Notifications/index.tsx +++ b/src/components/main/Notifications/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useMemo, useState, useCallback, useEffect } from 'react'; import { Icon } from '~/components/input/Icon'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { connect } from 'react-redux'; import { selectAuthUpdates, selectAuthUser } from '~/redux/auth/selectors'; import pick from 'ramda/es/pick'; diff --git a/src/components/main/Notifications/styles.scss b/src/components/main/Notifications/styles.module.scss similarity index 100% rename from src/components/main/Notifications/styles.scss rename to src/components/main/Notifications/styles.module.scss diff --git a/src/components/main/SidePane/index.tsx b/src/components/main/SidePane/index.tsx index f936a374..ee5c5907 100644 --- a/src/components/main/SidePane/index.tsx +++ b/src/components/main/SidePane/index.tsx @@ -2,7 +2,7 @@ import React, { FC, LegacyRef, ReactChild, useCallback, useEffect, useState } from 'react'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Group } from '~/components/containers/Group'; interface IProps { diff --git a/src/components/main/SidePane/styles.scss b/src/components/main/SidePane/styles.module.scss similarity index 100% rename from src/components/main/SidePane/styles.scss rename to src/components/main/SidePane/styles.module.scss diff --git a/src/components/main/UserButton/index.tsx b/src/components/main/UserButton/index.tsx index c3220067..b0b3af3b 100644 --- a/src/components/main/UserButton/index.tsx +++ b/src/components/main/UserButton/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; import { Group } from '~/components/containers/Group'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { getURL } from '~/utils/dom'; import { Icon } from '~/components/input/Icon'; import { IUser } from '~/redux/auth/types'; diff --git a/src/components/main/UserButton/styles.scss b/src/components/main/UserButton/styles.module.scss similarity index 100% rename from src/components/main/UserButton/styles.scss rename to src/components/main/UserButton/styles.module.scss diff --git a/src/components/media/AudioPlayer/index.tsx b/src/components/media/AudioPlayer/index.tsx index 420531c4..6e698639 100644 --- a/src/components/media/AudioPlayer/index.tsx +++ b/src/components/media/AudioPlayer/index.tsx @@ -6,7 +6,7 @@ import { IFile } from '~/redux/types'; import { PLAYER_STATES } from '~/redux/player/constants'; import { Player, IPlayerProgress } from '~/utils/player'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Icon } from '~/components/input/Icon'; import { InputText } from '~/components/input/InputText'; diff --git a/src/components/media/AudioPlayer/styles.scss b/src/components/media/AudioPlayer/styles.module.scss similarity index 100% rename from src/components/media/AudioPlayer/styles.scss rename to src/components/media/AudioPlayer/styles.module.scss diff --git a/src/components/node/CommendDeleted/index.tsx b/src/components/node/CommendDeleted/index.tsx index baaeebf0..340f6f90 100644 --- a/src/components/node/CommendDeleted/index.tsx +++ b/src/components/node/CommendDeleted/index.tsx @@ -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'; diff --git a/src/components/node/CommendDeleted/styles.scss b/src/components/node/CommendDeleted/styles.module.scss similarity index 100% rename from src/components/node/CommendDeleted/styles.scss rename to src/components/node/CommendDeleted/styles.module.scss diff --git a/src/components/node/Comment/index.tsx b/src/components/node/Comment/index.tsx index c126fa2b..839748b1 100644 --- a/src/components/node/Comment/index.tsx +++ b/src/components/node/Comment/index.tsx @@ -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'; diff --git a/src/components/node/Comment/styles.scss b/src/components/node/Comment/styles.module.scss similarity index 100% rename from src/components/node/Comment/styles.scss rename to src/components/node/Comment/styles.module.scss diff --git a/src/components/node/CommentContent/index.tsx b/src/components/node/CommentContent/index.tsx index e559e1dc..1accc82c 100644 --- a/src/components/node/CommentContent/index.tsx +++ b/src/components/node/CommentContent/index.tsx @@ -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'; diff --git a/src/components/node/CommentContent/styles.scss b/src/components/node/CommentContent/styles.module.scss similarity index 100% rename from src/components/node/CommentContent/styles.scss rename to src/components/node/CommentContent/styles.module.scss diff --git a/src/components/node/CommentForm/index.tsx b/src/components/node/CommentForm/index.tsx index 3d143d70..3481b9b5 100644 --- a/src/components/node/CommentForm/index.tsx +++ b/src/components/node/CommentForm/index.tsx @@ -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'; diff --git a/src/components/node/CommentForm/styles.scss b/src/components/node/CommentForm/styles.module.scss similarity index 100% rename from src/components/node/CommentForm/styles.scss rename to src/components/node/CommentForm/styles.module.scss diff --git a/src/components/node/CommentMenu/index.tsx b/src/components/node/CommentMenu/index.tsx index 9339f6b7..b8b84369 100644 --- a/src/components/node/CommentMenu/index.tsx +++ b/src/components/node/CommentMenu/index.tsx @@ -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; diff --git a/src/components/node/CommentMenu/styles.scss b/src/components/node/CommentMenu/styles.module.scss similarity index 100% rename from src/components/node/CommentMenu/styles.scss rename to src/components/node/CommentMenu/styles.module.scss diff --git a/src/components/node/ImageSwitcher/index.tsx b/src/components/node/ImageSwitcher/index.tsx index 89a4f456..dceb1eec 100644 --- a/src/components/node/ImageSwitcher/index.tsx +++ b/src/components/node/ImageSwitcher/index.tsx @@ -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; diff --git a/src/components/node/ImageSwitcher/styles.scss b/src/components/node/ImageSwitcher/styles.module.scss similarity index 100% rename from src/components/node/ImageSwitcher/styles.scss rename to src/components/node/ImageSwitcher/styles.module.scss diff --git a/src/components/node/MenuButton/index.tsx b/src/components/node/MenuButton/index.tsx index 4782c741..509a918d 100644 --- a/src/components/node/MenuButton/index.tsx +++ b/src/components/node/MenuButton/index.tsx @@ -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'; diff --git a/src/components/node/MenuButton/styles.scss b/src/components/node/MenuButton/styles.module.scss similarity index 100% rename from src/components/node/MenuButton/styles.scss rename to src/components/node/MenuButton/styles.module.scss diff --git a/src/components/node/NodeAudioBlock/index.tsx b/src/components/node/NodeAudioBlock/index.tsx index 6b3595e9..9581a16b 100644 --- a/src/components/node/NodeAudioBlock/index.tsx +++ b/src/components/node/NodeAudioBlock/index.tsx @@ -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 {} diff --git a/src/components/node/NodeAudioBlock/styles.scss b/src/components/node/NodeAudioBlock/styles.module.scss similarity index 100% rename from src/components/node/NodeAudioBlock/styles.scss rename to src/components/node/NodeAudioBlock/styles.module.scss diff --git a/src/components/node/NodeAudioImageBlock/index.tsx b/src/components/node/NodeAudioImageBlock/index.tsx index 1d7d295f..57e36d00 100644 --- a/src/components/node/NodeAudioImageBlock/index.tsx +++ b/src/components/node/NodeAudioImageBlock/index.tsx @@ -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'; diff --git a/src/components/node/NodeAudioImageBlock/styles.scss b/src/components/node/NodeAudioImageBlock/styles.module.scss similarity index 100% rename from src/components/node/NodeAudioImageBlock/styles.scss rename to src/components/node/NodeAudioImageBlock/styles.module.scss diff --git a/src/components/node/NodeCommentForm/index.tsx b/src/components/node/NodeCommentForm/index.tsx index 31506872..b72c663b 100644 --- a/src/components/node/NodeCommentForm/index.tsx +++ b/src/components/node/NodeCommentForm/index.tsx @@ -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'; diff --git a/src/components/node/NodeComments/index.tsx b/src/components/node/NodeComments/index.tsx index c7f541da..4cc1e3d3 100644 --- a/src/components/node/NodeComments/index.tsx +++ b/src/components/node/NodeComments/index.tsx @@ -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'; diff --git a/src/components/node/NodeComments/styles.scss b/src/components/node/NodeComments/styles.module.scss similarity index 100% rename from src/components/node/NodeComments/styles.scss rename to src/components/node/NodeComments/styles.module.scss diff --git a/src/components/node/NodeDeletedBadge/index.tsx b/src/components/node/NodeDeletedBadge/index.tsx index 1bb06283..c5cbbc03 100644 --- a/src/components/node/NodeDeletedBadge/index.tsx +++ b/src/components/node/NodeDeletedBadge/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps {} diff --git a/src/components/node/NodeDeletedBadge/styles.scss b/src/components/node/NodeDeletedBadge/styles.module.scss similarity index 100% rename from src/components/node/NodeDeletedBadge/styles.scss rename to src/components/node/NodeDeletedBadge/styles.module.scss diff --git a/src/components/node/NodeImageBlock/index.tsx b/src/components/node/NodeImageBlock/index.tsx index 124200d7..d3875ffc 100644 --- a/src/components/node/NodeImageBlock/index.tsx +++ b/src/components/node/NodeImageBlock/index.tsx @@ -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'; diff --git a/src/components/node/NodeImageBlock/styles.scss b/src/components/node/NodeImageBlock/styles.module.scss similarity index 100% rename from src/components/node/NodeImageBlock/styles.scss rename to src/components/node/NodeImageBlock/styles.module.scss diff --git a/src/components/node/NodeImageBlockPlaceholder/index.tsx b/src/components/node/NodeImageBlockPlaceholder/index.tsx index c63e9479..8a5c9b6e 100644 --- a/src/components/node/NodeImageBlockPlaceholder/index.tsx +++ b/src/components/node/NodeImageBlockPlaceholder/index.tsx @@ -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<{}> = () => ( diff --git a/src/components/node/NodeImageBlockPlaceholder/styles.scss b/src/components/node/NodeImageBlockPlaceholder/styles.module.scss similarity index 100% rename from src/components/node/NodeImageBlockPlaceholder/styles.scss rename to src/components/node/NodeImageBlockPlaceholder/styles.module.scss diff --git a/src/components/node/NodeImageSlideBlock/index.tsx b/src/components/node/NodeImageSlideBlock/index.tsx index 6ba8c19b..44e97b93 100644 --- a/src/components/node/NodeImageSlideBlock/index.tsx +++ b/src/components/node/NodeImageSlideBlock/index.tsx @@ -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'; diff --git a/src/components/node/NodeImageSlideBlock/styles.scss b/src/components/node/NodeImageSlideBlock/styles.module.scss similarity index 100% rename from src/components/node/NodeImageSlideBlock/styles.scss rename to src/components/node/NodeImageSlideBlock/styles.module.scss diff --git a/src/components/node/NodeNoComments/index.tsx b/src/components/node/NodeNoComments/index.tsx index f1395383..314670ee 100644 --- a/src/components/node/NodeNoComments/index.tsx +++ b/src/components/node/NodeNoComments/index.tsx @@ -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'; diff --git a/src/components/node/NodeNoComments/styles.scss b/src/components/node/NodeNoComments/styles.module.scss similarity index 100% rename from src/components/node/NodeNoComments/styles.scss rename to src/components/node/NodeNoComments/styles.module.scss diff --git a/src/components/node/NodePanel/index.tsx b/src/components/node/NodePanel/index.tsx index bebb3218..31973594 100644 --- a/src/components/node/NodePanel/index.tsx +++ b/src/components/node/NodePanel/index.tsx @@ -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'; diff --git a/src/components/node/NodePanel/styles.scss b/src/components/node/NodePanel/styles.module.scss similarity index 100% rename from src/components/node/NodePanel/styles.scss rename to src/components/node/NodePanel/styles.module.scss diff --git a/src/components/node/NodePanelInner/index.tsx b/src/components/node/NodePanelInner/index.tsx index 44799c1a..0ed58eab 100644 --- a/src/components/node/NodePanelInner/index.tsx +++ b/src/components/node/NodePanelInner/index.tsx @@ -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'; diff --git a/src/components/node/NodePanelInner/styles.scss b/src/components/node/NodePanelInner/styles.module.scss similarity index 100% rename from src/components/node/NodePanelInner/styles.scss rename to src/components/node/NodePanelInner/styles.module.scss diff --git a/src/components/node/NodeRelated/index.tsx b/src/components/node/NodeRelated/index.tsx index f119d9f2..8e9888f7 100644 --- a/src/components/node/NodeRelated/index.tsx +++ b/src/components/node/NodeRelated/index.tsx @@ -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[]; } diff --git a/src/components/node/NodeRelated/placeholder.tsx b/src/components/node/NodeRelated/placeholder.tsx index 42b6a2e0..b8e9d89f 100644 --- a/src/components/node/NodeRelated/placeholder.tsx +++ b/src/components/node/NodeRelated/placeholder.tsx @@ -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"; diff --git a/src/components/node/NodeRelated/styles.scss b/src/components/node/NodeRelated/styles.module.scss similarity index 90% rename from src/components/node/NodeRelated/styles.scss rename to src/components/node/NodeRelated/styles.module.scss index 1a47f904..2ffd5464 100644 --- a/src/components/node/NodeRelated/styles.scss +++ b/src/components/node/NodeRelated/styles.module.scss @@ -20,6 +20,11 @@ .title { @include title_with_line(); + + a { + text-decoration: none; + color: inherit; + } } .text { diff --git a/src/components/node/NodeRelatedItem/index.tsx b/src/components/node/NodeRelatedItem/index.tsx index 982f62e9..6c5a92c0 100644 --- a/src/components/node/NodeRelatedItem/index.tsx +++ b/src/components/node/NodeRelatedItem/index.tsx @@ -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'; diff --git a/src/components/node/NodeRelatedItem/styles.scss b/src/components/node/NodeRelatedItem/styles.module.scss similarity index 100% rename from src/components/node/NodeRelatedItem/styles.scss rename to src/components/node/NodeRelatedItem/styles.module.scss diff --git a/src/components/node/NodeTags/index.tsx b/src/components/node/NodeTags/index.tsx index 6c541051..d5c48923 100644 --- a/src/components/node/NodeTags/index.tsx +++ b/src/components/node/NodeTags/index.tsx @@ -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) => void; } -const NodeTags: FC = memo(({ is_editable, tags, onChange }) => ( - -)); +const NodeTags: FC = memo(({ is_editable, tags, onChange, onTagClick }) => { + return ( + + ); +}); export { NodeTags }; diff --git a/src/components/node/NodeTags/placeholder.tsx b/src/components/node/NodeTags/placeholder.tsx deleted file mode 100644 index f5b015b4..00000000 --- a/src/components/node/NodeTags/placeholder.tsx +++ /dev/null @@ -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 = memo( - ({ is_editable, tags, onChange }) => ( - - ) -); - -export { NodeTagsPlaceholder }; diff --git a/src/components/node/NodeTagsPlaceholder/index.tsx b/src/components/node/NodeTagsPlaceholder/index.tsx new file mode 100644 index 00000000..4fb8e75d --- /dev/null +++ b/src/components/node/NodeTagsPlaceholder/index.tsx @@ -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 = memo(({ is_editable, tags, onChange }) => ( + +)); + +export { NodeTagsPlaceholder }; diff --git a/src/components/node/NodeTextBlock/index.tsx b/src/components/node/NodeTextBlock/index.tsx index a272ac17..9ecbc69d 100644 --- a/src/components/node/NodeTextBlock/index.tsx +++ b/src/components/node/NodeTextBlock/index.tsx @@ -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 {} diff --git a/src/components/node/NodeTextBlock/styles.scss b/src/components/node/NodeTextBlock/styles.module.scss similarity index 100% rename from src/components/node/NodeTextBlock/styles.scss rename to src/components/node/NodeTextBlock/styles.module.scss diff --git a/src/components/node/NodeVideoBlock/index.tsx b/src/components/node/NodeVideoBlock/index.tsx index 9c03764c..406fb256 100644 --- a/src/components/node/NodeVideoBlock/index.tsx +++ b/src/components/node/NodeVideoBlock/index.tsx @@ -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'; diff --git a/src/components/node/NodeVideoBlock/styles.scss b/src/components/node/NodeVideoBlock/styles.module.scss similarity index 100% rename from src/components/node/NodeVideoBlock/styles.scss rename to src/components/node/NodeVideoBlock/styles.module.scss diff --git a/src/components/node/Tag/index.tsx b/src/components/node/Tag/index.tsx deleted file mode 100644 index fd8e4896..00000000 --- a/src/components/node/Tag/index.tsx +++ /dev/null @@ -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) => { - if (tag.title.substr(0, 1) === '/') return 'green'; - - return ''; -}; - -interface IProps { - tag: Partial; - - is_hoverable?: boolean; - is_editing?: boolean; - - onInput?: ChangeEventHandler; - onKeyUp?: KeyboardEventHandler; - onBlur?: FocusEventHandler; -} - -const Tag: FC = ({ tag, is_hoverable, is_editing, onInput, onKeyUp, onBlur }) => ( -
-
-
{tag.title}
- - {onInput && ( - - )} -
-); - -export { Tag }; diff --git a/src/components/node/Tags/index.tsx b/src/components/node/Tags/index.tsx deleted file mode 100644 index eafb933f..00000000 --- a/src/components/node/Tags/index.tsx +++ /dev/null @@ -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 & { - tags: Partial[]; - is_editable?: boolean; - onTagsChange?: (tags: string[]) => void; -}; - -export const Tags: FC = ({ 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) => { - 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 ( - - {catTags.map(tag => ( - - ))} - - {ordinaryTags.map(tag => ( - - ))} - - {data.map(tag => ( - - ))} - - {is_editable && ( - - )} - - ); -}; diff --git a/src/components/notifications/NotificationBubble/index.tsx b/src/components/notifications/NotificationBubble/index.tsx index 513a7013..9c9f2109 100644 --- a/src/components/notifications/NotificationBubble/index.tsx +++ b/src/components/notifications/NotificationBubble/index.tsx @@ -1,6 +1,6 @@ import React, { FC, createElement } from 'react'; import { INotification, NOTIFICATION_TYPES } from '~/redux/types'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { NotificationMessage } from '../NotificationMessage'; import { Icon } from '~/components/input/Icon'; import { getRandomPhrase } from '~/constants/phrases'; diff --git a/src/components/notifications/NotificationBubble/styles.scss b/src/components/notifications/NotificationBubble/styles.module.scss similarity index 100% rename from src/components/notifications/NotificationBubble/styles.scss rename to src/components/notifications/NotificationBubble/styles.module.scss diff --git a/src/components/notifications/NotificationMessage/index.tsx b/src/components/notifications/NotificationMessage/index.tsx index 09bf0165..f75f3dfb 100644 --- a/src/components/notifications/NotificationMessage/index.tsx +++ b/src/components/notifications/NotificationMessage/index.tsx @@ -1,5 +1,5 @@ import React, { FC, useCallback } from 'react'; -import styles from '~/components/notifications/NotificationBubble/styles.scss'; +import styles from '~/components/notifications/NotificationBubble/styles.module.scss'; import { Icon } from '~/components/input/Icon'; import { IMessageNotification, INotification } from '~/redux/types'; diff --git a/src/components/placeholders/ParagraphPlaceholder/index.tsx b/src/components/placeholders/ParagraphPlaceholder/index.tsx index aff5e8bf..3bbabab8 100644 --- a/src/components/placeholders/ParagraphPlaceholder/index.tsx +++ b/src/components/placeholders/ParagraphPlaceholder/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { Placeholder } from '~/components/placeholders/Placeholder'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Group } from '~/components/containers/Group'; const ParagraphPlaceholder = ({}) => ( diff --git a/src/components/placeholders/ParagraphPlaceholder/styles.scss b/src/components/placeholders/ParagraphPlaceholder/styles.module.scss similarity index 100% rename from src/components/placeholders/ParagraphPlaceholder/styles.scss rename to src/components/placeholders/ParagraphPlaceholder/styles.module.scss diff --git a/src/components/placeholders/Placeholder/index.tsx b/src/components/placeholders/Placeholder/index.tsx index b29d12bb..a5d3be7c 100644 --- a/src/components/placeholders/Placeholder/index.tsx +++ b/src/components/placeholders/Placeholder/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps { width?: string; diff --git a/src/components/placeholders/Placeholder/styles.scss b/src/components/placeholders/Placeholder/styles.module.scss similarity index 100% rename from src/components/placeholders/Placeholder/styles.scss rename to src/components/placeholders/Placeholder/styles.module.scss diff --git a/src/components/profile/Message/index.tsx b/src/components/profile/Message/index.tsx index c543f264..373159a4 100644 --- a/src/components/profile/Message/index.tsx +++ b/src/components/profile/Message/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; import { IMessage } from '~/redux/types'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { formatText, getPrettyDate, getURL } from '~/utils/dom'; import { PRESETS } from '~/constants/urls'; import classNames from 'classnames'; diff --git a/src/components/profile/Message/styles.scss b/src/components/profile/Message/styles.module.scss similarity index 100% rename from src/components/profile/Message/styles.scss rename to src/components/profile/Message/styles.module.scss diff --git a/src/components/profile/MessageForm/index.tsx b/src/components/profile/MessageForm/index.tsx index c9e123fb..2ac14bcc 100644 --- a/src/components/profile/MessageForm/index.tsx +++ b/src/components/profile/MessageForm/index.tsx @@ -1,5 +1,5 @@ import React, { FC, KeyboardEventHandler, useCallback, useMemo, useState } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { Textarea } from '~/components/input/Textarea'; import { Filler } from '~/components/containers/Filler'; import { Button } from '~/components/input/Button'; diff --git a/src/components/profile/MessageForm/styles.scss b/src/components/profile/MessageForm/styles.module.scss similarity index 100% rename from src/components/profile/MessageForm/styles.scss rename to src/components/profile/MessageForm/styles.module.scss diff --git a/src/components/profile/ProfileAccounts/index.tsx b/src/components/profile/ProfileAccounts/index.tsx index 33c1652d..01c820f5 100644 --- a/src/components/profile/ProfileAccounts/index.tsx +++ b/src/components/profile/ProfileAccounts/index.tsx @@ -1,6 +1,6 @@ import React, { FC, Fragment, useCallback, useEffect } from 'react'; import { ISocialProvider } from '~/redux/auth/types'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { Placeholder } from '~/components/placeholders/Placeholder'; import { Icon } from '~/components/input/Icon'; import { Button } from '~/components/input/Button'; diff --git a/src/components/profile/ProfileAccounts/styles.scss b/src/components/profile/ProfileAccounts/styles.module.scss similarity index 100% rename from src/components/profile/ProfileAccounts/styles.scss rename to src/components/profile/ProfileAccounts/styles.module.scss diff --git a/src/components/profile/ProfileAccountsError/index.tsx b/src/components/profile/ProfileAccountsError/index.tsx index 8fa52ff2..ad65fe5b 100644 --- a/src/components/profile/ProfileAccountsError/index.tsx +++ b/src/components/profile/ProfileAccountsError/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { Group } from '~/components/containers/Group'; import { ERROR_LITERAL } from '~/constants/errors'; import { Button } from '~/components/input/Button'; diff --git a/src/components/profile/ProfileAccountsError/styles.scss b/src/components/profile/ProfileAccountsError/styles.module.scss similarity index 100% rename from src/components/profile/ProfileAccountsError/styles.scss rename to src/components/profile/ProfileAccountsError/styles.module.scss diff --git a/src/components/profile/ProfileDescription/index.tsx b/src/components/profile/ProfileDescription/index.tsx index 77b229ec..4e471a97 100644 --- a/src/components/profile/ProfileDescription/index.tsx +++ b/src/components/profile/ProfileDescription/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { formatText } from '~/utils/dom'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { connect } from 'react-redux'; import { selectAuthProfile } from '~/redux/auth/selectors'; import { ProfileLoader } from '~/containers/profile/ProfileLoader'; diff --git a/src/components/profile/ProfileDescription/styles.scss b/src/components/profile/ProfileDescription/styles.module.scss similarity index 100% rename from src/components/profile/ProfileDescription/styles.scss rename to src/components/profile/ProfileDescription/styles.module.scss diff --git a/src/components/profile/ProfileSettings/index.tsx b/src/components/profile/ProfileSettings/index.tsx index df8482a1..f119adb2 100644 --- a/src/components/profile/ProfileSettings/index.tsx +++ b/src/components/profile/ProfileSettings/index.tsx @@ -1,5 +1,5 @@ import React, { FC, useCallback, useEffect, useState } from 'react'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { connect } from 'react-redux'; import { selectAuthProfile, selectAuthUser } from '~/redux/auth/selectors'; import { Textarea } from '~/components/input/Textarea'; diff --git a/src/components/profile/ProfileSettings/styles.scss b/src/components/profile/ProfileSettings/styles.module.scss similarity index 100% rename from src/components/profile/ProfileSettings/styles.scss rename to src/components/profile/ProfileSettings/styles.module.scss diff --git a/src/components/sidebar/TagSidebarList/index.tsx b/src/components/sidebar/TagSidebarList/index.tsx new file mode 100644 index 00000000..b4c11027 --- /dev/null +++ b/src/components/sidebar/TagSidebarList/index.tsx @@ -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 = ({ nodes }) => ( +
+ {nodes.map(node => ( + + ))} +
+); + +export { TagSidebarList }; diff --git a/src/components/sidebar/TagSidebarList/styles.module.scss b/src/components/sidebar/TagSidebarList/styles.module.scss new file mode 100644 index 00000000..868192b4 --- /dev/null +++ b/src/components/sidebar/TagSidebarList/styles.module.scss @@ -0,0 +1,4 @@ +.list { + flex: 1; + flex-direction: column; +} diff --git a/src/components/tags/Tag/index.tsx b/src/components/tags/Tag/index.tsx new file mode 100644 index 00000000..8207e65a --- /dev/null +++ b/src/components/tags/Tag/index.tsx @@ -0,0 +1,40 @@ +import React, { FC, FocusEventHandler, useCallback } from 'react'; +import { ITag } from '~/redux/types'; +import { TagWrapper } from '~/components/tags/TagWrapper'; + +const getTagFeature = (tag: Partial) => { + if (tag.title.substr(0, 1) === '/') return 'green'; + + return ''; +}; + +interface IProps { + tag: Partial; + size?: 'normal' | 'big'; + + is_hoverable?: boolean; + is_editing?: boolean; + + onBlur?: FocusEventHandler; + onClick?: (tag: Partial) => void; +} + +const Tag: FC = ({ tag, is_hoverable, is_editing, size = 'normal', onBlur, onClick }) => { + const onClickHandler = useCallback(() => { + if (!onClick) return; + onClick(tag); + }, [tag, onClick]); + + return ( + + ); +}; + +export { Tag }; diff --git a/src/containers/editors/EditorDialogVideo/styles.scss b/src/components/tags/Tag/styles.module.scss similarity index 100% rename from src/containers/editors/EditorDialogVideo/styles.scss rename to src/components/tags/Tag/styles.module.scss diff --git a/src/components/tags/TagAutocomplete/index.tsx b/src/components/tags/TagAutocomplete/index.tsx new file mode 100644 index 00000000..485a6fe1 --- /dev/null +++ b/src/components/tags/TagAutocomplete/index.tsx @@ -0,0 +1,145 @@ +import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import styles from './styles.module.scss'; +import classNames from 'classnames'; +import { connect } from 'react-redux'; +import * as TAG_ACTIONS from '~/redux/tag/actions'; +import { selectTagAutocomplete } from '~/redux/tag/selectors'; +import { separateTagOptions } from '~/utils/tag'; +import { TagAutocompleteRow } from '~/components/tags/TagAutocompleteRow'; +import { usePopper } from 'react-popper'; + +const mapStateToProps = selectTagAutocomplete; +const mapDispatchToProps = { + tagSetAutocomplete: TAG_ACTIONS.tagSetAutocomplete, + tagLoadAutocomplete: TAG_ACTIONS.tagLoadAutocomplete, +}; + +type Props = ReturnType & + typeof mapDispatchToProps & { + exclude: string[]; + input: HTMLInputElement; + onSelect: (val: string) => void; + search: string; + }; + +const TagAutocompleteUnconnected: FC = ({ + exclude, + input, + onSelect, + search, + tagSetAutocomplete, + tagLoadAutocomplete, + options, +}) => { + const [selected, setSelected] = useState(-1); + const [categories, tags] = useMemo( + () => + separateTagOptions( + options.slice(0, 7).filter(option => option !== search && !exclude.includes(option)) + ), + [options, search, exclude] + ); + const scroll = useRef(null); + const wrapper = useRef(null); + + const pop = usePopper(wrapper?.current?.parentElement, wrapper.current, { + placement: 'bottom-end', + modifiers: [ + { + name: 'offset', + options: { + offset: [0, 4], + }, + }, + ], + }); + + const onKeyDown = useCallback( + event => { + const all = [...categories, ...tags]; + + switch (event.key) { + case 'ArrowDown': + event.preventDefault(); + setSelected(selected < all.length - 1 ? selected + 1 : -1); + return; + case 'ArrowUp': + event.preventDefault(); + setSelected(selected > -1 ? selected - 1 : all.length - 1); + return; + case 'Enter': + event.preventDefault(); + onSelect(selected >= 0 ? all[selected] : search); + } + }, + [setSelected, selected, categories, tags, onSelect, search] + ); + + useEffect(() => { + input.addEventListener('keydown', onKeyDown, false); + return () => input.removeEventListener('keydown', onKeyDown); + }, [input, onKeyDown]); + + useEffect(() => { + setSelected(-1); + tagLoadAutocomplete(search, exclude); + }, [search]); + + useEffect(() => { + tagSetAutocomplete({ options: [] }); + return () => tagSetAutocomplete({ options: [] }); + }, [tagSetAutocomplete]); + + useEffect(() => { + if (!scroll.current || !scroll.current?.children[selected + 1]) return; + const el = scroll.current?.children[selected + 1] as HTMLDivElement; + const { scrollTop, clientHeight } = scroll.current; + const { offsetTop } = el; + + if (clientHeight - scrollTop + el.clientHeight < offsetTop || offsetTop < scrollTop) { + scroll.current.scrollTo(0, el.offsetTop - el.clientHeight); + } + }, [selected, scroll.current]); + + return ( +
+
+ + + {categories.map((item, i) => ( + + ))} + + {tags.map((item, i) => ( + + ))} +
+
+ ); +}; + +const TagAutocomplete = connect(mapStateToProps, mapDispatchToProps)(TagAutocompleteUnconnected); + +export { TagAutocomplete }; diff --git a/src/components/tags/TagAutocomplete/styles.module.scss b/src/components/tags/TagAutocomplete/styles.module.scss new file mode 100644 index 00000000..ec6baaef --- /dev/null +++ b/src/components/tags/TagAutocomplete/styles.module.scss @@ -0,0 +1,25 @@ +@keyframes appear { + 0% { opacity: 0 } + 100% { opacity: 100 } +} + +$row_height: 24px; + +.window { + box-shadow: transparentize(white, 0.9) 0 0 0 1px; + position: absolute; + top: -2px; + right: -2px; + width: calc(100vw - 15px); + max-width: 300px; + background: darken($content_bg, 2%); + z-index: 10; + border-radius: 4px; + animation: appear 0.25s forwards; +} + +.scroll { + overflow: hidden; + padding: 0 0 $gap / 2; + border-radius: 4px; +} diff --git a/src/components/tags/TagAutocompleteRow/index.tsx b/src/components/tags/TagAutocompleteRow/index.tsx new file mode 100644 index 00000000..27e8b282 --- /dev/null +++ b/src/components/tags/TagAutocompleteRow/index.tsx @@ -0,0 +1,27 @@ +import React, { FC, useCallback } from 'react'; +import styles from './styles.module.scss'; +import classNames from 'classnames'; +import { Icon } from '~/components/input/Icon'; + +interface IProps { + selected: boolean; + title: string; + type: string; + onSelect: (val: string) => void; +} + +const TagAutocompleteRow: FC = ({ selected, type, title, onSelect }) => { + const onClick = useCallback(() => onSelect(title), [title, onSelect]); + + return ( +
+ + {title} +
+ ); +}; + +export { TagAutocompleteRow }; diff --git a/src/components/tags/TagAutocompleteRow/styles.module.scss b/src/components/tags/TagAutocompleteRow/styles.module.scss new file mode 100644 index 00000000..51efd1b3 --- /dev/null +++ b/src/components/tags/TagAutocompleteRow/styles.module.scss @@ -0,0 +1,32 @@ +$row_height: 24px; + +.row { + height: $row_height; + padding: 0 $gap; + display: flex; + align-items: center; + justify-content: flex-start; + font: $font_16_semibold; + opacity: 0.5; + cursor: pointer; + transition: all 0.1s; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + + &:hover, &.selected { + opacity: 1; + background: transparentize($wisegreen, 0.5); + } + + &.right { + color: lighten($wisegreen, 4%); + opacity: 1; + } + + svg { + margin-right: 5px; + fill: currentColor; + flex: 0 0 16px; + } +} diff --git a/src/components/tags/TagInput/index.tsx b/src/components/tags/TagInput/index.tsx new file mode 100644 index 00000000..1d1c362e --- /dev/null +++ b/src/components/tags/TagInput/index.tsx @@ -0,0 +1,139 @@ +import React, { ChangeEvent, FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { TagAutocomplete } from '~/components/tags/TagAutocomplete'; +import { TagWrapper } from '~/components/tags/TagWrapper'; +import styles from './styles.module.scss'; + +const placeholder = 'Добавить'; + +const prepareInput = (input: string): string[] => { + return input + .split(',') + .map((title: string) => + title + .trim() + .substr(0, 32) + .toLowerCase() + ) + .filter(el => el.length > 0); +}; + +interface IProps { + onAppend: (tags: string[]) => void; + onClearTag: () => string | undefined; + onSubmit: (last: string[]) => void; + exclude: string[]; +} + +const TagInput: FC = ({ exclude, onAppend, onClearTag, onSubmit }) => { + const [focused, setFocused] = useState(false); + const [input, setInput] = useState(''); + const ref = useRef(null); + const wrapper = useRef(null); + + const onInput = useCallback( + ({ target: { value } }: ChangeEvent) => { + if (!value.trim()) { + setInput(value || ''); + return; + } + + const items = prepareInput(value); + + if (items.length > 1) { + onAppend(items.slice(0, items.length - 1)); + } + + setInput(items[items.length - 1] || ''); + }, + [setInput] + ); + + const onKeyDown = useCallback( + ({ key }) => { + if (key === 'Escape' && ref.current) { + setInput(''); + ref.current.blur(); + return; + } + + if (key === 'Backspace' && input === '') { + setInput(onClearTag() || ''); + return; + } + + if (key === ',' || key === 'Comma') { + const created = prepareInput(input); + + if (created.length) { + onAppend(created); + } + + setInput(''); + } + }, + [input, setInput, onClearTag, onAppend, onSubmit, ref.current, wrapper.current] + ); + + const onFocus = useCallback(() => setFocused(true), []); + const onBlur = useCallback( + event => { + if (wrapper.current.contains(event.target)) { + ref.current.focus(); + return; + } + + setFocused(false); + + if (input.trim()) { + setInput(''); + } + + onSubmit([]); + }, + [input, onAppend, setInput, onSubmit] + ); + + const onAutocompleteSelect = useCallback( + (val: string) => { + onAppend([val]); + setInput(''); + }, + [onAppend, setInput] + ); + + const feature = useMemo(() => (input?.substr(0, 1) === '/' ? 'green' : ''), [input]); + + useEffect(() => { + document.addEventListener('click', onBlur); + return () => document.removeEventListener('click', onBlur); + }, [onBlur]); + + return ( +
+ + + + + {onInput && focused && input?.length > 0 && ( + + )} +
+ ); +}; + +export { TagInput }; diff --git a/src/components/tags/TagInput/styles.module.scss b/src/components/tags/TagInput/styles.module.scss new file mode 100644 index 00000000..c5ef4d75 --- /dev/null +++ b/src/components/tags/TagInput/styles.module.scss @@ -0,0 +1,4 @@ +.wrap { + position: relative; + z-index: 20; +} diff --git a/src/components/tags/TagWrapper/index.tsx b/src/components/tags/TagWrapper/index.tsx new file mode 100644 index 00000000..2eb0f28e --- /dev/null +++ b/src/components/tags/TagWrapper/index.tsx @@ -0,0 +1,40 @@ +import React, { FC } from 'react'; +import classNames from 'classnames'; +import styles from './styles.module.scss'; + +interface IProps { + feature?: string; + size?: string; + is_hoverable?: boolean; + is_editing?: boolean; + has_input?: boolean; + onClick?: () => void; + title?: string; +} + +const TagWrapper: FC = ({ + children, + feature, + size, + is_hoverable, + is_editing, + has_input, + onClick, + title = '', +}) => ( +
+
+
{title}
+ {children} +
+); + +export { TagWrapper }; diff --git a/src/components/node/Tag/styles.scss b/src/components/tags/TagWrapper/styles.module.scss similarity index 81% rename from src/components/node/Tag/styles.scss rename to src/components/tags/TagWrapper/styles.module.scss index d5280c5c..a16a6358 100644 --- a/src/components/node/Tag/styles.scss +++ b/src/components/tags/TagWrapper/styles.module.scss @@ -1,6 +1,9 @@ +$big: 1.2; + .tag { @include outer_shadow(); + cursor: default; height: $tag_height; background: $tag_bg; display: flex; @@ -11,8 +14,20 @@ font: $font_14_semibold; align-self: flex-start; padding: 0 8px 0 0; - margin: 0 $gap $gap 0; + //margin: 0 $gap $gap 0; position: relative; + z-index: 12; + + &: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 +71,10 @@ min-width: 100px; } + &:global(.clickable) { + cursor: pointer; + } + input { background: none; border: none; @@ -70,6 +89,7 @@ top: 0; bottom: 0; width: 100%; + min-width: 100px; padding-left: $tag_height; padding-right: 5px; box-sizing: border-box; @@ -80,7 +100,6 @@ width: $tag_height; height: $tag_height; display: flex; - // padding-right: 0px; align-items: center; justify-content: center; flex: 0 0 $tag_height; @@ -101,3 +120,4 @@ overflow: hidden; text-overflow: ellipsis; } + diff --git a/src/components/tags/Tags/index.tsx b/src/components/tags/Tags/index.tsx new file mode 100644 index 00000000..8feec917 --- /dev/null +++ b/src/components/tags/Tags/index.tsx @@ -0,0 +1,76 @@ +import React, { FC, HTMLAttributes, useCallback, useEffect, useMemo, useState } from 'react'; +import { TagField } from '~/components/containers/TagField'; +import { ITag } from '~/redux/types'; +import uniq from 'ramda/es/uniq'; +import { Tag } from '~/components/tags/Tag'; +import { TagInput } from '~/components/tags/TagInput'; +import { separateTags } from '~/utils/tag'; + +type IProps = HTMLAttributes & { + tags: Partial[]; + is_editable?: boolean; + onTagsChange?: (tags: string[]) => void; + onTagClick?: (tag: Partial) => void; +}; + +export const Tags: FC = ({ tags, is_editable, onTagsChange, onTagClick, ...props }) => { + const [data, setData] = useState([]); + + const [catTags, ordinaryTags] = useMemo(() => separateTags(tags), [tags]); + + const onSubmit = useCallback( + (last: string[]) => { + const exist = tags.map(tag => tag.title); + onTagsChange(uniq([...exist, ...data, ...last])); + }, + [data] + ); + + useEffect(() => { + setData(data.filter(title => !tags.some(tag => tag.title.trim() === title.trim()))); + }, [tags]); + + const onAppendTag = useCallback( + (created: string[]) => { + setData(uniq([...data, ...created]).filter(title => !tags.some(it => it.title === title))); + }, + [data, setData, tags] + ); + + const onClearTag = useCallback((): string | undefined => { + if (!data.length) return; + const last = data[data.length - 1]; + setData(data.slice(0, data.length - 1)); + return last; + }, [data, setData]); + + const exclude = useMemo(() => [...(data || []), ...(tags || []).map(({ title }) => title)], [ + data, + tags, + ]); + + return ( + + {catTags.map(tag => ( + + ))} + + {ordinaryTags.map(tag => ( + + ))} + + {data.map(title => ( + + ))} + + {is_editable && ( + + )} + + ); +}; diff --git a/src/components/upload/AudioUpload/index.tsx b/src/components/upload/AudioUpload/index.tsx index fd150593..e6cfa172 100644 --- a/src/components/upload/AudioUpload/index.tsx +++ b/src/components/upload/AudioUpload/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { ArcProgress } from '~/components/input/ArcProgress'; import { IFile } from '~/redux/types'; import { Icon } from '~/components/input/Icon'; diff --git a/src/components/upload/AudioUpload/styles.scss b/src/components/upload/AudioUpload/styles.module.scss similarity index 100% rename from src/components/upload/AudioUpload/styles.scss rename to src/components/upload/AudioUpload/styles.module.scss diff --git a/src/components/upload/ImageUpload/index.tsx b/src/components/upload/ImageUpload/index.tsx index 81d010bd..fff82a40 100644 --- a/src/components/upload/ImageUpload/index.tsx +++ b/src/components/upload/ImageUpload/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useCallback } from 'react'; import classNames from 'classnames'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { ArcProgress } from '~/components/input/ArcProgress'; import { IFile } from '~/redux/types'; import { Icon } from '~/components/input/Icon'; diff --git a/src/components/upload/ImageUpload/styles.scss b/src/components/upload/ImageUpload/styles.module.scss similarity index 100% rename from src/components/upload/ImageUpload/styles.scss rename to src/components/upload/ImageUpload/styles.module.scss diff --git a/src/constants/api.ts b/src/constants/api.ts index 991fe958..4c23cf31 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -1,4 +1,4 @@ -import { INode, IComment } from '~/redux/types'; +import { IComment, INode } from '~/redux/types'; import { ISocialProvider } from '~/redux/auth/types'; export const API = { @@ -46,4 +46,8 @@ export const API = { BORIS: { GET_BACKEND_STATS: '/stats/', }, + TAG: { + NODES: `/tag/nodes`, + AUTOCOMPLETE: `/tag/autocomplete`, + }, }; diff --git a/src/constants/urls.ts b/src/constants/urls.ts index 055bc214..606e6407 100644 --- a/src/constants/urls.ts +++ b/src/constants/urls.ts @@ -13,6 +13,7 @@ export const URLS = { BACKEND_DOWN: '/oopsie', }, NODE_URL: (id: number | string) => `/post${id}`, + NODE_TAG_URL: (id: number, tagName: string) => `/post${id}/tag/${tagName}`, PROFILE: (username: string) => `/~${username}`, PROFILE_PAGE: (username: string) => `/profile/${username}`, }; diff --git a/src/containers/dialogs/BetterScrollDialog/index.tsx b/src/containers/dialogs/BetterScrollDialog/index.tsx index eb580ae9..66f1a525 100644 --- a/src/containers/dialogs/BetterScrollDialog/index.tsx +++ b/src/containers/dialogs/BetterScrollDialog/index.tsx @@ -1,5 +1,5 @@ import React, { FC, MouseEventHandler, ReactElement, useEffect, useRef, } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock'; import { Icon } from '~/components/input/Icon'; import { LoaderCircle } from '~/components/input/LoaderCircle'; diff --git a/src/containers/dialogs/BetterScrollDialog/styles.scss b/src/containers/dialogs/BetterScrollDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/BetterScrollDialog/styles.scss rename to src/containers/dialogs/BetterScrollDialog/styles.module.scss diff --git a/src/containers/dialogs/EditorDialog/index.tsx b/src/containers/dialogs/EditorDialog/index.tsx index 4888e82e..02e7933d 100644 --- a/src/containers/dialogs/EditorDialog/index.tsx +++ b/src/containers/dialogs/EditorDialog/index.tsx @@ -6,7 +6,7 @@ import { Group } from '~/components/containers/Group'; import { InputText } from '~/components/input/InputText'; import { Button } from '~/components/input/Button'; import { Padder } from '~/components/containers/Padder'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { selectNode } from '~/redux/node/selectors'; import { EditorPanel } from '~/components/editors/EditorPanel'; import * as NODE_ACTIONS from '~/redux/node/actions'; diff --git a/src/containers/dialogs/EditorDialog/styles.scss b/src/containers/dialogs/EditorDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/EditorDialog/styles.scss rename to src/containers/dialogs/EditorDialog/styles.module.scss diff --git a/src/containers/dialogs/LoadingDialog/index.tsx b/src/containers/dialogs/LoadingDialog/index.tsx index abead2d4..7ebea6de 100644 --- a/src/containers/dialogs/LoadingDialog/index.tsx +++ b/src/containers/dialogs/LoadingDialog/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { LoaderCircle } from '~/components/input/LoaderCircle'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; const LoadingDialog: FC<{}> = () => (
diff --git a/src/containers/dialogs/LoadingDialog/styles.scss b/src/containers/dialogs/LoadingDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/LoadingDialog/styles.scss rename to src/containers/dialogs/LoadingDialog/styles.module.scss diff --git a/src/containers/dialogs/LoginDialog/index.tsx b/src/containers/dialogs/LoginDialog/index.tsx index 5eb914ee..a2a9c92e 100644 --- a/src/containers/dialogs/LoginDialog/index.tsx +++ b/src/containers/dialogs/LoginDialog/index.tsx @@ -10,7 +10,7 @@ import { selectAuthLogin } from '~/redux/auth/selectors'; import { API } from '~/constants/api'; import { BetterScrollDialog } from '../BetterScrollDialog'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import * as ACTIONS from '~/redux/auth/actions'; import * as MODAL_ACTIONS from '~/redux/modal/actions'; import { ISocialProvider } from '~/redux/auth/types'; diff --git a/src/containers/dialogs/LoginDialog/styles.scss b/src/containers/dialogs/LoginDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/LoginDialog/styles.scss rename to src/containers/dialogs/LoginDialog/styles.module.scss diff --git a/src/containers/dialogs/LoginDialogButtons/index.tsx b/src/containers/dialogs/LoginDialogButtons/index.tsx index 7cc63492..f328f11d 100644 --- a/src/containers/dialogs/LoginDialogButtons/index.tsx +++ b/src/containers/dialogs/LoginDialogButtons/index.tsx @@ -2,7 +2,7 @@ import React, { FC, MouseEventHandler } from 'react'; import { Button } from '~/components/input/Button'; import { Grid } from '~/components/containers/Grid'; import { Group } from '~/components/containers/Group'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps { openOauthWindow: (provider: string) => MouseEventHandler; diff --git a/src/containers/dialogs/LoginDialogButtons/styles.scss b/src/containers/dialogs/LoginDialogButtons/styles.module.scss similarity index 100% rename from src/containers/dialogs/LoginDialogButtons/styles.scss rename to src/containers/dialogs/LoginDialogButtons/styles.module.scss diff --git a/src/containers/dialogs/LoginSocialRegisterButtons/index.tsx b/src/containers/dialogs/LoginSocialRegisterButtons/index.tsx index 905cbd77..991607cf 100644 --- a/src/containers/dialogs/LoginSocialRegisterButtons/index.tsx +++ b/src/containers/dialogs/LoginSocialRegisterButtons/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { Button } from '~/components/input/Button'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps {} diff --git a/src/containers/dialogs/LoginSocialRegisterButtons/styles.scss b/src/containers/dialogs/LoginSocialRegisterButtons/styles.module.scss similarity index 100% rename from src/containers/dialogs/LoginSocialRegisterButtons/styles.scss rename to src/containers/dialogs/LoginSocialRegisterButtons/styles.module.scss diff --git a/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx b/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx index 5964f94d..64789120 100644 --- a/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx +++ b/src/containers/dialogs/LoginSocialRegisterDialog/index.tsx @@ -6,7 +6,7 @@ import { Padder } from '~/components/containers/Padder'; import { DialogTitle } from '~/components/dialogs/DialogTitle'; import { Group } from '~/components/containers/Group'; import { InputText } from '~/components/input/InputText'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { selectAuthRegisterSocial } from '~/redux/auth/selectors'; import * as AUTH_ACTIONS from '~/redux/auth/actions'; import { useCloseOnEscape } from '~/utils/hooks'; diff --git a/src/containers/dialogs/LoginSocialRegisterDialog/styles.scss b/src/containers/dialogs/LoginSocialRegisterDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/LoginSocialRegisterDialog/styles.scss rename to src/containers/dialogs/LoginSocialRegisterDialog/styles.module.scss diff --git a/src/containers/dialogs/Modal/index.tsx b/src/containers/dialogs/Modal/index.tsx index cbb1f69d..dd7b768a 100644 --- a/src/containers/dialogs/Modal/index.tsx +++ b/src/containers/dialogs/Modal/index.tsx @@ -1,7 +1,7 @@ import React, { Attributes, FC, useCallback } from 'react'; import { connect } from 'react-redux'; import ReactDOM from 'react-dom'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { IState } from '~/redux/store'; import * as ACTIONS from '~/redux/modal/actions'; import { DIALOG_CONTENT } from '~/constants/dialogs'; diff --git a/src/containers/dialogs/Modal/styles.scss b/src/containers/dialogs/Modal/styles.module.scss similarity index 98% rename from src/containers/dialogs/Modal/styles.scss rename to src/containers/dialogs/Modal/styles.module.scss index bbc9d691..41d1b253 100644 --- a/src/containers/dialogs/Modal/styles.scss +++ b/src/containers/dialogs/Modal/styles.module.scss @@ -1,6 +1,6 @@ .fixed { position: fixed; - z-index: 10; + z-index: 30; top: 0; left: 0; width: 100%; diff --git a/src/containers/dialogs/PhotoSwipe/index.tsx b/src/containers/dialogs/PhotoSwipe/index.tsx index ec6bfdba..668c55eb 100644 --- a/src/containers/dialogs/PhotoSwipe/index.tsx +++ b/src/containers/dialogs/PhotoSwipe/index.tsx @@ -10,7 +10,7 @@ import { selectModal } from '~/redux/modal/selectors'; import { getURL } from '~/utils/dom'; import { PRESETS } from '~/constants/urls'; import * as MODAL_ACTIONS from '~/redux/modal/actions'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import classNames from 'classnames'; const mapStateToProps = (state: IState) => ({ diff --git a/src/containers/dialogs/PhotoSwipe/styles.scss b/src/containers/dialogs/PhotoSwipe/styles.module.scss similarity index 100% rename from src/containers/dialogs/PhotoSwipe/styles.scss rename to src/containers/dialogs/PhotoSwipe/styles.module.scss diff --git a/src/containers/dialogs/ProfileDialog/styles.scss b/src/containers/dialogs/ProfileDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/ProfileDialog/styles.scss rename to src/containers/dialogs/ProfileDialog/styles.module.scss diff --git a/src/containers/dialogs/RestorePasswordDialog/index.tsx b/src/containers/dialogs/RestorePasswordDialog/index.tsx index 370272bf..28928e43 100644 --- a/src/containers/dialogs/RestorePasswordDialog/index.tsx +++ b/src/containers/dialogs/RestorePasswordDialog/index.tsx @@ -5,7 +5,7 @@ import { BetterScrollDialog } from '../BetterScrollDialog'; import { Group } from '~/components/containers/Group'; import { InputText } from '~/components/input/InputText'; import { Button } from '~/components/input/Button'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import * as AUTH_ACTIONS from '~/redux/auth/actions'; import pick from 'ramda/es/pick'; diff --git a/src/containers/dialogs/RestorePasswordDialog/styles.scss b/src/containers/dialogs/RestorePasswordDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/RestorePasswordDialog/styles.scss rename to src/containers/dialogs/RestorePasswordDialog/styles.module.scss diff --git a/src/containers/dialogs/RestoreRequestDialog/index.tsx b/src/containers/dialogs/RestoreRequestDialog/index.tsx index 9e9641e8..bbe036b9 100644 --- a/src/containers/dialogs/RestoreRequestDialog/index.tsx +++ b/src/containers/dialogs/RestoreRequestDialog/index.tsx @@ -5,7 +5,7 @@ import { BetterScrollDialog } from '../BetterScrollDialog'; import { Group } from '~/components/containers/Group'; import { InputText } from '~/components/input/InputText'; import { Button } from '~/components/input/Button'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import * as AUTH_ACTIONS from '~/redux/auth/actions'; import pick from 'ramda/es/pick'; diff --git a/src/containers/dialogs/RestoreRequestDialog/styles.scss b/src/containers/dialogs/RestoreRequestDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/RestoreRequestDialog/styles.scss rename to src/containers/dialogs/RestoreRequestDialog/styles.module.scss diff --git a/src/containers/dialogs/ScrollDialog/index.tsx b/src/containers/dialogs/ScrollDialog/index.tsx index 431865ed..d045aa1c 100644 --- a/src/containers/dialogs/ScrollDialog/index.tsx +++ b/src/containers/dialogs/ScrollDialog/index.tsx @@ -4,7 +4,7 @@ import React, { // import { DialogPanel } from '~/components/panels/DialogPanel'; import classNames from 'classnames'; import { Scroll } from '~/components/containers/Scroll'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps { children: React.ReactChild; diff --git a/src/containers/dialogs/ScrollDialog/styles.scss b/src/containers/dialogs/ScrollDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/ScrollDialog/styles.scss rename to src/containers/dialogs/ScrollDialog/styles.module.scss diff --git a/src/containers/dialogs/TestDialog/index.tsx b/src/containers/dialogs/TestDialog/index.tsx index d8439586..9059d15d 100644 --- a/src/containers/dialogs/TestDialog/index.tsx +++ b/src/containers/dialogs/TestDialog/index.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import { BetterScrollDialog } from '../BetterScrollDialog'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; interface IProps {} diff --git a/src/containers/dialogs/TestDialog/styles.scss b/src/containers/dialogs/TestDialog/styles.module.scss similarity index 100% rename from src/containers/dialogs/TestDialog/styles.scss rename to src/containers/dialogs/TestDialog/styles.module.scss diff --git a/src/containers/editors/EditorDialogVideo/styles.module.scss b/src/containers/editors/EditorDialogVideo/styles.module.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/containers/flow/FlowLayout/index.tsx b/src/containers/flow/FlowLayout/index.tsx index a694776e..c9dd09b8 100644 --- a/src/containers/flow/FlowLayout/index.tsx +++ b/src/containers/flow/FlowLayout/index.tsx @@ -7,7 +7,7 @@ import * as FLOW_ACTIONS from '~/redux/flow/actions'; import pick from 'ramda/es/pick'; import { selectUser } from '~/redux/auth/selectors'; import { FlowHero } from '~/components/flow/FlowHero'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { IState } from '~/redux/store'; import { FlowStamp } from '~/components/flow/FlowStamp'; diff --git a/src/containers/flow/FlowLayout/styles.scss b/src/containers/flow/FlowLayout/styles.module.scss similarity index 100% rename from src/containers/flow/FlowLayout/styles.scss rename to src/containers/flow/FlowLayout/styles.module.scss diff --git a/src/containers/main/BottomContainer/index.tsx b/src/containers/main/BottomContainer/index.tsx index 1c551ade..dc93ac3d 100644 --- a/src/containers/main/BottomContainer/index.tsx +++ b/src/containers/main/BottomContainer/index.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { PlayerBar } from '~/components/bars/PlayerBar'; import { SubmitBar } from '~/components/bars/SubmitBar'; import { selectUser } from '~/redux/auth/selectors'; diff --git a/src/containers/main/BottomContainer/styles.scss b/src/containers/main/BottomContainer/styles.module.scss similarity index 100% rename from src/containers/main/BottomContainer/styles.scss rename to src/containers/main/BottomContainer/styles.module.scss diff --git a/src/containers/main/MainLayout/index.tsx b/src/containers/main/MainLayout/index.tsx index 08bef189..36c83871 100644 --- a/src/containers/main/MainLayout/index.tsx +++ b/src/containers/main/MainLayout/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import { Header } from '~/components/main/Header'; export const MainLayout = ({ children }) => ( diff --git a/src/containers/main/MainLayout/styles.scss b/src/containers/main/MainLayout/styles.module.scss similarity index 100% rename from src/containers/main/MainLayout/styles.scss rename to src/containers/main/MainLayout/styles.module.scss diff --git a/src/containers/main/SidebarRouter/index.tsx b/src/containers/main/SidebarRouter/index.tsx new file mode 100644 index 00000000..0bf35ca6 --- /dev/null +++ b/src/containers/main/SidebarRouter/index.tsx @@ -0,0 +1,15 @@ +import React, { FC } from 'react'; +import { Route, Switch } from 'react-router'; +import { TagSidebar } from '~/containers/sidebars/TagSidebar'; + +interface IProps { + prefix?: string; +} + +const SidebarRouter: FC = ({ prefix = '' }) => ( + + + +); + +export { SidebarRouter }; diff --git a/src/containers/node/BorisLayout/index.tsx b/src/containers/node/BorisLayout/index.tsx index e4296445..948879d0 100644 --- a/src/containers/node/BorisLayout/index.tsx +++ b/src/containers/node/BorisLayout/index.tsx @@ -4,7 +4,7 @@ import { selectNode } from '~/redux/node/selectors'; import { selectUser } from '~/redux/auth/selectors'; import { connect } from 'react-redux'; import { NodeComments } from '~/components/node/NodeComments'; -import styles from './styles.scss'; +import styles from './styles.module.scss'; import { Group } from '~/components/containers/Group'; import boris from '~/sprites/boris_robot.svg'; import { NodeNoComments } from '~/components/node/NodeNoComments'; diff --git a/src/containers/node/BorisLayout/styles.scss b/src/containers/node/BorisLayout/styles.module.scss similarity index 100% rename from src/containers/node/BorisLayout/styles.scss rename to src/containers/node/BorisLayout/styles.module.scss diff --git a/src/containers/node/NodeLayout/index.tsx b/src/containers/node/NodeLayout/index.tsx index 1e6d7ec0..88c762ba 100644 --- a/src/containers/node/NodeLayout/index.tsx +++ b/src/containers/node/NodeLayout/index.tsx @@ -1,5 +1,5 @@ -import React, { FC, createElement, useEffect, useCallback, useState, useMemo, memo } from 'react'; -import { RouteComponentProps } from 'react-router'; +import React, { createElement, FC, memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { RouteComponentProps, useHistory } from 'react-router'; import { connect } from 'react-redux'; import { canEditNode, canLikeNode, canStarNode } from '~/utils/node'; import { selectNode } from '~/redux/node/selectors'; @@ -12,12 +12,7 @@ import { NodeNoComments } from '~/components/node/NodeNoComments'; import { NodeRelated } from '~/components/node/NodeRelated'; import { NodeComments } from '~/components/node/NodeComments'; import { NodeTags } from '~/components/node/NodeTags'; -import { - NODE_COMPONENTS, - NODE_INLINES, - NODE_HEADS, - INodeComponentProps, -} from '~/redux/node/constants'; +import { INodeComponentProps, NODE_COMPONENTS, NODE_HEADS, NODE_INLINES, } from '~/redux/node/constants'; import { selectUser } from '~/redux/auth/selectors'; import pick from 'ramda/es/pick'; import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder'; @@ -25,12 +20,16 @@ import { NodeDeletedBadge } from '~/components/node/NodeDeletedBadge'; import { NodeCommentForm } from '~/components/node/NodeCommentForm'; import { Sticky } from '~/components/containers/Sticky'; import { Footer } from '~/components/main/Footer'; +import { Link } from 'react-router-dom'; -import * as styles from './styles.scss'; +import styles from './styles.module.scss'; import * as NODE_ACTIONS from '~/redux/node/actions'; import * as MODAL_ACTIONS from '~/redux/modal/actions'; import { IState } from '~/redux/store'; import { selectModal } from '~/redux/modal/selectors'; +import { SidebarRouter } from '~/containers/main/SidebarRouter'; +import { ITag } from '~/redux/types'; +import { URLS } from '~/constants/urls'; const mapStateToProps = (state: IState) => ({ node: selectNode(state), @@ -86,6 +85,7 @@ const NodeLayoutUnconnected: FC = memo( modalShowPhotoswipe, }) => { const [layout, setLayout] = useState({}); + const history = useHistory(); const updateLayout = useCallback(() => setLayout({}), []); @@ -101,6 +101,13 @@ const NodeLayoutUnconnected: FC = memo( [node, nodeUpdateTags] ); + const onTagClick = useCallback( + (tag: Partial) => { + history.push(URLS.NODE_TAG_URL(node.id, encodeURIComponent(tag.title))); + }, + [history, node.id] + ); + const can_edit = useMemo(() => canEditNode(node, user), [node, user]); const can_like = useMemo(() => canLikeNode(node, user), [node, user]); const can_star = useMemo(() => canStarNode(node, user), [node, user]); @@ -197,6 +204,7 @@ const NodeLayoutUnconnected: FC = memo( is_editable={is_user} tags={node.tags} onChange={onTagsChange} + onTagClick={onTagClick} /> )} @@ -209,7 +217,11 @@ const NodeLayoutUnconnected: FC = memo( .filter(album => related.albums[album].length > 0) .map(album => ( + {album} + + } items={related.albums[album]} key={album} /> @@ -231,6 +243,8 @@ const NodeLayoutUnconnected: FC = memo(