213 lines
7.9 KiB
TypeScript
213 lines
7.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Image from "next/image";
|
|
import { useApp } from "@/contexts/AppContext";
|
|
|
|
interface CalendarDayProps {
|
|
day: number | null;
|
|
value: string;
|
|
type: "positive" | "negative" | "neutral" | "current";
|
|
}
|
|
|
|
function CalendarDay({ day, value, type }: CalendarDayProps) {
|
|
// Empty cell
|
|
if (day === null) {
|
|
return <div className="flex-1" />;
|
|
}
|
|
|
|
const typeStyles = {
|
|
positive: "bg-[#f2fcf7] dark:bg-green-900/20 border-[#cef3e0] dark:border-green-700/30",
|
|
negative: "bg-[#fff8f7] dark:bg-red-900/20 border-[#ffdbd5] dark:border-red-700/30",
|
|
neutral: "bg-[#f9fafb] dark:bg-gray-700 border-[#f3f4f6] dark:border-gray-600",
|
|
current: "bg-[#111827] dark:bg-[#111827] border-[#111827] dark:border-[#111827]",
|
|
};
|
|
|
|
const isCurrent = type === "current";
|
|
const dayTextStyle = isCurrent
|
|
? "text-[#fcfcfd]"
|
|
: "text-[#9ca1af] dark:text-gray-400";
|
|
|
|
// Value text color should match the type
|
|
let valueTextStyle = "";
|
|
if (isCurrent) {
|
|
valueTextStyle = "text-[#10b981]";
|
|
} else if (type === "positive") {
|
|
valueTextStyle = "text-[#10b981] dark:text-green-400";
|
|
} else if (type === "negative") {
|
|
valueTextStyle = "text-[#dc2626] dark:text-red-400";
|
|
} else {
|
|
valueTextStyle = "text-[#9ca1af] dark:text-gray-400";
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={`rounded border flex flex-col items-center justify-center flex-1 p-3 gap-6 ${typeStyles[type]}`}
|
|
>
|
|
<div className="w-full flex items-start">
|
|
<span className={`text-[10px] font-bold leading-[150%] ${dayTextStyle}`}>
|
|
{day}
|
|
</span>
|
|
</div>
|
|
<div className="w-full flex flex-col items-end gap-1">
|
|
<span className={`text-body-small font-bold leading-[150%] ${valueTextStyle}`}>
|
|
{value}
|
|
</span>
|
|
{isCurrent && (
|
|
<span className="text-[10px] font-bold leading-[150%] tracking-[0.01em] text-[#9DA1AE]">
|
|
Today
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface StatCardProps {
|
|
label: string;
|
|
value: string;
|
|
}
|
|
|
|
function StatCard({ label, value }: StatCardProps) {
|
|
return (
|
|
<div className="flex flex-col items-center gap-1">
|
|
<span className="text-[10px] font-bold leading-[150%] tracking-[0.01em] text-[#9ca1af] dark:text-gray-400">
|
|
{label}
|
|
</span>
|
|
<span className="text-body-large font-bold text-[#10b981] dark:text-green-400">
|
|
{value}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function PerformanceAnalysis() {
|
|
const { t } = useApp();
|
|
const [currentMonth] = useState("November 2025");
|
|
|
|
// 模拟日历数据 - 5周数据
|
|
const weekData = [
|
|
[
|
|
{ day: 31, value: "0.00%", type: "neutral" as const },
|
|
{ day: 1, value: "+0.12%", type: "positive" as const },
|
|
{ day: 2, value: "+0.08%", type: "positive" as const },
|
|
{ day: 3, value: "-0.03%", type: "negative" as const },
|
|
{ day: 4, value: "+0.15%", type: "positive" as const },
|
|
{ day: 5, value: "+0.21%", type: "positive" as const },
|
|
{ day: 6, value: "0.00%", type: "neutral" as const },
|
|
],
|
|
[
|
|
{ day: 7, value: "+0.12%", type: "positive" as const },
|
|
{ day: 8, value: "+0.12%", type: "positive" as const },
|
|
{ day: 9, value: "-0.03%", type: "negative" as const },
|
|
{ day: 10, value: "+0.08%", type: "positive" as const },
|
|
{ day: 11, value: "-0.03%", type: "negative" as const },
|
|
{ day: 12, value: "+0.21%", type: "positive" as const },
|
|
{ day: 13, value: "0.00%", type: "neutral" as const },
|
|
],
|
|
[
|
|
{ day: 14, value: "-0.03%", type: "negative" as const },
|
|
{ day: 15, value: "-0.03%", type: "negative" as const },
|
|
{ day: 16, value: "+0.15%", type: "positive" as const },
|
|
{ day: 17, value: "+0.21%", type: "positive" as const },
|
|
{ day: 18, value: "+0.08%", type: "positive" as const },
|
|
{ day: 19, value: "0.00%", type: "neutral" as const },
|
|
{ day: 20, value: "+0.12%", type: "positive" as const },
|
|
],
|
|
[
|
|
{ day: 21, value: "+0.08%", type: "positive" as const },
|
|
{ day: 22, value: "+0.15%", type: "positive" as const },
|
|
{ day: 23, value: "-0.03%", type: "negative" as const },
|
|
{ day: 24, value: "+0.12%", type: "current" as const },
|
|
{ day: 25, value: "0.00%", type: "neutral" as const },
|
|
{ day: 26, value: "+0.21%", type: "positive" as const },
|
|
{ day: 27, value: "+0.08%", type: "positive" as const },
|
|
],
|
|
[
|
|
{ day: 28, value: "+0.12%", type: "positive" as const },
|
|
{ day: 30, value: "-0.03%", type: "negative" as const },
|
|
{ day: 29, value: "-0.03%", type: "negative" as const },
|
|
{ day: null, value: "", type: "neutral" as const },
|
|
{ day: null, value: "", type: "neutral" as const },
|
|
{ day: null, value: "", type: "neutral" as const },
|
|
{ day: null, value: "", type: "neutral" as const },
|
|
],
|
|
];
|
|
|
|
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 gap-8">
|
|
{/* Top Section - Title and Stats */}
|
|
<div className="flex items-start justify-between pb-8 border-b border-border-gray dark:border-gray-700">
|
|
<div className="flex flex-col gap-2">
|
|
<h2 className="text-body-large font-bold text-text-primary dark:text-white">
|
|
{t("performance.title")}
|
|
</h2>
|
|
<p className="text-body-small font-regular text-[#9ca1af] dark:text-gray-400">
|
|
{t("performance.description")}
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-8">
|
|
<StatCard label={t("performance.ytd")} value="+8.7%" />
|
|
<StatCard label={t("performance.ytd")} value="+8.7%" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Calendar Section */}
|
|
<div className="flex flex-col gap-6">
|
|
{/* Calendar Header */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-6 h-6">
|
|
<Image src="/component-114.svg" alt="" width={24} height={24} />
|
|
</div>
|
|
<h3 className="text-body-small font-bold text-text-primary dark:text-white">
|
|
{t("performance.dailyNetReturns")}
|
|
</h3>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<button className="w-6 h-6 rounded-lg flex items-center justify-center hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
|
|
<Image src="/icon9.svg" alt="Previous" width={16} height={16} />
|
|
</button>
|
|
<span className="text-body-small font-bold text-[#0a0a0a] dark:text-white tracking-tight">
|
|
{currentMonth}
|
|
</span>
|
|
<button className="w-6 h-6 rounded-lg flex items-center justify-center hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
|
|
<Image src="/icon10.svg" alt="Next" width={16} height={16} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Calendar */}
|
|
<div className="flex flex-col gap-4">
|
|
{/* Weekday Headers */}
|
|
<div className="grid grid-cols-7 gap-2">
|
|
{["sun", "mon", "tue", "wed", "thu", "fri", "sat"].map((day) => (
|
|
<div key={day} className="flex items-center justify-center">
|
|
<span className="text-[10px] font-bold leading-[150%] text-[#94a3b8] dark:text-gray-400">
|
|
{t(`performance.weekdays.${day}`)}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Calendar Grid */}
|
|
<div className="flex flex-col gap-1">
|
|
{weekData.map((week, weekIndex) => (
|
|
<div key={weekIndex} className="grid grid-cols-7 gap-2">
|
|
{week.map((day, dayIndex) => (
|
|
<CalendarDay
|
|
key={`${weekIndex}-${dayIndex}`}
|
|
day={day.day}
|
|
value={day.value}
|
|
type={day.type}
|
|
/>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|