Declarative categories list
This commit is contained in:
parent
43f239c853
commit
1c265b828d
@ -11,7 +11,7 @@ import BuildingView from './building/building-view';
|
|||||||
import ColouringMap from './map/map';
|
import ColouringMap from './map/map';
|
||||||
import Header from './header';
|
import Header from './header';
|
||||||
import MultiEdit from './building/multi-edit';
|
import MultiEdit from './building/multi-edit';
|
||||||
import Overview from './building/overview';
|
import Categories from './building/categories';
|
||||||
|
|
||||||
import AboutPage from './pages/about';
|
import AboutPage from './pages/about';
|
||||||
import ContributorAgreementPage from './pages/contributor-agreement';
|
import ContributorAgreementPage from './pages/contributor-agreement';
|
||||||
@ -195,6 +195,9 @@ class App extends React.Component<any, any> { // TODO: add proper types
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const building_id = (this.state.building)?
|
||||||
|
this.state.building.building_id
|
||||||
|
: 2503371 // Default to UCL main building. TODO use last selected if any
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Header user={this.state.user} />
|
<Header user={this.state.user} />
|
||||||
@ -203,18 +206,18 @@ class App extends React.Component<any, any> { // TODO: add proper types
|
|||||||
<Route exact path="/">
|
<Route exact path="/">
|
||||||
<Welcome />
|
<Welcome />
|
||||||
</Route>
|
</Route>
|
||||||
<Route exact path="/view/:cat.html" render={(props) => (
|
<Route exact path="/view/categories.html">
|
||||||
<Overview
|
<Categories
|
||||||
{...props}
|
mode="view"
|
||||||
mode='view' user={this.state.user}
|
building_id={building_id}
|
||||||
/>
|
/>
|
||||||
) } />
|
</Route>
|
||||||
<Route exact path="/edit/:cat.html" render={(props) => (
|
<Route exact path="/edit/categories.html">
|
||||||
<Overview
|
<Categories
|
||||||
{...props}
|
mode="edit"
|
||||||
mode='edit' user={this.state.user}
|
building_id={building_id}
|
||||||
/>
|
/>
|
||||||
) } />
|
</Route>
|
||||||
<Route exact path="/multi-edit/:cat.html" render={(props) => (
|
<Route exact path="/multi-edit/:cat.html" render={(props) => (
|
||||||
<MultiEdit
|
<MultiEdit
|
||||||
{...props}
|
{...props}
|
||||||
|
147
app/src/frontend/building/categories.tsx
Normal file
147
app/src/frontend/building/categories.tsx
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { NavLink } from 'react-router-dom';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import Sidebar from './sidebar';
|
||||||
|
|
||||||
|
const Categories = (props) => (
|
||||||
|
<Sidebar>
|
||||||
|
<Category
|
||||||
|
title="Location"
|
||||||
|
slug="location"
|
||||||
|
help="https://pages.colouring.london/location"
|
||||||
|
inactive={false}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Land Use"
|
||||||
|
slug="use"
|
||||||
|
help="https://pages.colouring.london/use"
|
||||||
|
inactive={true}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Type"
|
||||||
|
slug="type"
|
||||||
|
help="https://pages.colouring.london/buildingtypology"
|
||||||
|
inactive={true}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Age"
|
||||||
|
slug="age"
|
||||||
|
help="https://pages.colouring.london/age"
|
||||||
|
inactive={false}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Size & Shape"
|
||||||
|
slug="size"
|
||||||
|
help="https://pages.colouring.london/shapeandsize"
|
||||||
|
inactive={false}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Construction"
|
||||||
|
slug="construction"
|
||||||
|
help="https://pages.colouring.london/construction"
|
||||||
|
inactive={true}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Team"
|
||||||
|
slug="team"
|
||||||
|
help="https://pages.colouring.london/team"
|
||||||
|
inactive={true}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Sustainability"
|
||||||
|
slug="sustainability"
|
||||||
|
help="https://pages.colouring.london/sustainability"
|
||||||
|
inactive={true}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Greenery"
|
||||||
|
slug="greenery"
|
||||||
|
help="https://pages.colouring.london/greenery"
|
||||||
|
inactive={true}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Community"
|
||||||
|
slug="community"
|
||||||
|
help="https://pages.colouring.london/community"
|
||||||
|
inactive={false}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Planning"
|
||||||
|
slug="planning"
|
||||||
|
help="https://pages.colouring.london/planning"
|
||||||
|
inactive={true}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
<Category
|
||||||
|
title="Like Me!"
|
||||||
|
slug="like"
|
||||||
|
help="https://pages.colouring.london/likeme"
|
||||||
|
inactive={false}
|
||||||
|
mode={props.mode}
|
||||||
|
building_id={props.building_id}
|
||||||
|
/>
|
||||||
|
</Sidebar>
|
||||||
|
)
|
||||||
|
|
||||||
|
Categories.propTypes = {
|
||||||
|
mode: PropTypes.string,
|
||||||
|
building_id: PropTypes.number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Category = (props) => (
|
||||||
|
<section className={(props.inactive? 'inactive ': '') + 'data-section legend'}>
|
||||||
|
<header className={`section-header ${props.mode} ${props.slug}`}>
|
||||||
|
<NavLink
|
||||||
|
to={`/${props.mode}/${props.slug}/building/${props.building_id}.html`}
|
||||||
|
title={
|
||||||
|
(props.inactive)?
|
||||||
|
'Coming soon… Click the ? for more info.'
|
||||||
|
: 'Show on map'
|
||||||
|
}>
|
||||||
|
<h3 className="h3">{props.title}</h3>
|
||||||
|
</NavLink>
|
||||||
|
<nav className="icon-buttons">
|
||||||
|
{
|
||||||
|
props.help?
|
||||||
|
<a className="icon-button help" href={props.help}>
|
||||||
|
Info
|
||||||
|
</a>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
|
||||||
|
Category.propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
slug: PropTypes.string,
|
||||||
|
help: PropTypes.string,
|
||||||
|
inactive: PropTypes.bool,
|
||||||
|
mode: PropTypes.string,
|
||||||
|
building_id: PropTypes.number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Categories;
|
@ -1,107 +0,0 @@
|
|||||||
import React, { Fragment } from 'react';
|
|
||||||
import { NavLink, Redirect } from 'react-router-dom';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import Sidebar from './sidebar';
|
|
||||||
import { EditIcon } from '../components/icons';
|
|
||||||
import CONFIG from './fields-config.json';
|
|
||||||
|
|
||||||
const Overview = (props) => {
|
|
||||||
var dataLayer = 'age'; // always default
|
|
||||||
if (props.match && props.match.params && props.match.params.cat) {
|
|
||||||
dataLayer = props.match.params.cat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.mode === 'edit' && !props.user){
|
|
||||||
return <Redirect to="/sign-up.html" />
|
|
||||||
}
|
|
||||||
|
|
||||||
const title = (props.mode === 'view')? 'View maps' : 'Add or edit data';
|
|
||||||
const back = (props.mode === 'edit')? `/view/${dataLayer}.html` : undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Sidebar title={title} back={back}>
|
|
||||||
{
|
|
||||||
CONFIG.map((dataGroup) => (
|
|
||||||
<OverviewSection {...dataGroup}
|
|
||||||
dataLayer={dataLayer} key={dataGroup.slug} mode={props.mode} />
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</Sidebar>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Overview.propTypes = {
|
|
||||||
match: PropTypes.object,
|
|
||||||
mode: PropTypes.string,
|
|
||||||
user: PropTypes.object
|
|
||||||
}
|
|
||||||
|
|
||||||
const OverviewSection = (props) => {
|
|
||||||
const match = props.dataLayer === props.slug;
|
|
||||||
const inactive = props.inactive;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className={(inactive? 'inactive ': '') + 'data-section legend'}>
|
|
||||||
<header className={`section-header ${props.mode} ${props.slug} ${(match? 'active' : '')}`}>
|
|
||||||
<NavLink
|
|
||||||
to={`/${props.mode}/${props.slug}.html`}
|
|
||||||
isActive={() => match}
|
|
||||||
title={(inactive)? 'Coming soon… Click the ? for more info.' :
|
|
||||||
(match)? '' : 'Show on map'}>
|
|
||||||
<h3 className="h3">{props.title}</h3>
|
|
||||||
</NavLink>
|
|
||||||
<nav className="icon-buttons">
|
|
||||||
{
|
|
||||||
props.help?
|
|
||||||
<a className="icon-button help" href={props.help}>
|
|
||||||
Info
|
|
||||||
</a>
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
{
|
|
||||||
props.mode === 'view'?
|
|
||||||
<NavLink className="icon-button edit" title="Edit data"
|
|
||||||
to={`/edit/${props.slug}.html`}>
|
|
||||||
Edit
|
|
||||||
<EditIcon />
|
|
||||||
</NavLink>
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
{
|
|
||||||
(match && props.intro)?
|
|
||||||
(
|
|
||||||
<Fragment>
|
|
||||||
<p className="data-intro">{props.intro}</p>
|
|
||||||
<ul>
|
|
||||||
{
|
|
||||||
props.fields.map((field) => {
|
|
||||||
return (<li key={field.slug}>{field.title}</li>)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
OverviewSection.propTypes = {
|
|
||||||
title: PropTypes.string,
|
|
||||||
slug: PropTypes.string,
|
|
||||||
intro: PropTypes.string,
|
|
||||||
help: PropTypes.string,
|
|
||||||
dataLayer: PropTypes.string,
|
|
||||||
mode: PropTypes.string,
|
|
||||||
inactive: PropTypes.bool,
|
|
||||||
fields: PropTypes.arrayOf(PropTypes.shape({
|
|
||||||
title: PropTypes.string,
|
|
||||||
slug: PropTypes.string
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Overview;
|
|
@ -53,24 +53,6 @@
|
|||||||
/**
|
/**
|
||||||
* Sidebar main header
|
* Sidebar main header
|
||||||
*/
|
*/
|
||||||
.sidebar-header {
|
|
||||||
border-bottom: 6px solid;
|
|
||||||
border-image: linear-gradient(
|
|
||||||
to right,
|
|
||||||
#edc40b 0%, #edc40b 8.3%,
|
|
||||||
#f0ee0c 8.3%, #f0ee0c 16.6%,
|
|
||||||
#ff9100 16.6%, #ff9100 25%,
|
|
||||||
#ee5f63 25%, #ee5f63 33.3%,
|
|
||||||
#ee91bf 33.3%, #ee91bf 41.6%,
|
|
||||||
#aa7fa7 41.6%, #aa7fa7 50%,
|
|
||||||
#6f879c 50%, #6f879c 58.3%,
|
|
||||||
#5ec232 58.3%, #5ec232 66.6%,
|
|
||||||
#6dbb8b 66.6%, #6dbb8b 75%,
|
|
||||||
#65b7ff 75%, #65b7ff 83.3%,
|
|
||||||
#a1a3a9 83.3%, #a1a3a9 91.6%,
|
|
||||||
#9c896d 91.6%, #9c896d 100%
|
|
||||||
) 1;
|
|
||||||
}
|
|
||||||
.sidebar-header h2 {
|
.sidebar-header h2 {
|
||||||
margin: 0.45rem 0 0.6rem;
|
margin: 0.45rem 0 0.6rem;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -6,18 +6,24 @@ import './sidebar.css';
|
|||||||
import { BackIcon } from '../components/icons';
|
import { BackIcon } from '../components/icons';
|
||||||
|
|
||||||
const Sidebar = (props) => (
|
const Sidebar = (props) => (
|
||||||
<div id="legend" className="info-container">
|
<div id="sidebar" className="info-container">
|
||||||
<header className="sidebar-header">
|
{
|
||||||
{
|
props.title?
|
||||||
props.back?
|
<header className="sidebar-header">
|
||||||
<Link className="icon-button back" to={props.back}>
|
{
|
||||||
<BackIcon />
|
props.back?
|
||||||
</Link>
|
<Link className="icon-button back" to={props.back}>
|
||||||
: null
|
<BackIcon />
|
||||||
}
|
</Link>
|
||||||
<h2 className="h2">{props.title}</h2>
|
: null
|
||||||
</header>
|
}
|
||||||
{props.children}
|
<h2 className="h2">{props.title}</h2>
|
||||||
|
</header>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
props.children
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -51,13 +51,8 @@ class Header extends React.Component<any, any> { // TODO: add proper types
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<NavLink to="/view/age.html" className="nav-link">
|
<NavLink to="/view/categories.html" className="nav-link">
|
||||||
View Maps
|
View/Edit Maps
|
||||||
</NavLink>
|
|
||||||
</li>
|
|
||||||
<li className="nav-item">
|
|
||||||
<NavLink to="/edit/age.html" className="nav-link">
|
|
||||||
Add/Edit Data
|
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
|
@ -17,7 +17,7 @@ const Welcome = () => (
|
|||||||
volunteers of all ages and abilities to test and provide feedback on the site as we
|
volunteers of all ages and abilities to test and provide feedback on the site as we
|
||||||
build it.
|
build it.
|
||||||
</p>
|
</p>
|
||||||
<Link to="/view/age.html"
|
<Link to="/view/categories.html"
|
||||||
className="btn btn-outline-dark btn-lg btn-block">
|
className="btn btn-outline-dark btn-lg btn-block">
|
||||||
Start Colouring Here!
|
Start Colouring Here!
|
||||||
</Link>
|
</Link>
|
||||||
|
Loading…
Reference in New Issue
Block a user