Skip to content

Commit

Permalink
feat: replace big map with leaflet
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Patek committed Feb 7, 2025
1 parent 20004e6 commit 10c8c4f
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 94 deletions.
74 changes: 0 additions & 74 deletions app/(with-navbar)/mapa/Map.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion app/(with-navbar)/mapa/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const Loading = () => {
return <div className="flex justify-center items-stretch flex-grow h-[calc(100vh-66px)] md:h-[calc(100vh-70px)] skeleton rounded-none"></div>;
return <div className="flex justify-center items-stretch flex-grow h-[calc(100dvh-66px)] md:h-[calc(100dvh-69px)] skeleton rounded-none"></div>;
};

export default Loading;
19 changes: 5 additions & 14 deletions app/(with-navbar)/mapa/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import { Metadata } from "next";

import { getAllUserFavouritesIds } from "@/actions/favourites/favourites.action";
import { getAllTowers } from "@/actions/towers/towers.action";
import Map from "./Map";
import { getAllUserVisits } from "@/actions/visits/visits.action";
import MainMap from "@/components/shared/map/Map";

export const metadata: Metadata = {
title: "Mapa",
};

// every 1 hour new towers
export const revalidate = 3600;

async function MapPage() {
const towers = await getAllTowers();
const favouriteTowersIds = await getAllUserFavouritesIds();
const visits = await getAllUserVisits();
towers.forEach((tower) => {
tower.isFavourite = favouriteTowersIds.includes(tower.id);
tower.isVisited = visits.some((visit) => visit.tower_id === tower.id);
});
const [towers, favouriteTowersIds, visits] = await Promise.all([getAllTowers(), getAllUserFavouritesIds(), getAllUserVisits()]);

return (
<div className="flex justify-center items-stretch flex-grow h-[calc(100vh-66px)] md:h-[calc(100vh-70px)]">
<Map lat={49.8237572} long={15.6086383} name="Rozhlednový svět" towers={towers} />
<div className="flex justify-center items-stretch flex-grow h-[calc(100dvh-66px)] md:h-[calc(100dvh-69px)]">
<MainMap towers={towers} visits={visits} favourites={favouriteTowersIds} />
</div>
);
}
Expand Down
12 changes: 7 additions & 5 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
@tailwind components;
@tailwind utilities;

#big_map > div > div.card {
width: auto !important;
.leaflet-popup-content-wrapper {
padding: 0 !important;
overflow: hidden;
}

#big_map > div > div.card > div.card-body {
display: none !important;
.leaflet-popup-content {
margin: 0 !important;
width: 100% !important;
}

.content {
max-width: 1280px;
margin: 0 auto;
padding: 0 10px;
}
}
27 changes: 27 additions & 0 deletions components/shared/map/MainMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import { Tower } from "@/types/Tower";
import { Visit } from "@/types/Visit";
import { MapContainer, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet/dist/images/marker-shadow.png";
import TowerMarker from "@/components/shared/map/TowerMarker";

const MainMap = ({ towers, visits, favourites }: { towers: Tower[]; visits: Visit[]; favourites: string[] }) => {
return (
<MapContainer center={[49.8237572, 15.6086383]} zoom={8} scrollWheelZoom={true} className="w-full h-full z-0">
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{towers.map((tower) => {
const isVisited = visits.some((visit) => visit.tower_id === tower.id);
const isFavourite = favourites.includes(tower.id);

return <TowerMarker key={tower.id} tower={tower} isFavourite={isFavourite} isVisited={isVisited} />;
})}
</MapContainer>
);
};

export default MainMap;
7 changes: 7 additions & 0 deletions components/shared/map/Map.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use client";

import dynamic from "next/dynamic";

const MainMap = dynamic(() => import("@/components/shared/map/MainMap"), { ssr: false });

export default MainMap;
111 changes: 111 additions & 0 deletions components/shared/map/MapTowerCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { Tower } from "@/types/Tower";
import { cn } from "@/utils/cn";
import { formatDateYear } from "@/utils/date";
import { getOpeningHoursStateAndShortText } from "@/utils/openingHours";
import Image from "next/image";
import Link from "next/link";

const MapTowerCard = ({ tower, isFavourite = false, isVisited = false }: { tower: Tower; isFavourite?: boolean; isVisited?: boolean }) => {
const [state, openingHoursText] = getOpeningHoursStateAndShortText(tower.openingHours);
return (
<Link href={`/${tower.type || "rozhledna"}/${tower.nameID}`} scroll>
<div className="card card-compact cursor-pointer w-[225px] rounded-none">
<figure className="object-cover inline-block relative h-72">
<Image
src={tower.mainPhotoUrl}
alt={tower.name}
fill
priority={false}
className="object-cover object-top block"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 25vw"
unoptimized
/>

<div className="absolute top-0 left-3 flex gap-2">
{isVisited ? (
<span className="bg-white p-1 rounded-b-full" title="Navštíveno">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#1dad44"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0" />
<path d="m9 10 2 2 4-4" />
</svg>
</span>
) : null}
{isFavourite ? (
<span className="bg-white p-1 rounded-b-full" title="V oblíbených">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#F9BC0D"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z" />
</svg>
</span>
) : null}
</div>

{tower.opened ? (
<span
className={cn(
"badge badge-sm lg:badge-md absolute bottom-7 lg:bottom-8 right-2 text-white font-bold bg-black bg-opacity-50 border-white",
{
"bottom-2 lg:bottom-2": openingHoursText === "",
}
)}
>
{formatDateYear({ date: tower.opened })}
</span>
) : null}

{openingHoursText !== "" ? (
<div
className={cn("badge badge-sm lg:badge-md absolute bottom-2 right-2 font-bold border-white", {
"badge-success": state === true,
"badge-error": state === false,
})}
>
{openingHoursText}
</div>
) : null}
</figure>

<div className="card-body !py-3 !px-3 gap-0">
<h2 className="card-title whitespace-nowrap overflow-hidden overflow-ellipsis block text-xl text-black">{tower.name}</h2>
{/* <div className="flex items-center gap-2">
<ThemedRating size={20} value={avg} />
<div className="text-base text-gray-400 mt-0.5">{count}x</div>
</div> */}
<div className="flex justify-between items-center mt-2">
<div className="flex-row flex items-center">
<svg viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" className="w-5">
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g fill="#000000" transform="translate(106.666667, 42.666667)">
<path d="M149.333333,7.10542736e-15 C231.807856,7.10542736e-15 298.666667,66.8588107 298.666667,149.333333 C298.666667,176.537017 291.413333,202.026667 278.683512,224.008666 C270.196964,238.663333 227.080238,313.32711 149.333333,448 C71.5864284,313.32711 28.4697022,238.663333 19.9831547,224.008666 C7.25333333,202.026667 2.84217094e-14,176.537017 2.84217094e-14,149.333333 C2.84217094e-14,66.8588107 66.8588107,7.10542736e-15 149.333333,7.10542736e-15 Z M149.333333,85.3333333 C113.987109,85.3333333 85.3333333,113.987109 85.3333333,149.333333 C85.3333333,184.679557 113.987109,213.333333 149.333333,213.333333 C184.679557,213.333333 213.333333,184.679557 213.333333,149.333333 C213.333333,113.987109 184.679557,85.3333333 149.333333,85.3333333 Z"></path>
</g>
</g>
</svg>
<div className="ml-0.5 md:ml-1 text-base text-black">{tower.county}</div>
</div>
</div>
</div>
</div>
</Link>
);
};

export default MapTowerCard;
18 changes: 18 additions & 0 deletions components/shared/map/TowerMarker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defaultIcon, favouriteIcon, visitedIcon } from "@/components/shared/map/icons";
import MapTowerCard from "@/components/shared/map/MapTowerCard";
import { Tower } from "@/types/Tower";
import { Marker, Popup } from "react-leaflet";

const TowerMarker = ({ tower, isFavourite, isVisited }: { tower: Tower; isFavourite?: boolean; isVisited?: boolean }) => {
const icon = isVisited ? visitedIcon : isFavourite ? favouriteIcon : defaultIcon;

return (
<Marker key={tower.id} position={[tower.gps.latitude, tower.gps.longitude]} icon={icon} title={tower.name}>
<Popup closeButton={false}>
<MapTowerCard tower={tower} isFavourite={isFavourite} isVisited={isVisited} />
</Popup>
</Marker>
);
};

export default TowerMarker;
28 changes: 28 additions & 0 deletions components/shared/map/icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import L from "leaflet";

export const defaultIcon = L.icon({
iconUrl: "/img/marker_red.png",
shadowUrl: "/img/marker-shadow.png",
iconSize: [23, 32],
iconAnchor: [11, 32],
shadowSize: [41, 41],
shadowAnchor: [13, 41],
});

export const visitedIcon = L.icon({
iconUrl: "/img/marker_green.png",
shadowUrl: "/img/marker-shadow.png",
iconSize: [23, 32],
iconAnchor: [11, 32],
shadowSize: [41, 41],
shadowAnchor: [13, 41],
});

export const favouriteIcon = L.icon({
iconUrl: "/img/marker_yellow.png",
shadowUrl: "/img/marker-shadow.png",
iconSize: [23, 32],
iconAnchor: [11, 32],
shadowSize: [41, 41],
shadowAnchor: [13, 41],
});

0 comments on commit 10c8c4f

Please sign in to comment.