Prettify everything

This commit is contained in:
MICHAEL JACKSON
2018-02-17 18:00:56 -08:00
parent d6f2bc089a
commit 2e1f09e913
58 changed files with 1061 additions and 932 deletions

View File

@ -1,6 +1,8 @@
import React from "react"
import contentHTML from "./About.md"
import React from "react";
import contentHTML from "./About.md";
const About = () => <div className="wrapper" dangerouslySetInnerHTML={{ __html: contentHTML }} />
const About = () => (
<div className="wrapper" dangerouslySetInnerHTML={{ __html: contentHTML }} />
);
export default About
export default About;

View File

@ -1,11 +1,11 @@
import React from "react"
import { HashRouter } from "react-router-dom"
import Layout from "./Layout"
import React from "react";
import { HashRouter } from "react-router-dom";
import Layout from "./Layout";
const App = () => (
<HashRouter>
<Layout />
</HashRouter>
)
);
export default App
export default App;

View File

@ -1,6 +1,8 @@
import React from "react"
import contentHTML from "./Home.md"
import React from "react";
import contentHTML from "./Home.md";
const Home = () => <div className="wrapper" dangerouslySetInnerHTML={{ __html: contentHTML }} />
const Home = () => (
<div className="wrapper" dangerouslySetInnerHTML={{ __html: contentHTML }} />
);
export default Home
export default Home;

View File

@ -1,78 +1,81 @@
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"
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
let itemIndex;
switch (this.props.location.pathname) {
case "/stats":
itemIndex = 1
break
itemIndex = 1;
break;
case "/about":
itemIndex = 2
break
itemIndex = 2;
break;
case "/":
default:
itemIndex = 0
itemIndex = 0;
}
const itemNodes = this.listNode.querySelectorAll("li")
const currentNode = itemNodes[itemIndex]
const itemNodes = this.listNode.querySelectorAll("li");
const currentNode = itemNodes[itemIndex];
this.setState({
underlineLeft: currentNode.offsetLeft,
underlineWidth: currentNode.offsetWidth,
useSpring
})
}
});
};
componentDidMount() {
this.adjustUnderline()
this.adjustUnderline();
fetch("/_stats?period=last-month")
.then(res => res.json())
.then(stats => this.setState({ stats }))
.then(stats => this.setState({ stats }));
if (window.localStorage) {
const savedStats = window.localStorage.savedStats
const savedStats = window.localStorage.savedStats;
if (savedStats) this.setState({ stats: JSON.parse(savedStats) })
if (savedStats) this.setState({ stats: JSON.parse(savedStats) });
window.onbeforeunload = () => {
localStorage.savedStats = JSON.stringify(this.state.stats)
}
localStorage.savedStats = JSON.stringify(this.state.stats);
};
}
}
componentDidUpdate(prevProps) {
if (prevProps.location.pathname !== this.props.location.pathname) this.adjustUnderline(true)
if (prevProps.location.pathname !== this.props.location.pathname)
this.adjustUnderline(true);
}
render() {
const { underlineLeft, underlineWidth, useSpring } = this.state
const { underlineLeft, underlineWidth, useSpring } = this.state;
const style = {
left: useSpring ? spring(underlineLeft, { stiffness: 220 }) : underlineLeft,
left: useSpring
? spring(underlineLeft, { stiffness: 220 })
: underlineLeft,
width: useSpring ? spring(underlineWidth) : underlineWidth
}
};
return (
<div>
@ -81,7 +84,10 @@ class Layout extends React.Component {
<header>
<h1 className="layout-title">unpkg</h1>
<nav className="layout-nav">
<ol className="layout-nav-list" ref={node => (this.listNode = node)}>
<ol
className="layout-nav-list"
ref={node => (this.listNode = node)}
>
<li>
<Link to="/">Home</Link>
</li>
@ -111,13 +117,16 @@ class Layout extends React.Component {
</div>
<Switch>
<Route path="/stats" render={() => <Stats data={this.state.stats} />} />
<Route
path="/stats"
render={() => <Stats data={this.state.stats} />}
/>
<Route path="/about" component={About} />
<Route path="/" component={Home} />
</Switch>
</div>
)
);
}
}
export default withRouter(Layout)
export default withRouter(Layout);

View File

@ -1,51 +1,55 @@
import React from "react"
import PropTypes from "prop-types"
import formatBytes from "pretty-bytes"
import formatDate from "date-fns/format"
import parseDate from "date-fns/parse"
import formatNumber from "./utils/formatNumber"
import formatPercent from "./utils/formatPercent"
import React from "react";
import PropTypes from "prop-types";
import formatBytes from "pretty-bytes";
import formatDate from "date-fns/format";
import parseDate from "date-fns/parse";
import formatNumber from "./utils/formatNumber";
import formatPercent from "./utils/formatPercent";
import { continents, countries } from "countries-list"
import { continents, countries } from "countries-list";
const getCountriesByContinent = continent =>
Object.keys(countries).filter(country => countries[country].continent === continent)
Object.keys(countries).filter(
country => countries[country].continent === continent
);
const sumKeyValues = (hash, keys) => keys.reduce((n, key) => n + (hash[key] || 0), 0)
const sumKeyValues = (hash, keys) =>
keys.reduce((n, key) => n + (hash[key] || 0), 0);
const sumValues = hash => Object.keys(hash).reduce((memo, key) => memo + hash[key], 0)
const sumValues = hash =>
Object.keys(hash).reduce((memo, key) => memo + hash[key], 0);
class Stats extends React.Component {
static propTypes = {
data: PropTypes.object
}
};
state = {
minPackageRequests: 1000000,
minCountryRequests: 1000000
}
};
render() {
const { data } = this.props
const { data } = this.props;
if (data == null) return null
if (data == null) return null;
const totals = data.totals
const totals = data.totals;
// Summary data
const since = parseDate(totals.since)
const until = parseDate(totals.until)
const since = parseDate(totals.since);
const until = parseDate(totals.until);
// Packages
const packageRows = []
const packageRows = [];
Object.keys(totals.requests.package)
.sort((a, b) => {
return totals.requests.package[b] - totals.requests.package[a]
return totals.requests.package[b] - totals.requests.package[a];
})
.forEach(packageName => {
const requests = totals.requests.package[packageName]
const bandwidth = totals.bandwidth.package[packageName]
const requests = totals.requests.package[packageName];
const bandwidth = totals.bandwidth.package[packageName];
if (requests >= this.state.minPackageRequests) {
packageRows.push(
@ -59,44 +63,51 @@ class Stats extends React.Component {
</a>
</td>
<td>
{formatNumber(requests)} ({formatPercent(requests / totals.requests.all)}%)
{formatNumber(requests)} ({formatPercent(
requests / totals.requests.all
)}%)
</td>
{bandwidth ? (
<td>
{formatBytes(bandwidth)} ({formatPercent(bandwidth / totals.bandwidth.all)}%)
{formatBytes(bandwidth)} ({formatPercent(
bandwidth / totals.bandwidth.all
)}%)
</td>
) : (
<td>-</td>
)}
</tr>
)
);
}
})
});
// Regions
const regionRows = []
const regionRows = [];
const continentsData = Object.keys(continents).reduce((memo, continent) => {
const localCountries = getCountriesByContinent(continent)
const localCountries = getCountriesByContinent(continent);
memo[continent] = {
countries: localCountries,
requests: sumKeyValues(totals.requests.country, localCountries),
bandwidth: sumKeyValues(totals.bandwidth.country, localCountries)
}
};
return memo
}, {})
return memo;
}, {});
const topContinents = Object.keys(continentsData).sort((a, b) => {
return continentsData[b].requests - continentsData[a].requests
})
return continentsData[b].requests - continentsData[a].requests;
});
topContinents.forEach(continent => {
const continentName = continents[continent]
const continentData = continentsData[continent]
const continentName = continents[continent];
const continentData = continentsData[continent];
if (continentData.requests > this.state.minCountryRequests && continentData.bandwidth !== 0) {
if (
continentData.requests > this.state.minCountryRequests &&
continentData.bandwidth !== 0
) {
regionRows.push(
<tr key={continent} className="continent-row">
<td>{continentName}</td>
@ -111,15 +122,15 @@ class Stats extends React.Component {
)}%)
</td>
</tr>
)
);
const topCountries = continentData.countries.sort((a, b) => {
return totals.requests.country[b] - totals.requests.country[a]
})
return totals.requests.country[b] - totals.requests.country[a];
});
topCountries.forEach(country => {
const countryRequests = totals.requests.country[country]
const countryBandwidth = totals.bandwidth.country[country]
const countryRequests = totals.requests.country[country];
const countryBandwidth = totals.bandwidth.country[country];
if (countryRequests > this.state.minCountryRequests) {
regionRows.push(
@ -136,19 +147,19 @@ class Stats extends React.Component {
)}%)
</td>
</tr>
)
);
}
})
});
}
})
});
// Protocols
const protocolRows = Object.keys(totals.requests.protocol)
.sort((a, b) => {
return totals.requests.protocol[b] - totals.requests.protocol[a]
return totals.requests.protocol[b] - totals.requests.protocol[a];
})
.map(protocol => {
const requests = totals.requests.protocol[protocol]
const requests = totals.requests.protocol[protocol];
return (
<tr key={protocol}>
@ -159,19 +170,22 @@ class Stats extends React.Component {
)}%)
</td>
</tr>
)
})
);
});
return (
<div className="wrapper">
<p>
From <strong>{formatDate(since, "MMM D")}</strong> to{" "}
<strong>{formatDate(until, "MMM D")}</strong> unpkg served{" "}
<strong>{formatNumber(totals.requests.all)}</strong> requests and a total of{" "}
<strong>{formatBytes(totals.bandwidth.all)}</strong> of data to{" "}
<strong>{formatNumber(totals.uniques.all)}</strong> unique visitors,{" "}
<strong>{formatPercent(totals.requests.cached / totals.requests.all, 0)}%</strong> of
which were served from the cache.
<strong>{formatNumber(totals.requests.all)}</strong> requests and a
total of <strong>{formatBytes(totals.bandwidth.all)}</strong> of data
to <strong>{formatNumber(totals.uniques.all)}</strong> unique
visitors,{" "}
<strong>
{formatPercent(totals.requests.cached / totals.requests.all, 0)}%
</strong>{" "}
of which were served from the cache.
</p>
<h3>Packages</h3>
@ -241,7 +255,12 @@ class Stats extends React.Component {
requests.
</p>
<table cellSpacing="0" cellPadding="0" style={{ width: "100%" }} className="regions-table">
<table
cellSpacing="0"
cellPadding="0"
style={{ width: "100%" }}
className="regions-table"
>
<thead>
<tr>
<th>Region</th>
@ -270,8 +289,8 @@ class Stats extends React.Component {
<tbody>{protocolRows}</tbody>
</table>
</div>
)
);
}
}
export default Stats
export default Stats;

View File

@ -1,34 +1,34 @@
import React from "react"
import PropTypes from "prop-types"
import addEvent from "./utils/addEvent"
import removeEvent from "./utils/removeEvent"
import React from "react";
import PropTypes from "prop-types";
import addEvent from "./utils/addEvent";
import removeEvent from "./utils/removeEvent";
const ResizeEvent = "resize"
const ResizeEvent = "resize";
class WindowSize extends React.Component {
static propTypes = {
onChange: PropTypes.func
}
};
handleWindowResize = () => {
if (this.props.onChange)
this.props.onChange({
width: window.innerWidth,
height: window.innerHeight
})
}
});
};
componentDidMount() {
addEvent(window, ResizeEvent, this.handleWindowResize)
addEvent(window, ResizeEvent, this.handleWindowResize);
}
componentWillUnmount() {
removeEvent(window, ResizeEvent, this.handleWindowResize)
removeEvent(window, ResizeEvent, this.handleWindowResize);
}
render() {
return null
return null;
}
}
export default WindowSize
export default WindowSize;

View File

@ -1,12 +1,7 @@
body {
font-size: 16px;
font-family: -apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Helvetica,
Arial,
sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif;
line-height: 1.5;
padding: 5px 20px;
}
@ -50,7 +45,8 @@ th {
text-align: left;
background-color: #eee;
}
th, td {
th,
td {
padding: 5px;
}
th {

View File

@ -1,6 +1,6 @@
import React from "react"
import ReactDOM from "react-dom"
import App from "./App"
import "./main.css"
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./main.css";
ReactDOM.render(<App />, document.getElementById("app"))
ReactDOM.render(<App />, document.getElementById("app"));

View File

@ -1,9 +1,9 @@
const addEvent = (node, type, handler) => {
if (node.addEventListener) {
node.addEventListener(type, handler, false)
node.addEventListener(type, handler, false);
} else if (node.attachEvent) {
node.attachEvent("on" + type, handler)
node.attachEvent("on" + type, handler);
}
}
};
export default addEvent
export default addEvent;

View File

@ -1,10 +1,10 @@
const formatNumber = n => {
const digits = String(n).split("")
const groups = []
const digits = String(n).split("");
const groups = [];
while (digits.length) groups.unshift(digits.splice(-3).join(""))
while (digits.length) groups.unshift(digits.splice(-3).join(""));
return groups.join(",")
}
return groups.join(",");
};
export default formatNumber
export default formatNumber;

View File

@ -1,3 +1,4 @@
const formatPercent = (n, fixed = 1) => String((n.toPrecision(2) * 100).toFixed(fixed))
const formatPercent = (n, fixed = 1) =>
String((n.toPrecision(2) * 100).toFixed(fixed));
export default formatPercent
export default formatPercent;

View File

@ -1,3 +1,3 @@
const parseNumber = s => parseInt(s.replace(/,/g, ""), 10) || 0
const parseNumber = s => parseInt(s.replace(/,/g, ""), 10) || 0;
export default parseNumber
export default parseNumber;

View File

@ -1,9 +1,9 @@
const removeEvent = (node, type, handler) => {
if (node.removeEventListener) {
node.removeEventListener(type, handler, false)
node.removeEventListener(type, handler, false);
} else if (node.detachEvent) {
node.detachEvent("on" + type, handler)
node.detachEvent("on" + type, handler);
}
}
};
export default removeEvent
export default removeEvent;