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

Feat #599: Improve map toggle #622

Merged
merged 4 commits into from
May 31, 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
16 changes: 14 additions & 2 deletions src/app/find-properties/[[...opa_id]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "@/components";
import { FilterProvider } from "@/context/FilterContext";
import { NextUIProvider, Spinner } from "@nextui-org/react";
import { X } from "@phosphor-icons/react";
import { X, GlobeHemisphereWest, ListBullets } from "@phosphor-icons/react";
import { MapGeoJSONFeature } from "maplibre-gl";
import StreetView from "../../../components/StreetView";
import { centroid } from "@turf/centroid";
Expand Down Expand Up @@ -180,7 +180,6 @@ const MapPage = ({ params }: MapPageProps) => {
smallScreenMode,
setShouldFilterSavedProperties,
updateCurrentView,
updateSmallScreenMode,
};
const isVisible = (mode: string) =>
smallScreenMode === mode ? "" : "max-sm:hidden";
Expand Down Expand Up @@ -306,6 +305,19 @@ const MapPage = ({ params }: MapPageProps) => {
/>
)}
</SidePanel>
<ThemeButton
aria-label={`Change to ${smallScreenMode}`}
label={smallScreenMode === "map" ? "List View" : "Map View"}
className="fixed bottom-10 left-1/2 -ml-[3.5rem] rounded-2xl sm:hidden max-md:min-w-[7rem]"
onPress={updateSmallScreenMode}
startContent={
smallScreenMode === "map" ? (
<ListBullets />
) : (
<GlobeHemisphereWest />
)
}
/>
</div>
</div>
</NextUIProvider>
Expand Down
11 changes: 10 additions & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,8 @@ a .bg-color-none {
/* Style override for map controls */
.maplibregl-ctrl button.maplibregl-ctrl-geolocate,
.maplibregl-ctrl button.maplibregl-ctrl-zoom-in,
.maplibregl-ctrl button.maplibregl-ctrl-zoom-out {
.maplibregl-ctrl button.maplibregl-ctrl-zoom-out,
.maplibregl-ctrl button.custom-legend-info {
border-radius: 0.25em;
height: 40px;
width: 40px;
Expand All @@ -345,6 +346,14 @@ a .bg-color-none {
background-image: url('data:image/svg+xml,<svg width="16" height="2" viewBox="0 0 16 2" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.5 0.724609C15.5 0.89037 15.4342 1.04934 15.3169 1.16655C15.1997 1.28376 15.0408 1.34961 14.875 1.34961H1.125C0.95924 1.34961 0.800269 1.28376 0.683058 1.16655C0.565848 1.04934 0.5 0.89037 0.5 0.724609C0.5 0.558849 0.565848 0.399878 0.683058 0.282668C0.800269 0.165458 0.95924 0.0996094 1.125 0.0996094H14.875C15.0408 0.0996094 15.1997 0.165458 15.3169 0.282668C15.4342 0.399878 15.5 0.558849 15.5 0.724609Z" fill="%2303141B"/></svg>') !important;
}

.custom-legend-info-div {
top: 82%;
@apply left-7 fixed;
}

.custom-legend-info-icon {
background-image: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9 0.875C7.39303 0.875 5.82214 1.35152 4.486 2.24431C3.14985 3.1371 2.10844 4.40605 1.49348 5.8907C0.87852 7.37535 0.717618 9.00901 1.03112 10.5851C1.34463 12.1612 2.11846 13.6089 3.25476 14.7452C4.39106 15.8815 5.8388 16.6554 7.4149 16.9689C8.99099 17.2824 10.6247 17.1215 12.1093 16.5065C13.594 15.8916 14.8629 14.8502 15.7557 13.514C16.6485 12.1779 17.125 10.607 17.125 9C17.1227 6.84581 16.266 4.78051 14.7427 3.25727C13.2195 1.73403 11.1542 0.877275 9 0.875ZM9 15.875C7.64026 15.875 6.31105 15.4718 5.18046 14.7164C4.04987 13.9609 3.16868 12.8872 2.64833 11.6309C2.12798 10.3747 1.99183 8.99237 2.2571 7.65875C2.52238 6.32513 3.17716 5.10013 4.13864 4.13864C5.10013 3.17716 6.32514 2.52237 7.65876 2.2571C8.99238 1.99183 10.3747 2.12798 11.631 2.64833C12.8872 3.16868 13.9609 4.04987 14.7164 5.18045C15.4718 6.31104 15.875 7.64025 15.875 9C15.8729 10.8227 15.1479 12.5702 13.8591 13.8591C12.5702 15.1479 10.8227 15.8729 9 15.875ZM10.25 12.75C10.25 12.9158 10.1842 13.0747 10.0669 13.1919C9.94974 13.3092 9.79076 13.375 9.625 13.375C9.29348 13.375 8.97554 13.2433 8.74112 13.0089C8.5067 12.7745 8.375 12.4565 8.375 12.125V9C8.20924 9 8.05027 8.93415 7.93306 8.81694C7.81585 8.69973 7.75 8.54076 7.75 8.375C7.75 8.20924 7.81585 8.05027 7.93306 7.93306C8.05027 7.81585 8.20924 7.75 8.375 7.75C8.70652 7.75 9.02447 7.8817 9.25889 8.11612C9.49331 8.35054 9.625 8.66848 9.625 9V12.125C9.79076 12.125 9.94974 12.1908 10.0669 12.3081C10.1842 12.4253 10.25 12.5842 10.25 12.75ZM7.75 5.5625C7.75 5.37708 7.80499 5.19582 7.908 5.04165C8.01101 4.88748 8.15743 4.76732 8.32874 4.69636C8.50004 4.62541 8.68854 4.60684 8.8704 4.64301C9.05226 4.67919 9.2193 4.76848 9.35042 4.89959C9.48153 5.0307 9.57082 5.19775 9.60699 5.3796C9.64316 5.56146 9.6246 5.74996 9.55364 5.92127C9.48268 6.09257 9.36252 6.23899 9.20835 6.342C9.05418 6.44502 8.87292 6.5 8.6875 6.5C8.43886 6.5 8.20041 6.40123 8.02459 6.22541C7.84878 6.0496 7.75 5.81114 7.75 5.5625Z" fill="%23173009"/></svg>') !important;
}
/* Tooltips for maplibre components, classes style the title attributes */
.maplibregl-ctrl button.maplibregl-ctrl-geolocate[title]:hover::after,
.maplibregl-ctrl button.maplibregl-ctrl-zoom-in[title]:hover::after,
Expand Down
33 changes: 20 additions & 13 deletions src/components/MapLegendControl/MapLegend.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ExpressionName } from "mapbox-gl";
import React, { ReactElement } from "react";
import React, { ReactElement, Dispatch, SetStateAction } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { FillLayerSpecification } from "maplibre-gl";
import { IControl, MapboxMap } from "react-map-gl";


import "../../app/mapLegend.css";

interface LayerStyleMetadata {
Expand Down Expand Up @@ -79,28 +80,32 @@ function MapLegend(layerStyle: FillLayerSpecification) {
);

return (
<div className="panes" style={{ display: "block" }}>
<details
className={`mapboxgl-ctrl-legend-pane mapboxgl-ctrl-legend-pane--${layerStyle.source}`}
open
>
<summary id="legend-summary">
{(layerStyle.metadata as LayerStyleMetadata).name}
</summary>
<ul className="legend-list list list--color">{paneBlocks}</ul>
</details>
</div>
<>
<div className="panes" style={{ display: "block" }} onClick={() => console.log('hit') }>
<details
className={`mapboxgl-ctrl-legend-pane mapboxgl-ctrl-legend-pane--${layerStyle.source}`}
open
>
<summary id="legend-summary">
{(layerStyle.metadata as LayerStyleMetadata).name}
</summary>
<ul className="legend-list list list--color">{paneBlocks}</ul>
</details>
</div>
</>
);
}

export class MapLegendControlClass implements IControl {
private _map: MapboxMap | undefined;
private _container: HTMLElement;
private handler: () => void;

constructor(layerStyle: FillLayerSpecification) {
constructor(layerStyle: FillLayerSpecification, setSmallScreenToggle: Dispatch<SetStateAction<boolean>>) {
this._container = document.createElement("div");
this._container.classList.add("mapboxgl-ctrl", "mapboxgl-ctrl-legend");
// render legend as static markup so it can be rendered with map
this.handler = () => setSmallScreenToggle(s => !s);
this._container.innerHTML = renderToStaticMarkup(
<MapLegend {...layerStyle} />
);
Expand All @@ -109,10 +114,12 @@ export class MapLegendControlClass implements IControl {
// able to add event listeners here for interactivity with layer
onAdd = (map: MapboxMap) => {
this._map = map;
this._container.addEventListener("click", this.handler);
return this._container;
};

onRemove = () => {
this._container.removeEventListener("click", this.handler);
this._container.parentNode?.removeChild(this._container);
this._map = undefined;
};
Expand Down
5 changes: 3 additions & 2 deletions src/components/MapLegendControl/MapLegendControl.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { ControlPosition, FillLayerSpecification } from "maplibre-gl";
import React from "react";
import React, { Dispatch, SetStateAction } from "react";
import { useControl } from "react-map-gl";
import { MapLegendControlClass } from "./MapLegend";

interface LegendOptions {
position: ControlPosition;
layerStyle: FillLayerSpecification;
setSmallScreenToggle: Dispatch<SetStateAction<boolean>>;
}

export default function MapLegendControl(props: LegendOptions) {
useControl(() => new MapLegendControlClass(props.layerStyle), {
useControl(() => new MapLegendControlClass(props.layerStyle, props.setSmallScreenToggle), {
position: props.position,
});
return null;
Expand Down
31 changes: 23 additions & 8 deletions src/components/PropertyMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { Info, X } from "@phosphor-icons/react";
import { centroid } from "@turf/centroid";
import { Position } from "geojson";
import { toTitleCase } from "../utilities/toTitleCase";
import { ThemeButton } from "../components/ThemeButton";

type SearchedProperty = {
coordinates: [number, number];
Expand Down Expand Up @@ -108,14 +109,27 @@ const layerStylePoints: CircleLayerSpecification = {
// info icon in legend summary
let summaryInfo: ReactElement | null = null;

const MapControls = () => (
<>
<NavigationControl showCompass={false} position="bottom-right" />
<GeolocateControl position="bottom-right" />
<ScaleControl />
<MapLegendControl position="bottom-left" layerStyle={layerStylePolygon} />
</>
);
const MapControls = () => {
const [smallScreenToggle, setSmallScreenToggle] = useState<boolean>(false);
return (
<>
<NavigationControl showCompass={false} position="bottom-right" />
<GeolocateControl position="bottom-right" />
<ScaleControl />
{(smallScreenToggle || window.innerWidth > 640) ?
<MapLegendControl position="bottom-left" setSmallScreenToggle={setSmallScreenToggle} layerStyle={layerStylePolygon} />
:
<div className="custom-legend-info-div maplibregl-ctrl maplibregl-ctrl-group w-[40px] h-[40px]">
<ThemeButton
className="custom-legend-info z-10"
startContent={<span className="custom-legend-info-icon maplibregl-ctrl-icon"></span>}
onPress={() => setSmallScreenToggle(s => !s)}
/>
</div>
}
</>
)
};

interface PropertyMapProps {
featuresInView: MapGeoJSONFeature[];
Expand Down Expand Up @@ -147,6 +161,7 @@ const PropertyMap: FC<PropertyMapProps> = ({
coordinates: [-75.1628565788269, 39.97008211622267],
address: "",
});
const [smallScreenToggle, setSmallScreenToggle] = useState<boolean>(false);

useEffect(() => {
let protocol = new Protocol();
Expand Down
19 changes: 1 addition & 18 deletions src/components/SidePanelControlBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { BarClickOptions } from "@/app/find-properties/[[...opa_id]]/page";
import {
BookmarkSimple,
DownloadSimple,
Funnel,
GlobeHemisphereWest,
SquaresFour,
Funnel
} from "@phosphor-icons/react";
import { ThemeButton } from "./ThemeButton";
import { useFilter } from "@/context/FilterContext";
Expand All @@ -22,7 +20,6 @@ type SidePanelControlBarProps = {
smallScreenMode: string;
setShouldFilterSavedProperties: (shouldFilter: boolean) => void;
updateCurrentView: (view: BarClickOptions) => void;
updateSmallScreenMode: () => void;
};

const SearchBarComponent: FC<SidePanelControlBarProps> = ({
Expand All @@ -34,7 +31,6 @@ const SearchBarComponent: FC<SidePanelControlBarProps> = ({
smallScreenMode,
setShouldFilterSavedProperties,
updateCurrentView,
updateSmallScreenMode,
}) => {
const filterRef = useRef<HTMLButtonElement | null>(null);
const savedRef = useRef<HTMLButtonElement | null>(null);
Expand Down Expand Up @@ -73,19 +69,6 @@ const SearchBarComponent: FC<SidePanelControlBarProps> = ({
<>
<div className="flex justify-between -mx-6 px-12 top-0 py-4 z-10 bg-white">
{/* Left-aligned content: Total Properties in View */}
<ThemeButton
color="tertiary"
aria-label={`Change to ${smallScreenMode}`}
className="sm:hidden max-md:min-w-[4rem]"
onPress={updateSmallScreenMode}
startContent={
smallScreenMode === "map" ? (
<SquaresFour />
) : (
<GlobeHemisphereWest />
)
}
/>
<div className="sm:px-4 lg:px-0 py-2">
<h1 className="body-md">
<span className="font-bold">
Expand Down