Merge pull request #178 from trails-cool/fix/leaflet-ssr

Fix Leaflet SSR error: use .client.tsx convention
This commit is contained in:
Ullrich Schäfer 2026-04-06 21:56:00 +01:00 committed by GitHub
commit 12fde4aa20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 30 additions and 32 deletions

View file

@ -0,0 +1,21 @@
import { useState, useEffect, type ComponentProps } from "react";
type MapProps = ComponentProps<typeof import("./RouteMapThumbnail.client").RouteMapThumbnail>;
export function ClientMap(props: MapProps) {
const [Component, setComponent] = useState<React.ComponentType<MapProps>>();
useEffect(() => {
import("./RouteMapThumbnail.client").then((m) => setComponent(() => m.RouteMapThumbnail));
}, []);
if (!Component) {
return (
<div className={`flex items-center justify-center bg-gray-100 text-gray-500 ${props.className ?? "h-36 w-full rounded"}`}>
Loading map...
</div>
);
}
return <Component {...props} />;
}

View file

@ -1,4 +1,3 @@
import { Suspense, lazy } from "react";
import { data, redirect } from "react-router";
import { useTranslation } from "react-i18next";
import type { Route } from "./+types/activities.$id";
@ -7,10 +6,7 @@ import { getActivity, deleteActivity, linkActivityToRoute, createRouteFromActivi
import { deleteImportByActivity } from "~/lib/sync/imports.server";
import { listRoutes } from "~/lib/routes.server";
import { ClientDate } from "~/components/ClientDate";
const RouteMapThumbnail = lazy(() =>
import("~/components/RouteMapThumbnail").then((m) => ({ default: m.RouteMapThumbnail })),
);
import { ClientMap } from "~/components/ClientMap";
export async function loader({ params, request }: Route.LoaderArgs) {
const activity = await getActivity(params.id);
@ -125,9 +121,7 @@ export default function ActivityDetailPage({ loaderData }: Route.ComponentProps)
{activity.geojson && (
<div className="mt-6 overflow-hidden rounded-lg border border-gray-200" style={{ height: 400 }}>
<Suspense fallback={<div className="flex h-full items-center justify-center bg-gray-100 text-gray-500">Loading map...</div>}>
<RouteMapThumbnail geojson={activity.geojson} interactive className="h-full w-full" />
</Suspense>
<ClientMap geojson={activity.geojson} interactive className="h-full w-full" />
</div>
)}

View file

@ -1,14 +1,10 @@
import { data, redirect } from "react-router";
import { Suspense, lazy } from "react";
import { useTranslation } from "react-i18next";
import type { Route } from "./+types/activities._index";
import { getSessionUser } from "~/lib/auth.server";
import { listActivities } from "~/lib/activities.server";
import { ClientDate } from "~/components/ClientDate";
const RouteMapThumbnail = lazy(() =>
import("~/components/RouteMapThumbnail").then((m) => ({ default: m.RouteMapThumbnail })),
);
import { ClientMap } from "~/components/ClientMap";
export async function loader({ request }: Route.LoaderArgs) {
const user = await getSessionUser(request);
@ -64,9 +60,7 @@ export default function ActivitiesListPage({ loaderData }: Route.ComponentProps)
<div className="flex gap-4">
<div className="w-48 shrink-0">
{activity.geojson ? (
<Suspense fallback={<div className="h-36 w-full animate-pulse rounded bg-gray-100" />}>
<RouteMapThumbnail geojson={activity.geojson} />
</Suspense>
<ClientMap geojson={activity.geojson} />
) : (
<div className="flex h-36 w-full items-center justify-center rounded bg-gray-100 text-xs text-gray-400">
{t("routes.noMapPreview")}

View file

@ -1,14 +1,11 @@
import { useState, useCallback, Suspense, lazy } from "react";
import { useState, useCallback } from "react";
import { data, redirect } from "react-router";
import { useTranslation } from "react-i18next";
import type { Route } from "./+types/routes.$id";
import { getSessionUser } from "~/lib/auth.server";
import { getRoute, getRouteWithVersions, deleteRoute, updateRoute } from "~/lib/routes.server";
import { ClientDate } from "~/components/ClientDate";
const RouteMapThumbnail = lazy(() =>
import("~/components/RouteMapThumbnail").then((m) => ({ default: m.RouteMapThumbnail })),
);
import { ClientMap } from "~/components/ClientMap";
export async function loader({ params, request }: Route.LoaderArgs) {
@ -161,9 +158,7 @@ export default function RouteDetailPage({ loaderData }: Route.ComponentProps) {
{route.geojson && (
<div className="mt-6 overflow-hidden rounded-lg border border-gray-200" style={{ height: 400 }}>
<Suspense fallback={<div className="flex h-full items-center justify-center bg-gray-100 text-gray-500">Loading map...</div>}>
<RouteMapThumbnail geojson={route.geojson} interactive className="h-full w-full" />
</Suspense>
<ClientMap geojson={route.geojson} interactive className="h-full w-full" />
</div>
)}

View file

@ -1,14 +1,10 @@
import { data, redirect } from "react-router";
import { Suspense, lazy } from "react";
import { useTranslation } from "react-i18next";
import type { Route } from "./+types/routes._index";
import { getSessionUser } from "~/lib/auth.server";
import { listRoutes } from "~/lib/routes.server";
import { ClientDate } from "~/components/ClientDate";
const RouteMapThumbnail = lazy(() =>
import("~/components/RouteMapThumbnail").then((m) => ({ default: m.RouteMapThumbnail })),
);
import { ClientMap } from "~/components/ClientMap";
export async function loader({ request }: Route.LoaderArgs) {
const user = await getSessionUser(request);
@ -62,9 +58,7 @@ export default function RoutesListPage({ loaderData }: Route.ComponentProps) {
<div className="flex gap-4">
<div className="w-48 shrink-0">
{route.geojson ? (
<Suspense fallback={<div className="h-36 w-full animate-pulse rounded bg-gray-100" />}>
<RouteMapThumbnail geojson={route.geojson} />
</Suspense>
<ClientMap geojson={route.geojson} />
) : (
<div className="flex h-36 w-full items-center justify-center rounded bg-gray-100 text-xs text-gray-400">
{t("routes.noMapPreview")}