Skip to content

Commit

Permalink
merge: 'main'
Browse files Browse the repository at this point in the history
  • Loading branch information
Alunara committed Jan 14, 2025
2 parents 3f97303 + f72d959 commit 366f1c9
Show file tree
Hide file tree
Showing 35 changed files with 551 additions and 185 deletions.
2 changes: 1 addition & 1 deletion apps/dao/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"typescript": "*"
},
"dependencies": {
"@curvefi/api": "^2.65.26",
"@curvefi/api": "^2.65.27",
"@hookform/error-message": "^2.0.1",
"@hookform/resolvers": "^3.9.0",
"@lingui/react": "^4.6.0",
Expand Down
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 = ({
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

0 comments on commit 366f1c9

Please sign in to comment.