0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-01-06 22:40:26 -05:00

fix: Fix 404 packages view, refactor readme and some components. Split them up for easy testing.

This commit is contained in:
Juan Picado @jotadeveloper 2017-07-22 16:52:31 +02:00
parent 0f31b364e8
commit d72ee76d74
No known key found for this signature in database
GPG key ID: 18AC54485952D158
15 changed files with 182 additions and 50 deletions

View file

@ -1,14 +1,11 @@
import React from 'react';
import {HashRouter as Router, Route, Switch} from 'react-router-dom';
import 'element-theme-default';
import {i18n} from 'element-react';
import locale from 'element-react/src/locale/lang/en';
i18n.use(locale);
import Header from './components/Header';
import Home from './modules/home';
import Detail from './modules/detail';
import Route from './router';
import './styles/global.scss';
import 'normalize.css';
@ -16,17 +13,7 @@ import 'normalize.css';
export default class App extends React.Component {
render() {
return (
<Router>
<div>
<Header/>
<div className="container">
<Switch>
<Route exact path="/(search/:keyword)?" component={ Home } />
<Route path="/detail/:package" component={ Detail } />
</Switch>
</div>
</div>
</Router>
<Route/>
);
}
}

View file

@ -0,0 +1,14 @@
@import '../../styles/variable';
.notFound {
width: 100%;
font-size: 18px;
line-height: 30px;
border: none;
border-bottom: 1px solid lightgrey;
outline: none;
&:focus {
border-bottom: 1px solid grey;
}
}

View file

@ -0,0 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import classes from './404.scss';
const NotFound = (props) => {
return (
<div className={classes.notFound}>
<h1>Error 404 - {props.pkg}</h1>
<hr/>
<p>
Oops, The package you are trying to access does not exist.
</p>
</div>
);
};
NotFound.propTypes = {
pkg: PropTypes.string.isRequired
};
export default NotFound;

View file

@ -18,9 +18,17 @@ export default class Package extends React.Component {
return (
<Link to={`detail/${pkg.name}`} className={classes.package}>
<h1>{pkg.name}<Tag type="gray">v{pkg.version}</Tag></h1>
<span role="author" className={classes.author}>By: {pkg.author.name}</span>
{this.renderAuthor(pkg)}
<p>{pkg.description}</p>
</Link>
);
}
renderAuthor(pkg) {
if (!pkg.author.name) {
return;
}
return <span role="author" className={classes.author}>By: {pkg.author.name}</span>;
}
}

View file

@ -25,7 +25,10 @@ .package {
top: 10px;
right: 0;
color: lightgrey;
font-size: 12px;
font-size: inherit;
word-wrap: break-word;
width: 100px;
text-align: right;
}
p {

View file

@ -0,0 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import isNil from 'lodash/isNil';
import Readme from '../Readme';
import classes from './packageDetail.scss';
const PackageDetail = (props) => {
const displayState = (readMe) => {
if (isNil(readMe)) {
return;
}
return <Readme readMe={readMe}/>;
};
return (
<div className={classes.pkgDetail}>
<h1 className={ classes.title }>{ props.package }</h1>
<hr/>
<div className={classes.readme}>
{displayState(props.readMe)}
</div>
</div>
);
};
PackageDetail.propTypes = {
readMe: PropTypes.string,
package: PropTypes.string.isRequired
};
export default PackageDetail;

View file

@ -0,0 +1,14 @@
@import '../../styles/variable';
.pkgDetail {
.title {
font-size: 28px;
color: $text-black;
}
.readme {
margin-bottom: 5em;
}
}

View file

@ -0,0 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import 'github-markdown-css';
const Readme = (props) => {
return <div className="markdown-body" dangerouslySetInnerHTML={{__html: props.readMe}}/>;
};
Readme.propTypes = {
readMe: PropTypes.string.isRequired
};
export default Readme;

View file

@ -0,0 +1,14 @@
@import '../../styles/variable';
.searchBox {
width: 100%;
font-size: 18px;
line-height: 30px;
border: none;
border-bottom: 1px solid lightgrey;
outline: none;
&:focus {
border-bottom: 1px solid grey;
}
}

View file

@ -8,15 +8,20 @@ const Search = (props) => {
return (
<input
type="text"
placeholder="Type to search..."
placeholder={props.placeHolder}
className={ classes.searchBox }
onChange={ props.handleSearchInput }
/>
);
};
Search.defaultProps = {
placeHolder: 'Type to search...'
};
Search.propTypes = {
handleSearchInput: PropTypes.func.isRequired
handleSearchInput: PropTypes.func.isRequired,
placeHolder: PropTypes.string,
};
export default Search;

View file

@ -1,6 +1,2 @@
@import '../../styles/variable';
.title {
font-size: 28px;
color: $text-black;
}

View file

@ -1,10 +1,13 @@
import React from 'react';
import API from '../../../utils/api';
import {Loading} from 'element-react';
import PropTypes from 'prop-types';
import {Loading} from 'element-react';
import isEmpty from 'lodash/isEmpty';
import classes from './detail.scss';
import 'github-markdown-css';
import PackageDetail from '../../components/PackageDetail';
import NotFound from '../../components/NotFound';
import API from '../../../utils/api';
const loadingMessage = 'Loading...';
export default class Detail extends React.Component {
static propTypes = {
@ -12,41 +15,30 @@ export default class Detail extends React.Component {
}
state = {
readMe: ''
readMe: '',
notFound: false,
}
async componentDidMount() {
try {
let resp = await API.get(`package/readme/${this.props.match.params.package}`);
const resp = await API.get(`package/readme/${this.props.match.params.package}`);
this.setState({
readMe: resp.data
});
} catch (err) {
this.setState({
readMe: 'Failed to load readme...'
notFound: true
});
}
}
renderReadMe() {
if (this.state.readMe) {
return (
<div className="markdown-body" dangerouslySetInnerHTML={{__html: this.state.readMe}}/>
);
} else {
return (
<Loading text="Loading..." />
);
}
}
render() {
return (
<div>
<h1 className={ classes.title }>{ this.props.match.params.package }</h1>
<hr/>
{this.renderReadMe()}
</div>
);
if (this.state.notFound) {
return <NotFound
pkg={this.props.match.params.package}/>;
} else if (isEmpty(this.state.readMe)) {
return <Loading text={loadingMessage} />;
}
return <PackageDetail readMe={this.state.readMe} package={this.props.match.params.package}/>;
}
}

View file

@ -31,7 +31,8 @@ export default class Home extends React.Component {
this.loadPackages();
}
componentDidUpdate(prevProps, prevState) {
componentDidUpdate(prevProps, prevState) { // eslint-disable-line no-unused-vars
if (prevState.query !== this.state.query) {
if (this.req && this.req.abort) this.req.abort();
this.setState({

24
src/webui/src/router.js Normal file
View file

@ -0,0 +1,24 @@
import React from 'react';
import {HashRouter as Router, Route, Switch} from 'react-router-dom';
import Header from './components/Header';
import Home from './modules/home';
import Detail from './modules/detail';
const RouterApp = () => {
return (
<Router>
<div>
<Header/>
<div className="container">
<Switch>
<Route exact path="/(search/:keyword)?" component={ Home } />
<Route path="/detail/:package" component={Detail} />
</Switch>
</div>
</div>
</Router>
);
};
export default RouterApp;

View file

@ -2,6 +2,7 @@
body {
font-family: $font;
font-size: 12px;
}
:global {