From 8d4f6a4e9a2fd8a0492b259df13c9f74dbcdcdb2 Mon Sep 17 00:00:00 2001 From: Marcin Ciarka Date: Fri, 11 Oct 2024 16:26:47 +0200 Subject: [PATCH] Earn Protocol WIP #7 (#532) 7 of N pull requests. ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Introduced the `StrategyDetailsPage` component for detailed strategy information. - Added the `StrategyDetailsView` component to enhance the presentation of strategy details. - Launched the `ToggleButton` component for interactive toggle functionality. - Introduced the `Timeframes` component for selecting chart timeframes. - Enhanced navigation with a new "Yield Trend" item and improved descriptions. - Updated `StrategyExposure` to utilize `InlineButtons` for filter selection. - **Style** - Introduced new styles for the `ToggleButton`, `Timeframes`, and `InlineButtons` components. - Improved hover state styling for navigation items. - **Bug Fixes** - Replaced the `StrategyGridDetails` component with `StrategyGridPreview`, ensuring consistent rendering of strategy information. --------- Co-authored-by: sebastianPiekarczyk --- .../layout/Navigation/NavigationWrapper.tsx | 9 +- .../[strategy_id]/[wallet_address]/page.tsx | 4 +- .../strategy/[strategy_id]/details/page.tsx | 27 ++ .../[network]/strategy/[strategy_id]/page.tsx | 79 +++++- .../layout/Navigation/NavigationWrapper.tsx | 9 +- .../StrategyDetailsView.tsx | 88 ++++++ .../organisms/Charts/ChartHeader.tsx | 26 ++ .../organisms/Charts/ComparisonChart.tsx | 90 +++++++ .../organisms/Charts/MockedLineChart.tsx | 250 +++++++----------- .../StrategyDetailsHowItWorks.tsx | 101 +++++++ .../StrategyDetailsYields.tsx | 195 ++++++++++++++ .../StrategyDetailsYields/columns.tsx | 32 +++ .../StrategyDetailsYields/mapper.tsx | 52 ++++ .../StrategyExposure/StrategyExposure.tsx | 60 ++--- .../img/rebalancing/rebalancing-morpho.png | Bin 0 -> 60735 bytes .../NavigationExplore.module.scss | 2 +- .../atoms/Timeframes/Timeframes.module.scss | 9 + .../Timeframes/Timeframes.module.scss.d.ts | 9 + .../atoms/Timeframes/Timeframes.tsx | 39 +++ .../ToggleButton/ToggleButton.module.scss | 52 ++++ .../ToggleButton.module.scss.d.ts | 10 + .../atoms/ToggleButton/ToggleButton.tsx | 23 ++ .../StrategyGridDetails.module.scss | 34 +-- .../StrategyGridDetails.module.scss.d.ts | 8 +- .../StrategyGridDetails.tsx | 88 ++---- .../StrategyGridPreview.module.scss | 36 +++ .../StrategyGridPreview.module.scss.d.ts | 14 + .../StrategyGridPreview.tsx | 98 +++++++ .../InlineButtons/InlineButtons.module.scss | 7 + .../InlineButtons.module.scss.d.ts | 9 + .../molecules/InlineButtons/InlineButtons.tsx | 64 +++++ .../SkeletonImage/SkeletonImage.module.scss | 17 ++ .../SkeletonImage.module.scss.d.ts | 10 + .../molecules/SkeletonImage/SkeletonImage.tsx | 31 +++ packages/app-earn-ui/src/index.ts | 5 + .../src/components/InlineButtons.types.ts | 6 + .../types/src/components/Timeframes.types.ts | 1 + .../app-types/types/src/components/index.ts | 2 + 38 files changed, 1301 insertions(+), 295 deletions(-) create mode 100644 apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/details/page.tsx create mode 100644 apps/earn-protocol/components/layout/StrategyDetailsView/StrategyDetailsView.tsx create mode 100644 apps/earn-protocol/components/organisms/Charts/ChartHeader.tsx create mode 100644 apps/earn-protocol/components/organisms/Charts/ComparisonChart.tsx create mode 100644 apps/earn-protocol/components/organisms/StrategyDetailsHowItWorks/StrategyDetailsHowItWorks.tsx create mode 100644 apps/earn-protocol/components/organisms/StrategyDetailsYields/StrategyDetailsYields.tsx create mode 100644 apps/earn-protocol/components/organisms/StrategyDetailsYields/columns.tsx create mode 100644 apps/earn-protocol/components/organisms/StrategyDetailsYields/mapper.tsx create mode 100644 apps/earn-protocol/public/img/rebalancing/rebalancing-morpho.png create mode 100644 packages/app-earn-ui/src/components/atoms/Timeframes/Timeframes.module.scss create mode 100644 packages/app-earn-ui/src/components/atoms/Timeframes/Timeframes.module.scss.d.ts create mode 100644 packages/app-earn-ui/src/components/atoms/Timeframes/Timeframes.tsx create mode 100644 packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss create mode 100644 packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss.d.ts create mode 100644 packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.tsx create mode 100644 packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss create mode 100644 packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss.d.ts create mode 100644 packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.tsx create mode 100644 packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss create mode 100644 packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss.d.ts create mode 100644 packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.tsx create mode 100644 packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss create mode 100644 packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss.d.ts create mode 100644 packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.tsx create mode 100644 packages/app-types/types/src/components/InlineButtons.types.ts create mode 100644 packages/app-types/types/src/components/Timeframes.types.ts diff --git a/apps/earn-protocol-landing-page/components/layout/Navigation/NavigationWrapper.tsx b/apps/earn-protocol-landing-page/components/layout/Navigation/NavigationWrapper.tsx index d6bad4b05..1eadb2cc2 100644 --- a/apps/earn-protocol-landing-page/components/layout/Navigation/NavigationWrapper.tsx +++ b/apps/earn-protocol-landing-page/components/layout/Navigation/NavigationWrapper.tsx @@ -35,7 +35,14 @@ export const NavigationWrapper: FC = () => { { url: '/rebalancing-activity', id: 'rebalancing-activity', - title: 'Rebalancing activity', + title: 'Rebalancing Activity', + description: 'Text for rebalancing activity', + icon: 'rebalancing', + }, + { + url: '/yield-trend', + id: 'yield-trend', + title: 'Yield Trend', description: 'Text for rebalancing activity', icon: 'rebalancing', }, diff --git a/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/[wallet_address]/page.tsx b/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/[wallet_address]/page.tsx index bc9def402..42699dd94 100644 --- a/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/[wallet_address]/page.tsx +++ b/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/[wallet_address]/page.tsx @@ -1,4 +1,4 @@ -import { Expander, StrategyGridDetails, Text } from '@summerfi/app-earn-ui' +import { Expander, StrategyGridPreview, Text } from '@summerfi/app-earn-ui' import FormContainer from '@/components/organisms/Form/FormContainer' import { @@ -137,7 +137,7 @@ const EarnStrategyPage = ({ params }: EarnStrategyPageProps) => { const [id, symbol, network, apy, risk] = params.strategy.split('-') return ( - { + const selectedStrategyData = useMemo(() => { + return strategiesList.find((strategy) => strategy.id === params.strategy_id) + }, [params]) + + return ( + + + + ) +} + +export default StrategyDetailsPage diff --git a/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/page.tsx b/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/page.tsx index a011fafd6..58f0ceb79 100644 --- a/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/page.tsx +++ b/apps/earn-protocol/app/earn/[network]/strategy/[strategy_id]/page.tsx @@ -1,7 +1,8 @@ 'use client' import { useMemo } from 'react' -import { Expander, StrategyGridDetails, Text } from '@summerfi/app-earn-ui' +import { Expander, StrategyGridPreview, Text, WithArrow } from '@summerfi/app-earn-ui' +import Link from 'next/link' import { MockedLineChart } from '@/components/organisms/Charts/MockedLineChart' import FormContainer from '@/components/organisms/Form/FormContainer' @@ -136,6 +137,29 @@ const userActivityRawData: UserActivityRawData[] = [ }, ] +const detailsLinks = [ + { + label: 'How it all works', + id: 'how-it-works', + }, + { + label: 'Advanced yield data', + id: 'advanced-yield-data', + }, + { + label: 'Yield sources', + id: 'yield-sources', + }, + { + label: 'Security', + id: 'security', + }, + { + label: 'FAQ', + id: 'faq', + }, +] + const EarnStrategyPage = ({ params }: EarnStrategyPageProps) => { // open/manage view (not connected) const selectedStrategyData = useMemo(() => { @@ -143,7 +167,7 @@ const EarnStrategyPage = ({ params }: EarnStrategyPageProps) => { }, [params]) return ( - { width: '100%', }} > +
+ About the strategy + + The Summer Earn Protocol is a permissionless passive lending product, which sets out + to offer effortless and secure optimised yield, while diversifying risk. + +
+ {detailsLinks.map(({ label, id }) => ( + + + {label} + + + ))} +
+
- Chart i guess + Historical yield } defaultExpanded > -
- -
+
{ { url: '/rebalancing-activity', id: 'rebalancing-activity', - title: 'Rebalancing activity', + title: 'Rebalancing Activity', + description: 'Text for rebalancing activity', + icon: 'rebalancing', + }, + { + url: '/yield-trend', + id: 'yield-trend', + title: 'Yield Trend', description: 'Text for rebalancing activity', icon: 'rebalancing', }, diff --git a/apps/earn-protocol/components/layout/StrategyDetailsView/StrategyDetailsView.tsx b/apps/earn-protocol/components/layout/StrategyDetailsView/StrategyDetailsView.tsx new file mode 100644 index 000000000..2c2d56484 --- /dev/null +++ b/apps/earn-protocol/components/layout/StrategyDetailsView/StrategyDetailsView.tsx @@ -0,0 +1,88 @@ +'use client' +import { Card } from '@summerfi/app-earn-ui' + +import { StrategyDetailsHowItWorks } from '@/components/organisms/StrategyDetailsHowItWorks/StrategyDetailsHowItWorks' +import { type IndividualYieldsRawData } from '@/components/organisms/StrategyDetailsYields/mapper' +import { StrategyDetailsYields } from '@/components/organisms/StrategyDetailsYields/StrategyDetailsYields' + +const yieldsRawData: IndividualYieldsRawData[] = [ + { + strategy: 'Summer.fi USDC Strategy', + currentApy: '0.32', + avgApyPer30d: '0.103', + avgApyPer1y: '0.093', + allTimeMedianApy: '0.0643', + yieldLowHigh: { + low: '0.0643', + high: '0.1355', + }, + }, + { + strategy: 'Pendle USDC0++', + currentApy: '0.32', + avgApyPer30d: '0.103', + avgApyPer1y: '0.093', + allTimeMedianApy: '0.0643', + yieldLowHigh: { + low: '0.0643', + high: '0.1355', + }, + }, + { + strategy: 'AAVE v3 USDC', + currentApy: '0.32', + avgApyPer30d: '0.103', + avgApyPer1y: '0.093', + allTimeMedianApy: '0.0643', + yieldLowHigh: { + low: '0.0643', + high: '0.1355', + }, + }, + { + strategy: 'MetaMorpho Gauntlet MKR Blended', + currentApy: '0.32', + avgApyPer30d: '0.103', + avgApyPer1y: '0.093', + allTimeMedianApy: '0.0643', + yieldLowHigh: { + low: '0.0643', + high: '0.1355', + }, + }, + { + strategy: 'All Defi Median', + currentApy: '0.32', + avgApyPer30d: '0.103', + avgApyPer1y: '0.093', + allTimeMedianApy: '0.0643', + yieldLowHigh: { + low: '0.0643', + high: '0.1355', + }, + }, +] + +export const StrategyDetailsView = () => { + return ( + <> + + +
+ +
Yield Sources
+
+
+
+ +
Security
+
+
+
+ +
Faq
+
+
+ + ) +} diff --git a/apps/earn-protocol/components/organisms/Charts/ChartHeader.tsx b/apps/earn-protocol/components/organisms/Charts/ChartHeader.tsx new file mode 100644 index 000000000..2dbae85ef --- /dev/null +++ b/apps/earn-protocol/components/organisms/Charts/ChartHeader.tsx @@ -0,0 +1,26 @@ +import { SimpleGrid, Timeframes, ToggleButton } from '@summerfi/app-earn-ui' +import { type TimeframesType } from '@summerfi/app-types' + +type ChartHeaderProps = { + compare: boolean + setCompare: (value: boolean) => void + timeframe: TimeframesType + setTimeframe: (timeframe: string) => void +} + +export const ChartHeader = ({ compare, timeframe, setCompare, setTimeframe }: ChartHeaderProps) => { + return ( + + setCompare(!compare)} + /> + + + ) +} diff --git a/apps/earn-protocol/components/organisms/Charts/ComparisonChart.tsx b/apps/earn-protocol/components/organisms/Charts/ComparisonChart.tsx new file mode 100644 index 000000000..c7d4677e4 --- /dev/null +++ b/apps/earn-protocol/components/organisms/Charts/ComparisonChart.tsx @@ -0,0 +1,90 @@ +import { type TimeframesType } from '@summerfi/app-types' +import { + Area, + ComposedChart, + Legend, + Line, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts' + +type ComparisonChartProps = { + data: unknown[] + dataNames: string[] + colors: { [key: string]: string } + compare: boolean + timeframe: TimeframesType +} + +export const ComparisonChart = ({ data, dataNames, colors, compare }: ComparisonChartProps) => { + return ( +
+ + + + + + + + + + + `${label}%`} /> + `${Number(val).toFixed(2)}`} + useTranslate3d + contentStyle={{ + zIndex: 1000, + backgroundColor: 'var(--color-surface-subtler)', + borderRadius: '5px', + padding: '20px 30px', + border: 'none', + }} + /> + {dataNames.map((dataName, dataIndex) => + dataName === 'Summer USDS Strategy' ? ( + + ) : ( + + ), + )} + + + +
+ ) +} diff --git a/apps/earn-protocol/components/organisms/Charts/MockedLineChart.tsx b/apps/earn-protocol/components/organisms/Charts/MockedLineChart.tsx index dfb7891e4..5c7e86056 100644 --- a/apps/earn-protocol/components/organisms/Charts/MockedLineChart.tsx +++ b/apps/earn-protocol/components/organisms/Charts/MockedLineChart.tsx @@ -1,15 +1,12 @@ +'use client' + import { useMemo, useState } from 'react' -import { random } from 'lodash-es' -import { - Area, - ComposedChart, - Legend, - Line, - ResponsiveContainer, - Tooltip, - XAxis, - YAxis, -} from 'recharts' +import { Card } from '@summerfi/app-earn-ui' +import { type TimeframesType } from '@summerfi/app-types' +import { memoize, random } from 'lodash-es' + +import { ChartHeader } from '@/components/organisms/Charts/ChartHeader' +import { ComparisonChart } from '@/components/organisms/Charts/ComparisonChart' const dataNames = [ 'Median Defi Yield', @@ -27,158 +24,95 @@ const colors = { 'Summer USDS Strategy-color': '#FF49A4', } -const data = [ - { - name: 'Jun 2024', - 'Median Defi Yield': random(0, 1, true), - 'Median Aave Lending': random(0, 1, true), - 'Median Morpho Lending': random(0, 1, true), - 'Median USDS': random(0, 1, true), - 'Summer USDS Strategy': random(0, 2, true), - }, - { - name: 'Jul 2024', - 'Median Defi Yield': random(0, 3, true), - 'Median Aave Lending': random(0, 3, true), - 'Median Morpho Lending': random(0, 3, true), - 'Median USDS': random(0, 3, true), - 'Summer USDS Strategy': random(1, 3, true), - }, - { - name: 'Aug 2024', - 'Median Defi Yield': random(1, 7, true), - 'Median Aave Lending': random(1, 7, true), - 'Median Morpho Lending': random(1, 7, true), - 'Median USDS': random(1, 7, true), - 'Summer USDS Strategy': random(1, 7, true), - }, - { - name: 'Sep 2024', - 'Median Defi Yield': random(2, 9, true), - 'Median Aave Lending': random(2, 9, true), - 'Median Morpho Lending': random(2, 9, true), - 'Median USDS': random(2, 9, true), - 'Summer USDS Strategy': random(6, 14, true), - }, - { - name: 'Oct 2024', - 'Median Defi Yield': random(1, 8, true), - 'Median Aave Lending': random(1, 8, true), - 'Median Morpho Lending': random(1, 8, true), - 'Median USDS': random(1, 8, true), - 'Summer USDS Strategy': random(7, 15, true), - }, - { - name: 'Nov 2024', - 'Median Defi Yield': random(1, 8, true), - 'Median Aave Lending': random(1, 8, true), - 'Median Morpho Lending': random(1, 8, true), - 'Median USDS': random(1, 8, true), - 'Summer USDS Strategy': random(7, 15, true), - }, - { - name: 'Dec 2024', - 'Median Defi Yield': random(3, 12, true), - 'Median Aave Lending': random(3, 12, true), - 'Median Morpho Lending': random(3, 12, true), - 'Median USDS': random(3, 12, true), - 'Summer USDS Strategy': random(7, 15, true), - }, -] +const data = memoize( + // just to simulate data change + (_timeframe) => [ + { + name: 'Jun 2024', + 'Median Defi Yield': random(0, 1, true), + 'Median Aave Lending': random(0, 1, true), + 'Median Morpho Lending': random(0, 1, true), + 'Median USDS': random(0, 1, true), + 'Summer USDS Strategy': random(0, 2, true), + }, + { + name: 'Jul 2024', + 'Median Defi Yield': random(0, 3, true), + 'Median Aave Lending': random(0, 3, true), + 'Median Morpho Lending': random(0, 3, true), + 'Median USDS': random(0, 3, true), + 'Summer USDS Strategy': random(1, 3, true), + }, + { + name: 'Aug 2024', + 'Median Defi Yield': random(1, 7, true), + 'Median Aave Lending': random(1, 7, true), + 'Median Morpho Lending': random(1, 7, true), + 'Median USDS': random(1, 7, true), + 'Summer USDS Strategy': random(1, 7, true), + }, + { + name: 'Sep 2024', + 'Median Defi Yield': random(2, 9, true), + 'Median Aave Lending': random(2, 9, true), + 'Median Morpho Lending': random(2, 9, true), + 'Median USDS': random(2, 9, true), + 'Summer USDS Strategy': random(6, 14, true), + }, + { + name: 'Oct 2024', + 'Median Defi Yield': random(1, 8, true), + 'Median Aave Lending': random(1, 8, true), + 'Median Morpho Lending': random(1, 8, true), + 'Median USDS': random(1, 8, true), + 'Summer USDS Strategy': random(7, 15, true), + }, + { + name: 'Nov 2024', + 'Median Defi Yield': random(1, 8, true), + 'Median Aave Lending': random(1, 8, true), + 'Median Morpho Lending': random(1, 8, true), + 'Median USDS': random(1, 8, true), + 'Summer USDS Strategy': random(7, 15, true), + }, + { + name: 'Dec 2024', + 'Median Defi Yield': random(3, 12, true), + 'Median Aave Lending': random(3, 12, true), + 'Median Morpho Lending': random(3, 12, true), + 'Median USDS': random(3, 12, true), + 'Summer USDS Strategy': random(7, 15, true), + }, + ], + // just to simulate data change + (timeframe) => timeframe, +) export const MockedLineChart = () => { const [compare, setCompare] = useState(true) + const [timeframe, setTimeframe] = useState('3y') - const dataNamesParsed = useMemo(() => { - if (compare) { - return dataNames - } - - return dataNames - }, [compare]) + // just to simulate data change + const simulatedData = useMemo(() => ({ timeframe, data: data(timeframe) }), [timeframe]) return ( - <> -
- - setCompare(!compare)} - style={{ - margin: 10, - width: 20, - height: 20, - }} - /> -
- - - - - - - - - - - `${label}%`} /> - `${Number(val).toFixed(2)}`} - useTranslate3d - contentStyle={{ - zIndex: 1000, - backgroundColor: 'var(--color-surface-subtler)', - borderRadius: '5px', - padding: '20px 30px', - border: 'none', - }} - /> - {dataNamesParsed.map((dataName, dataIndex) => - dataName === 'Summer USDS Strategy' ? ( - - ) : ( - - ), - )} - - - - + + setTimeframe(nextTimeFrame as TimeframesType)} + /> + + ) } diff --git a/apps/earn-protocol/components/organisms/StrategyDetailsHowItWorks/StrategyDetailsHowItWorks.tsx b/apps/earn-protocol/components/organisms/StrategyDetailsHowItWorks/StrategyDetailsHowItWorks.tsx new file mode 100644 index 000000000..78edd195c --- /dev/null +++ b/apps/earn-protocol/components/organisms/StrategyDetailsHowItWorks/StrategyDetailsHowItWorks.tsx @@ -0,0 +1,101 @@ +'use client' +import { useState } from 'react' +import { Card, InlineButtons, SkeletonImage, Text, WithArrow } from '@summerfi/app-earn-ui' +import { type InlineButtonOption } from '@summerfi/app-types' +import Link from 'next/link' + +const options: InlineButtonOption[] = [ + { + title: 'Flow of funds', + key: 'flow-of-funds', + }, + { + title: 'Rebalance mechanism', + key: 'rebalance-mechanism', + }, + { + title: 'Governance', + key: 'governance', + }, +] + +const links = [ + { + label: 'White Paper', + href: '/', + }, + { + label: 'Lite Paper', + href: '/', + }, + { + label: 'Video', + href: '/', + }, +] + +export const StrategyDetailsHowItWorks = () => { + const [currentOption, setCurrentOption] = useState>(options[0]) + + return ( + +
+ + How it all works + + setCurrentOption(option)} + style={{ + marginBottom: 'var(--spacing-space-large)', + }} + variant="p4semi" + /> + + + The Summer Earn Protocol is a permissionless passive lending product, which sets out to + offer effortless and secure optimised yield, while diversifying risk. + +
+ {links.map((link) => ( + + + {link.label} + + + ))} +
+
+
+ ) +} diff --git a/apps/earn-protocol/components/organisms/StrategyDetailsYields/StrategyDetailsYields.tsx b/apps/earn-protocol/components/organisms/StrategyDetailsYields/StrategyDetailsYields.tsx new file mode 100644 index 000000000..ed6e302c6 --- /dev/null +++ b/apps/earn-protocol/components/organisms/StrategyDetailsYields/StrategyDetailsYields.tsx @@ -0,0 +1,195 @@ +'use client' +import { type FC, useMemo, useState } from 'react' +import { Card, InlineButtons, SkeletonImage, Table, Text } from '@summerfi/app-earn-ui' +import { type InlineButtonOption } from '@summerfi/app-types' + +import { individualYieldsColumns } from '@/components/organisms/StrategyDetailsYields/columns' +import { + individualYieldsMapper, + type IndividualYieldsRawData, +} from '@/components/organisms/StrategyDetailsYields/mapper' + +const yieldOptions: InlineButtonOption[] = [ + { + title: 'Advanced yield', + key: 'advanced-yield', + }, + { + title: 'Yield source', + key: 'yield-source', + }, +] + +const options: InlineButtonOption[] = [ + { + title: 'All', + key: 'all', + }, + { + title: 'Summer.fi', + key: 'summerfi', + }, + { + title: 'Pendle', + key: 'pendle', + }, + { + title: 'AAVE v3', + key: 'aavev3', + }, + { + title: 'MetaMorpho', + key: 'metamorpho', + }, + { + title: 'Uni V3', + key: 'univ3', + }, + { + title: 'DeFi Median', + key: 'defimedian', + }, + { + title: 'Strategy A', + key: 'strategya', + }, + { + title: 'Strategy B', + key: 'strategyb', + }, + { + title: 'Strategy C', + key: 'strategyc', + }, + { + title: 'Strategy D', + key: 'strategyd', + }, + { + title: 'Strategy E', + key: 'strategye', + }, +] + +enum StrategyExposureFilterType { + ALL = 'ALL', + ALLOCATED = 'ALLOCATED', + UNALLOCATED = 'UNALLOCATED', +} + +const individualYieldOptions = [ + { + title: 'All', + key: StrategyExposureFilterType.ALL, + }, + { + title: 'Allocated', + key: StrategyExposureFilterType.ALLOCATED, + }, + { + title: 'Unallocated', + key: StrategyExposureFilterType.UNALLOCATED, + }, +] + +interface StrategyDetailsYieldsProps { + rawData: IndividualYieldsRawData[] +} + +export const StrategyDetailsYields: FC = ({ rawData }) => { + const [currentOption, setCurrentOption] = useState>(options[0]) + const [currentYieldOption, setCurrentYieldOption] = useState>( + yieldOptions[0], + ) + const [individualYieldOption, setIndividualYieldOption] = useState>( + individualYieldOptions[0], + ) + const rows = useMemo(() => individualYieldsMapper(rawData), [rawData]) + + return ( + +
+ setCurrentYieldOption(option)} + style={{ + marginBottom: 'var(--spacing-space-large)', + }} + asUnstyled + variant="h5" + /> + + The Summer Earn Protocol is a permissionless passive lending product, which sets out to + offer effortless and secure optimised yield, while diversifying risk. + + + Historical Yields + + setCurrentOption(option)} + style={{ + marginBottom: 'var(--spacing-space-large)', + }} + asButtons + variant="p4semi" + /> + + + Individual Yield Data + + setIndividualYieldOption(option)} + style={{ + paddingBottom: 'var(--spacing-space-small)', + borderBottom: '1px solid var(--earn-protocol-neutral-70)', + }} + asUnstyled + variant="p3semi" + /> + console.log(item)} + /> + + + ) +} diff --git a/apps/earn-protocol/components/organisms/StrategyDetailsYields/columns.tsx b/apps/earn-protocol/components/organisms/StrategyDetailsYields/columns.tsx new file mode 100644 index 000000000..c688adf20 --- /dev/null +++ b/apps/earn-protocol/components/organisms/StrategyDetailsYields/columns.tsx @@ -0,0 +1,32 @@ +export const individualYieldsColumns = [ + { + title: 'Strategy', + key: 'strategy', + sortable: false, + }, + { + title: 'Current APY', + key: 'currentApy', + sortable: true, + }, + { + title: '30d AVG. APY', + key: 'avgApyPer30d', + sortable: true, + }, + { + title: '1y AVG. APY', + key: 'avgApyPer1y', + sortable: true, + }, + { + title: 'All-Time Median APY', + key: 'allTimeMedianApy', + sortable: true, + }, + { + title: 'Yield Low / High', + key: 'yieldLowHigh', + sortable: false, + }, +] diff --git a/apps/earn-protocol/components/organisms/StrategyDetailsYields/mapper.tsx b/apps/earn-protocol/components/organisms/StrategyDetailsYields/mapper.tsx new file mode 100644 index 000000000..70eb797af --- /dev/null +++ b/apps/earn-protocol/components/organisms/StrategyDetailsYields/mapper.tsx @@ -0,0 +1,52 @@ +import { TableCellText, TableRowAccent } from '@summerfi/app-earn-ui' +import { formatDecimalAsPercent } from '@summerfi/app-utils' +import BigNumber from 'bignumber.js' + +export interface IndividualYieldsRawData { + strategy: string + currentApy: string + avgApyPer30d: string + avgApyPer1y: string + allTimeMedianApy: string + yieldLowHigh: { + low: string + high: string + } +} + +export const individualYieldsMapper = (rawData: IndividualYieldsRawData[]) => { + return rawData.map((item) => { + return { + content: { + strategy: ( +
+ + {item.strategy} +
+ ), + currentApy: ( + {formatDecimalAsPercent(new BigNumber(item.currentApy))} + ), + avgApyPer30d: ( + {formatDecimalAsPercent(new BigNumber(item.avgApyPer30d))} + ), + avgApyPer1y: ( + {formatDecimalAsPercent(new BigNumber(item.avgApyPer1y))} + ), + allTimeMedianApy: ( + + {formatDecimalAsPercent(new BigNumber(item.allTimeMedianApy))} + + ), + yieldLowHigh: ( + + {formatDecimalAsPercent(new BigNumber(item.yieldLowHigh.low))} /{' '} + {formatDecimalAsPercent(new BigNumber(item.yieldLowHigh.high))} + + ), + }, + } + }) +} diff --git a/apps/earn-protocol/components/organisms/StrategyExposure/StrategyExposure.tsx b/apps/earn-protocol/components/organisms/StrategyExposure/StrategyExposure.tsx index 789f3f2c7..4cab5303a 100644 --- a/apps/earn-protocol/components/organisms/StrategyExposure/StrategyExposure.tsx +++ b/apps/earn-protocol/components/organisms/StrategyExposure/StrategyExposure.tsx @@ -1,9 +1,8 @@ 'use client' import { type Dispatch, type FC, type SetStateAction, useMemo, useState } from 'react' -import { Button, Card, Table, Text } from '@summerfi/app-earn-ui' +import { Card, InlineButtons, Table, Text } from '@summerfi/app-earn-ui' import { type TokenSymbolsList } from '@summerfi/app-types' -import { capitalize } from 'lodash-es' import { strategyExposureColumns } from '@/components/organisms/StrategyExposure/columns' import { strategyExposureMapper } from '@/components/organisms/StrategyExposure/mapper' @@ -14,6 +13,21 @@ enum StrategyExposureFilterType { UNALLOCATED = 'UNALLOCATED', } +const options = [ + { + title: 'All', + key: StrategyExposureFilterType.ALL, + }, + { + title: 'Allocated', + key: StrategyExposureFilterType.ALLOCATED, + }, + { + title: 'Unallocated', + key: StrategyExposureFilterType.UNALLOCATED, + }, +] + interface StrategyExposureTypePickerProps { currentType: StrategyExposureFilterType setExposureType: Dispatch> @@ -24,41 +38,13 @@ const StrategyExposureTypePicker: FC = ({ setExposureType, }) => { return ( -
- {[ - StrategyExposureFilterType.ALL, - StrategyExposureFilterType.ALLOCATED, - StrategyExposureFilterType.UNALLOCATED, - ].map((itemType) => ( - - ))} -
+ item.key === currentType) ?? options[0]} + handleOption={(option) => setExposureType(option.key)} + style={{ marginBottom: 'var(--spacing-space-small)' }} + variant="p4semi" + /> ) } diff --git a/apps/earn-protocol/public/img/rebalancing/rebalancing-morpho.png b/apps/earn-protocol/public/img/rebalancing/rebalancing-morpho.png new file mode 100644 index 0000000000000000000000000000000000000000..202f625b62a26ef56c7d4bd6b447f1ea01d6040e GIT binary patch literal 60735 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 + activeTimeframe: TimeframesType + setActiveTimeframe: (timeframe: TimeframesType) => void +}) => { + return ( +
+ {timeframes.map((timeframe) => ( + + ))} +
+ ) +} diff --git a/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss b/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss new file mode 100644 index 000000000..65d17c54c --- /dev/null +++ b/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss @@ -0,0 +1,52 @@ +.slideButtonWrapper { + display: flex; + align-items: center; + + + .slideButtonWrapper { + position: relative; + display: inline-block; + width: 44px; + height: 24px; + margin-left: var(--general-space-16); + } + + .slideButtonWrapper input { + opacity: 0; + width: 0; + height: 0; + } + + .slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: var(--color-surface-light); + transition: .2s; + border-radius: 34px; + } + + .slider:before { + position: absolute; + content: ""; + height: 20px; + width: 20px; + left: 2px; + bottom: 2px; + background-color: var(--color-background-primary); + transition: .2s; + border-radius: 50%; + } + + input:checked+.slider { + background-color: var(--color-background-primary); + } + + input:checked+.slider:before { + transform: translateX(20px); + background-color: var(--color-text-primary); + } +} \ No newline at end of file diff --git a/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss.d.ts b/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss.d.ts new file mode 100644 index 000000000..c4e393045 --- /dev/null +++ b/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.module.scss.d.ts @@ -0,0 +1,10 @@ +export type Styles = { + slideButtonWrapper: string + slider: string +} + +export type ClassNames = keyof Styles + +declare const styles: Styles + +export default styles diff --git a/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.tsx b/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.tsx new file mode 100644 index 000000000..a8e04546c --- /dev/null +++ b/packages/app-earn-ui/src/components/atoms/ToggleButton/ToggleButton.tsx @@ -0,0 +1,23 @@ +import { Text } from '@/components/atoms/Text/Text' + +import slideButtonStyles from './ToggleButton.module.scss' +import { type ClassNames as TextVariants } from '@/components/atoms/Text/Text.module.scss' + +type ToggleButtonProps = { + title: string + checked: boolean + onChange?: (event: React.FormEvent) => void + titleVariant?: TextVariants +} + +export const ToggleButton = ({ title, titleVariant, checked, onChange }: ToggleButtonProps) => { + return ( +
+ {title} + +
+ ) +} diff --git a/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss b/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss index 47611c2c6..67e2c5012 100644 --- a/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss +++ b/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss @@ -7,30 +7,24 @@ } } -.strategyGridDetailsPositionWrapper { - display: grid; - grid-gap: var(--general-space-16); - grid-template-columns: 1fr max(446px); - margin-top: 20px; - .leftBlock { - display: grid; - grid-gap: var(--general-space-16); - } - - .rightBlockWrapper { - height: 100%; - - .rightBlock { - position: sticky; - top: var(--general-space-16); - } - } +.strategyGridDetailsWrapper { + display: flex; + justify-content: space-between; + flex-direction: column; + margin-top: var(--general-space-24); } -.strategyGridDetailsTopLeftWrapper { +.strategyGridDetailsHeaderWrapper { display: flex; flex-direction: row; width: 100%; justify-content: space-between; - margin-bottom: var(--general-space-16); +} + +.strategyGridDetailsContentWrapper { + display: flex; + justify-content: space-between; + flex-direction: column; + margin-top: var(--general-space-24); + gap: var(--general-space-20); } diff --git a/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss.d.ts b/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss.d.ts index 5f3f725be..b82cc9e7d 100644 --- a/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss.d.ts +++ b/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.module.scss.d.ts @@ -1,10 +1,8 @@ export type Styles = { - leftBlock: string - rightBlock: string - rightBlockWrapper: string strategyGridDetailsBreadcrumbsWrapper: string - strategyGridDetailsPositionWrapper: string - strategyGridDetailsTopLeftWrapper: string + strategyGridDetailsContentWrapper: string + strategyGridDetailsHeaderWrapper: string + strategyGridDetailsWrapper: string } export type ClassNames = keyof Styles diff --git a/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.tsx b/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.tsx index 5fd8cc9f6..47ea1faae 100644 --- a/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.tsx +++ b/packages/app-earn-ui/src/components/layout/StrategyGridDetails/StrategyGridDetails.tsx @@ -4,23 +4,19 @@ import { type ReactNode } from 'react' import { type EarnProtocolStrategy } from '@summerfi/app-types' import Link from 'next/link' -import { Box } from '@/components/atoms/Box/Box' +import { Button } from '@/components/atoms/Button/Button' import { Text } from '@/components/atoms/Text/Text' -import { BonusLabel } from '@/components/molecules/BonusLabel/BonusLabel' -import { DataBlock } from '@/components/molecules/DataBlock/DataBlock' -import { SimpleGrid } from '@/components/molecules/Grid/SimpleGrid' +import { WithArrow } from '@/components/atoms/WithArrow/WithArrow' import { StrategyTitleWithRisk } from '@/components/molecules/StrategyTitleWithRisk/StrategyTitleWithRisk' import strategyGridDetailsStyles from './StrategyGridDetails.module.scss' export const StrategyGridDetails = ({ strategy, - leftContent, - rightContent, + children, }: { strategy: EarnProtocolStrategy - leftContent: ReactNode - rightContent: ReactNode + children: ReactNode }) => { return ( <> @@ -28,69 +24,33 @@ export const StrategyGridDetails = ({
- Earn /   + Earn / + + + + + {' '} + {strategy.id}{' '} - {strategy.id} + / Details
-
-
-
- - - - -
- - - - - - - - - - - - {leftContent} +
+
+ +
-
-
{rightContent}
+
+ {children}
diff --git a/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss b/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss new file mode 100644 index 000000000..c59d49bf0 --- /dev/null +++ b/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss @@ -0,0 +1,36 @@ +.strategyGridPreviewBreadcrumbsWrapper { + display: flex; + flex-direction: column; + a { + margin-top: var(--general-space-12); + color: var(--earn-protocol-primary-100); + } +} + +.strategyGridPreviewPositionWrapper { + display: grid; + grid-gap: var(--general-space-16); + grid-template-columns: 1fr max(446px); + margin-top: 20px; + .leftBlock { + display: grid; + grid-gap: var(--general-space-16); + } + + .rightBlockWrapper { + height: 100%; + + .rightBlock { + position: sticky; + top: var(--general-space-16); + } + } +} + +.strategyGridPreviewTopLeftWrapper { + display: flex; + flex-direction: row; + width: 100%; + justify-content: space-between; + margin-bottom: var(--general-space-16); +} diff --git a/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss.d.ts b/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss.d.ts new file mode 100644 index 000000000..7d3ba2998 --- /dev/null +++ b/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.module.scss.d.ts @@ -0,0 +1,14 @@ +export type Styles = { + leftBlock: string + rightBlock: string + rightBlockWrapper: string + strategyGridPreviewBreadcrumbsWrapper: string + strategyGridPreviewPositionWrapper: string + strategyGridPreviewTopLeftWrapper: string +} + +export type ClassNames = keyof Styles + +declare const styles: Styles + +export default styles diff --git a/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.tsx b/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.tsx new file mode 100644 index 000000000..d43016129 --- /dev/null +++ b/packages/app-earn-ui/src/components/layout/StrategyGridPreview/StrategyGridPreview.tsx @@ -0,0 +1,98 @@ +'use client' + +import { type ReactNode } from 'react' +import { type EarnProtocolStrategy } from '@summerfi/app-types' +import Link from 'next/link' + +import { Box } from '@/components/atoms/Box/Box' +import { Text } from '@/components/atoms/Text/Text' +import { BonusLabel } from '@/components/molecules/BonusLabel/BonusLabel' +import { DataBlock } from '@/components/molecules/DataBlock/DataBlock' +import { SimpleGrid } from '@/components/molecules/Grid/SimpleGrid' +import { StrategyTitleWithRisk } from '@/components/molecules/StrategyTitleWithRisk/StrategyTitleWithRisk' + +import strategyGridPreviewStyles from './StrategyGridPreview.module.scss' + +export const StrategyGridPreview = ({ + strategy, + leftContent, + rightContent, +}: { + strategy: EarnProtocolStrategy + leftContent: ReactNode + rightContent: ReactNode +}) => { + return ( + <> +
+
+ + + Earn /   + + + + {strategy.id} + +
+
+
+
+
+ + + + +
+ + + + + + + + + + + + {leftContent} +
+
+
{rightContent}
+
+
+ + ) +} diff --git a/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss b/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss new file mode 100644 index 000000000..a5cc230b9 --- /dev/null +++ b/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss @@ -0,0 +1,7 @@ +.inlineButtonsWrapper { + display: flex; + gap: var(--spacing-space-small); + justify-content: flex-start; + flex-wrap: wrap; + width: 100%; +} diff --git a/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss.d.ts b/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss.d.ts new file mode 100644 index 000000000..0d9bb3917 --- /dev/null +++ b/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.module.scss.d.ts @@ -0,0 +1,9 @@ +export type Styles = { + inlineButtonsWrapper: string +} + +export type ClassNames = keyof Styles + +declare const styles: Styles + +export default styles diff --git a/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.tsx b/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.tsx new file mode 100644 index 000000000..e87c8f471 --- /dev/null +++ b/packages/app-earn-ui/src/components/molecules/InlineButtons/InlineButtons.tsx @@ -0,0 +1,64 @@ +import { type CSSProperties } from 'react' +import { type InlineButtonOption } from '@summerfi/app-types' + +import { Button } from '@/components/atoms/Button/Button' +import { Text, type TextAllowedHtmlTags } from '@/components/atoms/Text/Text' +import type { ClassNames as TextClassNames } from '@/components/atoms/Text/Text.module.scss' + +import classNames from './InlineButtons.module.scss' + +interface InlineButtonsProps { + options: InlineButtonOption[] + currentOption: InlineButtonOption + handleOption: (option: InlineButtonOption) => void + style?: CSSProperties + asButtons?: boolean + asUnstyled?: boolean + as?: TextAllowedHtmlTags + variant: TextClassNames +} + +export function InlineButtons({ + options, + currentOption, + handleOption, + style, + asButtons, + asUnstyled, + as = 'span', + variant, +}: InlineButtonsProps) { + return ( +
+ {options.map((option) => ( + + ))} +
+ ) +} diff --git a/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss b/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss new file mode 100644 index 000000000..9986e5fc0 --- /dev/null +++ b/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss @@ -0,0 +1,17 @@ +.skeleton { + background-color: #e0e0e0; + animation: pulse 1.5s infinite; + border-radius: 8px; /* Optional for rounded corners */ +} + +@keyframes pulse { + 0% { + background-color: #464646; + } + 50% { + background-color: #383838; + } + 100% { + background-color: #444444; + } +} diff --git a/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss.d.ts b/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss.d.ts new file mode 100644 index 000000000..ba592b66a --- /dev/null +++ b/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.module.scss.d.ts @@ -0,0 +1,10 @@ +export type Styles = { + pulse: string + skeleton: string +} + +export type ClassNames = keyof Styles + +declare const styles: Styles + +export default styles diff --git a/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.tsx b/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.tsx new file mode 100644 index 000000000..ebf5822ee --- /dev/null +++ b/packages/app-earn-ui/src/components/molecules/SkeletonImage/SkeletonImage.tsx @@ -0,0 +1,31 @@ +'use client' + +import { type FC, useState } from 'react' +import Image, { type ImageProps } from 'next/image' + +import styles from './SkeletonImage.module.scss' // Import custom CSS + +export const SkeletonImage: FC = ({ src, alt, width, height, sizes, style }) => { + const [isLoading, setIsLoading] = useState(true) + + const handleImageLoad = () => { + setIsLoading(false) + } + + return ( +
+ {isLoading &&
} + + +
+ ) +} diff --git a/packages/app-earn-ui/src/index.ts b/packages/app-earn-ui/src/index.ts index 393fdca69..1a20b1b7d 100644 --- a/packages/app-earn-ui/src/index.ts +++ b/packages/app-earn-ui/src/index.ts @@ -18,11 +18,14 @@ export { List } from './components/atoms/List/List' export { WithArrow } from './components/atoms/WithArrow/WithArrow' export { Expander } from './components/atoms/Expander/Expander' export { TableRowAccent } from './components/atoms/TableRowAccent/TableRowAccent' +export { ToggleButton } from './components/atoms/ToggleButton/ToggleButton' +export { Timeframes } from './components/atoms/Timeframes/Timeframes' export { Footer } from './components/layout/Footer/Footer' export { Navigation } from './components/layout/Navigation/Navigation' export { StrategyGrid } from './components/layout/StrategyGrid/StrategyGrid' +export { StrategyGridPreview } from './components/layout/StrategyGridPreview/StrategyGridPreview' export { StrategyGridDetails } from './components/layout/StrategyGridDetails/StrategyGridDetails' export { MainBackground } from './components/layout/BackgroundComponents/MainBackground' @@ -39,6 +42,8 @@ export { StrategyTitleWithRisk } from './components/molecules/StrategyTitleWithR export { TableCellText } from './components/molecules/TableCellText/TableCellText' export { TableHeadWithTooltip } from './components/molecules/TableHeadWithTooltip/TableHeadWithTooltip' export { TokensGroup } from './components/molecules/TokensGroup/TokensGroup' +export { InlineButtons } from './components/molecules/InlineButtons/InlineButtons' +export { SkeletonImage } from './components/molecules/SkeletonImage/SkeletonImage' export { TermsOfService } from './components/organisms/TermsOfService/TermsOfService' export { Sidebar } from './components/organisms/Sidebar/Sidebar' diff --git a/packages/app-types/types/src/components/InlineButtons.types.ts b/packages/app-types/types/src/components/InlineButtons.types.ts new file mode 100644 index 000000000..e368d394a --- /dev/null +++ b/packages/app-types/types/src/components/InlineButtons.types.ts @@ -0,0 +1,6 @@ +import { type ReactNode } from 'react' + +export interface InlineButtonOption { + key: O + title: ReactNode +} diff --git a/packages/app-types/types/src/components/Timeframes.types.ts b/packages/app-types/types/src/components/Timeframes.types.ts new file mode 100644 index 000000000..125599795 --- /dev/null +++ b/packages/app-types/types/src/components/Timeframes.types.ts @@ -0,0 +1 @@ +export type TimeframesType = '90d' | '6m' | '1y' | '3y' diff --git a/packages/app-types/types/src/components/index.ts b/packages/app-types/types/src/components/index.ts index 367e8d61b..962ceb997 100644 --- a/packages/app-types/types/src/components/index.ts +++ b/packages/app-types/types/src/components/index.ts @@ -1,3 +1,5 @@ export * from './Navigation.types' export * from './Dropdown.types' export * from './Table.types' +export * from './InlineButtons.types' +export * from './Timeframes.types'