mirror of
https://github.com/elyby/emails-renderer.git
synced 2024-11-22 21:23:12 +05:30
Migrate project's code base to TypeScript
This commit is contained in:
parent
c2c920d5f7
commit
71021a52c9
@ -33,6 +33,10 @@
|
||||
"@babel/plugin-proposal-export-default-from": "^7.2.0",
|
||||
"@babel/preset-env": "^7.3.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.3.3",
|
||||
"@types/react": "^16.8.17",
|
||||
"@types/react-intl": "^2.3.17",
|
||||
"@types/webpack-env": "^1.13.9",
|
||||
"babel-eslint": "^6.0.0",
|
||||
"babel-loader": "^8.0.5",
|
||||
"babel-preset-react-hot": "^1.0.5",
|
||||
@ -45,13 +49,14 @@
|
||||
"i18n-crowdin": "file:scripts/i18n-crowdin",
|
||||
"intl-json-loader": "file:./webpack-utils/intl-json-loader",
|
||||
"json-loader": "^0.5.7",
|
||||
"prop-types": "^15.7.2",
|
||||
"text2png-loader": "file:./webpack-utils/text2png-loader",
|
||||
"typescript": "^3.4.5",
|
||||
"webpack": "^4.29.6",
|
||||
"webpack-bundle-analyzer": "^3.3.2",
|
||||
"webpack-cli": "^3.3.0",
|
||||
"webpack-dev-server": "^3.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.6.0"
|
||||
"node": ">=8.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
|
||||
import { SUPPORTED_LANGUAGES, DEFAULT_LANGUAGE } from './params';
|
||||
import { SUPPORTED_LANGUAGES, DEFAULT_LANGUAGE } from 'params';
|
||||
|
||||
import BaseLayout from 'components/BaseLayout';
|
||||
import { BaseLayout } from 'components';
|
||||
|
||||
export default function App({type, payload = {}}) {
|
||||
let { locale } = payload;
|
||||
export interface Params {
|
||||
type: string;
|
||||
payload: {
|
||||
locale: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
const App: FunctionComponent<Params> = ({ type, payload: { locale, ...params } }) => {
|
||||
if (!locale || SUPPORTED_LANGUAGES.indexOf(locale) === -1) {
|
||||
locale = DEFAULT_LANGUAGE;
|
||||
}
|
||||
@ -21,17 +25,13 @@ export default function App({type, payload = {}}) {
|
||||
const { default: Email } = require(`emails/${type}/index`);
|
||||
|
||||
return (
|
||||
// @ts-ignore have no idea why
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<BaseLayout>
|
||||
<Email {...payload} />
|
||||
<Email {...params} />
|
||||
</BaseLayout>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
payload: PropTypes.shape({
|
||||
locale: PropTypes.string,
|
||||
}),
|
||||
};
|
||||
|
||||
export default App;
|
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
import { Table } from 'components/table';
|
||||
|
||||
export default function BaseLayout(props) {
|
||||
const BaseLayout: FunctionComponent = ({ children }) => {
|
||||
return (
|
||||
<Table style={styles.body}>
|
||||
<tr>
|
||||
@ -12,7 +12,7 @@ export default function BaseLayout(props) {
|
||||
|
||||
</td>
|
||||
<td style={styles.container}>
|
||||
{props.children}
|
||||
{children}
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@ -20,4 +20,6 @@ export default function BaseLayout(props) {
|
||||
</tr>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default BaseLayout;
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
export default function Html(props) {
|
||||
const Html: FunctionComponent = ({ children }) => {
|
||||
return (
|
||||
<html>
|
||||
<head>
|
||||
@ -10,8 +10,10 @@ export default function Html(props) {
|
||||
<body style={{
|
||||
margin: 0
|
||||
}}>
|
||||
{props.children}
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Html;
|
@ -1,15 +1,21 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
|
||||
import { FormattedMessage as Message } from 'react-intl';
|
||||
|
||||
import { colors, green } from 'components/ui/colors';
|
||||
import { Colors } from 'components/ui/colors';
|
||||
import { Button, Input } from 'components/ui';
|
||||
|
||||
import styles from './styles';
|
||||
import messages from './messages.intl.json';
|
||||
|
||||
export default function Code({code, link, label, color = green}) {
|
||||
interface Props {
|
||||
code: string;
|
||||
link: string;
|
||||
label: ReactElement;
|
||||
color?: Colors;
|
||||
}
|
||||
|
||||
const Code: FunctionComponent<Props> = ({ code, link, label, color = 'green' }) => {
|
||||
return (
|
||||
<div style={styles.codeWrapper}>
|
||||
<div>
|
||||
@ -28,11 +34,6 @@ export default function Code({code, link, label, color = green}) {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Code.propTypes = {
|
||||
code: PropTypes.string.isRequired,
|
||||
link: PropTypes.string.isRequired,
|
||||
label: PropTypes.node.isRequired,
|
||||
color: PropTypes.oneOf(Object.values(colors))
|
||||
};
|
||||
|
||||
export default Code;
|
@ -1,21 +0,0 @@
|
||||
export default {
|
||||
codeWrapper: {
|
||||
paddingTop: '20px',
|
||||
textAlign: 'center'
|
||||
},
|
||||
confirmEmailButton: {
|
||||
paddingLeft: '50px',
|
||||
paddingRight: '50px'
|
||||
},
|
||||
or: {
|
||||
fontSize: '12px',
|
||||
paddingTop: '5px'
|
||||
},
|
||||
codeLabel: {
|
||||
paddingTop: '1px',
|
||||
fontSize: '16px'
|
||||
},
|
||||
code: {
|
||||
paddingTop: '5px'
|
||||
}
|
||||
};
|
25
src/components/blocks/code/styles.ts
Normal file
25
src/components/blocks/code/styles.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
const styles: { [key: string]: CSSProperties } = {
|
||||
codeWrapper: {
|
||||
paddingTop: '20px',
|
||||
textAlign: 'center',
|
||||
},
|
||||
confirmEmailButton: {
|
||||
paddingLeft: '50px',
|
||||
paddingRight: '50px',
|
||||
},
|
||||
or: {
|
||||
fontSize: '12px',
|
||||
paddingTop: '5px',
|
||||
},
|
||||
codeLabel: {
|
||||
paddingTop: '1px',
|
||||
fontSize: '16px',
|
||||
},
|
||||
code: {
|
||||
paddingTop: '5px',
|
||||
},
|
||||
};
|
||||
|
||||
export default styles;
|
@ -1,5 +0,0 @@
|
||||
import Code from './code/Code';
|
||||
|
||||
export {
|
||||
Code
|
||||
};
|
1
src/components/blocks/index.ts
Normal file
1
src/components/blocks/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as Code } from './code/Code';
|
@ -1,5 +0,0 @@
|
||||
import Html from './Html';
|
||||
|
||||
export {
|
||||
Html
|
||||
};
|
2
src/components/index.ts
Normal file
2
src/components/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { default as HTML } from './Html';
|
||||
export { default as BaseLayout } from './BaseLayout';
|
@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
export default function Content(props) {
|
||||
return (
|
||||
<div style={styles.content}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
13
src/components/layout/content/Content.tsx
Normal file
13
src/components/layout/content/Content.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
const Content: FunctionComponent = ({ children }) => {
|
||||
return (
|
||||
<div style={styles.content}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Content;
|
@ -1,24 +0,0 @@
|
||||
import {green} from 'components/ui/colors';
|
||||
|
||||
export default {
|
||||
footer: {
|
||||
borderTop: `10px solid ${green.color}`,
|
||||
background: '#DDD8CE',
|
||||
height: '135px'
|
||||
},
|
||||
footerText: {
|
||||
verticalAlign: 'middle',
|
||||
paddingLeft: '30px',
|
||||
fontSize: '13px',
|
||||
color: '#7A7A7A'
|
||||
},
|
||||
footerLink: {
|
||||
color: '#7A7A7A',
|
||||
textDecoration: 'none',
|
||||
borderBottom: '1px dashed #7A7A7A'
|
||||
},
|
||||
footerLogo: {
|
||||
padding: '0 30px',
|
||||
textAlign: 'center'
|
||||
}
|
||||
};
|
27
src/components/layout/footer/styles.ts
Normal file
27
src/components/layout/footer/styles.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { green } from 'components/ui/colors';
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
const styles: { [key: string]: CSSProperties } = {
|
||||
footer: {
|
||||
borderTop: `10px solid ${green.base}`,
|
||||
background: '#DDD8CE',
|
||||
height: '135px',
|
||||
},
|
||||
footerText: {
|
||||
verticalAlign: 'middle',
|
||||
paddingLeft: '30px',
|
||||
fontSize: '13px',
|
||||
color: '#7A7A7A',
|
||||
},
|
||||
footerLink: {
|
||||
color: '#7A7A7A',
|
||||
textDecoration: 'none',
|
||||
borderBottom: '1px dashed #7A7A7A',
|
||||
},
|
||||
footerLogo: {
|
||||
padding: '0 30px',
|
||||
textAlign: 'center',
|
||||
},
|
||||
};
|
||||
|
||||
export default styles;
|
@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import { FormattedMessage as Message } from 'react-intl';
|
||||
|
||||
import { Table } from 'components/table';
|
||||
@ -7,7 +6,12 @@ import { Table } from 'components/table';
|
||||
import styles from './styles';
|
||||
import messages from './messages.intl.json';
|
||||
|
||||
export default function Userbar({username, title}) {
|
||||
interface Props {
|
||||
username: string;
|
||||
title: ReactElement;
|
||||
}
|
||||
|
||||
const Userbar: FunctionComponent<Props> = ({ username, title }) => {
|
||||
return (
|
||||
<Table style={styles.headerImage}>
|
||||
<tr>
|
||||
@ -21,9 +25,6 @@ export default function Userbar({username, title}) {
|
||||
</tr>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
Userbar.propTypes = {
|
||||
username: PropTypes.string,
|
||||
title: PropTypes.node
|
||||
};
|
||||
|
||||
export default Userbar;
|
@ -1,16 +0,0 @@
|
||||
import background from './background.jpg';
|
||||
|
||||
export default {
|
||||
headerImage: {
|
||||
height: '200px',
|
||||
backgroundImage: `url(${background})`
|
||||
},
|
||||
headerTextContainer: {
|
||||
color: '#fff',
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle'
|
||||
},
|
||||
welcomeUsername: {
|
||||
fontSize: '20px'
|
||||
},
|
||||
};
|
19
src/components/layout/header/styles.ts
Normal file
19
src/components/layout/header/styles.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import background from './background.jpg';
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
const styles: { [key: string]: CSSProperties } = {
|
||||
headerImage: {
|
||||
height: '200px',
|
||||
backgroundImage: `url(${background})`,
|
||||
},
|
||||
headerTextContainer: {
|
||||
color: '#fff',
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
welcomeUsername: {
|
||||
fontSize: '20px',
|
||||
},
|
||||
};
|
||||
|
||||
export default styles;
|
@ -1,11 +0,0 @@
|
||||
import Userbar from './userbar/Userbar';
|
||||
import Header from './header/Header';
|
||||
import Content from './content/Content';
|
||||
import Footer from './footer/Footer';
|
||||
|
||||
export {
|
||||
Userbar,
|
||||
Header,
|
||||
Content,
|
||||
Footer
|
||||
};
|
4
src/components/layout/index.ts
Normal file
4
src/components/layout/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export { default as Userbar } from './userbar/Userbar';
|
||||
export { default as Header } from './header/Header';
|
||||
export { default as Content } from './content/Content';
|
||||
export { default as Footer } from './footer/Footer';
|
@ -1,26 +1,24 @@
|
||||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { Table } from 'components/table';
|
||||
|
||||
import styles from './styles';
|
||||
import logoImage from './logo.png';
|
||||
|
||||
export default function Userbar() {
|
||||
const Userbar: FunctionComponent = () => {
|
||||
return (
|
||||
<Table style={styles.userbar}>
|
||||
<tr>
|
||||
<td style={styles.marginColumn} />
|
||||
<td style={styles.logoColumn}>
|
||||
<a href="http://ely.by" style={styles.logo}>
|
||||
{/* TODO: здесь нужно динамически сформировать название, т.к. может быть Ёly.by */}
|
||||
<img src={logoImage} alt="Ely.by" style={{
|
||||
width: '65px',
|
||||
verticalAlign: 'middle'
|
||||
}} />
|
||||
<img src={logoImage} alt="Ely.by" style={styles.logoImage} />
|
||||
</a>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Userbar;
|
@ -1,21 +0,0 @@
|
||||
import {green} from 'components/ui/colors';
|
||||
|
||||
export default {
|
||||
userbar: {
|
||||
background: green.color,
|
||||
height: '50px'
|
||||
},
|
||||
marginColumn: {
|
||||
width: '20px'
|
||||
},
|
||||
logoColumn: {
|
||||
width: '1%',
|
||||
verticalAlign: 'middle',
|
||||
background: green.dark
|
||||
},
|
||||
logo: {
|
||||
padding: '0 13px',
|
||||
display: 'block',
|
||||
lineHeight: '50px'
|
||||
}
|
||||
};
|
25
src/components/layout/userbar/styles.ts
Normal file
25
src/components/layout/userbar/styles.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { green } from 'components/ui/colors';
|
||||
|
||||
export default {
|
||||
userbar: {
|
||||
background: green.base,
|
||||
height: '50px',
|
||||
},
|
||||
marginColumn: {
|
||||
width: '20px',
|
||||
},
|
||||
logoColumn: {
|
||||
width: '1%',
|
||||
verticalAlign: 'middle',
|
||||
background: green.dark,
|
||||
},
|
||||
logo: {
|
||||
padding: '0 13px',
|
||||
display: 'block',
|
||||
lineHeight: '50px',
|
||||
},
|
||||
logoImage: {
|
||||
width: '65px',
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
};
|
@ -3,9 +3,9 @@ export default {
|
||||
backgroundColor: '#EBE8E1',
|
||||
width: '100%',
|
||||
fontFamily: 'Roboto, Arial, sans-serif',
|
||||
color: '#444'
|
||||
color: '#444',
|
||||
},
|
||||
container: {
|
||||
width: '600px'
|
||||
}
|
||||
width: '600px',
|
||||
},
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
export default function Table(props) {
|
||||
return (
|
||||
<table cellPadding="0" cellSpacing="0" style={{
|
||||
...styles.table,
|
||||
...props.style
|
||||
}}>
|
||||
<tbody>
|
||||
{props.children}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
22
src/components/table/Table.tsx
Normal file
22
src/components/table/Table.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { CSSProperties, FunctionComponent } from 'react';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
interface Props {
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
const Table: FunctionComponent<Props> = ({ children, style }) => {
|
||||
return (
|
||||
<table cellPadding="0" cellSpacing="0" style={{
|
||||
...styles.table,
|
||||
...style
|
||||
}}>
|
||||
<tbody>
|
||||
{children}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export default Table;
|
@ -1 +0,0 @@
|
||||
export Table from './Table';
|
1
src/components/table/index.ts
Normal file
1
src/components/table/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as Table } from './Table';
|
@ -1,8 +0,0 @@
|
||||
export default {
|
||||
table: {
|
||||
borderCollapse: 'collapse',
|
||||
msoTableLspace: '0pt',
|
||||
msoTableRspace: '0pt',
|
||||
width: '100%'
|
||||
}
|
||||
};
|
13
src/components/table/styles.ts
Normal file
13
src/components/table/styles.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
const styles: { [key: string]: CSSProperties } = {
|
||||
table: {
|
||||
borderCollapse: 'collapse',
|
||||
// @ts-ignore
|
||||
msoTableLspace: '0pt',
|
||||
msoTableRspace: '0pt',
|
||||
width: '100%'
|
||||
},
|
||||
};
|
||||
|
||||
export default styles;
|
@ -1,34 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
import { colors, green } from 'components/ui/colors';
|
||||
|
||||
export default class Button extends Component {
|
||||
|
||||
static propTypes = {
|
||||
label: PropTypes.node.isRequired,
|
||||
color: PropTypes.oneOf(Object.values(colors))
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
color: green
|
||||
};
|
||||
|
||||
render() {
|
||||
const {props} = this;
|
||||
const {color, label} = props;
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
...styles.button,
|
||||
...styles[color],
|
||||
...props.style
|
||||
}}>
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
26
src/components/ui/button/Button.tsx
Normal file
26
src/components/ui/button/Button.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React, { CSSProperties, FunctionComponent, ReactElement } from 'react';
|
||||
|
||||
import { Colors, green } from 'components/ui/colors';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
interface Props {
|
||||
label: ReactElement;
|
||||
style?: CSSProperties;
|
||||
color?: Colors;
|
||||
}
|
||||
|
||||
const Button: FunctionComponent<Props> = ({ label, style, color = 'green' }) => {
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
...styles.button,
|
||||
...styles[color],
|
||||
...style,
|
||||
}}>
|
||||
{label}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
@ -1 +0,0 @@
|
||||
export Button from './Button';
|
1
src/components/ui/button/index.ts
Normal file
1
src/components/ui/button/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './Button';
|
@ -1,25 +0,0 @@
|
||||
import { colors } from 'components/ui/colors';
|
||||
|
||||
/**
|
||||
* @param {Color} color
|
||||
* @return {{backgroundColor: *}}
|
||||
*/
|
||||
function generateColor(color) {
|
||||
return {
|
||||
backgroundColor: color.color
|
||||
};
|
||||
}
|
||||
|
||||
const styles = {
|
||||
button: {
|
||||
padding: '0 13px',
|
||||
lineHeight: '50px',
|
||||
display: 'inline-block'
|
||||
}
|
||||
};
|
||||
|
||||
Object.values(colors).forEach((color) => {
|
||||
styles[color] = generateColor(color);
|
||||
});
|
||||
|
||||
export default styles;
|
27
src/components/ui/button/styles.ts
Normal file
27
src/components/ui/button/styles.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Color, Colors, colors } from 'components/ui/colors';
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
function generateColor({ base }: Color): CSSProperties {
|
||||
return {
|
||||
backgroundColor: base,
|
||||
};
|
||||
}
|
||||
|
||||
type Styles = {
|
||||
[key: string]: CSSProperties;
|
||||
}
|
||||
|
||||
const styles: Styles = {
|
||||
button: {
|
||||
padding: '0 13px',
|
||||
lineHeight: '50px',
|
||||
display: 'inline-block',
|
||||
},
|
||||
};
|
||||
|
||||
Object.keys(colors).forEach((colorName) => {
|
||||
// TS has error when trying to recognize keys types, so we cast it manually
|
||||
styles[colorName] = generateColor(colors[colorName as any as Colors]);
|
||||
});
|
||||
|
||||
export default styles;
|
@ -1,48 +0,0 @@
|
||||
export class Color {
|
||||
|
||||
constructor(name, base, light, dark) {
|
||||
this._name = name;
|
||||
this._base = base;
|
||||
this._light = light;
|
||||
this._dark = dark;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get color() {
|
||||
return this._base;
|
||||
}
|
||||
|
||||
get light() {
|
||||
return this._light;
|
||||
}
|
||||
|
||||
get dark() {
|
||||
return this._dark;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const green = new Color('green', '#207e5c', '#379070', '#1a6449');
|
||||
export const blue = new Color('blue', '#5b9aa9', '#71a6b2', '#568297');
|
||||
export const darkBlue = new Color('darkBlue', '#28555b', '#3e6164', '#233d49');
|
||||
export const violet = new Color('violet', '#6b5b8c', '#816795', '#66437a');
|
||||
export const lightViolet = new Color('lightViolet', '#8b5d79', '#a16982', '#864567');
|
||||
export const orange = new Color('orange', '#dd8650', '#f39259', '#d86e3e');
|
||||
export const red = new Color('red', '#e66c69', '#e15457', '#fc7872');
|
||||
|
||||
export const colors = {
|
||||
green,
|
||||
blue,
|
||||
darkBlue,
|
||||
violet,
|
||||
lightViolet,
|
||||
orange,
|
||||
red
|
||||
};
|
63
src/components/ui/colors.ts
Normal file
63
src/components/ui/colors.ts
Normal file
@ -0,0 +1,63 @@
|
||||
export type Colors =
|
||||
| 'green'
|
||||
| 'blue'
|
||||
| 'darkBlue'
|
||||
| 'violet'
|
||||
| 'lightViolet'
|
||||
| 'orange'
|
||||
| 'red'
|
||||
;
|
||||
|
||||
export interface Color {
|
||||
base: string;
|
||||
light: string;
|
||||
dark: string;
|
||||
}
|
||||
|
||||
export const green: Color = {
|
||||
base: '#207e5c',
|
||||
light: '#379070',
|
||||
dark: '#1a6449',
|
||||
};
|
||||
export const blue: Color = {
|
||||
base: '#5b9aa9',
|
||||
light: '#71a6b2',
|
||||
dark: '#568297',
|
||||
};
|
||||
export const darkBlue: Color = {
|
||||
base: '#28555b',
|
||||
light: '#3e6164',
|
||||
dark: '#233d49',
|
||||
};
|
||||
export const violet: Color = {
|
||||
base: '#6b5b8c',
|
||||
light: '#816795',
|
||||
dark: '#66437a',
|
||||
};
|
||||
export const lightViolet: Color = {
|
||||
base: '#8b5d79',
|
||||
light: '#a16982',
|
||||
dark: '#864567',
|
||||
};
|
||||
export const orange: Color = {
|
||||
base: '#dd8650',
|
||||
light: '#f39259',
|
||||
dark: '#d86e3e',
|
||||
};
|
||||
export const red: Color = {
|
||||
base: '#e66c69',
|
||||
light: '#e15457',
|
||||
dark: '#fc7872',
|
||||
};
|
||||
|
||||
type ColorsMap = { [key in Colors]: Color };
|
||||
|
||||
export const colors: ColorsMap = {
|
||||
green,
|
||||
blue,
|
||||
darkBlue,
|
||||
violet,
|
||||
lightViolet,
|
||||
orange,
|
||||
red,
|
||||
};
|
@ -1,32 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { colors, green } from 'components/ui/colors';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
export default class Input extends Component {
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
color: PropTypes.oneOf(Object.values(colors)),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
color: green,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {props} = this;
|
||||
const {value, color, style} = props;
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
...styles.input,
|
||||
...styles[color],
|
||||
...style
|
||||
}}>
|
||||
{value}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
25
src/components/ui/input/Input.tsx
Normal file
25
src/components/ui/input/Input.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React, { CSSProperties, FunctionComponent } from 'react';
|
||||
|
||||
import { Colors } from 'components/ui/colors';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
color?: Colors;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
const Input: FunctionComponent<Props> = ({ value, style, color = 'green' }) => {
|
||||
return (
|
||||
<div style={{
|
||||
...styles.input,
|
||||
...styles[color],
|
||||
...style
|
||||
}}>
|
||||
{value}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Input;
|
@ -1 +0,0 @@
|
||||
export Input from './Input';
|
1
src/components/ui/input/index.ts
Normal file
1
src/components/ui/input/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './Input';
|
@ -1,30 +0,0 @@
|
||||
import { colors } from 'components/ui/colors';
|
||||
|
||||
/**
|
||||
* @param {Color} color
|
||||
* @return {{backgroundColor: *}}
|
||||
*/
|
||||
function generateColor(color) {
|
||||
return {
|
||||
borderColor: color.color,
|
||||
color: color.dark
|
||||
};
|
||||
}
|
||||
|
||||
const styles = {
|
||||
input: {
|
||||
backgroundColor: '#fff',
|
||||
padding: '0 30px',
|
||||
lineHeight: '50px',
|
||||
fontSize: '18px',
|
||||
display: 'inline-block',
|
||||
border: '3px solid transparent',
|
||||
color: '#444'
|
||||
}
|
||||
};
|
||||
|
||||
Object.values(colors).forEach((color) => {
|
||||
styles[color] = generateColor(color);
|
||||
});
|
||||
|
||||
export default styles;
|
28
src/components/ui/input/styles.ts
Normal file
28
src/components/ui/input/styles.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import { Color, Colors, colors } from 'components/ui/colors';
|
||||
|
||||
const styles: { [key: string]: CSSProperties } = {
|
||||
input: {
|
||||
backgroundColor: '#fff',
|
||||
padding: '0 30px',
|
||||
lineHeight: '50px',
|
||||
fontSize: '18px',
|
||||
display: 'inline-block',
|
||||
border: '3px solid transparent',
|
||||
color: '#444',
|
||||
},
|
||||
};
|
||||
|
||||
function generateColor({ base, dark }: Color): CSSProperties {
|
||||
return {
|
||||
borderColor: base,
|
||||
color: dark,
|
||||
};
|
||||
}
|
||||
|
||||
Object.keys(colors).forEach((color) => {
|
||||
// TS has error when trying to recognize keys types, so we cast it manually
|
||||
styles[color] = generateColor(colors[color as any as Colors]);
|
||||
});
|
||||
|
||||
export default styles;
|
@ -1,94 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import App from 'App';
|
||||
|
||||
import List from './List';
|
||||
|
||||
import { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES } from 'params';
|
||||
|
||||
const AVAILABLE_EMAILS = require.context('emails', true, /index\.js$/).keys().map((path) => path.split('/')[1]);
|
||||
|
||||
export default class DevApp extends Component {
|
||||
state = {
|
||||
locale: DEFAULT_LANGUAGE,
|
||||
type: AVAILABLE_EMAILS[0],
|
||||
fixture: 'default',
|
||||
isMinimized: false,
|
||||
};
|
||||
|
||||
componentWillMount() {
|
||||
try {
|
||||
const lastState = JSON.parse(localStorage.getItem('emailRendererState'));
|
||||
lastState && this.setState(lastState);
|
||||
} catch (err) {/* no state was saved */}
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
localStorage.setItem('emailRendererState', JSON.stringify(nextState));
|
||||
}
|
||||
|
||||
render() {
|
||||
const {locale, type, isMinimized} = this.state;
|
||||
let {fixture} = this.state;
|
||||
|
||||
let fixturesAvailable = {};
|
||||
try {
|
||||
fixturesAvailable = require(`emails/${type}/fixtures`).default;
|
||||
} catch (err) {/* no fixtures available */}
|
||||
|
||||
if (!fixturesAvailable[fixture]) {
|
||||
fixture = 'default';
|
||||
}
|
||||
|
||||
const payload = {
|
||||
locale,
|
||||
...(fixturesAvailable[fixture] || {})
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={isMinimized ? {
|
||||
opacity: 0.4,
|
||||
position: 'fixed'
|
||||
} : {}}>
|
||||
[<a href="#" style={{textDecoration: 'none', padding: '6px'}} onClick={this.onMinimizeToggle}>
|
||||
{isMinimized ? '+' : '-'}
|
||||
</a>]
|
||||
|
||||
<div style={isMinimized ? {display: 'none'} : {}}>
|
||||
<List label="Lang"
|
||||
items={SUPPORTED_LANGUAGES}
|
||||
active={locale}
|
||||
onChange={this.onLocaleChange}
|
||||
/>
|
||||
|
||||
<List label="Email"
|
||||
items={AVAILABLE_EMAILS}
|
||||
active={type}
|
||||
onChange={this.onTypeChange}
|
||||
/>
|
||||
|
||||
<List label="Fixtures"
|
||||
items={Object.keys(fixturesAvailable)}
|
||||
active={fixture}
|
||||
onChange={this.onFixtureChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<App type={type} payload={payload} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onLocaleChange = (locale) => this.setState({locale});
|
||||
onTypeChange = (type) => this.setState({type});
|
||||
onFixtureChange = (fixture) => this.setState({fixture});
|
||||
onMinimizeToggle = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
this.setState({
|
||||
isMinimized: !this.state.isMinimized
|
||||
});
|
||||
}
|
||||
}
|
109
src/devTools/DevApp.tsx
Normal file
109
src/devTools/DevApp.tsx
Normal file
@ -0,0 +1,109 @@
|
||||
import React, { BaseSyntheticEvent, FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES } from 'params';
|
||||
|
||||
import App from 'App';
|
||||
|
||||
import List from './List';
|
||||
|
||||
const AVAILABLE_TEMPLATES = require.context('emails', true, /index\.[jt]s$/).keys().map((path) => path.split('/')[1]);
|
||||
|
||||
interface LocalStorageState {
|
||||
locale: string;
|
||||
template: string;
|
||||
fixture: string;
|
||||
isMinimized: boolean;
|
||||
}
|
||||
|
||||
const DevApp: FunctionComponent = () => {
|
||||
const [ locale, setLocale ] = useState(DEFAULT_LANGUAGE);
|
||||
const [ template, setTemplate ] = useState(AVAILABLE_TEMPLATES[0]);
|
||||
const [ fixture, setFixture ] = useState('default');
|
||||
const [ isMinimized, setIsMinimized ] = useState(false);
|
||||
|
||||
// Load stored state from local storage on the first run
|
||||
useEffect(() => {
|
||||
let state: LocalStorageState;
|
||||
try {
|
||||
state = JSON.parse(localStorage.getItem('emailRendererState') || '');
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLocale(state.locale);
|
||||
setTemplate(state.template);
|
||||
setFixture(state.fixture);
|
||||
setIsMinimized(state.isMinimized);
|
||||
}, []);
|
||||
|
||||
// Store current state to the local storage when any param is changed
|
||||
useEffect(() => {
|
||||
const state: LocalStorageState = { locale, template, fixture, isMinimized };
|
||||
localStorage.setItem('emailRendererState', JSON.stringify(state));
|
||||
}, [locale, template, fixture, isMinimized]);
|
||||
|
||||
const availableFixtures = useMemo(() => {
|
||||
try {
|
||||
return require(`emails/${template}/fixtures`).default;
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
}, [template]);
|
||||
|
||||
const payload = useMemo(() => ({
|
||||
locale,
|
||||
...(availableFixtures[fixture] || availableFixtures['default'] || {}),
|
||||
}), [locale, availableFixtures, fixture]);
|
||||
|
||||
const onMinimizeClick = useCallback((event: BaseSyntheticEvent) => {
|
||||
event.preventDefault();
|
||||
setIsMinimized(!isMinimized);
|
||||
}, [isMinimized, setIsMinimized]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={isMinimized ? {
|
||||
opacity: 0.4,
|
||||
position: 'fixed',
|
||||
} : {}}>
|
||||
[<a
|
||||
href="#"
|
||||
style={{
|
||||
textDecoration: 'none',
|
||||
padding: '6px',
|
||||
}}
|
||||
onClick={onMinimizeClick}
|
||||
>
|
||||
{isMinimized ? '+' : '-'}
|
||||
</a>]
|
||||
|
||||
<div style={isMinimized ? {display: 'none'} : {}}>
|
||||
<List label="Lang"
|
||||
items={SUPPORTED_LANGUAGES}
|
||||
active={locale}
|
||||
onChange={setLocale}
|
||||
/>
|
||||
|
||||
<List label="Email"
|
||||
items={AVAILABLE_TEMPLATES}
|
||||
active={template}
|
||||
onChange={setTemplate}
|
||||
/>
|
||||
|
||||
<List label="Fixtures"
|
||||
items={Object.keys(availableFixtures)}
|
||||
active={fixture}
|
||||
onChange={setFixture}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<App type={template} payload={payload} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DevApp;
|
@ -1,31 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function List({label, items, active, onChange}) {
|
||||
return (
|
||||
<div>
|
||||
{label}:
|
||||
{items.map((key) =>
|
||||
<a href="#"
|
||||
key={key}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
||||
onChange && onChange(key);
|
||||
}}
|
||||
style={{
|
||||
padding: '0 5px',
|
||||
color: active === key ? 'red' : ''
|
||||
}}
|
||||
>{key}</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
List.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
active: PropTypes.string,
|
||||
onChange: PropTypes.func
|
||||
};
|
34
src/devTools/List.tsx
Normal file
34
src/devTools/List.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
items: ReadonlyArray<string>;
|
||||
active: string;
|
||||
onChange: (item: string) => any;
|
||||
}
|
||||
|
||||
const List: FunctionComponent<Props> = ({ label, items, active, onChange = () => {} }) => {
|
||||
return (
|
||||
<div>
|
||||
{label}:
|
||||
{items.map((item) =>
|
||||
<a
|
||||
href="#"
|
||||
key={item}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
onChange(item);
|
||||
}}
|
||||
style={{
|
||||
padding: '0 5px',
|
||||
color: active === item ? 'red' : '',
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default List;
|
@ -1,3 +0,0 @@
|
||||
import DevApp from './DevApp';
|
||||
|
||||
export default DevApp;
|
1
src/devTools/index.ts
Normal file
1
src/devTools/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './DevApp';
|
@ -1,16 +1,20 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { FormattedMessage as Message, FormattedHTMLMessage as HTMLMessage } from 'react-intl';
|
||||
|
||||
import { Userbar, Header, Content, Footer } from 'components/layout';
|
||||
import { Table } from 'components/table';
|
||||
import { Code } from 'components/blocks';
|
||||
import { lightViolet } from 'components/ui/colors';
|
||||
|
||||
import styles from './styles';
|
||||
import messages from './messages.intl.json';
|
||||
|
||||
export default function ForgotPassword({username, link, code}) {
|
||||
interface Props {
|
||||
username: string;
|
||||
link: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
const ForgotPassword: FunctionComponent<Props> = ({ username, link, code }) => {
|
||||
return (
|
||||
<div>
|
||||
<Userbar />
|
||||
@ -30,7 +34,7 @@ export default function ForgotPassword({username, link, code}) {
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Code code={code} link={link} color={lightViolet} label={
|
||||
<Code code={code} link={link} color="lightViolet" label={
|
||||
<HTMLMessage {...messages.continue_image} />
|
||||
} />
|
||||
</td>
|
||||
@ -41,10 +45,6 @@ export default function ForgotPassword({username, link, code}) {
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ForgotPassword.propTypes = {
|
||||
username: PropTypes.string,
|
||||
link: PropTypes.string,
|
||||
code: PropTypes.string
|
||||
};
|
||||
|
||||
export default ForgotPassword;
|
@ -2,6 +2,6 @@ export default {
|
||||
default: {
|
||||
username: 'ErickSkrauch',
|
||||
code: 'I7SP06BUTLLM8MA03O',
|
||||
link: 'https://account.ely.by/activation/I7SP06BUTLLM8MA03O'
|
||||
link: 'https://account.ely.by/activation/I7SP06BUTLLM8MA03O',
|
||||
},
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
import ForgotPassword from './ForgotPassword';
|
||||
|
||||
export default ForgotPassword;
|
1
src/emails/forgotPassword/index.ts
Normal file
1
src/emails/forgotPassword/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './ForgotPassword';
|
@ -1,10 +1,9 @@
|
||||
export default {
|
||||
contentCenterCell: {
|
||||
textAlign: 'center'
|
||||
textAlign: 'center',
|
||||
},
|
||||
|
||||
paragraph: {
|
||||
fontSize: '16px',
|
||||
lineHeight: '125%'
|
||||
lineHeight: '125%',
|
||||
},
|
||||
};
|
@ -1,10 +1,8 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { FormattedMessage as Message, FormattedHTMLMessage as HTMLMessage } from 'react-intl';
|
||||
|
||||
import { Userbar, Header, Content, Footer } from 'components/layout';
|
||||
import { Table } from 'components/table';
|
||||
import { blue } from 'components/ui/colors';
|
||||
import { Code } from 'components/blocks';
|
||||
|
||||
import styles from './styles';
|
||||
@ -14,7 +12,13 @@ import violetManImage from './images/violetMan.png';
|
||||
import orangeManImage from './images/orangeMan.png';
|
||||
import darkBlueManImage from './images/darkBlueMan.png';
|
||||
|
||||
export default function Register({username, link, code}) {
|
||||
interface Props {
|
||||
username: string;
|
||||
link: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
const Register: FunctionComponent<Props> = ({ username, link, code }) => {
|
||||
return (
|
||||
<div>
|
||||
<Userbar />
|
||||
@ -34,7 +38,7 @@ export default function Register({username, link, code}) {
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Code code={code} link={link} color={blue} label={
|
||||
<Code code={code} link={link} color="blue" label={
|
||||
<HTMLMessage {...messages.confirm_email_image} />
|
||||
} />
|
||||
</td>
|
||||
@ -42,7 +46,7 @@ export default function Register({username, link, code}) {
|
||||
<tr>
|
||||
<td style={{
|
||||
...styles.contentCenterCell,
|
||||
...styles.whatsNextText
|
||||
...styles.whatsNextText,
|
||||
}}>
|
||||
<HTMLMessage {...messages.whats_next_image} />
|
||||
</td>
|
||||
@ -52,10 +56,7 @@ export default function Register({username, link, code}) {
|
||||
<Table>
|
||||
<tr>
|
||||
<td style={styles.todoItemIcon}>
|
||||
<img src={violetManImage} style={{
|
||||
width: '25px',
|
||||
verticalAlign: 'middle'
|
||||
}} />
|
||||
<img src={violetManImage} style={styles.todoItemIconImage} />
|
||||
</td>
|
||||
<td style={styles.todoItemContent}>
|
||||
<HTMLMessage {...messages.choose_you_skin_image} />
|
||||
@ -75,10 +76,7 @@ export default function Register({username, link, code}) {
|
||||
<Table>
|
||||
<tr>
|
||||
<td style={styles.todoItemIcon}>
|
||||
<img src={orangeManImage} style={{
|
||||
width: '25px',
|
||||
verticalAlign: 'middle'
|
||||
}} />
|
||||
<img src={orangeManImage} style={styles.todoItemIconImage} />
|
||||
</td>
|
||||
<td style={styles.todoItemContent}>
|
||||
<HTMLMessage {...messages.install_our_patch_image} />
|
||||
@ -98,10 +96,7 @@ export default function Register({username, link, code}) {
|
||||
<Table>
|
||||
<tr>
|
||||
<td style={styles.todoItemIcon}>
|
||||
<img src={darkBlueManImage} style={{
|
||||
width: '25px',
|
||||
verticalAlign: 'middle'
|
||||
}} />
|
||||
<img src={darkBlueManImage} style={styles.todoItemIconImage} />
|
||||
</td>
|
||||
<td style={styles.todoItemContent}>
|
||||
<HTMLMessage {...messages.useTLLauncher} />
|
||||
@ -122,10 +117,6 @@ export default function Register({username, link, code}) {
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Register.propTypes = {
|
||||
username: PropTypes.string,
|
||||
link: PropTypes.string,
|
||||
code: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Register;
|
@ -2,12 +2,11 @@ export default {
|
||||
default: {
|
||||
username: 'ErickSkrauch',
|
||||
code: 'I7SP06BUTLLM8MA03O',
|
||||
link: 'https://account.ely.by/activation/I7SP06BUTLLM8MA03O'
|
||||
link: 'https://account.ely.by/activation/I7SP06BUTLLM8MA03O',
|
||||
},
|
||||
|
||||
SleepWalker: {
|
||||
username: 'SleepWalker',
|
||||
code: 'TLLM8MA03OI7SP06BU',
|
||||
link: 'https://account.ely.by/activation/TLLM8MA03OI7SP06BU'
|
||||
}
|
||||
link: 'https://account.ely.by/activation/TLLM8MA03OI7SP06BU',
|
||||
},
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
import Register from './Register';
|
||||
|
||||
export default Register;
|
1
src/emails/register/index.ts
Normal file
1
src/emails/register/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './Register';
|
@ -1,28 +0,0 @@
|
||||
export default {
|
||||
contentCenterCell: {
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
paragraph: {
|
||||
fontSize: '16px',
|
||||
lineHeight: '125%'
|
||||
},
|
||||
|
||||
whatsNextText: {
|
||||
paddingTop: '30px'
|
||||
},
|
||||
|
||||
todoItem: {
|
||||
paddingTop: '30px'
|
||||
},
|
||||
todoItemIcon: {
|
||||
width: '46px',
|
||||
verticalAlign: 'top'
|
||||
},
|
||||
todoItemContent: {
|
||||
verticalAlign: 'top'
|
||||
},
|
||||
todoItemText: {
|
||||
paddingTop: '3px'
|
||||
}
|
||||
};
|
33
src/emails/register/styles.ts
Normal file
33
src/emails/register/styles.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
const styles: { [key: string]: CSSProperties } = {
|
||||
contentCenterCell: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
paragraph: {
|
||||
fontSize: '16px',
|
||||
lineHeight: '125%',
|
||||
},
|
||||
whatsNextText: {
|
||||
paddingTop: '30px',
|
||||
},
|
||||
todoItem: {
|
||||
paddingTop: '30px',
|
||||
},
|
||||
todoItemIcon: {
|
||||
width: '46px',
|
||||
verticalAlign: 'top',
|
||||
},
|
||||
todoItemIconImage: {
|
||||
width: '25px',
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
todoItemContent: {
|
||||
verticalAlign: 'top',
|
||||
},
|
||||
todoItemText: {
|
||||
paddingTop: '3px',
|
||||
},
|
||||
};
|
||||
|
||||
export default styles;
|
12
src/i18n/module.d.ts
vendored
Normal file
12
src/i18n/module.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
declare module 'i18n/index.json' {
|
||||
const content: {
|
||||
[key: string]: {
|
||||
code: string;
|
||||
name: string;
|
||||
englishName: string;
|
||||
progress: number;
|
||||
isReleased: boolean;
|
||||
},
|
||||
};
|
||||
export default content;
|
||||
}
|
@ -12,7 +12,7 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
|
||||
ReactDOM.render(
|
||||
<DevApp />,
|
||||
document.getElementById('app')
|
||||
document.getElementById('app'),
|
||||
);
|
||||
} else {
|
||||
const ReactDOMServer = require('react-dom/server');
|
||||
@ -20,7 +20,14 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
const App = require('App').default;
|
||||
|
||||
module.exports = {
|
||||
default(props) {
|
||||
default(props: {
|
||||
type: string;
|
||||
payload: {
|
||||
locale: string;
|
||||
[key: string]: string;
|
||||
};
|
||||
assetsHost?: string;
|
||||
}) {
|
||||
if (props.assetsHost) {
|
||||
// noinspection JSUnresolvedVariable
|
||||
__webpack_public_path__ = props.assetsHost.replace(/\/*$/, '/'); // eslint-disable-line
|
9
src/typings/file-loader.d.ts
vendored
Normal file
9
src/typings/file-loader.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
declare module "*.png" {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module "*.jpg" {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
9
src/typings/json-loader.d.ts
vendored
Normal file
9
src/typings/json-loader.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
declare module '*.intl.json' {
|
||||
const content: {
|
||||
[key: string]: {
|
||||
id: string;
|
||||
defaultMessage: string;
|
||||
},
|
||||
};
|
||||
export default content;
|
||||
}
|
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": [
|
||||
"es7",
|
||||
"dom",
|
||||
"dom.iterable"
|
||||
],
|
||||
"jsx": "preserve",
|
||||
"declaration": false,
|
||||
"skipLibCheck": false,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"baseUrl": "src",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
@ -4,6 +4,7 @@ const path = require('path');
|
||||
|
||||
const { ContextReplacementPlugin } = require('webpack');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||
|
||||
const SUPPORTED_LANGUAGES = Object.keys(require('./src/i18n/index.json'));
|
||||
|
||||
@ -31,7 +32,7 @@ module.exports = (env, { mode = 'development' }) => {
|
||||
path.join(__dirname, 'src'),
|
||||
path.join(__dirname, 'node_modules'),
|
||||
],
|
||||
extensions: ['.js', '.jsx'],
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
},
|
||||
|
||||
resolveLoader: {
|
||||
@ -49,33 +50,32 @@ module.exports = (env, { mode = 'development' }) => {
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new ContextReplacementPlugin(
|
||||
/i18n/, new RegExp(`/(${SUPPORTED_LANGUAGES.join('|')})\\.json`)
|
||||
),
|
||||
new ContextReplacementPlugin(
|
||||
/locale-data/, new RegExp(`/(${SUPPORTED_LANGUAGES.join('|')})\\.js`)
|
||||
),
|
||||
new ContextReplacementPlugin(/i18n/, new RegExp(`/(${SUPPORTED_LANGUAGES.join('|')})\\.json`)),
|
||||
new ContextReplacementPlugin(/locale-data/, new RegExp(`/(${SUPPORTED_LANGUAGES.join('|')})\\.js`)),
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'src/index.ejs',
|
||||
favicon: 'src/favicon.ico',
|
||||
filename: 'index.html',
|
||||
inject: false,
|
||||
}),
|
||||
new BundleAnalyzerPlugin({
|
||||
openAnalyzer: false,
|
||||
generateStatsFile: true,
|
||||
analyzerMode: isProduction ? 'static': 'server',
|
||||
}),
|
||||
],
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
test: /\.[jt]sx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
['@babel/preset-env', {
|
||||
targets: isProduction ? {
|
||||
node: '8',
|
||||
} : {
|
||||
@ -84,14 +84,13 @@ module.exports = (env, { mode = 'development' }) => {
|
||||
'last 1 firefox version',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'@babel/preset-react',
|
||||
{
|
||||
}],
|
||||
['@babel/preset-react', {
|
||||
development: !isProduction,
|
||||
},
|
||||
],
|
||||
}],
|
||||
['@babel/preset-typescript', {
|
||||
jsx: true,
|
||||
}],
|
||||
],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
|
Loading…
Reference in New Issue
Block a user