Commit 9ae7812c by Иван Кубота

pages

parent de81c8eb
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -6,9 +6,13 @@ ...@@ -6,9 +6,13 @@
"@material-ui/core": "latest", "@material-ui/core": "latest",
"@types/react": "latest", "@types/react": "latest",
"@types/react-dom": "latest", "@types/react-dom": "latest",
"@types/react-redux": "^7.1.1",
"react": "latest", "react": "latest",
"react-dom": "latest", "react-dom": "latest",
"react-redux": "^7.1.0",
"react-scripts": "latest", "react-scripts": "latest",
"redux": "^4.0.4",
"redux-thunk": "^2.3.0",
"typescript": "latest" "typescript": "latest"
}, },
"scripts": { "scripts": {
......
...@@ -2,14 +2,13 @@ import React from 'react'; ...@@ -2,14 +2,13 @@ import React from 'react';
import Container from '@material-ui/core/Container'; import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box'; import Box from '@material-ui/core/Box';
import Button from '@material-ui/core/Button';
import Link from '@material-ui/core/Link'; import Link from '@material-ui/core/Link';
import ProTip from './ProTip';
import {Grid} from "@material-ui/core"; import {Grid} from "@material-ui/core";
import store from "./store"; import store from "./store";
import {MainAsideMenu} from "./component/MainAsideMenu"; import {MainAsideMenu} from "./component/MainAsideMenu";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import {Content} from "./component/Content";
function MadeWithLove() { function MadeWithLove() {
return ( return (
...@@ -24,9 +23,6 @@ function MadeWithLove() { ...@@ -24,9 +23,6 @@ function MadeWithLove() {
} }
export class App extends React.Component<{}, {}> { export class App extends React.Component<{}, {}> {
render() { render() {
return ( return (
...@@ -38,15 +34,17 @@ export class App extends React.Component<{}, {}> { ...@@ -38,15 +34,17 @@ export class App extends React.Component<{}, {}> {
</Box> </Box>
<Box my={4}> <Box my={4}>
<Typography variant="h4" component="h1" gutterBottom> <Content/>
{/*<Typography variant="h4" component="h1" gutterBottom>
Create React App v4-beta example with TypeScript Create React App v4-beta example with TypeScript
</Typography> </Typography>
<ProTip/> */}
{/*<ProTip/>
<MadeWithLove/> <MadeWithLove/>
<Button variant="contained">12345</Button> <Button variant="contained">12345</Button>
<Button variant="contained" color="primary">12345</Button> <Button variant="contained" color="primary">12345</Button>
<Button variant="contained" color="secondary">12345</Button> <Button variant="contained" color="secondary">12345</Button>*/}
</Box> </Box>
</Grid> </Grid>
</Container> </Container>
......
import {Action, IMainStorage} from './index'; import {Action, IMainStorage} from './index';
export interface IAddLocale { export interface IAddLocale {
payload: {key: string, value: string} payload: {id: string}
} }
export const addLocale = Action('ADD_LOCALE', function (state: IMainStorage, {payload}: IAddLocale) { export const addLocale = Action('ADD_LOCALE', function (state: IMainStorage, {payload}: IAddLocale) {
return {...state, locale: {...state.locale, [payload.key]: [payload.value]}} if(payload.id in state.locale)
return state;
else
return {...state, locale: {
...state.locale,
[payload.id]: {
id: payload.id,
values: []
}
}};
}); });
\ No newline at end of file
import {Action, ILocaleTemplate, IMainStorage} from './index';
export interface IAddLocaleTemplate {
payload: {id: string, template: ILocaleTemplate}
}
export const addLocaleTemplate = Action('ADD_LOCALE_TEMPLATE', function (state: IMainStorage, {payload}: IAddLocaleTemplate) {
if(payload.id in state.locale)
return {...state, locale: {
...state.locale,
[payload.id]: {
id: payload.id,
values: state.locale[payload.id].values.concat(payload.template)
}
}};
else
return {...state, locale: {
...state.locale,
[payload.id]: {
id: payload.id,
values: [payload.template]
}
}};
});
export interface IPredef {
[key: string]: string
}
const predef: IPredef = {
"ban": "Пользователь {{$first_name}} {{$last_name}} был забанен лопатой.",
"warn": "Пользователь {{$first_name}} {{$last_name}} получает {{$count}} предупреждение из {{$maxWarns}}, осталось {{$diff}} {{plural:$diff,предупреждение,предупреждения,предупреждений}}",
"unban": "Пользователя {{$full_name}} пришлось разбанить.",
"unbanGreeting": "Ты разбанены в {{$title}}",
"pidor": "{{$first_name}}, ты — {{$condition?пацак:чатланин}}, а эта планета {{$condition?чатланская:пацакская}}.\n\nСчитай до {{$count}}.",
"pidorDoNotCount1": "Считай, кому говорят",
"pidorDoNotCount2": "Транклюкирую!",
"pidorDoNotCount3": "Последний раз предупреждаю!",
"pidorDoNotCount4": "Пожизненный эцих без гвоздей",
"pidorDoNotCount5": "Пожизненный эцих с гвоздями",
"pidorDoigralsa": "{{$full_name}} уехал в эцихе",
"pidorKletka": "Здесь можно только в клетке выступать.",
"pidorKU": "Говори «Ку»!",
"pidorOK": "Всё, хорошо посчитал. Эцилоп вернётся ночью.",
"pidorCanNotCount": "Правильно считай.",
"pidorCanNotCount2": "Эцилоп, бей его. Считай с начала давай.",
"ban2": "{{$count}} {{plural:$count,рыба,рыбы,рыб}}",
"ku": "Говори «ку»",
"permission": "Не можно",
"newLocale": "Теперь напиши боту лично. У тебя есть на это 15 минут, поторопись.",
"linkToUI": "Секретная ссылка! {{$link}}",
"_plural": "plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)"
};
setTimeout(()=>{
for(const key in predef){
addLocaleTemplate({
id: key,
template: {uuid: key, text: predef[key]}
});
}
}, 100)
\ No newline at end of file
// src/js/reducers/index.js // src/js/reducers/index.js
import {mainMenu} from "../model/mainMenu"; import store from "../store";
export interface ILocaleTemplate {
uuid: string,
text: string
}
export interface ILocale {
id: string,
values: ILocaleTemplate[]
}
export interface ILocaleHash {
[key: string]: ILocale
}
export interface IMainStorage { export interface IMainStorage {
activeMenu: string, activeMenu: string,
locale: { locale: ILocaleHash,
//string: string
},
chatData: { chatData: {
} }
} }
const initialState: IMainStorage = { const initialState: IMainStorage = {
activeMenu: mainMenu.filter((el)=>el.active)[0].id, activeMenu: 'main',
locale: { locale: {
}, },
...@@ -22,25 +32,31 @@ const initialState: IMainStorage = { ...@@ -22,25 +32,31 @@ const initialState: IMainStorage = {
const reducers: any = {}; const reducers: any = {};
export const Action = function (type: string, reducer: Function<IMainStorage,IAction>) { export interface IReducer {
(state: IMainStorage, action: IAction): IMainStorage;
}
export const Action = function (type: string, reducer: IReducer) {
reducers[type] = reducer; reducers[type] = reducer;
return function(payload: any){ return function(payload: any){
return {type, payload}; return store.dispatch({type, payload});
} }
}; };
export interface IAction { export interface IAction {
type: string, type: string,
payload: any payload: any
}; }
function rootReducer(state:IMainStorage = initialState, action: IAction) { function rootReducer(state:IMainStorage = initialState, action: IAction) {
if(action.type in reducers){ if(action.type in reducers){
reducers[action.type](state, action) return reducers[action.type](state, action)
}else{ }else{
throw new Error('No reducer for type `'+ action.type +'`') console.warn('No reducer for type `'+ action.type +'`')
} }
return state; return state;
} }
export default rootReducer; export default rootReducer;
import {Action} from './index'; import {Action} from './index';
export const setActiveMenu = Action('SET_ACTIVE_MENU', function (state, {payload}) { export const setActiveMenu = Action('SET_ACTIVE_MENU', function (state, {payload}) {
return {...state, activeMenu: payload.item}; console.log(state, payload);
return {...state, activeMenu: payload};
}); });
\ No newline at end of file
import React from "react";
import {connect} from "react-redux";
import {ILocale, IMainStorage} from "../action-reducers";
import {Button, List, ListItem, ListSubheader, TextField} from "@material-ui/core";
import {NewLocaleTemplate} from "./NewLocaleTemplate";
export interface IConstant {
item: ILocale
}
class ConstantView extends React.Component<IConstant, IConstant> {
render(): React.ReactNode {
const {id, values} = this.props.item;
return <List subheader={<ListSubheader>{id}</ListSubheader>}>
{values.map((val)=>
<ListItem key={val.uuid}>
{val.text}
{/*<TextField
value={val.text}
margin="normal"
inputProps={{ 'aria-label': 'bare' }}
/>*/}
</ListItem>
)}
<NewLocaleTemplate id={id}/>
</List>;
}
}
export const Constant = ConstantView;
import React from "react";
import {connect} from "react-redux";
import {IMainStorage} from "../action-reducers";
import {IMainAsideMenu} from "./MainAsideMenu";
import {mainMenu} from "../model/mainMenu";
export interface IContent extends IMainAsideMenu {
}
class ContentView extends React.Component<IContent, IContent> {
render(): React.ReactNode {
const {activeMenu} = this.props;
const item = mainMenu.filter((item)=>item.id===activeMenu)[0];
if(item){
const View = item.view();
return <View/>
}
console.warn('no view', activeMenu);
return null;
}
}
const ContentMap = function (store: IMainStorage): IContent {
return {activeMenu: store.activeMenu};
};
export const Content = connect(ContentMap)(ContentView);
\ No newline at end of file
...@@ -2,17 +2,29 @@ import React from "react"; ...@@ -2,17 +2,29 @@ import React from "react";
import {setActiveMenu} from "../action-reducers/setActiveMenu"; import {setActiveMenu} from "../action-reducers/setActiveMenu";
import {List, ListItem, ListItemText} from "@material-ui/core"; import {List, ListItem, ListItemText} from "@material-ui/core";
import {mainMenu} from "../model/mainMenu"; import {mainMenu} from "../model/mainMenu";
import {connect} from "react-redux";
import {IMainStorage} from "../action-reducers";
export class MainAsideMenu extends React.Component<{}, {}> { export interface IMainAsideMenu {
activeMenu: string
}
class MainAsideMenuView extends React.Component<IMainAsideMenu, IMainAsideMenu> {
render(): React.ReactNode { render(): React.ReactNode {
const {activeMenu} = this.state; const {activeMenu} = this.props;
return <List> return <List>
{mainMenu.map((item) => ( {mainMenu.map((item) => (
<ListItem button selected={(activeMenu === item.id)} key={item.id} onClick={() => setActiveMenu(item.id)}> <ListItem button selected={(activeMenu === item.id)} key={item.id} onClick={() => {
setActiveMenu(item.id)}}>
<ListItemText color={(activeMenu === item.id) ? "primary" : "secondary"} primary={item.text}/> <ListItemText color={(activeMenu === item.id) ? "primary" : "secondary"} primary={item.text}/>
</ListItem> </ListItem>
))} ))}
</List>; </List>;
} }
} }
const mapStoreToMenu = function(store:IMainStorage): IMainAsideMenu{
return {activeMenu: store.activeMenu};
};
export const MainAsideMenu = connect(mapStoreToMenu)(MainAsideMenuView);
\ No newline at end of file
import React, {ChangeEvent} from "react";
import {Button, Container, List, ListItem, TextField} from "@material-ui/core";
import {addLocale} from "../action-reducers/addLocale";
export interface INewLocale {
id: string
}
class NewLocaleView extends React.Component<{}, INewLocale> {
state = {
id: ''
};
changed(e: ChangeEvent) {
this.setState({id: (e.target as HTMLInputElement).value});
}
addLocale(){
const {id} = this.state;
addLocale({id})
this.setState({id: ''});
}
render(): React.ReactNode {
const {id} = this.state;
console.log(id);
return <List>
<ListItem>
<TextField
margin="normal"
inputProps={{ 'aria-label': 'bare' }}
onChange={(e)=>this.changed(e)}
value={id}
/>
<Button variant="contained" color="primary" onClick={()=>this.addLocale()}>+ Новая локализационная стринга</Button>
</ListItem>
</List>;
}
}
export const NewLocale = NewLocaleView;
\ No newline at end of file
import React from "react";
import {connect} from "react-redux";
import {IMainStorage} from "../action-reducers";
import {Button, Grid, TextField} from "@material-ui/core";
import {addLocaleTemplate, IAddLocaleTemplate} from "../action-reducers/addLocaleTemplate";
import {getUUID} from "../helpers";
export interface INewLocaleTemplate {
id: string
}
class NewLocaleTemplateView extends React.Component<INewLocaleTemplate, {}> {
state = {
expanded: false,
text: ''
};
addAction() {
addLocaleTemplate({id: this.props.id, template: {uuid: getUUID(), text: this.state.text}});
this.setState({expanded: false, text: ''})
}
render(): React.ReactNode {
return <div>
{this.state.expanded ?
<div>
<Grid spacing={1} container>
<Grid item>
<TextField
value={this.state.text}
onKeyDown={(e) => e.key === 'Enter' && e.ctrlKey && this.addAction()}
onChange={(e) => this.setState({text: e.target.value})}
margin="normal"
inputProps={{'aria-label': 'bare'}}
/>
</Grid>
<Grid item>
<Button variant="contained" color="secondary" onClick={() => this.addAction()}>
+ Сохранить (Ctrl+enter)
</Button>
</Grid>
<Grid item>
<Button variant="contained" color="primary"
onClick={() => this.setState({expanded: false})}>– Передумал</Button>
</Grid>
</Grid>
</div>
:
<Button variant="contained" color="secondary" onClick={() => this.setState({expanded: true})}>
+ Новый шаблон
</Button>
}
</div>;
}
}
export const NewLocaleTemplate = NewLocaleTemplateView;
\ No newline at end of file
export const AZ = function (key: string) {
return function (a: any, b: any) {
return a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0;
}
};
export const ZA = function (key: string) {
return function (a: any, b: any) {
return a[key] < b[key] ? 1 : a[key] > b[key] ? -1 : 0;
}
};
export const getUUID = function () {
return [
Math.random().toString(36).substr(2),
Math.random().toString(36).substr(2,7),
Math.random().toString(36).substr(2)
].join('-')
};
\ No newline at end of file
import {Constants} from "../view/Constants";
import React from "react";
import {Profile} from "../view/Profile";
import {Info} from "../view/Info";
import {setActiveMenu} from "../action-reducers/setActiveMenu";
export interface IComponentLambda {
(): React.ComponentClass
}
export interface menuItem { export interface menuItem {
id: string, id: string,
text: string, text: string,
active ?: boolean active ?: boolean,
view: IComponentLambda
} }
export const mainMenu: menuItem[] = [ export const mainMenu: menuItem[] = [
{ {
id: 'profile', id: 'info',
text: 'Profile', text: 'Info',
active: true active: true,
view: ()=>Info
}, },
{ {
id: 'constants', id: 'constants',
text: 'Constants' text: 'Constants',
view: ()=>Constants
},
{
id: 'profile',
text: 'Profile',
active: true,
view: ()=>Profile
}]; }];
setActiveMenu(mainMenu.filter((el)=>el.active)[0].id)
import React from "react";
import {connect} from "react-redux";
import {ILocaleHash, IMainStorage} from "../action-reducers";
import {AZ} from "../helpers";
import {Constant} from "../component/Constant";
import {Button, Container, List, ListItem, ListSubheader, TextField} from "@material-ui/core";
import {NewLocale} from "../component/NewLocale";
export interface IConstants {
locale: ILocaleHash
}
class ConstantsView extends React.Component<IConstants, IConstants> {
render(): React.ReactNode {
const {locale} = this.props,
localeList = Object.keys(locale).filter((key)=>key.charAt(0)!=='_').map((key)=>locale[key]).sort(AZ('id'));
return <Container>
<NewLocale/>
{localeList.map((item)=><Constant key={item.id} item={item}/>)}
</Container>;
}
}
const ConstantsMap = function (store: IMainStorage): IConstants {
return {locale: store.locale};
};
export const Constants = connect(ConstantsMap)(ConstantsView);
\ No newline at end of file
import React from "react";
import {connect} from "react-redux";
import {IMainStorage} from "../action-reducers";
class InfoView extends React.Component<{}, {}> {
render(): React.ReactNode {
return <div>
Этот бот может расширять свой лексикон
</div>;
}
}
export const Info = InfoView;
\ No newline at end of file
import React from "react";
import {connect} from "react-redux";
import {IMainStorage} from "../action-reducers";
export interface IProfile {
}
class ProfileView extends React.Component<IProfile, IProfile> {
render(): React.ReactNode {
return null;
}
}
const ProfileMap = function (store: IMainStorage): IProfile {
return {};
};
export const Profile = connect(ProfileMap)(ProfileView);
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment