Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Presentation Layer for NPM Register (#92)
* Adding webpack and React Hello World * adding react files, webpack, and package.json, ignoring compiled files * Adding updated gitignore and package.json * Adding material UI assets and basic layout * Breaking out webpack config adding typefaces and loaders for fonts and css * Breaking header out into a separate component * Modifying webpack config to resolve jsx * Fixing sigterm exit on ctrl-c crashing build by adding --success flag * Adding standard linting to build * Adjusting dev server config * Outputting full url to console for easier loading. * Adding support for windows in the npm scripts * Adding cross-env to handle environment variables on windows and unix platforms * Adding start of API * Adding method to get all packages and their info in a request * Adding current version and author * Removing erroneous files for now * Adding Axios http library * Restructuring as ES6 class * Tables added to render api, updated api to include tarballs * Fixing bug where if a package did not have a name it would break rendering * Adding production minification of UI assets * Adding favicon and logos to the header * Styling loader and hiding table while request is loading * Renaming api to client * Adding S3 client api and drying up json response in base storage class * Readme Feature Adding readme to the API response * Adding modal component * Prevent pushing of empty details * null didn't work... * adding readme modal, still need markdown rendering. * Adding markdown rendering and tarball downloading * Adding a darker header to the readme modal * moving dev dependencies to fix heroku * adding babel to dependencies for heroku * Adding responsive styles for the table * Loading .env files in development * Updating packages for dependencies * Adding default readme content and restructuring variable declarations. * fixing indentations per standard style * Fixing indentations to match standard style * Refactoring to fix code climate issues. Render function was too big... * Invoking react template partials * Fixing API changes for material ui components * Fixing refresh after refactor * Updating webpack and adding hot module reloading. * Fixing mode typo * Upgrading to latest version of material ui
- Loading branch information
Showing
23 changed files
with
15,647 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,5 @@ fs | |
node_modules | ||
tmp | ||
npm-debug.log | ||
public/app.js | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import http from 'axios' | ||
import Button from '@material-ui/core/Button' | ||
import CircularProgress from '@material-ui/core/CircularProgress' | ||
import Grid from '@material-ui/core/Grid' | ||
import Icon from '@material-ui/core/Icon' | ||
import IconButton from '@material-ui/core/IconButton' | ||
import Paper from '@material-ui/core/Paper' | ||
import PropTypes from 'prop-types' | ||
import React from 'react' | ||
import Table from '@material-ui/core/Table' | ||
import TableBody from '@material-ui/core/TableBody' | ||
import TableCell from '@material-ui/core/TableCell' | ||
import TableHead from '@material-ui/core/TableHead' | ||
import TableRow from '@material-ui/core/TableRow' | ||
import { withStyles } from '@material-ui/core/styles' | ||
|
||
import Header from './components/Header' | ||
import Modal from './components/Modal' | ||
|
||
const styles = theme => ({ | ||
root: { | ||
marginTop: 30, | ||
'font-family': ['Roboto', 'Arial', 'sans-serif'] | ||
}, | ||
button: { | ||
margin: theme.spacing.unit | ||
}, | ||
anchor: { | ||
'text-decoration': 'none' | ||
}, | ||
paper: { | ||
padding: 16, | ||
margin: 16, | ||
textAlign: 'center', | ||
color: theme.palette.text.secondary, | ||
width: '100%', | ||
marginTop: theme.spacing.unit * 3, | ||
overflowX: 'auto' | ||
}, | ||
table: { | ||
overflow: 'auto', | ||
'word=break': 'keep-all' | ||
}, | ||
loader: { | ||
color: '#282828' | ||
} | ||
}) | ||
|
||
class App extends React.Component { | ||
constructor (props) { | ||
super(props) | ||
this.classes = props.classes | ||
this.state = { | ||
packages: [], | ||
loading: false, | ||
readmeOpen: false, | ||
readmeContent: null | ||
} | ||
this.toggleReadMeModal = this.toggleReadMeModal.bind(this) | ||
this.refreshPackages = this.refreshPackages.bind(this) | ||
} | ||
|
||
getPackages () { | ||
this.setState({ | ||
loading: true | ||
}) | ||
return http.get('/-/api/v1/packages') | ||
} | ||
|
||
toggleReadMeModal (readmeContent) { | ||
return () => { | ||
this.setState({ | ||
readmeOpen: !this.state.readmeOpen, | ||
readmeContent | ||
}) | ||
} | ||
} | ||
|
||
refreshPackages () { | ||
this.getPackages().then((response) => { | ||
if (response && response.data) { | ||
this.setState({ | ||
packages: response.data, | ||
loading: false | ||
}) | ||
} | ||
}) | ||
} | ||
|
||
componentDidMount () { | ||
this.refreshPackages() | ||
} | ||
|
||
tableHeader () { | ||
return ( | ||
<TableHead> | ||
<TableRow> | ||
<TableCell>Package Name</TableCell> | ||
<TableCell>Author(s)</TableCell> | ||
<TableCell>Description</TableCell> | ||
<TableCell>Latest Version</TableCell> | ||
<TableCell>Readme</TableCell> | ||
<TableCell>Tarball</TableCell> | ||
</TableRow> | ||
</TableHead> | ||
) | ||
}; | ||
|
||
tableBody () { | ||
return ( | ||
<TableBody> | ||
{this.state.packages.map((item, idx) => ( | ||
<TableRow key={idx} hover> | ||
<TableCell>{item.name}</TableCell> | ||
<TableCell>{item.author.name}</TableCell> | ||
<TableCell>{item.description}</TableCell> | ||
<TableCell>{item.currentVersion}</TableCell> | ||
<TableCell> | ||
<IconButton color='default' aria-label='Open read me' onClick={this.toggleReadMeModal(item.readme)}> | ||
<Icon>class</Icon> | ||
</IconButton> | ||
</TableCell> | ||
<TableCell> | ||
<a href={item.tarball.tarball} className={this.classes.anchor}> | ||
<IconButton color='default' aria-label='Download Tarball'><Icon>get_app</Icon></IconButton> | ||
</a> | ||
</TableCell> | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
) | ||
} | ||
|
||
refreshButton () { | ||
return ( | ||
<Grid item xs={12} sm={12}> | ||
<Button variant='raised' className={this.classes.button} onClick={this.refreshPackages}> | ||
Refresh Packages | ||
</Button> | ||
</Grid> | ||
) | ||
} | ||
|
||
render () { | ||
return ( | ||
<div className={this.classes.root}> | ||
<Header /> | ||
<Grid container spacing={16}> | ||
<Paper className={this.classes.paper}> | ||
<Grid item xs={12} sm={12}> | ||
{this.state.loading && <CircularProgress size={120} className={this.classes.loader} />} | ||
{!this.state.loading && | ||
<Table className={this.classes.table}> | ||
{this.tableHeader()} | ||
{this.tableBody()} | ||
</Table> | ||
} | ||
</Grid> | ||
{this.refreshButton()} | ||
</Paper> | ||
</Grid> | ||
<Modal show={this.state.readmeOpen} onClose={this.toggleReadMeModal()} readme={this.state.readmeContent} /> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
App.propTypes = { | ||
classes: PropTypes.object.isRequired | ||
} | ||
|
||
export default withStyles(styles)(App) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
import { withStyles } from '@material-ui/core/styles' | ||
import AppBar from '@material-ui/core/AppBar' | ||
import Toolbar from '@material-ui/core/Toolbar' | ||
import Typography from '@material-ui/core/Typography' | ||
|
||
const styles = { | ||
root: { | ||
marginBottom: 30, | ||
width: '100%' | ||
}, | ||
appbar: { | ||
background: '#cc0000', | ||
color: '#FFF' | ||
}, | ||
type: { | ||
marginLeft: 10 | ||
} | ||
} | ||
|
||
function SimpleAppBar (props) { | ||
const classes = props.classes | ||
return ( | ||
<div className={classes.root}> | ||
<AppBar position='static' color='inherit' className={classes.appbar}> | ||
<Toolbar> | ||
<img src='/images/logo-small.png' alt='NPM Register' width='30px' height='30px' /> | ||
<Typography type='headline' color='inherit' className={classes.type}> | ||
NPM Register | ||
</Typography> | ||
</Toolbar> | ||
</AppBar> | ||
</div> | ||
) | ||
} | ||
|
||
SimpleAppBar.propTypes = { | ||
classes: PropTypes.object.isRequired | ||
} | ||
|
||
export default withStyles(styles)(SimpleAppBar) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
import { withStyles } from '@material-ui/core/styles' | ||
import Dialog from '@material-ui/core/Dialog' | ||
import Slide from '@material-ui/core/Slide' | ||
import Button from '@material-ui/core/Button' | ||
import AppBar from '@material-ui/core/AppBar' | ||
import Toolbar from '@material-ui/core/Toolbar' | ||
import IconButton from '@material-ui/core/IconButton' | ||
import Typography from '@material-ui/core/Typography' | ||
import CloseIcon from '@material-ui/icons/Close' | ||
import md from 'marked' | ||
|
||
const styles = { | ||
appBar: { | ||
position: 'relative', | ||
background: '#282828', | ||
color: '#FFF' | ||
}, | ||
flex: { | ||
flex: 1 | ||
}, | ||
readme: { | ||
overflow: 'auto', | ||
padding: 16 | ||
} | ||
} | ||
|
||
class Modal extends React.Component { | ||
constructor (props) { | ||
super(props) | ||
this.classes = props.classes | ||
this.readme = props.readme | ||
this.show = props.show | ||
this.onClose = props.onClose | ||
} | ||
|
||
Transition (props) { | ||
return <Slide direction='up' {...props} /> | ||
} | ||
|
||
render () { | ||
let readme = md.parse(this.props.readme || '', {sanitize: true}) | ||
return ( | ||
<Dialog | ||
fullScreen | ||
open={this.props.show} | ||
onClose={this.props.onClose} | ||
TransitionComponent={this.Transition} | ||
> | ||
<AppBar color='inherit' className={this.classes.appBar}> | ||
<Toolbar> | ||
<IconButton color='inherit' onClick={this.props.onClose} aria-label='Close'> | ||
<CloseIcon /> | ||
</IconButton> | ||
<Typography type='title' color='inherit' className={this.classes.flex}> | ||
README | ||
</Typography> | ||
<Button color='inherit' onClick={this.props.onClose}> | ||
Close | ||
</Button> | ||
</Toolbar> | ||
</AppBar> | ||
<Typography type='body1' component='div' dangerouslySetInnerHTML={{__html: readme}} className={this.classes.readme} /> | ||
</Dialog> | ||
) | ||
} | ||
} | ||
|
||
Modal.propTypes = { | ||
classes: PropTypes.object.isRequired, | ||
onClose: PropTypes.func.isRequired, | ||
readme: PropTypes.string, | ||
show: PropTypes.bool | ||
} | ||
|
||
export default withStyles(styles)(Modal) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React from 'react' | ||
import { render } from 'react-dom' | ||
import App from './App' | ||
|
||
const renderApp = () => { | ||
render( | ||
<App />, | ||
document.getElementById('app') | ||
) | ||
} | ||
|
||
renderApp() | ||
|
||
if (module.hot) { | ||
module.hot.accept('./App', renderApp) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
const path = require('path') | ||
const merge = require('webpack-merge') | ||
const devConfig = require('./webpack.dev') | ||
const prodConfig = require('./webpack.prod') | ||
const PATHS = { | ||
app: path.join(__dirname, '../client'), | ||
public: path.join(__dirname, '../public') | ||
} | ||
|
||
const baseConfig = { | ||
entry: { | ||
app: PATHS.app + '/index.jsx' | ||
}, | ||
output: { | ||
path: PATHS.public, | ||
filename: 'app.js' | ||
}, | ||
resolve: { | ||
extensions: ['.webpack.js', '.web.js', '.js', '.json', '.jsx'] | ||
}, | ||
module: { | ||
rules: [{ | ||
test: /\.jsx$/, | ||
exclude: /(node_modules|lib)/, | ||
use: { | ||
loader: 'babel-loader', | ||
options: { | ||
presets: ['react'] | ||
} | ||
} | ||
}, { | ||
test: /\.(png|jpg|gif)$/, | ||
use: [{ | ||
loader: 'url-loader', | ||
options: { | ||
limit: 8192 | ||
} | ||
}] | ||
}, { | ||
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, | ||
loader: 'url-loader', | ||
options: { | ||
limit: 50000, | ||
mimetype: 'application/font-woff', | ||
name: './fonts/[name].[ext]' | ||
} | ||
}, { | ||
test: /\.css$/, | ||
use: ['style-loader', 'css-loader'] | ||
}] | ||
} | ||
} | ||
|
||
module.exports = () => { | ||
if (process.env.NODE_ENV === 'production') { | ||
console.log('Loading production config...') | ||
return merge(baseConfig, prodConfig) | ||
} | ||
|
||
console.log('Loading development config...') | ||
return merge(baseConfig, devConfig) | ||
} |
Oops, something went wrong.