Skip to content

Commit

Permalink
Update the tables visually
Browse files Browse the repository at this point in the history
  • Loading branch information
clementprdhomme committed Oct 15, 2024
1 parent 69a60cf commit 815feb9
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 117 deletions.
4 changes: 4 additions & 0 deletions frontend/src/components/positional-scroll/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const PositionalScroll: React.FC<PositionalScrollProps> = ({
const handleScroll = useCallback(() => {
const target = ref.current;

if (!target) {
return;
}

const xAtStartPosition = target.scrollLeft === 0;
const xAtEndPosition = target.scrollLeft === target.scrollWidth - target.clientWidth;

Expand Down
12 changes: 4 additions & 8 deletions frontend/src/containers/map/content/details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import CloseIcon from '@/styles/icons/close.svg';
import { FCWithMessages } from '@/types';
import { getGetLocationsQueryOptions, useGetLocations } from '@/types/generated/location';

import ScrollingIndicators from './table/scrolling-indicators';

const MapDetails: FCWithMessages = () => {
const t = useTranslations('containers.map');
const locale = useLocale();
Expand Down Expand Up @@ -135,8 +133,8 @@ const MapDetails: FCWithMessages = () => {
}, [locale, tablesSettings, tab, locationsQuery.data]);

return (
<div className="absolute h-full w-full overflow-scroll bg-white px-4 py-4 md:px-6">
<div className="sticky left-0 mb-8 flex gap-8 md:justify-between">
<div className="flex h-full w-full flex-col overflow-hidden bg-white px-4 py-4 md:px-6">
<div className="mb-8 flex shrink-0 gap-8 md:justify-between">
<span className="max-w-xl">
<h2 className="text-4xl font-extrabold">{table.title}</h2>
</span>
Expand All @@ -149,10 +147,8 @@ const MapDetails: FCWithMessages = () => {
<Icon icon={CloseIcon} className="ml-2 h-3 w-3 pb-px " />
</Button>
</div>
<div className="relative z-0 mb-14">
<ScrollingIndicators className="mt-4 overflow-x-scroll">
<table.component />
</ScrollingIndicators>
<div className="flex-grow overflow-hidden">
<table.component />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const ExpansionControls: React.FC<ExpansionControlsProps> = ({ row, children })
{isRowExpandable && (
<button
type="button"
className="cursor pointer -ml-1.5 mr-1.5"
className="cursor pointer -ml-px mr-1.5"
onClick={toggleExpanded}
aria-label={isRowExpanded ? t('collapse-sub-rows') : t('expand-sub-rows')}
>
Expand Down
181 changes: 95 additions & 86 deletions frontend/src/containers/map/content/details/table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { cn } from '@/lib/classnames';
import { FCWithMessages } from '@/types';

import Pagination from './pagination';
import ScrollingIndicators from './scrolling-indicators';

type MapTableProps<TData> = FCWithMessages<{
columns: AccessorKeyColumnDef<TData>[];
Expand Down Expand Up @@ -71,112 +72,120 @@ const MapTable: MapTableProps<unknown> = <TData,>({

const shouldAddColumnSeparator = useCallback(
(columnId) => {
const isFirstColumn = columnId === firstColumn.accessorKey;
return columnSeparators ? columnSeparators?.includes(columnId) : isFirstColumn;
return columnSeparators ? columnSeparators?.includes(columnId) : false;
},
[columnSeparators, firstColumn.accessorKey]
[columnSeparators]
);

return (
<>
<table
ref={tableRef}
className="relative min-w-full border-spacing-0 whitespace-nowrap pr-6 font-mono text-xs"
>
<thead className="sticky -top-4 z-10 bg-white text-left">
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id} className="shadow-[0_2px_0_-1px_rgb(0,0,0)]">
{headerGroup.headers.map((header) => {
const { id, column } = header;
const isFirstColumn = id === firstColumn.accessorKey;
const isLastColumn = id === lastColumn.accessorKey;
const isMapColumn = column.id === 'map';

return (
<th
key={id}
ref={isFirstColumn ? firstColumnRef : null}
className={cn({
'border-r border-dashed border-black': shouldAddColumnSeparator(id),
'h-10 overflow-hidden': true,
'px-6': !isMapColumn,
'pl-0 pr-5': isFirstColumn,
'pr-0': isLastColumn,
})}
style={{
minWidth: column.getSize() ? `${column.getSize()}px` : undefined,
width: column.getSize() ? `${column.getSize()}px` : undefined,
maxWidth: column.getSize() ? `${column.getSize()}px` : undefined,
}}
>
{flexRender(column.columnDef.header, header.getContext())}
</th>
);
})}
</tr>
))}
</thead>
<tbody>
{hasData &&
table.getRowModel().rows.map((row, idx) => {
const { depth } = row;
const isParentRow = depth === 0;
const isFirstRow = idx === 0;
const isLastRow = idx + 1 === table.getRowModel().rows.length;

return (
<tr
key={row.id}
className={cn({
'border-t border-black': !isFirstRow,
'border-dashed': !isParentRow,
'border-b': isLastRow,
})}
>
{row.getVisibleCells().map((cell) => {
const { column } = cell;
const isFirstColumn = column.id === firstColumn.accessorKey;
const isLastColumn = column.id === lastColumn.accessorKey;
<div className="flex h-full flex-col">
<div className="relative flex-grow overflow-hidden pt-5">
<ScrollingIndicators className="h-full w-full overflow-scroll">
<table
ref={tableRef}
className="relative border-separate border-spacing-0 whitespace-nowrap font-mono text-xs"
>
<thead className="sticky top-0 z-10 bg-white text-left">
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id} className="shadow-[0_2px_0_-1px_rgb(0,0,0)]">
{headerGroup.headers.map((header) => {
const { id, column } = header;
const isFirstColumn = id === firstColumn.accessorKey;
const isLastColumn = id === lastColumn.accessorKey;
const isMapColumn = column.id === 'map';

return (
<td
key={cell.id}
<th
key={id}
ref={isFirstColumn ? firstColumnRef : null}
className={cn({
'overflow-hidden whitespace-normal py-5 pl-6': true,
'px-6 ': !isMapColumn,
'-mt-px -mb-px': isMapColumn,
'pl-0 pr-5': isFirstColumn,
'border-r border-black': shouldAddColumnSeparator(id),
'h-10 overflow-hidden': true,
'px-6': !isMapColumn,
'sticky left-0 z-10 border-r border-r-black bg-white pl-0 pr-5':
isFirstColumn,
'pr-0': isLastColumn,
'border-r border-dashed border-black': shouldAddColumnSeparator(
column.id
),
})}
style={{
minWidth: column.getSize() ? `${column.getSize()}px` : undefined,
width: column.getSize() ? `${column.getSize()}px` : undefined,
maxWidth: column.getSize() ? `${column.getSize()}px` : undefined,
}}
>
{flexRender(column.columnDef.cell, cell.getContext())}
</td>
{flexRender(column.columnDef.header, header.getContext())}
</th>
);
})}
</tr>
);
})}

{!hasData && (
<tr>
<td colSpan={columns.length} className="h-24 text-center">
{t('no-results')}
</td>
</tr>
)}
</tbody>
</table>
))}
</thead>
<tbody>
{hasData &&
table.getRowModel().rows.map((row, idx) => {
const isFirstRow = idx === 0;
const isLastRow = idx + 1 === table.getRowModel().rows.length;
const isLastSubRow =
row.depth === 1 &&
row.getParentRow().subRows.findIndex(({ id }) => id === row.id) ===
row.getParentRow().subRows.length - 1;

return (
<tr
key={row.id}
className={cn({
relative: true,
' after:absolute after:-bottom-px after:left-0 after:z-10 after:block after:h-px after:w-full after:bg-black':
isLastSubRow,
})}
>
{row.getVisibleCells().map((cell) => {
const { column } = cell;
const isFirstColumn = column.id === firstColumn.accessorKey;
const isLastColumn = column.id === lastColumn.accessorKey;
const isMapColumn = column.id === 'map';

return (
<td
key={cell.id}
className={cn({
'overflow-hidden whitespace-normal py-5 pl-6': true,
'px-6 ': !isMapColumn,
'-mt-px -mb-px': isMapColumn,
'sticky left-0 border-r border-r-black bg-white pl-0 pr-5':
isFirstColumn,
'pr-0': isLastColumn,
'border-r border-black': shouldAddColumnSeparator(column.id),
'border-t border-t-black': !isFirstRow,
'[border-top-style:dashed]': !isFirstRow && !row.getIsExpanded(),
'border-b border-b-black': isLastRow,
})}
style={{
minWidth: column.getSize() ? `${column.getSize()}px` : undefined,
width: column.getSize() ? `${column.getSize()}px` : undefined,
maxWidth: column.getSize() ? `${column.getSize()}px` : undefined,
}}
>
{flexRender(column.columnDef.cell, cell.getContext())}
</td>
);
})}
</tr>
);
})}

{!hasData && (
<tr>
<td colSpan={columns.length} className="h-24 text-center">
{t('no-results')}
</td>
</tr>
)}
</tbody>
</table>
</ScrollingIndicators>
</div>
<Pagination table={table} pagination={pagination} rowCount={rowCount} />
</>
</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const Pagination = <TData extends RowData>({
const t = useTranslations('containers.map');

return (
<div className="sticky bottom-0 left-0 flex items-center justify-end p-3">
<div className="relative flex shrink-0 items-center justify-end p-3">
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 font-mono text-xs">
{t('results-out-of', {
startIndex: pagination.pageIndex * pagination.pageSize + 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,7 @@ const ScrollingIndicators: React.FC<ScrollingIndicatorsProps> = ({ className, ch
{(xScrollPosition === 'start' || xScrollPosition === 'middle') && (
<>
<span className={cn(COMMON_CLASSNAMES.border, 'right-0 top-0')}>
<span
className={cn(COMMON_CLASSNAMES.iconWrapper, '-right-px top-0 -translate-y-full')}
>
<LuChevronRight className={COMMON_CLASSNAMES.icon} />
</span>
</span>
<span className={cn(COMMON_CLASSNAMES.border, 'right-0 bottom-0')}>
<span
className={cn(COMMON_CLASSNAMES.iconWrapper, '-right-px bottom-px translate-y-full')}
>
<span className={cn(COMMON_CLASSNAMES.iconWrapper, '-right-px top-0')}>
<LuChevronRight className={COMMON_CLASSNAMES.icon} />
</span>
</span>
Expand All @@ -41,14 +32,7 @@ const ScrollingIndicators: React.FC<ScrollingIndicatorsProps> = ({ className, ch
{(xScrollPosition === 'middle' || xScrollPosition === 'end') && (
<>
<span className={cn(COMMON_CLASSNAMES.border, 'left-0 top-0')}>
<span className={cn(COMMON_CLASSNAMES.iconWrapper, 'left-0 top-0 -translate-y-full')}>
<LuChevronLeft className={COMMON_CLASSNAMES.icon} />
</span>
</span>
<span className={cn(COMMON_CLASSNAMES.border, 'left-0 bottom-0')}>
<span
className={cn(COMMON_CLASSNAMES.iconWrapper, 'left-0 bottom-px translate-y-full')}
>
<span className={cn(COMMON_CLASSNAMES.iconWrapper, 'left-0 top-0')}>
<LuChevronLeft className={COMMON_CLASSNAMES.icon} />
</span>
</span>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/containers/map/content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const MapContent: FCWithMessages = () => {
<>
<Map />
{showDetails && (
<div className="relative h-full w-full border-b border-r border-black">
<div className="relative h-full w-full overflow-hidden border-b border-r border-black">
<Details />
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ type DetailsButtonProps = {
const DetailsButton: FCWithMessages<DetailsButtonProps> = ({ className, locationType }) => {
const t = useTranslations('containers.map-sidebar-main-panel');

const [{ tab }, setSettings] = useSyncMapContentSettings();
const [{ tab, showDetails }, setSettings] = useSyncMapContentSettings();

const handleButtonClick = useCallback(() => {
setSettings((prevSettings) => ({ ...prevSettings, showDetails: !prevSettings.showDetails }));
}, [setSettings]);

return (
<Button
className={cn('flex h-10 px-5 md:px-8', className)}
className={cn(
{
'flex h-10 px-5 md:px-8': true,
'border border-black bg-orange text-black hover:bg-orange': showDetails,
},
className
)}
size="full"
onClick={handleButtonClick}
>
Expand Down

0 comments on commit 815feb9

Please sign in to comment.