1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-05-05 09:36:41 +07:00

eslint fix

This commit is contained in:
muerwre 2019-08-09 12:23:07 +07:00
parent dfaac877fb
commit fa4d51360b
81 changed files with 741 additions and 972 deletions
.eslintrc.js.prettierrrrrrc
.vscode
package-lock.jsonpackage.json
src
components
containers
BlurWrapper
Card
CellGrid
Grid
Group
Padder
Panel
Scroll
TagField
editors
EditorPanel
EditorUploadButton
ImageEditor
ImageGrid
ImageUploadButton
flow
Cell
HeroPlaceholder
TestGrid
input
ArcProgress
Button
Icon
Info
InputText
TextInput
main
GodRays
Header
SidePane
node
Comment
MenuButton
NodeNoComments
NodePanel
NodeRelated
Tag
Tags
placeholders/ParagraphPlaceholder
upload/ImageUpload
containers
App.tsx
dialogs
EditorDialog
LoginDialog
Modal
ScrollDialog
examples
EditorExample
ImageExample
flow/FlowLayout
main/MainLayout
node/NodeLayout
redux
sprites
utils

View file

@ -1,26 +1,27 @@
module.exports = { module.exports = {
extends: ['airbnb', 'airbnb-base', 'plugin:@typescript-eslint/recommended', 'prettier'], extends: ['airbnb', 'airbnb-base', 'prettier/@typescript-eslint', 'plugin:@typescript-eslint/recommended'],
// "parser": "babel-eslint", // "parser": "babel-eslint",
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: { parserOptions: {
ecmaFeatures: { ecmaFeatures: {
jsx: true jsx: true,
}, },
project: './tsconfig.json' project: './tsconfig.json',
}, },
plugins: ['@typescript-eslint', 'react', 'jsx-a11y', 'import', 'react-hooks', 'prettier'], plugins: ['@typescript-eslint', 'react', 'jsx-a11y', 'import', 'react-hooks'],
settings: { settings: {
'import/resolver': { 'import/resolver': {
// node: { // node: {
// extensions: ['.js', '.jsx', '.ts', '.tsx'], // extensions: ['.js', '.jsx', '.ts', '.tsx'],
// }, // },
typescript: {} typescript: {},
} },
}, },
rules: { rules: {
indent: ['error', 2], indent: ['error', 2],
'@typescript-eslint/explicit-function-return-type': 0, '@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/indent': ['error', 2], '@typescript-eslint/indent': ['warn', 2],
"indent": "off",
'comma-dangle': 0, 'comma-dangle': 0,
'no-restricted-syntax': 1, 'no-restricted-syntax': 1,
'react/prop-types': 0, 'react/prop-types': 0,
@ -44,16 +45,16 @@ module.exports = {
'react-hooks/rules-of-hooks': 'error', 'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn', 'react-hooks/exhaustive-deps': 'warn',
'no-nested-ternary': 1, 'no-nested-ternary': 1,
'arrow-parens': 0,
'import/prefer-default-export': 0, 'import/prefer-default-export': 0,
'no-return-await': 0, 'max-line-length': [true, 100],
'prefer-promise-reject-errors': 0, // 'max-len': 100,
'import/order': 0 // 'max-len': { "code": 100 },
'max-len': ["warn", { "code": 100 }]
}, },
globals: { globals: {
document: false, document: false,
window: false, window: false,
HTMLInputElement: false, HTMLInputElement: false,
HTMLDivElement: false HTMLDivElement: false,
} },
}; };

View file

@ -1,4 +1,4 @@
{ {
"printWidth": 120, "printWidth": 100,
"singleQuote": true "singleQuote": true
} }

20
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,20 @@
{
"eslint.enable": true,
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"editor.rulers": [100],
"prettier.eslintIntegration": true,
"editor.formatOnSave": true,
"editor.formatOnSaveTimeout": 750,
"[javascript]": {
"editor.formatOnSave": true,
"editor.formatOnSaveTimeout": 750,
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.formatOnSaveTimeout": 750,
},
"[typescriptreact]": {
"editor.formatOnSave": true,
"editor.formatOnSaveTimeout": 750,
},
}

518
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -27,18 +27,6 @@
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1", "babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.28.11", "css-loader": "^0.28.11",
"eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.1",
"eslint-config-prettier": "^6.0.0",
"eslint-import-resolver-babel-module": "^4.0.0",
"eslint-import-resolver-typescript": "^1.1.1",
"eslint-import-resolver-webpack": "^0.9.0",
"eslint-loader": "^2.2.1",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-react": "^7.14.3",
"file-loader": "^1.1.11", "file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
@ -51,7 +39,6 @@
"style-loader": "^0.21.0", "style-loader": "^0.21.0",
"ts-node": "^8.0.1", "ts-node": "^8.0.1",
"typescript": "^3.2.4", "typescript": "^3.2.4",
"typescript-eslint-parser": "^22.0.0",
"uglifyjs-webpack-plugin": "^1.3.0", "uglifyjs-webpack-plugin": "^1.3.0",
"webpack": "^4.6.0", "webpack": "^4.6.0",
"webpack-cli": "^3.2.3", "webpack-cli": "^3.2.3",
@ -74,7 +61,19 @@
"date-fns": "^2.0.0-alpha.27", "date-fns": "^2.0.0-alpha.27",
"dotenv": "^8.0.0", "dotenv": "^8.0.0",
"dotenv-webpack": "^1.7.0", "dotenv-webpack": "^1.7.0",
"eslint-plugin-react-hooks": "^1.6.1", "eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.1",
"eslint-config-prettier": "^6.0.0",
"eslint-import-resolver-babel-module": "^4.0.0",
"eslint-import-resolver-typescript": "^1.1.1",
"eslint-import-resolver-webpack": "^0.9.0",
"eslint-loader": "^2.2.1",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-react": "^7.14.3",
"eslint-plugin-react-hooks": "^1.7.0",
"history": "^4.7.2", "history": "^4.7.2",
"http-errors": "~1.6.2", "http-errors": "~1.6.2",
"less": "^3.8.1", "less": "^3.8.1",

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 * as styles from './styles.scss';
type IProps = AllHTMLAttributes<HTMLDivElement> & { is_blurred: boolean }; type IProps = AllHTMLAttributes<HTMLDivElement> & { is_blurred: boolean };

View file

@ -1,7 +1,8 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import classNames = require("classnames");
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import classNames = require('classnames');
type IProps = React.HTMLAttributes<HTMLDivElement> & { type IProps = React.HTMLAttributes<HTMLDivElement> & {
seamless?: boolean; seamless?: boolean;
} }
@ -12,12 +13,12 @@ const Card: FC<IProps> = ({
seamless, seamless,
...props ...props
}) => ( }) => (
<div <div
className={classNames(styles.card, className, { seamless })} className={classNames(styles.card, className, { seamless })}
{...props} {...props}
> >
{children} {children}
</div> </div>
); );
export { Card }; export { Card };

View file

@ -1,6 +1,9 @@
import React, { FC, HTMLAttributes, ReactChild, ReactChildren } from 'react'; import React, {
FC, HTMLAttributes, ReactChild, ReactChildren
} from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import classNames = require("classnames");
import classNames = require('classnames');
type IProps = HTMLAttributes<HTMLDivElement> & { type IProps = HTMLAttributes<HTMLDivElement> & {
children: any; children: any;
@ -13,13 +16,13 @@ const CellGrid: FC<IProps> = ({
className, className,
...props ...props
}) => ( }) => (
<div <div
className={classNames(styles.grid, className)} className={classNames(styles.grid, className)}
style={{ gridTemplateColumns: `repeat(auto-fit, minmax(${size}px, 1fr))` }} style={{ gridTemplateColumns: `repeat(auto-fit, minmax(${size}px, 1fr))` }}
{...props} {...props}
> >
{children} {children}
</div> </div>
); );
export { CellGrid }; export { CellGrid };

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 * as styles from './styles.scss';
type IProps = React.HTMLAttributes<HTMLDivElement> & { type IProps = React.HTMLAttributes<HTMLDivElement> & {
horizontal?: boolean; horizontal?: boolean;
@ -15,14 +15,14 @@ type IProps = React.HTMLAttributes<HTMLDivElement> & {
const Grid: FC<IProps> = ({ const Grid: FC<IProps> = ({
children, children,
className = "", className = '',
horizontal = false, horizontal = false,
vertical = false, vertical = false,
square = false, square = false,
size = "auto", size = 'auto',
style = {}, style = {},
columns = "auto", columns = 'auto',
rows = "auto", rows = 'auto',
gap = 10, gap = 10,
stretchy, stretchy,
...props ...props
@ -37,10 +37,10 @@ const Grid: FC<IProps> = ({
style={{ style={{
...style, ...style,
gridTemplateColumns: square gridTemplateColumns: square
? `repeat(auto-fill, ${(columns !== "auto" && columns) || size})` ? `repeat(auto-fill, ${(columns !== 'auto' && columns) || size})`
: columns, : columns,
gridTemplateRows: square gridTemplateRows: square
? `repeat(auto-fill, ${(rows !== "auto" && rows) || size})` ? `repeat(auto-fill, ${(rows !== 'auto' && rows) || size})`
: rows, : rows,
gridAutoRows: rows, gridAutoRows: rows,
gridAutoColumns: columns, gridAutoColumns: columns,

View file

@ -18,7 +18,7 @@ const Group: FC<IProps> = ({
bottom = false, bottom = false,
wrap = false, wrap = false,
seamless = false, seamless = false,
...props ...props
}) => ( }) => (
<div <div
className={classNames( className={classNames(

View file

@ -1,8 +1,9 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import classNames = require("classnames");
type IProps = React.HTMLAttributes<HTMLDivElement> & { import classNames = require('classnames');
type IProps = React.HTMLAttributes<HTMLDivElement> & {
padding?: number; padding?: number;
vertical?: boolean; vertical?: boolean;
horizontal?: boolean; horizontal?: boolean;
@ -17,13 +18,13 @@ const Padder: FC<IProps> = ({
horizontal, horizontal,
...props ...props
}) => ( }) => (
<div <div
className={classNames(styles.padder, className, { vertical, horizontal })} className={classNames(styles.padder, className, { vertical, horizontal })}
style={padding ? { ...style, padding } : style} style={padding ? { ...style, padding } : style}
{...props} {...props}
> >
{children} {children}
</div> </div>
); );
export { Padder }; export { Padder };

View file

@ -1,10 +1,11 @@
import React, { FC, HTMLAttributes } from 'react'; import React, { FC, HTMLAttributes } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import classNames = require("classnames");
import classNames = require('classnames');
type IProps = HTMLAttributes<HTMLDivElement> & { type IProps = HTMLAttributes<HTMLDivElement> & {
seamless?: boolean; seamless?: boolean;
stretchy?: boolean stretchy?: boolean;
} }
const Panel: FC<IProps> = ({ const Panel: FC<IProps> = ({
@ -14,9 +15,9 @@ const Panel: FC<IProps> = ({
stretchy, stretchy,
...props ...props
}) => ( }) => (
<div className={classNames(styles.panel, className, { seamless, stretchy })} {...props}> <div className={classNames(styles.panel, className, { seamless, stretchy })} {...props}>
{children} {children}
</div> </div>
); );
export { Panel }; export { Panel };

View file

@ -1,7 +1,7 @@
import React, { MouseEventHandler, useEffect, useState } from 'react'; import React, { MouseEventHandler, useEffect, useState } from 'react';
import * as styles from './styles.scss';
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';
interface IProps { interface IProps {
children: Element | React.ReactChild; children: Element | React.ReactChild;
@ -33,11 +33,11 @@ export const Scroll = ({
renderTrackVertical={data => <div className={styles.track_vertical} {...data} />} renderTrackVertical={data => <div className={styles.track_vertical} {...data} />}
renderThumbHorizontal={data => <div className={styles.thumb_horizontal} {...data} />} renderThumbHorizontal={data => <div className={styles.thumb_horizontal} {...data} />}
renderThumbVertical={data => <div className={styles.thumb_vertical} {...data} />} renderThumbVertical={data => <div className={styles.thumb_vertical} {...data} />}
renderView = {data => <div className={styles.view} {...data} />} renderView={data => <div className={styles.view} {...data} />}
hideTracksWhenNotNeeded hideTracksWhenNotNeeded
universal universal
ref={setRef} ref={setRef}
{ ...props } {...props}
> >
{children} {children}
</Scrollbars> </Scrollbars>

View file

@ -1,10 +1,10 @@
import React, {FC, HTMLAttributes} from 'react'; import React, { FC, HTMLAttributes } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
type IProps = HTMLAttributes<HTMLDivElement> & {} type IProps = HTMLAttributes<HTMLDivElement> & {}
const TagField: FC<IProps> = ({ const TagField: FC<IProps> = ({
children, children,
}) => ( }) => (
<div className={styles.wrap}> <div className={styles.wrap}>
{children} {children}

View file

@ -1,7 +1,7 @@
import React, { FC, ChangeEventHandler } from 'react'; import React, { FC, ChangeEventHandler } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { INode } from '~/redux/types'; import { INode } from '~/redux/types';
import { ImageUploadButton } from '~/components/editors/ImageUploadButton'; import { EditorUploadButton } from '~/components/editors/EditorUploadButton';
interface IProps { interface IProps {
data: INode; data: INode;
@ -11,7 +11,7 @@ interface IProps {
const EditorPanel: FC<IProps> = ({ onUpload }) => ( const EditorPanel: FC<IProps> = ({ onUpload }) => (
<div className={styles.panel}> <div className={styles.panel}>
<ImageUploadButton onUpload={onUpload} /> <EditorUploadButton onUpload={onUpload} />
</div> </div>
); );

View file

@ -0,0 +1,21 @@
import React, { FC, ChangeEventHandler } from 'react';
import * as styles from './styles.scss';
import { Icon } from '~/components/input/Icon';
interface IProps {
onUpload?: ChangeEventHandler<HTMLInputElement>;
}
const EditorUploadButton: FC<IProps> = ({
onUpload,
}) => (
<div className={styles.wrap}>
<input type="file" onChange={onUpload} accept="image/*" multiple />
<div className={styles.icon}>
<Icon size={32} icon="plus" />
</div>
</div>
);
export { EditorUploadButton };

View file

@ -1,40 +1,55 @@
import React, { FC, useCallback, useEffect, useState, ChangeEventHandler, DragEventHandler } from 'react'; import React, {
FC,
useCallback,
useEffect,
useState,
ChangeEventHandler,
DragEventHandler
} from 'react';
import uuid from 'uuid4'; import uuid from 'uuid4';
import { INode, IFileWithUUID, IFile } from '~/redux/types';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectUploads } from '~/redux/uploads/selectors';
import assocPath from 'ramda/es/assocPath'; import assocPath from 'ramda/es/assocPath';
import append from 'ramda/es/append'; import append from 'ramda/es/append';
import { INode, IFileWithUUID, 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 { ImageGrid } from '~/components/editors/ImageGrid';
import { moveArrItem } from '~/utils/fn'; import { moveArrItem } from '~/utils/fn';
import { IUploadStatus } from '~/redux/uploads/reducer'; import { IUploadStatus } from '~/redux/uploads/reducer';
const mapStateToProps = selectUploads; const mapStateToProps = selectUploads;
const mapDispatchToProps = { const mapDispatchToProps = {
uploadUploadFiles: UPLOAD_ACTIONS.uploadUploadFiles, uploadUploadFiles: UPLOAD_ACTIONS.uploadUploadFiles
}; };
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { type IProps = ReturnType<typeof mapStateToProps> &
typeof mapDispatchToProps & {
data: INode; data: INode;
pending_files: IUploadStatus[]; pending_files: IUploadStatus[];
setData: (val: INode) => void; setData: (val: INode) => void;
onFileMove: (o: number, n: number) => void; onFileMove: (o: number, n: number) => void;
onInputChange: ChangeEventHandler<HTMLInputElement>; onInputChange: ChangeEventHandler<HTMLInputElement>;
onDrop: DragEventHandler<HTMLFormElement>; onDrop: DragEventHandler<HTMLFormElement>;
}
const ImageEditorUnconnected: FC<IProps> = ({ data, onFileMove, onInputChange, onDrop, pending_files }) => {
return (
<ImageGrid
onFileMove={onFileMove}
items={data.files}
locked={pending_files}
onUpload={onInputChange}
onDrop={onDrop}
/>
);
}; };
const ImageEditor = connect(mapStateToProps, mapDispatchToProps)(ImageEditorUnconnected) const ImageEditorUnconnected: FC<IProps> = ({
data,
onFileMove,
onInputChange,
onDrop,
pending_files
}) => (
<ImageGrid
onFileMove={onFileMove}
items={data.files}
locked={pending_files}
onUpload={onInputChange}
onDrop={onDrop}
/>
);
const ImageEditor = connect(
mapStateToProps,
mapDispatchToProps
)(ImageEditorUnconnected);
export { ImageEditor }; export { ImageEditor };

View file

@ -1,10 +1,11 @@
import React, { FC, ReactChildren, useCallback, ChangeEventHandler, DragEventHandler } from 'react'; import React, {
FC, ReactChildren, useCallback, ChangeEventHandler, DragEventHandler
} from 'react';
import { SortableContainer, SortableElement } from 'react-sortable-hoc'; import { SortableContainer, SortableElement } from 'react-sortable-hoc';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { ImageUpload } from '~/components/upload/ImageUpload'; import { ImageUpload } from '~/components/upload/ImageUpload';
import { IFile } from '~/redux/types'; import { IFile } from '~/redux/types';
import { IUploadStatus } from '~/redux/uploads/reducer'; import { IUploadStatus } from '~/redux/uploads/reducer';
import { ImageUploadButton } from '~/components/editors/ImageUploadButton';
interface IProps { interface IProps {
items: IFile[]; items: IFile[];
@ -12,50 +13,52 @@ interface IProps {
onFileMove: (o: number, n: number) => void; onFileMove: (o: number, n: number) => void;
onUpload?: ChangeEventHandler<HTMLInputElement>; onUpload?: ChangeEventHandler<HTMLInputElement>;
onDrop: DragEventHandler<HTMLFormElement>; onDrop: DragEventHandler<HTMLFormElement>;
}; }
const SortableItem = SortableElement(({ children }) => <div className={styles.item}>{children}</div>); const SortableItem = SortableElement(({ children }) => <div className={styles.item}>{children}</div>);
const SortableList = SortableContainer(({ items, locked, onUpload, onDrop }: { items: IFile[]; locked: IUploadStatus[]; onUpload: ChangeEventHandler<HTMLInputElement>; onDrop: DragEventHandler<HTMLFormElement> }) => { const SortableList = SortableContainer(
return ( ({
items,
locked,
onDrop
}: {
items: IFile[];
locked: IUploadStatus[];
onUpload: ChangeEventHandler<HTMLInputElement>;
onDrop: DragEventHandler<HTMLFormElement>;
}) => (
<form className={styles.grid} onDrop={onDrop}> <form className={styles.grid} onDrop={onDrop}>
{ {items.map((file, index) => (
items.map((file, index) => ( <SortableItem key={file.id} index={index} collection={0}>
<SortableItem key={file.id} index={index} collection={0}> <ImageUpload id={file.id} thumb={file.url} />
<ImageUpload </SortableItem>
id={file.id} ))}
thumb={file.url} {locked.map((item, index) => (
/> <SortableItem key={item.temp_id} index={index} collection={1} disabled>
</SortableItem> <ImageUpload thumb={item.preview} progress={item.progress} is_uploading />
)) </SortableItem>
} ))}
{
locked.map((item, index) => (
<SortableItem key={item.temp_id} index={index} collection={1} disabled>
<ImageUpload
thumb={item.preview}
progress={item.progress}
is_uploading
/>
</SortableItem>
))
}
</form> </form>
); )
}); );
const ImageGrid: FC<IProps> = ({ const ImageGrid: FC<IProps> = ({
items, items, locked, onFileMove, onUpload, onDrop
locked,
onFileMove,
onUpload,
onDrop,
}) => { }) => {
const onMove = useCallback(({ oldIndex, newIndex }) => onFileMove(oldIndex, newIndex), [onFileMove]); const onMove = useCallback(({ oldIndex, newIndex }) => onFileMove(oldIndex, newIndex), [onFileMove]);
return ( return (
<SortableList onSortEnd={onMove} axis="xy" items={items} locked={locked} onUpload={onUpload} onDrop={onDrop} pressDelay={100} /> <SortableList
) onSortEnd={onMove}
} axis="xy"
items={items}
locked={locked}
onUpload={onUpload}
onDrop={onDrop}
pressDelay={100}
/>
);
};
export { ImageGrid }; export { ImageGrid };

View file

@ -1,21 +0,0 @@
import React, { FC, ChangeEventHandler } from 'react';
import * as styles from './styles.scss';
import { Icon } from '~/components/input/Icon';
interface IProps {
onUpload?: ChangeEventHandler<HTMLInputElement>;
};
const ImageUploadButton: FC<IProps> = ({
onUpload,
}) => (
<div className={styles.wrap}>
<input type="file" onChange={onUpload} accept="image/*" multiple />
<div className={styles.icon}>
<Icon size={32} icon="plus" />
</div>
</div>
)
export { ImageUploadButton };

View file

@ -1,6 +1,7 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import classNames = require("classnames");
import classNames = require('classnames');
interface IProps { interface IProps {
height?: number; height?: number;
@ -16,15 +17,15 @@ const Cell: FC<IProps> = ({
title, title,
is_hero, is_hero,
}) => ( }) => (
<div <div
className={classNames(styles.cell, { is_hero })} className={classNames(styles.cell, { is_hero })}
style={{ style={{
gridRowEnd: `span ${height}`, gridRowEnd: `span ${height}`,
gridColumnEnd: `span ${width}`, gridColumnEnd: `span ${width}`,
}} }}
> >
{ title && <div className={styles.title}>{title}</div> } { title && <div className={styles.title}>{title}</div> }
</div> </div>
); );
export { Cell }; export { Cell };

View file

@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
const style = require('./style.scss'); const style = require('./style.scss');
export const HeroPlaceholder = () => ( export const HeroPlaceholder = () => (
<div className={style.container}> <div className={style.container} />
</div>
); );

View file

@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import { Cell } from '~/components/flow/Cell';
import { range } from 'ramda'; import { range } from 'ramda';
import { Cell } from '~/components/flow/Cell';
import * as styles from './styles.scss'; import * as styles from './styles.scss';

View file

@ -5,7 +5,7 @@ import { describeArc } from '~/utils/dom';
interface IProps { interface IProps {
size: number; size: number;
progress: number; progress: number;
}; }
export const ArcProgress: FC<IProps> = ({ size, progress }) => ( export const ArcProgress: FC<IProps> = ({ size, progress }) => (
<svg className={styles.icon} width={size} height={size}> <svg className={styles.icon} width={size} height={size}>

View file

@ -1,14 +1,14 @@
import classnames from "classnames"; import classnames from 'classnames';
import * as styles from "./styles.scss"; import React, { ButtonHTMLAttributes, DetailedHTMLProps, FC } from 'react';
import React, { ButtonHTMLAttributes, DetailedHTMLProps, FC } from "react"; import * as styles from './styles.scss';
import { Icon } from "~/components/input/Icon"; import { Icon } from '~/components/input/Icon';
import { IIcon } from "~/redux/types"; import { IIcon } from '~/redux/types';
type IButtonProps = DetailedHTMLProps< type IButtonProps = DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>, ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement HTMLButtonElement
> & { > & {
size?: "mini" | "normal" | "big" | "giant" | "micro"; size?: 'mini' | 'normal' | 'big' | 'giant' | 'micro';
iconLeft?: IIcon; iconLeft?: IIcon;
iconRight?: IIcon; iconRight?: IIcon;
seamless?: boolean; seamless?: boolean;
@ -22,8 +22,8 @@ type IButtonProps = DetailedHTMLProps<
}; };
export const Button: FC<IButtonProps> = ({ export const Button: FC<IButtonProps> = ({
className = "", className = '',
size = "normal", size = 'normal',
iconLeft, iconLeft,
iconRight, iconRight,
children, children,
@ -36,26 +36,25 @@ export const Button: FC<IButtonProps> = ({
title, title,
stretchy, stretchy,
...props ...props
}) => }) => React.createElement(seamless || non_submitting ? 'div' : 'button', {
React.createElement(seamless || non_submitting ? "div" : "button", { className: classnames(styles.button, className, styles[size], {
className: classnames(styles.button, className, styles[size], { red,
red, grey,
grey, seamless,
seamless, transparent,
transparent, disabled: props.disabled,
disabled: props.disabled, icon: (iconLeft || iconRight) && !title && !children,
icon: (iconLeft || iconRight) && !title && !children, is_loading,
is_loading, stretchy
stretchy }),
}), children: [
children: [ iconLeft && <Icon icon={iconLeft} size={20} key={0} />,
iconLeft && <Icon icon={iconLeft} size={20} key={0} />, title ? (
title ? ( <span key={1}>{title}</span>
<span key={1}>{title}</span> ) : (
) : ( (children && <span key={1}>{children}</span>) || null
(children && <span key={1}>{children}</span>) || null ),
), iconRight && <Icon icon={iconRight} size={20} key={2} />
iconRight && <Icon icon={iconRight} size={20} key={2} /> ],
], ...props
...props });
});

View file

@ -1,18 +1,20 @@
import React, { FC } from "react"; import React, { FC } from 'react';
import { IIcon } from "~/redux/types"; import { IIcon } from '~/redux/types';
type IProps = React.SVGAttributes<SVGElement> & { type IProps = React.SVGAttributes<SVGElement> & {
size?: number; size?: number;
icon: IIcon; icon: IIcon;
}; };
export const Icon: FC<IProps> = ({ size = 20, icon, style, ...props }) => ( export const Icon: FC<IProps> = ({
size = 20, icon, style, ...props
}) => (
<svg <svg
width={size} width={size}
height={size} height={size}
viewBox={`0 0 24 24`} viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid slice" preserveAspectRatio="xMidYMid slice"
style={{ ...style, outline: "none" }} style={{ ...style, outline: 'none' }}
{...props} {...props}
> >
<use xlinkHref={`#${icon}`} /> <use xlinkHref={`#${icon}`} />

View file

@ -1,12 +1,13 @@
import * as React from 'react'; import * as React from 'react';
import classNames = require("classnames");
import classNames = require('classnames');
const style = require('./style.scss'); const style = require('./style.scss');
interface IInfoProps { interface IInfoProps {
text?: string, text?: string;
children?: string, children?: string;
level?: string, level?: string;
} }
export const Info: React.FunctionComponent<IInfoProps> = ({ export const Info: React.FunctionComponent<IInfoProps> = ({
text, text,

View file

@ -4,8 +4,8 @@ import React, {
useCallback, useCallback,
useState, useEffect, useState, useEffect,
} from 'react'; } from 'react';
import * as styles from '~/styles/inputs.scss';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from '~/styles/inputs.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';
@ -31,8 +31,8 @@ const InputText: FC<IInputTextProps> = ({
[handler], [handler],
); );
const onFocus = useCallback(() => setFocused(true), [focused]); const onFocus = useCallback(() => setFocused(true), []);
const onBlur = useCallback(() => setFocused(false), [focused]); const onBlur = useCallback(() => setFocused(false), []);
useEffect(() => { useEffect(() => {
if (onRef) onRef(inner_ref); if (onRef) onRef(inner_ref);
@ -50,7 +50,8 @@ const InputText: FC<IInputTextProps> = ({
[styles.has_error]: !!error, [styles.has_error]: !!error,
[styles.has_loader]: is_loading, [styles.has_loader]: is_loading,
}, },
)}> )}
>
<div className={styles.input}> <div className={styles.input}>
<input <input
type="text" type="text"

View file

@ -2,12 +2,12 @@ import * as React from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
interface ITextInputProps { interface ITextInputProps {
type?: 'text' | 'password', type?: 'text' | 'password';
placeholder?: string, placeholder?: string;
label?: string, label?: string;
value?: string, value?: string;
onChange: React.ChangeEventHandler, onChange: React.ChangeEventHandler;
} }
export const TextInput: React.FunctionComponent<ITextInputProps> = ({ export const TextInput: React.FunctionComponent<ITextInputProps> = ({
@ -15,15 +15,15 @@ export const TextInput: React.FunctionComponent<ITextInputProps> = ({
placeholder = '', placeholder = '',
label, label,
onChange = () => {}, onChange = () => {},
value='', value = '',
}) => ( }) => (
<div <div
className={styles.wrapper} className={styles.wrapper}
> >
<div className={styles.container}> <div className={styles.container}>
{ {
label && label
<div className={styles.label}>{label}</div> && <div className={styles.label}>{label}</div>
} }
<input <input
placeholder={placeholder} placeholder={placeholder}

View file

@ -1,7 +1,7 @@
import * as React from 'react'; import * as React from 'react';
interface IGodRaysProps { interface IGodRaysProps {
raised?: boolean, raised?: boolean;
} }
export class GodRays extends React.Component<IGodRaysProps> { export class GodRays extends React.Component<IGodRaysProps> {
@ -30,22 +30,26 @@ export class GodRays extends React.Component<IGodRaysProps> {
return setTimeout(() => window.requestAnimationFrame(this.draw), 1000); return setTimeout(() => window.requestAnimationFrame(this.draw), 1000);
} }
const { width, height, rays, particles } = this.state; const {
width, height, rays, particles
} = this.state;
const ctx = this.canvas.getContext('2d'); const ctx = this.canvas.getContext('2d');
ctx.globalCompositeOperation = "luminosity"; ctx.globalCompositeOperation = 'luminosity';
ctx.clearRect(0, 0, width, height + 100); // clear canvas ctx.clearRect(0, 0, width, height + 100); // clear canvas
ctx.save(); ctx.save();
rays.map(({ angle, iterator, weight, speed, pulsar, opacity }, index) => { rays.map(({
angle, iterator, weight, speed, pulsar, opacity
}, index) => {
const gradient = ctx.createLinearGradient(0, 0, 0, height * 1.3); const gradient = ctx.createLinearGradient(0, 0, 0, height * 1.3);
gradient.addColorStop(0.2, `rgba(255, 60, 40, ${opacity * 0.1})`); gradient.addColorStop(0.2, `rgba(255, 60, 40, ${opacity * 0.1})`);
gradient.addColorStop(1, `rgba(255, 60, 40, 0)`); gradient.addColorStop(1, 'rgba(255, 60, 40, 0)');
const gradient2 = ctx.createLinearGradient(0, 0, 0, height * 1.3); const gradient2 = ctx.createLinearGradient(0, 0, 0, height * 1.3);
gradient2.addColorStop(0.2, `rgba(255, 40, 100, ${opacity * 0.2})`); gradient2.addColorStop(0.2, `rgba(255, 40, 100, ${opacity * 0.2})`);
gradient2.addColorStop(1, "rgba(255, 40, 100, 0)"); gradient2.addColorStop(1, 'rgba(255, 40, 100, 0)');
ctx.save(); ctx.save();
ctx.translate(width / 2, -900); ctx.translate(width / 2, -900);
@ -106,7 +110,7 @@ export class GodRays extends React.Component<IGodRaysProps> {
this.init(); this.init();
} }
render(){ render() {
const { width, height } = this.state; const { width, height } = this.state;
return ( return (
@ -119,7 +123,8 @@ export class GodRays extends React.Component<IGodRaysProps> {
zIndex: -1, zIndex: -1,
opacity: 1, opacity: 1,
pointerEvents: 'none', pointerEvents: 'none',
}}> }}
>
<canvas <canvas
width={width} width={width}
height={height + 100} height={height + 100}
@ -128,12 +133,13 @@ export class GodRays extends React.Component<IGodRaysProps> {
position: 'relative', position: 'relative',
top: -100, top: -100,
}} }}
ref={el => { this.canvas = el; }} ref={(el) => { this.canvas = el; }}
/> />
</div> </div>
); );
} }
canvas: HTMLCanvasElement; canvas: HTMLCanvasElement;
inc; inc;
}; }

View file

@ -1,13 +1,13 @@
import * as React from "react"; import * as React from 'react';
import { Logo } from "~/components/main/Logo"; import { connect } from 'react-redux';
import { connect } from "react-redux"; import { push as historyPush } from 'connected-react-router';
import { push as historyPush } from "connected-react-router"; import { Link } from 'react-router-dom';
import { Logo } from '~/components/main/Logo';
import * as style from "./style.scss"; import * as style from './style.scss';
import { Filler } from "~/components/containers/Filler"; import { Filler } from '~/components/containers/Filler';
import { Link } from "react-router-dom"; import { selectUser } from '~/redux/auth/selectors';
import {selectUser} from "~/redux/auth/selectors"; import { Group } from '~/components/containers/Group';
import {Group} from "~/components/containers/Group";
const mapStateToProps = selectUser; const mapStateToProps = selectUser;
@ -20,31 +20,29 @@ type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {
const HeaderUnconnected: React.FunctionComponent<IProps> = ({ const HeaderUnconnected: React.FunctionComponent<IProps> = ({
username, username,
is_user is_user
}) => { }) => (
return ( <div className="default_container head_container">
<div className="default_container head_container"> <div className={style.container}>
<div className={style.container}> <Logo />
<Logo />
<Filler /> <Filler />
<div className={style.plugs}> <div className={style.plugs}>
<Link to="/">flow</Link> <Link to="/">flow</Link>
<Link to="/examples/image">image</Link> <Link to="/examples/image">image</Link>
<Link to="/examples/edit">editor</Link> <Link to="/examples/edit">editor</Link>
<Link to="/examples/horizontal">horizontal</Link> <Link to="/examples/horizontal">horizontal</Link>
</div>
<Filler />
<Group horizontal className={style.user_button}>
<div>username</div>
<div className={style.user_avatar}/>
</Group>
</div> </div>
<Filler />
<Group horizontal className={style.user_button}>
<div>username</div>
<div className={style.user_avatar} />
</Group>
</div> </div>
); </div>
}; );
const Header = connect( const Header = connect(
mapStateToProps, mapStateToProps,

View file

@ -1,7 +1,9 @@
import React, { FC, LegacyRef, ReactChild, useCallback, useEffect, useState } from 'react'; import React, {
import * as styles from './styles.scss'; FC, LegacyRef, ReactChild, useCallback, useEffect, useState
} from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import {Group} from "~/components/containers/Group"; import * as styles from './styles.scss';
import { Group } from '~/components/containers/Group';
interface IProps { interface IProps {
} }
@ -28,8 +30,8 @@ export const SidePane: FC<IProps> = ({
return () => { return () => {
window.removeEventListener('resize', moveThis); window.removeEventListener('resize', moveThis);
document.removeEventListener('DOMContentLoaded', moveThis); document.removeEventListener('DOMContentLoaded', moveThis);
} };
}, []); }, [moveThis]);
return ( return (
<div className={styles.pane} style={{ transform: `translate(${left}px, 0px)` }}> <div className={styles.pane} style={{ transform: `translate(${left}px, 0px)` }}>

View file

@ -1,7 +1,8 @@
import React, {FC, HTMLAttributes} from 'react'; import React, { FC, HTMLAttributes } from 'react';
import { Card } from "~/components/containers/Card"; import { Card } from '~/components/containers/Card';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import classNames = require("classnames");
import classNames = require('classnames');
type IProps = HTMLAttributes<HTMLDivElement> & { type IProps = HTMLAttributes<HTMLDivElement> & {
is_empty?: boolean; is_empty?: boolean;
@ -14,17 +15,17 @@ const Comment: FC<IProps> = ({
className, className,
...props ...props
}) => ( }) => (
<Card <Card
className={classNames(styles.wrap, className, { is_empty, is_loading })} className={classNames(styles.wrap, className, { is_empty, is_loading })}
seamless seamless
{...props} {...props}
> >
<div className={styles.thumb}> <div className={styles.thumb}>
<div className={styles.thumb_image} /> <div className={styles.thumb_image} />
</div> </div>
<div className={styles.text} /> <div className={styles.text} />
</Card> </Card>
); );
export { Comment }; export { Comment };

View file

@ -1,7 +1,7 @@
import React, {FC} from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { Group } from "~/components/containers/Group"; import { Group } from '~/components/containers/Group';
import { Filler } from "~/components/containers/Filler"; import { Filler } from '~/components/containers/Filler';
interface IProps { interface IProps {
title: string; title: string;
@ -19,7 +19,10 @@ const MenuButton: FC<IProps> = ({
> >
<Group horizontal> <Group horizontal>
<div className={styles.icon}> <div className={styles.icon}>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24">
<path fill="none" d="M0 0h24v24H0V0z" />
<path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.88 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z" />
</svg>
</div> </div>
<Filler> <Filler>

View file

@ -1,15 +1,15 @@
import React, { FC } from "react"; import React, { FC } from 'react';
import { Comment } from "~/components/node/Comment"; import { Comment } from '~/components/node/Comment';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import {Group} from "~/components/containers/Group"; import { Group } from '~/components/containers/Group';
interface IProps {} interface IProps {}
const NodeNoComments: FC<IProps> = () => ( const NodeNoComments: FC<IProps> = () => (
<Group className={styles.wrap}> <Group className={styles.wrap}>
<Comment is_empty={true} is_loading={false} style={{ height: 94 }} /> <Comment is_empty is_loading={false} style={{ height: 94 }} />
<Comment is_empty={true} is_loading={false} style={{ height: 104 }} /> <Comment is_empty is_loading={false} style={{ height: 104 }} />
<Comment is_empty={true} is_loading={false} style={{ height: 100 }} /> <Comment is_empty is_loading={false} style={{ height: 100 }} />
</Group> </Group>
); );

View file

@ -1,21 +1,21 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { Group } from "~/components/containers/Group"; import { Group } from '~/components/containers/Group';
import { Filler } from "~/components/containers/Filler"; import { Filler } from '~/components/containers/Filler';
interface IProps {} interface IProps {}
const NodePanel: FC<IProps> = () => ( const NodePanel: FC<IProps> = () => (
<div className={styles.wrap}> <div className={styles.wrap}>
<Group horizontal className={styles.panel}> <Group horizontal className={styles.panel}>
<Filler> <Filler>
<div className={styles.title}>Node title</div> <div className={styles.title}>Node title</div>
<div className={styles.name}>~author</div> <div className={styles.name}>~author</div>
</Filler> </Filler>
</Group> </Group>
<div className={styles.mark} /> <div className={styles.mark} />
</div> </div>
); );
export { NodePanel }; export { NodePanel };

View file

@ -1,7 +1,7 @@
import React, {FC, HTMLAttributes} from 'react'; import React, { FC, HTMLAttributes } from 'react';
import { range } from 'ramda'; import { range } from 'ramda';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import {Group} from "~/components/containers/Group"; import { Group } from '~/components/containers/Group';
type IProps = HTMLAttributes<HTMLDivElement> & {} type IProps = HTMLAttributes<HTMLDivElement> & {}
@ -16,7 +16,7 @@ const NodeRelated: FC<IProps> = ({
</div> </div>
<div className={styles.grid}> <div className={styles.grid}>
{ {
range(1,7).map(el => (<div className={styles.item} key={el} />)) range(1, 7).map(el => (<div className={styles.item} key={el} />))
} }
</div> </div>
</Group> </Group>

View file

@ -1,7 +1,8 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import classNames = require("classnames"); import { ITag } from '~/redux/types';
import {ITag} from "~/redux/types";
import classNames = require('classnames');
interface IProps { interface IProps {
title: ITag['title']; title: ITag['title'];

View file

@ -1,7 +1,7 @@
import React, {FC, HTMLAttributes} from 'react'; import React, { FC, HTMLAttributes } from 'react';
import {TagField} from "~/components/containers/TagField"; import { TagField } from '~/components/containers/TagField';
import {ITag} from "~/redux/types"; import { ITag } from '~/redux/types';
import {Tag} from "~/components/node/Tag"; import { Tag } from '~/components/node/Tag';
type IProps = HTMLAttributes<HTMLDivElement> & { type IProps = HTMLAttributes<HTMLDivElement> & {
tags: ITag[]; tags: ITag[];

View file

@ -1,7 +1,7 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { Placeholder } from "~/components/placeholders/Placeholder"; import { Placeholder } from '~/components/placeholders/Placeholder';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import {Group} from "~/components/containers/Group"; import { Group } from '~/components/containers/Group';
const ParagraphPlaceholder = ({ }) => ( const ParagraphPlaceholder = ({ }) => (
<Group> <Group>

View file

@ -1,6 +1,6 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import * as styles from './styles.scss';
import classNames from 'classnames'; import classNames from 'classnames';
import * as styles from './styles.scss';
import { ArcProgress } from '~/components/input/ArcProgress'; import { ArcProgress } from '~/components/input/ArcProgress';
interface IProps { interface IProps {
@ -9,22 +9,20 @@ interface IProps {
progress?: number; progress?: number;
is_uploading?: boolean; is_uploading?: boolean;
}; }
const ImageUpload: FC<IProps> = ({ const ImageUpload: FC<IProps> = ({
thumb, thumb,
id, id,
progress, progress,
is_uploading, is_uploading,
}) => { }) => (
return ( <div className={styles.wrap}>
<div className={styles.wrap}> <div className={classNames(styles.thumb_wrap, { is_uploading })}>
<div className={classNames(styles.thumb_wrap, { is_uploading })}> {thumb && <div className={styles.thumb} style={{ background: `url("${thumb}")` }}>{id}</div>}
{thumb && <div className={styles.thumb} style={{ background: `url("${thumb}")` }}>{id}</div>} {is_uploading && <div className={styles.progress}><ArcProgress size={72} progress={progress} /></div>}
{is_uploading && <div className={styles.progress}><ArcProgress size={72} progress={progress} /></div>}
</div>
</div> </div>
); </div>
} );
export { ImageUpload }; export { ImageUpload };

View file

@ -1,20 +1,22 @@
import * as React from "react"; import * as React from 'react';
import { connect } from "react-redux"; import { connect } from 'react-redux';
import { bindActionCreators } from "redux"; import { bindActionCreators } from 'redux';
import { hot } from "react-hot-loader"; import { hot } from 'react-hot-loader';
import { ConnectedRouter } from "connected-react-router"; import { ConnectedRouter } from 'connected-react-router';
import { history } from "~/redux/store"; import {
import { NavLink, Switch, Route, Redirect } from "react-router-dom"; NavLink, Switch, Route, Redirect
import { FlowLayout } from "~/containers/flow/FlowLayout"; } from 'react-router-dom';
import { MainLayout } from "~/containers/main/MainLayout"; import { history } from '~/redux/store';
import { ImageExample } from "~/containers/examples/ImageExample"; import { FlowLayout } from '~/containers/flow/FlowLayout';
import { EditorExample } from "~/containers/examples/EditorExample"; import { MainLayout } from '~/containers/main/MainLayout';
import { HorizontalExample } from "~/containers/examples/HorizontalExample"; import { ImageExample } from '~/containers/examples/ImageExample';
import { Sprites } from "~/sprites/Sprites"; import { EditorExample } from '~/containers/examples/EditorExample';
import { URLS } from "~/constants/urls"; import { HorizontalExample } from '~/containers/examples/HorizontalExample';
import { Modal } from "~/containers/dialogs/Modal"; import { Sprites } from '~/sprites/Sprites';
import { selectModal } from "~/redux/modal/selectors"; import { URLS } from '~/constants/urls';
import { BlurWrapper } from "~/components/containers/BlurWrapper"; import { Modal } from '~/containers/dialogs/Modal';
import { selectModal } from '~/redux/modal/selectors';
import { BlurWrapper } from '~/components/containers/BlurWrapper';
const mapStateToProps = selectModal; const mapStateToProps = selectModal;
const mapDispatchToProps = {}; const mapDispatchToProps = {};

View file

@ -1,4 +1,10 @@
import React, { FC, useState, useCallback, useEffect } from 'react'; import React, {
FC, useState, useCallback, useEffect
} from 'react';
import { connect } from 'react-redux';
import assocPath from 'ramda/es/assocPath';
import append from 'ramda/es/append';
import uuid from 'uuid4';
import { ScrollDialog } from '../ScrollDialog'; import { ScrollDialog } from '../ScrollDialog';
import { IDialogProps } from '~/redux/modal/constants'; import { IDialogProps } from '~/redux/modal/constants';
import { useCloseOnEscape } from '~/utils/hooks'; import { useCloseOnEscape } from '~/utils/hooks';
@ -7,19 +13,15 @@ import { InputText } from '~/components/input/InputText';
import { Button } from '~/components/input/Button'; import { Button } from '~/components/input/Button';
import { Padder } from '~/components/containers/Padder'; import { Padder } from '~/components/containers/Padder';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { connect } from 'react-redux';
import { selectNode } from '~/redux/node/selectors'; import { selectNode } from '~/redux/node/selectors';
import { ImageEditor } from '~/components/editors/ImageEditor'; import { ImageEditor } from '~/components/editors/ImageEditor';
import { EditorPanel } from '~/components/editors/EditorPanel'; import { EditorPanel } from '~/components/editors/EditorPanel';
import assocPath from 'ramda/es/assocPath';
import append from 'ramda/es/append';
import { moveArrItem } from '~/utils/fn'; import { moveArrItem } from '~/utils/fn';
import { IFile, IFileWithUUID } from '~/redux/types'; import { IFile, IFileWithUUID } from '~/redux/types';
import uuid from 'uuid4';
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';
const mapStateToProps = state => { const mapStateToProps = (state) => {
const { editor } = selectNode(state); const { editor } = selectNode(state);
const { statuses, files } = selectUploads(state); const { statuses, files } = selectUploads(state);
@ -32,7 +34,9 @@ const mapDispatchToProps = {
type IProps = IDialogProps & ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {}; type IProps = IDialogProps & ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const EditorDialogUnconnected: FC<IProps> = ({ onRequestClose, editor, uploadUploadFiles, files, statuses }) => { const EditorDialogUnconnected: FC<IProps> = ({
onRequestClose, editor, uploadUploadFiles, files, statuses
}) => {
const [data, setData] = useState(editor); const [data, setData] = useState(editor);
const eventPreventer = useCallback(event => event.preventDefault(), []); const eventPreventer = useCallback(event => event.preventDefault(), []);
const [temp, setTemp] = useState([]); const [temp, setTemp] = useState([]);
@ -68,7 +72,7 @@ const EditorDialogUnconnected: FC<IProps> = ({ onRequestClose, editor, uploadUpl
); );
const onInputChange = useCallback( const onInputChange = useCallback(
event => { (event) => {
event.preventDefault(); event.preventDefault();
if (!event.target.files || !event.target.files.length) return; if (!event.target.files || !event.target.files.length) return;
@ -109,10 +113,10 @@ const EditorDialogUnconnected: FC<IProps> = ({ onRequestClose, editor, uploadUpl
setTemp(temp.filter(el => el !== id)); setTemp(temp.filter(el => el !== id));
} }
}); });
}, [statuses, files]); }, [statuses, files, temp, onFileAdd]);
const setTitle = useCallback( const setTitle = useCallback(
title => { (title) => {
setData({ ...data, title }); setData({ ...data, title });
}, },
[setData, data] [setData, data]

View file

@ -1,4 +1,7 @@
import React, { FC, FormEvent, useCallback, useEffect, useState } from 'react'; import React, {
FC, FormEvent, useCallback, useEffect, useState
} from 'react';
import { connect } from 'react-redux';
import { ScrollDialog } from '../ScrollDialog'; import { ScrollDialog } from '../ScrollDialog';
import { IDialogProps } from '~/redux/modal/constants'; import { IDialogProps } from '~/redux/modal/constants';
import { useCloseOnEscape } from '~/utils/hooks'; import { useCloseOnEscape } from '~/utils/hooks';
@ -7,9 +10,8 @@ import { InputText } from '~/components/input/InputText';
import { Button } from '~/components/input/Button'; import { Button } from '~/components/input/Button';
import { Padder } from '~/components/containers/Padder'; import { Padder } from '~/components/containers/Padder';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { selectAuthLogin } from "~/redux/auth/selectors"; import { selectAuthLogin } from '~/redux/auth/selectors';
import * as ACTIONS from '~/redux/auth/actions'; import * as ACTIONS from '~/redux/auth/actions';
import { connect } from "react-redux";
const mapStateToProps = selectAuthLogin; const mapStateToProps = selectAuthLogin;
@ -20,7 +22,9 @@ const mapDispatchToProps = {
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & IDialogProps & {}; type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & IDialogProps & {};
const LoginDialogUnconnected: FC<IProps> = ({ onRequestClose, error, userSendLoginRequest, userSetLoginError }) => { const LoginDialogUnconnected: FC<IProps> = ({
onRequestClose, error, userSendLoginRequest, userSetLoginError
}) => {
const [username, setUserName] = useState(''); const [username, setUserName] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
@ -31,7 +35,7 @@ const LoginDialogUnconnected: FC<IProps> = ({ onRequestClose, error, userSendLog
useEffect(() => { useEffect(() => {
if (error) userSetLoginError(null); if (error) userSetLoginError(null);
}, [username, password]); }, [username, password, error, userSetLoginError]);
const buttons = ( const buttons = (
<Padder> <Padder>

View file

@ -1,10 +1,10 @@
import React, { Attributes, FC, useCallback } from 'react'; import React, { Attributes, FC, useCallback } from 'react';
import { connect } from 'react-redux';
import ReactDOM from 'react-dom';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { IState } from '~/redux/store'; import { IState } from '~/redux/store';
import * as ACTIONS from '~/redux/modal/actions'; import * as ACTIONS from '~/redux/modal/actions';
import { connect } from 'react-redux';
import { DIALOG_CONTENT, IDialogProps } from '~/redux/modal/constants'; import { DIALOG_CONTENT, IDialogProps } from '~/redux/modal/constants';
import ReactDOM from 'react-dom';
const mapStateToProps = ({ modal }: IState) => ({ ...modal }); const mapStateToProps = ({ modal }: IState) => ({ ...modal });
const mapDispatchToProps = { const mapDispatchToProps = {

View file

@ -1,4 +1,6 @@
import React, { FC, MouseEventHandler, ReactChild, useCallback, useEffect, useState } from 'react'; import React, {
FC, MouseEventHandler, ReactChild, useCallback, useEffect, useState
} from 'react';
// import { DialogPanel } from '~/components/panels/DialogPanel'; // import { DialogPanel } from '~/components/panels/DialogPanel';
import classNames from 'classnames'; import classNames from 'classnames';
import { Scroll } from '~/components/containers/Scroll'; import { Scroll } from '~/components/containers/Scroll';
@ -41,7 +43,7 @@ const ScrollDialog: FC<IProps> = ({
useEffect(() => { useEffect(() => {
window.addEventListener('resize', onResize); window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize); return () => window.removeEventListener('resize', onResize);
}, []); }, [onResize]);
const onScroll = useCallback( const onScroll = useCallback(
({ target: { scrollTop = 0 } = {} } = {}) => { ({ target: { scrollTop = 0 } = {} } = {}) => {
@ -54,7 +56,7 @@ const ScrollDialog: FC<IProps> = ({
[top_sticky, top_sticky_offset, show_top_sticky, setShowTopSticky] [top_sticky, top_sticky_offset, show_top_sticky, setShowTopSticky]
); );
useEffect(() => onScroll(), []); useEffect(() => onScroll(), [onScroll]);
useEffect(() => { useEffect(() => {
if (ref && onRefCapture) onRefCapture(ref); if (ref && onRefCapture) onRefCapture(ref);
}, [ref, onRefCapture]); }, [ref, onRefCapture]);

View file

@ -1,17 +1,17 @@
import React, { FC } from "react"; import React, { FC } from 'react';
import { Card } from "~/components/containers/Card"; import classNames from 'classnames';
import * as styles from "./styles.scss"; import { Card } from '~/components/containers/Card';
import { Group } from "~/components/containers/Group"; import * as styles from './styles.scss';
import { CellGrid } from "~/components/containers/CellGrid"; import { Group } from '~/components/containers/Group';
import { Panel } from "~/components/containers/Panel"; import { CellGrid } from '~/components/containers/CellGrid';
import classNames from "classnames"; import { Panel } from '~/components/containers/Panel';
import { Scroll } from "~/components/containers/Scroll"; import { Scroll } from '~/components/containers/Scroll';
import { Tags } from "~/components/node/Tags"; import { Tags } from '~/components/node/Tags';
import { Button } from "~/components/input/Button"; import { Button } from '~/components/input/Button';
import { Filler } from "~/components/containers/Filler"; import { Filler } from '~/components/containers/Filler';
import { InputText } from "~/components/input/InputText"; import { InputText } from '~/components/input/InputText';
import { Icon } from "~/components/input/Icon"; import { Icon } from '~/components/input/Icon';
import { Grid } from "~/components/containers/Grid"; import { Grid } from '~/components/containers/Grid';
interface IProps {} interface IProps {}
@ -48,11 +48,11 @@ const EditorExample: FC<IProps> = () => (
<Tags <Tags
tags={[ tags={[
{ title: "Избранный", feature: "red" }, { title: 'Избранный', feature: 'red' },
{ title: "Плейлист", feature: "green" }, { title: 'Плейлист', feature: 'green' },
{ title: "Просто" }, { title: 'Просто' },
{ title: "+ фото", feature: "black" }, { title: '+ фото', feature: 'black' },
{ title: "+ с музыкой", feature: "black" } { title: '+ с музыкой', feature: 'black' }
]} ]}
/> />
</Group> </Group>

View file

@ -1,16 +1,16 @@
import React, { FC } from "react"; import React, { FC } from 'react';
import { Card } from "~/components/containers/Card"; import range from 'ramda/es/range';
import * as styles from "./styles.scss"; import { Card } from '~/components/containers/Card';
import { Group } from "~/components/containers/Group"; import * as styles from './styles.scss';
import { Padder } from "~/components/containers/Padder"; import { Group } from '~/components/containers/Group';
import range from "ramda/es/range"; import { Padder } from '~/components/containers/Padder';
import { Comment } from "~/components/node/Comment"; import { Comment } from '~/components/node/Comment';
import { NodePanel } from "~/components/node/NodePanel"; import { NodePanel } from '~/components/node/NodePanel';
import { NodeRelated } from "~/components/node/NodeRelated"; import { NodeRelated } from '~/components/node/NodeRelated';
import { Tags } from "~/components/node/Tags"; import { Tags } from '~/components/node/Tags';
import { MenuButton } from "~/components/node/MenuButton"; import { MenuButton } from '~/components/node/MenuButton';
import { NodeNoComments } from "~/components/node/NodeNoComments"; import { NodeNoComments } from '~/components/node/NodeNoComments';
import { InputText } from "~/components/input/InputText"; import { InputText } from '~/components/input/InputText';
interface IProps {} interface IProps {}
@ -55,11 +55,11 @@ const ImageExample: FC<IProps> = () => (
<Tags <Tags
tags={[ tags={[
{ title: "Избранный", feature: "red" }, { title: 'Избранный', feature: 'red' },
{ title: "Плейлист", feature: "green" }, { title: 'Плейлист', feature: 'green' },
{ title: "Просто" }, { title: 'Просто' },
{ title: "+ фото", feature: "black" }, { title: '+ фото', feature: 'black' },
{ title: "+ с музыкой", feature: "black" } { title: '+ с музыкой', feature: 'black' }
]} ]}
/> />

View file

@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { TestGrid } from "~/components/flow/TestGrid"; import { TestGrid } from '~/components/flow/TestGrid';
export const FlowLayout = () => ( export const FlowLayout = () => (
<div className="default_container content_container"> <div className="default_container content_container">

View file

@ -1,17 +1,14 @@
import * as React from 'react'; import * as React from 'react';
import { SidePane } from "~/components/main/SidePane"; import { SidePane } from '~/components/main/SidePane';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { Header } from "~/components/main/Header"; import { Header } from '~/components/main/Header';
export const MainLayout = ({ children }) => { export const MainLayout = ({ children }) => (
<div className={styles.wrapper}>
<Header />
return ( <div className={styles.content}>
<div className={styles.wrapper}> {children}
<Header />
<div className={styles.content}>
{children}
</div>
</div> </div>
); </div>
}; );

View file

@ -4,7 +4,7 @@ import * as styles from './styles.scss';
interface IProps {} interface IProps {}
const NodeLayout: FC<IProps> = () => ( const NodeLayout: FC<IProps> = () => (
<div></div> <div />
); );
export { NodeLayout }; export { NodeLayout };

View file

@ -1,10 +1,10 @@
import { AUTH_USER_ACTIONS } from "~/redux/auth/constants"; import { AUTH_USER_ACTIONS } from '~/redux/auth/constants';
import {IAuthState, IUser} from "~/redux/auth/types"; import { IAuthState, IUser } from '~/redux/auth/types';
export const userSendLoginRequest = ({ export const userSendLoginRequest = ({
username, password username, password
}: { }: {
username: string, password: string username: string; password: string;
}) => ({ type: AUTH_USER_ACTIONS.SEND_LOGIN_REQUEST, username, password }); }) => ({ type: AUTH_USER_ACTIONS.SEND_LOGIN_REQUEST, username, password });
export const userSetLoginError = (error: IAuthState['login']['error']) => ({ export const userSetLoginError = (error: IAuthState['login']['error']) => ({

View file

@ -15,9 +15,8 @@ export const apiUserLogin = ({
}: { }: {
username: string; username: string;
password: string; password: string;
}): Promise<IResultWithStatus<{ token: string; status?: number }>> => }): Promise<IResultWithStatus<{ token: string; status?: number }>> => api
api .post(API.USER.LOGIN, { username, password })
.post(API.USER.LOGIN, { username, password }) .then(resultMiddleware)
.then(resultMiddleware) .catch(errorMiddleware)
.catch(errorMiddleware) .then(userLoginTransform);
.then(userLoginTransform);

View file

@ -1,4 +1,4 @@
import {IToken, IUser} from "~/redux/auth/types"; import { IToken, IUser } from '~/redux/auth/types';
export const AUTH_USER_ACTIONS = { export const AUTH_USER_ACTIONS = {
SEND_LOGIN_REQUEST: 'SEND_LOGIN_REQUEST', SEND_LOGIN_REQUEST: 'SEND_LOGIN_REQUEST',
@ -39,11 +39,11 @@ export const EMPTY_USER: IUser = {
}; };
export interface IApiUser { export interface IApiUser {
id: number, id: number;
username: string, username: string;
email: string, email: string;
role: string, role: string;
activated: boolean, activated: boolean;
createdAt: string, createdAt: string;
updatedAt: string, updatedAt: string;
} }

View file

@ -1,6 +1,6 @@
import {AUTH_USER_ACTIONS} from "~/redux/auth/constants"; import { AUTH_USER_ACTIONS } from '~/redux/auth/constants';
import * as ActionCreators from "~/redux/auth/actions"; import * as ActionCreators from '~/redux/auth/actions';
import {IAuthState} from "~/redux/auth/types"; import { IAuthState } from '~/redux/auth/types';
interface ActionHandler<T> { interface ActionHandler<T> {
(state: IAuthState, payload: T extends (...args: any[]) => infer R ? R : any): IAuthState; (state: IAuthState, payload: T extends (...args: any[]) => infer R ? R : any): IAuthState;

View file

@ -1,7 +1,7 @@
import { EMPTY_USER } from "~/redux/auth/constants"; import { EMPTY_USER } from '~/redux/auth/constants';
import { createReducer } from "~/utils/reducer"; import { createReducer } from '~/utils/reducer';
import { IAuthState } from "~/redux/auth/types"; import { IAuthState } from '~/redux/auth/types';
import { AUTH_USER_HANDLERS } from "~/redux/auth/handlers"; import { AUTH_USER_HANDLERS } from '~/redux/auth/handlers';
const HANDLERS = { const HANDLERS = {
...AUTH_USER_HANDLERS, ...AUTH_USER_HANDLERS,

View file

@ -1,12 +1,14 @@
import { call, put, takeLatest, select } from 'redux-saga/effects'; import {
call, put, takeLatest, select
} from 'redux-saga/effects';
import { SagaIterator } from 'redux-saga'; import { SagaIterator } from 'redux-saga';
import { AUTH_USER_ACTIONS } from "~/redux/auth/constants";
import * as ActionCreators from '~/redux/auth/actions';
import { authSetToken, userSetLoginError, authSetUser } from "~/redux/auth/actions";
import { apiUserLogin } from "~/redux/auth/api";
import { modalSetShown, modalShowDialog } from "~/redux/modal/actions";
import { selectToken } from './selectors';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
import { AUTH_USER_ACTIONS } from '~/redux/auth/constants';
import * as ActionCreators from '~/redux/auth/actions';
import { authSetToken, userSetLoginError, authSetUser } from '~/redux/auth/actions';
import { apiUserLogin } from '~/redux/auth/api';
import { modalSetShown, modalShowDialog } from '~/redux/modal/actions';
import { selectToken } from './selectors';
import { URLS } from '~/constants/urls'; import { URLS } from '~/constants/urls';
import { DIALOGS } from '../modal/constants'; import { DIALOGS } from '../modal/constants';
import { IResultWithStatus } from '../types'; import { IResultWithStatus } from '../types';
@ -30,7 +32,7 @@ export function* reqWrapper(requestAction, props = {}): ReturnType<typeof reques
function* sendLoginRequestSaga({ username, password }: ReturnType<typeof ActionCreators.userSendLoginRequest>): SagaIterator { function* sendLoginRequestSaga({ username, password }: ReturnType<typeof ActionCreators.userSendLoginRequest>): SagaIterator {
if (!username || !password) return; if (!username || !password) return;
const { error, data: { token, user } }: IResultWithStatus<{ token: string, user: IUser }> = yield call(apiUserLogin, { username, password }); const { error, data: { token, user } }: IResultWithStatus<{ token: string; user: IUser }> = yield call(apiUserLogin, { username, password });
console.log({ token, error }); console.log({ token, error });

View file

@ -1,4 +1,4 @@
import { IState } from "~/redux/store"; import { IState } from '~/redux/store';
export const selectUser = (state: IState): IState['auth']['user'] => state.auth.user; export const selectUser = (state: IState): IState['auth']['user'] => state.auth.user;
export const selectToken = (state: IState): IState['auth']['token'] => state.auth.token; export const selectToken = (state: IState): IState['auth']['token'] => state.auth.token;

View file

@ -1,5 +1,5 @@
import { IResultWithStatus } from "~/redux/types"; import { IResultWithStatus } from '~/redux/types';
import { HTTP_RESPONSES } from "~/utils/api"; import { HTTP_RESPONSES } from '~/utils/api';
export const userLoginTransform = ({ status, data, error }: IResultWithStatus<any>): IResultWithStatus<any> => { export const userLoginTransform = ({ status, data, error }: IResultWithStatus<any>): IResultWithStatus<any> => {
switch (true) { switch (true) {

View file

@ -1,3 +1,3 @@
import { IState } from "~/redux/store"; import { IState } from '~/redux/store';
export const selectModal = (state: IState) => state.modal; export const selectModal = (state: IState) => state.modal;

View file

@ -1,4 +1,4 @@
import {IBlock, INode} from "../types"; import { IBlock, INode } from '../types';
export const EMPTY_BLOCK: IBlock = { export const EMPTY_BLOCK: IBlock = {
type: null, type: null,
@ -25,4 +25,4 @@ export const EMPTY_NODE: INode = {
show_description: false, show_description: false,
} }
}, },
} };

View file

@ -1,9 +1,9 @@
import { createReducer } from "~/utils/reducer";
import { INode } from "../types";
import { EMPTY_BLOCK, EMPTY_NODE } from "./constants";
import { NODE_HANDLERS } from "./handlers";
import { EMPTY_FILE } from "../uploads/constants";
import uuid from 'uuid4'; import uuid from 'uuid4';
import { createReducer } from '~/utils/reducer';
import { INode } from '../types';
import { EMPTY_BLOCK, EMPTY_NODE } from './constants';
import { NODE_HANDLERS } from './handlers';
import { EMPTY_FILE } from '../uploads/constants';
export type INodeState = Readonly<{ export type INodeState = Readonly<{
is_loading: boolean; is_loading: boolean;

View file

@ -1,4 +1,4 @@
import { IState } from "../store"; import { IState } from '../store';
import { INodeState } from "./reducer"; import { INodeState } from './reducer';
export const selectNode = (state: IState): INodeState => state.node; export const selectNode = (state: IState): INodeState => state.node;

View file

@ -1,28 +1,30 @@
import { createStore, applyMiddleware, combineReducers, compose, Store } from "redux"; import {
createStore, applyMiddleware, combineReducers, compose, Store
} from 'redux';
import { persistStore, persistReducer } from "redux-persist"; import { persistStore, persistReducer } from 'redux-persist';
import storage from "redux-persist/lib/storage"; import storage from 'redux-persist/lib/storage';
import createSagaMiddleware from "redux-saga"; import createSagaMiddleware from 'redux-saga';
import { connectRouter, RouterState, routerMiddleware } from "connected-react-router"; import { connectRouter, RouterState, routerMiddleware } from 'connected-react-router';
import { createBrowserHistory } from "history"; import { createBrowserHistory } from 'history';
import { PersistConfig, Persistor } from "redux-persist/es/types"; import { PersistConfig, Persistor } from 'redux-persist/es/types';
import authReducer from "~/redux/auth/reducer"; import authReducer from '~/redux/auth/reducer';
import authSaga from "~/redux/auth/sagas"; import authSaga from '~/redux/auth/sagas';
import nodeReducer, { INodeState } from "~/redux/node/reducer"; import nodeReducer, { INodeState } from '~/redux/node/reducer';
import nodeSaga from "~/redux/node/sagas"; import nodeSaga from '~/redux/node/sagas';
import uploadReducer, { IUploadState } from "~/redux/uploads/reducer"; import uploadReducer, { IUploadState } from '~/redux/uploads/reducer';
import uploadSaga from "~/redux/uploads/sagas"; import uploadSaga from '~/redux/uploads/sagas';
import { IAuthState } from "~/redux/auth/types"; import { IAuthState } from '~/redux/auth/types';
import modalReducer, { IModalState } from "~/redux/modal/reducer"; import modalReducer, { IModalState } from '~/redux/modal/reducer';
const authPersistConfig: PersistConfig = { const authPersistConfig: PersistConfig = {
key: "auth", key: 'auth',
whitelist: ["token", "user"], whitelist: ['token', 'user'],
storage storage
}; };
@ -37,10 +39,9 @@ export interface IState {
export const sagaMiddleware = createSagaMiddleware(); export const sagaMiddleware = createSagaMiddleware();
export const history = createBrowserHistory(); export const history = createBrowserHistory();
const composeEnhancers = const composeEnhancers = typeof window === 'object' && (<any>window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
typeof window === "object" && (<any>window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? (<any>window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
? (<any>window).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
: compose;
export const store = createStore( export const store = createStore(
combineReducers<IState>({ combineReducers<IState>({

View file

@ -7,8 +7,8 @@ export interface ITag {
} }
export type IInputTextProps = DetailedHTMLProps< export type IInputTextProps = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>, InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement HTMLInputElement
> & { > & {
wrapperClassName?: string; wrapperClassName?: string;
handler?: (value: string) => void; handler?: (value: string) => void;
@ -72,7 +72,7 @@ export interface IFileWithUUID {
} }
export interface IBlock { export interface IBlock {
type: 'image' | 'text' | 'media' | 'youtube' | 'video', type: 'image' | 'text' | 'media' | 'youtube' | 'video';
temp_ids: UUID[]; temp_ids: UUID[];
attaches: UUID[]; attaches: UUID[];
} }
@ -100,7 +100,7 @@ export interface INode {
flow: { flow: {
display: 'single' | 'double' | 'quadro'; display: 'single' | 'double' | 'quadro';
show_description: boolean; show_description: boolean;
} };
}; };
createdAt?: string; createdAt?: string;

View file

@ -1,30 +1,30 @@
import { UPLOAD_ACTIONS } from "~/redux/uploads/constants"; import { UPLOAD_ACTIONS } from '~/redux/uploads/constants';
import { IFileWithUUID, UUID, IFile } from "../types"; import { IFileWithUUID, UUID, IFile } from '../types';
import { IUploadStatus } from "./reducer"; import { IUploadStatus } from './reducer';
export const uploadUploadFiles = (files: IFileWithUUID[]) => ({ export const uploadUploadFiles = (files: IFileWithUUID[]) => ({
files, files,
type: UPLOAD_ACTIONS.UPLOAD_FILES, type: UPLOAD_ACTIONS.UPLOAD_FILES
}); });
export const uploadAddStatus = (temp_id: UUID, status?: Partial<IUploadStatus>) => ({ export const uploadAddStatus = (temp_id: UUID, status?: Partial<IUploadStatus>) => ({
temp_id, temp_id,
status, status,
type: UPLOAD_ACTIONS.ADD_STATUS, type: UPLOAD_ACTIONS.ADD_STATUS
}); });
export const uploadAddFile = (file: IFile) => ({ export const uploadAddFile = (file: IFile) => ({
file, file,
type: UPLOAD_ACTIONS.ADD_FILE, type: UPLOAD_ACTIONS.ADD_FILE
}); });
export const uploadSetStatus = (temp_id: UUID, status?: Partial<IUploadStatus>) => ({ export const uploadSetStatus = (temp_id: UUID, status?: Partial<IUploadStatus>) => ({
temp_id, temp_id,
status, status,
type: UPLOAD_ACTIONS.SET_STATUS, type: UPLOAD_ACTIONS.SET_STATUS
}); });
export const uploadDropStatus = (temp_id: UUID) => ({ export const uploadDropStatus = (temp_id: UUID) => ({
temp_id, temp_id,
type: UPLOAD_ACTIONS.DROP_STATUS, type: UPLOAD_ACTIONS.DROP_STATUS
}); });

View file

@ -1,5 +1,5 @@
import { IFile } from "~/redux/types"; import { IFile } from '~/redux/types';
import { IUploadState, IUploadStatus } from "./reducer"; import { IUploadState, IUploadStatus } from './reducer';
const prefix = 'UPLOAD.'; const prefix = 'UPLOAD.';
@ -38,4 +38,4 @@ export const EMPTY_UPLOAD_STATUS: IUploadStatus = {
thumbnail_url: null, thumbnail_url: null,
type: null, type: null,
temp_id: null, temp_id: null,
} };

View file

@ -2,7 +2,9 @@ import assocPath from 'ramda/es/assocPath';
import omit from 'ramda/es/omit'; import omit from 'ramda/es/omit';
import { UPLOAD_ACTIONS, EMPTY_UPLOAD_STATUS } from './constants'; import { UPLOAD_ACTIONS, EMPTY_UPLOAD_STATUS } from './constants';
import { uploadAddStatus, uploadDropStatus, uploadSetStatus, uploadAddFile } from './actions'; import {
uploadAddStatus, uploadDropStatus, uploadSetStatus, uploadAddFile
} from './actions';
import { IUploadState } from './reducer'; import { IUploadState } from './reducer';
const addStatus = ( const addStatus = (
@ -17,33 +19,25 @@ const addStatus = (
const dropStatus = ( const dropStatus = (
state: IUploadState, state: IUploadState,
{ temp_id }: ReturnType<typeof uploadDropStatus> { temp_id }: ReturnType<typeof uploadDropStatus>
): IUploadState => assocPath( ): IUploadState => assocPath(['statuses'], omit([temp_id], state.statuses), state);
['statuses'],
omit([temp_id], state.statuses),
state,
);
const setStatus = ( const setStatus = (
state: IUploadState, state: IUploadState,
{ temp_id, status }: ReturnType<typeof uploadSetStatus> { temp_id, status }: ReturnType<typeof uploadSetStatus>
): IUploadState => assocPath( ): IUploadState => assocPath(
['statuses'], ['statuses'],
{ ...state.statuses, [temp_id]: { ...(state.statuses[temp_id] || EMPTY_UPLOAD_STATUS), ...status } }, {
...state.statuses,
[temp_id]: { ...(state.statuses[temp_id] || EMPTY_UPLOAD_STATUS), ...status }
},
state state
); );
const addFile = ( const addFile = (state: IUploadState, { file }: ReturnType<typeof uploadAddFile>): IUploadState => assocPath(['files'], { ...state.files, [file.id]: file }, state);
state: IUploadState,
{ file }: ReturnType<typeof uploadAddFile>
): IUploadState => assocPath(
['files'],
{ ...state.files, [file.id]: file },
state
);
export const UPLOAD_HANDLERS = { export const UPLOAD_HANDLERS = {
[UPLOAD_ACTIONS.ADD_STATUS]: addStatus, [UPLOAD_ACTIONS.ADD_STATUS]: addStatus,
[UPLOAD_ACTIONS.DROP_STATUS]: dropStatus, [UPLOAD_ACTIONS.DROP_STATUS]: dropStatus,
[UPLOAD_ACTIONS.SET_STATUS]: setStatus, [UPLOAD_ACTIONS.SET_STATUS]: setStatus,
[UPLOAD_ACTIONS.ADD_FILE]: addFile, [UPLOAD_ACTIONS.ADD_FILE]: addFile
}; };

View file

@ -1,9 +1,9 @@
import { IResultWithStatus, IFile, UUID } from "../types";
import { HTTP_RESPONSES } from "~/utils/api";
import { EMPTY_FILE } from "./constants";
import uuid from 'uuid4'; import uuid from 'uuid4';
import { IResultWithStatus, IFile, UUID } from '../types';
import { HTTP_RESPONSES } from '~/utils/api';
import { EMPTY_FILE } from './constants';
export const uploadMock = ({ temp_id, file }: { temp_id: UUID, file: File }): Promise<IResultWithStatus<IFile>> => ( export const uploadMock = ({ temp_id, file }: { temp_id: UUID; file: File }): Promise<IResultWithStatus<IFile>> => (
Promise.resolve({ Promise.resolve({
status: HTTP_RESPONSES.CREATED, status: HTTP_RESPONSES.CREATED,
data: { data: {

View file

@ -1,6 +1,6 @@
import { createReducer } from "~/utils/reducer"; import { createReducer } from '~/utils/reducer';
import { IFile, UUID } from "~/redux/types"; import { IFile, UUID } from '~/redux/types';
import { UPLOAD_HANDLERS } from "./handlers"; import { UPLOAD_HANDLERS } from './handlers';
export interface IUploadStatus { export interface IUploadStatus {
is_uploading: boolean; is_uploading: boolean;

View file

@ -1,11 +1,15 @@
import { takeEvery, all, spawn, call, put, take, fork, race } from 'redux-saga/effects'; import {
takeEvery, all, spawn, call, put, take, fork, race
} from 'redux-saga/effects';
import { UPLOAD_ACTIONS } from '~/redux/uploads/constants'; import { UPLOAD_ACTIONS } from '~/redux/uploads/constants';
import { uploadUploadFiles, uploadSetStatus, uploadAddStatus, uploadDropStatus, uploadAddFile } from './actions'; import {
uploadUploadFiles, uploadSetStatus, uploadAddStatus, uploadDropStatus, uploadAddFile
} from './actions';
import { reqWrapper } from '../auth/sagas'; import { reqWrapper } from '../auth/sagas';
import { createUploader, uploadGetThumb, fakeUploader } from '~/utils/uploader'; import { createUploader, uploadGetThumb, fakeUploader } from '~/utils/uploader';
import { HTTP_RESPONSES } from '~/utils/api'; import { HTTP_RESPONSES } from '~/utils/api';
import { VALIDATORS } from '~/utils/validators'; import { VALIDATORS } from '~/utils/validators';
import { UUID, IFileWithUUID, IResultWithStatus, IFile } from '../types'; import { UUID, IFileWithUUID, IFile } from '../types';
function* uploadCall({ temp_id, onProgress, file }) { function* uploadCall({ temp_id, onProgress, file }) {
return yield call(reqWrapper, fakeUploader, { file: { url: 'some', error: 'cant do this boss' }, onProgress, mustSucceed: true }); return yield call(reqWrapper, fakeUploader, { file: { url: 'some', error: 'cant do this boss' }, onProgress, mustSucceed: true });

View file

@ -1,42 +1,43 @@
import React, {FC} from 'react'; import React, { FC } from 'react';
const Sprites: FC<{}> = () => ( const Sprites: FC<{}> = () => (
<svg width={0} height={0} viewBox="0 0 24 24"> <svg width={0} height={0} viewBox="0 0 24 24">
<g id="cell-single" stroke="none" transform="translate(2 2)"> <g id="cell-single" stroke="none" transform="translate(2 2)">
<path d="M0,0 L9,0 L9,9 L0,9 L0,0 Z"></path> <path d="M0,0 L9,0 L9,9 L0,9 L0,0 Z" />
<path d="M11,0 L20,0 L20,9 L11,9 L11,0 Z M12,1 L12,8 L19,8 L19,1 L12,1 Z"></path> <path d="M11,0 L20,0 L20,9 L11,9 L11,0 Z M12,1 L12,8 L19,8 L19,1 L12,1 Z" />
<path d="M11,11 L20,11 L20,20 L11,20 L11,11 Z M12,12 L12,19 L19,19 L19,12 L12,12 Z"></path> <path d="M11,11 L20,11 L20,20 L11,20 L11,11 Z M12,12 L12,19 L19,19 L19,12 L12,12 Z" />
<path d="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z"></path> <path d="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z" />
</g> </g>
<g id="cell-double-h" stroke="none"> <g id="cell-double-h" stroke="none">
<path d="M0,0 L20,0 L20,9 L0,9 L0,0 Z M1,1 L1,8 L19,8 L19,1 L1,1 Z"></path> <path d="M0,0 L20,0 L20,9 L0,9 L0,0 Z M1,1 L1,8 L19,8 L19,1 L1,1 Z" />
<path d="M11,11 L20,11 L20,20 L11,20 L11,11 Z M12,12 L12,19 L19,19 L19,12 L12,12 Z"/> <path d="M11,11 L20,11 L20,20 L11,20 L11,11 Z M12,12 L12,19 L19,19 L19,12 L12,12 Z" />
<path d="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z"></path> <path d="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z" />
</g> </g>
<g id="cell-double-v" stroke="none"> <g id="cell-double-v" stroke="none">
<path d="M0,0 L20,0 L20,9 L0,9 L0,0 Z M1,1 L1,8 L19,8 L19,1 L1,1 Z"></path> <path d="M0,0 L20,0 L20,9 L0,9 L0,0 Z M1,1 L1,8 L19,8 L19,1 L1,1 Z" />
<path d="M11,11 L20,11 L20,20 L11,20 L11,11 Z M12,12 L12,19 L19,19 L19,12 L12,12 Z"></path> <path d="M11,11 L20,11 L20,20 L11,20 L11,11 Z M12,12 L12,19 L19,19 L19,12 L12,12 Z" />
<path d="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z"></path> <path d="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z" />
</g> </g>
<g id="play"> <g id="play">
<path d="M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18c.62-.39.62-1.29 0-1.69L9.54 5.98C8.87 5.55 8 6.03 8 6.82z"/> <path d="M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18c.62-.39.62-1.29 0-1.69L9.54 5.98C8.87 5.55 8 6.03 8 6.82z" />
</g> </g>
<g id="plus" stroke="none"> <g id="plus" stroke="none">
<path fill="none" d="M0 0h24v24H0V0z"/> <path fill="none" d="M0 0h24v24H0V0z" />
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</g> </g>
<g id="close" stroke="none"> <g id="close" stroke="none">
<path fill="none" d="M0 0h24v24H0V0z"/> <path fill="none" d="M0 0h24v24H0V0z" />
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/> <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</g> </g>
<g id="check" stroke="none"> <g id="check" stroke="none">
<path fill="none" d="M0 0h24v24H0V0z"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/> <path fill="none" d="M0 0h24v24H0V0z" />
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" />
</g> </g>
</svg> </svg>
); );

View file

@ -1,10 +1,10 @@
import axios, { AxiosRequestConfig } from 'axios'; import axios, { AxiosRequestConfig } from 'axios';
import { push } from 'connected-react-router';
import { API } from '~/constants/api'; import { API } from '~/constants/api';
import { store } from '~/redux/store'; import { store } from '~/redux/store';
import { push } from 'connected-react-router';
import { IResultWithStatus } from '~/redux/types'; import { IResultWithStatus } from '~/redux/types';
export const authMiddleware = r => { export const authMiddleware = (r) => {
store.dispatch(push('/login')); store.dispatch(push('/login'));
return r; return r;
}; };
@ -23,18 +23,15 @@ export const HTTP_RESPONSES = {
TOO_MANY_REQUESTS: 429, TOO_MANY_REQUESTS: 429,
}; };
export const resultMiddleware = <T extends {}>({ export const resultMiddleware = (<)T extends {}>({
status, status,
data, data,
}: { }: {
status: number; status: number;
data: T; data: T;
}): { status: number; data: T } => { }): { status: number; data: T } => data && { status, data };
return data && { status, data };
};
export const errorMiddleware = <T extends any>(debug): IResultWithStatus<T> => export const errorMiddleware = <T extends any>(debug): IResultWithStatus<T> => debug && debug.response
debug && debug.response
? debug.response ? debug.response
: { : {
status: HTTP_RESPONSES.CONNECTION_REFUSED, status: HTTP_RESPONSES.CONNECTION_REFUSED,

View file

@ -26,7 +26,6 @@ export const describeArc = (
startAngle: number = 0, startAngle: number = 0,
endAngle: number = 360, endAngle: number = 360,
): string => { ): string => {
const start = polarToCartesian(x, y, radius, endAngle); const start = polarToCartesian(x, y, radius, endAngle);
const end = polarToCartesian(x, y, radius, startAngle); const end = polarToCartesian(x, y, radius, startAngle);

View file

@ -3,4 +3,4 @@ import insert from 'ramda/es/insert';
import nth from 'ramda/es/nth'; import nth from 'ramda/es/nth';
import remove from 'ramda/es/remove'; import remove from 'ramda/es/remove';
export const moveArrItem = curry((at, to, list) => insert(to, nth(at, list), remove(at, 1, list))) export const moveArrItem = curry((at, to, list) => insert(to, nth(at, list), remove(at, 1, list)));

View file

@ -1,17 +1,19 @@
import { useCallback, useEffect, useRef, useState } from 'react'; import {
useCallback, useEffect, useRef, useState
} from 'react';
export const useCloseOnEscape = (onRequestClose: () => void, ignore_inputs = false) => { export const useCloseOnEscape = (onRequestClose: () => void, ignore_inputs = false) => {
const onEscape = useCallback( const onEscape = useCallback(
event => { (event) => {
if (event.key !== 'Escape') return; if (event.key !== 'Escape') return;
if ( if (
ignore_inputs && ignore_inputs
(event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') && (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA')
) ) return;
return;
onRequestClose(); onRequestClose();
}, },
[onRequestClose], [ignore_inputs, onRequestClose],
); );
useEffect(() => { useEffect(() => {
@ -30,5 +32,5 @@ export const useDelayedReady = (setReady: (val: boolean) => void, delay: number
return () => { return () => {
if (timer) clearTimeout(timer); if (timer) clearTimeout(timer);
}; };
}, []); }, [delay, setReady]);
}; };

View file

@ -14,6 +14,6 @@ type Handlers<State, Types extends string, Actions extends Action<Types>> = {
export const createReducer = ( export const createReducer = (
initialState, initialState,
handlers, handlers,
) => (state = initialState, action) => handlers.hasOwnProperty(action.type) ) => (state = initialState, action) => (handlers.hasOwnProperty(action.type)
? handlers[action.type](state, action) ? handlers[action.type](state, action)
: state; : state);

View file

@ -13,7 +13,7 @@ export function createUploader<T extends {}, R extends {}>(
): [(args: T) => (args: T & { onProgress: (current: number, total: number) => void }) => any, EventChannel<any>] { ): [(args: T) => (args: T & { onProgress: (current: number, total: number) => void }) => any, EventChannel<any>] {
let emit; let emit;
const chan = eventChannel(emitter => { const chan = eventChannel((emitter) => {
emit = emitter; emit = emitter;
return () => null; return () => null;
}); });
@ -27,7 +27,7 @@ export function createUploader<T extends {}, R extends {}>(
return [wrappedCallback, chan]; return [wrappedCallback, chan];
} }
export const uploadGetThumb = async file => { export const uploadGetThumb = async (file) => {
if (!file.type || !VALIDATORS.IS_IMAGE_MIME(file.type)) return ''; if (!file.type || !VALIDATORS.IS_IMAGE_MIME(file.type)) return '';
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {