@@ -46,7 +26,32 @@ export default class PackageList extends React.Component {
hasPackages() {
const {packages} = this.props;
-
return packages.length > 0;
}
+
+ renderPackages = () => {
+ return (
+
+ {this.renderList()}
+
+ );
+ }
+
+ renderList = () => {
+ const { packages } = this.props;
+ return (
+ packages.map((pkg, i) => {
+ const { name, version, description, time, keywords, dist, homepage, bugs } = pkg;
+ const author = pkg.author;
+ // TODO: move format license to API side.
+ const license = formatLicense(pkg.license);
+ return (
+
+ {i !== 0 && }
+
+
+ );
+ })
+ );
+ }
}
diff --git a/src/components/PackageSidebar/Module/index.jsx b/src/components/PackageSidebar/Module/index.jsx
deleted file mode 100644
index ba2409d..0000000
--- a/src/components/PackageSidebar/Module/index.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import classes from './style.scss';
-
-export default function Module({title, description, children, className}) {
- return (
-
-
- {title}
- {description && {description}}
-
-
- {children}
-
-
- );
-}
-
-Module.propTypes = {
- title: PropTypes.string.isRequired,
- description: PropTypes.string,
- children: PropTypes.any.isRequired,
- className: PropTypes.string,
-};
diff --git a/src/components/PackageSidebar/Module/style.scss b/src/components/PackageSidebar/Module/style.scss
deleted file mode 100644
index 80164c7..0000000
--- a/src/components/PackageSidebar/Module/style.scss
+++ /dev/null
@@ -1,24 +0,0 @@
-@import '../../../styles/variables';
-@import '../../../styles/mixins';
-
-.module {
-
- margin-bottom: 10px;
-
- .moduleTitle {
- display: flex;
- align-items: flex-end;
- font-size: $font-size-lg;
- margin: 0 0 10px;
- padding: 5px 0;
- font-weight: $font-weight-semibold;
- @include border-bottom-default($greyGainsboro);
-
- span { // description
- font-size: $font-size-sm;
- color: $greyChateau;
- margin-left: auto;
- font-weight: $font-weight-light;
- }
- }
-}
diff --git a/src/components/PackageSidebar/ModuleContentPlaceholder/index.jsx b/src/components/PackageSidebar/ModuleContentPlaceholder/index.jsx
deleted file mode 100644
index 4df6744..0000000
--- a/src/components/PackageSidebar/ModuleContentPlaceholder/index.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import classes from './style.scss';
-
-export default function ModuleContentPlaceholder({text}) {
- return
{text}
;
-}
-ModuleContentPlaceholder.propTypes = {
- text: PropTypes.string.isRequired,
-};
diff --git a/src/components/PackageSidebar/ModuleContentPlaceholder/style.scss b/src/components/PackageSidebar/ModuleContentPlaceholder/style.scss
deleted file mode 100644
index 7980ba7..0000000
--- a/src/components/PackageSidebar/ModuleContentPlaceholder/style.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-@import '../../../styles/variables';
-
-.emptyPlaceholder {
- text-align: center;
- margin: 20px 0;
- font-size: $font-size-base;
- color: $greyChateau;
-}
diff --git a/src/components/PackageSidebar/index.jsx b/src/components/PackageSidebar/index.jsx
deleted file mode 100644
index 19db617..0000000
--- a/src/components/PackageSidebar/index.jsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import get from 'lodash/get';
-import LastSync from './modules/LastSync';
-import DistTags from './modules/DistTags';
-import Maintainers from './modules/Maintainers';
-import Dependencies from './modules/Dependencies';
-import PeerDependencies from './modules/PeerDependencies';
-import Infos from './modules/Infos';
-
-import {
- formatLicense,
- formatRepository,
- getLastUpdatedPackageTime,
- getRecentReleases,
-} from '../../utils/package';
-import API from '../../utils/api';
-import {DIST_TAGS} from '../../../lib/constants';
-
-export default class PackageSidebar extends React.Component {
- state = {};
-
- static propTypes = {
- packageName: PropTypes.string.isRequired,
- };
-
- constructor(props) {
- super(props);
- this.loadPackageData = this.loadPackageData.bind(this);
- }
-
- async componentDidMount() {
- const { packageName } = this.props;
- await this.loadPackageData(packageName);
- }
-
- async loadPackageData(packageName) {
- let packageMeta;
-
- try {
- packageMeta = await API.request(`sidebar/${packageName}`, 'GET');
- } catch (err) {
- this.setState({
- failed: true,
- });
- }
-
- this.setState({
- packageMeta,
- });
- }
-
- render() {
- const { packageMeta } = this.state;
-
- if (packageMeta) {
- const {time, _uplinks} = packageMeta;
-
- // Infos component
- const license = formatLicense(get(packageMeta, 'latest.license', null));
- const repository = formatRepository(
- get(packageMeta, 'latest.repository', null)
- );
- const homepage = get(packageMeta, 'latest.homepage', null);
-
- // dist-tags
- const distTags = packageMeta[DIST_TAGS];
-
- // Lastsync component
- const recentReleases = getRecentReleases(time);
- const lastUpdated = getLastUpdatedPackageTime(_uplinks);
-
- // Dependencies component
- const dependencies = get(packageMeta, 'latest.dependencies', {});
- const peerDependencies = get(packageMeta, 'latest.peerDependencies', {});
-
- // Maintainers component
- return (
-
- );
- }
- return (
-
- );
- }
-}
diff --git a/src/components/PackageSidebar/modules/Dependencies/index.jsx b/src/components/PackageSidebar/modules/Dependencies/index.jsx
deleted file mode 100644
index d2bb778..0000000
--- a/src/components/PackageSidebar/modules/Dependencies/index.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import Module from '../../Module';
-
-import {getDetailPageURL} from '../../../../utils/url';
-import ModuleContentPlaceholder from '../../ModuleContentPlaceholder';
-
-import classes from './style.scss';
-
-export const NO_DEPENDENCIES = 'Zero Dependencies!';
-export const DEP_ITEM_CLASS = 'dependency-item';
-
-const renderDependenciesList = (dependencies, dependenciesList) => {
- return (
-
- {dependenciesList.map((dependenceName, index) => {
- return (
- -
- {dependenceName}
- {index < dependenciesList.length - 1 && {', '}}
-
- );
- })}
-
- );
-};
-
-const Dependencies = ({dependencies = {}, title = 'Dependencies'}) => {
- const dependenciesList = Object.keys(dependencies);
- return (
-
- {dependenciesList.length > 0 ? (
- renderDependenciesList(dependencies, dependenciesList)
- ) : (
-
- )}
-
- );
-};
-
-Dependencies.propTypes = {
- dependencies: PropTypes.object,
- title: PropTypes.string,
-};
-
-export default Dependencies;
diff --git a/src/components/PackageSidebar/modules/Dependencies/style.scss b/src/components/PackageSidebar/modules/Dependencies/style.scss
deleted file mode 100644
index 8c8f84a..0000000
--- a/src/components/PackageSidebar/modules/Dependencies/style.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-@import '../../../../styles/variables';
-
-.dependenciesModule {
- li {
- display: inline-block;
- font-size: $font-size-sm;
- line-height: $line-height-xxs;
-
- a {
- color: inherit;
- }
- }
-}
diff --git a/src/components/PackageSidebar/modules/DistTags/index.jsx b/src/components/PackageSidebar/modules/DistTags/index.jsx
deleted file mode 100644
index 48f8cd1..0000000
--- a/src/components/PackageSidebar/modules/DistTags/index.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import React from 'react';
-import propTypes from 'prop-types';
-import Module from '../../Module';
-import ModuleContentPlaceholder from '../../ModuleContentPlaceholder';
-
-import classes from './style.scss';
-
-const renderDistTags = (distTags) => {
-
- const tags = Object.entries(distTags);
-
- return (
-
- {tags.map((tagItem) => {
- const [tag, version] = tagItem;
-
- return (
- -
- {tag}
- {version}
-
- );
- })}
-
- );
-};
-
-const DistTags = ({distTags = {}}) => {
- const hasTags = Object.keys(distTags).length > 0;
-
- return (
-
- {hasTags ? (
- renderDistTags(distTags)
- ) : (
-
- )}
-
- );
-};
-
-DistTags.propTypes = {
- distTags: propTypes.object,
-};
-
-export default DistTags;
diff --git a/src/components/PackageSidebar/modules/DistTags/style.scss b/src/components/PackageSidebar/modules/DistTags/style.scss
deleted file mode 100644
index f7823cc..0000000
--- a/src/components/PackageSidebar/modules/DistTags/style.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-@import '../../../../styles/variables';
-
-.releasesModule {
- li {
- display: flex;
- font-size: $font-size-sm;
- line-height: $line-height-xs;
-
- span:last-child {
- margin-left: auto;
- }
- }
-}
diff --git a/src/components/PackageSidebar/modules/Infos/index.jsx b/src/components/PackageSidebar/modules/Infos/index.jsx
deleted file mode 100644
index 14733b8..0000000
--- a/src/components/PackageSidebar/modules/Infos/index.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import Module from '../../Module';
-import ModuleContentPlaceholder from '../../ModuleContentPlaceholder';
-
-import classes from './style.scss';
-
-const renderSection = (title, url) => (
-
- {title}
-
- {url}
-
-
-);
-
-const Infos = ({homepage, repository, license}) => {
- const showInfo = homepage || repository || license;
- return (
-
- {showInfo ? (
-
- {homepage && renderSection('Homepage', homepage)}
- {repository && renderSection('Repository', repository)}
- {license && (
- -
- {'License'}
- {license}
-
)}
-
) : }
- );
-};
-
-Infos.propTypes = {
- homepage: PropTypes.string,
- repository: PropTypes.string,
- license: PropTypes.string,
-};
-
-export default Infos;
diff --git a/src/components/PackageSidebar/modules/Infos/style.scss b/src/components/PackageSidebar/modules/Infos/style.scss
deleted file mode 100644
index 13c8aa2..0000000
--- a/src/components/PackageSidebar/modules/Infos/style.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-@import '../../../../styles/variables';
-@import '../../../../styles/mixins';
-
-.infosModule {
- li {
- display: flex;
- font-size: $font-size-sm;
- line-height: $line-height-xs;
-
- a {
- color: inherit;
- max-width: 150px;
- @include ellipsis;
- }
-
- a:last-child,
- span:last-child {
- margin-left: auto;
- }
- }
-}
diff --git a/src/components/PackageSidebar/modules/LastSync/index.jsx b/src/components/PackageSidebar/modules/LastSync/index.jsx
deleted file mode 100644
index 3730b8e..0000000
--- a/src/components/PackageSidebar/modules/LastSync/index.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import propTypes from 'prop-types';
-import Module from '../../Module';
-import ModuleContentPlaceholder from '../../ModuleContentPlaceholder';
-
-import classes from './style.scss';
-
-const renderRecentReleases = (recentReleases) => (
-
- {recentReleases.map((versionInfo) => {
- const {version, time} = versionInfo;
- return (
- -
- {version}
- {time}
-
- );
- })}
-
-);
-
-const LastSync = ({recentReleases = [], lastUpdated = ''}) => {
- return (
-
- {recentReleases.length ? (
- renderRecentReleases(recentReleases)
- ) : (
-
- )}
-
- );
-};
-
-LastSync.propTypes = {
- recentReleases: propTypes.array,
- lastUpdated: propTypes.string,
-};
-
-export default LastSync;
diff --git a/src/components/PackageSidebar/modules/LastSync/style.scss b/src/components/PackageSidebar/modules/LastSync/style.scss
deleted file mode 100644
index f7823cc..0000000
--- a/src/components/PackageSidebar/modules/LastSync/style.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-@import '../../../../styles/variables';
-
-.releasesModule {
- li {
- display: flex;
- font-size: $font-size-sm;
- line-height: $line-height-xs;
-
- span:last-child {
- margin-left: auto;
- }
- }
-}
diff --git a/src/components/PackageSidebar/modules/Maintainers/MaintainerInfo/index.jsx b/src/components/PackageSidebar/modules/Maintainers/MaintainerInfo/index.jsx
deleted file mode 100644
index 5975e30..0000000
--- a/src/components/PackageSidebar/modules/Maintainers/MaintainerInfo/index.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import classes from './style.scss';
-
-const MaintainerInfo = ({title, name, avatar}) => {
- const avatarDescription = `${title} ${name}'s avatar`;
- return (
-
-
-
{name}
-
- );
-};
-
-MaintainerInfo.propTypes = {
- title: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- avatar: PropTypes.string.isRequired,
-};
-
-export default MaintainerInfo;
diff --git a/src/components/PackageSidebar/modules/Maintainers/MaintainerInfo/style.scss b/src/components/PackageSidebar/modules/Maintainers/MaintainerInfo/style.scss
deleted file mode 100644
index dc1805d..0000000
--- a/src/components/PackageSidebar/modules/Maintainers/MaintainerInfo/style.scss
+++ /dev/null
@@ -1,26 +0,0 @@
-@import '../../../../../styles/variables';
-@import '../../../../../styles/mixins';
-
-.maintainer {
- display: flex;
- line-height: $line-height-xl;
- cursor: default;
-
- &:not(:last-child) {
- margin-bottom: 10px;
- }
-
- img {
- width: 30px;
- height: 30px;
- margin-right: 10px;
- border-radius: 100%;
- flex-shrink: 0;
- }
-
- span {
- font-size: $font-size-sm;
- flex-shrink: 1;
- @include ellipsis;
- }
-}
diff --git a/src/components/PackageSidebar/modules/Maintainers/index.jsx b/src/components/PackageSidebar/modules/Maintainers/index.jsx
deleted file mode 100644
index bbdea22..0000000
--- a/src/components/PackageSidebar/modules/Maintainers/index.jsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import get from 'lodash/get';
-import filter from 'lodash/filter';
-import size from 'lodash/size';
-import has from 'lodash/has';
-import uniqBy from 'lodash/uniqBy';
-
-import Module from '../../Module';
-import MaintainerInfo from './MaintainerInfo';
-import ModuleContentPlaceholder from '../../ModuleContentPlaceholder';
-
-import classes from './style.scss';
-
-const CONTRIBUTORS_TO_SHOW = 5;
-
-export default class Maintainers extends React.Component {
- static propTypes = {
- packageMeta: PropTypes.object.isRequired,
- };
-
- state = {};
-
- constructor(props) {
- super(props);
- this.handleShowAllContributors = this.handleShowAllContributors.bind(this);
- }
-
- get author() {
- return get(this, 'props.packageMeta.latest.author');
- }
-
- get contributors() {
- const contributors = get(this, 'props.packageMeta.latest.contributors', {});
- return filter(contributors, (contributor) => {
- return (
- contributor.name !== get(this, 'author.name') &&
- contributor.email !== get(this, 'author.email')
- );
- });
- }
-
- get showAllContributors() {
- const { showAllContributors } = this.state;
- return showAllContributors || size(this.contributors) <= 5;
- }
-
- get uniqueContributors() {
- if (!this.contributors) {
- return [];
- }
-
- return uniqBy(this.contributors, (contributor) => contributor.name).slice(
- 0,
- CONTRIBUTORS_TO_SHOW
- );
- }
-
- handleShowAllContributors() {
- this.setState({
- showAllContributors: true,
- });
- }
-
- renderContributors() {
- if (!this.contributors) return null;
-
- return (this.showAllContributors
- ? this.contributors
- : this.uniqueContributors
- ).map((contributor, index) => {
- return (
-
- );
- });
- }
-
- renderAuthorAndContributors(author) {
- return (
-
-
- {author &&
- author.name && (
-
- )}
- {this.renderContributors()}
-
- {!this.showAllContributors && (
-
- )}
-
- );
- }
-
- render() {
- const contributors = this.renderContributors();
- return (
-
- {contributors.length || has(this.author, 'name') ? (
- this.renderAuthorAndContributors(this.author)
- ) : (
-
- )}
-
- );
- }
-}
diff --git a/src/components/PackageSidebar/modules/Maintainers/style.scss b/src/components/PackageSidebar/modules/Maintainers/style.scss
deleted file mode 100644
index 6294904..0000000
--- a/src/components/PackageSidebar/modules/Maintainers/style.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-@import '../../../../styles/variables';
-
-.maintainersModule {
- .showAllContributors {
- cursor: pointer;
- width: 100%;
- background: none;
- border: none;
- font-size: $font-size-sm;
- text-align: center;
- padding: 10px 0;
- }
-}
diff --git a/src/components/PackageSidebar/modules/PeerDependencies/index.jsx b/src/components/PackageSidebar/modules/PeerDependencies/index.jsx
deleted file mode 100644
index 287073f..0000000
--- a/src/components/PackageSidebar/modules/PeerDependencies/index.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import Dependencies from '../Dependencies';
-
-export const TITLE = 'Peer Dependencies';
-
-const PeerDependencies = ({dependencies = {}, title = TITLE}) => {
- return (
-
- );
-};
-
-PeerDependencies.propTypes = {
- dependencies: PropTypes.object,
- title: PropTypes.string,
-};
-
-export default PeerDependencies;
diff --git a/src/components/Repository/img/git.png b/src/components/Repository/img/git.png
new file mode 100644
index 0000000..51f4ae5
Binary files /dev/null and b/src/components/Repository/img/git.png differ
diff --git a/src/components/Repository/index.js b/src/components/Repository/index.js
index ded0216..68c2239 100644
--- a/src/components/Repository/index.js
+++ b/src/components/Repository/index.js
@@ -1,61 +1,59 @@
-/* eslint no-unused-vars: 0 */
/* eslint react/jsx-max-depth: 0 */
-import React, {Component, Fragment} from 'react';
+import React, {Component} from 'react';
+import Avatar from '@material-ui/core/Avatar';
+import List from '@material-ui/core/List';
+import ListItemText from '@material-ui/core/ListItemText';
import { DetailContextConsumer } from '../../pages/version/index';
-import Card from '@material-ui/core/Card/index';
-import CardContent from '@material-ui/core/CardContent/index';
-import Grid from '@material-ui/core/Grid/index';
-import GitHub from '../../icons/GitHub';
import CopyToClipBoard from '../CopyToClipBoard';
-import BugReport from '@material-ui/icons/BugReport';
-import CardActions from '@material-ui/core/CardActions/index';
-import Button from '@material-ui/core/Button';
-import {GridRepo} from './styles';
+
+import { Heading, GithubLink, RepositoryListItem } from './styles';
+import git from './img/git.png';
class Repository extends Component
{
render() {
return (
{(context) => {
- return this.renderAuthor(context);
+ return this.renderRepository(context);
}}
);
};
- renderAuthor = ({packageMeta}) => {
- const { repository, bugs } = packageMeta.latest;
- if (!repository) {
+ renderRepositoryText(url) {
+ return ({url});
+ }
+
+ renderRepository = ({packageMeta}) => {
+ const {
+ repository: {
+ url,
+ } = {},
+ } = packageMeta.latest;
+
+ if (!url) {
return null;
}
return (
-
-
-
- {this.renderRepository(repository, bugs)}
-
-
-
-
-
-
-
+ <>
+ {'Repository'}}>
+
+
+
+
+
+ >
);
}
-
- renderRepository = ({url, type}, bugs) => {
+
+ renderContent(url) {
return (
-
-
-
-
-
-
-
-
+
+ {this.renderRepositoryText(url)}
+
);
}
}
diff --git a/src/components/Repository/styles.js b/src/components/Repository/styles.js
index 8533347..12eddd1 100644
--- a/src/components/Repository/styles.js
+++ b/src/components/Repository/styles.js
@@ -5,9 +5,42 @@
import styled from 'react-emotion';
import Grid from '@material-ui/core/Grid/index';
+import ListItem from '@material-ui/core/ListItem/index';
+import Typography from '@material-ui/core/Typography/index';
+
+import Github from '../../icons/GitHub';
+import colors from '../../utils/styles/colors';
+
+export const Heading = styled(Typography)`
+ && {
+ font-weight: 700;
+ text-transform: capitalize;
+ }
+`;
export const GridRepo = styled(Grid)`
&& {
align-items: center;
}
`;
+
+export const GithubLink = styled('a')`
+ && {
+ color: ${colors.primary};
+ }
+`;
+
+export const GithubLogo = styled(Github)`
+ && {
+ font-size: 40px;
+ color: ${colors.primary};
+ background-color: ${colors.greySuperLight};
+ }
+`;
+
+export const RepositoryListItem = styled(ListItem)`
+ && {
+ padding-left: 0;
+ padding-right: 0;
+ }
+`;
diff --git a/src/components/Search/index.js b/src/components/Search/index.js
index 7fcc752..a013c71 100644
--- a/src/components/Search/index.js
+++ b/src/components/Search/index.js
@@ -100,7 +100,7 @@ export class Search extends Component {
case 'enter':
this.setState({ search: '' });
// $FlowFixMe
- history.push(`/-/web/version/${suggestionValue}`);
+ history.push(`/-/web/detail/${suggestionValue}`);
break;
}
};
diff --git a/src/components/Tag/styles.js b/src/components/Tag/styles.js
index a6eea8f..cd624ed 100644
--- a/src/components/Tag/styles.js
+++ b/src/components/Tag/styles.js
@@ -11,10 +11,10 @@ export const Wrapper = styled.span`
vertical-align: middle;
line-height: 22px;
border-radius: 2px;
- color: #9f9f9f;
- background-color: hsla(0, 0%, 51%, 0.1);
+ color: #485a3e;
+ background-color: #f3f4f2;
padding: 0.22rem 0.4rem;
- margin: 5px 10px 0 0;
+ margin: 8px 8px 0 0;
${ellipsis('300px')};
}
`;
diff --git a/src/components/UpLinks/index.js b/src/components/UpLinks/index.js
index 13bf1d3..8756a07 100644
--- a/src/components/UpLinks/index.js
+++ b/src/components/UpLinks/index.js
@@ -1,13 +1,15 @@
/**
* @prettier
*/
-
-import { DetailContextConsumer } from '../../pages/version/index';
-import { formatDateDistance } from '../../utils/package';
-import { Heading, Spacer, ListItemText } from './styles';
+import React from 'react';
import List from '@material-ui/core/List/index';
import ListItem from '@material-ui/core/ListItem/index';
-import React from 'react';
+
+import { DetailContextConsumer } from '../../pages/version/index';
+import NoItems from '../NoItems';
+import { formatDateDistance } from '../../utils/package';
+
+import { Heading, Spacer, ListItemText } from './styles';
class UpLinks extends React.PureComponent {
render() {
@@ -15,7 +17,7 @@ class UpLinks extends React.PureComponent {
// $FlowFixMe
{({ packageMeta }) => {
- return this.renderContent(packageMeta._uplinks);
+ return this.renderContent(packageMeta._uplinks, packageMeta.latest);
}}
);
@@ -35,15 +37,18 @@ class UpLinks extends React.PureComponent {
);
- renderContent(uplinks) {
- return (
- uplinks && (
- <>
- {'Uplinks'}
- {this.renderUpLinksList(uplinks)}
- >
- )
- );
+ renderContent(uplinks, { name }) {
+ if (Object.keys(uplinks).length > 0) {
+ return (
+ uplinks && (
+ <>
+ {'Uplinks'}
+ {this.renderUpLinksList(uplinks)}
+ >
+ )
+ );
+ }
+ return ;
}
}
diff --git a/src/components/Versions/index.js b/src/components/Versions/index.js
index 7dfe711..73496cf 100644
--- a/src/components/Versions/index.js
+++ b/src/components/Versions/index.js
@@ -17,40 +17,44 @@ class Versions extends React.PureComponent {
// $FlowFixMe
{({ packageMeta }) => {
- return this.renderContent(packageMeta[DIST_TAGS], packageMeta.versions);
+ return this.renderContent(packageMeta);
}}
);
}
- renderPackageList = (packages: any, isVersion: boolean = false) => (
-
- {Object.keys(packages)
- .reverse()
- .map(version => (
-
- {version}
-
- {isVersion ? `${formatDateDistance('2017-10-26T09:03:15.044Z')} ago` : packages[version]}
-
- ))}
-
- );
+ renderPackageList = (packages: any, isVersion: boolean = false, timeMap: Object = {}) => {
+ return (
+
+ {Object.keys(packages)
+ .reverse()
+ .map(version => (
+
+ {version}
+
+ {isVersion && timeMap[version] ? `${formatDateDistance(timeMap[version])} ago` : packages[version]}
+
+ ))}
+
+ );
+ };
// $FlowFixMe
- renderContent(distTags: object, versions: object) {
+ renderContent(packageMeta) {
+ const { versions = {}, time: timeMap = {}, [DIST_TAGS]: distTags = {} } = packageMeta;
+
return (
<>
{distTags && (
<>
{'Current Tags'}
- {this.renderPackageList(distTags)}
+ {this.renderPackageList(distTags, false, timeMap)}
>
)}
{versions && (
<>
{'Version History'}
- {this.renderPackageList(versions, true)}
+ {this.renderPackageList(versions, true, timeMap)}
>
)}
>
diff --git a/src/history.js b/src/history.js
index d000bcb..f8407b0 100644
--- a/src/history.js
+++ b/src/history.js
@@ -2,14 +2,8 @@
* @prettier
*/
-import {createBrowserHistory} from 'history';
+import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
-// Listen for changes to the current location.
-history.listen((location, action) => {
- // location is an object like window.location
- console.log('====>', action, location.pathname, location.state);
-});
-
export default history;
diff --git a/src/index.js b/src/index.js
index c1c9331..136c63c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,12 +1,14 @@
-import React from "react";
-import ReactDOM from "react-dom";
-import { AppContainer } from "react-hot-loader";
+import './utils/__setPublicPath__';
-import App from "./app";
+import React from 'react';
+import ReactDOM from 'react-dom';
+import {AppContainer} from 'react-hot-loader';
-const rootNode = document.getElementById("root");
+import App from './app';
-const renderApp = Component => {
+const rootNode = document.getElementById('root');
+
+const renderApp = (Component) => {
ReactDOM.render(
@@ -18,7 +20,7 @@ const renderApp = Component => {
renderApp(App);
if (module.hot) {
- module.hot.accept("./app", () => {
+ module.hot.accept('./app', () => {
renderApp(App);
});
}
diff --git a/src/pages/detail/detail.scss b/src/pages/detail/detail.scss
deleted file mode 100644
index 849a7f6..0000000
--- a/src/pages/detail/detail.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-@import '../../styles/variables';
-@import '../../styles/mixins';
-
-.twoColumn {
- @include container-size;
- display: flex;
-
- > div {
- &:first-child {
- flex-shrink: 1;
- min-width: 300px;
- width: 100%;
- }
- }
-
- > aside {
- &:last-child {
- margin-left: auto;
-
- padding-left: 15px;
- flex-shrink: 0;
- width: 285px;
- }
- }
-}
diff --git a/src/pages/detail/index.jsx b/src/pages/detail/index.jsx
deleted file mode 100644
index bc526a4..0000000
--- a/src/pages/detail/index.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import isEmpty from 'lodash/isEmpty';
-
-import PackageDetail from '../../components/PackageDetail';
-import NotFound from '../../components/NotFound';
-import Spinner from '../../components/Spinner';
-import API from '../../utils/api';
-
-import classes from './detail.scss';
-import PackageSidebar from '../../components/PackageSidebar/index';
-
-export default class Detail extends Component {
- static propTypes = {
- match: PropTypes.object,
- isUserLoggedIn: PropTypes.bool,
- };
-
- state = {
- readMe: '',
- notFound: false,
- };
-
- getPackageName(props = this.props) {
- const params = props.match.params;
- return `${(params.scope && '@' + params.scope + '/') || ''}${
- params.package
- }`;
- }
-
- get packageName() {
- return this.getPackageName();
- }
-
- async componentDidMount() {
- await this.loadPackageInfo(this.packageName);
- }
-
- componentDidUpdate(prevProps) {
- const { isUserLoggedIn, match } = this.props;
- const condition1 = prevProps.isUserLoggedIn !== isUserLoggedIn;
- const condition2 =
- prevProps.match.params.package !== match.params.package;
- if (condition1 || condition2) {
- const packageName = this.getPackageName(this.props);
- this.loadPackageInfo(packageName);
- }
- }
-
- async loadPackageInfo(packageName) {
- this.setState({
- readMe: '',
- });
-
- try {
- const resp = await API.request(`package/readme/${packageName}`, 'GET');
- this.setState({
- readMe: resp,
- notFound: false,
- });
- } catch (err) {
- this.setState({
- notFound: true,
- });
- }
- }
-
- render() {
- const { notFound, readMe } = this.state;
-
- if (notFound) {
- return (
-
-
-
- );
- } else if (isEmpty(readMe)) {
- return ;
- }
- return (
-
- );
- }
-}
diff --git a/src/pages/home/index.js b/src/pages/home/index.js
index 94530f8..e2661b3 100644
--- a/src/pages/home/index.js
+++ b/src/pages/home/index.js
@@ -1,4 +1,4 @@
-import React, {Component} from 'react';
+import React, { Component } from 'react';
import PropTypes from 'prop-types';
import PackageList from '../../components/PackageList';
@@ -10,10 +10,10 @@ class Home extends Component {
};
render() {
- const {packages} = this.props;
+ const { packages } = this.props;
return (
-
-
+
);
}
diff --git a/src/pages/version/index.js b/src/pages/version/index.js
index e40ff3f..ad7cefb 100644
--- a/src/pages/version/index.js
+++ b/src/pages/version/index.js
@@ -3,13 +3,14 @@
* @flow
*/
-import React, {Component} from 'react';
+import React, { Component } from 'react';
import Grid from '@material-ui/core/Grid/index';
import Loading from '../../components/Loading';
import DetailContainer from '../../components/DetailContainer';
import DetailSidebar from '../../components/DetailSidebar';
-import {callDetailPage} from '../../utils/calls';
-import {getRouterPackageName} from '../../utils/package';
+import { callDetailPage } from '../../utils/calls';
+import { getRouterPackageName } from '../../utils/package';
+import NotFound from '../../components/NotFound';
export const DetailContext = React.createContext();
@@ -35,9 +36,9 @@ class VersionPage extends Component
{
/* eslint no-unused-vars: 0 */
async componentDidUpdate(nextProps: any, prevState: any) {
- const {packageName} = this.state;
+ const { packageName } = this.state;
if (packageName !== prevState.packageName) {
- const {readMe, packageMeta} = await callDetailPage(packageName);
+ const { readMe, packageMeta } = await callDetailPage(packageName);
this.setState({
readMe,
packageMeta,
@@ -49,7 +50,7 @@ class VersionPage extends Component {
}
static getDerivedStateFromProps(nextProps: any, prevState: any) {
- const {match} = nextProps;
+ const { match } = nextProps;
const packageName = getRouterPackageName(match);
if (packageName !== prevState.packageName) {
@@ -70,7 +71,7 @@ class VersionPage extends Component {
}
async loadPackageInfo() {
- const {packageName} = this.state;
+ const { packageName } = this.state;
// FIXME: use utility
document.title = `Verdaccio - ${packageName}`;
@@ -79,7 +80,7 @@ class VersionPage extends Component {
});
try {
- const {readMe, packageMeta} = await callDetailPage(packageName);
+ const { readMe, packageMeta } = await callDetailPage(packageName);
this.setState({
readMe,
packageMeta,
@@ -103,11 +104,15 @@ class VersionPage extends Component {
};
render() {
- const {isLoading, packageMeta, readMe, packageName} = this.state;
+ const { isLoading, packageMeta, readMe, packageName } = this.state;
- if (isLoading === false) {
+ if (isLoading) {
+ return ;
+ } else if (!packageMeta) {
+ return ;
+ } else {
return (
-
+
{this.renderDetail()}
@@ -118,8 +123,6 @@ class VersionPage extends Component {
);
- } else {
- return ;
}
}
diff --git a/src/router.js b/src/router.js
index 915d919..53aaeb8 100644
--- a/src/router.js
+++ b/src/router.js
@@ -5,19 +5,17 @@
/* eslint react/jsx-max-depth:0 */
-import React, { Component, Fragment } from "react";
-import { Router, Route, Switch } from "react-router-dom";
-import { AppContextConsumer } from "./app";
+import React, { Component, Fragment } from 'react';
+import { Router, Route, Switch } from 'react-router-dom';
+import { AppContextConsumer } from './app';
-// import {asyncComponent} from '../others/utils/asyncComponent';
-import history from "./history";
-import Header from "./components/Header";
-import HomePage from "./pages/home";
-import NotFound from './components/NotFound'
-// const NotFound = asyncComponent(() => import("./components/NotFound"));
-// const DetailPackage = asyncComponent(() => import("./pages/detail"));
-// const VersionPackage = asyncComponent(() => import("./pages/version"));
-// const HomePage = asyncComponent(() => import("./pages/home"));
+import { asyncComponent } from './utils/asyncComponent';
+import history from './history';
+import Header from './components/Header';
+
+const NotFound = asyncComponent(() => import('./components/NotFound'));
+const VersionPackage = asyncComponent(() => import('./pages/version'));
+const HomePage = asyncComponent(() => import('./pages/home'));
class RouterApp extends Component {
render() {
@@ -26,11 +24,9 @@ class RouterApp extends Component {
{this.renderHeader()}
-
- {/*
-
-
- */}
+
+
+
@@ -44,15 +40,7 @@ class RouterApp extends Component {
return (
{function renderConsumerVersionPage({ logoUrl, scope, user }) {
- return (
-
- );
+ return ;
}}
);
@@ -62,21 +50,7 @@ class RouterApp extends Component {
return (
{function renderConsumerVersionPage({ isUserLoggedIn, packages }) {
- return (
-
- );
- }}
-
- );
- };
-
- renderDetailPage = (routerProps: any) => {
- return (
-
- {function renderConsumerVersionPage({ isUserLoggedIn }) {
- return (
-
- );
+ return ;
}}
);
@@ -86,9 +60,7 @@ class RouterApp extends Component {
return (
{function renderConsumerVersionPage({ isUserLoggedIn }) {
- return (
-
- );
+ return ;
}}
);
diff --git a/src/styles/mixins.scss b/src/styles/mixins.scss
index 17bcb83..2b2bc0e 100644
--- a/src/styles/mixins.scss
+++ b/src/styles/mixins.scss
@@ -37,9 +37,10 @@
}
@mixin container-size {
- margin-left: auto;
- margin-right: auto;
@media screen and (min-width: $break-lg) {
max-width: $break-lg;
+ width: 100%;
+ margin-left: auto;
+ margin-right: auto;
}
}
diff --git a/src/utils/__setPublicPath__.js b/src/utils/__setPublicPath__.js
index ad0f2d9..f528199 100644
--- a/src/utils/__setPublicPath__.js
+++ b/src/utils/__setPublicPath__.js
@@ -1,3 +1,3 @@
if (!__DEBUG__) {
- __webpack_public_path__ = window.VERDACCIO_API_URL.replace(/\/verdaccio\/$/, '/static/'); // eslint-disable-line
+ __webpack_public_path__ = window.VERDACCIO_API_URL.replace(/\/verdaccio\/$/, '/static/') // eslint-disable-line
}
diff --git a/src/utils/api.js b/src/utils/api.js
index 2d23a67..20b0faf 100644
--- a/src/utils/api.js
+++ b/src/utils/api.js
@@ -2,48 +2,48 @@ import storage from './storage';
class API {
request(url, method = 'GET', options = {}) {
- if (!window.VERDACCIO_API_URL) {
- throw new Error('VERDACCIO_API_URL is not defined!');
- }
+ if (!window.VERDACCIO_API_URL) {
+ throw new Error('VERDACCIO_API_URL is not defined!');
+ }
- const token = storage.getItem('token');
- if (token) {
- if (!options.headers) options.headers = {};
+ const token = storage.getItem('token');
+ if (token) {
+ if (!options.headers) options.headers = {};
- options.headers.authorization = `Bearer ${token}`;
- }
+ options.headers.authorization = `Bearer ${token}`;
+ }
- if (!['http://', 'https://', '//'].some((prefix) => url.startsWith(prefix))) {
- url = window.VERDACCIO_API_URL + url;
- }
+ if (!['http://', 'https://', '//'].some((prefix) => url.startsWith(prefix))) {
+ url = window.VERDACCIO_API_URL + url;
+ }
- /**
- * Handles response according to content type
- * @param {object} response
- * @returns {promise}
- */
- function handleResponseType(response) {
- if (response.headers) {
- const contentType = response.headers.get('Content-Type');
- if (contentType.includes('application/pdf')) {
- return Promise.all([response.ok, response.blob()]);
- }
- if (contentType.includes('application/json')) {
- return Promise.all([response.ok, response.json()]);
- }
- // it includes all text types
- if (contentType.includes('text/')) {
- return Promise.all([response.ok, response.text()]);
+ /**
+ * Handles response according to content type
+ * @param {object} response
+ * @returns {promise}
+ */
+ function handleResponseType(response) {
+ if (response.headers) {
+ const contentType = response.headers.get('Content-Type');
+ if (contentType.includes('application/pdf')) {
+ return Promise.all([response.ok, response.blob()]);
+ }
+ if (contentType.includes('application/json')) {
+ return Promise.all([response.ok, response.json()]);
+ }
+ // it includes all text types
+ if (contentType.includes('text/')) {
+ return Promise.all([response.ok, response.text()]);
+ }
}
}
- }
- return new Promise((resolve, reject) => {
- fetch(url, {
- method,
- credentials: 'same-origin',
- ...options,
- })
+ return new Promise((resolve, reject) => {
+ fetch(url, {
+ method,
+ credentials: 'same-origin',
+ ...options,
+ })
.then(handleResponseType)
.then(([responseOk, body]) => {
if (responseOk) {
@@ -52,11 +52,11 @@ class API {
reject(body);
}
})
- .catch((error) => {
+ .catch(error => {
reject(error);
});
- });
- }
+ });
+ }
}
export default new API();
diff --git a/src/utils/asyncComponent.js b/src/utils/asyncComponent.js
index 6ffa7b1..7aadf71 100644
--- a/src/utils/asyncComponent.js
+++ b/src/utils/asyncComponent.js
@@ -1,24 +1,32 @@
+/**
+ * @prettier
+ */
+
import React from 'react';
export function asyncComponent(getComponent) {
return class AsyncComponent extends React.Component {
static Component = null;
- state = {Component: AsyncComponent.Component};
+ state = { Component: AsyncComponent.Component };
componentDidMount() {
- const {Component} = this.state;
-
+ const { Component } = this.state;
if (!Component) {
- getComponent().then(({default: Component}) => {
- AsyncComponent.Component = Component;
- /* eslint react/no-did-mount-set-state:0 */
- this.setState({Component});
- });
+ getComponent()
+ .then(({ default: Component }) => {
+ AsyncComponent.Component = Component;
+ /* eslint react/no-did-mount-set-state:0 */
+ this.setState({ Component });
+ })
+ .catch(err => {
+ console.error(err);
+ });
}
}
render() {
- const {Component} = this.state;
+ const { Component } = this.state;
if (Component) {
+ // eslint-disable-next-line verdaccio/jsx-spread
return ;
}
diff --git a/src/utils/file-size.js b/src/utils/file-size.js
new file mode 100644
index 0000000..5281a57
--- /dev/null
+++ b/src/utils/file-size.js
@@ -0,0 +1,5 @@
+export default function fileSizeSI(a, b, c, d, e) {
+ return (b = Math, c = b.log, d = 1e3, e = c(a) / c(d) | 0, a / b.pow(d, e)).toFixed(2)
+ + ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes');
+};
+
diff --git a/src/utils/login.js b/src/utils/login.js
index 0dfe646..a51083d 100644
--- a/src/utils/login.js
+++ b/src/utils/login.js
@@ -1,76 +1,70 @@
-import isString from "lodash/isString";
-import isNumber from "lodash/isNumber";
-import isEmpty from "lodash/isEmpty";
-import { Base64 } from "js-base64";
-import API from "./api";
-
-const HEADERS = {
- JSON: "application/json",
- JSON_CHARSET: "application/json; charset=utf-8",
- OCTET_STREAM: "application/octet-stream; charset=utf-8",
- TEXT_CHARSET: "text/plain; charset=utf-8",
- GZIP: "gzip"
-};
+import isString from 'lodash/isString';
+import isNumber from 'lodash/isNumber';
+import isEmpty from 'lodash/isEmpty';
+import {Base64} from 'js-base64';
+import API from './api';
+import {HEADERS} from '../../lib/constants';
export function isTokenExpire(token) {
- if (!isString(token)) {
- return true;
- }
+ if (!isString(token)) {
+ return true;
+ }
- let [, payload] = token.split(".");
+ let [,payload] = token.split('.');
- if (!payload) {
- return true;
- }
+ if (!payload) {
+ return true;
+ }
- try {
- payload = JSON.parse(Base64.decode(payload));
- } catch (error) {
- // eslint-disable-next-line
- console.error("Invalid token:", error, token);
- return true;
- }
+ try {
+ payload = JSON.parse(Base64.decode(payload));
+ } catch (error) {
+ // eslint-disable-next-line
+ console.error('Invalid token:', error, token);
+ return true;
+ }
- if (!payload.exp || !isNumber(payload.exp)) {
- return true;
- }
- // Report as expire before (real expire time - 30s)
- const jsTimestamp = payload.exp * 1000 - 30000;
- const expired = Date.now() >= jsTimestamp;
+ if (!payload.exp || !isNumber(payload.exp)) {
+ return true;
+ }
+ // Report as expire before (real expire time - 30s)
+ const jsTimestamp = (payload.exp * 1000) - 30000;
+ const expired = Date.now() >= jsTimestamp;
- return expired;
+ return expired;
}
+
export async function makeLogin(username, password) {
- // checks isEmpty
- if (isEmpty(username) || isEmpty(password)) {
- const error = {
- title: "Unable to login",
- type: "error",
- description: "Username or password can't be empty!"
- };
- return { error };
- }
+ // checks isEmpty
+ if (isEmpty(username) || isEmpty(password)) {
+ const error = {
+ title: 'Unable to login',
+ type: 'error',
+ description: 'Username or password can\'t be empty!',
+ };
+ return {error};
+ }
- try {
- const response = await API.request("login", "POST", {
- body: JSON.stringify({ username, password }),
- headers: {
- Accept: HEADERS.JSON,
- "Content-Type": HEADERS.JSON
- }
- });
- const result = {
- username: response.username,
- token: response.token
- };
- return result;
- } catch (e) {
- const error = {
- title: "Unable to login",
- type: "error",
- description: e.error
- };
- return { error };
- }
+ try {
+ const response = await API.request('login', 'POST', {
+ body: JSON.stringify({username, password}),
+ headers: {
+ Accept: HEADERS.JSON,
+ 'Content-Type': HEADERS.JSON,
+ },
+ });
+ const result = {
+ username: response.username,
+ token: response.token,
+ };
+ return result;
+ } catch (e) {
+ const error = {
+ title: 'Unable to login',
+ type: 'error',
+ description: e.error,
+ };
+ return {error};
+ }
}
diff --git a/src/utils/package.js b/src/utils/package.js
index b3d18e1..3e26213 100644
--- a/src/utils/package.js
+++ b/src/utils/package.js
@@ -4,7 +4,6 @@ import format from 'date-fns/format';
import distanceInWordsToNow from 'date-fns/distance_in_words_to_now';
export const TIMEFORMAT = 'DD.MM.YYYY, HH:mm:ss';
-export const DEFAULT_USER = 'Anonymous';
/**
* Formats license field for webui.
@@ -39,36 +38,6 @@ export function formatRepository(repository) {
}
-/**
- * Formats author field for webui.
- * @see https://docs.npmjs.com/files/package.json#author
- */
-export function formatAuthor(author) {
- let authorDetails = {
- name: DEFAULT_USER,
- email: '',
- avatar: '',
- };
-
- if (isString(author)) {
- authorDetails = {
- ...authorDetails,
- name: author ? author : authorDetails.name,
- };
- }
-
- if (isObject(author)) {
- authorDetails = {
- ...authorDetails,
- name: author.name ? author.name : authorDetails.name,
- email: author.email ? author.email : authorDetails.email,
- avatar: author.avatar ? author.avatar : authorDetails.avatar,
- };
- }
-
- return authorDetails;
-}
-
/**
* For component
* @param {array} uplinks
diff --git a/src/utils/styles/colors.js b/src/utils/styles/colors.js
index 4cd495f..fecfa9c 100644
--- a/src/utils/styles/colors.js
+++ b/src/utils/styles/colors.js
@@ -10,7 +10,10 @@ const colors = {
grey: '#808080',
greySuperLight: '#f5f5f5',
greyLight: '#d3d3d3',
+ greyLight2: '#908ba1',
+ greyLight3: '#f3f4f240',
greyDark: '#a9a9a9',
+ greyDark2: '#586069',
greyChateau: '#95989a',
greyGainsboro: '#e3e3e3',
greyAthens: '#d3dddd',
diff --git a/src/utils/styles/media.js b/src/utils/styles/media.js
index 3240d70..1c74025 100644
--- a/src/utils/styles/media.js
+++ b/src/utils/styles/media.js
@@ -1,6 +1,6 @@
import { css } from 'emotion';
-const breakpoints = {
+export const breakpoints = {
small: 576,
medium: 768,
large: 1024,
diff --git a/src/utils/url.js b/src/utils/url.js
index 5346870..d704be5 100644
--- a/src/utils/url.js
+++ b/src/utils/url.js
@@ -2,11 +2,3 @@ export function getRegistryURL() {
// Don't add slash if it's not a sub directory
return `${location.origin}${location.pathname === '/' ? '' : location.pathname}`;
}
-
-/**
- * Get specified package detail page url
- * @param {string} packageName
- */
-export function getDetailPageURL(packageName) {
- return `${getRegistryURL()}/-/web/version/${packageName}`;
-}
diff --git a/src/utils/windows.js b/src/utils/windows.js
index 2a15a2c..9fb3b37 100644
--- a/src/utils/windows.js
+++ b/src/utils/windows.js
@@ -1,3 +1,3 @@
export function goToVerdaccioWebsite() {
- window.open('https://www.verdaccio.org/', '_blank');
+ window.open('https://www.verdaccio.org/', '_blank');
}