Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#8470] Add map tiles for project overview #5728

Merged
merged 2 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions meinberlin/assets/scss/components_user_facing/_project-tile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,35 @@ a.project-tile {
height: 100%;
}

&--horizontal {
&--horizontal:not(.project-tile--map) {
border-bottom: 1px solid $gray-lighter;
padding-bottom: 1.5em;
padding-top: 1.5em;
}
}

.project-tile__image-wrapper {
flex: 1
flex: 1;
hom3mad3 marked this conversation as resolved.
Show resolved Hide resolved
min-width: 0;

.project-tile--map & {
flex: 0 0 auto;

@media screen and (min-width: $breakpoint-tablet) {
flex: 3;
}
}
}

.project-tile__image {
object-fit: cover;
width: 100%;
max-width: 100%;
height: auto;
aspect-ratio: 4 / 3;

.project-tile--horizontal & {
aspect-ratio: 112 / 115;
}
}

.project-tile__body {
Expand Down Expand Up @@ -91,4 +106,5 @@ a.project-tile {

.project-tile__timespan {
font-size: $font-size-sm;
font-weight: 400;
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
flex: 1;
}

.projects-list__map,
.modul-geomap,
.geomap-main,
.geomap-container,
Expand Down Expand Up @@ -82,12 +83,20 @@
@media screen and (min-width: $breakpoint-tablet) {
display: flex;
align-items: center;
padding-bottom: .8em;
}
}

.projects-list__status--mobile {
margin-bottom: 1em;

@media screen and (min-width: $breakpoint-tablet) {
display: none;
}
}

.projects-list__wrapper--combined .projects-list__list-meta:not(.projects-list__list-meta--no-results) {
border-bottom: 1px solid $gray-lighter;
padding-bottom: .8em;
}

.projects-list__list-meta--no-results div:first-child {
Expand Down
54 changes: 53 additions & 1 deletion meinberlin/assets/scss/components_user_facing/_projects_map.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
.projects-map {
height: 100%;
height: 100%;

.leaflet-bottom.leaflet-left {
position: static;
}
}

.project-overlay-control {
background: $white;
position: absolute;
bottom: 1.5em;
left: 1.5em;
right: 1.5em;
z-index: 1000;
padding: 0.5em;

@media screen and (min-width: $breakpoint-tablet) {
display: none;
}

.project-tile__image {
height: 175px;
}

a {
color: $text-base;
}
}

.projects-map__popup {
display: none;

@media screen and (min-width: $breakpoint-tablet) {
display: block;

}

.leaflet-popup-content-wrapper {
border-radius: 0;
}

.leaflet-popup-content {
margin: 1em;
}

.leaflet-popup-content a {
color: $text-base;
}

.leaflet-popup-tip-container {
display: none;
}
}

7 changes: 3 additions & 4 deletions meinberlin/react/plans/PlansListMapBox.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* global django */
import StickyBox from 'react-sticky-box'
import React, { Component } from 'react'
import FilterNav from './FilterNav'
import Toggles from './Toggles'
Expand Down Expand Up @@ -409,9 +408,9 @@ class PlansListMapBox extends Component {
{this.getPlansList(true)}
</div>
<div id="map" className="projects-list__map">
<StickyBox offsetTop={0} offsetBottom={0}>
{this.getPlansMap(true, 'topright')}
</StickyBox>
{/* <StickyBox offsetTop={0} offsetBottom={0}> */}
{this.getPlansMap(true, 'topright')}
{/* </StickyBox> */}
</div>
</div>
)
Expand Down
76 changes: 76 additions & 0 deletions meinberlin/react/projects/ProjectMapOverlay.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react'
import L from 'leaflet'
import ReactDOM from 'react-dom'
import {
createContainerComponent,
createControlHook,
createElementHook,
createElementObject,
extendContext
} from '@react-leaflet/core'
import ProjectTile from './ProjectTile'

// Create the custom control class
const ProjectMapOverlayControl = L.Control.extend({
options: {
position: 'bottomleft'
},

onAdd: function (map) {
this._map = map
this._container = L.DomUtil.create('div', 'project-overlay-control')

if (this._content) {
this._container.appendChild(this._content)
}

L.DomEvent.disableClickPropagation(this._container)
L.DomEvent.disableScrollPropagation(this._container)

return this._container
},

onRemove: function (map) {
if (this._container) {
ReactDOM.unmountComponentAtNode(this._container)
L.DomUtil.remove(this._container)
this._container = null
}
},

addTo: function (map) {
L.Control.prototype.addTo.call(this, map)
this._container.classList.remove('leaflet-control')
return this
}
})

const useProjectMapOverlayElement = createElementHook((props, context) => {
const { position, children } = props

const control = new ProjectMapOverlayControl({ position })

// Create a div for React content
const contentDiv = L.DomUtil.create('div')
ReactDOM.render(children, contentDiv)
control._content = contentDiv

return createElementObject(control, extendContext(context, {
overlayContainer: control
}))
})

const useProjectMapOverlay = createControlHook(useProjectMapOverlayElement)
const ProjectMapOverlayContainer = createContainerComponent(useProjectMapOverlay)

const ProjectMapOverlay = ({ project, topicChoices, position = 'bottomleft', ...props }) => {
return project
? (
<ProjectMapOverlayContainer position={position} {...props}>
<ProjectTile project={project} isHorizontal isMapTile topicChoices={topicChoices} />
</ProjectMapOverlayContainer>
)
: null
}

export default ProjectMapOverlay
12 changes: 6 additions & 6 deletions meinberlin/react/projects/ProjectTile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function truncateText (item) {
}
}

const ProjectTile = ({ project, isHorizontal, topicChoices }) => {
const ProjectTile = ({ project, isHorizontal, topicChoices, isMapTile }) => {
const labelId = useId()
const describedById = useId()
const statusId = useId()
Expand All @@ -36,14 +36,14 @@ const ProjectTile = ({ project, isHorizontal, topicChoices }) => {
aria-labelledby={labelId}
id={describedById}
aria-describedby={describedById}
className={classNames('project-tile', isHorizontal ? 'project-tile--horizontal' : 'project-tile--vertical')}
className={classNames('project-tile', isHorizontal ? 'project-tile--horizontal' : 'project-tile--vertical', isMapTile && 'project-tile--map')}
>
<div className="project-tile__image-wrapper">
<ImageWithPlaceholder
src={project.tile_image}
alt={project.tile_image_alt_text ?? altImgStr}
height={245}
width={isHorizontal ? 245 : 315}
height={490}
width={isHorizontal ? 490 : 630}
className="project-tile__image"
/>
<span className="project-tile__copyright">
Expand All @@ -52,13 +52,13 @@ const ProjectTile = ({ project, isHorizontal, topicChoices }) => {
</div>

<div className="project-tile__body">
<span className="project-tile__head">{project.district}</span>
{!isMapTile && <span className="project-tile__head">{project.district}</span>}
{project.topics?.length > 0 &&
<div className="project-tile__topics">
<ProjectTopics project={project} topicChoices={topicChoices} />
</div>}
<h3 className="project-tile__title" id={labelId}>{project.title}</h3>
{project.description && (
{project.description && !isMapTile && (
<p className="project-tile__description">
{truncateText(project.description)}
</p>
Expand Down
35 changes: 22 additions & 13 deletions meinberlin/react/projects/ProjectsListMapBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,6 @@ const ProjectsListMapBox = ({
fetchItems()
}, [fetchItems])

useEffect(() => {
// toggle between full width (when map + list) and narrow (when list only)
document.querySelector('.mb-project-overview').classList.toggle('fullwidth', !!showMap)
}, [showMap])

let status = nothingStr

if (loading) {
Expand All @@ -104,6 +99,12 @@ const ProjectsListMapBox = ({
<div>
<div className="projects-list">
<h1 className="aural">{pageHeader}</h1>
<div
role="status"
className="projects-list__status projects-list__status--mobile"
>
{status}
</div>
<IconSwitch
fullWidth
className="projects-list__icon-switch"
Expand All @@ -115,15 +116,21 @@ const ProjectsListMapBox = ({
icon: 'fa fa-list',
id: 'show_list',
isActive: !showMap,
handleClick: () => setShowMap(false)
handleClick: () => {
document.querySelector('.mb-project-overview').classList.remove('fullwidth')
setShowMap(false)
}
},
{
ariaLabel: showMapAriaStr,
label: mapStr,
icon: 'fa fa-map',
id: 'show_map',
isActive: showMap,
handleClick: () => setShowMap(true)
handleClick: () => {
document.querySelector('.mb-project-overview').classList.add('fullwidth')
setShowMap(true)
}
}
]}
/>
Expand All @@ -141,7 +148,10 @@ const ProjectsListMapBox = ({
<ToggleSwitch
uniqueId="map-switch"
className="projects-list__toggle-switch"
toggleSwitch={() => setShowMap(!showMap)}
toggleSwitch={() => {
document.querySelector('.mb-project-overview').classList.toggle('fullwidth', !showMap)
setShowMap(!showMap)
}}
onSwitchStr={showMapStr}
checked={showMap}
/>
Expand All @@ -155,20 +165,19 @@ const ProjectsListMapBox = ({
</div>
{showMap &&
<div id="map" className="projects-list__map">
{/* <StickyBox offsetTop={0} offsetBottom={0}> */}
<ProjectsMap
attribution={attribution}
items={items}
bounds={bounds}
// currentDistrict={this.state.district}
// nonValue={districtnames[districtnames.length - 1]}
// districts={districts}
// currentDistrict={this.state.district}
// nonValue={districtnames[districtnames.length - 1]}
// districts={districts}
baseUrl={baseUrl}
mapboxToken={mapboxToken}
omtToken={omtToken}
useVectorMap={useVectorMap}
topicChoices={topicChoices}
/>
{/* </StickyBox> */}
</div>}
</div>
</div>
Expand Down
Loading
Loading