1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00
This commit is contained in:
muerwre 2019-08-02 17:17:09 +07:00
parent 132fe872b6
commit e5bc0d258f
17 changed files with 301 additions and 65 deletions

View file

@ -72,7 +72,7 @@
"raleway-cyrillic": "^4.0.2",
"ramda": "^0.26.1",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-dom": "^16.8.6",
"react-grid-layout": "^0.16.6",
"react-hot-loader": "^4.1.1",
"react-layout-pack": "^0.2.3",

View file

@ -0,0 +1,13 @@
import React, { AllHTMLAttributes, FC } from "react";
import * as styles from "./styles.scss";
type IProps = AllHTMLAttributes<HTMLDivElement> & { is_blurred: boolean };
export const BlurWrapper: FC<IProps> = ({ children, is_blurred }) => (
<div
className={styles.blur}
style={{ filter: `blur(${is_blurred ? 15 : 0}px) saturate(${is_blurred ? 1.5 : 0})` }}
>
{children}
</div>
);

View file

@ -0,0 +1,4 @@
.blur {
filter: blur(0) grayscale(0);
transition: filter 0.25s;
}

View file

@ -13,36 +13,41 @@ 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/index";
interface IAppProps {}
interface IAppState {}
const mapStateToProps = selectModal;
const mapDispatchToProps = {};
class Component extends React.Component<IAppProps, IAppState> {
type IProps = typeof mapDispatchToProps & ReturnType<typeof mapStateToProps> & {};
class Component extends React.Component<IProps, {}> {
render() {
return (
<ConnectedRouter history={history}>
<MainLayout>
<Sprites />
<BlurWrapper is_blurred={this.props.is_shown}>
<MainLayout>
<Modal />
<Sprites />
<Switch>
<Route path={URLS.EXAMPLES.IMAGE} component={ImageExample} />
<Route path={URLS.EXAMPLES.EDITOR} component={EditorExample} />
<Route path="/examples/horizontal" component={HorizontalExample} />
<Route exact path={URLS.BASE} component={FlowLayout} />
<Switch>
<Route path={URLS.EXAMPLES.IMAGE} component={ImageExample} />
<Route path={URLS.EXAMPLES.EDITOR} component={EditorExample} />
<Route path="/examples/horizontal" component={HorizontalExample} />
<Route exact path={URLS.BASE} component={FlowLayout} />
<Route path={URLS.AUTH.LOGIN} component={LoginLayout} />
<Route path={URLS.AUTH.LOGIN} component={LoginLayout} />
<Redirect to="/" />
</Switch>
</MainLayout>
<Redirect to="/" />
</Switch>
</MainLayout>
</BlurWrapper>
</ConnectedRouter>
);
}
}
const mapStateToProps = (state, props) => ({});
const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch);
export default connect(
mapStateToProps,
mapDispatchToProps

View file

@ -0,0 +1,55 @@
import React, { Attributes, FC, useCallback } from "react";
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 } from "~/redux/modal/constants";
import ReactDOM from "react-dom";
const mapStateToProps = ({ modal }: IState) => ({ ...modal });
const mapDispatchToProps = {
modalSetShown: ACTIONS.modalSetShown,
modalSetDialog: ACTIONS.modalSetDialog,
modalShowDialog: ACTIONS.modalShowDialog
};
type IProps = typeof mapDispatchToProps & ReturnType<typeof mapStateToProps> & {};
const ModalUnconnected: FC<IProps> = ({
modalSetShown,
modalSetDialog,
modalShowDialog,
is_shown,
dialog
}) => {
const onRequestClose = useCallback(() => {
modalSetShown(false);
modalSetDialog(null);
}, [modalSetShown, modalSetDialog]);
if (!dialog || !DIALOG_CONTENT[dialog] || !is_shown) return null;
return ReactDOM.createPortal(
<div className={styles.fixed}>
<div className={styles.overlay} onClick={onRequestClose} />
<div className={styles.content}>
<div className={styles.content_scroller}>
<div className={styles.content_padder}>
{React.createElement(DIALOG_CONTENT[dialog], {
onRequestClose,
onDialogChange: modalShowDialog
} as Attributes)}
</div>
</div>
</div>
</div>,
document.body
);
};
const Modal = connect(
mapStateToProps,
mapDispatchToProps
)(ModalUnconnected);
export { ModalUnconnected, Modal };

View file

@ -0,0 +1,54 @@
.fixed {
position: fixed;
z-index: 10;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
@keyframes appear {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.content {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
opacity: 0;
animation: appear 0.25s forwards;
}
.content_scroller {
width: 100%;
max-width: 100vw;
max-height: 100vh;
overflow: auto;
}
.content_padder {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparentize($color: #000000, $amount: 0.5);
cursor: pointer;
}

View file

@ -12,6 +12,7 @@
flex-direction: column;
justify-content: center;
background: darken($content_bg, 4%);
box-shadow: transparentize(black, 0.7) 0 10px 5px;
}
.editor {
@ -29,7 +30,6 @@
}
.panel {
}
.features {
@ -78,7 +78,7 @@
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
@media(max-width: 600px) {
@media (max-width: 600px) {
grid-template-columns: repeat(auto-fill, minmax(30vw, 1fr));
}
}

View file

@ -1,3 +1,6 @@
/*
sortable grid: http://clauderic.github.io/react-sortable-hoc/#/basic-configuration/grid?_k=hjqdj1
*/
import * as React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';

View file

@ -0,0 +1,17 @@
import { IModalState } from '~/redux/modal/reducer';
import { MODAL_ACTIONS } from '~/redux/modal/constants';
export const modalSetShown = (is_shown: IModalState['is_shown']) => ({
is_shown,
type: MODAL_ACTIONS.SET_SHOWN,
});
export const modalSetDialog = (dialog: IModalState['dialog']) => ({
dialog,
type: MODAL_ACTIONS.SET_DIALOG,
});
export const modalShowDialog = (dialog: IModalState['dialog']) => ({
dialog,
type: MODAL_ACTIONS.SHOW_DIALOG,
});

View file

@ -0,0 +1,21 @@
import { ValueOf } from "~/redux/types";
import { HorizontalExample } from "~/containers/examples/HorizontalExample";
export const MODAL_ACTIONS = {
SET_SHOWN: "MODAL.SET_SHOWN",
SET_DIALOG: "SET_DIALOG",
SHOW_DIALOG: "SHOW_DIALOG"
};
export const DIALOGS = {
TEST: "TEST"
};
export const DIALOG_CONTENT = {
[DIALOGS.TEST]: HorizontalExample
};
export interface IDialogProps {
onRequestClose: () => void;
onDialogChange: (dialog: ValueOf<typeof DIALOGS>) => void;
}

View file

@ -0,0 +1,11 @@
import { MODAL_ACTIONS } from '~/redux/modal/constants';
const setShown = (state, { is_shown }) => ({ ...state, is_shown });
const showDialog = (state, { dialog }) => ({ ...state, dialog, is_shown: true });
const setDialog = (state, { dialog }) => ({ ...state, dialog });
export const MODAL_HANDLERS = {
[MODAL_ACTIONS.SET_SHOWN]: setShown,
[MODAL_ACTIONS.SHOW_DIALOG]: showDialog,
[MODAL_ACTIONS.SET_DIALOG]: setDialog,
};

View file

@ -0,0 +1,16 @@
import { MODAL_HANDLERS } from "~/redux/modal/handlers";
import { createReducer } from "~/utils/reducer";
import { DIALOGS } from "~/redux/modal/constants";
import { ValueOf } from "~/redux/types";
export interface IModalState {
is_shown: boolean;
dialog: ValueOf<typeof DIALOGS>;
}
const INITIAL_STATE: IModalState = {
is_shown: true,
dialog: DIALOGS.TEST
};
export default createReducer(INITIAL_STATE, MODAL_HANDLERS);

View file

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

View file

@ -1,42 +1,49 @@
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 } from 'connected-react-router'
import userReducer from '~/redux/user/reducer';
import userSaga from '~/redux/user/sagas';
import { createBrowserHistory } from 'history';
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import createSagaMiddleware from "redux-saga";
import { connectRouter, RouterState } from "connected-react-router";
import { createBrowserHistory } from "history";
import { PersistConfig, Persistor } from "redux-persist/es/types";
import { routerMiddleware } from 'connected-react-router'
import { routerMiddleware } from "connected-react-router";
import userReducer, { IUserState } from "~/redux/user/reducer";
import userSaga from "~/redux/user/sagas";
import modalReducer, { IModalState } from "~/redux/modal/reducer";
import { IState } from "~/redux/store";
const userPersistConfig: PersistConfig = {
key: 'user',
whitelist: ['profile'],
storage,
key: "user",
whitelist: ["profile"],
storage
};
export interface IState {
user: IUserState;
modal: IModalState;
router: RouterState;
}
export const sagaMiddleware = createSagaMiddleware();
export const history = createBrowserHistory();
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__({})
: compose;
export const store = createStore(
combineReducers({
user: persistReducer(userPersistConfig, userReducer),
router: connectRouter(history),
modal: modalReducer,
router: connectRouter(history)
}),
composeEnhancers(applyMiddleware(
routerMiddleware(history),
sagaMiddleware
))
composeEnhancers(applyMiddleware(routerMiddleware(history), sagaMiddleware))
);
export function configureStore(): { store: Store<any>, persistor: Persistor } {
export function configureStore(): { store: Store<any>; persistor: Persistor } {
sagaMiddleware.run(userSaga);
const persistor = persistStore(store);

View file

@ -2,10 +2,13 @@ import { DetailedHTMLProps, InputHTMLAttributes } from "react";
export type ITag = {
title: string;
feature?: 'red' | 'blue' | 'green' | 'olive' | 'black';
}
feature?: "red" | "blue" | "green" | "olive" | "black";
};
export type IInputTextProps = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> & {
export type IInputTextProps = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
> & {
wrapperClassName?: string;
handler?: (value: string) => void;
required?: boolean;
@ -20,3 +23,5 @@ export type IInputTextProps = DetailedHTMLProps<InputHTMLAttributes<HTMLInputEle
};
export type IIcon = string;
export type ValueOf<T> = T[keyof T];

View file

@ -1,27 +1,27 @@
import { createReducer } from 'reduxsauce';
import * as ActionCreators from "~/redux/user/actions";
import { USER_ACTIONS } from "~/redux/user/constants";
import { createReducer } from "~/utils/reducer";
export interface IUserProfile {
id: number,
username: string,
email: string,
role: string,
token: string,
id: number;
username: string;
email: string;
role: string;
token: string;
is_activated: boolean,
is_user: boolean,
is_activated: boolean;
is_user: boolean;
}
export interface IUserFormStateLogin {
error: string,
error: string;
}
export type IUserState = Readonly<{
profile: IUserProfile,
profile: IUserProfile;
form_state: {
login: IUserFormStateLogin,
},
login: IUserFormStateLogin;
};
}>;
type UnsafeReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
@ -29,13 +29,16 @@ interface ActionHandler<T> {
(state: IUserState, payload: UnsafeReturnType<T>): IUserState;
}
const setLoginErrorHandler: ActionHandler<typeof ActionCreators.userSetLoginError> = (state, { error }) => ({
const setLoginErrorHandler: ActionHandler<typeof ActionCreators.userSetLoginError> = (
state,
{ error }
) => ({
...state,
form_state: {
...state.form_state,
login: {
...state.form_state.login,
error,
error
}
}
});
@ -44,28 +47,28 @@ const setUserHandler: ActionHandler<typeof ActionCreators.userSetUser> = (state,
...state,
profile: {
...state.profile,
...profile,
...profile
}
});
const HANDLERS = {
[USER_ACTIONS.SET_LOGIN_ERROR]: setLoginErrorHandler,
[USER_ACTIONS.SET_USER]: setUserHandler,
[USER_ACTIONS.SET_USER]: setUserHandler
};
const INITIAL_STATE: IUserState = {
profile: {
id: 0,
username: '',
email: '',
role: '',
token: '',
username: "",
email: "",
role: "",
token: "",
is_activated: false,
is_user: false,
is_user: false
},
form_state: {
login: {
error: '',
error: ""
}
}
};

19
src/utils/reducer.ts Normal file
View file

@ -0,0 +1,19 @@
// create-reducer.ts
import { Action } from 'redux';
type Handlers<State, Types extends string, Actions extends Action<Types>> = {
readonly [Type in Types]: (state: State, action: Actions) => State
}
// export const createReducer = <State, Types extends string, Actions extends Action<Types>>(
// initialState: State,
// handlers: Handlers<State, Types, Actions>,
// ) => (state = initialState, action: Actions) =>
// handlers.hasOwnProperty(action.type) ? handlers[action.type as Types](state, action) : state;
export const createReducer = (
initialState,
handlers,
) => (state = initialState, action) => handlers.hasOwnProperty(action.type)
? handlers[action.type](state, action)
: state;