Skip to content

Commit

Permalink
Merge pull request #59 from Georiviere/map_interactions
Browse files Browse the repository at this point in the history
Map interactions enhancements
  • Loading branch information
Bo-Duke authored Apr 9, 2024
2 parents f758718 + b7fdb18 commit ef0c2d9
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 175 deletions.
76 changes: 8 additions & 68 deletions src/components/details.page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import Image from 'next/image';
import { Attachement } from '@/api/settings';
import { LatLngTuple } from 'leaflet';
import { useTranslations } from 'next-intl';

import { convertAttachementsToImages } from '@/lib/utils';
import { Badge } from '@/components/ui/badge';
import { Icons, propsForSVGPresentation } from '@/components/icons';

import ButtonCenterView from './button-center-view';
import ButtonClose from './button-close';
import Carousel from './carousel';
import MeterLength from './length';
import { MetadataList } from './metadata-list';

type Props = {
content: {
Expand All @@ -35,13 +31,12 @@ type Props = {
};

export default function DetailsPageUI({ content }: Props) {
const t = useTranslations('details');
return (
<article>
{content.attachments.length > 0 && (
<div className="-m-8 mb-6">
<Carousel
className="min-w-full"
className="w-full"
images={convertAttachementsToImages(content.attachments)}
width={800}
height={600}
Expand All @@ -62,67 +57,12 @@ export default function DetailsPageUI({ content }: Props) {
)}
<ButtonClose />
</div>
<dl className="flex items-center gap-2 py-2">
{content.length !== undefined && (
<>
<dt>
<Icons.chevronsLeftRight
className="text-primary"
{...propsForSVGPresentation}
/>
<span className="sr-only">{t('length')}</span>
</dt>
<dd className="mr-2">
<MeterLength length={content.length} />
</dd>
</>
)}
{content.descent !== undefined && (
<>
<dt>
<Icons.arrowDownRight
className="text-primary"
{...propsForSVGPresentation}
/>
<span className="sr-only">{t('descent')}</span>
</dt>
<dd className="mr-2">
<MeterLength length={content.descent} />
</dd>
</>
)}
{content.flow && (
<>
<dt>
<Icons.waves
className="text-primary"
{...propsForSVGPresentation}
/>
<span className="sr-only">{t('flow')}</span>
</dt>
<dd className="mr-2">{content.flow}</dd>
</>
)}
{content.type && (
<>
<dt>{content.type.category.label} :</dt>
<dd>
<Badge className="gap-2">
{content.type.pictogram && (
<Image
loading="lazy"
src={content.type.pictogram}
width={24}
height={24}
alt=""
/>
)}
<span>{content.type.label}</span>
</Badge>
</dd>
</>
)}
</dl>
<MetadataList
length={content.length}
descent={content.descent}
flow={content.flow}
type={content.type}
/>
</header>

<div dangerouslySetInnerHTML={{ __html: content.description }} />
Expand Down
92 changes: 49 additions & 43 deletions src/components/map/geometry-item.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { Fragment } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { Layer } from '@/api/settings';
import { GeoJsonProperties, Geometry } from 'geojson';
import { GeoJSONOptions } from 'leaflet';
import { GeoJSONOptions, PathOptions } from 'leaflet';
import { renderToStaticMarkup } from 'react-dom/server';
import {
Popup as LeafletPopup,
Marker,
Polygon,
Polyline,
Tooltip,
} from 'react-leaflet';
import { Marker, Polygon, Polyline } from 'react-leaflet';

import { cn } from '@/lib/utils';
import { Icons } from '@/components/icons';
import { DefaultMarker } from '@/components/map/default-marker';
import Popup from '@/components/map/popup';

import { GeometryTooltip } from './geometry-tooltip';

type Props = {
geometry: Geometry;
Expand All @@ -23,41 +20,15 @@ type Props = {
options: GeoJSONOptions;
};

const MetaData = ({
properties,
layer,
}: {
properties: GeoJsonProperties;
layer: Layer;
}) => {
if (properties === null || (!properties.name && !properties.category)) {
return null;
}
return (
<>
<Tooltip>{properties.name ?? properties.category}</Tooltip>
{layer.type !== undefined && layer.url && properties.id && (
<LeafletPopup>
<Popup
name={properties.name ?? properties.category}
description={properties.description}
attachments={properties.attachments}
type={layer.type}
id={properties.id}
/>
</LeafletPopup>
)}
</>
);
};

export const GeometryItem = ({
geometry,
properties,
id,
layer,
options = { style: {} },
}: Props) => {
const params = useSearchParams();
const router = useRouter();
if (geometry.type === 'GeometryCollection') {
return (
<>
Expand All @@ -75,6 +46,18 @@ export const GeometryItem = ({
);
}

const hasDetails = layer.type !== undefined && layer.url && properties?.id;

const featureEventHandler = {
...(hasDetails && {
click: () => {
router.push(
`/map/${layer?.type}/${properties?.id}?${params.toString()}`,
);
},
}),
};

if (geometry.type === 'Point' || geometry.type === 'MultiPoint') {
const coordinatesAsMultiPoint =
geometry.type === 'Point' ? [geometry.coordinates] : geometry.coordinates;
Expand All @@ -90,8 +73,9 @@ export const GeometryItem = ({
key={`point-${id}-${index}`}
position={[lng, lat]}
icon={DefaultMarker(icon, 1)}
eventHandlers={featureEventHandler}
>
<MetaData properties={properties} layer={layer} />
<GeometryTooltip properties={properties} layer={layer} />
</Marker>
);
})}
Expand Down Expand Up @@ -129,9 +113,17 @@ export const GeometryItem = ({
weight: 10,
opacity: 0,
}}
className={layer.type}
eventHandlers={{
mouseover: e => e.target.setStyle({ opacity: 0.5 }),
mouseout: e => e.target.setStyle({ opacity: 0 }),
...featureEventHandler,
}}
className={cn(
'streams-hover',
!hasDetails && '!cursor-[unset]',
)}
>
<MetaData properties={properties} layer={layer} />
<GeometryTooltip properties={properties} layer={layer} />
</Polyline>
</Fragment>
);
Expand All @@ -140,9 +132,10 @@ export const GeometryItem = ({
<Polyline
positions={group.map(([lat, lng]) => [lng, lat])}
pathOptions={options.style as GeoJSONOptions}
className={layer.type}
className={cn(layer.type, !hasDetails && '!cursor-[unset]')}
eventHandlers={featureEventHandler}
>
<MetaData properties={properties} layer={layer} />
<GeometryTooltip properties={properties} layer={layer} />
</Polyline>
);
})}
Expand All @@ -164,9 +157,22 @@ export const GeometryItem = ({
line.map<[number, number]>(([lat, lng]) => [lng, lat]),
)}
pathOptions={options.style as GeoJSONOptions}
eventHandlers={{
mouseover: e => e.target.setStyle({ fillOpacity: 0.8 }),
mouseout: e =>
e.target.setStyle({
fillOpacity:
(options.style as PathOptions)?.fillOpacity ?? 0.2,
}),
...featureEventHandler,
}}
className={cn(
'transition-[fill-opacity]',
!hasDetails && '!cursor-[unset]',
)}
pane="tilePane"
>
<MetaData properties={properties} layer={layer} />
<GeometryTooltip properties={properties} layer={layer} />
</Polygon>
))}
</>
Expand Down
58 changes: 58 additions & 0 deletions src/components/map/geometry-tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Image from 'next/image';
import { Layer } from '@/api/settings';
import { GeoJsonProperties } from 'geojson';
import { Tooltip } from 'react-leaflet';

import { MetadataList } from '../metadata-list';

export const GeometryTooltip = ({
properties,
layer,
}: {
properties: GeoJsonProperties;
layer: Layer;
}) => {
if (properties === null || (!properties.name && !properties.category)) {
return null;
}
if (layer.type === undefined || !layer.url || !properties.id) {
return <Tooltip>{properties.name ?? properties.category}</Tooltip>;
}
return (
<Tooltip
sticky
className="w-64 !overflow-hidden !whitespace-normal !rounded-xl !border-0 !p-0"
>
<div className="flex flex-col">
{properties.attachments?.[0]?.thumbnail && (
<Image
loading="lazy"
className="aspect-[4/3] h-auto w-auto object-cover transition-all group-hover:scale-105"
src={properties.attachments[0].thumbnail}
alt=""
width="400"
height="300"
/>
)}
<div className="p-4">
<h3 className="line-clamp-2 text-lg font-bold">
{properties.name ?? properties.category}
</h3>
<MetadataList
descent={properties.descent}
flow={properties.flow}
length={properties.length}
type={properties.type}
small
/>
{properties.description && (
<span
className="mb-1 line-clamp-2"
dangerouslySetInnerHTML={{ __html: properties.description }}
></span>
)}
</div>
</div>
</Tooltip>
);
};
60 changes: 0 additions & 60 deletions src/components/map/popup.tsx

This file was deleted.

Loading

0 comments on commit ef0c2d9

Please sign in to comment.