Skip to content

Commit

Permalink
Merge pull request #54 from Vizzuality/develop
Browse files Browse the repository at this point in the history
Update staging with develop
  • Loading branch information
barbara-chaves authored Jun 25, 2024
2 parents 68c614c + f792264 commit b72d0e0
Show file tree
Hide file tree
Showing 83 changed files with 10,508 additions and 364 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ jobs:
run: |
echo 'Installing the Transifex CLI…'
curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash -s -- v1.6.13
echo 'Reload profile'
. ~/.bashrc
echo 'Pushing the source strings…'
npx txjs-cli push ./src --token=${{ env.TRANSIFEX_TOKEN }} --secret=${{ env.TRANSIFEX_SECRET }}
npx --yes @transifex/cli push ./src --token=${{ env.TRANSIFEX_TOKEN }} --secret=${{ env.TRANSIFEX_SECRET }}
- name: Build and Deploy
if: ${{ steps.applicable_check.outputs.flag }}
Expand Down
9 changes: 9 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,20 @@
"@loaders.gl/csv": "^4.2.2",
"@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.7",
"@svgr/webpack": "^8.1.0",
"@t3-oss/env-core": "^0.10.1",
"@tailwindcss/line-clamp": "^0.4.4",
"@tanstack/react-query": "^5.40.1",
"@transifex/native": "^7.1.0",
"@typescript-eslint/eslint-plugin": "^7.10.0",
Expand All @@ -42,6 +46,7 @@
"deck.gl": "^9.0.17",
"express": "^4.19.2",
"jotai": "^2.8.2",
"lodash-es": "^4.17.21",
"lucide-react": "^0.378.0",
"mapbox-gl": "^3.3.0",
"next": "14.2.3",
Expand All @@ -54,6 +59,9 @@
"react": "^18",
"react-dom": "^18",
"react-map-gl": "^7.1.7",
"react-markdown": "^9.0.1",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.0",
"rooks": "^7.14.1",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
Expand All @@ -63,6 +71,7 @@
"@types/color": "^3.0.6",
"@types/d3-dsv": "^3",
"@types/express": "^4",
"@types/lodash-es": "^4",
"@types/mapbox-gl": "^3",
"@types/node": "^20",
"@types/react": "^18",
Expand Down
2 changes: 2 additions & 0 deletions client/src/app/[locale]/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
--foreground-rgb: 33 31 77;
--background-rgb: 250 255 246;
--global-rgb: 235 135 49;
--header-height: 78px;
--content-height: calc(100vh - var(--header-height));
}

body {
Expand Down
7 changes: 6 additions & 1 deletion client/src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import "./globals.css";
import "mapbox-gl/dist/mapbox-gl.css";

import { getTranslations } from "@/i18n";
import { getMessages } from "next-intl/server";
import LayoutProviders from "./layout-providers";
import NextIntlProvider from "@/components/next-intl-provider";
import Header from "@/containers/header";

export async function generateMetadata({ params: { locale } }: { params: { locale: string } }) {
const t = await getTranslations({ locale });
Expand All @@ -29,7 +31,10 @@ export default async function LocaleLayout({
<LayoutProviders>
<html lang={locale}>
<NextIntlProvider locale={locale} messages={messages}>
<body>{children}</body>
<body className="flex h-[100svh] flex-col overflow-y-hidden">
<Header />
<div className="flex-1">{children}</div>
</body>
</NextIntlProvider>
</html>
</LayoutProviders>
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/[locale]/map/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Sidebar from "@/containers/sidebar";
export default async function Home() {
return (
// The map is a client component, so it needs to be wrapped in the NextIntlClientProvider to provide the translations
<div className="h-[100svh] overflow-y-hidden">
<div className="flex">
<Sidebar>
<Datasets />
</Sidebar>
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/map/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export const Map: FC<CustomMapProps> = ({
}, [bounds, isFlying]);

return (
<div className={cn("relative z-0 h-full w-full", className)}>
<div className={cn("absolute left-0 top-0 z-0 h-full w-full", className)}>
<ReactMapGL
id={id}
initialViewState={initialViewState}
Expand Down
21 changes: 21 additions & 0 deletions client/src/components/map/legends/content/basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import CircleLegend from "@/components/ui/circle-legend";
import { LegendComponent } from "../../types";

type LegendComponentProps = {
items: LegendComponent["items"];
};

const BasicLegend = ({ items }: LegendComponentProps) => {
return (
<ul className="space-y-2">
{items?.map((i) => (
<li key={i.name} className="flex gap-4">
{!!i.color && <CircleLegend colors={[i.color]} />}
<span className="text-xs font-light">{i.name}</span>
</li>
))}
</ul>
);
};

export default BasicLegend;
35 changes: 35 additions & 0 deletions client/src/components/map/legends/content/gradient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { LegendComponent } from "../../types";
import { cn } from "@/lib/utils";

type LegendComponentProps = {
items: LegendComponent["items"];
};

const GradientLegend = ({ items }: LegendComponentProps) => {
return (
<div>
<div
className="flex h-3 w-full rounded-full"
style={{
backgroundImage: `linear-gradient(to right, ${items.map((i) => i.color).join(",")})`,
}}
/>
<ul className="mt-1 flex w-full justify-between">
{items
.filter(({ name }) => typeof name !== "undefined" && name !== null)
.map(({ name }) => (
<li
key={`${name}`}
className={cn({
"flex-shrink-0 text-xs font-light text-foreground": true,
})}
>
{name}
</li>
))}
</ul>
</div>
);
};

export default GradientLegend;
106 changes: 106 additions & 0 deletions client/src/components/map/legends/content/rangeland.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"use client";
import { useMemo } from "react";
import { LegendComponent } from "../../types";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import CircleLegend from "@/components/ui/circle-legend";
import { ChevronDownIcon } from "lucide-react";
import { RANGELAND_BIOMES, RANGELAND_ECOREGIONS } from "@/containers/datasets/constants";
import { useGetRangelands } from "@/types/generated/rangeland";
import { useSyncRangelandRegions, useSyncRangelandType } from "@/store/map";
import { useTranslations } from "@/i18n";
import { useGetLocalizedList } from "@/lib/localized-query";

const RangelandLegend = () => {
const t = useTranslations();
const [rangelandType] = useSyncRangelandType();
const [rangelandRegions] = useSyncRangelandRegions();

const rangelandsQuery = useGetRangelands({
populate: "*",
sort: "title:asc",
locale: "all",
});

const { data: rangelandsData } = useGetLocalizedList(rangelandsQuery);

const items = useMemo((): LegendComponent["items"] => {
const biomes =
rangelandType === RANGELAND_BIOMES && !!rangelandRegions?.length
? rangelandsData?.data?.filter((rd) => rangelandRegions.includes(`${rd?.attributes?.code}`))
: rangelandsData?.data;

const biomesItems = biomes?.map((rd) => {
const ecoregions =
rangelandType === RANGELAND_ECOREGIONS
? !!rangelandRegions?.length
? rd?.attributes?.ecoregions?.data?.filter((rd) =>
rangelandRegions.includes(`${rd?.attributes?.code}`),
)
: rd?.attributes?.ecoregions?.data
: [];
return {
name: rd?.attributes?.title,
color: rd?.attributes?.color,
items: ecoregions?.map((e) => ({
name: e?.attributes?.title,
color: e?.attributes?.color,
})),
};
});

return biomesItems
? rangelandType === RANGELAND_BIOMES
? biomesItems
: biomesItems.filter((i) => !!i.items?.length)
: [];
}, [rangelandRegions, rangelandsData, rangelandType]);

const subtitle = useMemo(() => {
if (rangelandType === RANGELAND_BIOMES) {
return t("Types");
}
if (rangelandType === RANGELAND_ECOREGIONS) {
return t("Ecoregions");
}
}, [rangelandType]);

return (
<div className="space-y-2">
{!!subtitle && <p className="text-xs">{subtitle}</p>}
<ul className="space-y-2">
{items?.map((i) => (
<li key={i.name} className="flex gap-4">
{i.items?.length ? (
<Collapsible>
<CollapsibleTrigger className="group flex gap-2.5">
<ChevronDownIcon className="h-4 w-4 flex-shrink-0 opacity-50 group-data-[state=open]:rotate-180" />
{!!i.color && <CircleLegend className="h-3.5 w-3.5" colors={[i.color]} />}
<span className="text-start text-xs font-light">{i.name}</span>
</CollapsibleTrigger>
<CollapsibleContent asChild>
<ul className="space-y-1.5 pl-12 pt-2">
{i.items.map((subItem) => (
<li key={subItem.name} className="flex gap-2.5">
{!!subItem.color && (
<CircleLegend className="h-3.5 w-3.5" colors={[subItem.color]} />
)}
<span className="text-xs font-light">{subItem.name}</span>
</li>
))}
</ul>
</CollapsibleContent>
</Collapsible>
) : (
<>
{!!i.color && <CircleLegend colors={[i.color]} />}
<span className="text-xs font-light">{i.name}</span>
</>
)}
</li>
))}
</ul>
</div>
);
};

export default RangelandLegend;
69 changes: 69 additions & 0 deletions client/src/components/map/legends/header/buttons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Toggle } from "@/components/ui/toggle";
import { CircleHelpIcon } from "lucide-react";
import OpacityIcon from "@/svgs/opacity.svg";
import Slider from "@/components/ui/slider";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "@/components/ui/dialog";
import EyeOffIcon from "@/svgs/eye-off.svg";
import EyeIcon from "@/svgs/eye.svg";
import { ReactNode } from "react";
import { DialogProps } from "@radix-ui/react-dialog";

type LayerVisibilityProps = {
onChangeVisibility: (v: boolean) => void;
visible?: boolean;
};
const LayerVisibility = ({ onChangeVisibility, visible }: LayerVisibilityProps) => {
return (
<Toggle className="group h-min px-0" onPressedChange={onChangeVisibility} pressed={visible}>
<EyeIcon className="h-5 w-5 fill-foreground group-data-[state=off]:hidden" />
<EyeOffIcon className="h-5 w-5 fill-foreground group-data-[state=on]:hidden" />
</Toggle>
);
};

type LayerOpacityProps = {
opacity?: number;
onChangeOpacity: (o: number) => void;
};
const LayerOpacity = ({ opacity = 1, onChangeOpacity }: LayerOpacityProps) => (
<Popover>
<PopoverTrigger className="h-min">
<OpacityIcon
style={{
opacity: opacity + 0.2,
}}
className="h-5 w-5 fill-foreground stroke-1"
/>
</PopoverTrigger>
<PopoverContent side="top" sideOffset={8} className="w-20 bg-background p-3">
<Slider
value={[opacity]}
onValueChange={(v) => onChangeOpacity(v[0])}
aria-label="Opacity"
min={0}
max={1}
step={0.01}
/>
</PopoverContent>
</Popover>
);

type LayerInfoProps = DialogProps & {
info?: ReactNode;
title?: string;
};

const LayerInfo = ({ info, title, ...props }: LayerInfoProps) => (
<Dialog {...props}>
<DialogTrigger disabled={!info} className="h-min">
<CircleHelpIcon className="h-5 w-5 stroke-foreground" />
</DialogTrigger>
<DialogContent>
<DialogHeader>{title}</DialogHeader>
<div className="text-sm">{info}</div>
</DialogContent>
</Dialog>
);

export { LayerVisibility, LayerOpacity, LayerInfo };
35 changes: 35 additions & 0 deletions client/src/components/map/legends/header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { LayerInfo, LayerOpacity, LayerVisibility } from "./buttons";

type LegendHeaderProps = {
title?: string;
subtitle?: string;
setOpacity: (o: number) => void;
opacity?: number;
setVisibility: (v: boolean) => void;
visible: boolean;
info?: string;
};

const LegendHeader = ({
title,
subtitle,
setOpacity,
setVisibility,
info,
opacity,
visible,
}: LegendHeaderProps) => {
return (
<div>
<div className="flex items-center gap-2">
<span className="flex-1 font-medium">{title}</span>
<LayerOpacity onChangeOpacity={setOpacity} opacity={opacity} />
{!!info && <LayerInfo info={info} title={title} />}
<LayerVisibility onChangeVisibility={setVisibility} visible={visible} />
</div>
{subtitle && <span className="text-xs">{subtitle}</span>}
</div>
);
};

export default LegendHeader;
Loading

0 comments on commit b72d0e0

Please sign in to comment.