chore: sync with 4.x webui

This commit is contained in:
Juan Picado @jotadeveloper
2019-03-27 23:39:06 +01:00
parent e2d478d65b
commit 133a5f0171
88 changed files with 1302 additions and 1656 deletions

View File

@@ -2,104 +2,160 @@
* @prettier
* @flow
*/
import React from 'react';
import type { Element } from 'react';
import { spacing } from '../../utils/styles/mixings';
import BugReport from '@material-ui/icons/BugReport';
import Grid from '@material-ui/core/Grid/index';
import HomeIcon from '@material-ui/icons/Home';
import ListItem from '@material-ui/core/ListItem/index';
import Tooltip from '@material-ui/core/Tooltip/index';
import Tag from '../Tag';
import fileSizeSI from '../../utils/file-size';
import { formatDate, formatDateDistance } from '../../utils/package';
import { IProps } from './types';
import {
WrapperLink,
Header,
MainInfo,
Name,
Version,
Overview,
Published,
OverviewItem,
Description,
Icon,
Text,
Details,
Avatar,
Author,
Field,
Content,
Footer,
Avatar,
Description,
Details,
GridRightAligned,
Icon,
IconButton,
OverviewItem,
PackageList,
PackageListItem,
PackageListItemText,
PackageTitle,
Published,
TagContainer,
Text,
WrapperLink,
} from './styles';
const getInitialsName = (name: string) =>
name
.split(' ')
.reduce((accumulator, currentValue) => accumulator.charAt(0) + currentValue.charAt(0), '')
.toUpperCase();
const Package = ({
author: { name: authorName, avatar: authorAvatar },
bugs: { url } = {},
description,
dist: { unpackedSize } = {},
homepage,
keywords = [],
license,
name: packageName,
time,
version,
}: IProps): Element<WrapperLink> => {
//
const renderVersionInfo = () =>
version && (
<OverviewItem>
<Icon name={'version'} />
{`v${version}`}
</OverviewItem>
);
const Package = ({ name: label, version, time, author: { name, avatar }, description, license, keywords = [] }: IProps): Element<WrapperLink> => {
const renderMainInfo = () => (
<MainInfo>
<Name>{label}</Name>
<Version>{`v${version}`}</Version>
</MainInfo>
);
const renderAuthorInfo = () =>
authorName && (
<Author>
<Avatar alt={authorName} src={authorAvatar} />
<Details>
<Text text={authorName} />
</Details>
</Author>
);
const renderAuthorInfo = () => (
<Author>
<Avatar alt={name} src={avatar}>
{!avatar && getInitialsName(name)}
</Avatar>
<Details>
<Text text={name} weight={'bold'} />
</Details>
</Author>
);
const renderFileSize = () =>
unpackedSize && (
<OverviewItem>
<Icon name={'filebinary'} />
{fileSizeSI(unpackedSize)}
</OverviewItem>
);
const renderLicenseInfo = () =>
license && (
<OverviewItem>
<Icon modifiers={spacing('margin', '4px', '5px', '0px', '0px')} name={'license'} pointer={true} />
<Icon name={'law'} />
{license}
</OverviewItem>
);
const renderPublishedInfo = () => (
<OverviewItem>
<Icon name={'time'} pointer={true} />
<Published modifiers={spacing('margin', '0px', '5px', '0px', '0px')}>{`Published on ${formatDate(time)}`}</Published>
{`${formatDateDistance(time)} ago`}
</OverviewItem>
);
const renderDescription = () =>
description && (
<Field>
<Description>{description}</Description>
</Field>
const renderPublishedInfo = () =>
time && (
<OverviewItem>
<Icon name={'time'} />
<Published>{`Published on ${formatDate(time)} `}</Published>
{`${formatDateDistance(time)} ago`}
</OverviewItem>
);
const renderHomePageLink = () =>
homepage && (
<a href={homepage} target={'_blank'}>
<Tooltip aria-label={'Homepage'} title={'Visit homepage'}>
<IconButton aria-label={'Homepage'}>
{/* eslint-disable-next-line react/jsx-max-depth */}
<HomeIcon />
</IconButton>
</Tooltip>
</a>
);
const renderBugsLink = () =>
url && (
<a href={url} target={'_blank'}>
<Tooltip aria-label={'Bugs'} title={'Open an issue'}>
<IconButton aria-label={'Bugs'}>
{/* eslint-disable-next-line react/jsx-max-depth */}
<BugReport />
</IconButton>
</Tooltip>
</a>
);
const renderPrimaryComponent = () => {
return (
<Grid container={true} item={true} xs={12}>
<Grid item={true} xs={true}>
<WrapperLink to={`/-/web/detail/${packageName}`}>
{/* eslint-disable-next-line react/jsx-max-depth */}
<PackageTitle>{packageName}</PackageTitle>
</WrapperLink>
</Grid>
<GridRightAligned item={true} xs={true}>
{renderHomePageLink()}
{renderBugsLink()}
</GridRightAligned>
</Grid>
);
};
const renderSecondaryComponent = () => {
const tags = keywords.sort().map((keyword, index) => <Tag key={index}>{keyword}</Tag>);
return (
<>
<Description component={'span'}>{description}</Description>
{tags.length > 0 && <TagContainer>{tags}</TagContainer>}
</>
);
};
return (
<WrapperLink className={'package'} to={`/-/web/version/${label}`}>
<Header>
{renderMainInfo()}
<Overview>
{renderLicenseInfo()}
{renderPublishedInfo()}
</Overview>
</Header>
<Content>
<Field>{renderAuthorInfo()}</Field>
{renderDescription()}
</Content>
{keywords.length > 0 && (
<Footer>
{keywords.sort().map((keyword, index) => (
<Tag key={index}>{keyword}</Tag>
))}
</Footer>
)}
</WrapperLink>
<PackageList className={'package'}>
<ListItem alignItems={'flex-start'}>
<PackageListItemText className={'package-link'} component={'div'} primary={renderPrimaryComponent()} secondary={renderSecondaryComponent()} />
</ListItem>
<PackageListItem alignItems={'flex-start'}>
{renderAuthorInfo()}
{renderVersionInfo()}
{renderPublishedInfo()}
{renderFileSize()}
{renderLicenseInfo()}
</PackageListItem>
</PackageList>
);
};
export default Package;

View File

@@ -3,126 +3,68 @@
* @flow
*/
import styled, { css } from 'react-emotion';
import styled from 'react-emotion';
import { Link } from 'react-router-dom';
import { default as Photo } from '@material-ui/core/Avatar';
import { default as Ico } from '../Icon';
import mq from '../../utils/styles/media';
import { ellipsis } from '../../utils/styles/mixings';
import colors from '../../utils/styles/colors';
import Grid from '@material-ui/core/Grid/index';
import List from '@material-ui/core/List/index';
import ListItem from '@material-ui/core/ListItem/index';
import ListItemText from '@material-ui/core/ListItemText/index';
import MuiIconButton from '@material-ui/core/IconButton/index';
import Photo from '@material-ui/core/Avatar';
import Typography from '@material-ui/core/Typography/index';
import { breakpoints } from '../../utils/styles/media';
import Ico from '../Icon';
import Label from '../Label';
// HEADER
export const Header = styled.div`
&& {
display: flex;
flex-direction: column;
padding: 0 0 5px 0;
}
`;
export const Name = styled.span`
&& {
${ellipsis('50%')};
}
`;
export const MainInfo = styled.span`
&& {
font-size: 16px;
font-weight: 600;
line-height: 30px;
flex: 1;
color: #3a8bff;
padding: 0 10px 0 0;
overflow: hidden;
display: flex;
align-items: center;
:hover {
${Name} {
text-decoration: underline;
}
}
}
`;
import colors from '../../utils/styles/colors';
export const OverviewItem = styled.span`
&& {
display: flex;
align-items: center;
margin: 0 0 5px 0;
color: ${colors.greyLight};
}
`;
export const Overview = styled.span`
&& {
position: relative;
display: flex;
flex-direction: column;
}
`;
export const Version = styled.span`
&& {
margin: 0 0 0 16px;
color: ${colors.greyLight2};
font-size: 12px;
padding: 0 0 0 10px;
margin: 0 0 0 5px;
color: #9f9f9f;
position: relative;
${ellipsis('100%')};
:before {
content: '•';
position: absolute;
left: 0;
@media (max-width: ${breakpoints.medium}px) {
&:nth-child(3) {
display: none;
}
}
@media (max-width: ${breakpoints.small}px) {
&:nth-child(4) {
display: none;
}
}
}
`;
export const Icon = styled(Ico)`
&& {
margin: 1px 5px 0 0;
fill: ${colors.greyLight};
margin: 2px 10px 0px 0;
fill: ${colors.greyLight2};
}
`;
export const Published = styled.span`
&& {
display: none;
color: ${colors.greyLight};
${({ modifiers }) => modifiers};
}
`;
// Content
export const Field = styled.div`
&& {
padding: 0 0 5px 0;
}
`;
export const Content = styled.div`
&& {
${Field} {
:last-child {
padding: 0;
}
}
color: ${colors.greyLight2};
margin: 0px 5px 0px 0px;
}
`;
export const Text = styled(Label)`
&& {
color: #908ba1;
font-size: 12px;
font-weight: 500;
color: ${colors.greyLight2};
}
`;
export const Details = styled.span`
&& {
margin-left: 5px;
line-height: 14px;
line-height: 1.5;
display: flex;
flex-direction: column;
}
@@ -137,63 +79,88 @@ export const Author = styled.div`
export const Avatar = styled(Photo)`
&& {
width: 30px;
height: 30px;
background: #4b5e40;
font-size: 15px;
width: 20px;
height: 20px;
}
`;
export const Description = styled.div`
&& {
margin: 5px 0;
}
`;
// Footer
export const Footer = styled.div`
&& {
display: none;
padding: 5px 0 0 0;
}
`;
// Container
export const WrapperLink = styled(Link)`
&& {
font-size: 12px;
background-color: white;
margin: 0 0 15px 0;
transition: box-shadow 0.15s;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.15);
border-radius: 3px;
padding: 10px;
text-decoration: none;
display: block;
color: #2f273c;
${mq.medium(css`
${Header} {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
${OverviewItem} {
margin: 0 0 0 10px;
}
${Overview} {
flex-direction: row;
${OverviewItem} {
:first-child {
margin: 0;
}
}
}
${Footer} {
display: block;
}
${Published} {
display: inline-block;
}
`)};
}
`;
export const PackageTitle = styled.span`
&& {
font-weight: 600;
font-size: 20px;
display: block;
margin-bottom: 12px;
color: ${colors.eclipse};
cursor: pointer;
&:hover {
color: ${colors.black};
}
@media (max-width: ${breakpoints.small}px) {
font-size: 14px;
margin-bottom: 8px;
}
}
`;
export const GridRightAligned = styled(Grid)`
&& {
text-align: right;
}
`;
export const PackageList = styled(List)`
&& {
padding: 12px 0 12px 0;
&:hover {
background-color: ${colors.greyLight3};
}
}
`;
export const IconButton = styled(MuiIconButton)`
&& {
padding: 6px;
svg {
font-size: 16px;
}
}
`;
export const TagContainer = styled.span`
&& {
margin-top: 8px;
margin-bottom: 12px;
display: block;
@media (max-width: ${breakpoints.medium}px) {
display: none;
}
}
`;
export const PackageListItem = styled(ListItem)`
&& {
padding-top: 0;
}
`;
export const PackageListItemText = styled(ListItemText)`
&& {
padding-right: 0;
}
`;
export const Description = styled(Typography)`
color: ${colors.greyDark2};
font-size: 14px;
padding-right: 0;
`;

View File

@@ -11,6 +11,9 @@ export interface IProps {
description?: string;
keywords?: string[];
license?: string;
homepage: string;
bugs: IBugs;
dist: IDist;
}
export interface IAuthor {
@@ -18,3 +21,10 @@ export interface IAuthor {
avatar: string;
email: string;
}
export interface IBugs {
url: string;
}
export interface IDist {
unpackedSize: number;
}