feat(contact-page): implement contact page with dynamic content and map integration
This commit is contained in:
@@ -11,7 +11,31 @@ import {
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import type { LayerGroup, Map as LeafletMap, LatLngBounds, LatLngTuple } from 'leaflet';
|
||||
import type { LayerGroup, Map as LeafletMap, LatLngBounds, LatLngTuple, TileLayer } from 'leaflet';
|
||||
|
||||
export type MapStyle = 'minimal-light' | 'standard';
|
||||
|
||||
const MAP_LAYERS: Record<
|
||||
MapStyle,
|
||||
{
|
||||
url: string;
|
||||
attribution: string;
|
||||
maxZoom: number;
|
||||
}
|
||||
> = {
|
||||
'minimal-light': {
|
||||
url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
||||
maxZoom: 20,
|
||||
},
|
||||
standard: {
|
||||
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
maxZoom: 19,
|
||||
},
|
||||
};
|
||||
|
||||
export interface MapLocation {
|
||||
id: string | number;
|
||||
@@ -32,12 +56,15 @@ export class LocationMapComponent implements AfterViewInit, OnChanges, OnDestroy
|
||||
@Input() fallbackCenter: LatLngTuple = [-32.94682, -60.63932];
|
||||
@Input() fallbackZoom = 13;
|
||||
@Input() maxFitZoom = 15;
|
||||
@Input() mapStyle: MapStyle = 'minimal-light';
|
||||
@Input() markerColor = '#24a9e0';
|
||||
|
||||
@ViewChild('mapContainer', { static: true })
|
||||
private readonly mapContainer!: ElementRef<HTMLDivElement>;
|
||||
|
||||
private leaflet: typeof import('leaflet') | null = null;
|
||||
private map: LeafletMap | null = null;
|
||||
private baseLayer: TileLayer | null = null;
|
||||
private markerLayer: LayerGroup | null = null;
|
||||
|
||||
constructor(
|
||||
@@ -52,7 +79,11 @@ export class LocationMapComponent implements AfterViewInit, OnChanges, OnDestroy
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['locations'] && this.map) {
|
||||
if (changes['mapStyle'] && this.map) {
|
||||
this.renderBaseLayer();
|
||||
}
|
||||
|
||||
if ((changes['locations'] || changes['markerColor']) && this.map) {
|
||||
this.renderLocations();
|
||||
}
|
||||
}
|
||||
@@ -60,6 +91,7 @@ export class LocationMapComponent implements AfterViewInit, OnChanges, OnDestroy
|
||||
ngOnDestroy(): void {
|
||||
this.map?.remove();
|
||||
this.map = null;
|
||||
this.baseLayer = null;
|
||||
this.markerLayer = null;
|
||||
}
|
||||
|
||||
@@ -88,17 +120,30 @@ export class LocationMapComponent implements AfterViewInit, OnChanges, OnDestroy
|
||||
scrollWheelZoom: false,
|
||||
});
|
||||
|
||||
leaflet
|
||||
.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© OpenStreetMap contributors',
|
||||
})
|
||||
.addTo(this.map);
|
||||
|
||||
this.renderBaseLayer();
|
||||
this.markerLayer = leaflet.layerGroup().addTo(this.map);
|
||||
this.renderLocations();
|
||||
}
|
||||
|
||||
private renderBaseLayer(): void {
|
||||
if (!this.leaflet || !this.map) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.baseLayer) {
|
||||
this.map.removeLayer(this.baseLayer);
|
||||
}
|
||||
|
||||
const layer = MAP_LAYERS[this.mapStyle];
|
||||
this.baseLayer = this.leaflet
|
||||
.tileLayer(layer.url, {
|
||||
maxZoom: layer.maxZoom,
|
||||
attribution: layer.attribution,
|
||||
crossOrigin: true,
|
||||
})
|
||||
.addTo(this.map);
|
||||
}
|
||||
|
||||
private renderLocations(): void {
|
||||
if (!this.leaflet || !this.map || !this.markerLayer) {
|
||||
return;
|
||||
@@ -152,7 +197,7 @@ export class LocationMapComponent implements AfterViewInit, OnChanges, OnDestroy
|
||||
radius: 8,
|
||||
color: '#ffffff',
|
||||
weight: 3,
|
||||
fillColor: '#24a9e0',
|
||||
fillColor: this.markerColor,
|
||||
fillOpacity: 1,
|
||||
})
|
||||
.bindTooltip(tooltip)
|
||||
|
||||
Reference in New Issue
Block a user