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: market badges #654

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5868805
refactor: rename PoolTitleCell
DanielSchiavini Jan 29, 2025
fac74ef
feat: TokenPair component with chain icon
DanielSchiavini Jan 29, 2025
efbb440
feat: chips and badges
DanielSchiavini Jan 29, 2025
0034738
Merge branch 'main' of github.com:curvefi/curve-frontend into feat/mu…
DanielSchiavini Jan 30, 2025
43ee75c
feat: chip sizes and typography
DanielSchiavini Jan 30, 2025
ebbef25
fix: ChipProps thanks to @0xAlunara
DanielSchiavini Jan 30, 2025
f436d46
Merge branch 'main' into feat/mui-chip
DanielSchiavini Jan 30, 2025
c010513
fix: custom padding for clickable chips with icon
DanielSchiavini Jan 30, 2025
a7ee9f4
fix: border radius, doc: mui-chip
DanielSchiavini Jan 31, 2025
e38df81
fix: highlight background
DanielSchiavini Jan 31, 2025
ee9dee6
fix: separate highlight and selected colors
DanielSchiavini Jan 31, 2025
f54e51f
Merge branch 'feat/mui-chip' into feat/pool-badges
DanielSchiavini Jan 31, 2025
ba2b325
feat: market badges (with fake data)
DanielSchiavini Jan 31, 2025
0f14636
feat: only show favorite button on hover
DanielSchiavini Jan 31, 2025
315e3e4
feat: market link
DanielSchiavini Jan 31, 2025
9fdcb96
fix: connect wallet in llama markets
DanielSchiavini Jan 31, 2025
6240e79
refactor: delete MarketLink component
DanielSchiavini Jan 31, 2025
5b80580
Update packages/curve-ui-kit/src/themes/chip/mui-chip.ts
0xAlunara Feb 1, 2025
d377bcd
Merge branch 'main' of github.com:curvefi/curve-frontend into feat/mu…
DanielSchiavini Feb 3, 2025
77618a1
fix: chip typography for L/XL
DanielSchiavini Feb 3, 2025
d120d50
fix: chip font size
DanielSchiavini Feb 3, 2025
61fe630
Merge branch 'feat/mui-chip' into feat/pool-badges
DanielSchiavini Feb 3, 2025
3009f12
refactor: use prices API
DanielSchiavini Feb 3, 2025
ac9ca38
feat: MarketFilterChips
DanielSchiavini Feb 3, 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
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ const { Spacing } = SizesAndSpaces
* This is used in the lending markets filters to display collateral and debt tokens.
*/
const Token = ({ symbol, data, field }: { symbol: string; data: LlamaMarket[]; field: 'collateral' | 'borrowed' }) => {
const { blockchainId, address } = useMemo(
const { chain, address } = useMemo(
() => data.find((d) => d.assets[field].symbol === symbol)!.assets[field],
[data, field, symbol],
)
return (
<>
<TokenIcon imageBaseUrl={getImageBaseUrl(blockchainId)} token={symbol} address={address} size="mui-md" />
<TokenIcon imageBaseUrl={getImageBaseUrl(chain)} token={symbol} address={address} size="mui-md" />
<Typography component="span" variant="bodyMBold">
{symbol}
</Typography>
Expand All @@ -45,12 +45,12 @@ export const LendingMarketsFilters = ({
<Grid container spacing={Spacing.sm} paddingTop={Spacing.sm}>
<Grid size={{ mobile: 12, tablet: 4 }}>
<MultiSelectFilter
field="blockchainId"
renderItem={(blockchainId) => (
field="chain"
renderItem={(chain) => (
<>
<ChainIcon blockchainId={blockchainId} size="md" />
<ChainIcon blockchainId={chain} size="md" />
<Typography component="span" variant="bodyMBold">
{capitalize(blockchainId)}
{capitalize(chain)}
</Typography>
</>
)}
Expand Down Expand Up @@ -79,7 +79,7 @@ export const LendingMarketsFilters = ({

<Grid size={{ mobile: 12, tablet: 6 }}>
<MinimumSliderFilter
field="totalSupplied.usdTotal"
field="liquidityUsd"
title={t`Min Liquidity`}
format={(value) => formatNumber(value, { currency: 'USD' })}
{...props}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Stack from '@mui/material/Stack'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { TableFilters, useColumnFilters } from '@ui-kit/shared/ui/TableFilters'
import { t } from '@lingui/macro'
import { CompactUsdCell, LineGraphCell, PoolTitleCell, RateCell, UtilizationCell } from './cells'
import { CompactUsdCell, LineGraphCell, MarketTitleCell, RateCell, UtilizationCell } from './cells'
import { DataTable } from '@ui-kit/shared/ui/DataTable'
import { LlamaMarket } from '@/loan/entities/llama-markets'
import {
Expand All @@ -17,6 +17,10 @@ import { LendingMarketsFilters } from '@/loan/components/PageLlamaMarkets/Lendin
import { useSortFromQueryString } from '@ui-kit/hooks/useSortFromQueryString'
import { DeepKeys } from '@tanstack/table-core/build/lib/utils'
import { useVisibilitySettings, VisibilityGroup } from '@ui-kit/shared/ui/TableVisibilitySettingsPopover'
import Chip from '@mui/material/Chip'
import { FavoriteHeartIcon, HeartIcon } from '@ui-kit/shared/icons/HeartIcon'
import { PointsIcon } from '@ui-kit/shared/icons/PointsIcon'
import { MarketsFilterChips } from '@/loan/components/PageLlamaMarkets/MarketsFilterChips'

const { ColumnWidth, Spacing, MaxWidth } = SizesAndSpaces

Expand All @@ -35,7 +39,7 @@ const [borrowChartId, lendChartId] = ['borrowChart', 'lendChart']
const columns = [
columnHelper.accessor('assets', {
header: t`Collateral • Borrow`,
cell: PoolTitleCell,
cell: MarketTitleCell,
size: ColumnWidth.lg,
}),
columnHelper.accessor('rates.borrow', {
Expand Down Expand Up @@ -72,25 +76,27 @@ const columns = [
meta: { type: 'numeric' },
size: ColumnWidth.sm,
}),
columnHelper.accessor('totalSupplied.usdTotal', {
columnHelper.accessor('liquidityUsd', {
header: () => t`Available Liquidity`,
cell: CompactUsdCell,
meta: { type: 'numeric' },
size: ColumnWidth.sm,
}),
// following columns are used to configure and filter tanstack, but they are displayed together in PoolTitleCell
hidden('blockchainId'),
// Following columns are used in tanstack filter, but they are displayed together in MarketTitleCell
hidden('chain'),
hidden('assets.collateral.symbol'),
hidden('assets.borrowed.symbol'),
hidden('isFavorite'),
hidden('hasPoints'),
] satisfies ColumnDef<LlamaMarket, any>[]

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

const DEFAULT_VISIBILITY: VisibilityGroup[] = [
{
label: t`Markets`,
options: [
{ label: t`Available Liquidity`, id: 'totalSupplied.usdTotal', active: true },
{ label: t`Available Liquidity`, id: 'liquidityUsd', active: true },
{ label: t`Utilization`, id: 'utilizationPercent', active: true },
],
},
Expand Down Expand Up @@ -144,8 +150,11 @@ export const LendingMarketsTable = ({
learnMoreUrl="https://docs.curve.fi/lending/overview/"
visibilityGroups={columnSettings}
toggleVisibility={toggleVisibility}
collapsible={
<LendingMarketsFilters columnFilters={columnFiltersById} setColumnFilter={setColumnFilter} data={data} />
}
>
<LendingMarketsFilters columnFilters={columnFiltersById} setColumnFilter={setColumnFilter} data={data} />
<MarketsFilterChips columnFiltersById={columnFiltersById} setColumnFilter={setColumnFilter} />
</TableFilters>
</DataTable>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Chip from '@mui/material/Chip'
import { t } from '@lingui/macro'
import { HeartIcon } from '@ui-kit/shared/icons/HeartIcon'
import { PointsIcon } from '@ui-kit/shared/icons/PointsIcon'
import { LlamaMarketType } from '@/loan/entities/llama-markets'
import Stack from '@mui/material/Stack'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'

const { Spacing } = SizesAndSpaces

export const MarketsFilterChips = ({
columnFiltersById,
setColumnFilter,
}: {
columnFiltersById: Record<string, unknown>
setColumnFilter: (id: string, value: unknown) => void
}) => {
console.log(columnFiltersById)
const isFavoriteFiltered = columnFiltersById['isFavorite']
const toggleFilterFavorite = () => setColumnFilter('isFavorite', !isFavoriteFiltered)
const hasPointsFiltered = columnFiltersById['hasPoints']
const toggleHasPoints = () => setColumnFilter('hasPoints', !hasPointsFiltered)
const showMintMarkets = columnFiltersById['type'] !== LlamaMarketType.Mint
const toggleShowMintMarkets = () => setColumnFilter('type', showMintMarkets ? undefined : LlamaMarketType.Mint)
const showPoolMarkets = columnFiltersById['type'] !== LlamaMarketType.Pool
const toggleShowPoolMarkets = () => setColumnFilter('type', showPoolMarkets ? undefined : LlamaMarketType.Pool)

return (
<Stack direction="row" gap={Spacing.lg}>
<Stack direction="row" gap="4px">
<Chip
clickable
label={t`Favorites`}
color={isFavoriteFiltered ? 'selected' : 'unselected'}
onClick={toggleFilterFavorite}
icon={<HeartIcon />}
/>
<Chip
clickable
label={t`Points`}
color={hasPointsFiltered ? 'selected' : 'unselected'}
onClick={toggleHasPoints}
icon={<PointsIcon />}
/>
</Stack>
<Stack direction="row" gap="4px">
<Chip
clickable
label={t`Mint Markets`}
color={showMintMarkets ? 'selected' : 'unselected'}
onDelete={showMintMarkets ? toggleShowMintMarkets : undefined}
/>
<Chip
clickable
label={t`Pool Markets`}
color={showPoolMarkets ? 'selected' : 'unselected'}
onDelete={showPoolMarkets ? toggleShowPoolMarkets : undefined}
/>
</Stack>
</Stack>
)
}
3 changes: 3 additions & 0 deletions apps/main/src/loan/components/PageLlamaMarkets/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { useHeaderHeight } from '@ui-kit/widgets/Header'
import useStore from '@/loan/store/useStore'
import { useLlamaMarkets } from '@/loan/entities/llama-markets'
import usePageOnMount from '@/loan/hooks/usePageOnMount'
import { useLocation, useNavigate, useParams } from 'react-router-dom'

const onReload = () => invalidateLendingVaults({})

Expand All @@ -22,6 +24,7 @@ export const PageLlamaMarkets = () => {
const { data, isFetching, isError } = useLlamaMarkets() // todo: show errors and loading state
const bannerHeight = useStore((state) => state.layout.height.globalAlert)
const headerHeight = useHeaderHeight(bannerHeight)
usePageOnMount(useParams(), useLocation(), useNavigate()) // required for connecting wallet
return (
<Box sx={{ marginBlockEnd: Spacing.xxl }}>
<DocumentHead title={t`Llamalend Markets`} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,28 @@ type RateCellProps = {
export const LineGraphCell = ({ market, type }: RateCellProps) => {
const { snapshots, snapshotKey, isLoading, rate } = useSnapshots(market, type)
const { design } = useTheme()
if (rate == null) {
return '-'
}
return (
<Box data-testid={`line-graph-${type}`}>
{snapshots?.length ? (
<LineChart data={snapshots} {...graphSize} compact>
<YAxis hide type="number" domain={calculateDomain(snapshots[0][snapshotKey] as number)} />
<Line
type="monotone"
dataKey={snapshotKey}
stroke={getColor(design, snapshots, snapshotKey)}
strokeWidth={1}
dot={<></>}
/>
</LineChart>
) : isLoading ? (
<Skeleton {...graphSize} />
) : (
<Typography sx={{ ...graphSize, alignContent: 'center', textAlign: 'left' }} variant="bodyXsBold">
{t`No historical data`}
</Typography>
)}
</Box>
rate != null && (
<Box data-testid={`line-graph-${type}`}>
{snapshots?.length ? (
<LineChart data={snapshots} {...graphSize} compact>
<YAxis hide type="number" domain={calculateDomain(snapshots[0][snapshotKey] as number)} />
<Line
type="monotone"
dataKey={snapshotKey}
stroke={getColor(design, snapshots, snapshotKey)}
strokeWidth={1}
dot={<></>}
/>
</LineChart>
) : isLoading ? (
<Skeleton {...graphSize} />
) : (
<Typography sx={{ ...graphSize, alignContent: 'center', textAlign: 'left' }} variant="bodyXsBold">
{t`No historical data`}
</Typography>
)}
</Box>
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Stack from '@mui/material/Stack'
import Chip from '@mui/material/Chip'
import { t } from '@lingui/macro'
import React from 'react'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { LlamaMarket, LlamaMarketType } from '@/loan/entities/llama-markets'
import IconButton from '@mui/material/IconButton'
import { FavoriteHeartIcon } from '@ui-kit/shared/icons/HeartIcon'
import { PointsIcon } from '@ui-kit/shared/icons/PointsIcon'
import { useTheme } from '@mui/material/styles'
import Tooltip from '@mui/material/Tooltip'
import { DesktopOnlyHoverClass } from '@ui-kit/shared/ui/DataTable'
import { useFavoriteMarket } from '@/loan/entities/favorite-markets'

const { Spacing } = SizesAndSpaces

const poolTypeNames: Record<LlamaMarketType, () => string> = {
[LlamaMarketType.Pool]: () => t`Pool`,
[LlamaMarketType.Mint]: () => t`Mint`,
}

/** Displays badges for a pool, such as the chain icon and the pool type. */
export const MarketBadges = ({ market: { address, hasPoints, type, leverage } }: { market: LlamaMarket }) => {
const [isFavorite, toggleFavorite] = useFavoriteMarket(address)
const iconsColor = useTheme().design.Text.TextColors.Highlight
return (
<Stack direction="row" gap={Spacing.sm} alignItems="center">
<Chip size="small" color="default" label={poolTypeNames[type]()} />
{leverage > 0 && <Chip size="small" color="highlight" label={t`🔥 ${leverage}x leverage`} />}

{hasPoints && (
<Tooltip title={t`This pool has points`} placement="top">
<PointsIcon htmlColor={iconsColor} />
</Tooltip>
)}

<IconButton size="extraSmall" onClick={toggleFavorite} className={isFavorite ? '' : DesktopOnlyHoverClass}>
<FavoriteHeartIcon color={iconsColor} isFavorite={isFavorite} />
</IconButton>
</Stack>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { LlamaMarket } from '@/loan/entities/llama-markets'
import Stack from '@mui/material/Stack'
import React from 'react'
import { CellContext } from '@tanstack/react-table'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import Typography from '@mui/material/Typography'
import { MarketBadges } from '@/loan/components/PageLlamaMarkets/cells/MarketTitleCell/MarketBadges'
import { MarketWarnings } from '@/loan/components/PageLlamaMarkets/cells/MarketTitleCell/MarketWarnings'
import { TokenPair } from '@/loan/components/PageLlamaMarkets/cells/MarketTitleCell/TokenPair'
import { TransitionFunction } from '@ui-kit/themes/design/0_primitives'
import { t } from '@lingui/macro'
import { CopyIconButton } from '@ui-kit/shared/ui/CopyIconButton'
import { Link as RouterLink } from 'react-router-dom'
import MuiLink from '@mui/material/Link'

const { Spacing } = SizesAndSpaces

const showIconOnHover = {
'& .MuiIconButton-root': { opacity: 0, transition: `opacity ${TransitionFunction}` },
[`&:hover .MuiIconButton-root`]: { opacity: 1 },
}

export const MarketTitleCell = ({ row: { original: market } }: CellContext<LlamaMarket, LlamaMarket['assets']>) => (
<Stack direction="row" gap={Spacing.sm} alignItems="center">
<TokenPair chain={market.chain} assets={market.assets} />
<Stack direction="column" gap={Spacing.xs}>
<MarketBadges market={market} />
<Typography component={Stack} variant="tableCellL" sx={showIconOnHover} direction="row" gap={2}>
<MuiLink
color="inherit"
underline="hover"
{...(market.url.startsWith('http') ? { href: market.url } : { component: RouterLink, to: market.url })}
>
{market.assets.borrowed.symbol} - {market.assets.collateral.symbol}
</MuiLink>
<CopyIconButton
label={t`Copy market address`}
copyText={market.address}
confirmationText={t`Market address copied`}
/>
</Typography>
<MarketWarnings market={market} />
</Stack>
</Stack>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Stack from '@mui/material/Stack'
import React from 'react'
import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces'
import { LlamaMarket } from '@/loan/entities/llama-markets'
import Chip from '@mui/material/Chip'
import { t } from '@lingui/macro'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
import { ExclamationTriangleIcon } from '@ui-kit/shared/icons/ExclamationTriangleIcon'

const { Spacing } = SizesAndSpaces

/**
* Displays warnings for a pool, such as deprecated pools or pools with collateral corrosion.
*/
export const MarketWarnings = ({ market: { isCollateralEroded, deprecatedMessage } }: { market: LlamaMarket }) => (
<Stack direction="row" gap={Spacing.md} sx={{ height: 20 }}>
{deprecatedMessage && (
<Tooltip title={deprecatedMessage}>
<Typography variant="bodySRegular" color="warning" sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
{t`Deprecated`}
<ExclamationTriangleIcon />
</Typography>
</Tooltip>
)}
{isCollateralEroded && (
<Tooltip title={t`Your position is in eroded`}>
<Chip label={t`Collateral erosion`} color="alert" size="small" />
</Tooltip>
)}
</Stack>
)
Loading
Loading