mirror of https://github.com/mitchell/mjfs.us.git
Migrate project from JS+Flow to TypeScript
This commit is contained in:
parent
60a557f918
commit
356b95579e
|
@ -1,11 +0,0 @@
|
||||||
extends:
|
|
||||||
- 'standard'
|
|
||||||
- 'plugin:react/recommended'
|
|
||||||
- 'plugin:flowtype/recommended'
|
|
||||||
- 'prettier'
|
|
||||||
- 'prettier/flowtype'
|
|
||||||
- 'prettier/react'
|
|
||||||
- 'prettier/standard'
|
|
||||||
plugins:
|
|
||||||
- react
|
|
||||||
- flowtype
|
|
12
.flowconfig
12
.flowconfig
|
@ -1,12 +0,0 @@
|
||||||
[ignore]
|
|
||||||
|
|
||||||
[include]
|
|
||||||
|
|
||||||
[libs]
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
all=warn
|
|
||||||
|
|
||||||
[options]
|
|
||||||
|
|
||||||
[strict]
|
|
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
|
@ -3,13 +3,19 @@
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome": "^1.1.8",
|
"@fortawesome/fontawesome-svg-core": "^1.2.22",
|
||||||
"@fortawesome/fontawesome-free-solid": "^5.0.13",
|
"@fortawesome/free-solid-svg-icons": "^5.10.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.0.19",
|
"@fortawesome/react-fontawesome": "^0.1.4",
|
||||||
|
"@types/jest": "^24.0.18",
|
||||||
|
"@types/node": "^12.7.3",
|
||||||
|
"@types/react": "^16.9.2",
|
||||||
|
"@types/react-dom": "^16.9.0",
|
||||||
|
"@types/react-router-dom": "^4.3.5",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-router-dom": "^4.3.1",
|
"react-router-dom": "^4.3.1",
|
||||||
"react-scripts": "^3.0.1"
|
"react-scripts": "^3.0.1",
|
||||||
|
"typescript": "^3.5.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
@ -18,17 +24,9 @@
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"csslint": "^1.0.5",
|
"prettier": "^1.17.1",
|
||||||
"eslint-config-prettier": "^2.10.0",
|
"tslint": "^5.19.0",
|
||||||
"eslint-config-standard": "^11.0.0",
|
"tslint-config-prettier": "^1.18.0"
|
||||||
"eslint-plugin-flowtype": "^2.50.3",
|
|
||||||
"eslint-plugin-import": "^2.17.3",
|
|
||||||
"eslint-plugin-node": "^6.0.1",
|
|
||||||
"eslint-plugin-promise": "^3.8.0",
|
|
||||||
"eslint-plugin-react": "^7.13.0",
|
|
||||||
"eslint-plugin-standard": "^3.1.0",
|
|
||||||
"flow-bin": "^0.76.0",
|
|
||||||
"prettier": "^1.17.1"
|
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
">0.2%",
|
">0.2%",
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import Header from './components/Header'
|
|
||||||
import Navbar from './components/Navbar'
|
|
||||||
import Routes from './routes'
|
|
||||||
|
|
||||||
import './Website.css'
|
|
||||||
|
|
||||||
type Props = {}
|
|
||||||
|
|
||||||
class Website extends React.Component<Props> {
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='website'>
|
|
||||||
<div className='main-container'>
|
|
||||||
<Navbar />
|
|
||||||
<Header />
|
|
||||||
<Routes />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Website
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React from 'react'
|
import React from "react"
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from "react-dom"
|
||||||
import Website from './Website.js'
|
import Website from "./Website"
|
||||||
|
|
||||||
it('renders without crashing', () => {
|
it("renders without crashing", () => {
|
||||||
const div = document.createElement('div')
|
const div = document.createElement("div")
|
||||||
ReactDOM.render(<Website />, div)
|
ReactDOM.render(<Website />, div)
|
||||||
ReactDOM.unmountComponentAtNode(div)
|
ReactDOM.unmountComponentAtNode(div)
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import Header from "./components/Header"
|
||||||
|
import Navbar from "./components/Navbar"
|
||||||
|
import Routes from "./routes"
|
||||||
|
|
||||||
|
import "./Website.css"
|
||||||
|
|
||||||
|
export default class Website extends React.Component {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="website">
|
||||||
|
<div className="main-container">
|
||||||
|
<Navbar />
|
||||||
|
<Header />
|
||||||
|
<Routes />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
href: string,
|
|
||||||
children: string
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClearButton extends React.PureComponent<Props> {
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<a className='clear-button' href={this.props.href}>
|
|
||||||
{this.props.children}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ClearButton
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
href: string
|
||||||
|
children: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ClearButton extends React.PureComponent<Props> {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<a className="clear-button" href={this.props.href}>
|
||||||
|
{this.props.children}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import SmallText from '../SmallText'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
|
|
||||||
type Props = {}
|
|
||||||
|
|
||||||
class Header extends React.PureComponent<Props> {
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='header-container'>
|
|
||||||
<h2>Mitchell J. F. Simon</h2>
|
|
||||||
<SmallText>
|
|
||||||
Software engineer;
|
|
||||||
<span style={{ display: 'inline-block' }}>
|
|
||||||
cloud-native web services and clients
|
|
||||||
</span>
|
|
||||||
</SmallText>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Header
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import SmallText from "../SmallText"
|
||||||
|
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
export default class Header extends React.PureComponent {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="header-container">
|
||||||
|
<h2>Mitchell J. F. Simon</h2>
|
||||||
|
<SmallText>
|
||||||
|
Software engineer;
|
||||||
|
<span style={{ display: "inline-block" }}>
|
||||||
|
cloud-native web services and clients
|
||||||
|
</span>
|
||||||
|
</SmallText>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as React from 'react'
|
|
||||||
|
|
||||||
import SmallText from '../../components/SmallText'
|
|
||||||
import './index.css'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
title: string,
|
|
||||||
company: string,
|
|
||||||
timeSpan: string,
|
|
||||||
bullets: Array<string>
|
|
||||||
}
|
|
||||||
|
|
||||||
class Experience extends React.PureComponent<Props> {
|
|
||||||
listedBullets: Array<React.Element<string>>
|
|
||||||
|
|
||||||
constructor (props: Props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.listedBullets = this.props.bullets.map((bullet, index) => (
|
|
||||||
<li key={index}>{bullet}</li>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='job-container'>
|
|
||||||
<div className='job-title'>{this.props.title}</div>
|
|
||||||
<div className='job-company'>{this.props.company}</div>
|
|
||||||
<SmallText>{this.props.timeSpan}</SmallText>
|
|
||||||
<ul>{this.listedBullets}</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Experience
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import SmallText from "../../components/SmallText"
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title: string
|
||||||
|
company: string
|
||||||
|
timeSpan: string
|
||||||
|
bullets: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Experience extends React.PureComponent<Props> {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="job-container">
|
||||||
|
<div className="job-title">{this.props.title}</div>
|
||||||
|
<div className="job-company">{this.props.company}</div>
|
||||||
|
<SmallText>{this.props.timeSpan}</SmallText>
|
||||||
|
<ul>{this.renderBullets()}</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
private renderBullets() {
|
||||||
|
return this.props.bullets.map((bullet, index) => (
|
||||||
|
<li key={index}>{bullet}</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,88 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as React from 'react'
|
|
||||||
import { NavLink } from 'react-router-dom'
|
|
||||||
import FontAwesomeIcon from '@fortawesome/react-fontawesome'
|
|
||||||
import faBars from '@fortawesome/fontawesome-free-solid/faBars'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
import { routes } from '../../routes/routes.js'
|
|
||||||
|
|
||||||
const changeMenu = 800
|
|
||||||
|
|
||||||
type Props = {}
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
showMenu: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
class Navbar extends React.Component<Props, State> {
|
|
||||||
buttons: Array<NavLink<string>>
|
|
||||||
|
|
||||||
constructor (props: Props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
if (window.innerWidth <= changeMenu) {
|
|
||||||
this.state = { showMenu: false }
|
|
||||||
} else {
|
|
||||||
this.state = { showMenu: true }
|
|
||||||
}
|
|
||||||
|
|
||||||
this.buttons = routes.map(route => (
|
|
||||||
<NavLink
|
|
||||||
key={route.name}
|
|
||||||
className='navbar-menu-button'
|
|
||||||
activeClassName='active-button'
|
|
||||||
exact={route.exact}
|
|
||||||
to={route.path}
|
|
||||||
onClick={this.closeMenu}
|
|
||||||
>
|
|
||||||
{route.name}
|
|
||||||
</NavLink>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
isMobile = () => window.innerWidth <= changeMenu
|
|
||||||
|
|
||||||
closeMenu = () => {
|
|
||||||
window.scrollTo(0, 0)
|
|
||||||
if (this.isMobile()) {
|
|
||||||
this.setState({ showMenu: false })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleMenu = () => {
|
|
||||||
if (this.isMobile() || !this.state.showMenu) {
|
|
||||||
this.setState(prev => ({ showMenu: !prev.showMenu }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
let menuButton: ?React.Element<string>
|
|
||||||
|
|
||||||
if (this.isMobile()) {
|
|
||||||
menuButton = (
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
this.state.showMenu
|
|
||||||
? 'navbar-button navbar-button-closed'
|
|
||||||
: 'navbar-button'
|
|
||||||
}
|
|
||||||
onClick={this.toggleMenu}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faBars} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='navbar'>
|
|
||||||
{menuButton}
|
|
||||||
{this.state.showMenu ? (
|
|
||||||
<div className='navbar-menu'>{this.buttons}</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Navbar
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { faBars } from "@fortawesome/free-solid-svg-icons"
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
|
import * as React from "react"
|
||||||
|
import { NavLink } from "react-router-dom"
|
||||||
|
|
||||||
|
import { routes } from "../../routes/routes"
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
showMenu: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class Navbar extends React.Component<{}, State> {
|
||||||
|
constructor(props: {}) {
|
||||||
|
super(props)
|
||||||
|
this.state = { showMenu: !this.isMobile() }
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
let menuButton: JSX.Element | null = null
|
||||||
|
|
||||||
|
if (this.isMobile()) {
|
||||||
|
menuButton = (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
this.state.showMenu
|
||||||
|
? "navbar-button navbar-button-closed"
|
||||||
|
: "navbar-button"
|
||||||
|
}
|
||||||
|
onClick={this.toggleMenu}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faBars} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="navbar">
|
||||||
|
{menuButton}
|
||||||
|
{this.state.showMenu ? (
|
||||||
|
<div className="navbar-menu">{this.renderButtons()}</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private isMobile() {
|
||||||
|
const mobileMenuMaximum = 800
|
||||||
|
return window.innerWidth <= mobileMenuMaximum
|
||||||
|
}
|
||||||
|
|
||||||
|
private toggleMenu() {
|
||||||
|
if (this.isMobile() || !this.state.showMenu) {
|
||||||
|
this.setState(prev => ({ showMenu: !prev.showMenu }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderButtons() {
|
||||||
|
return routes.map(route => (
|
||||||
|
<NavLink
|
||||||
|
key={route.name}
|
||||||
|
className="navbar-menu-button"
|
||||||
|
activeClassName="active-button"
|
||||||
|
exact={route.exact}
|
||||||
|
to={route.path}
|
||||||
|
onClick={this.closeMenu}
|
||||||
|
>
|
||||||
|
{route.name}
|
||||||
|
</NavLink>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
private closeMenu() {
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
if (this.isMobile()) {
|
||||||
|
this.setState({ showMenu: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Navbar
|
|
@ -1,42 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as React from 'react'
|
|
||||||
|
|
||||||
import ClearButton from '../../components/ClearButton'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
|
|
||||||
type Badge = {
|
|
||||||
imgUrl: string,
|
|
||||||
linkUrl: string,
|
|
||||||
alt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
title: string,
|
|
||||||
children: string,
|
|
||||||
repoUrl: string,
|
|
||||||
badges: Array<Badge>
|
|
||||||
}
|
|
||||||
|
|
||||||
class Project extends React.PureComponent<Props> {
|
|
||||||
renderBadges = (badges: Array<Badge>) => {
|
|
||||||
return this.props.badges.map((badge, index) => (
|
|
||||||
<a className='project-badge' href={badge.linkUrl} key={index}>
|
|
||||||
<img src={badge.imgUrl} alt={badge.alt} />
|
|
||||||
</a>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='project-container'>
|
|
||||||
<h4>{this.props.title}</h4>
|
|
||||||
{this.renderBadges(this.props.badges)}
|
|
||||||
<p>{this.props.children}</p>
|
|
||||||
<ClearButton href={this.props.repoUrl}>Repository</ClearButton>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Project
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import ClearButton from "../../components/ClearButton"
|
||||||
|
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
type Badge = {
|
||||||
|
imgUrl: string
|
||||||
|
linkUrl: string
|
||||||
|
alt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title: string
|
||||||
|
children: string
|
||||||
|
repoUrl: string
|
||||||
|
badges: Badge[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Project extends React.PureComponent<Props> {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="project-container">
|
||||||
|
<h4>{this.props.title}</h4>
|
||||||
|
{this.renderBadges(this.props.badges)}
|
||||||
|
<p>{this.props.children}</p>
|
||||||
|
<ClearButton href={this.props.repoUrl}>Repository</ClearButton>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderBadges(badges: Badge[]) {
|
||||||
|
return this.props.badges.map((badge, index) => (
|
||||||
|
<a className="project-badge" href={badge.linkUrl} key={index}>
|
||||||
|
<img src={badge.imgUrl} alt={badge.alt} />
|
||||||
|
</a>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
children: string
|
|
||||||
}
|
|
||||||
|
|
||||||
class SmallText extends React.PureComponent<Props> {
|
|
||||||
render () {
|
|
||||||
return <div className='small-text'>{this.props.children}</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SmallText
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// @flow
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
export default class SmallText extends React.PureComponent {
|
||||||
|
public render() {
|
||||||
|
return <div className="small-text">{this.props.children}</div>
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
declare module "*.webp" {
|
||||||
|
const value: any
|
||||||
|
export default value
|
||||||
|
}
|
15
src/index.js
15
src/index.js
|
@ -1,15 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import ReactDOM from 'react-dom'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
import Website from './Website'
|
|
||||||
import registerServiceWorker from './registerServiceWorker'
|
|
||||||
|
|
||||||
ReactDOM.render(
|
|
||||||
<BrowserRouter>
|
|
||||||
<Website />
|
|
||||||
</BrowserRouter>,
|
|
||||||
document.getElementById('root')
|
|
||||||
)
|
|
||||||
registerServiceWorker()
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import React from "react"
|
||||||
|
import ReactDOM from "react-dom"
|
||||||
|
import { BrowserRouter } from "react-router-dom"
|
||||||
|
|
||||||
|
import "./index.css"
|
||||||
|
import registerServiceWorker from "./registerServiceWorker"
|
||||||
|
import Website from "./Website"
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<BrowserRouter>
|
||||||
|
<Website />
|
||||||
|
</BrowserRouter>,
|
||||||
|
document.getElementById("root")
|
||||||
|
)
|
||||||
|
registerServiceWorker()
|
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="react-scripts" />
|
|
@ -1,40 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react'
|
|
||||||
import { Route, Switch } from 'react-router-dom'
|
|
||||||
|
|
||||||
import { routes, redirects } from './routes.js'
|
|
||||||
|
|
||||||
type Props = {}
|
|
||||||
|
|
||||||
class Routes extends React.Component<Props> {
|
|
||||||
routes: Array<Route>
|
|
||||||
redirects: Array<Route>
|
|
||||||
|
|
||||||
constructor (props: Props) {
|
|
||||||
super(props)
|
|
||||||
|
|
||||||
this.routes = routes.map(route => (
|
|
||||||
<Route
|
|
||||||
key={route.name}
|
|
||||||
exact={route.exact}
|
|
||||||
path={route.path}
|
|
||||||
component={route.component}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
|
|
||||||
this.redirects = redirects.map(route => (
|
|
||||||
<Route key={route.path} path={route.path} render={route.func} />
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<Switch>
|
|
||||||
{this.routes}
|
|
||||||
{this.redirects}
|
|
||||||
</Switch>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Routes
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import React from "react"
|
||||||
|
import { Route, Switch } from "react-router-dom"
|
||||||
|
|
||||||
|
import { redirects, routes } from "./routes"
|
||||||
|
|
||||||
|
export default class Routes extends React.Component {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<Switch>
|
||||||
|
{this.renderRoutes()}
|
||||||
|
{this.renderRedirects()}
|
||||||
|
</Switch>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderRoutes() {
|
||||||
|
return routes.map(route => (
|
||||||
|
<Route
|
||||||
|
key={route.name}
|
||||||
|
exact={route.exact}
|
||||||
|
path={route.path}
|
||||||
|
component={route.component}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderRedirects() {
|
||||||
|
return redirects.map(route => (
|
||||||
|
<Route key={route.path} path={route.path} render={route.func} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
// @flow
|
|
||||||
import Home from '../screens/Home'
|
|
||||||
import Projects from '../screens/Projects'
|
|
||||||
import Contact from '../screens/Contact'
|
|
||||||
|
|
||||||
const routes = [
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
name: 'Home',
|
|
||||||
component: Home,
|
|
||||||
exact: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/projects',
|
|
||||||
name: 'Projects',
|
|
||||||
component: Projects,
|
|
||||||
exact: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/contact',
|
|
||||||
name: 'Contact',
|
|
||||||
component: Contact,
|
|
||||||
exact: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const redirects = [
|
|
||||||
{
|
|
||||||
path: '/linkedin',
|
|
||||||
func: () => (window.location = 'https://linkedin.com/in/mitchelljfsimon')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
export { routes, redirects }
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import Contact from "../screens/Contact"
|
||||||
|
import Home from "../screens/Home"
|
||||||
|
import Projects from "../screens/Projects"
|
||||||
|
|
||||||
|
export const routes = [
|
||||||
|
{
|
||||||
|
component: Home,
|
||||||
|
exact: true,
|
||||||
|
name: "Home",
|
||||||
|
path: "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: Projects,
|
||||||
|
exact: false,
|
||||||
|
name: "Projects",
|
||||||
|
path: "/projects"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: Contact,
|
||||||
|
exact: false,
|
||||||
|
name: "Contact",
|
||||||
|
path: "/contact"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const redirects = [
|
||||||
|
{
|
||||||
|
func: () => {
|
||||||
|
window.location.replace("https://linkedin.com/in/mitchelljfsimon")
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
path: "/linkedin"
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,22 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
import linkedIn from '../../images/In-2C-128px-TM.png'
|
|
||||||
|
|
||||||
type Props = {}
|
|
||||||
|
|
||||||
class Contact extends React.PureComponent<Props> {
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='contact-container'>
|
|
||||||
<p>m@mjfs.us</p>
|
|
||||||
<a href='https://www.linkedin.com/in/mitchelljfsimon/'>
|
|
||||||
<img src={linkedIn} alt='LinkedIn' />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Contact
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import linkedIn from "../../images/In-2C-128px-TM.png"
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
export default class Contact extends React.PureComponent {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="contact-container">
|
||||||
|
<p>m@mjfs.us</p>
|
||||||
|
<a href="https://www.linkedin.com/in/mitchelljfsimon/">
|
||||||
|
<img src={linkedIn} alt="LinkedIn" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as React from 'react'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
import JobComponent from '../../components/Job'
|
|
||||||
|
|
||||||
import jobsData from '../../data/jobs.json'
|
|
||||||
|
|
||||||
type Props = {}
|
|
||||||
|
|
||||||
type Job = {
|
|
||||||
timeSpan: string,
|
|
||||||
title: string,
|
|
||||||
company: string,
|
|
||||||
bullets: Array<string>
|
|
||||||
}
|
|
||||||
|
|
||||||
class Experience extends React.PureComponent<Props> {
|
|
||||||
renderJobs = (jobs: Array<Job>) => {
|
|
||||||
return jobs.map(job => (
|
|
||||||
<JobComponent
|
|
||||||
key={job.title}
|
|
||||||
title={job.title}
|
|
||||||
company={job.company}
|
|
||||||
timeSpan={job.timeSpan}
|
|
||||||
bullets={job.bullets}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='experience-container'>{this.renderJobs(jobsData)}</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Experience
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import Job from "../../components/Job"
|
||||||
|
import jobsData from "../../data/jobs.json"
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
type JobData = {
|
||||||
|
title: string
|
||||||
|
company: string
|
||||||
|
timeSpan: string
|
||||||
|
bullets: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Experience extends React.PureComponent {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="experience-container">{this.renderJobs(jobsData)}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderJobs(jobs: JobData[]) {
|
||||||
|
return jobs.map(job => (
|
||||||
|
<Job
|
||||||
|
key={job.title}
|
||||||
|
title={job.title}
|
||||||
|
company={job.company}
|
||||||
|
timeSpan={job.timeSpan}
|
||||||
|
bullets={job.bullets}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,13 @@
|
||||||
// @flow
|
import * as React from "react"
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import './index.css'
|
import profile from "../../images/profile.webp"
|
||||||
import profile from '../../images/profile.webp'
|
import "./index.css"
|
||||||
|
|
||||||
type Props = {}
|
export default class Home extends React.PureComponent {
|
||||||
|
public render() {
|
||||||
class Home extends React.PureComponent<Props> {
|
|
||||||
render () {
|
|
||||||
return (
|
return (
|
||||||
<div className='home-container'>
|
<div className="home-container">
|
||||||
<img src={profile} alt='Profile' />
|
<img src={profile} alt="Profile" />
|
||||||
<p>Hello and welcome,</p>
|
<p>Hello and welcome,</p>
|
||||||
<p>
|
<p>
|
||||||
I am a software developer, with most of my experience in web services.
|
I am a software developer, with most of my experience in web services.
|
||||||
|
@ -32,10 +29,8 @@ class Home extends React.PureComponent<Props> {
|
||||||
Thank you for reading my quick bio. If you would like to contact me
|
Thank you for reading my quick bio. If you would like to contact me
|
||||||
visit the contact page for all of your options.
|
visit the contact page for all of your options.
|
||||||
</p>
|
</p>
|
||||||
<p className='signature'>- Mitchell J. F. Simon, III</p>
|
<p className="signature">- Mitchell J. F. Simon, III</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Home
|
|
|
@ -1,48 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as React from 'react'
|
|
||||||
|
|
||||||
import ProjectComponent from '../../components/Project'
|
|
||||||
|
|
||||||
import './index.css'
|
|
||||||
|
|
||||||
import projectsData from '../../data/projects.json'
|
|
||||||
|
|
||||||
type Props = {}
|
|
||||||
|
|
||||||
type Badge = {
|
|
||||||
imgUrl: string,
|
|
||||||
linkUrl: string,
|
|
||||||
alt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Project = {
|
|
||||||
title: string,
|
|
||||||
repoUrl: string,
|
|
||||||
badges: Array<Badge>,
|
|
||||||
description: string
|
|
||||||
}
|
|
||||||
|
|
||||||
class Projects extends React.PureComponent<Props> {
|
|
||||||
renderProjects = (projects: Array<Project>) => {
|
|
||||||
return projects.map(project => (
|
|
||||||
<ProjectComponent
|
|
||||||
key={project.title}
|
|
||||||
title={project.title}
|
|
||||||
repoUrl={project.repoUrl}
|
|
||||||
badges={project.badges}
|
|
||||||
>
|
|
||||||
{project.description}
|
|
||||||
</ProjectComponent>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='projects-container'>
|
|
||||||
{this.renderProjects(projectsData)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Projects
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import Project from "../../components/Project"
|
||||||
|
|
||||||
|
import "./index.css"
|
||||||
|
|
||||||
|
import projectsData from "../../data/projects.json"
|
||||||
|
|
||||||
|
type BadgeData = {
|
||||||
|
imgUrl: string
|
||||||
|
linkUrl: string
|
||||||
|
alt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectData = {
|
||||||
|
title: string
|
||||||
|
repoUrl: string
|
||||||
|
badges: BadgeData[]
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Projects extends React.PureComponent {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div className="projects-container">
|
||||||
|
{this.renderProjects(projectsData)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderProjects(projects: ProjectData[]) {
|
||||||
|
return projects.map(project => (
|
||||||
|
<Project
|
||||||
|
key={project.title}
|
||||||
|
title={project.title}
|
||||||
|
repoUrl={project.repoUrl}
|
||||||
|
badges={project.badges}
|
||||||
|
>
|
||||||
|
{project.description}
|
||||||
|
</Project>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "build/dist",
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["es6", "dom"],
|
||||||
|
"sourceMap": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"rootDir": "src",
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"build",
|
||||||
|
"scripts",
|
||||||
|
"acceptance-tests",
|
||||||
|
"webpack",
|
||||||
|
"jest",
|
||||||
|
"src/setupTests.ts"
|
||||||
|
],
|
||||||
|
"types": ["typePatches"],
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"extends": ["tslint:latest", "tslint-config-prettier"],
|
||||||
|
"defaultSeverity": "warning",
|
||||||
|
"rules": {
|
||||||
|
"semicolon": false,
|
||||||
|
"resolve-json-module": true,
|
||||||
|
"interface-over-type-literal": false
|
||||||
|
},
|
||||||
|
"linterOptions": {
|
||||||
|
"exclude": ["config/**/*.js", "node_modules/**/*.ts"]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue