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

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

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

View file

@ -47,7 +47,7 @@
"resolve-url-loader": "^3.0.1", "resolve-url-loader": "^3.0.1",
"style-loader": "^0.21.0", "style-loader": "^0.21.0",
"ts-node": "^8.4.1", "ts-node": "^8.4.1",
"typescript": "^3.6.4", "typescript": "^3.7.2",
"uglifyjs-webpack-plugin": "^1.3.0", "uglifyjs-webpack-plugin": "^1.3.0",
"webpack": "^4.41.2", "webpack": "^4.41.2",
"webpack-cli": "^3.3.9", "webpack-cli": "^3.3.9",
@ -56,6 +56,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@hot-loader/react-dom": "^16.10.2", "@hot-loader/react-dom": "^16.10.2",
"@popperjs/core": "^2.5.4",
"@typescript-eslint/eslint-plugin": "^1.13.0", "@typescript-eslint/eslint-plugin": "^1.13.0",
"@typescript-eslint/parser": "^1.13.0", "@typescript-eslint/parser": "^1.13.0",
"autosize": "^4.0.2", "autosize": "^4.0.2",
@ -95,6 +96,7 @@
"react-dom": "^16.13.0", "react-dom": "^16.13.0",
"react-hot-loader": "^4.12.15", "react-hot-loader": "^4.12.15",
"react-packery-component": "^1.0.2", "react-packery-component": "^1.0.2",
"react-popper": "^2.2.3",
"react-redux": "^6.0.1", "react-redux": "^6.0.1",
"react-router": "^5.1.2", "react-router": "^5.1.2",
"react-router-dom": "^5.1.2", "react-router-dom": "^5.1.2",

View file

@ -1,7 +1,6 @@
import React, { FC, useCallback, useState, useEffect } from 'react'; import React, { FC, useCallback, useEffect, useState } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';
import { Filler } from '~/components/containers/Filler';
import { PLAYER_STATES } from '~/redux/player/constants'; import { PLAYER_STATES } from '~/redux/player/constants';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import pick from 'ramda/es/pick'; import pick from 'ramda/es/pick';

View file

@ -4,7 +4,7 @@ import { Icon } from '~/components/input/Icon';
import * as NODE_ACTIONS from '~/redux/node/actions'; import * as NODE_ACTIONS from '~/redux/node/actions';
import { DIALOGS } from '~/redux/modal/constants'; 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'; import { NODE_TYPES } from '~/redux/node/constants';
const mapStateToProps = null; const mapStateToProps = null;

View file

@ -1,6 +1,6 @@
import React, { FC, memo, useMemo, useEffect } from 'react'; import React, { FC, memo, useMemo, useEffect } from 'react';
import { ICommentBlockProps } from '~/constants/comment'; import { ICommentBlockProps } from '~/constants/comment';
import styles from './styles.scss'; import styles from './styles.module.scss';
import { getYoutubeThumb } from '~/utils/dom'; import { getYoutubeThumb } from '~/utils/dom';
import { selectPlayer } from '~/redux/player/selectors'; import { selectPlayer } from '~/redux/player/selectors';
import { connect } from 'react-redux'; import { connect } from 'react-redux';

View file

@ -1,6 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { ICommentBlockProps } from '~/constants/comment'; import { ICommentBlockProps } from '~/constants/comment';
import styles from './styles.scss'; import styles from './styles.module.scss';
interface IProps extends ICommentBlockProps {} interface IProps extends ICommentBlockProps {}

View file

@ -1,5 +1,5 @@
import React, { AllHTMLAttributes, FC } from 'react'; import React, { AllHTMLAttributes, FC } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import classNames from 'classnames'; import classNames from 'classnames';
type IProps = AllHTMLAttributes<HTMLDivElement> & { is_blurred: boolean }; type IProps = AllHTMLAttributes<HTMLDivElement> & { is_blurred: boolean };

View file

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

View file

@ -1,5 +1,5 @@
import React, { FC, HTMLAttributes } from 'react'; import React, { FC, HTMLAttributes } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import classNames = require('classnames'); import classNames = require('classnames');

View file

@ -1,7 +1,7 @@
import React, { FC, HTMLAttributes } from 'react'; import React, { FC, HTMLAttributes } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { Card } from '../Card'; import { Card } from '../Card';
import { IUser } from '~/redux/auth/types'; import { IUser } from '~/redux/auth/types';
import { getURL } from '~/utils/dom'; import { getURL } from '~/utils/dom';

View file

@ -1,6 +1,6 @@
import React, { FC, useState, useCallback, useEffect, useRef } from "react"; import React, { FC, useState, useCallback, useEffect, useRef } from "react";
import { IUser } from "~/redux/auth/types"; import { IUser } from "~/redux/auth/types";
import styles from "./styles.scss"; import styles from './styles.module.scss';
import { getURL } from "~/utils/dom"; import { getURL } from "~/utils/dom";
import { PRESETS } from "~/constants/urls"; import { PRESETS } from "~/constants/urls";
import classNames from "classnames"; import classNames from "classnames";

View file

@ -1,6 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
type IProps = React.HTMLAttributes<HTMLDivElement>; type IProps = React.HTMLAttributes<HTMLDivElement>;

View file

@ -1,6 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
type IProps = React.HTMLAttributes<HTMLDivElement> & { type IProps = React.HTMLAttributes<HTMLDivElement> & {
horizontal?: boolean; horizontal?: boolean;

View file

@ -1,6 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
type IProps = React.HTMLAttributes<HTMLDivElement> & { type IProps = React.HTMLAttributes<HTMLDivElement> & {
horizontal?: boolean; horizontal?: boolean;

View file

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

View file

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

View file

@ -1,5 +1,5 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import classNames = require('classnames'); import classNames = require('classnames');

View file

@ -1,5 +1,5 @@
import React, { FC, memo } from 'react'; import React, { FC, memo } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { selectNode } from '~/redux/node/selectors'; import { selectNode } from '~/redux/node/selectors';
import { connect } from 'react-redux'; import { connect } from 'react-redux';

View file

@ -1,5 +1,5 @@
import React, { FC, HTMLAttributes } from 'react'; import React, { FC, HTMLAttributes } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import classNames = require('classnames'); import classNames = require('classnames');

View file

@ -1,7 +1,7 @@
import React, { MouseEventHandler, useEffect, useState } from 'react'; import React, { MouseEventHandler, useEffect, useState } from 'react';
import { Scrollbars } from 'tt-react-custom-scrollbars'; import { Scrollbars } from 'tt-react-custom-scrollbars';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
interface IProps { interface IProps {
children: Element | React.ReactChild; children: Element | React.ReactChild;

View file

@ -1,5 +1,5 @@
import React, { FC, ReactComponentElement, DetailsHTMLAttributes, useEffect, useRef } from 'react'; 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 StickySidebar from 'sticky-sidebar';
import classnames from 'classnames'; import classnames from 'classnames';
import ResizeSensor from 'resize-sensor'; import ResizeSensor from 'resize-sensor';

View file

@ -1,5 +1,5 @@
import React, { FC, HTMLAttributes } from 'react'; import React, { FC, HTMLAttributes } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
type IProps = HTMLAttributes<HTMLDivElement> & {} type IProps = HTMLAttributes<HTMLDivElement> & {}

View file

@ -3,4 +3,8 @@
align-items: flex-start; align-items: flex-start;
justify-content: flex-start; justify-content: flex-start;
flex-wrap: wrap; flex-wrap: wrap;
&> * {
margin: 0 $gap $gap 0;
}
} }

View file

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

View file

@ -7,7 +7,7 @@ import { AudioGrid } from '../AudioGrid';
import { selectUploads } from '~/redux/uploads/selectors'; import { selectUploads } from '~/redux/uploads/selectors';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions'; import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
const mapStateToProps = selectUploads; const mapStateToProps = selectUploads;
const mapDispatchToProps = { const mapDispatchToProps = {

View file

@ -5,7 +5,7 @@ import { IUploadStatus } from '~/redux/uploads/reducer';
import { moveArrItem } from '~/utils/fn'; import { moveArrItem } from '~/utils/fn';
import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid'; import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
interface IProps { interface IProps {
files: IFile[]; files: IFile[];

View file

@ -1,5 +1,5 @@
import React, { FC, createElement } from 'react'; import React, { FC, createElement } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { INode } from '~/redux/types'; import { INode } from '~/redux/types';
import { NODE_PANEL_COMPONENTS } from '~/redux/node/constants'; import { NODE_PANEL_COMPONENTS } from '~/redux/node/constants';

View file

@ -1,5 +1,5 @@
import React, { FC, useCallback, useEffect } from 'react'; 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 { Icon } from '~/components/input/Icon';
import { IFileWithUUID, INode, IFile } from '~/redux/types'; import { IFileWithUUID, INode, IFile } from '~/redux/types';
import uuid from 'uuid4'; import uuid from 'uuid4';

View file

@ -1,7 +1,7 @@
import React, { FC, useCallback, useEffect, useState } from 'react'; import React, { FC, useCallback, useEffect, useState } from 'react';
import { IFileWithUUID } from '~/redux/types'; import { IFileWithUUID } from '~/redux/types';
import uuid from 'uuid4'; 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 { UPLOAD_SUBJECTS, UPLOAD_TARGETS, UPLOAD_TYPES } from '~/redux/uploads/constants';
import path from 'ramda/es/path'; import path from 'ramda/es/path';
import { connect } from 'react-redux'; import { connect } from 'react-redux';

View file

@ -4,7 +4,7 @@ import { INode, IFile } from '~/redux/types';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions'; import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { selectUploads } from '~/redux/uploads/selectors'; import { selectUploads } from '~/redux/uploads/selectors';
import { ImageGrid } from '~/components/editors/ImageGrid'; import { ImageGrid } from '~/components/editors/ImageGrid';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
const mapStateToProps = selectUploads; const mapStateToProps = selectUploads;
const mapDispatchToProps = { const mapDispatchToProps = {

View file

@ -1,6 +1,6 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback } from 'react';
import { SortEnd } from 'react-sortable-hoc'; import { SortEnd } from 'react-sortable-hoc';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { IFile } from '~/redux/types'; import { IFile } from '~/redux/types';
import { IUploadStatus } from '~/redux/uploads/reducer'; import { IUploadStatus } from '~/redux/uploads/reducer';
import { moveArrItem } from '~/utils/fn'; import { moveArrItem } from '~/utils/fn';

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { SortableContainer } from 'react-sortable-hoc'; import { SortableContainer } from 'react-sortable-hoc';
import { AudioUpload } from '~/components/upload/AudioUpload'; 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 { SortableAudioGridItem } from '~/components/editors/SortableAudioGridItem';
import { IFile } from '~/redux/types'; import { IFile } from '~/redux/types';
import { IUploadStatus } from '~/redux/uploads/reducer'; import { IUploadStatus } from '~/redux/uploads/reducer';

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { SortableElement } from 'react-sortable-hoc'; import { SortableElement } from 'react-sortable-hoc';
import styles from './styles.scss'; import styles from './styles.module.scss';
const SortableAudioGridItem = SortableElement(({ children }) => ( const SortableAudioGridItem = SortableElement(({ children }) => (
<div className={styles.item}>{children}</div> <div className={styles.item}>{children}</div>

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { SortableContainer } from 'react-sortable-hoc'; import { SortableContainer } from 'react-sortable-hoc';
import { ImageUpload } from '~/components/upload/ImageUpload'; 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 { SortableImageGridItem } from '~/components/editors/SortableImageGridItem';
import { IFile } from '~/redux/types'; import { IFile } from '~/redux/types';
import { IUploadStatus } from '~/redux/uploads/reducer'; import { IUploadStatus } from '~/redux/uploads/reducer';

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { SortableElement } from 'react-sortable-hoc'; import { SortableElement } from 'react-sortable-hoc';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
const SortableImageGridItem = SortableElement(({ children }) => ( const SortableImageGridItem = SortableElement(({ children }) => (
<div className={styles.item}>{children}</div> <div className={styles.item}>{children}</div>

View file

@ -1,6 +1,6 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback } from 'react';
import { INode } from '~/redux/types'; import { INode } from '~/redux/types';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { Textarea } from '~/components/input/Textarea'; import { Textarea } from '~/components/input/Textarea';
import path from 'ramda/es/path'; import path from 'ramda/es/path';

View file

@ -1,6 +1,6 @@
import React, { FC, useCallback, useMemo } from 'react'; import React, { FC, useCallback, useMemo } from 'react';
import { INode } from '~/redux/types'; import { INode } from '~/redux/types';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import path from 'ramda/es/path'; import path from 'ramda/es/path';
import { InputText } from '~/components/input/InputText'; import { InputText } from '~/components/input/InputText';
import classnames from 'classnames'; import classnames from 'classnames';

View file

@ -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 { INode } from '~/redux/types';
import { getURL, formatCellText } from '~/utils/dom'; import { formatCellText, getURL } from '~/utils/dom';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';
import { flowSetCellView } from '~/redux/flow/actions'; import { flowSetCellView } from '~/redux/flow/actions';
import { PRESETS } from '~/constants/urls'; import { PRESETS } from '~/constants/urls';
@ -109,6 +109,16 @@ const Cell: FC<IProps> = ({
return getURL({ url: thumbnail }, preset); return getURL({ url: thumbnail }, preset);
}, [thumbnail, flow]); }, [thumbnail, flow]);
const titleSize = useMemo(() => {
if (title.length > 100) {
return styles.small;
} else if (title.length > 64) {
return styles.medium;
} else {
return;
}
}, [title]);
return ( return (
<div className={classNames(styles.cell, styles[(flow && flow.display) || 'single'])} ref={ref}> <div className={classNames(styles.cell, styles[(flow && flow.display) || 'single'])} ref={ref}>
{is_visible && ( {is_visible && (
@ -134,7 +144,7 @@ const Cell: FC<IProps> = ({
<Link className={classNames(styles.face)} to={`/post${id}`}> <Link className={classNames(styles.face)} to={`/post${id}`}>
<div className={styles.face_content}> <div className={styles.face_content}>
{!text && <div className={styles.title}>{title || '...'}</div>} {!text && <div className={classNames(styles.title, titleSize)}>{title || '...'}</div>}
{!!text && !!thumbnail && ( {!!text && !!thumbnail && (
<div className={styles.text}> <div className={styles.text}>

View file

@ -95,10 +95,21 @@
opacity: 1; opacity: 1;
transform: translate(0, 0); transform: translate(0, 0);
transition: opacity 0.5s, transform 1s; 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 { .text_title {
margin-bottom: $gap / 2; margin-bottom: $gap / 2;
@include clamp(3, 1.25em)
} }
.horizontal, .horizontal,

View file

@ -2,116 +2,94 @@ import React, { FC, useState, useCallback, useEffect, useRef, useMemo } from 're
import { IFlowState } from '~/redux/flow/reducer'; import { IFlowState } from '~/redux/flow/reducer';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { getURL } from '~/utils/dom'; 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 { URLS, PRESETS } from '~/constants/urls';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';
import { INode } from "~/redux/types";
type IProps = RouteComponentProps & { type IProps = RouteComponentProps & {
heroes: IFlowState['heroes']; heroes: IFlowState['heroes'];
}; };
const FlowHeroUnconnected: FC<IProps> = ({ heroes, history }) => { const FlowHeroUnconnected: FC<IProps> = ({ heroes }) => {
const [limit, setLimit] = useState(Math.min(heroes.length, 6)); const preset = useMemo(() => (window.innerWidth <= 768 ? PRESETS.cover : PRESETS.small_hero), []);
const [limit, setLimit] = useState(6);
const [current, setCurrent] = useState(0); const [current, setCurrent] = useState(0);
const [loaded, setLoaded] = useState([]); const [loaded, setLoaded] = useState<Partial<INode>[]>([]);
const timer = useRef(null)
const history = useHistory();
const timer = useRef(null); const onLoad = useCallback((i: number) => {
const onLoad = useCallback(id => () => setLoaded([...loaded, id]), [setLoaded, loaded]); setLoaded([...loaded, heroes[i]])
const onNext = useCallback(() => { }, [heroes, loaded, setLoaded])
clearTimeout(timer.current);
if (loaded.length <= 1) return; const items = Math.min(heroes.length, limit)
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 title = useMemo(() => { const title = useMemo(() => {
if (loaded.length === 0) return null; return loaded[current]?.title || '';
const item = heroes.find(hero => hero.id === current);
if (!item || !item.title) return null;
return item.title;
}, [loaded, current, heroes]); }, [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 ( return (
<div className={styles.wrap} onMouseOver={stopSliding} onFocus={stopSliding}> <div className={styles.wrap}>
{loaded && loaded.length > 0 && ( <div className={styles.loaders}>
{
heroes.slice(0, items).map((hero, i) => (
<img src={getURL({ url: hero.thumbnail }, preset)} key={hero.id} onLoad={() => onLoad(i)} />
))
}
</div>
{loaded.length > 0 && (
<div className={styles.info}> <div className={styles.info}>
<div className={styles.title_wrap}>{title}</div> <div className={styles.title_wrap}>{title}</div>
<div className={styles.buttons}> <div className={styles.buttons}>
<div className={styles.button} onClick={onPrevious}> <div className={styles.button} onClick={onPrev}>
<Icon icon="left" /> <Icon icon="left" />
</div> </div>
<div className={styles.button} onClick={onNextPress}> <div className={styles.button} onClick={onNext}>
<Icon icon="right" /> <Icon icon="right" />
</div> </div>
</div> </div>
</div> </div>
)} )}
{heroes.slice(0, limit).map(hero => ( {loaded.slice(0, limit).map((hero, index) => (
<div <div
className={classNames(styles.hero, { className={classNames(styles.hero, {
[styles.is_visible]: loaded.includes(hero.id), [styles.is_visible]: true,
[styles.is_active]: current === hero.id, [styles.is_active]: current === index,
})} })}
style={{ style={{
backgroundImage: `url("${getURL({ url: hero.thumbnail }, preset)}")`, backgroundImage: `url("${getURL({ url: hero.thumbnail }, preset)}")`,
}} }}
key={hero.id} key={hero.id}
onClick={onClick} onClick={goToNode}
> >
<img <img
src={getURL({ url: hero.thumbnail }, preset)} src={getURL({ url: hero.thumbnail }, preset)}
alt={hero.thumbnail} alt={hero.thumbnail}
onLoad={onLoad(hero.id)}
/> />
</div> </div>
))} ))}

View file

@ -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 { .buttons {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 48px; height: 48px;
// background: rgba(0, 0, 0, 0.7);
flex-direction: row; flex-direction: row;
width: 96px; width: 96px;
border-radius: $radius; 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;
}
}

View file

@ -1,6 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { INode } from '~/redux/types'; import { INode } from '~/redux/types';
import styles from './styles.scss'; import styles from './styles.module.scss';
import { URLS } from '~/constants/urls'; import { URLS } from '~/constants/urls';
import { NodeRelatedItem } from '~/components/node/NodeRelatedItem'; import { NodeRelatedItem } from '~/components/node/NodeRelatedItem';
import { getPrettyDate } from '~/utils/dom'; import { getPrettyDate } from '~/utils/dom';

View file

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

View file

@ -1,5 +1,5 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback } from 'react';
import styles from './styles.scss'; import styles from './styles.module.scss';
import { IFlowState } from '~/redux/flow/reducer'; import { IFlowState } from '~/redux/flow/reducer';
import { LoaderCircle } from '~/components/input/LoaderCircle'; import { LoaderCircle } from '~/components/input/LoaderCircle';
import { FlowRecentItem } from '../FlowRecentItem'; import { FlowRecentItem } from '../FlowRecentItem';

View file

@ -4,7 +4,7 @@ import { InputText } from '~/components/input/InputText';
import { FlowRecent } from '../FlowRecent'; import { FlowRecent } from '../FlowRecent';
import classnames from 'classnames'; 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 * as FLOW_ACTIONS from '~/redux/flow/actions';
import { FlowSearchResults } from '../FlowSearchResults'; import { FlowSearchResults } from '../FlowSearchResults';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';

View file

@ -1,5 +1,5 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { describeArc } from '~/utils/dom'; import { describeArc } from '~/utils/dom';
interface IProps { interface IProps {

View file

@ -1,6 +1,6 @@
import classnames from 'classnames'; import classnames from 'classnames';
import React, { ButtonHTMLAttributes, DetailedHTMLProps, FC, createElement, memo } from 'react'; 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 { Icon } from '~/components/input/Icon';
import { IIcon } from '~/redux/types'; import { IIcon } from '~/redux/types';

View file

@ -1,5 +1,5 @@
import React, { HTMLAttributes } from 'react'; import React, { HTMLAttributes } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
type IProps = HTMLAttributes<HTMLDivElement> & {}; type IProps = HTMLAttributes<HTMLDivElement> & {};

View file

@ -1,6 +1,6 @@
import React, { FC, ChangeEvent, useCallback, useState, useEffect, LegacyRef } from 'react'; import React, { FC, ChangeEvent, useCallback, useState, useEffect, LegacyRef } from 'react';
import classNames from 'classnames'; 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 { Icon } from '~/components/input/Icon';
import { IInputTextProps } from '~/redux/types'; import { IInputTextProps } from '~/redux/types';
import { LoaderCircle } from '~/components/input/LoaderCircle'; import { LoaderCircle } from '~/components/input/LoaderCircle';

View file

@ -1,5 +1,5 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { describeArc } from '~/utils/dom'; import { describeArc } from '~/utils/dom';
import classNames from 'classnames'; import classNames from 'classnames';

View file

@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
interface ITextInputProps { interface ITextInputProps {
type?: 'text' | 'password'; type?: 'text' | 'password';

View file

@ -11,7 +11,7 @@ import React, {
import classNames from 'classnames'; import classNames from 'classnames';
import autosize from 'autosize'; import autosize from 'autosize';
import * as styles from '~/styles/inputs.scss'; import * as styles from '~/styles/common/inputs.module.scss';
import { Icon } from '../Icon'; import { Icon } from '../Icon';
type IProps = TextareaHTMLAttributes<HTMLTextAreaElement> & { type IProps = TextareaHTMLAttributes<HTMLTextAreaElement> & {

View file

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

View file

@ -1,6 +1,6 @@
.wrap { .wrap {
height: $header_height; height: $header_height;
z-index: 5; z-index: 25;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;

View file

@ -1,6 +1,6 @@
import React, { FC, useMemo, useState, useCallback, useEffect } from 'react'; import React, { FC, useMemo, useState, useCallback, useEffect } from 'react';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';
import styles from './styles.scss'; import styles from './styles.module.scss';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectAuthUpdates, selectAuthUser } from '~/redux/auth/selectors'; import { selectAuthUpdates, selectAuthUser } from '~/redux/auth/selectors';
import pick from 'ramda/es/pick'; import pick from 'ramda/es/pick';

View file

@ -2,7 +2,7 @@ import React, {
FC, LegacyRef, ReactChild, useCallback, useEffect, useState FC, LegacyRef, ReactChild, useCallback, useEffect, useState
} from 'react'; } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss'; import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group'; import { Group } from '~/components/containers/Group';
interface IProps { interface IProps {

View file

@ -1,6 +1,6 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback } from 'react';
import { Group } from '~/components/containers/Group'; import { Group } from '~/components/containers/Group';
import styles from './styles.scss'; import styles from './styles.module.scss';
import { getURL } from '~/utils/dom'; import { getURL } from '~/utils/dom';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';
import { IUser } from '~/redux/auth/types'; import { IUser } from '~/redux/auth/types';

Some files were not shown because too many files have changed in this diff Show more