Fix exploding table layout

This commit is contained in:
dominik-zeglen 2020-09-25 16:49:21 +02:00
parent 4cecf238d6
commit e13086fef3
19 changed files with 210 additions and 97 deletions

View file

@ -51,7 +51,7 @@ interface CollectionListProps
collections: CollectionList_collections_edges_node[];
}
const numberOfColumns = 5;
const numberOfColumns = 4;
const CollectionList: React.FC<CollectionListProps> = props => {
const {

View file

@ -32,11 +32,16 @@ export interface FormData {
const useStyles = makeStyles(
{
avatar: {
"&:first-child": {
"&&:first-child": {
paddingLeft: 0
}
},
width: 72
},
checkboxCell: {
paddingLeft: 0,
width: 88
},
colName: {
paddingLeft: 0
},
overflow: {
@ -44,10 +49,6 @@ const useStyles = makeStyles(
},
scrollArea: {
overflowY: "scroll"
},
wideCell: {
paddingLeft: 0,
width: "100%"
}
},
{ name: "AssignProductDialog" }
@ -148,7 +149,7 @@ const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
className={classes.avatar}
thumbnail={maybe(() => product.thumbnail.url)}
/>
<TableCell className={classes.wideCell}>
<TableCell className={classes.colName}>
{product.name}
</TableCell>
<TableCell

View file

@ -1,6 +1,6 @@
import Avatar from "@material-ui/core/Avatar";
import { makeStyles } from "@material-ui/core/styles";
import TableCell from "@material-ui/core/TableCell";
import TableCell, { TableCellProps } from "@material-ui/core/TableCell";
import Cached from "@material-ui/icons/Cached";
import classNames from "classnames";
import React from "react";
@ -11,6 +11,9 @@ export const AVATAR_MARGIN = 32;
const useStyles = makeStyles(
theme => ({
alignRight: {
justifyContent: "flex-end"
},
avatar: {
background: "none",
border: `1px solid ${theme.palette.divider}`,
@ -39,21 +42,33 @@ const useStyles = makeStyles(
{ name: "TableCellAvatar" }
);
interface TableCellAvatarProps {
interface TableCellAvatarProps extends TableCellProps {
className?: string;
thumbnail?: string;
alignRight?: boolean;
avatarProps?: string;
children?: React.ReactNode | React.ReactNodeArray;
}
const TableCellAvatar: React.FC<TableCellAvatarProps> = props => {
const { children, className, thumbnail, avatarProps, ...rest } = props;
const {
children,
className,
alignRight,
thumbnail,
avatarProps,
...rest
} = props;
const classes = useStyles(props);
return (
<TableCell className={classNames(classes.root, className)} {...rest}>
<div className={classes.content}>
<div
className={classNames(classes.content, {
[classes.alignRight]: alignRight
})}
>
{thumbnail === undefined ? (
<Avatar className={classNames(classes.avatar, avatarProps)}>
<Cached color="primary" />
@ -68,7 +83,7 @@ const TableCellAvatar: React.FC<TableCellAvatarProps> = props => {
src={thumbnail}
/>
)}
<div className={classes.children}>{children}</div>
{!alignRight && <div className={classes.children}>{children}</div>}
</div>
</TableCell>
);

View file

@ -63,6 +63,14 @@ const useStyles = makeStyles(
{ name: "TableHead" }
);
function getColSpan(colSpan: number, dragRows: boolean): number {
if (dragRows) {
return colSpan - 2;
}
return colSpan - 1;
}
const TableHead: React.FC<TableHeadProps> = props => {
const {
children,
@ -107,7 +115,7 @@ const TableHead: React.FC<TableHeadProps> = props => {
<>
<TableCell
className={classNames(classes.root)}
colSpan={colSpan - 1}
colSpan={getColSpan(colSpan, dragRows)}
>
<div className={classes.container}>
{selected && (

View file

@ -28,23 +28,24 @@ export interface DiscountCategoriesProps extends ListProps, ListActions {
}
const useStyles = makeStyles(
theme => ({
iconCell: {
{
colActions: {
"&:last-child": {
paddingRight: 0
},
width: 48 + theme.spacing(0.5)
width: 80
},
colName: {
width: "auto"
},
colProducts: {
textAlign: "right",
width: 140
},
tableRow: {
cursor: "pointer"
},
textRight: {
textAlign: "right"
},
wideColumn: {
width: "60%"
}
}),
},
{ name: "DiscountCategories" }
);
@ -52,8 +53,7 @@ const numberOfColumns = 4;
const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
const {
discount: sale,
discount,
disabled,
pageInfo,
onCategoryAssign,
@ -88,19 +88,25 @@ const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
}
/>
<ResponsiveTable>
<colgroup>
<col />
<col className={classes.colName} />
<col className={classes.colProducts} />
<col className={classes.colActions} />
</colgroup>
<TableHead
colSpan={numberOfColumns}
selected={selected}
disabled={disabled}
items={maybe(() => sale.categories.edges.map(edge => edge.node))}
items={maybe(() => discount.categories.edges.map(edge => edge.node))}
toggleAll={toggleAll}
toolbar={toolbar}
>
<>
<TableCell className={classes.wideColumn}>
<TableCell className={classes.colName}>
<FormattedMessage defaultMessage="Category name" />
</TableCell>
<TableCell className={classes.textRight}>
<TableCell className={classes.colProducts}>
<FormattedMessage
defaultMessage="Products"
description="number of products"
@ -124,7 +130,7 @@ const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
</TableFooter>
<TableBody>
{renderCollection(
maybe(() => sale.categories.edges.map(edge => edge.node)),
maybe(() => discount.categories.edges.map(edge => edge.node)),
category => {
const isSelected = category ? isChecked(category.id) : false;
@ -147,13 +153,13 @@ const DiscountCategories: React.FC<DiscountCategoriesProps> = props => {
<TableCell>
{maybe<React.ReactNode>(() => category.name, <Skeleton />)}
</TableCell>
<TableCell className={classes.textRight}>
<TableCell className={classes.colProducts}>
{maybe<React.ReactNode>(
() => category.products.totalCount,
<Skeleton />
)}
</TableCell>
<TableCell className={classes.iconCell}>
<TableCell className={classes.colActions}>
<IconButton
disabled={!category || disabled}
onClick={event => {

View file

@ -28,23 +28,25 @@ export interface DiscountCollectionsProps extends ListProps, ListActions {
}
const useStyles = makeStyles(
theme => ({
iconCell: {
{
colActions: {
"&:last-child": {
paddingRight: 0
},
width: 48 + theme.spacing(0.5)
width: 80
},
colName: {
width: "auto"
},
colProducts: {
textAlign: "right",
width: 140
},
tableRow: {
cursor: "pointer"
},
textRight: {
textAlign: "right"
},
wideColumn: {
width: "60%"
}
}),
textRight: {}
},
{ name: "DiscountCollections" }
);
@ -88,6 +90,12 @@ const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
}
/>
<ResponsiveTable>
<colgroup>
<col />
<col className={classes.colName} />
<col className={classes.colProducts} />
<col className={classes.colActions} />
</colgroup>
<TableHead
colSpan={numberOfColumns}
selected={selected}
@ -96,7 +104,7 @@ const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
toggleAll={toggleAll}
toolbar={toolbar}
>
<TableCell className={classes.wideColumn}>
<TableCell className={classes.colName}>
<FormattedMessage defaultMessage="Collection name" />
</TableCell>
<TableCell className={classes.textRight}>
@ -141,19 +149,19 @@ const DiscountCollections: React.FC<DiscountCollectionsProps> = props => {
onChange={() => toggle(collection.id)}
/>
</TableCell>
<TableCell>
<TableCell className={classes.colName}>
{maybe<React.ReactNode>(
() => collection.name,
<Skeleton />
)}
</TableCell>
<TableCell className={classes.textRight}>
<TableCell className={classes.colProducts}>
{maybe<React.ReactNode>(
() => collection.products.totalCount,
<Skeleton />
)}
</TableCell>
<TableCell className={classes.iconCell}>
<TableCell className={classes.colActions}>
<IconButton
disabled={!collection || disabled}
onClick={event => {

View file

@ -44,7 +44,7 @@ const useStyles = makeStyles(
width: "auto"
},
colNameLabel: {
marginLeft: AVATAR_MARGIN
marginLeft: AVATAR_MARGIN + theme.spacing(3)
},
colPublished: {
width: 150
@ -102,6 +102,13 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
}
/>
<ResponsiveTable>
<colgroup>
<col />
<col className={classes.colName} />
<col className={classes.colType} />
<col className={classes.colPublished} />
<col className={classes.colActions} />
</colgroup>
<TableHead
colSpan={numberOfColumns}
selected={selected}
@ -124,7 +131,7 @@ const DiscountProducts: React.FC<SaleProductsProps> = props => {
description="product is published"
/>
</TableCell>
<TableCell />
<TableCell className={classes.colActions} />
</TableHead>
<TableFooter>
<TableRow>

View file

@ -17,6 +17,7 @@ import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps, SortPage } from "@saleor/types";
import { DiscountValueTypeEnum } from "@saleor/types/globalTypes";
import { getArrowDirection } from "@saleor/utils/sort";
import { getFooterColSpanWithBulkActions } from "@saleor/utils/tables";
import React from "react";
import { FormattedMessage } from "react-intl";
@ -78,7 +79,7 @@ const useStyles = makeStyles(
{ name: "VoucherList" }
);
const numberOfColumns = 7;
const numberOfColumns = 6;
const VoucherList: React.FC<VoucherListProps> = props => {
const {
@ -130,6 +131,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
? getArrowDirection(sort.asc)
: undefined
}
textAlign="right"
onClick={() => onSort(VoucherListUrlSortField.minSpent)}
className={classes.colMinSpent}
>
@ -144,6 +146,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
? getArrowDirection(sort.asc)
: undefined
}
textAlign="right"
onClick={() => onSort(VoucherListUrlSortField.startDate)}
className={classes.colStart}
>
@ -158,6 +161,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
? getArrowDirection(sort.asc)
: undefined
}
textAlign="right"
onClick={() => onSort(VoucherListUrlSortField.endDate)}
className={classes.colEnd}
>
@ -172,6 +176,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
? getArrowDirection(sort.asc)
: undefined
}
textAlign="right"
onClick={() => onSort(VoucherListUrlSortField.value)}
className={classes.colValue}
>
@ -186,6 +191,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
? getArrowDirection(sort.asc)
: undefined
}
textAlign="right"
onClick={() => onSort(VoucherListUrlSortField.limit)}
className={classes.colUses}
>
@ -195,7 +201,7 @@ const VoucherList: React.FC<VoucherListProps> = props => {
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
colSpan={getFooterColSpanWithBulkActions(vouchers, numberOfColumns)}
settings={settings}
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
onNextPage={onNextPage}

View file

@ -22,10 +22,14 @@ const useStyles = makeStyles(
height: 64,
width: 64
},
avatarSpacing: {
colAvatar: {
paddingBottom: theme.spacing(2),
paddingRight: theme.spacing(),
paddingTop: theme.spacing(2)
paddingTop: theme.spacing(2),
width: 112
},
colName: {
width: "auto"
},
label: {
paddingLeft: 0
@ -62,6 +66,11 @@ export const HomeProductList: React.FC<HomeProductListProps> = props => {
})}
/>
<ResponsiveTable>
<colgroup>
<col className={classes.colAvatar} />
<col className={classes.colName} />
<col />
</colgroup>
<TableBody>
{renderCollection(
topProducts,
@ -79,7 +88,7 @@ export const HomeProductList: React.FC<HomeProductListProps> = props => {
}
>
<TableCellAvatar
className={classes.avatarSpacing}
className={classes.colAvatar}
thumbnail={maybe(() => variant.product.thumbnail.url)}
avatarProps={classes.avatarProps}
/>

View file

@ -16,6 +16,7 @@ import { maybe, renderCollection } from "@saleor/misc";
import { MenuListUrlSortField } from "@saleor/navigation/urls";
import { ListActions, ListProps, SortPage } from "@saleor/types";
import { getArrowDirection } from "@saleor/utils/sort";
import { getFooterColSpanWithBulkActions } from "@saleor/utils/tables";
import React from "react";
import { FormattedMessage } from "react-intl";
@ -37,6 +38,9 @@ const useStyles = makeStyles(
},
colTitle: {}
},
colAction: {
width: 80
},
colItems: {
textAlign: "right"
},
@ -50,7 +54,7 @@ const useStyles = makeStyles(
{ name: "MenuList" }
);
const numberOfColumns = 4;
const numberOfColumns = 3;
const MenuList: React.FC<MenuListProps> = props => {
const {
@ -116,12 +120,12 @@ const MenuList: React.FC<MenuListProps> = props => {
id="menuListItems"
/>
</TableCellHeader>
<TableCell />
<TableCell className={classes.colAction} />
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
colSpan={getFooterColSpanWithBulkActions(menus, numberOfColumns)}
settings={settings}
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
onNextPage={onNextPage}
@ -165,6 +169,7 @@ const MenuList: React.FC<MenuListProps> = props => {
)}
</TableCell>
<IconButtonTableCell
className={classes.colAction}
disabled={disabled}
onClick={() => onDelete(menu.id)}
>

View file

@ -82,7 +82,7 @@ interface OrderFulfillmentProps {
onTrackingCodeAdd: () => void;
}
const numberOfColumns = 4;
const numberOfColumns = 5;
const OrderFulfillment: React.FC<OrderFulfillmentProps> = props => {
const {

View file

@ -38,7 +38,8 @@ import {
const useStyles = makeStyles(
theme => ({
avatar: {
paddingLeft: 0
paddingLeft: 0,
width: 64
},
colName: {
paddingLeft: 0

View file

@ -28,18 +28,16 @@ export interface PluginListProps
const useStyles = makeStyles(
theme => ({
[theme.breakpoints.up("lg")]: {
colAction: {
"& svg": {
color: theme.palette.primary.main
},
textAlign: "right" as "right"
colAction: {
"& svg": {
color: theme.palette.primary.main
},
colActive: {},
colName: {}
textAlign: "right",
width: 200
},
colActive: {
width: 200
},
colAction: {},
colActive: {},
colName: {},
link: {
cursor: "pointer"
@ -48,7 +46,7 @@ const useStyles = makeStyles(
{ name: "PluginsList" }
);
const numberOfColumns = 4;
const numberOfColumns = 3;
const PluginList: React.FC<PluginListProps> = props => {
const {

View file

@ -26,16 +26,19 @@ import {
} from "../../types/ProductTypeDetails";
const useStyles = makeStyles(
theme => ({
colName: {},
colSlug: {
width: 300
},
iconCell: {
{
colAction: {
"&:last-child": {
paddingRight: 0
},
width: 48 + theme.spacing(1.5)
width: 80
},
colGrab: {
width: 60
},
colName: {},
colSlug: {
width: 300
},
link: {
cursor: "pointer"
@ -43,7 +46,7 @@ const useStyles = makeStyles(
textLeft: {
textAlign: "left"
}
}),
},
{ name: "ProductTypeAttributes" }
);
@ -115,6 +118,13 @@ const ProductTypeAttributes: React.FC<ProductTypeAttributesProps> = props => {
}
/>
<ResponsiveTable>
<colgroup>
<col className={classes.colGrab} />
<col />
<col className={classes.colName} />
<col className={classes.colSlug} />
<col className={classes.colAction} />
</colgroup>
<TableHead
colSpan={numberOfColumns}
disabled={disabled}
@ -178,7 +188,7 @@ const ProductTypeAttributes: React.FC<ProductTypeAttributesProps> = props => {
<Skeleton />
)}
</TableCell>
<TableCell className={classes.iconCell}>
<TableCell className={classes.colAction}>
<IconButton
onClick={stopPropagation(() =>
onAttributeUnassign(attribute.id)

View file

@ -22,13 +22,18 @@ import { ProductVariantDetails_productVariant } from "../../types/ProductVariant
const useStyles = makeStyles(
theme => ({
colAvatar: {
width: 64
},
colName: {
paddingLeft: 0,
textAlign: [["left"], "!important"] as any
paddingLeft: 0
},
link: {
cursor: "pointer"
},
noHandle: {
textAlign: "right"
},
tabActive: {
"& > td:first-child": {
"&:before": {
@ -92,6 +97,7 @@ const ProductVariantNavigation: React.FC<ProductVariantNavigationProps> = props
onClick={variant ? () => onRowClick(variant.id) : undefined}
>
<TableCellAvatar
className={classes.colAvatar}
thumbnail={maybe(
() => variant.images[0].url,
fallbackThumbnail
@ -115,8 +121,17 @@ const ProductVariantNavigation: React.FC<ProductVariantNavigationProps> = props
</TableRow>
) : (
<TableRow>
<TableCellAvatar className={classes.tabActive} thumbnail={null} />
<TableCell className={classes.colName} colSpan={2}>
<TableCellAvatar
alignRight
className={classNames(
classes.colAvatar,
classes.tabActive,
classes.noHandle
)}
thumbnail={null}
colSpan={2}
/>
<TableCell className={classes.colName}>
<FormattedMessage
defaultMessage="New Variant"
description="variant name"

View file

@ -73,16 +73,19 @@ const useStyles = makeStyles(
width: 30
},
colInventory: {
width: 270
width: 200
},
colName: {},
colPrice: {
width: 150
width: 135
},
colSku: {
width: 200
}
},
colGrab: {
width: 60
},
colInventory: {
textAlign: "right"
},
@ -278,6 +281,14 @@ export const ProductVariants: React.FC<ProductVariantsProps> = props => {
)}
{hasVariants && (
<ResponsiveTable className={classes.denseTable}>
<colgroup>
<col className={classes.colGrab} />
<col />
<col className={classes.colName} />
<col className={classes.colSku} />
<col className={classes.colPrice} />
<col className={classes.colInventory} />
</colgroup>
<TableHead
colSpan={numberOfColumns}
selected={selected}

View file

@ -15,8 +15,8 @@ import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination";
import { ShippingZoneFragment } from "@saleor/fragments/types/ShippingZoneFragment";
import { maybe, renderCollection } from "@saleor/misc";
import { ICONBUTTON_SIZE } from "@saleor/theme";
import { ListActions, ListProps } from "@saleor/types";
import { getFooterColSpanWithBulkActions } from "@saleor/utils/tables";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -28,17 +28,15 @@ export interface ShippingZonesListProps extends ListProps, ListActions {
const useStyles = makeStyles(
theme => ({
[theme.breakpoints.up("lg")]: {
colCountries: {},
colName: { width: 200 }
},
alignRight: {
colAction: {
"&:last-child": {
paddingRight: theme.spacing(1)
},
width: ICONBUTTON_SIZE + theme.spacing(0.5)
width: 80
},
colCountries: {
width: 180
},
colCountries: {},
colName: {
paddingLeft: 0
},
@ -49,7 +47,7 @@ const useStyles = makeStyles(
{ name: "ShippingZonesList" }
);
const numberOfColumns = 4;
const numberOfColumns = 3;
const ShippingZonesList: React.FC<ShippingZonesListProps> = props => {
const {
@ -108,12 +106,15 @@ const ShippingZonesList: React.FC<ShippingZonesListProps> = props => {
<TableCell className={classes.colCountries}>
<FormattedMessage defaultMessage="Countries" />
</TableCell>
<TableCell />
<TableCell className={classes.colAction} />
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={4}
colSpan={getFooterColSpanWithBulkActions(
shippingZones,
numberOfColumns
)}
settings={settings}
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
onNextPage={onNextPage}
@ -161,7 +162,7 @@ const ShippingZonesList: React.FC<ShippingZonesListProps> = props => {
<Skeleton />
)}
</TableCell>
<TableCell className={classes.alignRight}>
<TableCell className={classes.colAction}>
<IconButton
color="primary"
disabled={disabled}

View file

@ -68,6 +68,8 @@ interface StaffListProps extends ListProps, SortPage<StaffListUrlSortField> {
staffMembers: StaffList_staffUsers_edges_node[];
}
const numberOfColumns = 2;
const StaffList: React.FC<StaffListProps> = props => {
const {
settings,
@ -119,7 +121,7 @@ const StaffList: React.FC<StaffListProps> = props => {
<TableFooter>
<TableRow>
<TablePagination
colSpan={3}
colSpan={numberOfColumns}
settings={settings}
hasNextPage={
pageInfo && !disabled ? pageInfo.hasNextPage : undefined

10
src/utils/tables.ts Normal file
View file

@ -0,0 +1,10 @@
export function getFooterColSpanWithBulkActions(
arr: any[],
numberOfColumns: number
): number {
if (arr === undefined || arr.length > 0) {
return numberOfColumns + 1;
}
return numberOfColumns;
}