Skip to content

Commit 44050a7

Browse files
Merge pull request #67 from Vizzuality/develop
Update staging
2 parents 918af38 + 8c1c4d4 commit 44050a7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1073
-474
lines changed

client/next.config.mjs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import createNextIntlPlugin from 'next-intl/plugin'
2-
1+
import createNextIntlPlugin from "next-intl/plugin";
32

43
const withNextIntl = createNextIntlPlugin();
54

@@ -11,6 +10,11 @@ const nextConfig = {
1110
protocol: "https",
1211
hostname: "api.mapbox.com",
1312
},
13+
{
14+
protocol: "https",
15+
hostname: "storage.googleapis.com",
16+
pathname: "/rdp-landing-bucket/**",
17+
},
1418
],
1519
},
1620
webpack(config) {

client/src/app/[locale]/layout.tsx

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import "./globals.css";
22
import "mapbox-gl/dist/mapbox-gl.css";
33

4+
import localFont from "next/font/local";
5+
46
import { getTranslations } from "@/i18n";
57
import { getMessages } from "next-intl/server";
68
import LayoutProviders from "./layout-providers";
79
import NextIntlProvider from "@/components/next-intl-provider";
810
import Header from "@/containers/header";
9-
11+
// import { w } from "next/font/google"
1012
export async function generateMetadata({ params: { locale } }: { params: { locale: string } }) {
1113
const t = await getTranslations({ locale });
1214

@@ -18,6 +20,12 @@ export async function generateMetadata({ params: { locale } }: { params: { local
1820
};
1921
}
2022

23+
// Font files can be colocated inside of `app`
24+
const wotfard = localFont({
25+
src: "../../assets/fonts/wotfard-regular-webfont.woff2",
26+
display: "swap",
27+
});
28+
2129
export default async function LocaleLayout({
2230
children,
2331
params: { locale },
@@ -29,9 +37,9 @@ export default async function LocaleLayout({
2937

3038
return (
3139
<LayoutProviders>
32-
<html lang={locale}>
40+
<html lang={locale} className={wotfard.className}>
3341
<NextIntlProvider locale={locale} messages={messages}>
34-
<body className="flex h-[100svh] flex-col overflow-y-hidden">
42+
<body className="flex flex-col">
3543
<Header />
3644
<div className="flex-1">{children}</div>
3745
</body>

client/src/app/[locale]/map/page.tsx

+32-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,40 @@
11
import Datasets from "@/containers/datasets";
22
import Map from "@/containers/map";
33
import Sidebar from "@/containers/sidebar";
4+
import getQueryClient from "@/lib/react-query/getQueryClient";
5+
import { getGetDatasetsQueryOptions } from "@/types/generated/dataset";
6+
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
7+
8+
async function prefetchQueries() {
9+
const queryClient = getQueryClient();
10+
try {
11+
const { queryKey, queryFn } = getGetDatasetsQueryOptions({
12+
populate: ["layers", "layers.layer", "sources", "citations"],
13+
sort: "id:asc",
14+
locale: "all",
15+
});
16+
17+
await queryClient.prefetchQuery({
18+
queryKey,
19+
queryFn,
20+
});
21+
return dehydrate(queryClient);
22+
} catch (error) {
23+
console.info(error);
24+
return null;
25+
}
26+
}
427

528
export default async function Home() {
29+
const dehydratedState = await prefetchQueries();
630
return (
7-
// The map is a client component, so it needs to be wrapped in the NextIntlClientProvider to provide the translations
8-
<div className="flex">
9-
<Sidebar>
10-
<Datasets />
11-
</Sidebar>
12-
<Map />
13-
</div>
31+
<HydrationBoundary state={dehydratedState}>
32+
<div className="flex h-[var(--content-height)] w-full overflow-y-hidden">
33+
<Sidebar>
34+
<Datasets />
35+
</Sidebar>
36+
<Map />
37+
</div>
38+
</HydrationBoundary>
1439
);
1540
}

client/src/app/[locale]/page.tsx

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { useTranslations } from "@/i18n";
1+
import Footer from "@/containers/footer";
2+
import HomeComponent from "@/containers/home";
23

34
export default function Home() {
4-
const t = useTranslations();
55
return (
6-
<main className="flex min-h-screen flex-col items-center justify-between p-24">
7-
<div>{t("Rangelands Data Platform")}</div>
8-
<div>{t("Exploring Rangelands")}</div>
9-
<div>{t("Test string")}</div>
6+
<main className="h-auto min-h-screen w-[100vsw] overflow-x-hidden">
7+
<HomeComponent />
8+
<Footer />
109
</main>
1110
);
1211
}
Binary file not shown.

client/src/assets/images/gmv-logo.png

10.7 KB
Loading

client/src/assets/images/map.png

355 KB
Loading
Loading
Loading
278 KB
Loading
1.94 KB
Loading

client/src/components/map/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export const Map: FC<CustomMapProps> = ({
132132
}, [bounds, isFlying]);
133133

134134
return (
135-
<div className={cn("absolute left-0 top-0 z-0 h-full w-full", className)}>
135+
<div className={cn("absolute bottom-0 left-0 z-0 h-[var(--content-height)] w-full", className)}>
136136
<ReactMapGL
137137
id={id}
138138
initialViewState={initialViewState}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { MVTLayer } from "@deck.gl/geo-layers";
2+
import { useDeckMapboxOverlayContext } from "../../provider";
3+
import { env } from "@/env.mjs";
4+
import { useEffect, useMemo, useState } from "react";
5+
6+
export interface RangelandsLayerComponentProps {
7+
id: string;
8+
data: string;
9+
opacity?: number;
10+
visibility?: boolean;
11+
colorProperty: string;
12+
lineWidth?: number;
13+
}
14+
15+
const RangelandsLayerComponent = ({
16+
id,
17+
data,
18+
opacity,
19+
visibility,
20+
colorProperty,
21+
lineWidth = 1,
22+
...props
23+
}: RangelandsLayerComponentProps) => {
24+
const dataWithMapboxToken = data + `?access_token=${env.NEXT_PUBLIC_MAPBOX_TOKEN}`;
25+
const [hoveredProperty, setHoveredProperty] = useState(null);
26+
const i = `${id}-deck`;
27+
const { addLayer, removeLayer } = useDeckMapboxOverlayContext();
28+
const config = useMemo(
29+
() =>
30+
new MVTLayer({
31+
id: i,
32+
data: dataWithMapboxToken,
33+
opacity: opacity ?? 1,
34+
visible: visibility ?? true,
35+
pickable: true,
36+
onHover: (info) => {
37+
setHoveredProperty(info?.object?.properties?.[colorProperty]);
38+
},
39+
getLineWidth: (f) => {
40+
return f?.properties?.[colorProperty] === hoveredProperty ? lineWidth : 0;
41+
},
42+
lineWidthUnits: "pixels",
43+
getLineColor: [255, 255, 255],
44+
updateTriggers: {
45+
getLineWidth: hoveredProperty,
46+
},
47+
...props,
48+
}),
49+
[id, dataWithMapboxToken, opacity, visibility, props],
50+
);
51+
52+
useEffect(() => {
53+
if (!config) return;
54+
// Give the map a chance to load the background layer before adding the Deck layer
55+
setTimeout(() => {
56+
// https://github.com/visgl/deck.gl/blob/c2ba79b08b0ea807c6779d8fe1aaa307ebc22f91/modules/mapbox/src/resolve-layers.ts#L66
57+
addLayer(config);
58+
}, 10);
59+
}, [i, id, config, addLayer]);
60+
61+
useEffect(() => {
62+
if (!config) return;
63+
return () => {
64+
removeLayer(i);
65+
};
66+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
67+
68+
return null;
69+
};
70+
71+
export default RangelandsLayerComponent;

client/src/components/map/layers/deck-layer/raster.tsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { LayerProps } from "@/types/layers";
77

88
export interface RasterLayerProps extends LayerProps {
99
id: string;
10+
beforeId: string;
1011
source: RasterSource;
1112
opacity: number;
1213
visibility: boolean;
@@ -15,14 +16,25 @@ export interface RasterLayerProps extends LayerProps {
1516
}
1617

1718
class RasterLayer {
18-
constructor({ id, source, visibility, opacity, tileProps, bitmapProps }: RasterLayerProps) {
19+
constructor({
20+
id,
21+
source,
22+
visibility,
23+
opacity,
24+
beforeId,
25+
tileProps,
26+
bitmapProps,
27+
}: RasterLayerProps) {
1928
return new TileLayer<unknown>({
2029
...tileProps,
2130
id,
31+
// @ts-expect-error - `beforeId` is not a valid prop for TileLayer
32+
beforeId,
2233
data: source.tiles,
2334
tileSize: source.tileSize ?? 256,
2435
minZoom: source.minzoom,
2536
maxZoom: source.maxzoom,
37+
year: 2020,
2638
visible: visibility ?? true,
2739
opacity: opacity ?? 1,
2840
refinementStrategy: "never",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from "react";
2+
3+
import { LegendComponent } from "../../types";
4+
5+
type LegendComponentProps = {
6+
items: LegendComponent["items"];
7+
};
8+
9+
export const LegendChoropleth: React.FC<LegendComponentProps> = ({ items }) => {
10+
return (
11+
<div>
12+
<ul className="flex w-full overflow-hidden rounded-full">
13+
{items.map(({ color }) => (
14+
<li
15+
key={`${color}`}
16+
className="h-2 flex-shrink-0"
17+
style={{
18+
width: `${100 / items.length}%`,
19+
backgroundColor: color,
20+
}}
21+
/>
22+
))}
23+
</ul>
24+
25+
<ul className="mt-1 flex w-full">
26+
{items.map(({ name }) => (
27+
<li
28+
key={`${name}`}
29+
className="flex-shrink-0 text-center text-xs"
30+
style={{
31+
width: `${100 / items.length}%`,
32+
}}
33+
>
34+
{name}
35+
</li>
36+
))}
37+
</ul>
38+
</div>
39+
);
40+
};
41+
42+
export default LegendChoropleth;

client/src/components/map/legends/content/gradient.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const GradientLegend = ({ items }: LegendComponentProps) => {
99
return (
1010
<div>
1111
<div
12-
className="flex h-3 w-full rounded-full"
12+
className="flex h-2 w-full rounded-full"
1313
style={{
1414
backgroundImage: `linear-gradient(to right, ${items.map((i) => i.color).join(",")})`,
1515
}}

client/src/components/map/legends/header/index.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { ChevronDown } from "lucide-react";
12
import { LayerInfo, LayerOpacity, LayerVisibility } from "./buttons";
3+
import { Button } from "@/components/ui/button";
24

35
type LegendHeaderProps = {
46
title?: string;
@@ -8,6 +10,7 @@ type LegendHeaderProps = {
810
setVisibility: (v: boolean) => void;
911
visible: boolean;
1012
info?: string;
13+
handleChangeIsOpen: () => void;
1114
};
1215

1316
const LegendHeader = ({
@@ -18,6 +21,7 @@ const LegendHeader = ({
1821
info,
1922
opacity,
2023
visible,
24+
handleChangeIsOpen,
2125
}: LegendHeaderProps) => {
2226
return (
2327
<div>
@@ -26,6 +30,9 @@ const LegendHeader = ({
2630
<LayerOpacity onChangeOpacity={setOpacity} opacity={opacity} />
2731
{!!info && <LayerInfo info={info} title={title} />}
2832
<LayerVisibility onChangeVisibility={setVisibility} visible={visible} />
33+
<Button onClick={handleChangeIsOpen} variant="link" className="h-fit px-0 py-0">
34+
<ChevronDown className="h-5 w-5 shrink-0 group-data-[state=open]:rotate-180" />
35+
</Button>
2936
</div>
3037
{subtitle && <span className="text-xs">{subtitle}</span>}
3138
</div>

client/src/components/map/legends/index.tsx

-20
This file was deleted.

client/src/components/map/tooltip/components/index.css

-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,4 @@
22
background-color: transparent;
33
padding: 0;
44
border-radius: theme("borderRadius.lg");
5-
box-shadow: theme("boxShadow.lg");
6-
}
7-
.mapboxgl-popup-close-button {
8-
display: none;
95
}

client/src/components/map/tooltip/components/rangelands.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const RangelandsTooltip = (props: MapTooltipProps) => {
7777
}, []);
7878

7979
return (
80-
<div className="overflow-hidden rounded-lg bg-background">
80+
<div className="overflow-hidden rounded-lg bg-background drop-shadow-2xl">
8181
<div className="border-t-[12px]" style={{ borderColor: content.color }}></div>
8282
<div className="space-y-4 p-6 pt-3">
8383
<div className="space-y-2">

0 commit comments

Comments
 (0)