Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@reduxjs/toolkit": "^1.8.6",
"@types/lodash": "^4.14.191",
"apexcharts": "^3.36.0",
"autoprefixer": "^10.4.13",
"axios": "^1.1.3",
"bootstrap": "^5.2.2",
"cookies-next": "^2.1.1",
"dayjs": "^1.11.6",
"lodash": "^4.17.21",
"next": "12.3.1",
"nextjs-google-analytics": "^2.2.1",
"react": "17.0.2",
Expand Down
58 changes: 12 additions & 46 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import { TvlUnit } from 'store/reducers/tvl-evolution.slice'
import { formatCurrency } from 'utils/helpers/format'
import Loader from 'components/Loader'
import DataEvolution from 'components/DataEvolution'
import { getTokensValue } from 'utils/helpers/tokens'
import { getTokensValue, tokens } from 'utils/helpers/tokens'
import { TokenPricesState } from 'store/reducers/tokens-prices.slice'
import { AreaChart } from 'components/Charts/AreaChart'
import { periodOptions } from 'types'
import { ChainComparisonTVL } from 'components/Tables/ChainComparisonTVL'

const Home = () => {
const tvlUnits = useSelector<RootState, TvlUnit[]>(state => state.tvlEvolution.data)
Expand All @@ -18,6 +21,9 @@ const Home = () => {

const fetchingData = useSelector<RootState, boolean>(state => state.tvlEvolution.loading)
const loading = fetchingData || tvlUnits.length === 0 || tvlUnitsInDollars.length === 0

const formattedData = useMemo(() => tokens.map((token) => ({ data: tvlUnitsInDollars.map(unit => [unit.day.getTime(), unit[token.toLowerCase() as 'eth']]), name: token })), [tvlUnitsInDollars])

const content = (
<>
<div className="row justify-content-between">
Expand All @@ -29,52 +35,12 @@ const Home = () => {
<DataBlock color="BLACK" title="TVL in non-native" data="Soon" />
</div>
</div>
<div className="container my-5 p-2 black-gradient rounded-custom">
<div className="row text-white text-center mt-3">
<h6 className="mb-0 font-weight-bold">TVL Evolution (USD)</h6>
</div>
<div className="row" id="tvl-chart">
{/* <Chart
customOptions={{
chart: {
...baseChartOptions.chart,
stacked: true
},
legend: {
onItemClick: {
toggleDataSeries: false
}
},
colors: tokensColor,
tooltip: {
...baseChartOptions.tooltip,
shared: true,
intersect: false,
fixed: {
enabled: true,
position: 'topRight'
},
x: {
formatter: function (value, { series, dataPointIndex }) {
let output = new Intl.DateTimeFormat('en', { year: 'numeric', month: 'long', day: 'numeric' }).format(new Date(value))
if (series) {
const total = series.map((serie: number[]) => serie[dataPointIndex]).reduce((a: number, b: number) => a + b)
output = output + ' (Total: ' + formatCurrency(total) + ')'
}
return output
}
}
},
fill: {
type: 'none'
}
}}
series={formattedData}
formatter={(value) => formatCurrency(value, 0)}
/> */}
</div>
<div className="flex flex-row gap-x-10 h-80 my-5" id="tvl-chart">
<AreaChart title={'TVL Evolution (USD)'} series={[formattedData[0]]} formatter={(value) => formatCurrency(value, 0)} dateOptions={periodOptions} displayDateSelector={true} />
<AreaChart title={'User Evolution'} series={[formattedData[0]]} formatter={(value) => formatCurrency(value, 0)} dateOptions={periodOptions} displayDateSelector={true} />
</div>
<h2 className="ps-0 pb-4 page-title">TVL Ranking</h2>
<ChainComparisonTVL />
<h2 className="ps-0 pb-4 page-title">Assets ranking</h2>
<Table />
</>
)
Expand Down
24 changes: 24 additions & 0 deletions src/components/Button/DateButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { FC } from 'react'

export interface DateButtonProps {
value: {
value: string;
originalValue: string;
};
isSelected: boolean;
onClick: (value: string) => void;
}

export const DateButton: FC<DateButtonProps> = ({ value, isSelected, onClick }) => {
return (
<div
key={value.value}
onClick={() => onClick(value.originalValue)}
className={`flex flex-row justify-center items-center px-2.5 py-1 cursor-pointer rounded ${
isSelected ? 'bg-slate-50 rounded' : 'data-button-not-selected'
}`}
>
<div className={`selector-text font-bold ${isSelected ? 'text-black' : 'text-white'}`}>{value.value}</div>
</div>
)
}
108 changes: 108 additions & 0 deletions src/components/Charts/AreaChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React, { FC, useCallback, useState } from 'react'
import Chart, { Series } from '.'
import { ApexOptions } from 'apexcharts'
import { DateButton } from 'components/Button/DateButton'
import { Period } from 'types'

interface AreaChartProps {
title: string;
series: Series[];
formatter: (value: number) => string;
displayDateSelector?: boolean;
dateOptions?: {
value: string;
originalValue: string;
}[];
}

export const AreaChart: FC<AreaChartProps> = ({ title, series, formatter, displayDateSelector, dateOptions }) => {
const [period, setPeriod] = useState<string>(Period.SEMESTER)

const options = {
colors: ['#5B61D5'],
xaxis: {
show: false,
labels: {
show: false
},
axisBorder: {
show: false
},
axisTicks: {
show: false
}
},
yaxis: {
show: true,
labels: {
show: true,
align: 'right',
minWidth: 0,
maxWidth: 0,
style: {
colors: ['white'],
fontWeight: 400,
fontSize: 15,
fontFamily: 'DM Sans, sans-serif'
},
offsetX: 60,
formatter
}
},
grid: {
show: false,
padding: {
bottom: -30,
right: -30,
left: -10
}
},
stroke: {
show: true,
curve: 'straight',
width: 1.5
},
fill: {
colors: ['#2B355B'],
type: 'gradient',
gradient: {
type: 'vertical',
gradientToColors: ['#5A5FCC', '#2B355B', '#191C34'],
opacityFrom: 0.9,
opacityTo: 0
},
pattern: {
style: 'verticalLines',
width: 6,
height: 6,
strokeWidth: 2
}
}
}

const handleOnChangeDate = useCallback(
(value: string) => {
setPeriod(value)
},
[setPeriod]
)

return (
<div className="container pt-2 black-gradient rounded-custom px-0 h-full relative">
<div className="row text-white text-center mt-3">
<h6 className="mb-0 font-weight-bold">{title}</h6>
</div>
<Chart series={series} formatter={formatter} customOptions={options as unknown as ApexOptions} chartType="area" height={260} />
{displayDateSelector && dateOptions && (
<div className='flex flex-row absolute bottom-5 right-5 gap-2'>
{dateOptions.map(option => {
const isSelected = option.originalValue === period
return (
<DateButton key={option.originalValue} value={option} isSelected={isSelected} onClick={handleOnChangeDate} />
)
})}
</div>
)}
</div>
)
}
62 changes: 62 additions & 0 deletions src/components/Charts/PieChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { ApexOptions } from 'apexcharts'
import React, { FC } from 'react'
import { Chain } from 'types/chain'
import { getColorForChain } from 'utils/helpers/getColorForChain'
import Chart, { DonutSeries } from '.'

interface PieChartProps {
series: DonutSeries;
formatter: (value: number) => string;
customOptions?: ApexOptions,
}

export const PieChart: FC<PieChartProps> = ({ series, formatter, customOptions }) => {
const baseOptions: ApexOptions = {
chart: {
type: 'donut'
},
legend: {
show: false
},
fill: {
type: 'solid',
opacity: 1
},
stroke: {
show: false
},
tooltip: {
enabled: true,
custom: ({ series, seriesIndex, _dataPointIndex, w }) => {
const { labels } = w.config
const chain = labels[seriesIndex]
const textColor = chain === Chain.ZkSync ? 'black' : 'white'
const value = formatter
? formatter(series[seriesIndex])
: series[seriesIndex]
return '<div class="donut-chart-tooltip">' +
'<span>' + `${chain}: ${value}` + '</span>' +
'</div>' +
'<style>' +
'.donut-chart-tooltip {' +
` background: ${getColorForChain(chain)};` +
` color: ${textColor};` +
" font-family: 'Poppins', sans-serif;" +
' font-weight: 600;' +
' -webkit-box-shadow: none !important;' +
' -moz-box-shadow: none !important;' +
' box-shadow: none !important;' +
' border-radius: 15px !important;' +
' padding: 15px !important;' +
' margin: -10px !important;' +
' border: none !important;' +
'}' +
'</style>'
}
},
...customOptions
}
return (
<Chart series={series} chartType="donut" formatter={formatter} customOptions={baseOptions} width={300} height={300} />
)
}
24 changes: 16 additions & 8 deletions src/components/Charts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@ import dynamic from 'next/dynamic'
import { ApexOptions } from 'apexcharts'
import { baseChartOptions } from 'utils/shared'

interface Props {
series: {
name: string,
data: number[][]
}[],
export interface Series {
name: string;
data: number[][];
}

export type DonutSeries = number[];

interface ChartProps {
series: Series[] | DonutSeries,
customOptions?: ApexOptions,
formatter: (value: number) => string,
chartType?: 'bar' | 'area' | 'donut',
height?: number,
width?: number,
}
const Chart: React.FC<Props> = ({ series, formatter, customOptions }: Props) => {
const Chart: React.FC<ChartProps> = ({ series, formatter, customOptions, chartType = 'bar', height = 400, width }) => {
const ApexCharts = dynamic(() => import('react-apexcharts'), { ssr: false })

const options = {
Expand All @@ -33,8 +40,9 @@ const Chart: React.FC<Props> = ({ series, formatter, customOptions }: Props) =>
options={options.options as ApexOptions}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
series={options.series as any}
type="bar"
height="400"
type={chartType}
height={height}
width={width}
/>
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/DataBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface Props {
}
const DataBlock: React.FC<Props> = ({ color, classes = '', title, data, mobileTitle }: Props) => {
return (
<div className={`pt-3 pb-2 text-white data-block rounded-custom d-flex flex-column align-items-center ${color.toLowerCase()}-gradient ${classes}`}>
<div className={`pt-4 pb-3 text-white data-block rounded-custom d-flex flex-column align-items-center ${color.toLowerCase()}-gradient ${classes}`}>
<p className="text-center d-none d-md-block">{title}</p>
<p className="text-center d-block d-md-none">{mobileTitle || title}</p>
<p className="text-center h4">{data}</p>
Expand Down
37 changes: 37 additions & 0 deletions src/components/Selector/Selector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { FC, ReactNode } from 'react'

interface SelectorProps {
options: {
value: string;
originalValue: string;
}[];
currentOption: string;
onChange: (option: string) => void;
icon?: ReactNode;
}

export const Selector: FC<SelectorProps> = ({ options, currentOption, onChange, icon }) => {
return (
<div className="flex flex-row rounded-md border-opacity-20 p-1.5 selector-border">
{options.map(option => {
const isSelected = option.originalValue === currentOption
return (
<div
key={option.originalValue}
onClick={() => onChange(option.originalValue)}
className={`flex flex-row justify-center items-center px-2.5 py-2 cursor-pointer ${
isSelected ? 'purple-gradient rounded' : 'hover:bg-white hover:bg-opacity-10'
}`}
>
<div className={`selector-text ${isSelected ? 'text-white' : ''}`}>{option.value}</div>
</div>
)
})}
{icon && (
<div className="flex justify-center items-center px-3">
{icon}
</div>
)}
</div>
)
}
Loading