Components: refactored UI components to use new state. Minor changes to exports and props
This commit is contained in:
parent
adc017c48d
commit
89d935e27f
16 changed files with 118 additions and 146 deletions
|
@ -2,55 +2,45 @@ import { Fragment } from 'react';
|
|||
import { Link } from 'react-router-dom';
|
||||
|
||||
import classes from './ActionButton.module.css';
|
||||
import Icon from '../../Icons/Icon/Icon';
|
||||
import { Icon } from '../..';
|
||||
|
||||
interface ComponentProps {
|
||||
interface Props {
|
||||
name: string;
|
||||
icon: string;
|
||||
link?: string;
|
||||
handler?: () => void;
|
||||
}
|
||||
|
||||
const ActionButton = (props: ComponentProps): JSX.Element => {
|
||||
export const ActionButton = (props: Props): JSX.Element => {
|
||||
const body = (
|
||||
<Fragment>
|
||||
<div className={classes.ActionButtonIcon}>
|
||||
<Icon icon={props.icon} />
|
||||
</div>
|
||||
<div className={classes.ActionButtonName}>
|
||||
{props.name}
|
||||
</div>
|
||||
<div className={classes.ActionButtonName}>{props.name}</div>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
if (props.link) {
|
||||
return (
|
||||
<Link
|
||||
to={props.link}
|
||||
tabIndex={0}>
|
||||
<Link to={props.link} tabIndex={0}>
|
||||
{body}
|
||||
</Link>
|
||||
)
|
||||
);
|
||||
} else if (props.handler) {
|
||||
return (
|
||||
<div
|
||||
className={classes.ActionButton}
|
||||
onClick={props.handler}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === 'Enter' && props.handler) props.handler()
|
||||
if (e.key === 'Enter' && props.handler) props.handler();
|
||||
}}
|
||||
tabIndex={0}
|
||||
>{body}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
className={classes.ActionButton}>
|
||||
>
|
||||
{body}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return <div className={classes.ActionButton}>{body}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default ActionButton;
|
||||
};
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
import classes from './Button.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
interface Props {
|
||||
children: string;
|
||||
click?: any;
|
||||
}
|
||||
|
||||
const Button = (props: ComponentProps): JSX.Element => {
|
||||
const {
|
||||
children,
|
||||
click
|
||||
} = props;
|
||||
export const Button = (props: Props): JSX.Element => {
|
||||
const { children, click } = props;
|
||||
|
||||
return (
|
||||
<button className={classes.Button} onClick={click ? click : () => {}} >
|
||||
<button className={classes.Button} onClick={click ? click : () => {}}>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default Button;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
import { ReactNode } from 'react';
|
||||
import classes from './InputGroup.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
children: JSX.Element | JSX.Element[];
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const InputGroup = (props: ComponentProps): JSX.Element => {
|
||||
return (
|
||||
<div className={classes.InputGroup}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default InputGroup;
|
||||
export const InputGroup = (props: Props): JSX.Element => {
|
||||
return <div className={classes.InputGroup}>{props.children}</div>;
|
||||
};
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
import { SyntheticEvent } from 'react';
|
||||
import { ReactNode, SyntheticEvent } from 'react';
|
||||
|
||||
import classes from './ModalForm.module.css';
|
||||
import Icon from '../../Icons/Icon/Icon';
|
||||
import { Icon } from '../..';
|
||||
|
||||
interface ComponentProps {
|
||||
children: JSX.Element | JSX.Element[];
|
||||
children: ReactNode;
|
||||
modalHandler?: () => void;
|
||||
formHandler: (e: SyntheticEvent<HTMLFormElement>) => void;
|
||||
}
|
||||
|
||||
const ModalForm = (props: ComponentProps): JSX.Element => {
|
||||
export const ModalForm = (props: ComponentProps): JSX.Element => {
|
||||
const _modalHandler = (): void => {
|
||||
if (props.modalHandler) {
|
||||
props.modalHandler();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.ModalForm}>
|
||||
<div className={classes.ModalFormIcon} onClick={_modalHandler}>
|
||||
<Icon icon='mdiClose' />
|
||||
<Icon icon="mdiClose" />
|
||||
</div>
|
||||
<form onSubmit={(e) => props.formHandler(e)}>
|
||||
{props.children}
|
||||
</form>
|
||||
<form onSubmit={(e) => props.formHandler(e)}>{props.children}</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModalForm;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { Fragment } from 'react';
|
||||
import { Fragment, ReactNode } from 'react';
|
||||
import classes from './Headline.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string | JSX.Element;
|
||||
subtitle?: ReactNode;
|
||||
}
|
||||
|
||||
const Headline = (props: ComponentProps): JSX.Element => {
|
||||
export const Headline = (props: Props): JSX.Element => {
|
||||
return (
|
||||
<Fragment>
|
||||
<h1 className={classes.HeadlineTitle}>{props.title}</h1>
|
||||
{props.subtitle && <p className={classes.HeadlineSubtitle}>{props.subtitle}</p>}
|
||||
{props.subtitle && (
|
||||
<p className={classes.HeadlineSubtitle}>{props.subtitle}</p>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
export default Headline;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,17 +2,15 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
import classes from './SectionHeadline.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
interface Props {
|
||||
title: string;
|
||||
link: string
|
||||
link: string;
|
||||
}
|
||||
|
||||
const SectionHeadline = (props: ComponentProps): JSX.Element => {
|
||||
export const SectionHeadline = (props: Props): JSX.Element => {
|
||||
return (
|
||||
<Link to={props.link}>
|
||||
<h2 className={classes.SectionHeadline}>{props.title}</h2>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default SectionHeadline;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,8 +4,6 @@ interface Props {
|
|||
text: string;
|
||||
}
|
||||
|
||||
const SettingsHeadline = (props: Props): JSX.Element => {
|
||||
export const SettingsHeadline = (props: Props): JSX.Element => {
|
||||
return <h2 className={classes.SettingsHeadline}>{props.text}</h2>;
|
||||
};
|
||||
|
||||
export default SettingsHeadline;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
.Icon {
|
||||
color: var(--color-primary);
|
||||
/* for settings */
|
||||
/* color: var(--color-background); */
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@ import classes from './Icon.module.css';
|
|||
|
||||
import { Icon as MDIcon } from '@mdi/react';
|
||||
|
||||
interface ComponentProps {
|
||||
interface Props {
|
||||
icon: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const Icon = (props: ComponentProps): JSX.Element => {
|
||||
export const Icon = (props: Props): JSX.Element => {
|
||||
const MDIcons = require('@mdi/js');
|
||||
let iconPath = MDIcons[props.icon];
|
||||
|
||||
|
@ -22,7 +22,5 @@ const Icon = (props: ComponentProps): JSX.Element => {
|
|||
path={iconPath}
|
||||
color={props.color ? props.color : 'var(--color-primary)'}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Icon;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,39 +1,32 @@
|
|||
import { useEffect } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Skycons } from 'skycons-ts';
|
||||
import { GlobalState, Theme } from '../../../../interfaces';
|
||||
import { State } from '../../../../store/reducers';
|
||||
import { IconMapping, TimeOfDay } from './IconMapping';
|
||||
|
||||
interface ComponentProps {
|
||||
theme: Theme;
|
||||
interface Props {
|
||||
weatherStatusCode: number;
|
||||
isDay: number;
|
||||
}
|
||||
|
||||
const WeatherIcon = (props: ComponentProps): JSX.Element => {
|
||||
export const WeatherIcon = (props: Props): JSX.Element => {
|
||||
const { theme } = useSelector((state: State) => state.theme);
|
||||
|
||||
const icon = props.isDay
|
||||
? new IconMapping().mapIcon(props.weatherStatusCode, TimeOfDay.day)
|
||||
: new IconMapping().mapIcon(props.weatherStatusCode, TimeOfDay.night);
|
||||
|
||||
useEffect(() => {
|
||||
const delay = setTimeout(() => {
|
||||
const skycons = new Skycons({'color': props.theme.colors.accent});
|
||||
const skycons = new Skycons({ color: theme.colors.accent });
|
||||
skycons.add(`weather-icon`, icon);
|
||||
skycons.play();
|
||||
}, 1);
|
||||
|
||||
return () => {
|
||||
clearTimeout(delay);
|
||||
}
|
||||
}, [props.weatherStatusCode, icon, props.theme.colors.accent]);
|
||||
};
|
||||
}, [props.weatherStatusCode, icon, theme.colors.accent]);
|
||||
|
||||
return <canvas id={`weather-icon`} width='50' height='50'></canvas>
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: GlobalState) => {
|
||||
return {
|
||||
theme: state.theme.theme
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(WeatherIcon);
|
||||
return <canvas id={`weather-icon`} width="50" height="50"></canvas>;
|
||||
};
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import { ReactNode } from 'react';
|
||||
import classes from './Layout.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
children: JSX.Element | JSX.Element[];
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const Container = (props: ComponentProps): JSX.Element => {
|
||||
return (
|
||||
<div className={classes.Container}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return <div className={classes.Container}>{props.children}</div>;
|
||||
};
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
import { MouseEvent, useRef } from 'react';
|
||||
import { MouseEvent, ReactNode, useRef } from 'react';
|
||||
|
||||
import classes from './Modal.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
setIsOpen: Function;
|
||||
children: JSX.Element;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const Modal = (props: ComponentProps): JSX.Element => {
|
||||
export const Modal = (props: Props): JSX.Element => {
|
||||
const modalRef = useRef(null);
|
||||
const modalClasses = [classes.Modal, props.isOpen ? classes.ModalOpen : classes.ModalClose].join(' ');
|
||||
const modalClasses = [
|
||||
classes.Modal,
|
||||
props.isOpen ? classes.ModalOpen : classes.ModalClose,
|
||||
].join(' ');
|
||||
|
||||
const clickHandler = (e: MouseEvent) => {
|
||||
if (e.target === modalRef.current) {
|
||||
props.setIsOpen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={modalClasses} onClick={clickHandler} ref={modalRef}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Modal;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { clearNotification } from '../../../store/actions';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { actionCreators } from '../../../store';
|
||||
|
||||
import classes from './Notification.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
interface Props {
|
||||
title: string;
|
||||
message: string;
|
||||
id: number;
|
||||
url: string | null;
|
||||
clearNotification: (id: number) => void;
|
||||
}
|
||||
|
||||
const Notification = (props: ComponentProps): JSX.Element => {
|
||||
export const Notification = (props: Props): JSX.Element => {
|
||||
const dispatch = useDispatch();
|
||||
const { clearNotification } = bindActionCreators(actionCreators, dispatch);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const elementClasses = [
|
||||
classes.Notification,
|
||||
|
@ -24,13 +27,13 @@ const Notification = (props: ComponentProps): JSX.Element => {
|
|||
setIsOpen(false);
|
||||
}, 3500);
|
||||
|
||||
const clearNotification = setTimeout(() => {
|
||||
props.clearNotification(props.id);
|
||||
const clearNotificationTimeout = setTimeout(() => {
|
||||
clearNotification(props.id);
|
||||
}, 3600);
|
||||
|
||||
return () => {
|
||||
window.clearTimeout(closeNotification);
|
||||
window.clearTimeout(clearNotification);
|
||||
window.clearTimeout(clearNotificationTimeout);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
@ -48,5 +51,3 @@ const Notification = (props: ComponentProps): JSX.Element => {
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(null, { clearNotification })(Notification);
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import classes from './Spinner.module.css';
|
||||
|
||||
const Spinner = (): JSX.Element => {
|
||||
export const Spinner = (): JSX.Element => {
|
||||
return (
|
||||
<div className={classes.SpinnerWrapper}>
|
||||
<div className={classes.Spinner}>Loading...</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Spinner;
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
import classes from './Table.module.css';
|
||||
|
||||
interface ComponentProps {
|
||||
children: JSX.Element | JSX.Element[];
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
headers: string[];
|
||||
innerRef?: any;
|
||||
}
|
||||
|
||||
const Table = (props: ComponentProps): JSX.Element => {
|
||||
export const Table = (props: Props): JSX.Element => {
|
||||
return (
|
||||
<div className={classes.TableContainer} ref={props.innerRef}>
|
||||
<table className={classes.Table}>
|
||||
<thead className={classes.TableHead}>
|
||||
<tr>
|
||||
{props.headers.map((header: string, index: number): JSX.Element => (<th key={index}>{header}</th>))}
|
||||
{props.headers.map(
|
||||
(header: string, index: number): JSX.Element => (
|
||||
<th key={index}>{header}</th>
|
||||
)
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className={classes.TableBody}>
|
||||
{props.children}
|
||||
</tbody>
|
||||
<tbody className={classes.TableBody}>{props.children}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Table;
|
||||
);
|
||||
};
|
||||
|
|
14
client/src/components/UI/index.ts
Normal file
14
client/src/components/UI/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
export * from './Table/Table';
|
||||
export * from './Spinner/Spinner';
|
||||
export * from './Notification/Notification';
|
||||
export * from './Modal/Modal';
|
||||
export * from './Layout/Layout';
|
||||
export * from './Icons/Icon/Icon';
|
||||
export * from './Icons/WeatherIcon/WeatherIcon';
|
||||
export * from './Headlines/Headline/Headline';
|
||||
export * from './Headlines/SectionHeadline/SectionHeadline';
|
||||
export * from './Headlines/SettingsHeadline/SettingsHeadline';
|
||||
export * from './Forms/InputGroup/InputGroup';
|
||||
export * from './Forms/ModalForm/ModalForm';
|
||||
export * from './Buttons/ActionButton/ActionButton';
|
||||
export * from './Buttons/Button/Button';
|
Loading…
Reference in a new issue