initial commit

This commit is contained in:
YoRHa
2026-02-04 13:39:12 +08:00
commit 199940e958
175 changed files with 19963 additions and 0 deletions

View File

@@ -0,0 +1,226 @@
"use client";
import { useState, useEffect, useRef } from "react";
import Image from "next/image";
import { Button } from "@heroui/react";
import { useApp } from "@/contexts/AppContext";
import * as echarts from "echarts";
export default function SupplyContent() {
const { t } = useApp();
const [selectedPeriod, setSelectedPeriod] = useState<"1W" | "1M" | "1Y">("1W");
const chartRef = useRef<HTMLDivElement>(null);
const chartInstance = useRef<echarts.ECharts | null>(null);
// 模拟 APY 数据
const generateChartData = (period: "1W" | "1M" | "1Y") => {
const dataPoints = period === "1W" ? 7 : period === "1M" ? 30 : 365;
const data = [];
let baseValue = 18 + Math.random() * 4;
for (let i = 0; i < dataPoints; i++) {
const change = (Math.random() - 0.45) * 2;
baseValue = Math.max(15, Math.min(25, baseValue + change));
data.push(parseFloat(baseValue.toFixed(2)));
}
return data;
};
const chartData = generateChartData(selectedPeriod);
// 根据周期生成 X 轴标签
const getXAxisLabels = (period: "1W" | "1M" | "1Y") => {
if (period === "1W") {
return ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
} else if (period === "1M") {
return Array.from({ length: 7 }, (_, i) => `${i * 4 + 1}d`);
} else {
return Array.from({ length: 7 }, (_, i) => `${i * 50 + 1}d`);
}
};
useEffect(() => {
if (chartRef.current) {
chartInstance.current = echarts.init(chartRef.current);
updateChart();
}
const handleResize = () => {
chartInstance.current?.resize();
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
chartInstance.current?.dispose();
};
}, [selectedPeriod]);
const updateChart = () => {
if (!chartInstance.current) return;
const option: echarts.EChartsOption = {
grid: {
left: 0,
right: 0,
top: 10,
bottom: 0,
},
tooltip: {
trigger: "axis",
show: true,
confine: true,
backgroundColor: "rgba(17, 24, 39, 0.9)",
borderColor: "#374151",
textStyle: {
color: "#f9fafb",
fontSize: 12,
fontWeight: 500,
},
formatter: function(params: any) {
const data = params[0];
return `<div style="padding: 4px 8px;">
<span style="color: #9ca3af; font-size: 11px;">${data.axisValueLabel}</span><br/>
<span style="color: #10b981; font-weight: 600; font-size: 14px;">${data.value}%</span>
</div>`;
},
},
xAxis: {
type: "category",
data: getXAxisLabels(selectedPeriod),
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: selectedPeriod === "1W",
color: "#9ca3af",
fontSize: 10,
fontWeight: 500,
},
},
yAxis: {
type: "value",
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
splitLine: {
show: false,
},
},
series: [
{
data: chartData,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 6,
lineStyle: {
color: "#10b981",
width: 2,
},
itemStyle: {
color: "#10b981",
},
areaStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "rgba(16, 185, 129, 0.3)" },
{ offset: 1, color: "rgba(16, 185, 129, 0)" },
],
},
},
},
],
};
chartInstance.current.setOption(option);
};
return (
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 p-8 flex flex-col h-full w-full shadow-md">
{/* Header - USDC Lend Pool */}
<div className="flex items-center gap-3 flex-shrink-0">
<Image
src="/usd-coin-usdc-logo-10.svg"
alt="USDC"
width={32}
height={32}
/>
<h1 className="text-heading-h2 font-bold text-text-primary dark:text-white leading-[130%] tracking-[-0.01em]">
{t("supply.usdcLendPool")}
</h1>
</div>
{/* Historical APY Section */}
<div className="flex items-start justify-between flex-shrink-0">
{/* Left - APY Display */}
<div className="flex flex-col gap-1">
<span className="text-[12px] font-bold text-text-tertiary dark:text-gray-400 leading-[16px] tracking-[1.2px] uppercase">
{t("supply.historicalApy")}
</span>
<div className="flex items-center gap-2">
<span className="text-heading-h2 font-bold text-[#10b981] dark:text-green-400 leading-[130%] tracking-[-0.01em]">
20.5%
</span>
<div className="bg-[#e1f8ec] dark:bg-green-900/30 rounded-full px-2 py-0.5 flex items-center justify-center">
<span className="text-caption-tiny font-bold text-[#10b981] dark:text-green-400 leading-[150%] tracking-[0.01em]">
+2.4%
</span>
</div>
</div>
</div>
{/* Right - Period Selector */}
<div className="bg-[#F9FAFB] dark:bg-gray-700 rounded-xl p-1 flex items-center gap-1">
<Button
size="sm"
variant={selectedPeriod === "1W" ? "solid" : "light"}
onPress={() => setSelectedPeriod("1W")}
>
1W
</Button>
<Button
size="sm"
variant={selectedPeriod === "1M" ? "solid" : "light"}
onPress={() => setSelectedPeriod("1M")}
>
1M
</Button>
<Button
size="sm"
variant={selectedPeriod === "1Y" ? "solid" : "light"}
onPress={() => setSelectedPeriod("1Y")}
>
1Y
</Button>
</div>
</div>
{/* Chart Section */}
<div className="flex-1 min-h-0 w-full">
{/* ECharts Chart */}
<div
ref={chartRef}
className="w-full h-full"
style={{
background: "linear-gradient(0deg, rgba(16, 185, 129, 0.1) 0%, transparent 100%)",
}}
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,159 @@
"use client";
import { useState } from "react";
import Image from "next/image";
import { Button } from "@heroui/react";
import { useApp } from "@/contexts/AppContext";
import { buttonStyles } from "@/lib/buttonStyles";
export default function SupplyPanel() {
const { t } = useApp();
const [amount, setAmount] = useState("");
return (
<div className="p-6 flex flex-col gap-6 flex-1">
{/* Token Balance & Supplied */}
<div className="flex flex-col gap-4">
{/* Token Balance */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 p-3 flex flex-col gap-1">
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
{t("supply.tokenBalance")}
</span>
<div className="flex items-center justify-between">
<span className="text-body-large font-bold text-text-primary dark:text-white leading-[150%]">
45,230.00
</span>
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
JLP
</span>
</div>
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
$45,230.00
</span>
</div>
{/* Supplied */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 p-3 flex flex-col gap-1">
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
{t("supply.supplied")}
</span>
<div className="flex items-center justify-between">
<span className="text-body-large font-bold text-text-primary dark:text-white leading-[150%]">
0.00
</span>
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
USDC
</span>
</div>
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
$0.00
</span>
</div>
</div>
{/* Deposit Section */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 p-4 flex flex-col gap-4">
{/* Deposit Label and Available */}
<div className="flex items-center gap-2">
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
{t("supply.deposit")}
</span>
<div className="flex items-center gap-2 ml-auto">
<Image src="/wallet-icon.svg" alt="" width={12} height={12} />
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
45,230.00 USDC
</span>
</div>
<Button size="sm" color="default" variant="solid" className={buttonStyles({ intent: "max" })}>
{t("supply.max")}
</Button>
</div>
{/* Input Row */}
<div className="flex items-center justify-between h-12">
{/* USDC Token Button */}
<div className="bg-bg-surface dark:bg-gray-800 rounded-full border border-border-normal dark:border-gray-600 p-2 flex items-center gap-2 h-12">
<Image
src="/usd-coin-usdc-logo-10.svg"
alt="USDC"
width={32}
height={32}
/>
<span className="text-body-default font-bold text-text-primary dark:text-white leading-[150%]">
USDC
</span>
</div>
{/* Amount Input */}
<div className="flex flex-col items-end">
<input
type="text"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="0.00"
className="text-heading-h3 font-bold text-text-input-box dark:text-gray-500 leading-[130%] tracking-[-0.005em] text-right bg-transparent outline-none w-24"
/>
<span className="text-caption-tiny font-regular text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
--
</span>
</div>
</div>
</div>
{/* Health Factor */}
<div className="flex flex-col gap-3">
<div className="flex items-center justify-between">
<div className="flex flex-col gap-1">
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
{t("supply.healthFactor")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white leading-[150%]">
0% {t("supply.utilization")}
</span>
</div>
<span className="text-caption-tiny font-bold text-[#10b981] dark:text-green-400 leading-[150%] tracking-[0.01em]">
{t("supply.safe")}
</span>
</div>
{/* Progress Bar */}
<div className="w-full h-2 bg-fill-secondary-click dark:bg-gray-700 rounded-full overflow-hidden">
<div
className="h-full rounded-full"
style={{
background: "linear-gradient(90deg, #10b981 0%, #ffb933 100%)",
width: "0%",
}}
/>
</div>
</div>
{/* Estimated Returns */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-2xl p-4 flex flex-col gap-2">
<span className="text-body-small font-medium text-text-secondary dark:text-gray-300 leading-[150%]">
{t("supply.estimatedReturns")}
</span>
<div className="flex items-center justify-between">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400 leading-[150%]">
{t("supply.estApy")}
</span>
<span className="text-body-small font-bold text-[#ff6900] dark:text-orange-400 leading-[150%]">
22%
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400 leading-[150%]">
{t("supply.estReturnsYear")}
</span>
<span className="text-body-small font-bold text-[#10b981] dark:text-green-400 leading-[150%]">
~ $0.50
</span>
</div>
</div>
{/* Supply Button */}
<Button color="default" variant="solid" className={`${buttonStyles({ intent: "theme" })} mt-auto`} endContent={<Image src="/arrow-right-icon.svg" alt="" width={20} height={20} />}>
{t("supply.supply")}
</Button>
</div>
);
}

View File

@@ -0,0 +1,159 @@
"use client";
import { useState } from "react";
import Image from "next/image";
import { Button } from "@heroui/react";
import { useApp } from "@/contexts/AppContext";
import { buttonStyles } from "@/lib/buttonStyles";
export default function WithdrawPanel() {
const { t } = useApp();
const [amount, setAmount] = useState("45230");
return (
<div className="p-6 flex flex-col gap-6 flex-1">
{/* Token Balance & Supplied */}
<div className="flex flex-col gap-4">
{/* Token Balance */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 p-3 flex flex-col gap-1">
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
{t("supply.tokenBalance")}
</span>
<div className="flex items-center justify-between">
<span className="text-body-large font-bold text-text-primary dark:text-white leading-[150%]">
45,230.00
</span>
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
JLP
</span>
</div>
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
$45,230.00
</span>
</div>
{/* Supplied */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 p-3 flex flex-col gap-1">
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
{t("supply.supplied")}
</span>
<div className="flex items-center justify-between">
<span className="text-body-large font-bold text-text-primary dark:text-white leading-[150%]">
0.00
</span>
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
USDC
</span>
</div>
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
$0.00
</span>
</div>
</div>
{/* Withdraw Section */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 p-4 flex flex-col gap-4">
{/* Withdraw Label and Available */}
<div className="flex items-center gap-2">
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
{t("supply.withdraw")}
</span>
<div className="flex items-center gap-2 ml-auto">
<Image src="/wallet-icon.svg" alt="" width={12} height={12} />
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
45,230.00 USDC
</span>
</div>
<Button size="sm" className={buttonStyles({ intent: "max" })}>
{t("supply.max")}
</Button>
</div>
{/* Input Row */}
<div className="flex items-center justify-between h-12">
{/* USDC Token Button */}
<div className="bg-bg-surface dark:bg-gray-800 rounded-full border border-border-normal dark:border-gray-600 p-2 flex items-center gap-2 h-12">
<Image
src="/usd-coin-usdc-logo-10.svg"
alt="USDC"
width={32}
height={32}
/>
<span className="text-body-default font-bold text-text-primary dark:text-white leading-[150%]">
USDC
</span>
</div>
{/* Amount Input */}
<div className="flex flex-col items-end">
<input
type="text"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="0"
className="text-heading-h3 font-bold text-text-primary dark:text-white leading-[130%] tracking-[-0.005em] text-right bg-transparent outline-none w-24"
/>
<span className="text-caption-tiny font-regular text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
$1233.00 USD
</span>
</div>
</div>
</div>
{/* Health Factor */}
<div className="flex flex-col gap-3">
<div className="flex items-center justify-between">
<div className="flex flex-col gap-1">
<span className="text-[10px] font-medium text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
{t("supply.healthFactor")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white leading-[150%]">
0% {t("supply.utilization")}
</span>
</div>
<span className="text-caption-tiny font-bold text-[#10b981] dark:text-green-400 leading-[150%] tracking-[0.01em]">
{t("supply.safe")}
</span>
</div>
{/* Progress Bar */}
<div className="w-full h-2 bg-fill-secondary-click dark:bg-gray-700 rounded-full overflow-hidden">
<div
className="h-full rounded-full"
style={{
background: "linear-gradient(90deg, #10b981 0%, #ffb933 100%)",
width: "0%",
}}
/>
</div>
</div>
{/* Estimated Returns */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-2xl p-4 flex flex-col gap-2">
<span className="text-body-small font-medium text-text-secondary dark:text-gray-300 leading-[150%]">
{t("supply.estimatedReturns")}
</span>
<div className="flex items-center justify-between">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400 leading-[150%]">
{t("supply.estApy")}
</span>
<span className="text-body-small font-bold text-[#ff6900] dark:text-orange-400 leading-[150%]">
22%
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400 leading-[150%]">
{t("supply.estReturnsYear")}
</span>
<span className="text-body-small font-bold text-[#10b981] dark:text-green-400 leading-[150%]">
~ $0.50
</span>
</div>
</div>
{/* Withdraw Button */}
<Button className={`${buttonStyles({ intent: "theme" })} mt-auto`} endContent={<Image src="/arrow-right-icon.svg" alt="" width={20} height={20} />}>
{t("supply.withdraw")}
</Button>
</div>
);
}