Update ListTable display of items.

This commit is contained in:
Mike Cao 2023-10-15 13:12:29 -07:00
parent 934b107e5e
commit 8d85e3fcdb
10 changed files with 115 additions and 21 deletions

View File

@ -9,7 +9,7 @@ import WebsiteChart from './WebsiteChart';
import WebsiteMenuView from './WebsiteMenuView'; import WebsiteMenuView from './WebsiteMenuView';
import WebsiteHeader from './WebsiteHeader'; import WebsiteHeader from './WebsiteHeader';
import WebsiteMetricsBar from './WebsiteMetricsBar'; import WebsiteMetricsBar from './WebsiteMetricsBar';
import WebsiteTableView from '../WebsiteTableView'; import WebsiteTableView from './WebsiteTableView';
export default function WebsiteDetails({ websiteId }) { export default function WebsiteDetails({ websiteId }) {
const { data: website, isLoading, error } = useWebsite(websiteId); const { data: website, isLoading, error } = useWebsite(websiteId);

View File

@ -1,4 +1,4 @@
import { Text } from 'react-basics'; import { Icons, Icon, Text } from 'react-basics';
import BrowsersTable from 'components/metrics/BrowsersTable'; import BrowsersTable from 'components/metrics/BrowsersTable';
import CountriesTable from 'components/metrics/CountriesTable'; import CountriesTable from 'components/metrics/CountriesTable';
import RegionsTable from 'components/metrics/RegionsTable'; import RegionsTable from 'components/metrics/RegionsTable';
@ -110,6 +110,9 @@ export default function WebsiteMenuView({ websiteId, websiteDomain }) {
<div className={styles.layout}> <div className={styles.layout}>
<div className={styles.menu}> <div className={styles.menu}>
<LinkButton href={pathname} className={styles.back}> <LinkButton href={pathname} className={styles.back}>
<Icon rotate={180}>
<Icons.ArrowRight />
</Icon>
<Text>{formatMessage(labels.back)}</Text> <Text>{formatMessage(labels.back)}</Text>
</LinkButton> </LinkButton>
<SideNav items={items} selectedKey={view} shallow={true} /> <SideNav items={items} selectedKey={view} shallow={true} />
@ -122,6 +125,7 @@ export default function WebsiteMenuView({ websiteId, websiteDomain }) {
animate={false} animate={false}
showFilters={true} showFilters={true}
virtualize={true} virtualize={true}
itemCount={25}
/> />
</div> </div>
</div> </div>

View File

@ -3,11 +3,15 @@ import Link from 'next/link';
import { useLocale } from 'components/hooks'; import { useLocale } from 'components/hooks';
import styles from './LinkButton.module.css'; import styles from './LinkButton.module.css';
export function LinkButton({ href, className, children }) { export function LinkButton({ href, className, variant, children }) {
const { dir } = useLocale(); const { dir } = useLocale();
return ( return (
<Link className={classNames(styles.button, className)} href={href} dir={dir}> <Link
className={classNames(styles.button, className, { [styles[variant]]: true })}
href={href}
dir={dir}
>
{children} {children}
</Link> </Link>
); );

View File

@ -26,3 +26,82 @@
.button:visited { .button:visited {
color: var(--base900); color: var(--base900);
} }
.button.disabled {
color: var(--disabled-color) !important;
background-color: var(--disabled-background) !important;
border-color: transparent !important;
pointer-events: none;
}
.button.primary {
color: var(--light50);
background: var(--primary400);
}
.button.primary:hover {
color: var(--light50);
background: var(--primary500);
}
.button.primary:active {
color: var(--light50);
background: var(--primary600);
}
.button.secondary {
border: 1px solid var(--border-color);
background: var(--base50);
}
.button.secondary:hover {
background: var(--base75);
}
.button.secondary:active {
background: var(--base100);
}
.button.quiet {
color: var(--base900);
background: transparent;
}
.button.quiet:hover {
background: var(--base100);
}
.button.quiet:active {
background: var(--base200);
}
.button.danger {
color: var(--light50);
background: var(--red800);
}
.button.danger:hover {
color: var(--light50);
background: var(--red900);
}
.button.danger:active {
color: var(--light50);
background: var(--red1000);
}
.button.size-sm {
font-size: var(--font-size-sm);
height: calc(var(--base-height) * 0.75);
padding: 0 calc(var(--size600) * 0.75);
}
.button.size-md {
font-size: var(--font-size-md);
}
.button.size-lg {
font-size: var(--font-size-lg);
height: calc(var(--base-height) * 1.25);
padding: 0 calc(var(--size600) * 1.25);
}

View File

@ -26,7 +26,7 @@ export function Pager({ page, pageSize, count, onPageChange, className }) {
return ( return (
<div className={classNames(styles.pager, className)}> <div className={classNames(styles.pager, className)}>
<div>{formatMessage(labels.numberOfRecords, { x: count })}</div> <div className={styles.count}>{formatMessage(labels.numberOfRecords, { x: count })}</div>
<div className={styles.nav}> <div className={styles.nav}>
<Button onClick={() => handlePageChange(-1)} disabled={firstPage}> <Button onClick={() => handlePageChange(-1)} disabled={firstPage}>
<Icon rotate={90}> <Icon rotate={90}>

View File

@ -16,6 +16,11 @@
justify-content: center; justify-content: center;
} }
.count {
color: var(--base600);
font-weight: 700;
}
@media only screen and (max-width: 992px) { @media only screen and (max-width: 992px) {
.pager { .pager {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);

View File

@ -1,4 +1,3 @@
import useMeasure from 'react-use-measure';
import { FixedSizeList } from 'react-window'; import { FixedSizeList } from 'react-window';
import { useSpring, animated, config } from '@react-spring/web'; import { useSpring, animated, config } from '@react-spring/web';
import classNames from 'classnames'; import classNames from 'classnames';
@ -7,6 +6,8 @@ import { formatLongNumber } from 'lib/format';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import styles from './ListTable.module.css'; import styles from './ListTable.module.css';
const ITEM_SIZE = 30;
export function ListTable({ export function ListTable({
data = [], data = [],
title, title,
@ -16,9 +17,9 @@ export function ListTable({
animate = true, animate = true,
virtualize = false, virtualize = false,
showPercentage = true, showPercentage = true,
itemCount = 10,
}) { }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const [ref, bounds] = useMeasure();
const getRow = row => { const getRow = row => {
const { x: label, y: value, z: percent } = row; const { x: label, y: value, z: percent } = row;
@ -45,10 +46,14 @@ export function ListTable({
<div className={styles.title}>{title}</div> <div className={styles.title}>{title}</div>
<div className={styles.metric}>{metric}</div> <div className={styles.metric}>{metric}</div>
</div> </div>
<div ref={ref} className={styles.body}> <div className={styles.body}>
{data?.length === 0 && <Empty />} {data?.length === 0 && <Empty />}
{virtualize && data.length > 0 ? ( {virtualize && data.length > 0 ? (
<FixedSizeList height={bounds.height} itemCount={data.length} itemSize={30}> <FixedSizeList
height={itemCount * ITEM_SIZE}
itemCount={data.length}
itemSize={ITEM_SIZE}
>
{Row} {Row}
</FixedSizeList> </FixedSizeList>
) : ( ) : (

View File

@ -1,6 +1,5 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Loading, Icon, Text, Button } from 'react-basics'; import { Loading, Icon, Text } from 'react-basics';
import Link from 'next/link';
import firstBy from 'thenby'; import firstBy from 'thenby';
import classNames from 'classnames'; import classNames from 'classnames';
import useApi from 'components/hooks/useApi'; import useApi from 'components/hooks/useApi';
@ -8,12 +7,13 @@ import { percentFilter } from 'lib/filters';
import useDateRange from 'components/hooks/useDateRange'; import useDateRange from 'components/hooks/useDateRange';
import useNavigation from 'components/hooks/useNavigation'; import useNavigation from 'components/hooks/useNavigation';
import ErrorMessage from 'components/common/ErrorMessage'; import ErrorMessage from 'components/common/ErrorMessage';
import LinkButton from 'components/common/LinkButton';
import ListTable from './ListTable'; import ListTable from './ListTable';
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants'; import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
import Icons from 'components/icons'; import Icons from 'components/icons';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import styles from './MetricsTable.module.css';
import useLocale from 'components/hooks/useLocale'; import useLocale from 'components/hooks/useLocale';
import styles from './MetricsTable.module.css';
export function MetricsTable({ export function MetricsTable({
websiteId, websiteId,
@ -103,14 +103,12 @@ export function MetricsTable({
{data && !error && <ListTable {...props} data={filteredData} className={className} />} {data && !error && <ListTable {...props} data={filteredData} className={className} />}
<div className={styles.footer}> <div className={styles.footer}>
{data && !error && limit && ( {data && !error && limit && (
<Link href={makeUrl({ view: type })}> <LinkButton href={makeUrl({ view: type })} variant="quiet">
<Button variant="quiet"> <Text>{formatMessage(labels.more)}</Text>
<Text>{formatMessage(labels.more)}</Text> <Icon size="sm" rotate={dir === 'rtl' ? 180 : 0}>
<Icon size="sm" rotate={dir === 'rtl' ? 180 : 0}> <Icons.ArrowRight />
<Icons.ArrowRight /> </Icon>
</Icon> </LinkButton>
</Button>
</Link>
)} )}
</div> </div>
</div> </div>

View File

@ -1,7 +1,6 @@
.container { .container {
position: relative; position: relative;
min-height: 430px; min-height: 430px;
height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;