unpkg/client/Layout.js

124 lines
3.3 KiB
JavaScript

import React from "react"
import PropTypes from "prop-types"
import { Motion, spring } from "react-motion"
import { Switch, Route, Link, withRouter } from "react-router-dom"
import WindowSize from "./WindowSize"
import About from "./About"
import Stats from "./Stats"
import Home from "./Home"
class Layout extends React.Component {
static propTypes = {
location: PropTypes.object,
children: PropTypes.node
}
state = {
underlineLeft: 0,
underlineWidth: 0,
useSpring: false,
stats: null
}
adjustUnderline = (useSpring = false) => {
let itemIndex
switch (this.props.location.pathname) {
case "/stats":
itemIndex = 1
break
case "/about":
itemIndex = 2
break
case "/":
default:
itemIndex = 0
}
const itemNodes = this.listNode.querySelectorAll("li")
const currentNode = itemNodes[itemIndex]
this.setState({
underlineLeft: currentNode.offsetLeft,
underlineWidth: currentNode.offsetWidth,
useSpring
})
}
componentDidMount() {
this.adjustUnderline()
fetch("/_stats?period=last-month")
.then(res => res.json())
.then(stats => this.setState({ stats }))
if (window.localStorage) {
const savedStats = window.localStorage.savedStats
if (savedStats) this.setState({ stats: JSON.parse(savedStats) })
window.onbeforeunload = () => {
localStorage.savedStats = JSON.stringify(this.state.stats)
}
}
}
componentDidUpdate(prevProps) {
if (prevProps.location.pathname !== this.props.location.pathname) this.adjustUnderline(true)
}
render() {
const { underlineLeft, underlineWidth, useSpring } = this.state
const style = {
left: useSpring ? spring(underlineLeft, { stiffness: 220 }) : underlineLeft,
width: useSpring ? spring(underlineWidth) : underlineWidth
}
return (
<div>
<WindowSize onChange={this.adjustUnderline} />
<div className="wrapper">
<header>
<h1 className="layout-title">unpkg</h1>
<nav className="layout-nav">
<ol className="layout-nav-list" ref={node => (this.listNode = node)}>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/stats">Stats</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ol>
<Motion
defaultStyle={{ left: underlineLeft, width: underlineWidth }}
style={style}
children={style => (
<div
className="layout-nav-underline"
style={{
WebkitTransform: `translate3d(${style.left}px,0,0)`,
transform: `translate3d(${style.left}px,0,0)`,
width: style.width
}}
/>
)}
/>
</nav>
</header>
</div>
<Switch>
<Route path="/stats" render={() => <Stats data={this.state.stats} />} />
<Route path="/about" component={About} />
<Route path="/" component={Home} />
</Switch>
</div>
)
}
}
export default withRouter(Layout)