diff --git a/modules/client/browse/App.js b/modules/client/browse/App.js index 1d73b54..dcf8173 100644 --- a/modules/client/browse/App.js +++ b/modules/client/browse/App.js @@ -5,8 +5,7 @@ import PropTypes from 'prop-types'; import { fontSans, fontMono } from '../utils/style.js'; -import { PackageInfoProvider } from './PackageInfo.js'; -import DirectoryViewer from './DirectoryViewer.js'; +import FolderViewer from './FolderViewer.js'; import FileViewer from './FileViewer.js'; import { TwitterIcon, GitHubIcon } from './Icons.js'; @@ -128,30 +127,52 @@ function Link({ css, ...rest }) { css={{ color: '#0076ff', textDecoration: 'none', - ':hover': { - textDecoration: 'underline' - }, + ':hover': { textDecoration: 'underline' }, ...css }} /> ); } -export default function App({ +function AppHeader() { + return ( +
+

+ + UNPKG + +

+ {/* + + */} +
+ ); +} + +function AppNavigation({ packageName, packageVersion, - availableVersions = [], - filename, - target + availableVersions, + filename }) { - function handleChange(event) { + function handleVersionChange(nextVersion) { window.location.href = window.location.href.replace( '@' + packageVersion, - '@' + event.target.value + '@' + nextVersion ); } - const breadcrumbs = []; + let breadcrumbs = []; if (filename === '/') { breadcrumbs.push(packageName); @@ -160,12 +181,11 @@ export default function App({ breadcrumbs.push({packageName}); - const segments = filename + let segments = filename .replace(/^\/+/, '') .replace(/\/+$/, '') .split('/'); - - const lastSegment = segments.pop(); + let lastSegment = segments.pop(); segments.forEach(segment => { url += `/${segment}`; @@ -175,8 +195,126 @@ export default function App({ breadcrumbs.push(lastSegment); } - // TODO: Provide a user pref to go full width? - const maxContentWidth = 940; + return ( +
+

+ +

+ +
+ ); +} + +function PackageVersionPicker({ packageVersion, availableVersions, onChange }) { + function handleChange(event) { + if (onChange) onChange(event.target.value); + } + + return ( +

+ +

+ ); +} + +function AppContent({ packageName, packageVersion, target }) { + return target.type === 'directory' ? ( + + ) : target.type === 'file' ? ( + + ) : null; +} + +export default function App({ + packageName, + packageVersion, + availableVersions = [], + filename, + target +}) { + let maxContentWidth = 940; + // TODO: Make this changeable + let isFullWidth = false; return ( @@ -191,115 +329,25 @@ export default function App({ margin: '0 auto' }} > -
-

- - UNPKG - -

- {/* - - */} -
- -
-

- -

-

- -

-
+ -
+ +
+
- - {target.type === 'directory' ? ( - - ) : target.type === 'file' ? ( - - ) : null} - + target={target} + />
@@ -342,7 +385,6 @@ export default function App({

© {new Date().getFullYear()} UNPKG

diff --git a/modules/client/browse/ContentArea.js b/modules/client/browse/ContentArea.js new file mode 100644 index 0000000..09a3608 --- /dev/null +++ b/modules/client/browse/ContentArea.js @@ -0,0 +1,49 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/core'; + +const maxWidth = 700; + +export function ContentArea({ children, css }) { + return ( +

+ {children} +
+ ); +} + +export function ContentAreaHeaderBar({ children, css }) { + return ( +
+ {children} +
+ ); +} diff --git a/modules/client/browse/FileViewer.js b/modules/client/browse/FileViewer.js index fcb0418..4989283 100644 --- a/modules/client/browse/FileViewer.js +++ b/modules/client/browse/FileViewer.js @@ -5,10 +5,10 @@ import PropTypes from 'prop-types'; import { formatBytes } from '../utils/format.js'; import { createHTML } from '../utils/markup.js'; -import { usePackageInfo } from './PackageInfo.js'; +import { ContentArea, ContentAreaHeaderBar } from './ContentArea.js'; function getBasename(path) { - const segments = path.split('/'); + let segments = path.split('/'); return segments[segments.length - 1]; } @@ -21,8 +21,8 @@ function ImageViewer({ path, uri }) { } function CodeListing({ highlights }) { - const lines = highlights.slice(0); - const hasTrailingNewline = lines.length && lines[lines.length - 1] === ''; + let lines = highlights.slice(0); + let hasTrailingNewline = lines.length && lines[lines.length - 1] === ''; if (hasTrailingNewline) { lines.pop(); } @@ -46,7 +46,7 @@ function CodeListing({ highlights }) { > {lines.map((line, index) => { - const lineNumber = index + 1; + let lineNumber = index + 1; return ( @@ -120,71 +120,48 @@ function BinaryViewer() { ); } -export default function FileViewer({ path, details }) { - const { packageName, packageVersion } = usePackageInfo(); - const { highlights, uri, language, size } = details; - - const segments = path.split('/'); - const filename = segments[segments.length - 1]; +export default function FileViewer({ + packageName, + packageVersion, + path, + details +}) { + let { highlights, uri, language, size } = details; return ( -
- + + + {formatBytes(size)} + {language} + + + View Raw + + + {highlights ? ( @@ -193,7 +170,7 @@ export default function FileViewer({ path, details }) { ) : ( )} -
+ ); } diff --git a/modules/client/browse/DirectoryViewer.js b/modules/client/browse/FolderViewer.js similarity index 69% rename from modules/client/browse/DirectoryViewer.js rename to modules/client/browse/FolderViewer.js index 93301ec..aecf1c6 100644 --- a/modules/client/browse/DirectoryViewer.js +++ b/modules/client/browse/FolderViewer.js @@ -6,7 +6,8 @@ import sortBy from 'sort-by'; import { formatBytes } from '../utils/format.js'; -import { DirectoryIcon, CodeFileIcon } from './Icons.js'; +import { ContentArea, ContentAreaHeaderBar } from './ContentArea.js'; +import { FolderIcon, FileIcon, FileCodeIcon } from './Icons.js'; const linkStyle = { color: '#0076ff', @@ -48,7 +49,26 @@ function getRelName(path, base) { return path.substr(base.length > 1 ? base.length + 1 : 1); } -export default function DirectoryViewer({ path, details: entries }) { +export default function FolderViewer({ path, details: entries }) { + const { subdirs, files } = Object.keys(entries).reduce( + (memo, key) => { + const { subdirs, files } = memo; + const entry = entries[key]; + + if (entry.type === 'directory') { + subdirs.push(entry); + } else if (entry.type === 'file') { + files.push(entry); + } + + return memo; + }, + { subdirs: [], files: [] } + ); + + subdirs.sort(sortBy('path')); + files.sort(sortBy('path')); + const rows = []; if (path !== '/') { @@ -66,30 +86,14 @@ export default function DirectoryViewer({ path, details: entries }) { ); } - const { subdirs, files } = Object.keys(entries).reduce( - (memo, key) => { - const { subdirs, files } = memo; - const entry = entries[key]; - - if (entry.type === 'directory') { - subdirs.push(entry); - } else if (entry.type === 'file') { - files.push(entry); - } - - return memo; - }, - { subdirs: [], files: [] } - ); - - subdirs.sort(sortBy('path')).forEach(({ path: dirname }) => { + subdirs.forEach(({ path: dirname }) => { const relName = getRelName(dirname, path); const href = relName + '/'; rows.push( - + @@ -102,40 +106,44 @@ export default function DirectoryViewer({ path, details: entries }) { ); }); - files - .sort(sortBy('path')) - .forEach(({ path: filename, size, contentType }) => { - const relName = getRelName(filename, path); - const href = relName; + files.forEach(({ path: filename, size, contentType }) => { + const relName = getRelName(filename, path); + const href = relName; - rows.push( - - - - - - - {relName} - - - {formatBytes(size)} - {contentType} - - ); - }); + rows.push( + + + {contentType === 'text/plain' || contentType === 'text/markdown' ? ( + + ) : ( + + )} + + + + {relName} + + + {formatBytes(size)} + {contentType} + + ); + }); + + let counts = []; + if (files.length > 0) { + counts.push(`${files.length} file${files.length === 1 ? '' : 's'}`); + } + if (subdirs.length > 0) { + counts.push(`${subdirs.length} folder${subdirs.length === 1 ? '' : 's'}`); + } return ( -
+ + + {counts.join(', ')} + + @@ -167,12 +178,12 @@ export default function DirectoryViewer({ path, details: entries }) { {rows}
-
+ ); } if (process.env.NODE_ENV !== 'production') { - DirectoryViewer.propTypes = { + FolderViewer.propTypes = { path: PropTypes.string.isRequired, details: PropTypes.objectOf( PropTypes.shape({ diff --git a/modules/client/browse/Icons.js b/modules/client/browse/Icons.js index 664b3d7..ee97022 100644 --- a/modules/client/browse/Icons.js +++ b/modules/client/browse/Icons.js @@ -1,18 +1,27 @@ /** @jsx jsx */ import { jsx } from '@emotion/core'; -import { GoFileDirectory, GoFile } from 'react-icons/go'; +import { + GoArrowBoth, + GoFile, + GoFileCode, + GoFileDirectory +} from 'react-icons/go'; import { FaTwitter, FaGithub } from 'react-icons/fa'; function createIcon(Type, { css, ...rest }) { return ; } -export function DirectoryIcon(props) { - return createIcon(GoFileDirectory, props); +export function FileIcon(props) { + return createIcon(GoFile, props); } -export function CodeFileIcon(props) { - return createIcon(GoFile, props); +export function FileCodeIcon(props) { + return createIcon(GoFileCode, props); +} + +export function FolderIcon(props) { + return createIcon(GoFileDirectory, props); } export function TwitterIcon(props) { @@ -22,3 +31,7 @@ export function TwitterIcon(props) { export function GitHubIcon(props) { return createIcon(FaGithub, props); } + +export function ArrowBothIcon(props) { + return createIcon(GoArrowBoth, props); +} diff --git a/modules/client/browse/PackageInfo.js b/modules/client/browse/PackageInfo.js deleted file mode 100644 index 36e049d..0000000 --- a/modules/client/browse/PackageInfo.js +++ /dev/null @@ -1,11 +0,0 @@ -import React, { createContext, useContext } from 'react'; - -const Context = createContext(); - -export function PackageInfoProvider({ children, ...rest }) { - return ; -} - -export function usePackageInfo() { - return useContext(Context); -} diff --git a/modules/client/main/App.js b/modules/client/main/App.js index 9609906..2374637 100644 --- a/modules/client/main/App.js +++ b/modules/client/main/App.js @@ -41,6 +41,9 @@ const globalStyles = css` code { ${fontMono} + font-size: 1rem; + padding: 0 3px; + background-color: #eee; } dd, @@ -58,9 +61,7 @@ function Link(props) { css={{ color: '#0076ff', textDecoration: 'none', - ':hover': { - textDecoration: 'underline' - } + ':hover': { textDecoration: 'underline' } }} /> ); @@ -127,7 +128,10 @@ export default function App() { css={{ textAlign: 'center', fontSize: '4.5em', - letterSpacing: '0.05em' + letterSpacing: '0.05em', + '@media (min-width: 700px)': { + margin: '1.5em 0 1em' + } }} > UNPKG @@ -365,10 +369,11 @@ export default function App() {

- The origin infrastructure runs on{' '} + The origin servers run on world-class auto-scaling infrastructure + provided by{' '} Google Cloud which - automatically scales the number of available servers to meet the - current demand. + dynamically adjusts the number of available servers to meet the + current demand for maximum efficiency and uptime.