1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +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

View file

@ -1,26 +1,27 @@
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: '@typescript-eslint/parser',
parserOptions: {
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: {
'import/resolver': {
// node: {
// extensions: ['.js', '.jsx', '.ts', '.tsx'],
// },
typescript: {}
}
typescript: {},
},
},
rules: {
indent: ['error', 2],
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/indent': ['error', 2],
'@typescript-eslint/indent': ['warn', 2],
"indent": "off",
'comma-dangle': 0,
'no-restricted-syntax': 1,
'react/prop-types': 0,
@ -44,16 +45,16 @@ module.exports = {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'no-nested-ternary': 1,
'arrow-parens': 0,
'import/prefer-default-export': 0,
'no-return-await': 0,
'prefer-promise-reject-errors': 0,
'import/order': 0
'max-line-length': [true, 100],
// 'max-len': 100,
// 'max-len': { "code": 100 },
'max-len': ["warn", { "code": 100 }]
},
globals: {
document: false,
window: false,
HTMLInputElement: false,
HTMLDivElement: false
}
HTMLDivElement: false,
},
};

View file

@ -1,4 +1,4 @@
{
"printWidth": 120,
"printWidth": 100,
"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-stage-2": "^6.24.1",
"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",
"html-webpack-plugin": "^3.2.0",
"identity-obj-proxy": "^3.0.0",
@ -51,7 +39,6 @@
"style-loader": "^0.21.0",
"ts-node": "^8.0.1",
"typescript": "^3.2.4",
"typescript-eslint-parser": "^22.0.0",
"uglifyjs-webpack-plugin": "^1.3.0",
"webpack": "^4.6.0",
"webpack-cli": "^3.2.3",
@ -74,7 +61,19 @@
"date-fns": "^2.0.0-alpha.27",
"dotenv": "^8.0.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",
"http-errors": "~1.6.2",
"less": "^3.8.1",

View file

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

View file

@ -1,7 +1,8 @@
import React, { FC } from 'react';
import classNames = require("classnames");
import * as styles from './styles.scss';
import classNames = require('classnames');
type IProps = React.HTMLAttributes<HTMLDivElement> & {
seamless?: boolean;
}
@ -12,12 +13,12 @@ const Card: FC<IProps> = ({
seamless,
...props
}) => (
<div
className={classNames(styles.card, className, { seamless })}
{...props}
>
{children}
</div>
<div
className={classNames(styles.card, className, { seamless })}
{...props}
>
{children}
</div>
);
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 classNames = require("classnames");
import classNames = require('classnames');
type IProps = HTMLAttributes<HTMLDivElement> & {
children: any;
@ -13,13 +16,13 @@ const CellGrid: FC<IProps> = ({
className,
...props
}) => (
<div
className={classNames(styles.grid, className)}
style={{ gridTemplateColumns: `repeat(auto-fit, minmax(${size}px, 1fr))` }}
{...props}
>
{children}
</div>
<div
className={classNames(styles.grid, className)}
style={{ gridTemplateColumns: `repeat(auto-fit, minmax(${size}px, 1fr))` }}
{...props}
>
{children}
</div>
);
export { CellGrid };

View file

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

View file

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

View file

@ -1,8 +1,9 @@
import React, { FC } from 'react';
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;
vertical?: boolean;
horizontal?: boolean;
@ -17,13 +18,13 @@ const Padder: FC<IProps> = ({
horizontal,
...props
}) => (
<div
className={classNames(styles.padder, className, { vertical, horizontal })}
style={padding ? { ...style, padding } : style}
{...props}
>
{children}
</div>
<div
className={classNames(styles.padder, className, { vertical, horizontal })}
style={padding ? { ...style, padding } : style}
{...props}
>
{children}
</div>
);
export { Padder };

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import React, { FC, ChangeEventHandler } from 'react';
import * as styles from './styles.scss';
import { INode } from '~/redux/types';
import { ImageUploadButton } from '~/components/editors/ImageUploadButton';
import { EditorUploadButton } from '~/components/editors/EditorUploadButton';
interface IProps {
data: INode;
@ -11,7 +11,7 @@ interface IProps {
const EditorPanel: FC<IProps> = ({ onUpload }) => (
<div className={styles.panel}>
<ImageUploadButton onUpload={onUpload} />
<EditorUploadButton onUpload={onUpload} />
</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 { INode, IFileWithUUID, IFile } from '~/redux/types';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { connect } from 'react-redux';
import { selectUploads } from '~/redux/uploads/selectors';
import assocPath from 'ramda/es/assocPath';
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 { moveArrItem } from '~/utils/fn';
import { IUploadStatus } from '~/redux/uploads/reducer';
const mapStateToProps = selectUploads;
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;
pending_files: IUploadStatus[];
setData: (val: INode) => void;
onFileMove: (o: number, n: number) => void;
onInputChange: ChangeEventHandler<HTMLInputElement>;
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 };

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 * as styles from './styles.scss';
import { ImageUpload } from '~/components/upload/ImageUpload';
import { IFile } from '~/redux/types';
import { IUploadStatus } from '~/redux/uploads/reducer';
import { ImageUploadButton } from '~/components/editors/ImageUploadButton';
interface IProps {
items: IFile[];
@ -12,50 +13,52 @@ interface IProps {
onFileMove: (o: number, n: number) => void;
onUpload?: ChangeEventHandler<HTMLInputElement>;
onDrop: DragEventHandler<HTMLFormElement>;
};
}
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> }) => {
return (
const SortableList = SortableContainer(
({
items,
locked,
onDrop
}: {
items: IFile[];
locked: IUploadStatus[];
onUpload: ChangeEventHandler<HTMLInputElement>;
onDrop: DragEventHandler<HTMLFormElement>;
}) => (
<form className={styles.grid} onDrop={onDrop}>
{
items.map((file, index) => (
<SortableItem key={file.id} index={index} collection={0}>
<ImageUpload
id={file.id}
thumb={file.url}
/>
</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>
))
}
{items.map((file, index) => (
<SortableItem key={file.id} index={index} collection={0}>
<ImageUpload id={file.id} thumb={file.url} />
</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>
);
});
)
);
const ImageGrid: FC<IProps> = ({
items,
locked,
onFileMove,
onUpload,
onDrop,
items, locked, onFileMove, onUpload, onDrop
}) => {
const onMove = useCallback(({ oldIndex, newIndex }) => onFileMove(oldIndex, newIndex), [onFileMove]);
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 };

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import * as React from 'react';
interface IGodRaysProps {
raised?: boolean,
raised?: boolean;
}
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);
}
const { width, height, rays, particles } = this.state;
const {
width, height, rays, particles
} = this.state;
const ctx = this.canvas.getContext('2d');
ctx.globalCompositeOperation = "luminosity";
ctx.globalCompositeOperation = 'luminosity';
ctx.clearRect(0, 0, width, height + 100); // clear canvas
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);
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);
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.translate(width / 2, -900);
@ -106,7 +110,7 @@ export class GodRays extends React.Component<IGodRaysProps> {
this.init();
}
render(){
render() {
const { width, height } = this.state;
return (
@ -119,7 +123,8 @@ export class GodRays extends React.Component<IGodRaysProps> {
zIndex: -1,
opacity: 1,
pointerEvents: 'none',
}}>
}}
>
<canvas
width={width}
height={height + 100}
@ -128,12 +133,13 @@ export class GodRays extends React.Component<IGodRaysProps> {
position: 'relative',
top: -100,
}}
ref={el => { this.canvas = el; }}
ref={(el) => { this.canvas = el; }}
/>
</div>
);
}
canvas: HTMLCanvasElement;
inc;
};
}

View file

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

View file

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

View file

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

View file

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

View file

@ -1,21 +1,21 @@
import React, { FC } from 'react';
import * as styles from './styles.scss';
import { Group } from "~/components/containers/Group";
import { Filler } from "~/components/containers/Filler";
import { Group } from '~/components/containers/Group';
import { Filler } from '~/components/containers/Filler';
interface IProps {}
const NodePanel: FC<IProps> = () => (
<div className={styles.wrap}>
<Group horizontal className={styles.panel}>
<Filler>
<div className={styles.title}>Node title</div>
<div className={styles.name}>~author</div>
</Filler>
</Group>
<div className={styles.wrap}>
<Group horizontal className={styles.panel}>
<Filler>
<div className={styles.title}>Node title</div>
<div className={styles.name}>~author</div>
</Filler>
</Group>
<div className={styles.mark} />
</div>
<div className={styles.mark} />
</div>
);
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 * as styles from './styles.scss';
import {Group} from "~/components/containers/Group";
import { Group } from '~/components/containers/Group';
type IProps = HTMLAttributes<HTMLDivElement> & {}
@ -16,7 +16,7 @@ const NodeRelated: FC<IProps> = ({
</div>
<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>
</Group>

View file

@ -1,7 +1,8 @@
import React, { FC } from 'react';
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 {
title: ITag['title'];

View file

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

View file

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

View file

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

View file

@ -1,20 +1,22 @@
import * as React from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { hot } from "react-hot-loader";
import { ConnectedRouter } from "connected-react-router";
import { history } from "~/redux/store";
import { NavLink, Switch, Route, Redirect } from "react-router-dom";
import { FlowLayout } from "~/containers/flow/FlowLayout";
import { MainLayout } from "~/containers/main/MainLayout";
import { ImageExample } from "~/containers/examples/ImageExample";
import { EditorExample } from "~/containers/examples/EditorExample";
import { HorizontalExample } from "~/containers/examples/HorizontalExample";
import { Sprites } from "~/sprites/Sprites";
import { URLS } from "~/constants/urls";
import { Modal } from "~/containers/dialogs/Modal";
import { selectModal } from "~/redux/modal/selectors";
import { BlurWrapper } from "~/components/containers/BlurWrapper";
import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { hot } from 'react-hot-loader';
import { ConnectedRouter } from 'connected-react-router';
import {
NavLink, Switch, Route, Redirect
} from 'react-router-dom';
import { history } from '~/redux/store';
import { FlowLayout } from '~/containers/flow/FlowLayout';
import { MainLayout } from '~/containers/main/MainLayout';
import { ImageExample } from '~/containers/examples/ImageExample';
import { EditorExample } from '~/containers/examples/EditorExample';
import { HorizontalExample } from '~/containers/examples/HorizontalExample';
import { Sprites } from '~/sprites/Sprites';
import { URLS } from '~/constants/urls';
import { Modal } from '~/containers/dialogs/Modal';
import { selectModal } from '~/redux/modal/selectors';
import { BlurWrapper } from '~/components/containers/BlurWrapper';
const mapStateToProps = selectModal;
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 { IDialogProps } from '~/redux/modal/constants';
import { useCloseOnEscape } from '~/utils/hooks';
@ -7,19 +13,15 @@ import { InputText } from '~/components/input/InputText';
import { Button } from '~/components/input/Button';
import { Padder } from '~/components/containers/Padder';
import * as styles from './styles.scss';
import { connect } from 'react-redux';
import { selectNode } from '~/redux/node/selectors';
import { ImageEditor } from '~/components/editors/ImageEditor';
import { EditorPanel } from '~/components/editors/EditorPanel';
import assocPath from 'ramda/es/assocPath';
import append from 'ramda/es/append';
import { moveArrItem } from '~/utils/fn';
import { IFile, IFileWithUUID } from '~/redux/types';
import uuid from 'uuid4';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { selectUploads } from '~/redux/uploads/selectors';
const mapStateToProps = state => {
const mapStateToProps = (state) => {
const { editor } = selectNode(state);
const { statuses, files } = selectUploads(state);
@ -32,7 +34,9 @@ const 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 eventPreventer = useCallback(event => event.preventDefault(), []);
const [temp, setTemp] = useState([]);
@ -68,7 +72,7 @@ const EditorDialogUnconnected: FC<IProps> = ({ onRequestClose, editor, uploadUpl
);
const onInputChange = useCallback(
event => {
(event) => {
event.preventDefault();
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));
}
});
}, [statuses, files]);
}, [statuses, files, temp, onFileAdd]);
const setTitle = useCallback(
title => {
(title) => {
setData({ ...data, title });
},
[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 { IDialogProps } from '~/redux/modal/constants';
import { useCloseOnEscape } from '~/utils/hooks';
@ -7,9 +10,8 @@ import { InputText } from '~/components/input/InputText';
import { Button } from '~/components/input/Button';
import { Padder } from '~/components/containers/Padder';
import * as styles from './styles.scss';
import { selectAuthLogin } from "~/redux/auth/selectors";
import { selectAuthLogin } from '~/redux/auth/selectors';
import * as ACTIONS from '~/redux/auth/actions';
import { connect } from "react-redux";
const mapStateToProps = selectAuthLogin;
@ -20,7 +22,9 @@ const mapDispatchToProps = {
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 [password, setPassword] = useState('');
@ -31,7 +35,7 @@ const LoginDialogUnconnected: FC<IProps> = ({ onRequestClose, error, userSendLog
useEffect(() => {
if (error) userSetLoginError(null);
}, [username, password]);
}, [username, password, error, userSetLoginError]);
const buttons = (
<Padder>

View file

@ -1,10 +1,10 @@
import React, { Attributes, FC, useCallback } from 'react';
import { connect } from 'react-redux';
import ReactDOM from 'react-dom';
import * as styles from './styles.scss';
import { IState } from '~/redux/store';
import * as ACTIONS from '~/redux/modal/actions';
import { connect } from 'react-redux';
import { DIALOG_CONTENT, IDialogProps } from '~/redux/modal/constants';
import ReactDOM from 'react-dom';
const mapStateToProps = ({ modal }: IState) => ({ ...modal });
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 classNames from 'classnames';
import { Scroll } from '~/components/containers/Scroll';
@ -41,7 +43,7 @@ const ScrollDialog: FC<IProps> = ({
useEffect(() => {
window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize);
}, []);
}, [onResize]);
const onScroll = useCallback(
({ target: { scrollTop = 0 } = {} } = {}) => {
@ -54,7 +56,7 @@ const ScrollDialog: FC<IProps> = ({
[top_sticky, top_sticky_offset, show_top_sticky, setShowTopSticky]
);
useEffect(() => onScroll(), []);
useEffect(() => onScroll(), [onScroll]);
useEffect(() => {
if (ref && onRefCapture) onRefCapture(ref);
}, [ref, onRefCapture]);

View file

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

View file

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

View file

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

View file

@ -1,17 +1,14 @@
import * as React from 'react';
import { SidePane } from "~/components/main/SidePane";
import { SidePane } from '~/components/main/SidePane';
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.wrapper}>
<Header />
<div className={styles.content}>
{children}
</div>
<div className={styles.content}>
{children}
</div>
);
};
</div>
);

View file

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

View file

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

View file

@ -15,9 +15,8 @@ export const apiUserLogin = ({
}: {
username: string;
password: string;
}): Promise<IResultWithStatus<{ token: string; status?: number }>> =>
api
.post(API.USER.LOGIN, { username, password })
.then(resultMiddleware)
.catch(errorMiddleware)
.then(userLoginTransform);
}): Promise<IResultWithStatus<{ token: string; status?: number }>> => api
.post(API.USER.LOGIN, { username, password })
.then(resultMiddleware)
.catch(errorMiddleware)
.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 = {
SEND_LOGIN_REQUEST: 'SEND_LOGIN_REQUEST',
@ -39,11 +39,11 @@ export const EMPTY_USER: IUser = {
};
export interface IApiUser {
id: number,
username: string,
email: string,
role: string,
activated: boolean,
createdAt: string,
updatedAt: string,
id: number;
username: string;
email: string;
role: string;
activated: boolean;
createdAt: string;
updatedAt: string;
}

View file

@ -1,6 +1,6 @@
import {AUTH_USER_ACTIONS} from "~/redux/auth/constants";
import * as ActionCreators from "~/redux/auth/actions";
import {IAuthState} from "~/redux/auth/types";
import { AUTH_USER_ACTIONS } from '~/redux/auth/constants';
import * as ActionCreators from '~/redux/auth/actions';
import { IAuthState } from '~/redux/auth/types';
interface ActionHandler<T> {
(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 { createReducer } from "~/utils/reducer";
import { IAuthState } from "~/redux/auth/types";
import { AUTH_USER_HANDLERS } from "~/redux/auth/handlers";
import { EMPTY_USER } from '~/redux/auth/constants';
import { createReducer } from '~/utils/reducer';
import { IAuthState } from '~/redux/auth/types';
import { AUTH_USER_HANDLERS } from '~/redux/auth/handlers';
const 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 { 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 { 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 { DIALOGS } from '../modal/constants';
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 {
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 });

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 selectToken = (state: IState): IState['auth']['token'] => state.auth.token;

View file

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

View file

@ -1,4 +1,4 @@
import {IBlock, INode} from "../types";
import { IBlock, INode } from '../types';
export const EMPTY_BLOCK: IBlock = {
type: null,
@ -25,4 +25,4 @@ export const EMPTY_NODE: INode = {
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 { 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<{
is_loading: boolean;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
import { createReducer } from "~/utils/reducer";
import { IFile, UUID } from "~/redux/types";
import { UPLOAD_HANDLERS } from "./handlers";
import { createReducer } from '~/utils/reducer';
import { IFile, UUID } from '~/redux/types';
import { UPLOAD_HANDLERS } from './handlers';
export interface IUploadStatus {
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 { uploadUploadFiles, uploadSetStatus, uploadAddStatus, uploadDropStatus, uploadAddFile } from './actions';
import {
uploadUploadFiles, uploadSetStatus, uploadAddStatus, uploadDropStatus, uploadAddFile
} from './actions';
import { reqWrapper } from '../auth/sagas';
import { createUploader, uploadGetThumb, fakeUploader } from '~/utils/uploader';
import { HTTP_RESPONSES } from '~/utils/api';
import { VALIDATORS } from '~/utils/validators';
import { UUID, IFileWithUUID, IResultWithStatus, IFile } from '../types';
import { UUID, IFileWithUUID, IFile } from '../types';
function* uploadCall({ temp_id, onProgress, file }) {
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<{}> = () => (
<svg width={0} height={0} viewBox="0 0 24 24">
<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="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,11 L20,11 L20,20 L11,20 L11,11 Z M12,12 L12,19 L19,19 L19,12 L12,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"></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 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" />
</g>
<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="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,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="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z" />
</g>
<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="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="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,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="M0,11 L9,11 L9,20 L0,20 L0,11 Z M1,12 L1,19 L8,19 L8,12 L1,12 Z" />
</g>
<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 id="plus" stroke="none">
<path fill="none" d="M0 0h24v24H0V0z"/>
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
<path fill="none" d="M0 0h24v24H0V0z" />
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</g>
<g id="close" stroke="none">
<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 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" />
</g>
<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>
</svg>
);

View file

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

View file

@ -26,7 +26,6 @@ export const describeArc = (
startAngle: number = 0,
endAngle: number = 360,
): string => {
const start = polarToCartesian(x, y, radius, endAngle);
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 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) => {
const onEscape = useCallback(
event => {
(event) => {
if (event.key !== 'Escape') return;
if (
ignore_inputs &&
(event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA')
)
return;
ignore_inputs
&& (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA')
) return;
onRequestClose();
},
[onRequestClose],
[ignore_inputs, onRequestClose],
);
useEffect(() => {
@ -30,5 +32,5 @@ export const useDelayedReady = (setReady: (val: boolean) => void, delay: number
return () => {
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 = (
initialState,
handlers,
) => (state = initialState, action) => handlers.hasOwnProperty(action.type)
) => (state = initialState, action) => (handlers.hasOwnProperty(action.type)
? 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>] {
let emit;
const chan = eventChannel(emitter => {
const chan = eventChannel((emitter) => {
emit = emitter;
return () => null;
});
@ -27,7 +27,7 @@ export function createUploader<T extends {}, R extends {}>(
return [wrappedCallback, chan];
}
export const uploadGetThumb = async file => {
export const uploadGetThumb = async (file) => {
if (!file.type || !VALIDATORS.IS_IMAGE_MIME(file.type)) return '';
return await new Promise((resolve, reject) => {