2019-07-25 00:55:13 +00:00
|
|
|
/** @jsx jsx */
|
|
|
|
import { Global, css, jsx } from '@emotion/core';
|
|
|
|
import { Fragment } from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
|
|
|
import { fontSans, fontMono } from '../utils/style.js';
|
|
|
|
|
2020-06-03 18:45:16 +00:00
|
|
|
import FolderViewer from './FolderViewer.js';
|
2019-07-25 00:55:13 +00:00
|
|
|
import FileViewer from './FileViewer.js';
|
|
|
|
import { TwitterIcon, GitHubIcon } from './Icons.js';
|
|
|
|
|
|
|
|
import SelectDownArrow from './images/SelectDownArrow.png';
|
|
|
|
|
2020-06-06 16:36:38 +00:00
|
|
|
const buildId = process.env.BUILD_ID;
|
|
|
|
|
2019-07-25 00:55:13 +00:00
|
|
|
const globalStyles = css`
|
|
|
|
html {
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
*,
|
|
|
|
*:before,
|
|
|
|
*:after {
|
|
|
|
box-sizing: inherit;
|
|
|
|
}
|
|
|
|
|
|
|
|
html,
|
|
|
|
body,
|
|
|
|
#root {
|
|
|
|
height: 100%;
|
|
|
|
margin: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
body {
|
|
|
|
${fontSans}
|
|
|
|
font-size: 16px;
|
|
|
|
line-height: 1.5;
|
2020-06-02 19:29:37 +00:00
|
|
|
overflow-wrap: break-word;
|
2019-07-25 00:55:13 +00:00
|
|
|
background: white;
|
|
|
|
color: black;
|
|
|
|
}
|
|
|
|
|
|
|
|
code {
|
|
|
|
${fontMono}
|
|
|
|
}
|
|
|
|
|
|
|
|
th,
|
|
|
|
td {
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
font-size: inherit;
|
|
|
|
}
|
|
|
|
|
|
|
|
#root {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
// Adapted from https://github.com/highlightjs/highlight.js/blob/master/src/styles/atom-one-light.css
|
|
|
|
const lightCodeStyles = css`
|
|
|
|
.code-listing {
|
|
|
|
background: #fbfdff;
|
|
|
|
color: #383a42;
|
|
|
|
}
|
|
|
|
.code-comment,
|
|
|
|
.code-quote {
|
|
|
|
color: #a0a1a7;
|
|
|
|
font-style: italic;
|
|
|
|
}
|
|
|
|
.code-doctag,
|
|
|
|
.code-keyword,
|
|
|
|
.code-link,
|
|
|
|
.code-formula {
|
|
|
|
color: #a626a4;
|
|
|
|
}
|
|
|
|
.code-section,
|
|
|
|
.code-name,
|
|
|
|
.code-selector-tag,
|
|
|
|
.code-deletion,
|
|
|
|
.code-subst {
|
|
|
|
color: #e45649;
|
|
|
|
}
|
|
|
|
.code-literal {
|
|
|
|
color: #0184bb;
|
|
|
|
}
|
|
|
|
.code-string,
|
|
|
|
.code-regexp,
|
|
|
|
.code-addition,
|
|
|
|
.code-attribute,
|
|
|
|
.code-meta-string {
|
|
|
|
color: #50a14f;
|
|
|
|
}
|
|
|
|
.code-built_in,
|
|
|
|
.code-class .code-title {
|
|
|
|
color: #c18401;
|
|
|
|
}
|
|
|
|
.code-attr,
|
|
|
|
.code-variable,
|
|
|
|
.code-template-variable,
|
|
|
|
.code-type,
|
|
|
|
.code-selector-class,
|
|
|
|
.code-selector-attr,
|
|
|
|
.code-selector-pseudo,
|
|
|
|
.code-number {
|
|
|
|
color: #986801;
|
|
|
|
}
|
|
|
|
.code-symbol,
|
|
|
|
.code-bullet,
|
|
|
|
.code-meta,
|
|
|
|
.code-selector-id,
|
|
|
|
.code-title {
|
|
|
|
color: #4078f2;
|
|
|
|
}
|
|
|
|
.code-emphasis {
|
|
|
|
font-style: italic;
|
|
|
|
}
|
|
|
|
.code-strong {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
2020-06-02 19:29:37 +00:00
|
|
|
function Link({ css, ...rest }) {
|
|
|
|
return (
|
|
|
|
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
|
|
|
<a
|
|
|
|
{...rest}
|
|
|
|
css={{
|
|
|
|
color: '#0076ff',
|
|
|
|
textDecoration: 'none',
|
2020-06-03 18:45:16 +00:00
|
|
|
':hover': { textDecoration: 'underline' },
|
2020-06-02 19:29:37 +00:00
|
|
|
...css
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
2019-07-25 00:55:13 +00:00
|
|
|
|
2020-06-03 18:45:16 +00:00
|
|
|
function AppHeader() {
|
|
|
|
return (
|
|
|
|
<header css={{ marginTop: '2rem' }}>
|
|
|
|
<h1
|
|
|
|
css={{
|
|
|
|
textAlign: 'center',
|
|
|
|
fontSize: '3rem',
|
|
|
|
letterSpacing: '0.05em'
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<a href="/" css={{ color: '#000', textDecoration: 'none' }}>
|
|
|
|
UNPKG
|
|
|
|
</a>
|
|
|
|
</h1>
|
|
|
|
{/*
|
|
|
|
<nav>
|
|
|
|
<Link href="#" css={{ color: '#c400ff' }}>
|
|
|
|
Become a Sponsor
|
|
|
|
</Link>
|
|
|
|
</nav>
|
|
|
|
*/}
|
|
|
|
</header>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function AppNavigation({
|
2019-07-25 00:55:13 +00:00
|
|
|
packageName,
|
|
|
|
packageVersion,
|
2020-06-03 18:45:16 +00:00
|
|
|
availableVersions,
|
|
|
|
filename
|
2019-07-25 00:55:13 +00:00
|
|
|
}) {
|
2020-06-03 18:45:16 +00:00
|
|
|
function handleVersionChange(nextVersion) {
|
2019-07-25 00:55:13 +00:00
|
|
|
window.location.href = window.location.href.replace(
|
|
|
|
'@' + packageVersion,
|
2020-06-03 18:45:16 +00:00
|
|
|
'@' + nextVersion
|
2019-07-25 00:55:13 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-06-03 18:45:16 +00:00
|
|
|
let breadcrumbs = [];
|
2019-07-25 00:55:13 +00:00
|
|
|
|
|
|
|
if (filename === '/') {
|
|
|
|
breadcrumbs.push(packageName);
|
|
|
|
} else {
|
|
|
|
let url = `/browse/${packageName}@${packageVersion}`;
|
|
|
|
|
2020-06-02 19:29:37 +00:00
|
|
|
breadcrumbs.push(<Link href={`${url}/`}>{packageName}</Link>);
|
2019-07-25 00:55:13 +00:00
|
|
|
|
2020-06-03 18:45:16 +00:00
|
|
|
let segments = filename
|
2019-07-25 00:55:13 +00:00
|
|
|
.replace(/^\/+/, '')
|
|
|
|
.replace(/\/+$/, '')
|
|
|
|
.split('/');
|
2020-06-03 18:45:16 +00:00
|
|
|
let lastSegment = segments.pop();
|
2019-07-25 00:55:13 +00:00
|
|
|
|
|
|
|
segments.forEach(segment => {
|
|
|
|
url += `/${segment}`;
|
2020-06-02 19:29:37 +00:00
|
|
|
breadcrumbs.push(<Link href={`${url}/`}>{segment}</Link>);
|
2019-07-25 00:55:13 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
breadcrumbs.push(lastSegment);
|
|
|
|
}
|
|
|
|
|
2020-06-03 18:45:16 +00:00
|
|
|
return (
|
|
|
|
<header
|
|
|
|
css={{
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
|
|
|
alignItems: 'center',
|
|
|
|
'@media (max-width: 700px)': {
|
|
|
|
flexDirection: 'column-reverse',
|
|
|
|
alignItems: 'flex-start'
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<h1
|
|
|
|
css={{
|
|
|
|
fontSize: '1.5rem',
|
|
|
|
fontWeight: 'normal',
|
|
|
|
flex: 1,
|
|
|
|
wordBreak: 'break-all'
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<nav>
|
|
|
|
{breadcrumbs.map((item, index, array) => (
|
|
|
|
<Fragment key={index}>
|
|
|
|
{index !== 0 && (
|
|
|
|
<span css={{ paddingLeft: 5, paddingRight: 5 }}>/</span>
|
|
|
|
)}
|
|
|
|
{index === array.length - 1 ? <strong>{item}</strong> : item}
|
|
|
|
</Fragment>
|
|
|
|
))}
|
|
|
|
</nav>
|
|
|
|
</h1>
|
|
|
|
<PackageVersionPicker
|
|
|
|
packageVersion={packageVersion}
|
|
|
|
availableVersions={availableVersions}
|
|
|
|
onChange={handleVersionChange}
|
|
|
|
/>
|
|
|
|
</header>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function PackageVersionPicker({ packageVersion, availableVersions, onChange }) {
|
|
|
|
function handleChange(event) {
|
|
|
|
if (onChange) onChange(event.target.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<p
|
|
|
|
css={{
|
|
|
|
marginLeft: 20,
|
|
|
|
'@media (max-width: 700px)': {
|
|
|
|
marginLeft: 0,
|
|
|
|
marginBottom: 0
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<label>
|
|
|
|
Version:{' '}
|
|
|
|
<select
|
|
|
|
name="version"
|
|
|
|
defaultValue={packageVersion}
|
|
|
|
onChange={handleChange}
|
|
|
|
css={{
|
|
|
|
appearance: 'none',
|
|
|
|
cursor: 'pointer',
|
|
|
|
padding: '4px 24px 4px 8px',
|
|
|
|
fontWeight: 600,
|
|
|
|
fontSize: '0.9em',
|
|
|
|
color: '#24292e',
|
|
|
|
border: '1px solid rgba(27,31,35,.2)',
|
|
|
|
borderRadius: 3,
|
|
|
|
backgroundColor: '#eff3f6',
|
|
|
|
backgroundImage: `url(${SelectDownArrow})`,
|
|
|
|
backgroundPosition: 'right 8px center',
|
|
|
|
backgroundRepeat: 'no-repeat',
|
|
|
|
backgroundSize: 'auto 25%',
|
|
|
|
':hover': {
|
|
|
|
backgroundColor: '#e6ebf1',
|
|
|
|
borderColor: 'rgba(27,31,35,.35)'
|
|
|
|
},
|
|
|
|
':active': {
|
|
|
|
backgroundColor: '#e9ecef',
|
|
|
|
borderColor: 'rgba(27,31,35,.35)',
|
|
|
|
boxShadow: 'inset 0 0.15em 0.3em rgba(27,31,35,.15)'
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{availableVersions.map(v => (
|
|
|
|
<option key={v} value={v}>
|
|
|
|
{v}
|
|
|
|
</option>
|
|
|
|
))}
|
|
|
|
</select>
|
|
|
|
</label>
|
|
|
|
</p>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function AppContent({ packageName, packageVersion, target }) {
|
|
|
|
return target.type === 'directory' ? (
|
|
|
|
<FolderViewer path={target.path} details={target.details} />
|
|
|
|
) : target.type === 'file' ? (
|
|
|
|
<FileViewer
|
|
|
|
packageName={packageName}
|
|
|
|
packageVersion={packageVersion}
|
|
|
|
path={target.path}
|
|
|
|
details={target.details}
|
|
|
|
/>
|
|
|
|
) : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default function App({
|
|
|
|
packageName,
|
|
|
|
packageVersion,
|
|
|
|
availableVersions = [],
|
|
|
|
filename,
|
|
|
|
target
|
|
|
|
}) {
|
|
|
|
let maxContentWidth = 940;
|
|
|
|
// TODO: Make this changeable
|
|
|
|
let isFullWidth = false;
|
2019-07-25 00:55:13 +00:00
|
|
|
|
|
|
|
return (
|
2020-06-02 19:29:37 +00:00
|
|
|
<Fragment>
|
|
|
|
<Global styles={globalStyles} />
|
|
|
|
<Global styles={lightCodeStyles} />
|
2019-07-25 00:55:13 +00:00
|
|
|
|
2020-06-02 19:29:37 +00:00
|
|
|
<div css={{ flex: '1 0 auto' }}>
|
|
|
|
<div
|
|
|
|
css={{
|
|
|
|
maxWidth: maxContentWidth,
|
|
|
|
padding: '0 20px',
|
|
|
|
margin: '0 auto'
|
|
|
|
}}
|
|
|
|
>
|
2020-06-03 18:45:16 +00:00
|
|
|
<AppHeader />
|
2020-06-02 19:29:37 +00:00
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
css={{
|
2020-06-03 18:45:16 +00:00
|
|
|
maxWidth: isFullWidth ? undefined : maxContentWidth,
|
|
|
|
padding: '0 20px',
|
|
|
|
margin: '0 auto'
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<AppNavigation
|
|
|
|
packageName={packageName}
|
|
|
|
packageVersion={packageVersion}
|
|
|
|
availableVersions={availableVersions}
|
|
|
|
filename={filename}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
css={{
|
|
|
|
maxWidth: isFullWidth ? undefined : maxContentWidth,
|
2020-06-02 19:29:37 +00:00
|
|
|
padding: '0 20px',
|
|
|
|
margin: '0 auto',
|
|
|
|
'@media (max-width: 700px)': {
|
|
|
|
padding: 0,
|
|
|
|
margin: 0
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
>
|
2020-06-03 18:45:16 +00:00
|
|
|
<AppContent
|
2020-06-02 19:29:37 +00:00
|
|
|
packageName={packageName}
|
|
|
|
packageVersion={packageVersion}
|
2020-06-03 18:45:16 +00:00
|
|
|
target={target}
|
|
|
|
/>
|
2019-07-25 00:55:13 +00:00
|
|
|
</div>
|
2020-06-02 19:29:37 +00:00
|
|
|
</div>
|
2019-07-25 00:55:13 +00:00
|
|
|
|
2020-06-02 19:29:37 +00:00
|
|
|
<footer
|
|
|
|
css={{
|
|
|
|
marginTop: '5rem',
|
|
|
|
background: 'black',
|
|
|
|
color: '#aaa'
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div
|
2019-07-25 00:55:13 +00:00
|
|
|
css={{
|
2020-06-02 19:29:37 +00:00
|
|
|
maxWidth: maxContentWidth,
|
|
|
|
padding: '10px 20px',
|
|
|
|
margin: '0 auto',
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
|
|
|
alignItems: 'center',
|
|
|
|
justifyContent: 'space-between'
|
2019-07-25 00:55:13 +00:00
|
|
|
}}
|
|
|
|
>
|
2020-06-06 16:36:38 +00:00
|
|
|
<p>
|
|
|
|
<span>Build: {buildId}</span>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<span>© {new Date().getFullYear()} UNPKG</span>
|
|
|
|
</p>
|
2020-06-02 19:29:37 +00:00
|
|
|
<p css={{ fontSize: '1.5rem' }}>
|
|
|
|
<a
|
|
|
|
href="https://twitter.com/unpkg"
|
|
|
|
css={{
|
|
|
|
color: '#aaa',
|
|
|
|
display: 'inline-block',
|
|
|
|
':hover': { color: 'white' }
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<TwitterIcon />
|
|
|
|
</a>
|
|
|
|
<a
|
|
|
|
href="https://github.com/mjackson/unpkg"
|
|
|
|
css={{
|
|
|
|
color: '#aaa',
|
|
|
|
display: 'inline-block',
|
2020-06-03 18:45:16 +00:00
|
|
|
':hover': { color: 'white' },
|
|
|
|
marginLeft: '1rem'
|
2020-06-02 19:29:37 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<GitHubIcon />
|
|
|
|
</a>
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
</footer>
|
|
|
|
</Fragment>
|
2019-07-25 00:55:13 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
const targetType = PropTypes.shape({
|
|
|
|
path: PropTypes.string.isRequired,
|
|
|
|
type: PropTypes.oneOf(['directory', 'file']).isRequired,
|
|
|
|
details: PropTypes.object.isRequired
|
|
|
|
});
|
|
|
|
|
|
|
|
App.propTypes = {
|
|
|
|
packageName: PropTypes.string.isRequired,
|
|
|
|
packageVersion: PropTypes.string.isRequired,
|
|
|
|
availableVersions: PropTypes.arrayOf(PropTypes.string),
|
|
|
|
filename: PropTypes.string.isRequired,
|
|
|
|
target: targetType.isRequired
|
|
|
|
};
|
|
|
|
}
|