Skip to content

Commit

Permalink
Merge pull request #31
Browse files Browse the repository at this point in the history
Display dataset metadata
  • Loading branch information
clementprdhomme authored Nov 20, 2024
2 parents c738faa + c94dc0b commit 543f3e4
Show file tree
Hide file tree
Showing 15 changed files with 1,114 additions and 69 deletions.
3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@radix-ui/react-slot": "1.1.0",
"@radix-ui/react-switch": "1.1.1",
"@radix-ui/react-tabs": "1.1.1",
"@radix-ui/react-tooltip": "1.1.3",
"@radix-ui/react-tooltip": "1.1.4",
"@t3-oss/env-nextjs": "0.11.1",
"@tanstack/react-query": "5.59.16",
"@turf/bbox": "7.1.0",
Expand All @@ -57,6 +57,7 @@
"react": "18.3.1",
"react-dom": "18.3.1",
"react-map-gl": "7.1.7",
"react-markdown": "9.0.1",
"tailwind-merge": "2.5.4",
"tailwindcss-animate": "1.0.7",
"tailwindcss-border-image": "1.1.2",
Expand Down
70 changes: 54 additions & 16 deletions client/src/components/dataset-card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import Link from "next/link";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import * as React from "react";

import DatasetMetadata from "@/components/dataset-metadata";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import MonthPicker from "@/components/ui/month-picker";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
Expand All @@ -18,14 +20,16 @@ import {
SelectValue,
} from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import useMapLayers from "@/hooks/use-map-layers";
import { cn } from "@/lib/utils";
import CalendarDaysIcon from "@/svgs/calendar-days.svg";
import ChevronDownIcon from "@/svgs/chevron-down.svg";
import DownloadIcon from "@/svgs/download.svg";
import PauseIcon from "@/svgs/pause.svg";
import PlayIcon from "@/svgs/play.svg";
import { DatasetLayersDataItem } from "@/types/generated/strapi.schemas";
import QuestionMarkIcon from "@/svgs/question-mark.svg";
import { DatasetLayersDataItem, MetadataItemComponent } from "@/types/generated/strapi.schemas";
import { LayerParamsConfig } from "@/types/layer";

import {
Expand All @@ -40,9 +44,10 @@ interface DatasetCardProps {
name: string;
defaultLayerId: number | undefined;
layers: DatasetLayersDataItem[];
metadata?: MetadataItemComponent;
}

const DatasetCard = ({ id, name, defaultLayerId, layers }: DatasetCardProps) => {
const DatasetCard = ({ id, name, defaultLayerId, layers, metadata }: DatasetCardProps) => {
const [layersConfiguration, { addLayer, updateLayer, removeLayer }] = useMapLayers();

const defaultSelectedLayerId = useMemo(
Expand Down Expand Up @@ -219,21 +224,54 @@ const DatasetCard = ({ id, name, defaultLayerId, layers }: DatasetCardProps) =>
<Label htmlFor={`dataset-${id}-toggle`} className="text-[20px]">
{name}
</Label>
<div className="flex items-center gap-0.5 pt-1">
<div className="flex items-center gap-1 pt-1.5">
{!!selectedLayer?.attributes!.download_link && (
<Button variant="ghost" size="icon-sm" className="group/download" asChild>
<Link
href={selectedLayer?.attributes!.download_link ?? ""}
rel="noopener noreferrer"
download={selectedLayer?.attributes!.name}
>
<span className="sr-only">Download</span>
<DownloadIcon
className="!size-4 transition-colors group-hover/download:text-casper-blue-300"
aria-hidden
/>
</Link>
</Button>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon-sm" className="group/download" asChild>
<Link
href={selectedLayer?.attributes!.download_link ?? ""}
rel="noopener noreferrer"
download={selectedLayer?.attributes!.name}
>
<span className="sr-only">Download</span>
<DownloadIcon
className="!size-4 transition-colors group-hover/download:text-casper-blue-300"
aria-hidden
/>
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>Download dataset</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
{!!metadata && (
<Dialog>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button variant="ghost" size="icon-sm" className="group/info">
<span className="sr-only">Information</span>
<QuestionMarkIcon
className="!size-4 transition-colors group-hover/info:text-casper-blue-300"
aria-hidden
/>
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent>More info</TooltipContent>
</Tooltip>
</TooltipProvider>
<DialogContent>
<DatasetMetadata name={name} metadata={metadata} />
</DialogContent>
</Dialog>
)}
{(!!selectedLayer?.attributes!.download_link || !!metadata) && (
<div className="mx-0.5 h-5 w-px bg-casper-blue-400" />
)}
<Switch
id={`dataset-${id}-toggle`}
Expand Down
93 changes: 93 additions & 0 deletions client/src/components/dataset-metadata/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Link from "next/link";

import Markdown from "@/components/markdown";
import { DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { MetadataItemComponent } from "@/types/generated/strapi.schemas";

interface DatasetMetadataProps {
name: string;
metadata: MetadataItemComponent;
}

const DatasetMetadata = ({ name, metadata }: DatasetMetadataProps) => {
return (
<>
<DialogHeader>
<DialogTitle>{name}</DialogTitle>
</DialogHeader>
<dl className="mt-8 flex flex-col gap-2 text-xs">
{!!metadata.full_name && (
<div>
<dt className="font-bold">Full name</dt>
<dd>{metadata.full_name}</dd>
</div>
)}
{!!metadata.source && (
<div>
<dt className="font-bold">Source</dt>
<dd>{metadata.source}</dd>
</div>
)}
{!!metadata.website && (
<div>
<dt className="font-bold">Website</dt>
<dd>
<Link
href={metadata.website}
target="_blank"
rel="noopener noreferrer"
className="break-all underline"
>
{metadata.website}
</Link>
</dd>
</div>
)}
{!!metadata.description && (
<div>
<dt className="font-bold">Description</dt>
<dd>{metadata.description}</dd>
</div>
)}
{!!metadata.main_applications && (
<div>
<dt className="font-bold">Main applications</dt>
<dd>
<Markdown>{metadata.main_applications}</Markdown>
</dd>
</div>
)}
{!!metadata.temporal_resolution && (
<div>
<dt className="font-bold">Temporal resolution</dt>
<dd>
<Markdown>{metadata.temporal_resolution}</Markdown>
</dd>
</div>
)}
{!!metadata.temporal_coverage && (
<div>
<dt className="font-bold">Temporal coverage</dt>
<dd>
<Markdown>{metadata.temporal_coverage}</Markdown>
</dd>
</div>
)}
{!!metadata.spatial_resolution && (
<div>
<dt className="font-bold">Spatial resolution</dt>
<dd>{metadata.spatial_resolution}</dd>
</div>
)}
{!!metadata.units && (
<div>
<dt className="font-bold">Units</dt>
<dd>{metadata.units}</dd>
</div>
)}
</dl>
</>
);
};

export default DatasetMetadata;
32 changes: 32 additions & 0 deletions client/src/components/markdown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Link from "next/link";
import ReactMarkdown from "react-markdown";

interface MarkdownProps {
children: string | null | undefined;
}

const Markdown = ({ children }: MarkdownProps) => {
return (
<ReactMarkdown
allowedElements={["ul", "ol", "li", "b", "strong", "em", "i", "a", "br", "p"]}
components={{
ul: ({ children }) => <ul className="list-inside list-disc">{children}</ul>,
ol: ({ children }) => <ol className="list-inside list-decimal">{children}</ol>,
a: ({ children, href }) => (
<Link
href={href!}
target={href?.startsWith("http") ? "_blank" : undefined}
rel={href?.startsWith("http") ? "noopener noreferrer" : undefined}
className="break-all underline"
>
{children}
</Link>
),
}}
>
{children}
</ReactMarkdown>
);
};

export default Markdown;
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const NavigationDesktop = () => {
<MapPinIcon aria-hidden />
</Button>
</DialogTrigger>
<DialogContent className="gap-0">
<DialogContent>
<LocationPanel onExit={onExitLocationDialog} />
</DialogContent>
</Dialog>
Expand Down
11 changes: 7 additions & 4 deletions client/src/components/panels/contextual-layers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import XMarkIcon from "@/svgs/xmark.svg";
import Item from "./item";

const ContextualLayersPanel = () => {
const { data, isLoading } = useDatasetsBySubTopic("contextual", "sub_topic.name,name", [
"layer",
"download_link",
]);
const { data, isLoading } = useDatasetsBySubTopic(
"contextual",
"sub_topic.name,name",
["layer", "download_link"],
true,
);

return (
<>
Expand Down Expand Up @@ -75,6 +77,7 @@ const ContextualLayersPanel = () => {
id: dataset.layers[0].id!,
name: dataset.layers[0].attributes!.name!,
downloadLink: dataset.layers[0].attributes!.download_link,
metadata: dataset.metadata,
}))}
/>
))}
Expand Down
88 changes: 61 additions & 27 deletions client/src/components/panels/contextual-layers/item.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import Link from "next/link";
import * as React from "react";

import DatasetMetadata from "@/components/dataset-metadata";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import useMapLayers from "@/hooks/use-map-layers";
import { cn } from "@/lib/utils";
import DownloadIcon from "@/svgs/download.svg";
import { Dataset, Layer } from "@/types/generated/strapi.schemas";
import QuestionMarkIcon from "@/svgs/question-mark.svg";
import { Dataset, Layer, MetadataItemComponent } from "@/types/generated/strapi.schemas";

interface ItemProps {
name: Dataset["name"];
layers: { id: number; name: Layer["name"]; downloadLink?: Layer["download_link"] }[];
layers: {
id: number;
name: Layer["name"];
downloadLink?: Layer["download_link"];
metadata?: MetadataItemComponent;
}[];
}

const Item = ({ name, layers }: ItemProps) => {
Expand All @@ -25,30 +34,55 @@ const Item = ({ name, layers }: ItemProps) => {
<Label htmlFor={`${layer.id}-toggle`} className="text-xl">
{layer.name}
</Label>
<div className="flex items-center gap-0.5 pt-1">
<Button
variant="ghost"
size="icon-sm"
className={cn({
"group/download": true,
"pointer-events-none opacity-20": !layer.downloadLink,
})}
aria-disabled={!layer.downloadLink}
tabIndex={!layer.downloadLink ? -1 : undefined}
asChild
>
<Link
href={layer.downloadLink ?? ""}
rel="noopener noreferrer"
download={layer.name}
>
<span className="sr-only">Download</span>
<DownloadIcon
className="!size-4 transition-colors group-hover/download:text-casper-blue-300"
aria-hidden
/>
</Link>
</Button>
<div className="flex items-center gap-1 pt-1.5">
{!!layer.downloadLink && (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon-sm" className="group/download" asChild>
<Link
href={layer.downloadLink ?? ""}
rel="noopener noreferrer"
download={layer.name}
>
<span className="sr-only">Download</span>
<DownloadIcon
className="!size-4 transition-colors group-hover/download:text-casper-blue-300"
aria-hidden
/>
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>Download dataset</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
{!!layer.metadata && (
<Dialog>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<DialogTrigger asChild>
<Button variant="ghost" size="icon-sm" className="group/info">
<span className="sr-only">Information</span>
<QuestionMarkIcon
className="!size-4 transition-colors group-hover/info:text-casper-blue-300"
aria-hidden
/>
</Button>
</DialogTrigger>
</TooltipTrigger>
<TooltipContent>More info</TooltipContent>
</Tooltip>
</TooltipProvider>
<DialogContent>
<DatasetMetadata name={name} metadata={layer.metadata} />
</DialogContent>
</Dialog>
)}
{(!!layer.downloadLink || !!layer.metadata) && (
<div className="mx-0.5 h-5 w-px bg-casper-blue-400" />
)}
<Switch
id={`${layer.id}-toggle`}
checked={layersConfiguration.findIndex(({ id }) => id === layer.id) !== -1}
Expand Down
Loading

0 comments on commit 543f3e4

Please sign in to comment.