mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-30 22:34:10 -05:00
chore: add sidebar experiment
This commit is contained in:
parent
8a168760f5
commit
b6a8dd37d0
14 changed files with 267 additions and 43 deletions
|
@ -160,7 +160,8 @@
|
|||
"webpack-cli": "3.1.1",
|
||||
"webpack-dev-server": "3.1.14",
|
||||
"webpack-merge": "4.1.4",
|
||||
"whatwg-fetch": "3.0.0"
|
||||
"whatwg-fetch": "3.0.0",
|
||||
"xss": "1.0.3"
|
||||
},
|
||||
"keywords": [
|
||||
"private",
|
||||
|
|
49
src/webui/components/DetailContainer/index.js
Normal file
49
src/webui/components/DetailContainer/index.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
import React, {Component} from 'react';
|
||||
|
||||
import { DetailContextConsumer } from '../../pages/version/index';
|
||||
import Readme from '../Readme';
|
||||
import {preventXSS} from '../../utils/sec-utils';
|
||||
import Tabs from '@material-ui/core/Tabs/index';
|
||||
import Tab from '@material-ui/core/Tab/index';
|
||||
import { Content } from './styles';
|
||||
|
||||
class DetailContainer extends Component<any, any> {
|
||||
state = {
|
||||
tabPosition: 0,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DetailContextConsumer>
|
||||
{(context) => {
|
||||
return this.renderTabs(context);
|
||||
}}
|
||||
</DetailContextConsumer>
|
||||
);
|
||||
};
|
||||
|
||||
renderTabs = ({readMe}) => {
|
||||
const { tabPosition } = this.state;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Tabs indicatorColor={'primary'} onChange={this.handleChange} textColor={'primary'} value={tabPosition} variant={'fullWidth'}>
|
||||
<Tab label={'Readme'} />
|
||||
<Tab label={'Dependencies'} />
|
||||
<Tab label={'Versions'} />
|
||||
<Tab label={'Uplinks'} />
|
||||
</Tabs>
|
||||
{tabPosition === 0 && this.renderReadme(readMe)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
renderReadme = (readMe) => {
|
||||
const encodedReadme = preventXSS(readMe);
|
||||
|
||||
return (<Content><Readme description={encodedReadme}></Readme></Content>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default DetailContainer;
|
12
src/webui/components/DetailContainer/styles.js
Normal file
12
src/webui/components/DetailContainer/styles.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import styled from 'react-emotion';
|
||||
|
||||
export const Content = styled.div`
|
||||
&& {
|
||||
padding: 20px;
|
||||
}
|
||||
`;
|
12
src/webui/components/DetailContainer/types.js
Normal file
12
src/webui/components/DetailContainer/types.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type { Node } from 'react';
|
||||
|
||||
export interface IProps {
|
||||
children: Node;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
75
src/webui/components/DetailSidebar/index.js
Normal file
75
src/webui/components/DetailSidebar/index.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* eslint react/jsx-max-depth: 0 */
|
||||
|
||||
import React, {Component} from 'react';
|
||||
|
||||
import { DetailContextConsumer } from '../../pages/version/index';
|
||||
// import Paper from '@material-ui/core/Paper/index';
|
||||
import Typography from '@material-ui/core/Typography/index';
|
||||
import Grid from '@material-ui/core/Grid/index';
|
||||
// import CardHeader from '@material-ui/core/CardHeader';
|
||||
import Card from '@material-ui/core/Card/index';
|
||||
import CardContent from '@material-ui/core/CardContent/index';
|
||||
import { Content } from './styles';
|
||||
import CopyToClipBoard from '../CopyToClipBoard';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
// import Paper from '@material-ui/core/Paper/index';
|
||||
|
||||
class DetailSidebar extends Component<any, any> {
|
||||
render() {
|
||||
return (
|
||||
<DetailContextConsumer>
|
||||
{(context) => {
|
||||
return this.renderSideBar(context);
|
||||
}}
|
||||
</DetailContextConsumer>
|
||||
);
|
||||
};
|
||||
|
||||
renderSideBar = ({packageMeta, packageName}) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{this.renderDescription(packageMeta, packageName)}
|
||||
<Content>
|
||||
<Grid container={true} spacing={24}>
|
||||
<Grid item={true} xs={12}>
|
||||
<Typography color={"textPrimary"} gutterBottom={true} variant={'title'}>
|
||||
{packageName}
|
||||
</Typography>
|
||||
<Typography color={"textSecondary"} gutterBottom={true} variant={'subtitle2'}>
|
||||
{packageMeta.latest.description}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item={true} xs={12}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<CopyToClipBoard text={`npm install ${packageName}`} />
|
||||
<CopyToClipBoard text={`pnpm install ${packageName}`} />
|
||||
<CopyToClipBoard text={`yarn add ${packageName}`} />
|
||||
<CardActions>
|
||||
<Button color={"primary"} variant={"contained"}>
|
||||
{'Download Tarball'}
|
||||
</Button>
|
||||
</CardActions>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
renderDescription = (packageMeta) => {
|
||||
console.log('packageMeta', packageMeta);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default DetailSidebar;
|
14
src/webui/components/DetailSidebar/styles.js
Normal file
14
src/webui/components/DetailSidebar/styles.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import styled from 'react-emotion';
|
||||
import colors from '../../utils/styles/colors';
|
||||
|
||||
export const Content = styled.div`
|
||||
&& {
|
||||
padding: 10px;
|
||||
background-color: ${colors.white};
|
||||
}
|
||||
`;
|
12
src/webui/components/DetailSidebar/types.js
Normal file
12
src/webui/components/DetailSidebar/types.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type { Node } from 'react';
|
||||
|
||||
export interface IProps {
|
||||
children: Node;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
|
@ -7,7 +7,7 @@ import styled, { css } from 'react-emotion';
|
|||
|
||||
export const Content = styled.div`
|
||||
&& {
|
||||
background-color: #fff;
|
||||
background-color: #ffffff;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ const Package = ({ name: label, version, time, author: { name, avatar }, descrip
|
|||
);
|
||||
|
||||
return (
|
||||
<Wrapper className={'package'} to={`detail/${label}`}>
|
||||
<Wrapper className={'package'} to={`version/${label}`}>
|
||||
<Header>
|
||||
{renderMainInfo()}
|
||||
<Overview>
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import API from '../../utils/api';
|
||||
import Grid from '@material-ui/core/Grid/index';
|
||||
import Loading from '../../components/Loading';
|
||||
import DetailContainer from '../../components/DetailContainer';
|
||||
import DetailSidebar from '../../components/DetailSidebar';
|
||||
|
||||
export const DetailContext = React.createContext();
|
||||
|
||||
export const DetailContextProvider = DetailContext.Provider;
|
||||
export const DetailContextConsumer = DetailContext.Consumer;
|
||||
|
||||
class VersionPage extends Component<any, any> {
|
||||
|
||||
state = {
|
||||
readMe: '',
|
||||
packageMeta: null,
|
||||
|
@ -18,6 +30,8 @@ class VersionPage extends Component<any, any> {
|
|||
async loadPackageInfo() {
|
||||
const { match } = this.props;
|
||||
const packageName = match.params.package;
|
||||
// FIXME: use utility
|
||||
document.title = `Verdaccio - ${packageName}`;
|
||||
|
||||
this.setState({
|
||||
readMe: '',
|
||||
|
@ -41,11 +55,34 @@ class VersionPage extends Component<any, any> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {isLoading} = this.state;
|
||||
const { isLoading, packageMeta, readMe } = this.state;
|
||||
const { match } = this.props;
|
||||
const packageName = match.params.package;
|
||||
|
||||
return (
|
||||
<div>{isLoading && <Loading />}</div>
|
||||
);
|
||||
if (isLoading === false) {
|
||||
return (
|
||||
<DetailContextProvider value={{ packageMeta, readMe, packageName }}>
|
||||
<Grid className={'container content'} container={true} spacing={0}>
|
||||
<Grid item={true} xs={8}>
|
||||
{this.renderDetail()}
|
||||
</Grid>
|
||||
<Grid item={true} xs={4}>
|
||||
{this.renderSidebar()}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DetailContextProvider>
|
||||
);
|
||||
} else {
|
||||
return <Loading />;
|
||||
}
|
||||
}
|
||||
|
||||
renderDetail() {
|
||||
return <DetailContainer />;
|
||||
}
|
||||
|
||||
renderSidebar() {
|
||||
return <DetailSidebar />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
:global {
|
||||
.container {
|
||||
padding: 15px;
|
||||
padding: 0px 15px;
|
||||
flex: 1;
|
||||
|
||||
@include container-size;
|
||||
|
|
12
src/webui/utils/sec-utils.js
Normal file
12
src/webui/utils/sec-utils.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
// $FlowFixMe
|
||||
import parseXSS from 'xss';
|
||||
|
||||
export function preventXSS(text: string) {
|
||||
const encodedText = parseXSS(text);
|
||||
|
||||
return encodedText;
|
||||
}
|
|
@ -1,34 +1,34 @@
|
|||
// Verdaccio
|
||||
// -------------------------
|
||||
|
||||
// Main colors
|
||||
// -------------------------
|
||||
const colors = {
|
||||
black: '#000',
|
||||
white: '#fff',
|
||||
red: '#d32f2f',
|
||||
grey: '#808080',
|
||||
|
||||
greyLight: '#d3d3d3',
|
||||
greyDark: '#a9a9a9',
|
||||
greyChateau: '#95989a',
|
||||
greyGainsboro: '#e3e3e3',
|
||||
greyAthens: '#d3dddd',
|
||||
|
||||
eclipse: '#3c3c3c',
|
||||
paleNavy: '#e4e8f1',
|
||||
saltpan: '#f7f8f6',
|
||||
snow: '#f9f9f9',
|
||||
|
||||
nobel01: '#999999',
|
||||
nobel02: '#9f9f9f',
|
||||
|
||||
// Main colors
|
||||
// -------------------------
|
||||
|
||||
primary: '#4b5e40',
|
||||
secondary: '#20232a',
|
||||
|
||||
};
|
||||
|
||||
export default colors;
|
||||
// Verdaccio
|
||||
// -------------------------
|
||||
|
||||
// Main colors
|
||||
// -------------------------
|
||||
const colors = {
|
||||
black: '#000',
|
||||
white: '#fff',
|
||||
red: '#d32f2f',
|
||||
grey: '#808080',
|
||||
greySuperLight: '#f5f5f5',
|
||||
greyLight: '#d3d3d3',
|
||||
greyDark: '#a9a9a9',
|
||||
greyChateau: '#95989a',
|
||||
greyGainsboro: '#e3e3e3',
|
||||
greyAthens: '#d3dddd',
|
||||
|
||||
eclipse: '#3c3c3c',
|
||||
paleNavy: '#e4e8f1',
|
||||
saltpan: '#f7f8f6',
|
||||
snow: '#f9f9f9',
|
||||
|
||||
nobel01: '#999999',
|
||||
nobel02: '#9f9f9f',
|
||||
|
||||
// Main colors
|
||||
// -------------------------
|
||||
|
||||
primary: '#4b5e40',
|
||||
secondary: '#20232a',
|
||||
|
||||
};
|
||||
|
||||
export default colors;
|
||||
|
|
BIN
yarn.lock
BIN
yarn.lock
Binary file not shown.
Loading…
Reference in a new issue