Added some basic shared components, utils, hooks

This commit is contained in:
ireic
2019-12-08 03:49:49 +01:00
parent 6be3ac2e77
commit 3143f66a0f
82 changed files with 40121 additions and 5 deletions

View File

@@ -0,0 +1,19 @@
import React from 'react';
import Toast from './Toast';
import Routes from './Routes';
import NormalizeStyles from './NormalizeStyles';
import FontStyles from './FontStyles';
import BaseStyles from './BaseStyles';
const App = () => (
<>
<NormalizeStyles />
<FontStyles />
<BaseStyles />
<Toast />
<Routes />
</>
);
export default App;

View File

@@ -0,0 +1,6 @@
import styled from 'styled-components';
export const Main = styled.main`
width: 100%;
padding-left: 75px;
`;

View File

@@ -0,0 +1,108 @@
import { createGlobalStyle } from 'styled-components';
import { color, font, mixin } from 'shared/utils/styles';
export default createGlobalStyle`
html, body, #root {
height: 100%;
min-height: 100%;
}
body {
color: ${color.textDarkest};
-webkit-tap-highlight-color: transparent;
line-height: 1.2;
${font.size(16)}
${font.regular}
}
#root {
display: flex;
flex-direction: column;
}
button,
input,
optgroup,
select,
textarea {
${font.regular}
}
*, *:after, *:before, input[type="search"] {
box-sizing: border-box;
}
a, a:hover, a:visited, a:active {
text-decoration: none;
}
ul {
list-style: none;
}
ul, li, ol, dd, h1, h2, h3, h4, h5, h6, p {
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, strong {
${font.bold}
}
button {
background: none;
border: none;
}
/* Workaround for IE11 focus highlighting for select elements */
select::-ms-value {
background: none;
color: #42413d;
}
[role="button"], button, input, select, textarea {
outline: none;
&:focus {
outline: none;
}
&:disabled {
opacity: 1;
}
}
[role="button"], button, input, textarea {
appearance: none;
}
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
select::-ms-expand {
display: none;
}
select option {
color: ${color.textDarkest};
}
p {
line-height: 1.6;
a {
${mixin.link()}
}
}
textarea {
line-height: 1.6;
}
body, select {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html {
touch-action: manipulation;
}
${mixin.placeholderColor(color.textLightBlue)}
`;

View File

@@ -0,0 +1,53 @@
import { createGlobalStyle } from 'styled-components';
import BlackWoff2 from 'shared/assets/fonts/CircularStd-Black.woff2';
import BoldWoff2 from 'shared/assets/fonts/CircularStd-Bold.woff2';
import MediumWoff2 from 'shared/assets/fonts/CircularStd-Medium.woff2';
import BookWoff2 from 'shared/assets/fonts/CircularStd-Book.woff2';
import BlackWoff from 'shared/assets/fonts/CircularStd-Black.woff';
import BoldWoff from 'shared/assets/fonts/CircularStd-Bold.woff';
import MediumWoff from 'shared/assets/fonts/CircularStd-Medium.woff';
import BookWoff from 'shared/assets/fonts/CircularStd-Book.woff';
import IconsSvg from 'shared/assets/icons/jira.svg';
import IconsTtf from 'shared/assets/icons/jira.ttf';
import IconsWoff from 'shared/assets/icons/jira.woff';
export default createGlobalStyle`
@font-face {
font-family: "CircularStdBlack";
src: url("${BlackWoff2}") format("woff2"),
url("${BlackWoff}") format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "CircularStdBold";
src: url("${BoldWoff2}") format("woff2"),
url("${BoldWoff}") format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "CircularStdMedium";
src: url("${MediumWoff2}") format("woff2"),
url("${MediumWoff}") format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "CircularStdBook";
src: url("${BookWoff2}") format("woff2"),
url("${BookWoff}") format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "jira";
src:
url("${IconsTtf}") format("truetype"),
url("${IconsWoff}") format("woff"),
url("${IconsSvg}#jira") format("svg");
font-weight: normal;
font-style: normal;
}
`;

View File

@@ -0,0 +1,107 @@
import styled from 'styled-components';
import { NavLink } from 'react-router-dom';
import { font, sizes, color, mixin, zIndexValues } from 'shared/utils/styles';
import Logo from 'shared/components/Logo';
export const NavLeft = styled.aside`
z-index: ${zIndexValues.navLeft};
position: absolute;
top: 0;
left: 0;
overflow-x: hidden;
height: 100%;
width: ${sizes.appNavBarLeftWidth}px;
background: ${color.primary};
transition: all 0.1s;
${mixin.hardwareAccelerate}
&:hover {
width: 260px;
box-shadow: 0 0 50px 0 rgba(0, 0, 0, 0.6);
}
`;
export const LogoLink = styled(NavLink)`
display: block;
position: relative;
left: 0;
margin: 40px 0 40px;
transition: left 0.1s;
&:before {
display: inline-block;
content: '';
position: absolute;
top: 0;
right: 0;
height: 50px;
width: 20px;
background: ${color.primary};
}
${NavLeft}:hover & {
left: 3px;
&:before {
display: none;
}
}
`;
export const StyledLogo = styled(Logo)`
display: inline-block;
margin-left: 13px;
padding: 10px;
${mixin.clickable}
`;
export const IconLink = styled(NavLink)`
display: block;
position: relative;
width: 100%;
height: 60px;
line-height: 60px;
padding-left: 67px;
color: rgba(255, 255, 255, 0.75);
transition: color 0.1s;
${mixin.clickable}
&:before {
content: '';
display: none;
position: absolute;
top: 5px;
right: 0;
height: 50px;
width: 5px;
background: #fff;
border-radius: 6px 0 0 6px;
}
&.active,
&:hover {
color: #fff;
}
&.active:before {
display: inline-block;
}
&:hover {
background: rgba(255, 255, 255, 0.1);
}
i {
position: absolute;
left: 27px;
}
`;
export const LinkText = styled.div`
position: relative;
right: 12px;
visibility: hidden;
opacity: 0;
text-transform: uppercase;
transition: all 0.1s;
transition-property: right, visibility, opacity;
${font.bold}
${font.size(12)}
${NavLeft}:hover & {
right: 0;
visibility: visible;
opacity: 1;
}
`;

View File

@@ -0,0 +1,26 @@
import React from 'react';
import { Icon } from 'shared/components';
import { NavLeft, LogoLink, StyledLogo, IconLink, LinkText } from './Styles';
const NavbarLeft = () => (
<NavLeft>
<LogoLink to="/">
<StyledLogo color="#fff" />
</LogoLink>
<IconLink to="/projects">
<Icon type="archive" size={16} />
<LinkText>Projects</LinkText>
</IconLink>
<IconLink to="/subcontractors">
<Icon type="briefcase" size={16} />
<LinkText>Subcontractors</LinkText>
</IconLink>
<IconLink to="/bids">
<Icon type="file-text" size={20} left={-2} />
<LinkText>Bids</LinkText>
</IconLink>
</NavLeft>
);
export default NavbarLeft;

View File

@@ -0,0 +1,152 @@
import { createGlobalStyle } from 'styled-components';
/** DO NOT ALTER THIS FILE. It is a copy of https://necolas.github.io/normalize.css/ */
export default createGlobalStyle`
html {
line-height: 1.15;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
}
main {
display: block;
}
h1 {
font-size: 2em;
margin: 0.67em 0;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
pre {
font-family: monospace, monospace;
font-size: 1em;
}
a {
background-color: transparent;
}
abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted;
}
b,
strong {
font-weight: bolder;
}
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
img {
border-style: none;
}
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
margin: 0;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
fieldset {
padding: 0.35em 0.75em 0.625em;
}
legend {
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
progress {
vertical-align: baseline;
}
textarea {
overflow: auto;
}
[type="checkbox"],
[type="radio"] {
box-sizing: border-box;
padding: 0;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
details {
display: block;
}
summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none;
}
`;

View File

@@ -0,0 +1,21 @@
import React from 'react';
import history from 'browserHistory';
import { Router, Switch, Route } from 'react-router-dom';
import PageNotFound from 'components/PageNotFound';
import NavbarLeft from './NavbarLeft';
import { Main } from './AppStyles';
const Routes = () => (
<Router history={history}>
<Main>
<NavbarLeft />
<Switch>
<Route component={PageNotFound} />
</Switch>
</Main>
</Router>
);
export default Routes;

View File

@@ -0,0 +1,58 @@
import styled from 'styled-components';
import { color, font, mixin, zIndexValues } from 'shared/utils/styles';
export const Container = styled.div`
z-index: ${zIndexValues.modal + 1};
position: fixed;
right: 30px;
top: 50px;
`;
export const StyledToast = styled.div`
position: relative;
margin-bottom: 5px;
width: 300px;
padding: 15px 20px;
border-radius: 4px;
color: #fff;
background: ${props => color[props.type]};
cursor: pointer;
transition: all 0.15s;
${mixin.clearfix}
${mixin.hardwareAccelerate}
&.jira-toast-enter,
&.jira-toast-exit.jira-toast-exit-active {
opacity: 0;
right: -10px;
}
&.jira-toast-exit,
&.jira-toast-enter.jira-toast-enter-active {
opacity: 1;
right: 0;
}
i {
position: absolute;
top: 13px;
right: 14px;
font-size: 22px;
cursor: pointer;
color: #fff;
}
`;
export const Title = styled.div`
padding-right: 22px;
${font.size(16)}
${font.medium}
`;
export const Message = styled.div`
padding: 8px 10px 0 0;
white-space: pre-wrap;
${font.size(14)}
${font.medium}
`;

View File

@@ -0,0 +1,62 @@
import React, { Component } from 'react';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import pubsub from 'sweet-pubsub';
import { uniqueId } from 'lodash';
import { Icon } from 'shared/components';
import { Container, StyledToast, Title, Message } from './Styles';
class Toast extends Component {
state = { toasts: [] };
componentDidMount() {
pubsub.on('toast', this.addToast);
}
componentWillUnmount() {
pubsub.off('toast', this.addToast);
}
addToast = ({ type = 'success', title, message, duration = 5 }) => {
const id = uniqueId('toast-');
this.setState(state => ({
toasts: [...state.toasts, { id, type, title, message }],
}));
if (duration) {
setTimeout(() => this.removeToast(id), duration * 1000);
}
};
removeToast = id => {
this.setState(state => ({
toasts: state.toasts.filter(toast => toast.id !== id),
}));
};
render() {
const { toasts } = this.state;
return (
<Container>
<TransitionGroup>
{toasts.map(toast => (
<CSSTransition key={toast.id} classNames="jira-toast" timeout={200}>
<StyledToast
key={toast.id}
type={toast.type}
onClick={() => this.removeToast(toast.id)}
>
<Icon type="close" />
{toast.title && <Title>{toast.title}</Title>}
{toast.message && <Message>{toast.message}</Message>}
</StyledToast>
</CSSTransition>
))}
</TransitionGroup>
</Container>
);
}
}
export default Toast;