From 7e7c5e14abdeb3048af89bca2603fdae98cc937c Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Sat, 24 Dec 2022 16:46:18 +0530 Subject: [PATCH] refactor(dev-only): files table view (#2118) --- .../FilesTableView/FilesTableView.tsx | 12 +- .../Components/Table/CommonTypes.ts | 13 +- .../javascripts/Components/Table/Table.tsx | 169 +++++++++++++----- .../javascripts/Components/Table/useTable.tsx | 23 ++- 4 files changed, 160 insertions(+), 57 deletions(-) diff --git a/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx b/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx index 95d1369b4..271dc0665 100644 --- a/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx +++ b/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx @@ -20,6 +20,7 @@ import LinkedItemBubble from '../LinkedItems/LinkedItemBubble' import LinkedItemsPanel from '../LinkedItems/LinkedItemsPanel' import { LinkingController } from '@/Controllers/LinkingController' import { FeaturesController } from '@/Controllers/FeaturesController' +import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery' const ContextMenuCell = ({ files, filesController }: { files: FileItem[]; filesController: FilesController }) => { const [contextMenuVisible, setContextMenuVisible] = useState(false) @@ -152,6 +153,8 @@ const FilesTableView = ({ application, filesController, featuresController, link const [contextMenuFile, setContextMenuFile] = useState(undefined) const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | undefined>(undefined) + const isSmallBreakpoint = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm) + const columnDefs: TableColumn[] = useMemo( () => [ { @@ -159,9 +162,9 @@ const FilesTableView = ({ application, filesController, featuresController, link sortBy: 'title', cell: (file) => { return ( -
+
{getFileIconComponent(getIconForFileType(file.mimeType), 'w-6 h-6 flex-shrink-0')} - {file.title} + {file.title} {file.protected && ( { return formatDateForContextMenu(file.created_at) }, + hidden: isSmallBreakpoint, }, { name: 'Size', cell: (file) => { return formatSizeToReadableString(file.decryptedSize) }, + hidden: isSmallBreakpoint, }, { name: 'Attached to', + hidden: isSmallBreakpoint, cell: (file) => { const links = [ ...naturalSort(application.items.referencesForItem(file), 'title').map((item) => @@ -223,7 +229,7 @@ const FilesTableView = ({ application, filesController, featuresController, link }, }, ], - [application.items], + [application.items, isSmallBreakpoint], ) const getRowId = useCallback((file: FileItem) => file.uuid, []) diff --git a/packages/web/src/javascripts/Components/Table/CommonTypes.ts b/packages/web/src/javascripts/Components/Table/CommonTypes.ts index a86b29f03..37122d9e4 100644 --- a/packages/web/src/javascripts/Components/Table/CommonTypes.ts +++ b/packages/web/src/javascripts/Components/Table/CommonTypes.ts @@ -7,11 +7,18 @@ export type TableColumn = { name: string sortBy?: TableSortBy cell: (data: Data) => ReactNode + hidden?: boolean +} + +type TableCell = { + render: ReactNode + hidden: boolean + colIndex: number } export type TableRow = { id: string - cells: ReactNode[] + cells: TableCell[] isSelected: boolean rowData: Data rowActions?: ReactNode @@ -23,11 +30,15 @@ export type TableHeader = { sortBy?: TableSortBy sortReversed: boolean | undefined onSortChange: () => void + hidden: boolean + colIndex: number } export type Table = { headers: TableHeader[] rows: TableRow[] + rowCount: number + colCount: number handleRowClick: (id: string) => MouseEventHandler handleRowDoubleClick: (id: string) => MouseEventHandler handleRowContextMenu: (id: string) => MouseEventHandler diff --git a/packages/web/src/javascripts/Components/Table/Table.tsx b/packages/web/src/javascripts/Components/Table/Table.tsx index 65caaa0be..5bf97b57a 100644 --- a/packages/web/src/javascripts/Components/Table/Table.tsx +++ b/packages/web/src/javascripts/Components/Table/Table.tsx @@ -1,26 +1,122 @@ import { classNames } from '@standardnotes/snjs' +import { useState } from 'react' import Icon from '../Icon/Icon' -import { Table } from './CommonTypes' +import { Table, TableRow } from './CommonTypes' + +function TableRow({ + row, + index: rowIndex, + canSelectRows, + handleRowClick, + handleRowContextMenu, + handleRowDoubleClick, +}: { + row: TableRow + index: number + canSelectRows: Table['canSelectRows'] + handleRowClick: Table['handleRowClick'] + handleRowContextMenu: Table['handleRowContextMenu'] + handleRowDoubleClick: Table['handleRowDoubleClick'] +}) { + const [isHovered, setIsHovered] = useState(false) + + const visibleCells = row.cells.filter((cell) => !cell.hidden) + + return ( +
{ + setIsHovered(true) + }} + onMouseLeave={() => { + setIsHovered(false) + }} + onClick={handleRowClick(row.id)} + onDoubleClick={handleRowDoubleClick(row.id)} + onContextMenu={handleRowContextMenu(row.id)} + > + {visibleCells.map((cell, index, array) => { + return ( +
+ {cell.render} + {row.rowActions && index === array.length - 1 && ( +
+ {row.rowActions} +
+ )} +
+ ) + })} +
+ ) +} function Table({ table }: { table: Table }) { + const { + headers, + rows, + colCount, + rowCount, + handleRowClick, + handleRowContextMenu, + handleRowDoubleClick, + selectedRows, + selectionActions, + canSelectRows, + showSelectionActions, + } = table + return (
- {table.showSelectionActions && table.selectedRows.length >= 2 && ( + {showSelectionActions && selectedRows.length >= 2 && (
- {table.selectedRows.length} selected - {table.selectedRows.length > 0 && table.selectionActions} + {selectedRows.length} selected + {selectedRows.length > 0 && selectionActions}
)} - - - - {table.headers.map((header, index) => { +
+
+ {headers + .filter((header) => !header.hidden) + .map((header, index) => { return ( -
+ ) })} - - - - {table.rows.map((row) => { - return ( - - {row.cells.map((cell, index) => { - return ( - - ) - })} - {row.rowActions ? ( -
- {row.rowActions} -
- ) : null} - - ) - })} - -
@@ -34,47 +130,24 @@ function Table({ table }: { table: Table }) { /> )} -
- {cell} -
+
+
+ {rows.map((row, index) => ( + + ))} +
+
) } diff --git a/packages/web/src/javascripts/Components/Table/useTable.tsx b/packages/web/src/javascripts/Components/Table/useTable.tsx index d7d556c56..2f5beb37c 100644 --- a/packages/web/src/javascripts/Components/Table/useTable.tsx +++ b/packages/web/src/javascripts/Components/Table/useTable.tsx @@ -1,6 +1,6 @@ import { MouseEventHandler, ReactNode, useCallback, useEffect, useMemo, useState } from 'react' import { useApplication } from '../ApplicationProvider' -import { Table, TableColumn, TableRow, TableSortBy } from './CommonTypes' +import { Table, TableColumn, TableHeader, TableRow, TableSortBy } from './CommonTypes' type TableSortOptions = | { @@ -78,9 +78,9 @@ export function useTable({ } }, [selectedRows, onRowSelectionChange]) - const headers = useMemo( + const headers: TableHeader[] = useMemo( () => - columns.map((column) => { + columns.map((column, index) => { return { name: column.name, isSorting: sortBy && sortBy === column.sortBy, @@ -92,6 +92,8 @@ export function useTable({ } onSortChange(column.sortBy, sortBy === column.sortBy ? !sortReversed : false) }, + hidden: column.hidden || false, + colIndex: index, } }), [columns, onSortChange, sortBy, sortReversed], @@ -100,8 +102,12 @@ export function useTable({ const rows: TableRow[] = useMemo( () => data.map((rowData, index) => { - const cells = columns.map((column) => { - return column.cell(rowData) + const cells = columns.map((column, index) => { + return { + render: column.cell(rowData), + hidden: column.hidden || false, + colIndex: index, + } }) const id = getRowId ? getRowId(rowData) : index.toString() const row: TableRow = { @@ -175,10 +181,15 @@ export function useTable({ [onRowContextMenu, rows], ) + const colCount = useMemo(() => columns.length, [columns]) + const rowCount = useMemo(() => data.length, [data.length]) + const table: Table = useMemo( () => ({ headers, rows, + colCount, + rowCount, handleRowClick, handleRowDoubleClick, handleRowContextMenu, @@ -188,11 +199,13 @@ export function useTable({ showSelectionActions: showSelectionActions || false, }), [ + colCount, enableRowSelection, handleRowClick, handleRowContextMenu, handleRowDoubleClick, headers, + rowCount, rows, selectedRows, selectionActions,