Experimental port to Firebase hosting
This commit is contained in:
@ -9,6 +9,8 @@
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"react/no-children-prop": 0
|
||||
"import/no-unresolved": 0,
|
||||
"react/no-children-prop": 0,
|
||||
"react/prop-types": 0
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,30 @@
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const createHTML = require('./utils/createHTML');
|
||||
const x = require('./utils/execScript');
|
||||
import createHTML from './utils/createHTML';
|
||||
import x from './utils/execScript';
|
||||
|
||||
function MainPage({ title, description, scripts, styles, data, content }) {
|
||||
export default function MainPage({
|
||||
title,
|
||||
description,
|
||||
favicon,
|
||||
scripts,
|
||||
styles,
|
||||
data,
|
||||
content
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="description" content={description} />
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
{description && <meta name="description" content={description} />}
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width,initial-scale=1,maximum-scale=1"
|
||||
/>
|
||||
<meta name="timestamp" content={new Date().toISOString()} />
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
{favicon && <link rel="shortcut icon" href={favicon} />}
|
||||
{styles.map(s => (
|
||||
<link key={s} rel="stylesheet" href={s} />
|
||||
))}
|
||||
@ -39,6 +47,16 @@ function MainPage({ title, description, scripts, styles, data, content }) {
|
||||
);
|
||||
}
|
||||
|
||||
MainPage.defaultProps = {
|
||||
title: 'UNPKG',
|
||||
description: 'The CDN for everything on npm',
|
||||
favicon: '/favicon.ico',
|
||||
scripts: [],
|
||||
styles: [],
|
||||
data: {},
|
||||
content: createHTML('')
|
||||
};
|
||||
|
||||
const htmlType = PropTypes.shape({
|
||||
__html: PropTypes.string
|
||||
});
|
||||
@ -46,19 +64,9 @@ const htmlType = PropTypes.shape({
|
||||
MainPage.propTypes = {
|
||||
title: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
favicon: PropTypes.string,
|
||||
scripts: PropTypes.arrayOf(PropTypes.string),
|
||||
styles: PropTypes.arrayOf(PropTypes.string),
|
||||
data: PropTypes.any,
|
||||
content: htmlType
|
||||
};
|
||||
|
||||
MainPage.defaultProps = {
|
||||
title: 'UNPKG',
|
||||
description: 'The CDN for everything on npm',
|
||||
scripts: [],
|
||||
styles: [],
|
||||
data: {},
|
||||
content: createHTML('')
|
||||
};
|
||||
|
||||
module.exports = MainPage;
|
||||
|
@ -1,9 +1,9 @@
|
||||
require('./autoIndex.css');
|
||||
// import './autoIndex.css';
|
||||
|
||||
const React = require('react');
|
||||
const ReactDOM = require('react-dom');
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const App = require('./autoIndex/App');
|
||||
import App from './autoIndex/App';
|
||||
|
||||
const props = window.__DATA__ || {};
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
.app {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.app-version-selector {
|
||||
line-height: 2.25em;
|
||||
float: right;
|
||||
}
|
||||
.app-version-selector select {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.app-address {
|
||||
text-align: right;
|
||||
}
|
@ -1,10 +1,43 @@
|
||||
require('./App.css');
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const React = require('react');
|
||||
import DirectoryListing from './DirectoryListing';
|
||||
|
||||
const DirectoryListing = require('./DirectoryListing');
|
||||
const styles = {
|
||||
wrapper: {
|
||||
maxWidth: 900,
|
||||
margin: '0 auto'
|
||||
},
|
||||
header: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
versionSelector: {
|
||||
float: 'right',
|
||||
lineHeight: '2.25em'
|
||||
},
|
||||
versionDropdown: {
|
||||
fontSize: '1em'
|
||||
},
|
||||
address: {
|
||||
textAlign: 'right'
|
||||
}
|
||||
};
|
||||
|
||||
const entryType = PropTypes.object;
|
||||
|
||||
export default class App extends React.Component {
|
||||
static propTypes = {
|
||||
packageName: PropTypes.string.isRequired,
|
||||
packageVersion: PropTypes.string.isRequired,
|
||||
availableVersions: PropTypes.arrayOf(PropTypes.string),
|
||||
filename: PropTypes.string.isRequired,
|
||||
entry: entryType.isRequired,
|
||||
entries: PropTypes.objectOf(entryType).isRequired
|
||||
};
|
||||
|
||||
class App extends React.Component {
|
||||
static defaultProps = {
|
||||
availableVersions: []
|
||||
};
|
||||
@ -18,19 +51,20 @@ class App extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="app">
|
||||
<header className="app-header">
|
||||
<div style={styles.wrapper}>
|
||||
<header style={styles.header}>
|
||||
<h1>
|
||||
Index of /{this.props.packageName}@{this.props.packageVersion}
|
||||
{this.props.filename}
|
||||
</h1>
|
||||
|
||||
<div className="app-version-selector">
|
||||
<div style={styles.versionSelector}>
|
||||
Version:{' '}
|
||||
<select
|
||||
id="version"
|
||||
defaultValue={this.props.packageVersion}
|
||||
onChange={this.handleChange}
|
||||
style={styles.versionDropdown}
|
||||
>
|
||||
{this.props.availableVersions.map(v => (
|
||||
<option key={v} value={v}>
|
||||
@ -51,27 +85,10 @@ class App extends React.Component {
|
||||
|
||||
<hr />
|
||||
|
||||
<address className="app-address">
|
||||
<address style={styles.address}>
|
||||
{this.props.packageName}@{this.props.packageVersion}
|
||||
</address>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const PropTypes = require('prop-types');
|
||||
|
||||
const entryType = PropTypes.object;
|
||||
|
||||
App.propTypes = {
|
||||
packageName: PropTypes.string.isRequired,
|
||||
packageVersion: PropTypes.string.isRequired,
|
||||
availableVersions: PropTypes.arrayOf(PropTypes.string),
|
||||
filename: PropTypes.string.isRequired,
|
||||
entry: entryType.isRequired,
|
||||
entries: PropTypes.objectOf(entryType).isRequired
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = App;
|
||||
|
@ -1,17 +0,0 @@
|
||||
.directory-listing table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font: 0.85em Monaco, monospace;
|
||||
}
|
||||
|
||||
.directory-listing tr.even {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.directory-listing th {
|
||||
text-align: left;
|
||||
}
|
||||
.directory-listing th,
|
||||
.directory-listing td {
|
||||
padding: 0.5em 1em;
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
require('./DirectoryListing.css');
|
||||
|
||||
const React = require('react');
|
||||
const formatBytes = require('pretty-bytes');
|
||||
const sortBy = require('sort-by');
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import formatBytes from 'pretty-bytes';
|
||||
import sortBy from 'sort-by';
|
||||
|
||||
function getDirname(name) {
|
||||
return (
|
||||
@ -25,20 +24,38 @@ function getRelativeName(base, name) {
|
||||
return base.length ? name.substr(base.length + 1) : name;
|
||||
}
|
||||
|
||||
function DirectoryListing({ filename, entry, entries }) {
|
||||
const styles = {
|
||||
table: {
|
||||
width: '100%',
|
||||
borderCollapse: 'collapse',
|
||||
font: '0.85em Monaco, monospace'
|
||||
},
|
||||
evenRow: {
|
||||
backgroundColor: '#eee'
|
||||
},
|
||||
tableHead: {
|
||||
textAlign: 'left',
|
||||
padding: '0.5em 1em'
|
||||
},
|
||||
tableCell: {
|
||||
padding: '0.5em 1em'
|
||||
}
|
||||
};
|
||||
|
||||
export default function DirectoryListing({ filename, entry, entries }) {
|
||||
const rows = [];
|
||||
|
||||
if (filename !== '/') {
|
||||
rows.push(
|
||||
<tr key="..">
|
||||
<td>
|
||||
<td style={styles.tableCell}>
|
||||
<a title="Parent directory" href="../">
|
||||
..
|
||||
</a>
|
||||
</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td style={styles.tableCell}>-</td>
|
||||
<td style={styles.tableCell}>-</td>
|
||||
<td style={styles.tableCell}>-</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
@ -54,14 +71,14 @@ function DirectoryListing({ filename, entry, entries }) {
|
||||
|
||||
rows.push(
|
||||
<tr key={name}>
|
||||
<td>
|
||||
<td style={styles.tableCell}>
|
||||
<a title={relName} href={href}>
|
||||
{href}
|
||||
</a>
|
||||
</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td style={styles.tableCell}>-</td>
|
||||
<td style={styles.tableCell}>-</td>
|
||||
<td style={styles.tableCell}>-</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
@ -74,33 +91,33 @@ function DirectoryListing({ filename, entry, entries }) {
|
||||
|
||||
rows.push(
|
||||
<tr key={name}>
|
||||
<td>
|
||||
<td style={styles.tableCell}>
|
||||
<a title={relName} href={relName}>
|
||||
{relName}
|
||||
</a>
|
||||
</td>
|
||||
<td>{contentType}</td>
|
||||
<td>{formatBytes(size)}</td>
|
||||
<td>{lastModified}</td>
|
||||
<td style={styles.tableCell}>{contentType}</td>
|
||||
<td style={styles.tableCell}>{formatBytes(size)}</td>
|
||||
<td style={styles.tableCell}>{lastModified}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="directory-listing">
|
||||
<table>
|
||||
<div>
|
||||
<table style={styles.table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Size</th>
|
||||
<th>Last Modified</th>
|
||||
<th style={styles.tableHead}>Name</th>
|
||||
<th style={styles.tableHead}>Type</th>
|
||||
<th style={styles.tableHead}>Size</th>
|
||||
<th style={styles.tableHead}>Last Modified</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, index) =>
|
||||
React.cloneElement(row, {
|
||||
className: index % 2 ? 'odd' : 'even'
|
||||
style: index % 2 ? undefined : styles.evenRow
|
||||
})
|
||||
)}
|
||||
</tbody>
|
||||
@ -109,18 +126,12 @@ function DirectoryListing({ filename, entry, entries }) {
|
||||
);
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const PropTypes = require('prop-types');
|
||||
const entryType = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired
|
||||
});
|
||||
|
||||
const entryType = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired
|
||||
});
|
||||
|
||||
DirectoryListing.propTypes = {
|
||||
filename: PropTypes.string.isRequired,
|
||||
entry: entryType.isRequired,
|
||||
entries: PropTypes.objectOf(entryType).isRequired
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = DirectoryListing;
|
||||
DirectoryListing.propTypes = {
|
||||
filename: PropTypes.string.isRequired,
|
||||
entry: entryType.isRequired,
|
||||
entries: PropTypes.objectOf(entryType).isRequired
|
||||
};
|
||||
|
@ -1,8 +1,8 @@
|
||||
require('./main.css');
|
||||
// import './main.css';
|
||||
|
||||
const React = require('react');
|
||||
const ReactDOM = require('react-dom');
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const App = require('./main/App');
|
||||
import App from './main/App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
|
@ -1,13 +0,0 @@
|
||||
.about-logos {
|
||||
margin: 2em 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.about-logo {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
max-width: 80%;
|
||||
}
|
||||
.about-logo img {
|
||||
max-width: 60%;
|
||||
}
|
@ -1,12 +1,95 @@
|
||||
require('./About.css');
|
||||
import React from 'react';
|
||||
|
||||
const React = require('react');
|
||||
import Wrapper from './Wrapper';
|
||||
|
||||
const h = require('../utils/createHTML');
|
||||
const markup = require('./About.md');
|
||||
import cloudflareLogo from './CloudflareLogo.png';
|
||||
import herokuLogo from './HerokuLogo.png';
|
||||
|
||||
function About() {
|
||||
return <div className="wrapper" dangerouslySetInnerHTML={h(markup)} />;
|
||||
const styles = {
|
||||
logoList: {
|
||||
margin: '2em 0',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
logo: {
|
||||
textAlign: 'center',
|
||||
flex: '1',
|
||||
maxWidth: '80%'
|
||||
},
|
||||
logoImage: {
|
||||
maxWidth: '60%'
|
||||
}
|
||||
};
|
||||
|
||||
function AboutLogo({ children }) {
|
||||
return <div style={styles.logo}>{children}</div>;
|
||||
}
|
||||
|
||||
module.exports = About;
|
||||
function AboutLogoImage(props) {
|
||||
return <img {...props} style={styles.logoImage} />;
|
||||
}
|
||||
|
||||
export default function About() {
|
||||
return (
|
||||
<Wrapper>
|
||||
<p>
|
||||
unpkg is an <a href="https://github.com/unpkg">open source</a> project
|
||||
built and maintained by{' '}
|
||||
<a href="https://twitter.com/mjackson">Michael Jackson</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="sponsors">Sponsors</h3>
|
||||
<p>
|
||||
The fast, global infrastructure that powers unpkg is generously donated
|
||||
by <a href="https://www.cloudflare.com">Cloudflare</a> and{' '}
|
||||
<a href="https://www.heroku.com">Heroku</a>.
|
||||
</p>
|
||||
|
||||
<div style={styles.logoList}>
|
||||
<AboutLogo>
|
||||
<a href="https://www.cloudflare.com">
|
||||
<AboutLogoImage src={cloudflareLogo} />
|
||||
</a>
|
||||
</AboutLogo>
|
||||
<AboutLogo>
|
||||
<a href="https://www.heroku.com">
|
||||
<AboutLogoImage src={herokuLogo} />
|
||||
</a>
|
||||
</AboutLogo>
|
||||
</div>
|
||||
|
||||
<h3 id="cache-behavior">Cache Behavior</h3>
|
||||
<p>
|
||||
The CDN caches files based on their permanent URL, which includes the
|
||||
npm package version. This works because npm does not allow package
|
||||
authors to overwrite a package that has already been published with a
|
||||
different one at the same version number.
|
||||
</p>
|
||||
<p>
|
||||
URLs that do not specify a package version number redirect to one that
|
||||
does. This is the <code>latest</code> version when no version is
|
||||
specified, or the <code>maxSatisfying</code> version when a{' '}
|
||||
<a href="https://github.com/npm/node-semver">semver version</a> is
|
||||
given. Redirects are cached for 5 minutes.
|
||||
</p>
|
||||
<p>
|
||||
Browsers are instructed (via the <code>Cache-Control</code> header) to
|
||||
cache assets for 1 year.
|
||||
</p>
|
||||
|
||||
<h3 id="abuse">Abuse</h3>
|
||||
<p>
|
||||
unpkg maintains a list of packages that are known to be malicious. If
|
||||
you find such a package on npm, please let us know!
|
||||
</p>
|
||||
|
||||
<h3 id="support">Support</h3>
|
||||
<p>
|
||||
unpkg is not affiliated with or supported by npm, Inc. in any way.
|
||||
Please do not contact npm for help with unpkg. Instead, please reach out
|
||||
to <a href="https://twitter.com/unpkg">@unpkg</a> with any questions or
|
||||
concerns.
|
||||
</p>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
unpkg is an [open source](https://github.com/unpkg) project built and maintained by [Michael Jackson](https://twitter.com/mjackson).
|
||||
|
||||
### Sponsors
|
||||
|
||||
The fast, global infrastructure that powers unpkg is generously donated by [Cloudflare](https://www.cloudflare.com) and [Heroku](https://www.heroku.com).
|
||||
|
||||
<div class="about-logos">
|
||||
<div class="about-logo">
|
||||
<a href="https://www.cloudflare.com"><img src="CloudflareLogo.png"></a>
|
||||
</div>
|
||||
<div class="about-logo">
|
||||
<a href="https://www.heroku.com"><img src="HerokuLogo.png"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Cache Behavior
|
||||
|
||||
The CDN caches files based on their permanent URL, which includes the npm package version. This works because npm does not allow package authors to overwrite a package that has already been published with a different one at the same version number.
|
||||
|
||||
URLs that do not specify a package version number redirect to one that does. This is the `latest` version when no version is specified, or the `maxSatisfying` version when a [semver version](https://github.com/npm/node-semver) is given. Redirects are cached for 5 minutes.
|
||||
|
||||
Browsers are instructed (via the `Cache-Control` header) to cache assets for 1 year.
|
||||
|
||||
### Abuse
|
||||
|
||||
unpkg maintains a list of packages that are known to be malicious. If you find such a package on npm, please let us know!
|
||||
|
||||
### Support
|
||||
|
||||
unpkg is not affiliated with or supported by npm, Inc. in any way. Please do not contact npm for help with unpkg. Instead, please reach out to [@unpkg](https://twitter.com/unpkg) with any questions or concerns.
|
@ -1,7 +1,7 @@
|
||||
const React = require('react');
|
||||
const { HashRouter } = require('react-router-dom');
|
||||
import React from 'react';
|
||||
import { HashRouter } from 'react-router-dom';
|
||||
|
||||
const Layout = require('./Layout');
|
||||
import Layout from './Layout';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
@ -11,4 +11,4 @@ function App() {
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = App;
|
||||
export default App;
|
||||
|
@ -1,6 +0,0 @@
|
||||
.home-example {
|
||||
text-align: center;
|
||||
background-color: #eee;
|
||||
margin: 2em 0;
|
||||
padding: 5px 0;
|
||||
}
|
@ -1,12 +1,159 @@
|
||||
require('./Home.css');
|
||||
import React from 'react';
|
||||
|
||||
const React = require('react');
|
||||
import Wrapper from './Wrapper';
|
||||
|
||||
const h = require('../utils/createHTML');
|
||||
const markup = require('./Home.md');
|
||||
const styles = {
|
||||
homeExample: {
|
||||
textAlign: 'center',
|
||||
backgroundColor: '#eee',
|
||||
margin: '2em 0',
|
||||
padding: '5px 0'
|
||||
}
|
||||
};
|
||||
|
||||
function Home() {
|
||||
return <div className="wrapper" dangerouslySetInnerHTML={h(markup)} />;
|
||||
export default function Home() {
|
||||
return (
|
||||
<Wrapper>
|
||||
<p>
|
||||
unpkg is a fast, global{' '}
|
||||
<a href="https://en.wikipedia.org/wiki/Content_delivery_network">
|
||||
content delivery network
|
||||
</a>{' '}
|
||||
for everything on <a href="https://www.npmjs.com/">npm</a>. Use it to
|
||||
quickly and easily load any file from any package using a URL like:
|
||||
</p>
|
||||
|
||||
<div style={styles.homeExample}>unpkg.com/:package@:version/:file</div>
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
<p>Using a fixed version:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/react@16.0.0/umd/react.production.min.js">
|
||||
unpkg.com/react@16.0.0/umd/react.production.min.js
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/react-dom@16.0.0/umd/react-dom.production.min.js">
|
||||
unpkg.com/react-dom@16.0.0/umd/react-dom.production.min.js
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
You may also use a{' '}
|
||||
<a href="https://docs.npmjs.com/misc/semver">semver range</a> or a{' '}
|
||||
<a href="https://docs.npmjs.com/cli/dist-tag">tag</a> instead of a fixed
|
||||
version number, or omit the version/tag entirely to use the{' '}
|
||||
<code>latest</code> tag.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/react@^16/umd/react.production.min.js">
|
||||
unpkg.com/react@^16/umd/react.production.min.js
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/react/umd/react.production.min.js">
|
||||
unpkg.com/react/umd/react.production.min.js
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If you omit the file path (i.e. use a “bare” URL), unpkg
|
||||
will serve the file specified by the <code>unpkg</code> field in{' '}
|
||||
<code>package.json</code>, or fall back to
|
||||
<code>main</code>.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/d3">unpkg.com/d3</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/jquery">unpkg.com/jquery</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/three">unpkg.com/three</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Append a <code>/</code> at the end of a URL to view a listing of all the
|
||||
files in a package.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/react/">unpkg.com/react/</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/lodash/">unpkg.com/lodash/</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Query Parameters</h3>
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
<code>?meta</code>
|
||||
</dt>
|
||||
<dd>
|
||||
Return metadata about any file in a package as JSON (e.g.
|
||||
<code>/any/file?meta</code>)
|
||||
</dd>
|
||||
|
||||
<dt>
|
||||
<code>?module</code>
|
||||
</dt>
|
||||
<dd>
|
||||
Expands all{' '}
|
||||
<a href="https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier">
|
||||
“bare” <code>import</code> specifiers
|
||||
</a>
|
||||
in JavaScript modules to unpkg URLs. This feature is{' '}
|
||||
<em>very experimental</em>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Workflow</h3>
|
||||
|
||||
<p>
|
||||
For npm package authors, unpkg relieves the burden of publishing your
|
||||
code to a CDN in addition to the npm registry. All you need to do is
|
||||
include your <a href="https://github.com/umdjs/umd">UMD</a> build in
|
||||
your npm package (not your repo, that's different!).
|
||||
</p>
|
||||
|
||||
<p>You can do this easily using the following setup:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Add the <code>umd</code> (or <code>dist</code>) directory to your{' '}
|
||||
<code>.gitignore</code> file
|
||||
</li>
|
||||
<li>
|
||||
Add the <code>umd</code> directory to your{' '}
|
||||
<a href="https://docs.npmjs.com/files/package.json#files">
|
||||
files array
|
||||
</a>{' '}
|
||||
in
|
||||
<code>package.json</code>
|
||||
</li>
|
||||
<li>
|
||||
Use a build script to generate your UMD build in the <code>umd</code>{' '}
|
||||
directory when you publish
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
That's it! Now when you <code>npm publish</code> you'll have a
|
||||
version available on unpkg as well.
|
||||
</p>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = Home;
|
||||
|
@ -1,48 +0,0 @@
|
||||
unpkg is a fast, global [content delivery network](https://en.wikipedia.org/wiki/Content_delivery_network) for everything on [npm](https://www.npmjs.com/). Use it to quickly and easily load any file from any package using a URL like:
|
||||
|
||||
<div class="home-example">unpkg.com/:package@:version/:file</div>
|
||||
|
||||
### Examples
|
||||
|
||||
Using a fixed version:
|
||||
|
||||
* [unpkg.com/react@16.0.0/umd/react.production.min.js](/react@16.0.0/umd/react.production.min.js)
|
||||
* [unpkg.com/react-dom@16.0.0/umd/react-dom.production.min.js](/react-dom@16.0.0/umd/react-dom.production.min.js)
|
||||
|
||||
You may also use a [semver range](https://docs.npmjs.com/misc/semver) or a [tag](https://docs.npmjs.com/cli/dist-tag) instead of a fixed version number, or omit the version/tag entirely to use the `latest` tag.
|
||||
|
||||
* [unpkg.com/react@^16/umd/react.production.min.js](/react@^16/umd/react.production.min.js)
|
||||
* [unpkg.com/react/umd/react.production.min.js](/react/umd/react.production.min.js)
|
||||
|
||||
If you omit the file path (i.e. use a "bare" URL), unpkg will serve the file specified by the `unpkg` field in `package.json`, or fall back to `main`.
|
||||
|
||||
* [unpkg.com/d3](/d3)
|
||||
* [unpkg.com/jquery](/jquery)
|
||||
* [unpkg.com/three](/three)
|
||||
|
||||
Append a `/` at the end of a URL to view a listing of all the files in a package.
|
||||
|
||||
* [unpkg.com/react/](/react/)
|
||||
* [unpkg.com/lodash/](/lodash/)
|
||||
|
||||
### Query Parameters
|
||||
|
||||
<dl>
|
||||
<dt>`?meta`</dt>
|
||||
<dd>Return metadata about any file in a package as JSON (e.g. `/any/file?meta`)</dd>
|
||||
|
||||
<dt>`?module`</dt>
|
||||
<dd>Expands all ["bare" `import` specifiers](https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier) in JavaScript modules to unpkg URLs. This feature is *very experimental*</dd>
|
||||
</dl>
|
||||
|
||||
### Workflow
|
||||
|
||||
For npm package authors, unpkg relieves the burden of publishing your code to a CDN in addition to the npm registry. All you need to do is include your [UMD](https://github.com/umdjs/umd) build in your npm package (not your repo, that's different!).
|
||||
|
||||
You can do this easily using the following setup:
|
||||
|
||||
* Add the `umd` (or `dist`) directory to your `.gitignore` file
|
||||
* Add the `umd` directory to your [files array](https://docs.npmjs.com/files/package.json#files) in `package.json`
|
||||
* Use a build script to generate your UMD build in the `umd` directory when you publish
|
||||
|
||||
That's it! Now when you `npm publish` you'll have a version available on unpkg as well.
|
@ -1,38 +0,0 @@
|
||||
.layout-title {
|
||||
margin: 0;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
font-size: 5em;
|
||||
}
|
||||
|
||||
.layout-nav {
|
||||
margin: 0 0 3em;
|
||||
}
|
||||
|
||||
.layout-navList {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.layout-navList li {
|
||||
flex-basis: auto;
|
||||
list-style-type: none;
|
||||
display: inline-block;
|
||||
font-size: 1.1em;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.layout-navList li a:link {
|
||||
text-decoration: none;
|
||||
}
|
||||
.layout-navList li a:link,
|
||||
.layout-navList li a:visited {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.layout-navUnderline {
|
||||
height: 4px;
|
||||
background-color: black;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
@ -1,14 +1,47 @@
|
||||
require('./Layout.css');
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Switch, Route, Link, withRouter } from 'react-router-dom';
|
||||
import { Motion, spring } from 'react-motion';
|
||||
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const { Switch, Route, Link, withRouter } = require('react-router-dom');
|
||||
const { Motion, spring } = require('react-motion');
|
||||
import WindowSize from './WindowSize';
|
||||
import About from './About';
|
||||
import Stats from './Stats';
|
||||
import Home from './Home';
|
||||
|
||||
const WindowSize = require('./WindowSize');
|
||||
const About = require('./About');
|
||||
const Stats = require('./Stats');
|
||||
const Home = require('./Home');
|
||||
const styles = {
|
||||
title: {
|
||||
margin: 0,
|
||||
textTransform: 'uppercase',
|
||||
textAlign: 'center',
|
||||
fontSize: '5em'
|
||||
},
|
||||
nav: {
|
||||
margin: '0 0 3em'
|
||||
},
|
||||
navList: {
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
navListItem: {
|
||||
flexBasis: 'auto',
|
||||
listStyleType: 'none',
|
||||
display: 'inline-block',
|
||||
fontSize: '1.1em',
|
||||
margin: '0 10px'
|
||||
},
|
||||
navLink: {
|
||||
textDecoration: 'none',
|
||||
color: 'black'
|
||||
},
|
||||
navUnderline: {
|
||||
height: 4,
|
||||
backgroundColor: 'black',
|
||||
position: 'absolute',
|
||||
left: 0
|
||||
}
|
||||
};
|
||||
|
||||
class Layout extends React.Component {
|
||||
static propTypes = {
|
||||
@ -66,8 +99,9 @@ class Layout extends React.Component {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.location.pathname !== this.props.location.pathname)
|
||||
if (prevProps.location.pathname !== this.props.location.pathname) {
|
||||
this.adjustUnderline(true);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -85,20 +119,23 @@ class Layout extends React.Component {
|
||||
<WindowSize onChange={this.adjustUnderline} />
|
||||
<div className="wrapper">
|
||||
<header>
|
||||
<h1 className="layout-title">unpkg</h1>
|
||||
<nav className="layout-nav">
|
||||
<ol
|
||||
className="layout-navList"
|
||||
ref={node => (this.listNode = node)}
|
||||
>
|
||||
<li>
|
||||
<Link to="/">Home</Link>
|
||||
<h1 style={styles.title}>unpkg</h1>
|
||||
<nav style={styles.nav}>
|
||||
<ol style={styles.navList} ref={node => (this.listNode = node)}>
|
||||
<li style={styles.navListItem}>
|
||||
<Link to="/" style={styles.navLink}>
|
||||
Home
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/stats">Stats</Link>
|
||||
<li style={styles.navListItem}>
|
||||
<Link to="/stats" style={styles.navLink}>
|
||||
Stats
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/about">About</Link>
|
||||
<li style={styles.navListItem}>
|
||||
<Link to="/about" style={styles.navLink}>
|
||||
About
|
||||
</Link>
|
||||
</li>
|
||||
</ol>
|
||||
<Motion
|
||||
@ -106,8 +143,8 @@ class Layout extends React.Component {
|
||||
style={style}
|
||||
children={style => (
|
||||
<div
|
||||
className="layout-navUnderline"
|
||||
style={{
|
||||
...styles.navUnderline,
|
||||
WebkitTransform: `translate3d(${style.left}px,0,0)`,
|
||||
transform: `translate3d(${style.left}px,0,0)`,
|
||||
width: style.width
|
||||
@ -132,4 +169,4 @@ class Layout extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = withRouter(Layout);
|
||||
export default withRouter(Layout);
|
||||
|
@ -1,8 +0,0 @@
|
||||
.table-filter {
|
||||
font-size: 0.8em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.regions-table .country-row td.country-name {
|
||||
padding-left: 20px;
|
||||
}
|
@ -1,14 +1,24 @@
|
||||
require('./Stats.css');
|
||||
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';
|
||||
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const formatBytes = require('pretty-bytes');
|
||||
const formatDate = require('date-fns/format');
|
||||
const parseDate = require('date-fns/parse');
|
||||
const { continents, countries } = require('countries-list');
|
||||
import { continents, countries } from './countries.json';
|
||||
|
||||
const formatNumber = require('../utils/formatNumber');
|
||||
const formatPercent = require('../utils/formatPercent');
|
||||
import Wrapper from './Wrapper';
|
||||
import formatNumber from '../utils/formatNumber';
|
||||
import formatPercent from '../utils/formatPercent';
|
||||
|
||||
const styles = {
|
||||
tableFilter: {
|
||||
fontSize: '0.8em',
|
||||
textAlign: 'right'
|
||||
},
|
||||
countryName: {
|
||||
paddingLeft: 20
|
||||
}
|
||||
};
|
||||
|
||||
function getCountriesByContinent(continent) {
|
||||
return Object.keys(countries).filter(
|
||||
@ -20,17 +30,17 @@ function sumKeyValues(hash, keys) {
|
||||
return keys.reduce((n, key) => n + (hash[key] || 0), 0);
|
||||
}
|
||||
|
||||
function sumValues(hash) {
|
||||
return Object.keys(hash).reduce((memo, key) => memo + hash[key], 0);
|
||||
}
|
||||
// function sumValues(hash) {
|
||||
// return Object.keys(hash).reduce((memo, key) => memo + hash[key], 0);
|
||||
// }
|
||||
|
||||
class Stats extends React.Component {
|
||||
export default class Stats extends React.Component {
|
||||
static propTypes = {
|
||||
data: PropTypes.object
|
||||
};
|
||||
|
||||
state = {
|
||||
minPackageRequests: 1000000,
|
||||
// minPackageRequests: 1000000,
|
||||
minCountryRequests: 1000000
|
||||
};
|
||||
|
||||
@ -46,45 +56,45 @@ class Stats extends React.Component {
|
||||
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];
|
||||
})
|
||||
.forEach(packageName => {
|
||||
const requests = totals.requests.package[packageName];
|
||||
const bandwidth = totals.bandwidth.package[packageName];
|
||||
// Object.keys(totals.requests.package)
|
||||
// .sort((a, b) => {
|
||||
// return totals.requests.package[b] - totals.requests.package[a];
|
||||
// })
|
||||
// .forEach(packageName => {
|
||||
// const requests = totals.requests.package[packageName];
|
||||
// const bandwidth = totals.bandwidth.package[packageName];
|
||||
|
||||
if (requests >= this.state.minPackageRequests) {
|
||||
packageRows.push(
|
||||
<tr key={packageName}>
|
||||
<td>
|
||||
<a
|
||||
href={`https://npmjs.org/package/${packageName}`}
|
||||
title={`${packageName} on npm`}
|
||||
>
|
||||
{packageName}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{formatNumber(requests)} (
|
||||
{formatPercent(requests / totals.requests.all)}
|
||||
%)
|
||||
</td>
|
||||
{bandwidth ? (
|
||||
<td>
|
||||
{formatBytes(bandwidth)} (
|
||||
{formatPercent(bandwidth / totals.bandwidth.all)}
|
||||
%)
|
||||
</td>
|
||||
) : (
|
||||
<td>-</td>
|
||||
)}
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
});
|
||||
// if (requests >= this.state.minPackageRequests) {
|
||||
// packageRows.push(
|
||||
// <tr key={packageName}>
|
||||
// <td>
|
||||
// <a
|
||||
// href={`https://npmjs.org/package/${packageName}`}
|
||||
// title={`${packageName} on npm`}
|
||||
// >
|
||||
// {packageName}
|
||||
// </a>
|
||||
// </td>
|
||||
// <td>
|
||||
// {formatNumber(requests)} (
|
||||
// {formatPercent(requests / totals.requests.all)}
|
||||
// %)
|
||||
// </td>
|
||||
// {bandwidth ? (
|
||||
// <td>
|
||||
// {formatBytes(bandwidth)} (
|
||||
// {formatPercent(bandwidth / totals.bandwidth.all)}
|
||||
// %)
|
||||
// </td>
|
||||
// ) : (
|
||||
// <td>-</td>
|
||||
// )}
|
||||
// </tr>
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
|
||||
// Regions
|
||||
const regionRows = [];
|
||||
@ -114,7 +124,7 @@ class Stats extends React.Component {
|
||||
continentData.bandwidth !== 0
|
||||
) {
|
||||
regionRows.push(
|
||||
<tr key={continent} className="continent-row">
|
||||
<tr key={continent}>
|
||||
<td>
|
||||
<strong>{continentName}</strong>
|
||||
</td>
|
||||
@ -145,8 +155,8 @@ class Stats extends React.Component {
|
||||
|
||||
if (countryRequests > this.state.minCountryRequests) {
|
||||
regionRows.push(
|
||||
<tr key={continent + country} className="country-row">
|
||||
<td className="country-name">{countries[country].name}</td>
|
||||
<tr key={continent + country}>
|
||||
<td style={styles.countryName}>{countries[country].name}</td>
|
||||
<td>
|
||||
{formatNumber(countryRequests)} (
|
||||
{formatPercent(countryRequests / totals.requests.all)}
|
||||
@ -165,27 +175,27 @@ class Stats extends React.Component {
|
||||
});
|
||||
|
||||
// Protocols
|
||||
const protocolRows = Object.keys(totals.requests.protocol)
|
||||
.sort((a, b) => {
|
||||
return totals.requests.protocol[b] - totals.requests.protocol[a];
|
||||
})
|
||||
.map(protocol => {
|
||||
const requests = totals.requests.protocol[protocol];
|
||||
// const protocolRows = Object.keys(totals.requests.protocol)
|
||||
// .sort((a, b) => {
|
||||
// return totals.requests.protocol[b] - totals.requests.protocol[a];
|
||||
// })
|
||||
// .map(protocol => {
|
||||
// const requests = totals.requests.protocol[protocol];
|
||||
|
||||
return (
|
||||
<tr key={protocol}>
|
||||
<td>{protocol}</td>
|
||||
<td>
|
||||
{formatNumber(requests)} (
|
||||
{formatPercent(requests / sumValues(totals.requests.protocol))}
|
||||
%)
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
// return (
|
||||
// <tr key={protocol}>
|
||||
// <td>{protocol}</td>
|
||||
// <td>
|
||||
// {formatNumber(requests)} (
|
||||
// {formatPercent(requests / sumValues(totals.requests.protocol))}
|
||||
// %)
|
||||
// </td>
|
||||
// </tr>
|
||||
// );
|
||||
// });
|
||||
|
||||
return (
|
||||
<div className="wrapper">
|
||||
<Wrapper>
|
||||
<p>
|
||||
From <strong>{formatDate(since, 'MMM D')}</strong> to{' '}
|
||||
<strong>{formatDate(until, 'MMM D')}</strong> unpkg served{' '}
|
||||
@ -201,6 +211,12 @@ class Stats extends React.Component {
|
||||
|
||||
<h3>Packages</h3>
|
||||
|
||||
<p>
|
||||
We recently migrated unpkg to a new backend and are working on getting
|
||||
package-specific data back on the site.
|
||||
</p>
|
||||
|
||||
{/*
|
||||
<p>
|
||||
The table below shows the most popular packages served by unpkg from{' '}
|
||||
<strong>{formatDate(since, 'MMM D')}</strong> to{' '}
|
||||
@ -208,7 +224,7 @@ class Stats extends React.Component {
|
||||
{Object.keys(totals.requests.package).length} packages are shown.
|
||||
</p>
|
||||
|
||||
<p className="table-filter">
|
||||
<p style={styles.tableFilter}>
|
||||
Include only packages that received at least{' '}
|
||||
<select
|
||||
value={this.state.minPackageRequests}
|
||||
@ -244,6 +260,7 @@ class Stats extends React.Component {
|
||||
</thead>
|
||||
<tbody>{packageRows}</tbody>
|
||||
</table>
|
||||
*/}
|
||||
|
||||
<h3>Regions</h3>
|
||||
|
||||
@ -253,7 +270,7 @@ class Stats extends React.Component {
|
||||
<strong>{formatDate(until, 'MMM D')}</strong> by geographic region.
|
||||
</p>
|
||||
|
||||
<p className="table-filter">
|
||||
<p style={styles.tableFilter}>
|
||||
Include only countries that made at least{' '}
|
||||
<select
|
||||
value={this.state.minCountryRequests}
|
||||
@ -272,12 +289,7 @@ 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%' }}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
@ -294,6 +306,7 @@ class Stats extends React.Component {
|
||||
<tbody>{regionRows}</tbody>
|
||||
</table>
|
||||
|
||||
{/*
|
||||
<h3>Protocols</h3>
|
||||
|
||||
<p>
|
||||
@ -315,9 +328,8 @@ class Stats extends React.Component {
|
||||
</thead>
|
||||
<tbody>{protocolRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
*/}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Stats;
|
||||
|
@ -1,22 +1,22 @@
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const addEvent = require('../utils/addEvent');
|
||||
const removeEvent = require('../utils/removeEvent');
|
||||
import { addEvent, removeEvent } from '../utils/dom';
|
||||
|
||||
const resizeEvent = 'resize';
|
||||
|
||||
class WindowSize extends React.Component {
|
||||
export default class WindowSize extends React.Component {
|
||||
static propTypes = {
|
||||
onChange: PropTypes.func
|
||||
};
|
||||
|
||||
handleWindowResize = () => {
|
||||
if (this.props.onChange)
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
@ -31,5 +31,3 @@ class WindowSize extends React.Component {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WindowSize;
|
||||
|
5
modules/client/main/Wrapper.js
Normal file
5
modules/client/main/Wrapper.js
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function Wrapper({ children }) {
|
||||
return <div style={{ maxWidth: 700, margin: '0 auto' }}>{children}</div>;
|
||||
}
|
1
modules/client/main/countries.json
Normal file
1
modules/client/main/countries.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,9 +0,0 @@
|
||||
function addEvent(node, type, handler) {
|
||||
if (node.addEventListener) {
|
||||
node.addEventListener(type, handler, false);
|
||||
} else if (node.attachEvent) {
|
||||
node.attachEvent('on' + type, handler);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = addEvent;
|
@ -1,5 +1,3 @@
|
||||
function createHTML(code) {
|
||||
export default function createHTML(code) {
|
||||
return { __html: code };
|
||||
}
|
||||
|
||||
module.exports = createHTML;
|
||||
|
15
modules/client/utils/dom.js
Normal file
15
modules/client/utils/dom.js
Normal file
@ -0,0 +1,15 @@
|
||||
export function addEvent(node, type, handler) {
|
||||
if (node.addEventListener) {
|
||||
node.addEventListener(type, handler, false);
|
||||
} else if (node.attachEvent) {
|
||||
node.attachEvent('on' + type, handler);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeEvent(node, type, handler) {
|
||||
if (node.removeEventListener) {
|
||||
node.removeEventListener(type, handler, false);
|
||||
} else if (node.detachEvent) {
|
||||
node.detachEvent('on' + type, handler);
|
||||
}
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
const React = require('react');
|
||||
import React from 'react';
|
||||
|
||||
const h = require('./createHTML');
|
||||
import h from './createHTML';
|
||||
|
||||
function execScript(code) {
|
||||
export default function execScript(code) {
|
||||
return <script dangerouslySetInnerHTML={h(code)} />;
|
||||
}
|
||||
|
||||
module.exports = execScript;
|
||||
|
@ -1,4 +1,4 @@
|
||||
function formatNumber(n) {
|
||||
export default function formatNumber(n) {
|
||||
const digits = String(n).split('');
|
||||
const groups = [];
|
||||
|
||||
@ -8,5 +8,3 @@ function formatNumber(n) {
|
||||
|
||||
return groups.join(',');
|
||||
}
|
||||
|
||||
module.exports = formatNumber;
|
||||
|
@ -1,5 +1,3 @@
|
||||
function formatPercent(n, fixed = 1) {
|
||||
export default function formatPercent(n, fixed = 1) {
|
||||
return String((n.toPrecision(2) * 100).toFixed(fixed));
|
||||
}
|
||||
|
||||
module.exports = formatPercent;
|
||||
|
@ -1,5 +1,3 @@
|
||||
function parseNumber(s) {
|
||||
export default function parseNumber(s) {
|
||||
return parseInt(s.replace(/,/g, ''), 10) || 0;
|
||||
}
|
||||
|
||||
module.exports = parseNumber;
|
||||
|
@ -1,9 +0,0 @@
|
||||
function removeEvent(node, type, handler) {
|
||||
if (node.removeEventListener) {
|
||||
node.removeEventListener(type, handler, false);
|
||||
} else if (node.detachEvent) {
|
||||
node.detachEvent('on' + type, handler);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = removeEvent;
|
Reference in New Issue
Block a user