mirror of
https://github.com/mitchell/mjfs.us.git
synced 2025-12-19 13:47:22 +00:00
Migrate project from JS+Flow to TypeScript
This commit is contained in:
parent
60a557f918
commit
356b95579e
36 changed files with 3300 additions and 3058 deletions
|
|
@ -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
|
||||
18
src/components/ClearButton/index.tsx
Normal file
18
src/components/ClearButton/index.tsx
Normal file
|
|
@ -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
|
||||
21
src/components/Header/index.tsx
Normal file
21
src/components/Header/index.tsx
Normal file
|
|
@ -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
|
||||
29
src/components/Job/index.tsx
Normal file
29
src/components/Job/index.tsx
Normal file
|
|
@ -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
|
||||
81
src/components/Navbar/index.tsx
Normal file
81
src/components/Navbar/index.tsx
Normal file
|
|
@ -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
|
||||
39
src/components/Project/index.tsx
Normal file
39
src/components/Project/index.tsx
Normal file
|
|
@ -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
|
||||
10
src/components/SmallText/index.tsx
Normal file
10
src/components/SmallText/index.tsx
Normal file
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue