Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: column visibility settings #583

Merged
merged 22 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e400655
feat: column visibility settings
DanielSchiavini Jan 6, 2025
2cf326b
Merge branch 'feat/table-filters' into feat/table-settings
DanielSchiavini Jan 6, 2025
c5a529b
fix: self-review and cypress tests
DanielSchiavini Jan 6, 2025
d4dbc61
fix: collateral vs debt
DanielSchiavini Jan 6, 2025
1716c75
Merge branch 'feat/table-filters' into feat/table-settings
DanielSchiavini Jan 7, 2025
caf0c43
Merge branch 'main' into feat/table-settings
DanielSchiavini Jan 7, 2025
f02aaca
Merge branch 'main' of github.com:curvefi/curve-frontend into feat/ta…
DanielSchiavini Jan 8, 2025
28014a2
feat: hide only the graphs, average graph data
DanielSchiavini Jan 8, 2025
1aae2c3
Merge branch 'main' of github.com:curvefi/curve-frontend into feat/ta…
DanielSchiavini Jan 8, 2025
9f28dc2
fix: paper box shadow
DanielSchiavini Jan 8, 2025
901e3f8
feat: implement shadows from design system depending on elevation
DanielSchiavini Jan 8, 2025
18a22a8
fix: leftover review comments #575
DanielSchiavini Jan 8, 2025
bfbcf92
fix: bad imports
DanielSchiavini Jan 8, 2025
4f0ded7
Merge branch 'main' into feat/table-settings
DanielSchiavini Jan 8, 2025
900f755
Merge branch 'main' of github.com:curvefi/curve-frontend into feat/ta…
DanielSchiavini Jan 9, 2025
8f0e35b
fix: background url
DanielSchiavini Jan 9, 2025
fae8631
Merge branch 'main' into feat/table-settings
DanielSchiavini Jan 13, 2025
27978b3
fix: chart toggle test
DanielSchiavini Jan 13, 2025
854c14c
feat: add filters to sticky header, fix switch spacing
DanielSchiavini Jan 14, 2025
ef3b1d8
fix: filter spacing, progress animation
DanielSchiavini Jan 14, 2025
b219f2e
Merge branch 'main' into feat/table-settings
DanielSchiavini Jan 14, 2025
ba17a40
fix: table header height + test
DanielSchiavini Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions apps/lend/src/globalStyle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createGlobalStyle } from 'styled-components'
import { CURVE_ASSETS_URL } from '@/ui/utils'

const GlobalStyle = createGlobalStyle`
/* || GENERAL STYLES */
Expand All @@ -17,11 +16,6 @@ const GlobalStyle = createGlobalStyle`

color: var(--page--text-color);
background-color: var(--page--background-color);
/* background-image: url(${CURVE_ASSETS_URL + '/branding/curve-app-header.webp'});
background-size: auto 400px;
background-repeat: repeat-x;
background-attachment: fixed; */
//background-position-y: var(--header-height);

&.scrollSmooth {
scroll-behavior: smooth;
Expand Down
7 changes: 4 additions & 3 deletions apps/lend/src/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'
import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document'
import { ServerStyleSheet } from 'styled-components'
import { RootCssProperties } from '@ui-kit/themes/typography'
import { CURVE_LOGO_URL } from '@/ui/utils/utilsConstants'

const injectIpfsPrefix = `
(function () {
Expand Down Expand Up @@ -65,7 +66,7 @@ export default class CurveDocument extends Document {
property="og:description"
content="Curve-frontend is a user interface application designed to connect to Curve's deployment of smart contracts."
/>
<meta property="og:image" content="https://cdn.jsdelivr.net/gh/curvefi/curve-assets/branding/logo.png" />
<meta property="og:image" content={CURVE_LOGO_URL} />

{/* Twitter */}
<meta property="twitter:card" content="summary" />
Expand All @@ -75,7 +76,7 @@ export default class CurveDocument extends Document {
property="twitter:description"
content="Curve-frontend is a user interface application designed to connect to Curve's deployment of smart contracts."
/>
<meta property="twitter:image" content="https://cdn.jsdelivr.net/gh/curvefi/curve-assets/branding/logo.png" />
<meta property="twitter:image" content={CURVE_LOGO_URL} />

<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const LendingMarketsFilters = ({
setColumnFilter: (id: string, value: unknown) => void
data: LendingVault[]
}) => (
<Grid container spacing={Spacing.md} paddingBlock={Spacing.sm}>
<Grid container spacing={Spacing.sm} paddingTop={Spacing.sm}>
<Grid size={{ mobile: 12, tablet: 4 }}>
<MultiSelectFilter
field="blockchainId"
Expand Down
57 changes: 44 additions & 13 deletions apps/loan/src/components/PageLlamaMarkets/LendingMarketsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ import {
import { LendingMarketsFilters } from '@/components/PageLlamaMarkets/LendingMarketsFilters'
import { useSortFromQueryString } from '@ui-kit/hooks/useSortFromQueryString'
import { DeepKeys } from '@tanstack/table-core/build/lib/utils'
import {
isFeatureVisible,
useVisibilitySettings,
VisibilityGroup,
} from '@ui-kit/shared/ui/TableVisibilitySettingsPopover'

const { ColumnWidth, Spacing, MinWidth, MaxWidth } = SizesAndSpaces
const { ColumnWidth, Spacing, MaxWidth } = SizesAndSpaces

const columnHelper = createColumnHelper<LendingVault>()

Expand All @@ -28,6 +33,8 @@ const hidden = (id: DeepKeys<LendingVault>) =>
meta: { hidden: true },
})

const [borrowChartId, lendChartId] = ['borrowChart', 'lendChart']

/** Columns for the lending markets table. */
const columns = [
columnHelper.accessor('assets', {
Expand All @@ -37,13 +44,13 @@ const columns = [
}),
columnHelper.accessor('rates.borrowApyPcent', {
header: t`7D Borrow Rate`,
cell: (c) => <LineGraphCell vault={c.row.original} type="borrow" />,
cell: (c) => <LineGraphCell vault={c.row.original} type="borrow" showChart={isFeatureVisible(c, borrowChartId)} />,
meta: { type: 'numeric' },
size: ColumnWidth.md,
}),
columnHelper.accessor('rates.lendApyPcent', {
header: t`7D Supply Yield`,
cell: (c) => <LineGraphCell vault={c.row.original} type="lend" />,
cell: (c) => <LineGraphCell vault={c.row.original} type="lend" showChart={isFeatureVisible(c, lendChartId)} />,
meta: { type: 'numeric' },
size: ColumnWidth.md,
}),
Expand All @@ -59,13 +66,32 @@ const columns = [
meta: { type: 'numeric' },
size: ColumnWidth.sm,
}),
// following columns are used to configure and filter tanstack, but they are displayed together in PoolTitleCell
hidden('blockchainId'),
hidden('assets.collateral.symbol'),
hidden('assets.borrowed.symbol'),
] satisfies ColumnDef<LendingVault, any>[]

const DEFAULT_SORT = [{ id: 'totalSupplied.usdTotal', desc: true }]

const DEFAULT_VISIBILITY: VisibilityGroup[] = [
{
label: t`Markets`,
options: [
{ label: t`Available Liquidity`, id: 'totalSupplied.usdTotal', active: true, type: 'column' },
{ label: t`Utilization`, id: 'utilizationPercent', active: true, type: 'column' },
],
},
{
label: t`Borrow`,
options: [{ label: t`Chart`, id: borrowChartId, active: true, type: 'feature' }],
},
{
label: t`Lend`,
options: [{ label: t`Chart`, id: lendChartId, active: true, type: 'feature' }],
},
]

export const LendingMarketsTable = ({
DanielSchiavini marked this conversation as resolved.
Show resolved Hide resolved
onReload,
data,
Expand All @@ -76,6 +102,8 @@ export const LendingMarketsTable = ({
headerHeight: string
}) => {
const [columnFilters, columnFiltersById, setColumnFilter] = useColumnFilters()
const { columnSettings, columnVisibility, featureVisibility, toggleVisibility } =
useVisibilitySettings(DEFAULT_VISIBILITY)

const [sorting, onSortingChange] = useSortFromQueryString(DEFAULT_SORT)
const table = useReactTable({
Expand All @@ -84,7 +112,7 @@ export const LendingMarketsTable = ({
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
state: { sorting, columnFilters },
state: { sorting, columnVisibility, featureVisibility, columnFilters },
onSortingChange,
maxMultiSortColCount: 3, // allow 3 columns to be sorted at once
})
Expand All @@ -97,15 +125,18 @@ export const LendingMarketsTable = ({
maxWidth: MaxWidth.table,
}}
>
<TableFilters
title={t`Llamalend Markets`}
subtitle={t`Select a market to view more details`}
onReload={onReload}
learnMoreUrl="https://docs.curve.fi/lending/overview/"
>
<LendingMarketsFilters columnFilters={columnFiltersById} setColumnFilter={setColumnFilter} data={data} />
</TableFilters>
<DataTable table={table} headerHeight={headerHeight} rowHeight={'3xl'} emptyText={t`No markets found`} />
<DataTable table={table} headerHeight={headerHeight} rowHeight="3xl" emptyText={t`No markets found`}>
<TableFilters
title={t`Llamalend Markets`}
subtitle={t`Select a market to view more details`}
onReload={onReload}
learnMoreUrl="https://docs.curve.fi/lending/overview/"
visibilityGroups={columnSettings}
toggleVisibility={toggleVisibility}
>
<LendingMarketsFilters columnFilters={columnFiltersById} setColumnFilter={setColumnFilter} data={data} />
</TableFilters>
</DataTable>
</Stack>
)
}
79 changes: 59 additions & 20 deletions apps/loan/src/components/PageLlamaMarkets/cells/LineGraphCell.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,90 @@
import { LendingSnapshot, useLendingSnapshots } from '@/entities/lending'
import { LendingVault } from '@/entities/vaults'
import { Line, LineChart } from 'recharts'
import { Line, LineChart, YAxis } from 'recharts'
import { useTheme } from '@mui/material/styles'
import { DesignSystem } from '@ui-kit/themes/design'
import Box from '@mui/material/Box'
import Stack from '@mui/material/Stack'
import Skeleton from '@mui/material/Skeleton'
import Typography from '@mui/material/Typography'
import { t } from '@lingui/macro'
import { useMemo } from 'react'
import { meanBy } from 'lodash'
import Box from '@mui/material/Box'

const graphSize = { width: 172, height: 48 }

type GraphType = 'borrow' | 'lend'

/**
* Get the color for the line graph. Will be green if the last value is higher than the first, red if lower, and blue if equal.
*/
function getColor(design: DesignSystem, data: LendingSnapshot[], type: GraphType) {
if (!data.length) return undefined
const first = data[0][`${type}_apy`]
const last = data[data.length - 1][`${type}_apy`]
return design.Text.TextColors[last === first ? 'Info' : last < first ? 'Error' : 'Success']
}

export const LineGraphCell = ({ vault, type }: { vault: LendingVault; type: GraphType }) => {
/** Center the y-axis around the first value */
const calculateDomain =
(first: number) =>
([dataMin, dataMax]: [number, number]): [number, number] => {
const diff = Math.max(dataMax - first, first - dataMin)
return [first - diff, first + diff]
}

/**
* Line graph cell that displays the average historical APY for a vault and a given type (borrow or lend).
*/
export const LineGraphCell = ({
vault,
type,
showChart,
}: {
vault: LendingVault
type: GraphType
showChart: boolean // chart is hidden depending on the chart settings
}) => {
const { data: snapshots, isLoading } = useLendingSnapshots({
blockchainId: vault.blockchainId,
contractAddress: vault.controllerAddress,
})
const { design } = useTheme()
const value = vault.rates[`${type}ApyPcent`]
if (value == null) {
const currentValue = vault.rates[`${type}ApyPcent`]
const snapshotKey = `${type}_apy` as const

const rate = useMemo(
() => (snapshots?.length ? meanBy(snapshots, (row) => row[snapshotKey]) : currentValue),
[snapshots, currentValue, snapshotKey],
)
if (rate == null) {
return '-'
}

return (
<Stack direction="row" alignItems="center" justifyContent="end" gap={3} data-testid={`line-graph-cell-${type}`}>
{value.toPrecision(4)}%
{snapshots?.length ? (
<LineChart data={snapshots} {...graphSize}>
<Line
type="monotone"
dataKey={`${type}_apy`}
stroke={getColor(design, snapshots, type)}
strokeWidth={1}
dot={<></>}
/>
</LineChart>
) : isLoading ? (
<Skeleton {...graphSize} />
) : (
<Box sx={graphSize} />
{rate.toPrecision(4)}%
{showChart && (
<Box data-testid={`line-graph-${type}`}>
{snapshots?.length ? (
<LineChart data={snapshots} {...graphSize} compact>
<YAxis hide type="number" domain={calculateDomain(snapshots[0][snapshotKey])} />
<Line
type="monotone"
dataKey={snapshotKey}
stroke={getColor(design, snapshots, type)}
strokeWidth={1}
dot={<></>}
/>
</LineChart>
) : isLoading ? (
<Skeleton {...graphSize} />
) : (
<Typography sx={{ ...graphSize, alignContent: 'center', textAlign: 'left' }} variant="bodyXsBold">
{t`No historical data`}
</Typography>
)}
</Box>
)}
</Stack>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import Typography from '@mui/material/Typography'
import { PoolBadges } from '@/components/PageLlamaMarkets/cells/PoolTitleCell/PoolBadges'
import { PoolWarnings } from '@/components/PageLlamaMarkets/cells/PoolTitleCell/PoolWarnings'
import { getImageBaseUrl } from '@/ui/utils'
import { cleanColumnId } from '@ui-kit/shared/ui/TableVisibilitySettingsPopover'

const { Spacing } = SizesAndSpaces

export const PoolTitleCell = ({ getValue, row }: CellContext<LendingVault, LendingVault['assets']>) => {
const coins = useMemo(() => Object.values(getValue()), [getValue])
export const PoolTitleCell = ({ getValue, row, table }: CellContext<LendingVault, LendingVault['assets']>) => {
const showCollateral = table.getColumn(cleanColumnId('assets.collateral.symbol'))!.getIsVisible()
const coins = useMemo(() => {
const { borrowed, collateral } = getValue()
return showCollateral ? [collateral, borrowed] : [borrowed]
}, [getValue, showCollateral])
const { blockchainId } = row.original
const imageBaseUrl = getImageBaseUrl(blockchainId)
return (
Expand Down
1 change: 0 additions & 1 deletion apps/loan/src/components/PageLlamaMarkets/cells/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ export * from './CompactUsdCell'
export * from './PoolTitleCell'
export * from './LineGraphCell'
export * from './UtilizationCell'
export { LinearProgress } from '@ui-kit/shared/ui/LinearProgress'
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Fragment, useMemo } from 'react'
import { useMemo } from 'react'
import Select from '@mui/material/Select'
import Slider from '@mui/material/Slider'
import { DeepKeys } from '@tanstack/table-core/build/lib/utils'
import { get } from 'lodash'
import Stack from '@mui/material/Stack'
import Typography from '@mui/material/Typography'
import { cleanColumnId } from '@ui-kit/shared/ui/TableVisibilitySettingsPopover'

/**
* Get the maximum value from a field in an array of objects.
Expand All @@ -31,7 +32,7 @@ export const MinimumSliderFilter = <T extends unknown>({
field: DeepKeys<T>
format: (value: number) => string
}) => {
const id = field.replaceAll('.', '_')
const id = cleanColumnId(field)
const max = useMemo(() => getMaxValueFromData(data, field), [data, field])
const [value] = (columnFilters[id] ?? [0, max]) as [number, number] // tanstack expects a [min, max] tuple
return (
Expand All @@ -51,7 +52,7 @@ export const MinimumSliderFilter = <T extends unknown>({
)}
value="" // we actually don't use the value of the select, but it needs to be set to avoid a warning
>
<Stack paddingBlock={3} paddingInline={4} direction="row" spacing={6}>
<Stack paddingBlock={3} paddingInline={4} direction="row" spacing={6} alignItems="center">
<Typography>{format(0)}</Typography>
<Slider
data-testid={`slider-${id}`}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Fragment, ReactNode, useMemo } from 'react'
import { ReactNode, useMemo } from 'react'
import { get, identity, sortBy, sortedUniq } from 'lodash'
import Select from '@mui/material/Select'
import Typography from '@mui/material/Typography'
import MenuItem from '@mui/material/MenuItem'
import { DeepKeys } from '@tanstack/table-core/build/lib/utils'
import { cleanColumnId } from '@ui-kit/shared/ui/TableVisibilitySettingsPopover'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'

const { Spacing } = SizesAndSpaces
Expand Down Expand Up @@ -36,7 +37,7 @@ export const MultiSelectFilter = <T extends unknown>({
renderItem?: (value: string) => ReactNode
}) => {
const options = useMemo(() => getSortedStrings(data, field), [data, field])
const id = field.replaceAll('.', '_')
const id = cleanColumnId(field)
const value = (columnFilters[id] ?? []) as string[]
return (
<Select
Expand Down
6 changes: 0 additions & 6 deletions apps/loan/src/globalStyle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createGlobalStyle } from 'styled-components'
import { CURVE_ASSETS_URL } from '@/ui/utils'

const GlobalStyle = createGlobalStyle`
/* || GENERAL STYLES */
Expand All @@ -17,11 +16,6 @@ const GlobalStyle = createGlobalStyle`

color: var(--page--text-color);
background-color: var(--page--background-color);
/* background-image: url(${CURVE_ASSETS_URL + '/branding/curve-app-header.webp'}); */
/* background-size: auto 400px;
background-repeat: repeat-x;
background-attachment: fixed; */
//background-position-y: var(--header-height);

&.scrollSmooth {
scroll-behavior: smooth;
Expand Down
Loading
Loading