Skip to content

Commit

Permalink
Merge pull request #67 from oceanprotocol/feat/dashboard-v2-enhancements
Browse files Browse the repository at this point in the history
Feat/dashboard v2 enhancements
  • Loading branch information
bogdanfazakas authored Jan 30, 2025
2 parents 41ac8a1 + ae44842 commit 635b577
Show file tree
Hide file tree
Showing 21 changed files with 1,694 additions and 1,078 deletions.
131 changes: 129 additions & 2 deletions src/components/Card/Card.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,30 @@
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
height: 100%;
min-height: 238px;
aspect-ratio: 1 / 1;
width: 100%;
position: relative;
animation: fadeIn 0.5s ease-in;
}

@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

.cardContent {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
position: absolute;
inset: 20px;
}

.cardTitle {
Expand Down Expand Up @@ -65,3 +80,115 @@
line-height: 24px;
}
}

.cardLoading {
position: relative;
overflow: hidden;
}

.cardLoading .cardTitle,
.cardLoading .bigNumber,
.cardLoading .subText {
position: relative;
background: #f6f7f8;
border-radius: 4px;
overflow: hidden;
}

.cardLoading .cardTitle {
height: 24px;
width: 70%;
}

.cardLoading .bigNumber {
height: 60px;
width: 50%;
margin: 100px auto;
}

.cardLoading .subText {
height: 20px;
width: 40%;
margin-left: auto;
margin-top: auto;
margin-bottom: 0;
}

.cardLoading .cardTitle::after,
.cardLoading .bigNumber::after,
.cardLoading .subText::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 100%;
background: linear-gradient(
90deg,
transparent 0%,
rgba(207, 31, 177, 0.2) 50%,
transparent 100%
);
animation: shimmer 2s infinite linear;
transform: translateX(-100%);
}

.cardLoading .bigNumber::after {
animation-delay: 0.1s;
}

.cardLoading .subText::after {
animation-delay: 0.2s;
}

@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(50%);
}
}

.skeletonText {
background: #f0f0f0;
border-radius: 4px;
height: 24px;
width: 80%;
margin-bottom: 15px;
}

.skeletonNumber {
background: #f0f0f0;
border-radius: 4px;
height: 60px;
width: 60%;
margin: 20px auto;
}

.dataLoading {
position: relative;
background: #f6f7f8;
border-radius: 4px;
overflow: hidden;
height: 60px;
width: 50%;
margin: 95px auto;
}

.dataLoading::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 100%;
background: linear-gradient(
90deg,
transparent 0%,
rgba(207, 31, 177, 0.2) 50%,
transparent 100%
);
animation: shimmer 2s infinite linear;
transform: translateX(-100%);
}
182 changes: 131 additions & 51 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Bar,
LineChart,
Line,
Area,
ResponsiveContainer,
XAxis,
Tooltip
Expand All @@ -22,10 +23,8 @@ interface CardProps {
bigNumber?: string | number
subText?: string
additionalInfo?: React.ReactNode
}

const getStrokeColor = ({ channel }: { channel: string }) => {
return channel === 'foreground' ? 'url(#gradient)' : '#E0E0E0'
isLoading?: boolean
dataLoading?: boolean
}

const CustomBar = (props: any) => {
Expand Down Expand Up @@ -74,58 +73,139 @@ const Card: React.FC<CardProps> = ({
chartData,
bigNumber,
subText,
additionalInfo
additionalInfo,
isLoading = false,
dataLoading = false
}) => {
console.log('🚀 ~ chartData:', chartData)
const formatNumber = (num: string | number) => {
if (typeof num === 'string') return num

if (num >= 1000 && num < 1000000) {
return `${(num / 1000).toFixed(1)}K`
}
if (num >= 1000000) {
return `${(num / 1000000).toFixed(2)}M`
}
return new Intl.NumberFormat('en-US').format(num)
}

return (
<div className={styles.card}>
<h3 className={styles.cardTitle}>{title}</h3>
<div className={`${styles.card} ${isLoading ? styles.cardLoading : ''}`}>
<div className={styles.cardContent}>
{chartType === 'bar' && chartData && (
<ResponsiveContainer width="100%" height={100}>
<BarChart data={chartData} barSize={15}>
<defs>
<linearGradient id="gradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#CF1FB1" />
<stop offset="100%" stopColor="#DA4A8C" />
</linearGradient>
</defs>
<XAxis dataKey="date" hide />
<Bar
dataKey="background.value"
shape={(props: any) => (
<CustomBar
{...props}
foregroundValue={props.payload.foreground.value}
backgroundValue={props.payload.background.value}
/>
{isLoading ? (
<>
<div className={styles.cardTitle} aria-hidden="true" />
<div className={styles.bigNumber} aria-hidden="true" />
{chartType && <div className={styles.chartSkeleton} aria-hidden="true" />}
{subText && <div className={styles.subText} aria-hidden="true" />}
</>
) : (
<>
<h3 className={styles.cardTitle}>{title}</h3>
{dataLoading ? (
<div className={styles.dataLoading} aria-hidden="true" />
) : (
<>
{chartType === 'bar' && chartData && (
<ResponsiveContainer width="100%" height={100}>
<BarChart data={chartData} barSize={15}>
<defs>
<linearGradient id="gradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#CF1FB1" />
<stop offset="100%" stopColor="#DA4A8C" />
</linearGradient>
</defs>
<XAxis dataKey="date" hide />
<Bar
dataKey="background.value"
shape={(props: any) => (
<CustomBar
{...props}
foregroundValue={props.payload.foreground.value}
backgroundValue={props.payload.background.value}
/>
)}
/>
<Tooltip />
</BarChart>
</ResponsiveContainer>
)}
/>
<Tooltip />
</BarChart>
</ResponsiveContainer>
)}
{chartType === 'line' && chartData && (
<ResponsiveContainer width="100%" height={100}>
<LineChart data={chartData}>
<defs>
<linearGradient id="lineGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="20%" stopColor="#CF1FB1" stopOpacity={1} />
</linearGradient>
</defs>
<Line
type="monotone"
dataKey="value"
stroke="url(#lineGradient)"
strokeWidth={2}
dot={false}
/>
<Tooltip />
</LineChart>
</ResponsiveContainer>
{chartType === 'line' && chartData && chartData.length > 0 && (
<ResponsiveContainer
width="100%"
height={200}
style={{ paddingTop: '50px' }}
>
<LineChart data={chartData}>
<defs>
<linearGradient id="lineWave" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#CF1FB1" stopOpacity={1} />
<stop offset="100%" stopColor="#CF1FB1" stopOpacity={0.2} />
</linearGradient>
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" />
<feOffset dx="0" dy="4" result="offsetblur" />
<feComponentTransfer>
<feFuncA type="linear" slope="0.2" />
</feComponentTransfer>
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<Line
type="basis"
dataKey="foreground.value"
stroke="url(#lineWave)"
strokeWidth={3}
strokeLinecap="round"
strokeLinejoin="round"
dot={false}
activeDot={{
r: 8,
fill: '#CF1FB1',
stroke: '#ffffff',
strokeWidth: 2
}}
filter="url(#shadow)"
/>
<Area
type="basis"
dataKey="foreground.value"
fill="url(#lineWave)"
strokeWidth={0}
opacity={0.1}
/>
<Tooltip
contentStyle={{
background: '#1A0820',
border: '1px solid #CF1FB1',
borderRadius: '8px',
boxShadow: '0 4px 20px rgba(207, 31, 177, 0.3)'
}}
formatter={(value) => [
<span key="value" style={{ color: '#CF1FB1' }}>
{Number(value).toLocaleString()} ROSE
</span>
]}
labelFormatter={(label) => (
<span style={{ color: '#CF1FB1' }}>{label}</span>
)}
/>
</LineChart>
</ResponsiveContainer>
)}
{bigNumber && (
<div className={styles.bigNumber}>{formatNumber(bigNumber)}</div>
)}
{subText && <p className={styles.subText}>{subText}</p>}
{additionalInfo}
</>
)}
</>
)}
{bigNumber && <div className={styles.bigNumber}>{bigNumber}</div>}
{subText && <p className={styles.subText}>{subText}</p>}
{additionalInfo}
</div>
</div>
)
Expand Down
Loading

0 comments on commit 635b577

Please sign in to comment.