forked from sombochea/verdaccio-ui
Feat: added "Fund this package" button (#375)
This commit is contained in:
parent
3a9f66c023
commit
bf093cc27b
12
.vscode/settings.json
vendored
12
.vscode/settings.json
vendored
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"eslint.packageManager": "yarn",
|
"eslint.packageManager": "yarn",
|
||||||
"eslint.validate": [
|
// "eslint.validate": [
|
||||||
"javascript",
|
// "javascript",
|
||||||
"javascriptreact",
|
// "javascriptreact",
|
||||||
"typescript",
|
// "typescript",
|
||||||
"typescriptreact"
|
// "typescriptreact"
|
||||||
],
|
// ],
|
||||||
"typescript.tsdk": "node_modules/typescript/lib"
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
}
|
}
|
@ -1,78 +1,52 @@
|
|||||||
import React, { ReactElement } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { DetailContext } from '../../pages/Version';
|
||||||
|
import Paper from '../../muiComponents/Paper';
|
||||||
import ActionBar from '../ActionBar';
|
import ActionBar from '../ActionBar';
|
||||||
|
import Repository from '../Repository';
|
||||||
|
import Engines from '../Engines';
|
||||||
|
import Dist from '../Dist';
|
||||||
|
import Install from '../Install';
|
||||||
import Author from '../Author';
|
import Author from '../Author';
|
||||||
import Developers, { DeveloperType } from '../Developers';
|
import Developers, { DeveloperType } from '../Developers';
|
||||||
import Dist from '../Dist/Dist';
|
import { Theme } from '../../design-tokens/theme';
|
||||||
import Engine from '../Engines/Engines';
|
|
||||||
import Install from '../Install';
|
|
||||||
import Repository from '../Repository/Repository';
|
|
||||||
import { DetailContext } from '../../pages/Version';
|
|
||||||
import List from '../../muiComponents/List';
|
|
||||||
import Card from '../../muiComponents/Card';
|
|
||||||
import CardContent from '../../muiComponents/CardContent';
|
|
||||||
|
|
||||||
import { TitleListItem, TitleListItemText, PackageDescription, PackageVersion } from './styles';
|
import DetailSidebarTitle from './DetailSidebarTitle';
|
||||||
|
import DetailSidebarFundButton from './DetailSidebarFundButton';
|
||||||
|
|
||||||
const renderLatestDescription = (description, version, isLatest = true): JSX.Element => {
|
const StyledPaper = styled(Paper)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
return (
|
padding: theme.spacing(3, 2),
|
||||||
<>
|
}));
|
||||||
<PackageDescription>{description}</PackageDescription>
|
|
||||||
{version ? (
|
|
||||||
<PackageVersion>
|
|
||||||
<small>{`${isLatest ? 'Latest v' : 'v'}${version}`}</small>
|
|
||||||
</PackageVersion>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderCopyCLI = (): JSX.Element => <Install />;
|
const DetailSidebar: React.FC = () => {
|
||||||
const renderRepository = (): JSX.Element => <Repository />;
|
const detailContext = useContext(DetailContext);
|
||||||
const renderAuthor = (): JSX.Element => <Author />;
|
|
||||||
const renderEngine = (): JSX.Element => <Engine />;
|
const { packageMeta, packageName, packageVersion } = detailContext;
|
||||||
const renderDist = (): JSX.Element => <Dist />;
|
|
||||||
const renderActionBar = (): JSX.Element => <ActionBar />;
|
if (!packageMeta || !packageName) {
|
||||||
const renderTitle = (packageName, packageVersion, packageMeta): JSX.Element => {
|
return null;
|
||||||
const version = packageVersion ? packageVersion : packageMeta.latest.version;
|
}
|
||||||
const isLatest = typeof packageVersion === 'undefined';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List className="detail-info">
|
<StyledPaper className={'sidebar-info'}>
|
||||||
<TitleListItem alignItems="flex-start" button={true}>
|
<DetailSidebarTitle
|
||||||
<TitleListItemText
|
description={packageMeta.latest?.description}
|
||||||
primary={<b>{packageName}</b>}
|
isLatest={typeof packageVersion === 'undefined'}
|
||||||
secondary={renderLatestDescription(packageMeta.latest.description, version, isLatest)}
|
packageName={packageName}
|
||||||
|
version={packageVersion || packageMeta.latest.version}
|
||||||
/>
|
/>
|
||||||
</TitleListItem>
|
<ActionBar />
|
||||||
</List>
|
<Install />
|
||||||
);
|
{packageMeta?.latest?.funding && <DetailSidebarFundButton to={packageMeta.latest.funding.url} />}
|
||||||
};
|
<Repository />
|
||||||
|
<Engines />
|
||||||
function renderSideBar(packageName, packageVersion, packageMeta): ReactElement<HTMLElement> {
|
<Dist />
|
||||||
return (
|
<Author />
|
||||||
<div className={'sidebar-info'}>
|
|
||||||
<Card>
|
|
||||||
<CardContent>
|
|
||||||
{renderTitle(packageName, packageVersion, packageMeta)}
|
|
||||||
{renderActionBar()}
|
|
||||||
{renderCopyCLI()}
|
|
||||||
{renderRepository()}
|
|
||||||
{renderEngine()}
|
|
||||||
{renderDist()}
|
|
||||||
{renderAuthor()}
|
|
||||||
<Developers type={DeveloperType.MAINTAINERS} />
|
<Developers type={DeveloperType.MAINTAINERS} />
|
||||||
<Developers type={DeveloperType.CONTRIBUTORS} />
|
<Developers type={DeveloperType.CONTRIBUTORS} />
|
||||||
</CardContent>
|
</StyledPaper>
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
const DetailSidebar = (): JSX.Element => {
|
|
||||||
const { packageName, packageMeta, packageVersion } = React.useContext(DetailContext);
|
|
||||||
|
|
||||||
return renderSideBar(packageName, packageVersion, packageMeta);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DetailSidebar;
|
export default DetailSidebar;
|
||||||
|
46
src/components/DetailSidebar/DetailSidebarFundButton.tsx
Normal file
46
src/components/DetailSidebar/DetailSidebarFundButton.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import React, { MouseEvent } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import Favorite from '@material-ui/icons/Favorite';
|
||||||
|
|
||||||
|
import Button from '../../muiComponents/Button';
|
||||||
|
import Link from '../Link';
|
||||||
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
|
const StyledLink = styled(Link)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
|
marginTop: theme && theme.spacing(1),
|
||||||
|
marginBottom: theme && theme.spacing(1),
|
||||||
|
textDecoration: 'none',
|
||||||
|
display: 'block',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledFavoriteIcon = styled(Favorite)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
|
color: theme && theme.palette.orange,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledFundStrong = styled('strong')({
|
||||||
|
marginRight: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
to: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable react/jsx-no-bind */
|
||||||
|
const DetailSidebarFundButton: React.FC<Props> = ({ to }) => {
|
||||||
|
const preventDefault = (event: MouseEvent<HTMLButtonElement>) => event.preventDefault();
|
||||||
|
return (
|
||||||
|
<StyledLink external={true} to={to}>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
fullWidth={true}
|
||||||
|
onClick={preventDefault}
|
||||||
|
startIcon={<StyledFavoriteIcon />}
|
||||||
|
variant="outlined">
|
||||||
|
<StyledFundStrong>{'Fund'}</StyledFundStrong>
|
||||||
|
{'this package'}
|
||||||
|
</Button>
|
||||||
|
</StyledLink>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DetailSidebarFundButton;
|
33
src/components/DetailSidebar/DetailSidebarTitle.tsx
Normal file
33
src/components/DetailSidebar/DetailSidebarTitle.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import Box from '../../muiComponents/Box';
|
||||||
|
import Heading from '../../muiComponents/Heading';
|
||||||
|
import { Theme } from '../../design-tokens/theme';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
packageName: string;
|
||||||
|
description?: string;
|
||||||
|
version: string;
|
||||||
|
isLatest: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyledHeading = styled(Heading)({
|
||||||
|
fontSize: '1rem',
|
||||||
|
fontWeight: 700,
|
||||||
|
textTransform: 'capitalize',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
||||||
|
color: theme && theme.palette.text.secondary,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const DetailSidebarTitle: React.FC<Props> = ({ description, packageName, version, isLatest }) => (
|
||||||
|
<Box className={'detail-info'} display="flex" flexDirection="column" marginBottom="8px">
|
||||||
|
<StyledHeading>{packageName}</StyledHeading>
|
||||||
|
{description && <div>{description}</div>}
|
||||||
|
<StyledBoxVersion>{`${isLatest ? 'Latest v' : 'v'}${version}`}</StyledBoxVersion>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default DetailSidebarTitle;
|
@ -1,24 +0,0 @@
|
|||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import ListItem from '../../muiComponents/ListItem';
|
|
||||||
import ListItemText from '../../muiComponents/ListItemText';
|
|
||||||
|
|
||||||
export const TitleListItem = styled(ListItem)({
|
|
||||||
paddingLeft: 0,
|
|
||||||
paddingRight: 0,
|
|
||||||
paddingBottom: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const TitleListItemText = styled(ListItemText)({
|
|
||||||
paddingLeft: 0,
|
|
||||||
paddingRight: 0,
|
|
||||||
paddingTop: '8px',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const PackageDescription = styled('span')({
|
|
||||||
display: 'block',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const PackageVersion = styled('span')({
|
|
||||||
display: 'block',
|
|
||||||
});
|
|
@ -6,6 +6,7 @@ const colors = {
|
|||||||
black: '#000',
|
black: '#000',
|
||||||
white: '#fff',
|
white: '#fff',
|
||||||
red: '#d32f2f',
|
red: '#d32f2f',
|
||||||
|
orange: '#CD4000',
|
||||||
greySuperLight: '#f5f5f5',
|
greySuperLight: '#f5f5f5',
|
||||||
greyLight: '#d3d3d3',
|
greyLight: '#d3d3d3',
|
||||||
greyLight2: '#908ba1',
|
greyLight2: '#908ba1',
|
||||||
@ -93,6 +94,7 @@ declare module '@material-ui/core/styles/createPalette' {
|
|||||||
black: string;
|
black: string;
|
||||||
white: string;
|
white: string;
|
||||||
red: string;
|
red: string;
|
||||||
|
orange: string;
|
||||||
greySuperLight: string;
|
greySuperLight: string;
|
||||||
greyLight: string;
|
greyLight: string;
|
||||||
greyLight2: string;
|
greyLight2: string;
|
||||||
|
@ -37,7 +37,7 @@ new WebpackDevServer(compiler, {
|
|||||||
proxy: [
|
proxy: [
|
||||||
{
|
{
|
||||||
context: ['/-/verdaccio/**', '**/*.tgz'],
|
context: ['/-/verdaccio/**', '**/*.tgz'],
|
||||||
target: 'http://localhost:8080',
|
target: 'http://localhost:4873',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}).listen(4872, 'localhost', function(err) {
|
}).listen(4872, 'localhost', function(err) {
|
||||||
|
@ -24,6 +24,8 @@ export interface PackageMetaInterface {
|
|||||||
type?: string;
|
type?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
};
|
};
|
||||||
|
description?: string;
|
||||||
|
funding?: Funding;
|
||||||
maintainers?: Array<Developer>;
|
maintainers?: Array<Developer>;
|
||||||
contributors?: Array<Developer>;
|
contributors?: Array<Developer>;
|
||||||
};
|
};
|
||||||
@ -35,6 +37,11 @@ export interface Developer {
|
|||||||
avatar: string;
|
avatar: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Funding {
|
||||||
|
type?: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface LicenseInterface {
|
interface LicenseInterface {
|
||||||
type: string;
|
type: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
1
~/.config/verdaccio/storage_demo_gif/.verdaccio-db.json
Normal file
1
~/.config/verdaccio/storage_demo_gif/.verdaccio-db.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"list":[],"secret":"819a0e7ff50afc060d18d766705b95c3924a82f2aee580fd53fa2235faea87e7"}
|
Loading…
Reference in New Issue
Block a user