diff --git a/docker-compose.yml b/docker-compose.yml index 438b0781d..c6f91f9e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,8 +50,8 @@ services: - ./src/frontend:/app # One-way volume to use node_modules from inside image - /app/node_modules - depends_on: - - django + # depends_on: + # - django command: npm run start-frontend db: diff --git a/src/frontend/src/Components/Map.js b/src/frontend/src/Components/Map.js index d148749ac..82c680c57 100644 --- a/src/frontend/src/Components/Map.js +++ b/src/frontend/src/Components/Map.js @@ -102,6 +102,7 @@ export default function MapWrapper({ const mapElement = useRef(); const mapRef = useRef(); const popup = useRef(); + const panel = useRef(); const mapLayers = useRef({}); const mapView = useRef(); const container = useRef(); @@ -652,6 +653,20 @@ export default function MapWrapper({ } } + function togglePanel() { + panel.current.classList.toggle('open'); + panel.current.classList.remove('maximized'); + if (!panel.current.classList.contains('open')) { + closePopup(); + } + } + + function maximizePanel() { + if (panel.current.classList.contains('open')) { + panel.current.classList.add('maximized'); + } + } + function handleCenter() { if (typeof camera === 'string') { camera = JSON.parse(camera); @@ -692,9 +707,40 @@ export default function MapWrapper({ mapContext.visible_layers['inlandFerries'] = true; } + const openPanel = !!(clickedCamera || clickedEvent || clickedFerry); + return (
+ +
+
+ +
+ +
+ {clickedCamera && + + } + + {clickedEvent && getEventPopup(clickedEvent)} + + {clickedFerry && getFerryPopup(clickedFerry)} +
+ +
+
+
)} + + {!isPreview && ( +
+ + +
+ )} + +
); } diff --git a/src/frontend/src/Components/Map.scss b/src/frontend/src/Components/Map.scss index 158374488..3d713bbb5 100644 --- a/src/frontend/src/Components/Map.scss +++ b/src/frontend/src/Components/Map.scss @@ -18,6 +18,36 @@ z-index: 5; } +@keyframes open-panel { + from { + min-width: 0px; + @media (max-width: 575px) { + min-height: 0%; + } + } + + to { + min-width: 500px; + @media (max-width: 575px) { + min-height: 50%; + } + } +} + +@keyframes maximize-panel { + from { + @media (max-width: 575px) { + min-height: 50%; + } + } + + to { + @media (max-width: 575px) { + min-height: 100%; + } + } +} + .map-wrap { position: absolute; top: 58px; @@ -28,187 +58,263 @@ top: 58px; } - .map { - position: absolute; - width: 100%; - top: 0; - bottom: 0; - - .ol-overlay-container:not(:has(> img)) { - //overriding openlayers dynamic styles for mobile layout except for having img as a direct child - @media (max-width: 575px) { - position: fixed !important; - bottom: 0 !important; - transform: none !important; - } + .map-container { - // overlay content styling moved to App.scss - } + display: flex; + align-items: stretch; + height: 100%; - .ol-zoom .ol-zoom-out { - margin-top: 200px; + @media (max-width: 575px) { + flex-direction: column; } - .ol-scale-line { - background: var(--ol-partial-background-color); - border-radius: 4px; - left: auto; - right: 8rem; - bottom: 1rem; - padding: 2px; - position: absolute; + .side-panel { + flex: 0; + min-width: 0px; + min-height: 0%; + transition: min-width 0.25s ease-in-out; + overflow: hidden; + display: flex; + flex-direction: column; - @media (min-width: 768px) { - right: 1rem; - bottom: 1rem; + @media (max-width: 575px) { + transition: min-height 0.25s ease-in-out; + order: 2; } - @media (min-width: 992px) { - right: 4rem; - bottom: 1rem; + &.open { + min-width: 500px; + animation-name: open-panel; + .panel-content { + min-width: 450px; + } + + @media (max-width: 575px) { + min-width: 100%; + min-height: 50%; + .panel-content { + min-width: 100%; + overflow-y: hidden; + } + } } - } - .ol-scale-line-inner { - border: 1px solid var(--ol-subtle-foreground-color); - border-top: none; - color: var(--ol-foreground-color); - font-size: 0.75rem; - text-align: center; - font-family: 'BCSans', serif; - margin: 1px; - will-change: contents, width; - transition: all 0.25s; - } - } + &.maximized { + @media (max-width: 575px) { + min-height: 100%; + .panel-content { + overflow-y: scroll; + } + } + } - .map-btn { - background-color: $Surface-tinted; - color: $Type-Link; - position: absolute; - margin-bottom: 0; - font-size: 0.875rem; - font-weight: 700; - height: auto; - border-radius: 4px; - border: 1px solid $Type-Link; - box-shadow: 0px 1.9368422031402588px 4.3578948974609375px 0px #00000021; - - &:hover { - background: $Type-Link; - color: $White; - } + .closer-bar { + padding: 0.5rem; + text-align: right; + // width: 300px; + flex: 0; - &.map-view, &.cam-location { - svg { - margin-right: 8px; + .panel-closer { + cursor: pointer; + } } - } - &.map-view, &.my-location, &.open-filters { - svg { - margin-right: 8px; + + .panel-content { + flex: 1; + padding: 1rem; + overflow-y: scroll; + // min-width: 450px; } } - &.map-view { - position: absolute; - top: 2rem; - right: 2rem; - } + .map { + flex: 1; + position: relative; + width: 100%; + height: 100%; + overflow: hidden; - &.cam-location { - position: absolute; - bottom: 2rem; - left: 2rem; - } + .ol-overlay-container:not(:has(> img)) { + //overriding openlayers dynamic styles for mobile layout except for having img as a direct child + @media (max-width: 575px) { + position: fixed !important; + bottom: 0 !important; + transform: none !important; + } - &.my-location { - position: absolute; - bottom: 1rem; - left: 1rem; - } + // overlay content styling moved to App.scss + } - &.open-filters { - position: absolute; - top: 1rem; - right: 1rem; + .ol-zoom .ol-zoom-out { + margin-top: 200px; + } - @media (max-width: 768px) { - top: initial; + .ol-scale-line { + background: var(--ol-partial-background-color); + border-radius: 4px; + left: auto; + right: 1rem; bottom: 1rem; - } + padding: 2px; + position: absolute; - // styling for badge - // &:after { - // content: '1'; - // font-size: 10px; - // font-weight: 700; - // padding: 1px 8px; - // color: white; - // background-color: $Type-Link; - // border-radius: 5px; - // margin-left: 8px; - // vertical-align: middle; - // padding: 0 5px; - // } - - // &:hover { - // &:after { - // color: $Type-Link; - // background-color: white; - // } - // } - } - } + @media (min-width: 768px) { + right: 1rem; + bottom: 1rem; + } - .zoom-btn { - background-color: $Surface-tinted; - color: $Type-Link; - position: absolute; - margin-bottom: 0; - font-size: 1rem; - font-weight: 700; - height: auto; - border-radius: 6px; - border: 1px solid $Type-Link; - box-shadow: 0px 1.9368422031402588px 4.3578948974609375px 0px #00000021; - bottom: 1rem; - right: 1rem; - display: flex; - flex-direction: column; + @media (min-width: 992px) { + right: 4rem; + bottom: 1rem; + } - //Hide zoom slider on touch devices - @media (max-width: 992px) { - display: none; + @media (max-width: 575px) { + bottom: 4rem; + } + } + + .ol-scale-line-inner { + border: 1px solid var(--ol-subtle-foreground-color); + border-top: none; + color: var(--ol-foreground-color); + font-size: 0.75rem; + text-align: center; + font-family: 'BCSans', serif; + margin: 1px; + will-change: contents, width; + transition: all 0.25s; + } } - & > .btn { - margin-bottom: 0; + .map-btn { background-color: $Surface-tinted; color: $Type-Link; - border: none; - border-radius: 0; - padding: 4px 8px; + position: absolute; + margin-bottom: 0; + font-size: 0.875rem; + font-weight: 700; + height: auto; + border-radius: 4px; + border: 1px solid $Type-Link; + box-shadow: 0px 1.9368422031402588px 4.3578948974609375px 0px #00000021; &:hover { background: $Type-Link; color: $White; } - &.zoom-in { - border-top-left-radius: 5px; - border-top-right-radius: 5px; + &.map-view, &.cam-location { + svg { + margin-right: 8px; + } + } + &.map-view, &.my-location, &.open-filters { + svg { + margin-right: 8px; + } + } + + &.map-view { + position: absolute; + top: 2rem; + right: 2rem; + } + + &.cam-location { + position: absolute; + bottom: 2rem; + left: 2rem; + } + + &.my-location { + position: absolute; + bottom: 1rem; + left: 1rem; } - &.zoom-out { - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; + &.open-filters { + position: absolute; + top: 1rem; + right: 1rem; + z-index: 5; + + @media (max-width: 768px) { + top: initial; + bottom: 1rem; + } + + // styling for badge + // &:after { + // content: '1'; + // font-size: 10px; + // font-weight: 700; + // padding: 1px 8px; + // color: white; + // background-color: $Type-Link; + // border-radius: 5px; + // margin-left: 8px; + // vertical-align: middle; + // padding: 0 5px; + // } + + // &:hover { + // &:after { + // color: $Type-Link; + // background-color: white; + // } + // } } } - .zoom-divider { - margin: 0 10px; - border-bottom: 1px solid $Divider; + .zoom-btn { + background-color: $Surface-tinted; + color: $Type-Link; + position: absolute; + margin-bottom: 0; + font-size: 1rem; + font-weight: 700; + height: auto; + border-radius: 6px; + border: 1px solid $Type-Link; + box-shadow: 0px 1.9368422031402588px 4.3578948974609375px 0px #00000021; + bottom: 1rem; + right: 1rem; + display: flex; + flex-direction: column; + + //Hide zoom slider on touch devices + @media (max-width: 992px) { + display: none; + } + + & > .btn { + margin-bottom: 0; + background-color: $Surface-tinted; + color: $Type-Link; + border: none; + border-radius: 0; + padding: 4px 8px; + + &:hover { + background: $Type-Link; + color: $White; + } + + &.zoom-in { + border-top-left-radius: 5px; + border-top-right-radius: 5px; + } + + &.zoom-out { + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + } + } + + .zoom-divider { + margin: 0 10px; + border-bottom: 1px solid $Divider; + } } } } diff --git a/src/frontend/src/Components/map/RouteSearch.scss b/src/frontend/src/Components/map/RouteSearch.scss index 13b7d9da4..638ae6606 100644 --- a/src/frontend/src/Components/map/RouteSearch.scss +++ b/src/frontend/src/Components/map/RouteSearch.scss @@ -1,8 +1,10 @@ @import "../../styles/variables.scss"; .routing-container { - background: white; + // background: white; + position: absolute; padding: 1rem 1rem 0; + z-index: 5; .typeahead-container { position: relative;