From b897de35ede7b027a895360a94c4a33bd1d6766d Mon Sep 17 00:00:00 2001 From: esikkala <esko.ikkala@aalto.fi> Date: Fri, 9 Nov 2018 09:26:52 -0800 Subject: [PATCH] Add tabs for subviews --- src/client/components/LeafletMap.js | 66 ++----------- src/client/components/Main.js | 2 +- src/client/components/Manuscripts.js | 47 ++++++--- src/client/components/ResultTable.js | 121 ++++++++++------------- src/client/components/ResultTableHead.js | 7 +- src/client/components/TopBar.js | 2 +- src/client/components/ViewTabs.js | 58 +++++++++++ src/client/containers/MapApp.js | 44 +-------- src/client/index.html | 6 +- webpack.client.common.js | 1 + webpack.client.dev.js | 5 +- 11 files changed, 172 insertions(+), 187 deletions(-) create mode 100644 src/client/components/ViewTabs.js diff --git a/src/client/components/LeafletMap.js b/src/client/components/LeafletMap.js index a3d36267..781ec553 100644 --- a/src/client/components/LeafletMap.js +++ b/src/client/components/LeafletMap.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import L from 'leaflet'; import { has, orderBy } from 'lodash'; -import LeafletSidebar from './LeafletSidebar'; +// import LeafletSidebar from './LeafletSidebar'; import 'leaflet-sidebar-v2/js/leaflet-sidebar.min.js'; import 'leaflet-sidebar-v2/css/leaflet-sidebar.min.css'; @@ -46,6 +46,7 @@ const style = { class LeafletMap extends React.Component { componentDidMount() { + console.log('mounted') //this.props.fetchManuscripts(); this.props.fetchPlaces('creationPlaces'); @@ -76,6 +77,7 @@ class LeafletMap extends React.Component { this.bouncingMarkerObj = null; this.popupMarkerObj = null; + if (this.props.mapMode === 'cluster') { this.updateMarkersAndCluster(this.props.results); } else { @@ -121,34 +123,7 @@ class LeafletMap extends React.Component { } - componentDidUpdate({ results, place, mapMode, geoJSONKey, bouncingMarkerKey, openPopupMarkerKey }) { - if (this.props.bouncingMarker === '' && this.bouncingMarkerObj !== null) { - this.leafletMap.removeLayer(this.bouncingMarkerObj); - } - - if (this.props.bouncingMarkerKey !== bouncingMarkerKey) { - if (this.props.mapMode === 'cluster') { - const m = this.markers[this.props.bouncingMarker]; - const latlng = m.getLatLng(); - // create a new marker so that the temporary popup can be left open - this.bouncingMarkerObj = L.marker(latlng); - this.bouncingMarkerObj.addTo(this.leafletMap).bounce(1); - } else { - this.markers[this.props.bouncingMarker].bounce(1); - } - } - - if (this.props.openPopupMarkerKey !== openPopupMarkerKey) { - if (this.props.mapMode === 'cluster') { - if (this.popupMarkerObj !== null) { - this.leafletMap.removeLayer(this.popupMarkerObj); - } - this.popupMarkerObj = this.markers[this.props.popupMarker]; - this.popupMarkerObj.addTo(this.leafletMap).openPopup(); - } else { - this.markers[this.props.popupMarker].openPopup(); - } - } + componentDidUpdate({ results, mapMode }) { // check if results data or mapMode have changed if (this.props.results !== results || this.props.mapMode !== mapMode) { @@ -158,27 +133,6 @@ class LeafletMap extends React.Component { this.updateMarkers(this.props.results); } } - - if (this.props.place !== place) { - this.markers[this.props.place.id.replace('http://ldf.fi/mmm/place/', '')] - .bindPopup(this.createPopUpContent(this.props.place), { - maxHeight: 300, - maxWidth: 400, - minWidth: 400, - //closeButton: false, - }) - .openPopup(); - } - - // check if geoJSON has updated - if (this.props.geoJSONKey !== geoJSONKey) { - this.props.geoJSON.map(obj => { - const layer = L.geoJSON(obj.geoJSON, { - onEachFeature: this.onEachFeature - }); - this.layerControl.addOverlay(layer, obj.layerID); - }); - } } updateMarkers(results) { @@ -301,7 +255,7 @@ class LeafletMap extends React.Component { render() { return ( - <div className="leaflet-container"> + <div className="leaflet-outer-container"> {/*<LeafletSidebar />*/} <div id="map" style={style} /> </div> @@ -314,15 +268,7 @@ LeafletMap.propTypes = { fetchPlace: PropTypes.func.isRequired, fetchManuscripts: PropTypes.func.isRequired, results: PropTypes.array.isRequired, - place: PropTypes.object.isRequired, - mapMode: PropTypes.string.isRequired, - geoJSON: PropTypes.array, - geoJSONKey: PropTypes.number.isRequired, - getGeoJSON: PropTypes.func.isRequired, - bouncingMarker: PropTypes.string.isRequired, - popupMarker: PropTypes.string.isRequired, - bouncingMarkerKey: PropTypes.number.isRequired, - openPopupMarkerKey: PropTypes.number.isRequired, + mapMode: PropTypes.string.isRequired }; export default LeafletMap; diff --git a/src/client/components/Main.js b/src/client/components/Main.js index 252d8f91..cb3e15f3 100644 --- a/src/client/components/Main.js +++ b/src/client/components/Main.js @@ -38,7 +38,7 @@ const styles = theme => ({ maxWidth: 340, }, media: { - height: 110, + height: 100, }, }); diff --git a/src/client/components/Manuscripts.js b/src/client/components/Manuscripts.js index 86ce7517..442d4921 100644 --- a/src/client/components/Manuscripts.js +++ b/src/client/components/Manuscripts.js @@ -1,20 +1,42 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { Route, Switch } from 'react-router-dom'; +import ViewTabs from './ViewTabs'; import ResultTable from './ResultTable'; +import LeafletMap from './LeafletMap'; let Manuscripts = props => { - return ( - <ResultTable - rows={props.search.manuscripts} - facet={props.facet} - fetchManuscripts={props.fetchManuscripts} - fetchingManuscripts={props.search.fetchingManuscripts} - fetchFacet={props.fetchFacet} - results={props.search.results} - fetchResults={props.fetchResults} - page={props.search.page} - /> + <React.Fragment> + <ViewTabs /> + <Switch> + <Route + path={props.match.url + '/table'} + render={() => + <ResultTable + rows={props.search.manuscripts} + facet={props.facet} + fetchManuscripts={props.fetchManuscripts} + fetchingManuscripts={props.search.fetchingManuscripts} + fetchFacet={props.fetchFacet} + results={props.search.results} + fetchResults={props.fetchResults} + page={props.search.page} + />} + /> + <Route + path={props.match.url + '/creation_places'} + render={() => + <LeafletMap + fetchPlaces={props.fetchPlaces} + fetchPlace={props.fetchPlace} + fetchManuscripts={props.fetchManuscripts} + results={props.search.places} + mapMode='cluster' + />} + /> + </Switch> + </React.Fragment> ); }; @@ -26,7 +48,8 @@ Manuscripts.propTypes = { fetchPlaces: PropTypes.func.isRequired, fetchPlace: PropTypes.func.isRequired, fetchFacet: PropTypes.func.isRequired, - fetchResults: PropTypes.func.isRequired + fetchResults: PropTypes.func.isRequired, + match: PropTypes.object.isRequired }; export default Manuscripts; diff --git a/src/client/components/ResultTable.js b/src/client/components/ResultTable.js index f230a8ba..19006337 100644 --- a/src/client/components/ResultTable.js +++ b/src/client/components/ResultTable.js @@ -12,19 +12,12 @@ import purple from '@material-ui/core/colors/purple'; import ResultTableHead from './ResultTableHead'; import { has, orderBy } from 'lodash'; -const styles = () => ({ - root: { - width: '100%', - height: '100%', - //marginTop: theme.spacing.unit * 3, - overflowX: 'auto', - - }, +const styles = (theme) => ({ table: { + marginTop: 72, minWidth: 700, - }, - tableWrapper: { - overflow: 'auto', + overflowX: 'auto', + backgroundColor: theme.palette.background.paper }, paginationRow: { borderBottom: '1px solid lightgrey' @@ -43,6 +36,7 @@ const styles = () => ({ paddingTop: 15 }, progressContainer: { + width: '100%', height: '100%', display: 'flex', alignItems: 'center', @@ -212,70 +206,61 @@ class ResultTable extends React.Component { render() { const { classes, rows } = this.props; - let table = ''; if (this.props.fetchingManuscripts ) { - table = ( - <div className={classes.progressContainer}> + return ( + <Paper className={classes.progressContainer}> <Typography className={classes.progressTitle} variant="h4" color='primary'>Fetching manuscript data</Typography> <CircularProgress style={{ color: purple[500] }} thickness={5} /> - </div> + </Paper> ); } else { - table = ( - <div className={classes.tableWrapper}> - <Table className={classes.table}> - <ResultTableHead - fetchFacet={this.props.fetchFacet} - fetchManuscripts={this.props.fetchManuscripts} - facet={this.props.facet} - results={this.props.results} - page={this.props.page} - /> - <TableBody> - {rows.map(row => { - return ( - <TableRow key={row.id}> - <TableCell component="th" scope="row" > - {this.idRenderer(row)} - </TableCell> - <TableCell className={classes.withFilter} > - {this.stringListRenderer(row.prefLabel)} - </TableCell> - <TableCell className={classes.withFilter}> - {this.objectListRenderer(row.author, true)} - </TableCell> - <TableCell className={classes.withFilter}> - {this.objectListRenderer(row.creationPlace, true)} - </TableCell> - <TableCell className={classes.withFilter}> - {this.objectListRenderer(row.timespan)} - </TableCell> - <TableCell className={classes.withFilter}> - {this.stringListRenderer(row.language)} - </TableCell> - {/*<TableCell className={classes.withFilter}> - {this.stringListRenderer(row.material)} - </TableCell>*/} - <TableCell className={classes.withFilter}> - {this.transactionRenderer(row.acquisition)} - </TableCell> - <TableCell className={classes.withFilter}> - {this.ownerRenderer(row.owner)} - </TableCell> - </TableRow> - ); - })} - </TableBody> - </Table> - </div> + return ( + <Table className={classes.table}> + <ResultTableHead + fetchFacet={this.props.fetchFacet} + fetchManuscripts={this.props.fetchManuscripts} + facet={this.props.facet} + results={this.props.results} + page={this.props.page} + /> + <TableBody> + {rows.map(row => { + return ( + <TableRow key={row.id}> + <TableCell component="th" scope="row" > + {this.idRenderer(row)} + </TableCell> + <TableCell className={classes.withFilter} > + {this.stringListRenderer(row.prefLabel)} + </TableCell> + <TableCell className={classes.withFilter}> + {this.objectListRenderer(row.author, true)} + </TableCell> + <TableCell className={classes.withFilter}> + {this.objectListRenderer(row.creationPlace, true)} + </TableCell> + <TableCell className={classes.withFilter}> + {this.objectListRenderer(row.timespan)} + </TableCell> + <TableCell className={classes.withFilter}> + {this.stringListRenderer(row.language)} + </TableCell> + {/*<TableCell className={classes.withFilter}> + {this.stringListRenderer(row.material)} + </TableCell>*/} + <TableCell className={classes.withFilter}> + {this.transactionRenderer(row.acquisition)} + </TableCell> + <TableCell className={classes.withFilter}> + {this.ownerRenderer(row.owner)} + </TableCell> + </TableRow> + ); + })} + </TableBody> + </Table> ); } - - return ( - <Paper className={classes.root}> - {table} - </Paper> - ); } } diff --git a/src/client/components/ResultTableHead.js b/src/client/components/ResultTableHead.js index c899d45b..fd45ae53 100644 --- a/src/client/components/ResultTableHead.js +++ b/src/client/components/ResultTableHead.js @@ -14,6 +14,10 @@ import ResultTablePaginationActions from './ResultTablePaginationActions'; const styles = () => ({ paginationRow: { borderBottom: '1px solid lightgrey' + }, + paginationRoot: { + display: 'flex', + justifyContent: 'flex-start' } }); @@ -75,7 +79,7 @@ class ResultTableHead extends React.Component { }; handleChangePage = (event, page) => { - console.log(page) + // console.log(page) this.props.fetchManuscripts(page); }; @@ -115,6 +119,7 @@ class ResultTableHead extends React.Component { onChangePage={this.handleChangePage} onChangeRowsPerPage={this.handleChangeRowsPerPage} ActionsComponent={ResultTablePaginationActions} + classes={{root: classes.paginationRoot}} /> </TableRow> <TableRow> diff --git a/src/client/components/TopBar.js b/src/client/components/TopBar.js index cbb774e6..36cb627b 100644 --- a/src/client/components/TopBar.js +++ b/src/client/components/TopBar.js @@ -172,7 +172,7 @@ class TopBar extends React.Component { const ManuscriptLink = props => <NavLink - to="/manuscripts" + to="/manuscripts/table" className={classes.appBarButton} activeClassName={classes.appBarButtonActive} {...props} diff --git a/src/client/components/ViewTabs.js b/src/client/components/ViewTabs.js new file mode 100644 index 00000000..e2eace35 --- /dev/null +++ b/src/client/components/ViewTabs.js @@ -0,0 +1,58 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Paper from '@material-ui/core/Paper'; +import { withStyles } from '@material-ui/core/styles'; +import Tabs from '@material-ui/core/Tabs'; +import Tab from '@material-ui/core/Tab'; +import CalendarViewDayIcon from '@material-ui/icons/CalendarViewDay'; +import AddLocationIcon from '@material-ui/icons/AddLocation'; +import RedoIcon from '@material-ui/icons/Redo'; +import PieChartIcon from '@material-ui/icons/PieChart'; +import { Link } from 'react-router-dom'; + + +const styles = { + root: { + width: 'calc(100% - 8px)', + position: 'absolute', + top: 64, + //backgroundColor: 'rgb(238, 238, 238)', + }, +}; + +class ViewTabs extends React.Component { + state = { + value: 0, + }; + + handleChange = (event, value) => { + this.setState({ value }); + }; + + render() { + const { classes } = this.props; + + return ( + <Paper square className={classes.root}> + <Tabs + value={this.state.value} + onChange={this.handleChange} + fullWidth + indicatorColor="secondary" + textColor="secondary" + > + <Tab icon={<CalendarViewDayIcon />} label="table" component={Link} to="/manuscripts/table" /> + <Tab icon={<AddLocationIcon />} label="creation places" component={Link} to="/manuscripts/creation_places" /> + <Tab icon={<RedoIcon />} label="migrations" /> + <Tab icon={<PieChartIcon />} label="statistics" /> + </Tabs> + </Paper> + ); + } +} + +ViewTabs.propTypes = { + classes: PropTypes.object.isRequired, +}; + +export default withStyles(styles)(ViewTabs); diff --git a/src/client/containers/MapApp.js b/src/client/containers/MapApp.js index f077cdde..16a5e9eb 100644 --- a/src/client/containers/MapApp.js +++ b/src/client/containers/MapApp.js @@ -54,46 +54,6 @@ const styles = theme => ({ borderLeft: '4px solid' + theme.palette.primary.main, backgroundColor: 'rgb(238, 238, 238)' }, - // resultTable: { - // width: 1024, - // height: 'calc(100% - 5px)', - // borderRight: '4px solid' + theme.palette.primary.main, - // - // }, - // resultTableOneColumn: { - // width: '100%', - // height: 'calc(100% - 5px)', - // overflow: 'auto' - // }, - // rightColumn: { - // height: '100%', - // width: 'calc(100% - 1024px)', - // }, - // map: { - // width: '100%', - // height: '50%', - // borderBottom: '4px solid' + theme.palette.primary.main, - // }, - // fullMap: { - // width: '100%', - // height: '100%', - // }, - // statistics: { - // width: '100%', - // height: '50%', - // }, - // statisticsOneColumn: { - // width: '100%', - // height: '100%', - // }, - // progress: { - // display: 'flex', - // alignItems: 'center', - // justifyContent: 'center', - // }, - // progressTitle: { - // marginRight: 15 - // }, footer: { position: 'absolute', borderTop: '4px solid' + theme.palette.primary.main, @@ -151,6 +111,7 @@ let MapApp = (props) => { fetchPlace={props.fetchPlace} fetchFacet={props.fetchFacet} fetchResults={props.fetchResults} + match={props.match} />} /> </Switch> @@ -198,7 +159,8 @@ MapApp.propTypes = { fetchPlaces: PropTypes.func.isRequired, fetchPlace: PropTypes.func.isRequired, fetchFacet: PropTypes.func.isRequired, - fetchResults: PropTypes.func.isRequired + fetchResults: PropTypes.func.isRequired, + match: PropTypes.object.isRequired }; export default compose( diff --git a/src/client/index.html b/src/client/index.html index 5fb22df7..b750d60f 100644 --- a/src/client/index.html +++ b/src/client/index.html @@ -21,8 +21,10 @@ #root, #app { height: 100%; } - .leaflet-container { - height: 100%; + .leaflet-outer-container { + height: cacl(100% - 72px); + width: 100%; + margin-top: 72px } a, a:visited, a:hover, a:active { color: blue; diff --git a/webpack.client.common.js b/webpack.client.common.js index ba4ef89c..70ff3ea3 100644 --- a/webpack.client.common.js +++ b/webpack.client.common.js @@ -26,6 +26,7 @@ module.exports = { output: { filename: '[name].bundle.js', path: path.resolve(__dirname, outputDirectory), + publicPath: '/' }, module: { rules: [ diff --git a/webpack.client.dev.js b/webpack.client.dev.js index 11d9dbfb..819680a2 100644 --- a/webpack.client.dev.js +++ b/webpack.client.dev.js @@ -1,5 +1,6 @@ const merge = require('webpack-merge'); const common = require('./webpack.client.common.js'); +const path = require('path'); module.exports = merge(common, { mode: 'development', @@ -8,6 +9,8 @@ module.exports = merge(common, { hot: true, port: 8080, open: true, - historyApiFallback: true + historyApiFallback: true, + publicPath: '/', + contentBase: path.join(__dirname, 'dist/public') } }); -- GitLab