Skip to content

Commit

Permalink
Merge pull request #40 from Vizzuality/table-design
Browse files Browse the repository at this point in the history
[SKY30-88] Implement a static version of the table
  • Loading branch information
agnlez authored Nov 8, 2023
2 parents 4adc814 + 9ed9bd2 commit 5cc94a7
Show file tree
Hide file tree
Showing 11 changed files with 2,017 additions and 1,397 deletions.
37 changes: 24 additions & 13 deletions frontend/src/containers/data-tool/content/details/index.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
import DashboardTable from '@/components/dashboard-table';
import { useMemo } from 'react';

import { useAtomValue } from 'jotai';

import { Button } from '@/components/ui/button';
import tablesSettings from '@/containers/data-tool/content/details/tables-settings';
import { useSyncDataToolContentSettings } from '@/containers/data-tool/sync-settings';

import { mockedData } from './mocked-data';
import { locationAtom } from '@/store/location';

const DataToolDetails: React.FC = () => {
const [, setSettings] = useSyncDataToolContentSettings();
const location = useAtomValue(locationAtom);

const handleOnCloseClick = () => {
setSettings((prevSettings) => ({ ...prevSettings, showDetails: false }));
};

const table = useMemo(() => {
// TODO: Improve to support more entries (although not needed right now)
const tableSettings = tablesSettings.worldwideRegion.locationTypes.includes(location.type)
? tablesSettings.worldwideRegion
: tablesSettings.countryHighseas;

const parsedTitle = tableSettings.title[location.type].replace('{location}', location.name);

return {
title: parsedTitle,
component: tableSettings.component,
};
}, [location]);

return (
<div className="absolute h-full w-full overflow-scroll bg-white px-4 py-4 md:px-6">
<div className="mb-8 flex gap-8 md:justify-between">
<span className="max-w-lg">
<h2 className="text-4xl font-extrabold">
Marine Conservation at National and Regional Levels
</h2>
<h2 className="text-4xl font-extrabold">{table.title}</h2>
</span>
<Button variant="text-link" className="m-0 cursor-pointer p-0" onClick={handleOnCloseClick}>
Close
</Button>
</div>
<div className="overflow-scroll">
{/* NOTE: Div to test the horizontal overflow */}
<div className="mt-4" style={{ width: '130%' }}>
{/*
NOTE: We don't need a separate table component, but it's easier
to have one while using mocked data in order to keep this component clean
*/}
<DashboardTable data={mockedData} />
<div className="mt-4">
<table.component />
</div>
</div>
</div>
Expand Down
67 changes: 0 additions & 67 deletions frontend/src/containers/data-tool/content/details/mocked-data.ts

This file was deleted.

128 changes: 128 additions & 0 deletions frontend/src/containers/data-tool/content/details/table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { useLayoutEffect, useRef, useState } from 'react';

import {
flexRender,
getCoreRowModel,
getSortedRowModel,
useReactTable,
} from '@tanstack/react-table';

import { cn } from '@/lib/classnames';

// ! todo: type columns,data properly
const DataToolTable = ({ columns, data }) => {
const tableRef = useRef<HTMLTableElement>();
const firstColumnRef = useRef<HTMLTableCellElement>(null);

const [tableDimensions, setTableDimensions] = useState<{
firstColumnWidth: HTMLTableCellElement['offsetWidth'];
tableWidth: HTMLTableElement['offsetWidth'];
availableBarWidth: number;
}>({
firstColumnWidth: 0,
tableWidth: 0,
availableBarWidth: 0,
});

const table = useReactTable<typeof data>({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
});

const hasData = table.getRowModel().rows?.length;

const firstColumn = columns[0];
const lastColumn = columns[columns.length - 1];

useLayoutEffect(() => {
const tableWidth = tableRef.current?.offsetWidth;
const firstColumnWidth = firstColumnRef.current?.offsetWidth;
const availableBarWidth = tableWidth - firstColumnWidth;

setTableDimensions({
firstColumnWidth,
tableWidth,
availableBarWidth,
});
}, [data]);

return (
<table ref={tableRef} className="whitespace-nowrap font-mono text-xs">
<thead className="text-left">
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
const { id, column } = header;
const isFirstColumn = id === firstColumn.accessorKey;
const isLastColumn = id === lastColumn.accessorKey;

return (
<th
key={id}
ref={isFirstColumn ? firstColumnRef : null}
className={cn({
'h-10 py-3 pl-6 pr-16': true,
'border-r border-dashed border-black pl-0 pr-5': isFirstColumn,
'pr-0': isLastColumn,
})}
>
{flexRender(column.columnDef.header, header.getContext())}
</th>
);
})}
</tr>
))}
</thead>
<tbody>
{hasData &&
table.getRowModel().rows.map((row) => {
const coverage = row.original?.coverage || null; // %;
const offset = tableDimensions.firstColumnWidth;
const barWidth = (coverage * tableDimensions.availableBarWidth) / 100;

return (
<tr
key={row.id}
className="border-b border-t border-black"
style={{
backgroundImage: `linear-gradient(to right, rgb(72, 121, 255) ${barWidth}px, transparent ${barWidth}px)`,
backgroundPositionX: `${offset}px`,
}}
>
{row.getVisibleCells().map((cell) => {
const { column } = cell;
const isFirstColumn = column.id === firstColumn.accessorKey;
const isLastColumn = column.id === lastColumn.accessorKey;

return (
<td
key={cell.id}
className={cn({
'h-16 py-3 pl-6 pr-16': true,
'border-r border-dashed border-black pl-0 pr-5': isFirstColumn,
'pr-0': isLastColumn,
})}
>
{flexRender(column.columnDef.cell, cell.getContext())}
</td>
);
})}
</tr>
);
})}

{!hasData && (
<tr>
<td colSpan={columns.length} className="h-24 text-center">
No results.
</td>
</tr>
)}
</tbody>
</table>
);
};

export default DataToolTable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import GlobalRegionalTable from '@/containers/data-tool/content/details/tables/global-regional';
import NationalHighSeasTable from '@/containers/data-tool/content/details/tables/national-highseas';

const tablesSettings = {
worldwideRegion: {
locationTypes: ['worldwide', 'region'],
component: GlobalRegionalTable,
title: {
worldwide: 'Marine Conservation at National and Regional Levels',
region: 'Marine Conservation for {location}',
},
},
countryHighseas: {
locationTypes: ['country', 'highseas'],
component: NationalHighSeasTable,
title: {
country: 'Marine Conservation for {location}',
highSeas: 'Marine Conservation for High Seas',
},
},
};

export default tablesSettings;
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { format } from 'd3-format';

// ! type me
const columns = [
{
accessorKey: 'location',
header: 'Location',
cell: ({ row }) => {
const { location } = row.original;
return <span className="underline">{location}</span>;
},
},
{
accessorKey: 'coverage',
header: 'Coverage',
cell: ({ row }) => {
const { coverage: value } = row.original;
if (!value) return <>&mdash;</>;
return (
<span className="text-4xl font-bold">
{value}
<span className="text-xs">%</span>
</span>
);
},
},
{
accessorKey: 'locationType',
header: 'Location type',
},
{
accessorKey: 'mpas',
header: 'MPAs',
},
{
accessorKey: 'oecms',
header: 'OECMs',
},
{
accessorKey: 'area',
header: 'Area',
cell: ({ row }) => {
const { area: value } = row.original;
const formattedValue = format(',.2r')(value);
return (
<span>
{formattedValue} km<sup>2</sup>
</span>
);
},
},
{
accessorKey: 'fullyHighProtected',
header: 'Fully/Highly Protected',
cell: ({ row }) => {
const { fullyHighProtected: value } = row.original;
if (!value) return <>No data</>;
return (
<>
{value}
<span className="text-xs">%</span>
</>
);
},
},
{
accessorKey: 'highlyProtectedLFP',
header: 'Highly Protected LFP',
cell: ({ row }) => {
const { highlyProtectedLFP: value } = row.original;
if (!value) return <>No data</>;
return (
<>
{value}
<span className="text-xs">%</span>
</>
);
},
},
{
accessorKey: 'globalContribution',
header: 'Global contribution',
cell: ({ row }) => {
const { globalContribution: value } = row.original;
if (!value) return <>No data</>;
return (
<>
{value}
<span className="text-xs">%</span>
</>
);
},
},
];

export default columns;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Table from '@/containers/data-tool/content/details/table';
import columns from '@/containers/data-tool/content/details/tables/global-regional/columns';
import mockedData from '@/containers/data-tool/content/details/tables/global-regional/mocked-data';

const GlobalRegionalTable: React.FC = () => {
const data = mockedData;

return <Table columns={columns} data={data} />;
};

export default GlobalRegionalTable;
Loading

0 comments on commit 5cc94a7

Please sign in to comment.