Adding some more controls & other clean-up

This commit is contained in:
John Lyon-Smith
2018-02-25 11:49:47 -08:00
parent 96fc7cb2c9
commit c60bfcedf8
44 changed files with 307 additions and 550 deletions

View File

@@ -1,5 +1,5 @@
{ {
"expoServerPort": 19000, "expoServerPort": 19000,
"packagerPort": 19001, "packagerPort": 19001,
"packagerPid": 7732 "packagerPid": 44581
} }

View File

@@ -1759,6 +1759,11 @@
"hoek": "4.2.0" "hoek": "4.2.0"
} }
}, },
"bowser": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.2.tgz",
"integrity": "sha512-fuiANC1Bqbqa/S4gmvfCt7bGBmNELMsGZj4Wg3PrP6esP66Ttoj1JSlzFlXtHyduMv07kDNmDsX6VsMWT/MLGg=="
},
"boxen": { "boxen": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-0.6.0.tgz", "resolved": "https://registry.npmjs.org/boxen/-/boxen-0.6.0.tgz",
@@ -2789,6 +2794,14 @@
"integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
"dev": true "dev": true
}, },
"css-in-js-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-2.0.0.tgz",
"integrity": "sha512-yuWmPMD9FLi50Xf3k8W8oO3WM1eVnxEGCldCLyfusQ+CgivFk0s23yst4ooW6tfxMuSa03S6uUEga9UhX6GRrA==",
"requires": {
"hyphenate-style-name": "1.0.2"
}
},
"css-loader": { "css-loader": {
"version": "0.28.1", "version": "0.28.1",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.1.tgz", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.1.tgz",
@@ -4034,6 +4047,11 @@
"merge": "1.2.0" "merge": "1.2.0"
} }
}, },
"exenv": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
"integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
},
"exit-hook": { "exit-hook": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
@@ -6215,6 +6233,11 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true "dev": true
}, },
"hyphenate-style-name": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz",
"integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es="
},
"iconv-lite": { "iconv-lite": {
"version": "0.4.19", "version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
@@ -6321,6 +6344,15 @@
"integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=",
"dev": true "dev": true
}, },
"inline-style-prefixer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-4.0.0.tgz",
"integrity": "sha1-MKA98bNGumsfuKgSvDydq+9IAi0=",
"requires": {
"bowser": "1.9.2",
"css-in-js-utils": "2.0.0"
}
},
"inquirer": { "inquirer": {
"version": "0.12.0", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
@@ -10404,6 +10436,16 @@
"integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=",
"dev": true "dev": true
}, },
"radium": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/radium/-/radium-0.22.0.tgz",
"integrity": "sha512-9zOYegr4gXfgDiVcf02Qyj8zzupmYSTtIhxvSU/42Ls1Q/+r1cisuGUUJ5m06Ha2cc/f3e5vMM80rj2l34Slew==",
"requires": {
"exenv": "1.2.2",
"inline-style-prefixer": "4.0.0",
"prop-types": "15.6.0"
}
},
"raf": { "raf": {
"version": "3.4.0", "version": "3.4.0",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz",

View File

@@ -9,6 +9,7 @@
"moment": "^2.18.1", "moment": "^2.18.1",
"papaparse": "^4.3.3", "papaparse": "^4.3.3",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"radium": "^0.22.0",
"rc-datepicker": "^5.0.7", "rc-datepicker": "^5.0.7",
"react": "^16.2.0", "react": "^16.2.0",
"react-data-grid": "^2.0.51", "react-data-grid": "^2.0.51",

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 910 B

View File

@@ -1,20 +1,10 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<title>Transition Management Resources</title> <title>Deighton AR</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png">
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.9/semantic.min.css">-->
<!--
Notice the use of %PUBLIC_URL% in the tag above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -1,35 +1,38 @@
import React from 'react' import React from 'react'
import './App.scss'
import { NavBar } from './Navigation'
import { Home } from './Home'
import { Login, Logout, ResetPassword, ForgotPassword, ConfirmEmail, ProtectedRoute } from './Auth' import { Login, Logout, ResetPassword, ForgotPassword, ConfirmEmail, ProtectedRoute } from './Auth'
import { Dashboard } from './Dashboard' import { Home } from './Home'
import { Profile } from './Profile' import { Profile } from './Profile'
import { Users } from './Users' import { Users } from './Users'
import { Footer } from './Footer' import { HolyGrail } from './ui'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom' import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import logoImage from 'images/logo.png'
export class App extends React.Component { export class App extends React.Component {
render() { render() {
return ( return (
<Router basename='/'> <HolyGrail>
<div className='App'> <HolyGrail.Header>
<NavBar /> <img src={logoImage} style={{ width: '50px', height: '50px', margin: '5px' }} />
<Switch> </HolyGrail.Header>
<Route exact path='/' component={Home} /> <HolyGrail.Body>
<Route path='/login' component={Login} /> <Router basename='/'>
<Route path='/confirm-email' component={ConfirmEmail} /> <Switch>
<Route path='/reset-password' component={ResetPassword} /> <Route path='/login' component={Login} />
<Route path='/forgot-password' component={ForgotPassword} /> <Route path='/confirm-email' component={ConfirmEmail} />
<ProtectedRoute path='/logout' component={Logout} /> <Route path='/reset-password' component={ResetPassword} />
<ProtectedRoute path='/profile' component={Profile} /> <Route path='/forgot-password' component={ForgotPassword} />
<ProtectedRoute roles={['administrator', 'normal']} path='/dashboard' component={Dashboard} /> <ProtectedRoute path='/logout' component={Logout} />
<ProtectedRoute roles={['administrator']} path='/users' component={Users} /> <ProtectedRoute path='/profile' component={Profile} />
<Route component={Home} />{/* No Match Route */} <ProtectedRoute roles={['administrator', 'normal']} path='/' component={Home} />
</Switch> <ProtectedRoute roles={['administrator']} path='/users' component={Users} />
<Footer /> <Route component={Home} />{/* No Match Route */}
</div> </Switch>
</Router> </Router>
</HolyGrail.Body>
<HolyGrail.Footer>
<div style={{ margin: '10px' }}>v1.0.0. Copyright &copy; 2018, Deighton.</div>
</HolyGrail.Footer>
</HolyGrail>
) )
} }
} }

View File

@@ -1,9 +0,0 @@
.App {
text-align: center;
}
@media screen and (max-width: 768px) {
html, body {
padding-top: 4em;
}
}

View File

@@ -4,9 +4,10 @@ import { Container, Header, Form, Message } from 'semantic-ui-react'
import './Login.scss' import './Login.scss'
import { regExpPattern } from 'regexp-pattern' import { regExpPattern } from 'regexp-pattern'
import { api } from '../helpers' import { api } from '../helpers'
import { Validator, ValidatedInput, ValidatedCheckbox, ValidatedButton } from '../Validated' import { Validator, ValidatedInput, ValidatedCheckbox } from '../Validated'
import { WaitDialog, MessageDialog } from '../Dialog' import { WaitDialog, MessageDialog } from '../Dialog'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { Button } from '../ui'
export class Login extends React.Component { export class Login extends React.Component {
static propTypes = { static propTypes = {
@@ -106,8 +107,9 @@ export class Login extends React.Component {
name='rememberMe' onChange={this.handleChange} validator={this.state.validator} name='rememberMe' onChange={this.handleChange} validator={this.state.validator}
message='Should we keep you logged in on this computer?' className='login-checkbox' /> message='Should we keep you logged in on this computer?' className='login-checkbox' />
</Form.Group> </Form.Group>
<ValidatedButton className='submit' name='submit' content='Submit' { /* <ValidatedButton className='submit' name='submit' content='Submit'
primary submit validator={this.state.validator} /> primary submit validator={this.state.validator} /> */ }
<Button>Login</Button>
<Message info> <Message info>
Please contact <a href='mailto:support@jamoki.com'>support@jamoki.com</a> to request login credentials. Please contact <a href='mailto:support@jamoki.com'>support@jamoki.com</a> to request login credentials.
</Message> </Message>

View File

@@ -1,31 +0,0 @@
import React from 'react'
import { Container } from 'semantic-ui-react'
import { ProjectList } from './ProjectList'
import { api } from '../helpers'
export class Dashboard extends React.Component {
constructor(props) {
super(props)
this.state = {
projects: []
}
}
componentDidMount() {
api.listDashboardProjects().then((list) => {
this.setState({
projects: list.items
})
}).catch((error) => {
console.error(error)
})
}
render() {
return (
<Container>
<ProjectList projects={this.state.projects} />
</Container>
)
}
}

View File

@@ -1,60 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Card, Image, Button, Icon, Popup } from 'semantic-ui-react'
import { Link } from 'react-router-dom'
import { Constants, api } from '../helpers'
import './ProjectCard.scss'
export class ProjectCard extends React.Component {
static propTypes = {
project: PropTypes.object.isRequired // TODO: Add required fields
}
render() {
let { project } = this.props
const corporationLink = `/corporations/${project.branch.corporation.fingerprint}`
const branchLink = corporationLink + `/branches/${project.branch.fingerprint}`
const projectLink = branchLink + `/projects/${project.fingerprint}`
return (
<Card className='project-card' fluid>
{/* Project/Corp Logo Link Section */}
<Card.Content>
<Image as={Link} to={corporationLink}
src={api.makeImageUrl(project.branch.corporation.imageId, Constants.logoImageSize)}
alt={project.branch.corporation.name} />
</Card.Content>
{/* Project Info Section */}
<Card.Content className='project-info'>
<Card.Header as={Link}
to={projectLink}
className='project-name' content={project.name} />
<Card.Description>
<Link to={branchLink}>{project.branch.name}</Link>
&nbsp;@&nbsp;
<Link to={corporationLink}>{project.branch.corporation.name}</Link>
</Card.Description>
</Card.Content>
{/* Project Link and Status Icon */}
<Card.Content className='project-links'>
<Button fluid as={Link} to={projectLink}
className='project-link' content='View Project' />
{ project.error
? <Popup trigger={<Icon name='check' size='large' />}
content='This project is underway with no errors!'
position='bottom left' />
: <Popup trigger={<Icon name='table' size='large' color='red' />}
content='The Client Data Sheet for this project has not been completed.'
position='bottom left' />
}
</Card.Content>
{/* Project Status Bar */}
<div className={`status in-progress`}>
In-Progress
</div>
</Card>
)
}
}

View File

@@ -1,55 +0,0 @@
.ui.card.project-card {
border-top: 2px solid #D4D4D5;
}
.status {
color: WhiteSmoke;
padding: 0.25em 1em;
text-align: right;
font-size: 0.85em;
text-transform: capitalize;
}
.in-progress { background-color: #CF414A; }
.sending { background-color: #D66C0A; }
.receiving { background-color: #0062AF; }
.project-card img {
height: 2.5em !important;
width: auto !important;
margin: 0.25em auto;
}
.project-info {
height: 7em !important;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.project-info a {
padding: 0.25em;
color: black;
border-radius: 5px;
}
.project-name.header { font-size: 1em !important; }
.project-links {
padding: 0 !important;
display: flex;
flex-direction: row;
align-items: center;
}
.project-links a {
background-color: transparent !important;
}
.project-links i.icon {
position: absolute;
right: 0.25em;
color: LightSlateGrey;
}

View File

@@ -1,32 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Grid } from 'semantic-ui-react'
import { ProjectCard } from './ProjectCard'
import './ProjectList.scss'
export class ProjectList extends React.Component {
static propTypes = {
projects: PropTypes.arrayOf(PropTypes.object)
}
render() {
let { projects } = this.props
return (
<div className='project-list'>
<Grid centered={(window.innerWidth <= 768)}>
<Grid.Column width={16} textAlign='left' className='project-list-heading'>
{projects.length} Projects Underway
</Grid.Column>
{this.props.projects
? projects.map((project, index) => (
<Grid.Column mobile={12} tablet={8} computer={4} textAlign='center' key={index}>
<ProjectCard project={project} />
</Grid.Column>))
: null
}
</Grid>
</div>
)
}
}

View File

@@ -1,11 +0,0 @@
.project-list {
margin: 3em 0 2em 0;
padding-bottom: 2em;
border-bottom: 1px solid Silver;
}
.project-list-heading {
font-size: 1.5em;
border-bottom: 1px solid Silver;
margin-bottom: 1em !important;
}

View File

@@ -1 +0,0 @@
export { Dashboard } from './Dashboard'

View File

@@ -1,169 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import { autoBind } from 'auto-bind2'
import { Menu, Image, Button, Dropdown } from 'semantic-ui-react'
import { Link, NavLink } from 'react-router-dom'
import logoImg from 'images/logo.png'
import { Constants, api } from '../helpers'
import './NavBar.scss'
export class NavBar extends React.Component {
static propTypes = {
activeItem: PropTypes.string
}
constructor() {
super()
autoBind(this, (name) => (name.startsWith('handle')))
this.state = {
activeItem: null
}
}
handleItemClick = (event, { name }) => this.setState({ activeItem: name })
handleUpdate() {
this.forceUpdate()
}
componentDidMount() {
api.addListener('login', this.handleUpdate)
api.addListener('logout', this.handleUpdate)
api.addListener('newThumbnailImage', this.handleUpdate)
}
componentWillUnmount() {
api.removeListener('login', this.handleUpdate)
api.removeListener('logout', this.handleUpdate)
api.addListener('newThumbnailImage', this.handleUpdate)
}
render() {
const { activeItem } = this.state
const user = api.loggedInUser
if (!user) {
if (window.innerWidth <= 768) {
return (
<Menu fluid inverted borderless fixed='top' size='large' id='MobileNavMenu'>
<Menu.Item>
<Image as={Link} to='/' src={logoImg} alt='Deighton Logo' size='tiny' centered />
</Menu.Item>
<Menu.Menu position='right'>
<Menu.Item>
<Button as={Link} to='/login' color='facebook' content='Login' />
</Menu.Item>
</Menu.Menu>
</Menu>
)
} else {
return (<Menu pointing stackable secondary id='NavMenu'>
<Menu.Item link href='/' active={activeItem === 'logo'} onClick={this.handleItemClick}>
<Image className='menu-logo' src={logoImg} alt='Deighton Logo' />
</Menu.Item>
<Menu.Item id='nav-item1' name='meetTheTeam' active={activeItem === 'meetTheTeam'} onClick={this.handleItemClick} />
<Menu.Item id='nav-item2' name='testimonials' active={activeItem === 'testimonials'} onClick={this.handleItemClick} />
<Menu.Item id='nav-item3' name='contactUs' active={activeItem === 'contactUs'} onClick={this.handleItemClick} />
<Menu.Menu position='right'>
<Button as={Link} to='/login' primary content='Login' id='login-button' />
</Menu.Menu>
</Menu>)
}
}
if (user.pending) {
return <div />
}
const userImageUrl = api.makeImageUrl(user.thumbnailImageId, Constants.smallUserImageSize)
const userName = user.firstName + ' ' + user.lastName
if (window.innerWidth <= 768) {
return (
user.role === 'broker'
? <Menu fluid inverted borderless fixed='top' size='large' id='MobileNavMenu'>
<Menu.Item>
<Image as={Link} to='/' src={logoImg} alt='Deighton Logo' size='tiny' centered />
</Menu.Item>
<Menu.Menu position='right'>
<Dropdown icon='content' item>
<Dropdown.Menu>
<Dropdown.Item as={Link} exact to='/'>Home</Dropdown.Item>
<Dropdown.Item as={Link} to='/broker-dashboard'>Dashboard</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item as={Link} to='/profile'>Profile</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item as={Link} to='/logout'>Logout</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</Menu.Menu>
</Menu>
: <Menu fluid inverted borderless fixed='top' size='large' id='MobileNavMenu'>
<Menu.Item>
<Image as={Link} to='/' src={logoImg} alt='Deighton Logo' size='tiny' centered />
</Menu.Item>
<Menu.Menu position='right'>
<Dropdown icon='content' item>
<Dropdown.Menu>
<Dropdown.Item as={Link} exact to='/'>Home</Dropdown.Item>
<Dropdown.Item as={Link} to='/dashboard'>Dashboard</Dropdown.Item>
<Dropdown.Item as={Link} to='/corporations'>Corporations</Dropdown.Item>
{ api.loggedInUser.role === 'administrator' || api.loggedInUser.role === 'executive'
? <Dropdown.Item as={Link} to='/forms'>Forms</Dropdown.Item>
: null
}
{ api.loggedInUser.role === 'administrator' || api.loggedInUser.role === 'executive'
? <Dropdown.Item as={Link} to='/users'>Users</Dropdown.Item>
: null
}
<Dropdown.Divider />
<Dropdown.Item as={Link} to='/profile'>Profile</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item as={Link} to='/logout'>Logout</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</Menu.Menu>
</Menu>
)
}
return (
user.role === 'broker'
? <Menu pointing secondary stackable id='NavMenu'>
<Menu.Item as={NavLink} activeClassName='nav-menu-active' exact to='/' name='home' active={activeItem === 'home'} onClick={this.handleItemClick} />
<Menu.Item as={NavLink} activeClassName='nav-menu-active' to='/broker-dashboard' name='dashboard' active={activeItem === 'dashboard'} onClick={this.handleItemClick} />
<Menu.Menu position='right'>
<div className='logged-in-user'>
<NavLink to='/profile' activeClassName='nav-menu-active'>
<Image avatar src={this.userImage} />
<span className='user-name'>{userName}</span>
</NavLink>
<Button as={Link} to='/logout' content='Logout' id='logout-button' />
</div>
</Menu.Menu>
</Menu>
: <Menu pointing secondary stackable id='NavMenu'>
<Menu.Item as={NavLink} activeClassName='nav-menu-active' exact to='/' name='home' active={activeItem === 'home'} onClick={this.handleItemClick} />
<Menu.Item as={NavLink} activeClassName='nav-menu-active' to='/dashboard' name='dashboard' active={activeItem === 'dashboard'} onClick={this.handleItemClick} />
<Menu.Item as={NavLink} activeClassName='nav-menu-active' to='/corporations' name='corporations' active={activeItem === 'corporations'} onClick={this.handleItemClick} />
{ api.loggedInUser.role === 'administrator' || api.loggedInUser.role === 'executive'
? <Menu.Item as={NavLink} activeClassName='nav-menu-active' to='/forms' name='forms' active={activeItem === 'forms'} onClick={this.handleItemClick} />
: null
}
{ api.loggedInUser.role === 'administrator' || api.loggedInUser.role === 'executive'
? <Menu.Item as={NavLink} activeClassName='nav-menu-active' to='/users' name='users' active={activeItem === 'users'} onClick={this.handleItemClick} />
: null
}
<Menu.Menu position='right'>
<div className='logged-in-user'>
<NavLink to='/profile' activeClassName='nav-menu-active'>
<Image avatar src={userImageUrl} />
<span className='user-name'>{userName}</span>
</NavLink>
<Button as={Link} to='/logout' content='Logout' id='logout-button' />
</div>
</Menu.Menu>
</Menu>
)
}
}

View File

@@ -1,116 +0,0 @@
/* === Nav Menu Stylesheet === */
#NavMenu {
background-color: #1b1b1b;
box-shadow: 0 0 20px 2px Grey;
}
#NavMenu a.item {
color: white;
align-self: flex-end;
}
#NavMenu a.item.nav-menu-active {
background-color: #2d2b2b;
height: 100%;
}
#NavMenu a.item.nav-menu-active:nth-child(n) { border-bottom: 0.25em solid #CF414A; }
#NavMenu a.item.nav-menu-active:nth-child(2n) { border-bottom: 0.25em solid #2185D0; }
#NavMenu a.item.nav-menu-active:nth-child(3n) { border-bottom: 0.25em solid #DB822E; }
#NavMenu a.item:hover { background-color: #444344; }
#NavMenu img.menu-logo {
height: 1em;
}
#login-button {
height: 60%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 1em;
margin: auto 1em;
background-color: #3f62ab;
}
#logout-button {
height: 60%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 1em;
margin: auto 1em;
background-color: silver;
}
.logged-in-user {
display: flex;
flex-direction: row;
align-items: center;
}
.logged-in-user a {
color: Silver;
margin-right: 1em;
}
.logged-in-user a:hover {
color: white;
}
.logged-in-user .user-name {
margin-left: 0.25em;
}
#nav-item1 { border-bottom: 5px solid #2e4d9a; }
#nav-item2 { border-bottom: 5px solid #db822e; }
#nav-item3 { border-bottom: 5px solid #cf414a; }
/* === Tablet-Specific Menu Styles === */
#MobileNavMenu {
border-radius: 0 !important;
border-bottom: 5px solid #db822e !important;
}
@media screen and (max-width: 992px) {
.user-name {
display: none;
}
}
/* === Mobile-Specific Menu Styles === */
@media screen and (max-width: 767px) {
#NavMenu {
font-size: 1em;
}
#NavMenu a.item {
text-align: center !important;
}
.logged-in-user {
width: 100%;
flex-direction: column;
align-items: flex-end;
}
.user-name {
display: inline;
}
.logged-in-user a {
width: 30%;
}
#logout-button {
width: 30%;
margin: 1.5em 0.5em 0.5em 0;
}
}

View File

@@ -1 +0,0 @@
export { NavBar } from './NavBar'

View File

@@ -1,13 +1,13 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Form, Popup, Checkbox } from 'semantic-ui-react' import { Form } from 'semantic-ui-react'
import { Checkbox } from '../ui'
// This is an example of a validated component with a value that can change itself, that cannot ever be invalid. // This is an example of a validated component with a value that can change itself, that cannot ever be invalid.
export class ValidatedCheckbox extends React.Component { export class ValidatedCheckbox extends React.Component {
static propTypes = { static propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
label: PropTypes.string, label: PropTypes.string,
width: PropTypes.number, width: PropTypes.number,
validator: PropTypes.object.isRequired, validator: PropTypes.object.isRequired,
@@ -39,9 +39,7 @@ export class ValidatedCheckbox extends React.Component {
render() { render() {
return ( return (
<Form.Field width={this.props.width} disabled={this.state.disabled} className={this.props.className}> <Form.Field width={this.props.width} disabled={this.state.disabled} className={this.props.className}>
<Popup content={this.props.message} position='bottom center' hoverable trigger={ <Checkbox value={!!this.state.value} name={this.props.name} label={this.props.label} />
<Checkbox checked={!!this.state.value} name={this.props.name} label={this.props.label}
onChange={this.handleChange} />} />
</Form.Field> </Form.Field>
) )
} }

View File

@@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Form, Popup, Input } from 'semantic-ui-react' import { Form } from 'semantic-ui-react'
import { Input } from '../ui'
// This is an example of a validated component with a value that changes itself // This is an example of a validated component with a value that changes itself
@@ -44,19 +45,14 @@ export class ValidatedInput extends React.Component {
return ( return (
<Form.Field error={!this.state.valid} width={this.props.width} disabled={this.state.disabled} className={this.props.className}> <Form.Field error={!this.state.valid} width={this.props.width} disabled={this.state.disabled} className={this.props.className}>
<label>{this.props.label}</label> <label>{this.props.label}</label>
{this.props.message <Input value={this.state.value}
? <Popup content={this.props.message} position='bottom center' hoverable trigger={ hidden={this.props.password}
<Input value={this.state.value} type={this.props.password ? 'password' : 'text'} name={this.props.name}
name={this.props.name} onChange={this.handleChange} placeholder={this.props.placeholder} onChange={this.handleChange}
className={this.props.className} icon={this.props.icon} iconPosition={this.props.iconPosition} />}
/>
: <Input value={this.state.value}
type={this.props.password ? 'password' : 'text'}
name={this.props.name} onChange={this.handleChange}
placeholder={this.props.placeholder} placeholder={this.props.placeholder}
className={this.props.className} icon={this.props.icon} className={this.props.className} icon={this.props.icon}
iconPosition={this.props.iconPosition} /> iconPosition={this.props.iconPosition} />
} <label>{this.props.message}</label>
</Form.Field> </Form.Field>
) )
} }

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" ?><svg enable-background="new 0 0 500 500" id="Layer_1" version="1.1" viewBox="0 0 500 500" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><g><path d="M427.9,402.1H72.1V128.4h355.9V402.1z M99.4,374.8h301.1v-219H99.4V374.8z"/></g><g><path d="M373.2,292.6H126.8c-30.2,0-54.8-24.6-54.8-54.8v-41.1h27.4v41.1c0,15.1,12.3,27.4,27.4,27.4h246.4 c15.1,0,27.4-12.3,27.4-27.4v-41.1h27.4v41.1C427.9,268.1,403.4,292.6,373.2,292.6z"/></g><g><path d="M304.8,155.8H195.2v-41.1c0-15.1,12.3-27.4,27.4-27.4h54.8c15.1,0,27.4,12.3,27.4,27.4V155.8z M222.6,128.4h54.8v-13.7 h-54.8V128.4z"/></g><g><rect height="41.1" width="27.4" x="318.4" y="210.5"/></g><g><rect height="41.1" width="27.4" x="154.2" y="210.5"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 784 B

View File

@@ -1,14 +1,6 @@
@import '~semantic-ui-css/semantic.min.css'; @import '~semantic-ui-css/semantic.min.css';
html, body { body #root {
margin: 0; min-height: 100vh;
font-family: sans-serif;
height: 100%;
position: relative; position: relative;
} }
#root {
min-height: 100%;
position: relative;
padding-bottom: 3em;
}

19
website/src/ui/Button.js Normal file
View File

@@ -0,0 +1,19 @@
import Radium from 'radium'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import style from './Button.style'
class Button extends Component {
static propTypes = {
submit: PropTypes.string,
children: PropTypes.node
}
render() {
return (
<button type={this.props.submit ? 'submit' : 'button'} style={style.base}>{this.props.children}</button>
)
}
}
export default Radium(Button)

View File

@@ -0,0 +1,17 @@
export default {
base: {
borderRadius: '10px',
fontFamily: 'Arial',
color: '#ffffff',
fontSize: '20px',
background: '#3498db',
padding: '10px 20px 10px 20px',
textDecoration: 'none',
outline: 'none',
':hover': {
background: '#3cb0fd',
textDecoration: 'none'
}
}
}

View File

@@ -0,0 +1,33 @@
import Radium from 'radium'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import style from './Checkbox.style'
import { reactAutoBind } from 'auto-bind2'
class Checkbox extends Component {
static propTypes = {
value: PropTypes.bool
}
constructor(props) {
super(props)
reactAutoBind(this)
this.state = {
checked: props.value
}
}
onClick() {
this.setState({ checked: !this.state.checked })
}
render() {
return (
<div style={[style.checkbox, !this.state.checked && style.checkboxUnchecked]} onClick={this.onClick}>
<div style={[style.checkmark, !this.state.checked && style.checkmarkUnchecked]} />
</div>
)
}
}
export default Radium(Checkbox)

View File

@@ -0,0 +1,36 @@
export default {
checkbox: {
cursor: 'pointer',
position: 'relative',
backgroundColor: '#2196F3',
top: 0,
left: 0,
height: 25,
width: 25
},
checkboxUnchecked: {
backgroundColor: '#E0E0E0',
':hover': {
backgroundColor: '#C0C0C0'
}
},
checkmark: {
position: 'absolute',
display: 'block',
content: '',
left: 10,
top: 5,
width: 6,
height: 12,
borderStyle: 'solid',
borderColor: '#FFFFFF',
borderWidth: '0 3px 3px 0',
transform: 'rotate(45deg)'
},
checkmarkUnchecked: {
display: 'none'
}
}

View File

@@ -0,0 +1,54 @@
import Radium from 'radium'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import style from './HolyGrail.style.js'
class HolyGrail extends Component {
static propTypes = {
children: PropTypes.node
}
render() {
return (
<div style={style.base}>{this.props.children}</div>
)
}
}
HolyGrail.Header = Radium(class HolyGrailHeader extends Component {
static propTypes = {
children: PropTypes.node
}
render() {
return (
<div style={style.header}>{this.props.children}</div>
)
}
})
HolyGrail.Footer = Radium(class HolyGrailFooter extends Component {
static propTypes = {
children: PropTypes.node
}
render() {
return (
<div style={style.footer}>{this.props.children}</div>
)
}
})
HolyGrail.Body = Radium(class HolyGrailBody extends Component {
static propTypes = {
children: PropTypes.node
}
render() {
return (
<div style={style.body}>{this.props.children}</div>
)
}
})
export default Radium(HolyGrail)

View File

@@ -0,0 +1,19 @@
export default {
base: {
display: 'flex',
minHeight: '100vh',
flexDirection: 'column'
},
body: {
display: 'flex',
flexGrow: 1
},
header: {
backgroundColor: '#FAFAFA',
borderBottom: '1px solid #B2B2B2'
},
footer: {
backgroundColor: '#FAFAFA',
borderTop: '1px solid #B2B2B2'
}
}

0
website/src/ui/Icon.js Normal file
View File

View File

0
website/src/ui/Image.js Normal file
View File

View File

19
website/src/ui/Input.js Normal file
View File

@@ -0,0 +1,19 @@
import Radium from 'radium'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import style from './Input.style'
class Input extends Component {
static propTypes = {
hidden: PropTypes.bool,
children: PropTypes.node
}
render() {
return (
<input type={this.props.hidden ? 'password' : 'text'} style={style.base}>{this.props.children}</input>
)
}
}
export default Radium(Input)

View File

@@ -0,0 +1,18 @@
export default {
base: {
padding: '5px',
fontSize: '16px',
borderWidth: '1px',
borderColor: '#b2b2b2',
backgroundColor: '#ffffff',
color: '#000000',
borderStyle: 'solid',
borderRadius: '5px',
// boxShadow: '0px 0px 0px rgba(66,66,66,.75)'
// textShadow: 'undefined 0px 0px 5px px rgba(66,66,66,.75)'
':focus': {
outline: 'none'
}
}
}

0
website/src/ui/Text.js Normal file
View File

View File

4
website/src/ui/index.js Normal file
View File

@@ -0,0 +1,4 @@
export { default as Button } from './Button'
export { default as Checkbox } from './Checkbox'
export { default as Input } from './Input'
export { default as HolyGrail } from './HolyGrail'