feat: integrate HeroUI component library

Implemented HeroUI migration plan with the following changes:

Stage 0: Environment Setup
- Installed @heroui/react@2.8.7, @heroui/theme@2.4.26, framer-motion@12.29.2
- Configured Tailwind with HeroUI plugin
- Added HeroUI content paths to Tailwind config

Stage 1: Provider Architecture
- Created Providers.tsx wrapper combining HeroUIProvider and AppProvider
- Updated app/layout.tsx to use new Providers component
- Preserved all AppContext functionality (theme, language, translations)

Stage 2: Component Migrations
- TabNavigation: Migrated to HeroUI Tabs with keyboard navigation support
- TopBar: Migrated buttons to HeroUI Button components
- LanguageSwitch: Migrated to HeroUI Dropdown for better UX
- ThemeSwitch: Migrated to HeroUI Button (isIconOnly variant)
- MintSwapPanel: Migrated to HeroUI Tabs and Button components

Benefits:
- Enhanced accessibility with ARIA attributes and keyboard navigation
- Smooth animations and transitions via Framer Motion
- Consistent component API across the application
- Maintained all existing design tokens and color system
- Preserved dark mode functionality

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-30 03:49:53 +00:00
parent 098a91f2ac
commit 9e0dd1d278
27 changed files with 11184 additions and 7928 deletions

View File

@@ -1,101 +1,101 @@
"use client";
import { useState } from "react";
import { useApp } from "@/contexts/AppContext";
export default function APYHistoryCard() {
const { t } = useApp();
const [activeTab, setActiveTab] = useState<"apy" | "price">("apy");
// 橙色渐变条形图数据
const chartData = [
{ height: 85, color: "#ffe9dc" },
{ height: 93, color: "#ffc9ad" },
{ height: 100, color: "#ffc9ad" },
{ height: 105, color: "#ffba96" },
{ height: 108, color: "#ffa67e" },
{ height: 116, color: "#f48d5f" },
{ height: 124, color: "#ff6900" },
{ height: 127, color: "#f35b00" },
{ height: 139, color: "#d64700" },
];
return (
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 p-6 flex flex-col gap-6">
{/* Tabs */}
<div className="flex gap-6 border-b border-border-gray dark:border-gray-700">
<button
onClick={() => setActiveTab("apy")}
className={`pb-3 px-1 text-body-small font-bold transition-colors ${
activeTab === "apy"
? "text-text-primary dark:text-white border-b-2 border-text-primary dark:border-white -mb-[1px]"
: "text-text-tertiary dark:text-gray-400"
}`}
>
{t("apy.apyHistory")}
</button>
<button
onClick={() => setActiveTab("price")}
className={`pb-3 px-1 text-body-small font-bold transition-colors ${
activeTab === "price"
? "text-text-primary dark:text-white border-b-2 border-text-primary dark:border-white -mb-[1px]"
: "text-text-tertiary dark:text-gray-400"
}`}
>
{t("apy.priceHistory")}
</button>
</div>
{/* Chart Area */}
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">
{t("apy.lastDays")}
</span>
</div>
{/* Orange Gradient Chart */}
<div
className="flex items-end gap-4 w-full border-b border-border-gray dark:border-gray-700"
style={{
height: "140px",
background:
"linear-gradient(0deg, rgba(255, 247, 237, 0.5) 0%, rgba(255, 247, 237, 0) 100%)",
}}
>
{chartData.map((bar, index) => (
<div
key={index}
className="flex-1"
style={{
height: `${bar.height}px`,
backgroundColor: bar.color,
borderRadius: "2px 2px 0px 0px",
}}
/>
))}
</div>
{/* Stats */}
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">
{t("apy.highest")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white">
24.8%
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">
{t("apy.lowest")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white">
18.2%
</span>
</div>
</div>
</div>
</div>
);
}
"use client";
import { useState } from "react";
import { useApp } from "@/contexts/AppContext";
export default function APYHistoryCard() {
const { t } = useApp();
const [activeTab, setActiveTab] = useState<"apy" | "price">("apy");
// 橙色渐变条形图数据
const chartData = [
{ height: 85, color: "#ffe9dc" },
{ height: 93, color: "#ffc9ad" },
{ height: 100, color: "#ffc9ad" },
{ height: 105, color: "#ffba96" },
{ height: 108, color: "#ffa67e" },
{ height: 116, color: "#f48d5f" },
{ height: 124, color: "#ff6900" },
{ height: 127, color: "#f35b00" },
{ height: 139, color: "#d64700" },
];
return (
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 p-6 flex flex-col gap-6">
{/* Tabs */}
<div className="flex gap-6 border-b border-border-gray dark:border-gray-700">
<button
onClick={() => setActiveTab("apy")}
className={`pb-3 px-1 text-body-small font-bold transition-colors ${
activeTab === "apy"
? "text-text-primary dark:text-white border-b-2 border-text-primary dark:border-white -mb-[1px]"
: "text-text-tertiary dark:text-gray-400"
}`}
>
{t("apy.apyHistory")}
</button>
<button
onClick={() => setActiveTab("price")}
className={`pb-3 px-1 text-body-small font-bold transition-colors ${
activeTab === "price"
? "text-text-primary dark:text-white border-b-2 border-text-primary dark:border-white -mb-[1px]"
: "text-text-tertiary dark:text-gray-400"
}`}
>
{t("apy.priceHistory")}
</button>
</div>
{/* Chart Area */}
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">
{t("apy.lastDays")}
</span>
</div>
{/* Orange Gradient Chart */}
<div
className="flex items-end gap-4 w-full border-b border-border-gray dark:border-gray-700"
style={{
height: "140px",
background:
"linear-gradient(0deg, rgba(255, 247, 237, 0.5) 0%, rgba(255, 247, 237, 0) 100%)",
}}
>
{chartData.map((bar, index) => (
<div
key={index}
className="flex-1"
style={{
height: `${bar.height}px`,
backgroundColor: bar.color,
borderRadius: "2px 2px 0px 0px",
}}
/>
))}
</div>
{/* Stats */}
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">
{t("apy.highest")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white">
24.8%
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-text-tertiary dark:text-gray-400">
{t("apy.lowest")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white">
18.2%
</span>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,237 +1,237 @@
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface VerificationCardProps {
icon: string;
title: string;
description: string;
buttonText: string;
}
function VerificationCard({ icon, title, description, buttonText }: VerificationCardProps) {
return (
<div className="flex-1 bg-bg-surface dark:bg-gray-700 rounded-2xl border border-border-normal dark:border-gray-600 p-6 flex flex-col justify-between">
<div className="flex items-start gap-4">
<div className="w-5 h-5 flex-shrink-0">
<Image src={icon} alt={title} width={20} height={20} />
</div>
<div className="flex flex-col gap-1">
<h4 className="text-body-default font-bold text-text-primary dark:text-white">
{title}
</h4>
<p className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
{description}
</p>
</div>
</div>
<button className="flex items-center gap-2 hover:opacity-80 transition-opacity mt-[118px]">
<span className="text-[10px] font-bold leading-[150%] tracking-[0.01em] text-[#9ca1af] dark:text-gray-400">
{buttonText}
</span>
<Image src="/component-118.svg" alt="" width={16} height={16} />
</button>
</div>
);
}
export default function AssetCustodyVerification() {
const { t } = useApp();
return (
<div className="flex flex-col gap-8 w-full">
{/* Header */}
<div className="flex flex-col gap-2">
<h2 className="text-body-large font-bold text-text-primary dark:text-white">
{t("custody.title")}
</h2>
<p className="text-body-small font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.description")}
</p>
</div>
{/* Holdings Table Card */}
<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-6">
{/* Table Header */}
<div className="flex flex-col gap-6 pb-6 border-b border-border-gray dark:border-gray-700">
<div className="flex flex-col gap-1">
<h3 className="text-body-default font-bold text-text-primary dark:text-white">
{t("custody.underlyingHoldings")}
</h3>
<p className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.verifiedBy")}
</p>
</div>
<div className="flex items-center gap-2">
<Image src="/component-115.svg" alt="" width={16} height={16} />
<span className="text-caption-tiny font-medium text-[#9ca1af] dark:text-gray-400">
{t("custody.lastUpdated")}: 2 {t("custody.minutesAgo")}
</span>
</div>
</div>
{/* Table */}
<div className="flex flex-col">
{/* Table Header Row */}
<div className="grid grid-cols-5 gap-4 pb-4 border-b border-border-gray dark:border-gray-700">
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.custodian")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.assetType")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.maturity")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.valueUSD")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.status")}
</div>
</div>
{/* Table Body Row */}
<div className="grid grid-cols-5 gap-4 py-6">
{/* Custodian */}
<div className="flex items-center gap-3">
<div
className="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0"
style={{
background: "linear-gradient(135deg, rgba(255, 137, 4, 1) 0%, rgba(245, 73, 0, 1) 100%)",
}}
>
<span className="text-[13.5px] font-bold leading-[19px] text-white tracking-tight">
GY
</span>
</div>
<div className="flex flex-col">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.morganStanley")}
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.primeBroker")}
</span>
</div>
</div>
{/* Asset Type */}
<div className="flex items-center">
<span className="text-body-small font-medium text-text-primary dark:text-white">
{t("custody.usEquityPortfolio")}
</span>
</div>
{/* Maturity */}
<div className="flex flex-col justify-center">
<span className="text-body-small font-medium text-text-primary dark:text-white">
05 Feb 2026
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
(77 {t("custody.days")})
</span>
</div>
{/* Value */}
<div className="flex items-center">
<span className="text-body-small font-medium text-text-primary dark:text-white">
$12,500,000.00
</span>
</div>
{/* Status */}
<div className="flex items-center">
<div className="rounded-full px-3 py-1.5 flex items-center gap-2 bg-[#f2fcf7] dark:bg-green-900/20">
<Image src="/component-116.svg" alt="" width={12} height={12} />
<span className="text-[10px] font-bold leading-[150%] text-[#10b981] dark:text-green-400">
{t("custody.verified")}
</span>
</div>
</div>
</div>
{/* Table Footer Row */}
<div className="grid grid-cols-5 gap-4 pt-6 border-t border-border-gray dark:border-gray-700">
<div className="col-span-3 flex items-center">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.totalValue")}
</span>
</div>
<div className="col-span-2 flex items-center">
<span className="text-body-default font-bold text-text-primary dark:text-white">
$12,500,000.00
</span>
</div>
</div>
</div>
</div>
{/* Verification Cards Row */}
<div className="flex flex-row gap-6 pt-6">
<VerificationCard
icon="/component-117.svg"
title={t("custody.smartContract")}
description={t("custody.smartContractDesc")}
buttonText={t("custody.viewReports")}
/>
<VerificationCard
icon="/component-119.svg"
title={t("custody.compliance")}
description={t("custody.complianceDesc")}
buttonText={t("custody.viewReports")}
/>
<VerificationCard
icon="/component-121.svg"
title={t("custody.proofOfReserves")}
description={t("custody.proofDesc")}
buttonText={t("custody.viewReports")}
/>
{/* Independent Verifications */}
<div className="flex-1 rounded-2xl border bg-[#f9fafb] dark:bg-gray-700 border-[#e5e7eb] dark:border-gray-600 p-6 flex flex-col">
<div className="flex flex-col gap-2">
<h3 className="text-body-default font-bold text-text-primary dark:text-white">
{t("custody.independentVerifications")}
</h3>
<p className="text-body-small font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.independentDesc")}
</p>
</div>
<div className="flex flex-col gap-2 mt-6">
<div className="rounded-2xl border bg-white dark:bg-gray-800 border-[#e5e7eb] dark:border-gray-600 p-4 flex items-center justify-between">
<div className="flex flex-col gap-0.5">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.attestationReport")}
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
November 2025
</span>
</div>
<Image src="/component-123.svg" alt="" width={24} height={24} />
</div>
<div className="rounded-2xl border bg-white dark:bg-gray-800 border-[#e5e7eb] dark:border-gray-600 p-4 flex items-center justify-between">
<div className="flex flex-col gap-0.5">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.attestationReport")}
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
October 2025
</span>
</div>
<Image src="/component-124.svg" alt="" width={24} height={24} />
</div>
</div>
<button className="flex items-center gap-2 hover:opacity-80 transition-opacity mt-4">
<span className="text-[10px] font-bold leading-[150%] tracking-[0.01em] text-[#9ca1af] dark:text-gray-400">
{t("custody.viewAllArchive")}
</span>
<Image src="/component-125.svg" alt="" width={16} height={16} />
</button>
</div>
</div>
</div>
);
}
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface VerificationCardProps {
icon: string;
title: string;
description: string;
buttonText: string;
}
function VerificationCard({ icon, title, description, buttonText }: VerificationCardProps) {
return (
<div className="flex-1 bg-bg-surface dark:bg-gray-700 rounded-2xl border border-border-normal dark:border-gray-600 p-6 flex flex-col justify-between">
<div className="flex items-start gap-4">
<div className="w-5 h-5 flex-shrink-0">
<Image src={icon} alt={title} width={20} height={20} />
</div>
<div className="flex flex-col gap-1">
<h4 className="text-body-default font-bold text-text-primary dark:text-white">
{title}
</h4>
<p className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
{description}
</p>
</div>
</div>
<button className="flex items-center gap-2 hover:opacity-80 transition-opacity mt-[118px]">
<span className="text-[10px] font-bold leading-[150%] tracking-[0.01em] text-[#9ca1af] dark:text-gray-400">
{buttonText}
</span>
<Image src="/component-118.svg" alt="" width={16} height={16} />
</button>
</div>
);
}
export default function AssetCustodyVerification() {
const { t } = useApp();
return (
<div className="flex flex-col gap-8 w-full">
{/* Header */}
<div className="flex flex-col gap-2">
<h2 className="text-body-large font-bold text-text-primary dark:text-white">
{t("custody.title")}
</h2>
<p className="text-body-small font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.description")}
</p>
</div>
{/* Holdings Table Card */}
<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-6">
{/* Table Header */}
<div className="flex flex-col gap-6 pb-6 border-b border-border-gray dark:border-gray-700">
<div className="flex flex-col gap-1">
<h3 className="text-body-default font-bold text-text-primary dark:text-white">
{t("custody.underlyingHoldings")}
</h3>
<p className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.verifiedBy")}
</p>
</div>
<div className="flex items-center gap-2">
<Image src="/component-115.svg" alt="" width={16} height={16} />
<span className="text-caption-tiny font-medium text-[#9ca1af] dark:text-gray-400">
{t("custody.lastUpdated")}: 2 {t("custody.minutesAgo")}
</span>
</div>
</div>
{/* Table */}
<div className="flex flex-col">
{/* Table Header Row */}
<div className="grid grid-cols-5 gap-4 pb-4 border-b border-border-gray dark:border-gray-700">
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.custodian")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.assetType")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.maturity")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.valueUSD")}
</div>
<div className="text-caption-tiny font-bold uppercase tracking-wider text-[#9ca1af] dark:text-gray-400">
{t("custody.status")}
</div>
</div>
{/* Table Body Row */}
<div className="grid grid-cols-5 gap-4 py-6">
{/* Custodian */}
<div className="flex items-center gap-3">
<div
className="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0"
style={{
background: "linear-gradient(135deg, rgba(255, 137, 4, 1) 0%, rgba(245, 73, 0, 1) 100%)",
}}
>
<span className="text-[13.5px] font-bold leading-[19px] text-white tracking-tight">
GY
</span>
</div>
<div className="flex flex-col">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.morganStanley")}
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.primeBroker")}
</span>
</div>
</div>
{/* Asset Type */}
<div className="flex items-center">
<span className="text-body-small font-medium text-text-primary dark:text-white">
{t("custody.usEquityPortfolio")}
</span>
</div>
{/* Maturity */}
<div className="flex flex-col justify-center">
<span className="text-body-small font-medium text-text-primary dark:text-white">
05 Feb 2026
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
(77 {t("custody.days")})
</span>
</div>
{/* Value */}
<div className="flex items-center">
<span className="text-body-small font-medium text-text-primary dark:text-white">
$12,500,000.00
</span>
</div>
{/* Status */}
<div className="flex items-center">
<div className="rounded-full px-3 py-1.5 flex items-center gap-2 bg-[#f2fcf7] dark:bg-green-900/20">
<Image src="/component-116.svg" alt="" width={12} height={12} />
<span className="text-[10px] font-bold leading-[150%] text-[#10b981] dark:text-green-400">
{t("custody.verified")}
</span>
</div>
</div>
</div>
{/* Table Footer Row */}
<div className="grid grid-cols-5 gap-4 pt-6 border-t border-border-gray dark:border-gray-700">
<div className="col-span-3 flex items-center">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.totalValue")}
</span>
</div>
<div className="col-span-2 flex items-center">
<span className="text-body-default font-bold text-text-primary dark:text-white">
$12,500,000.00
</span>
</div>
</div>
</div>
</div>
{/* Verification Cards Row */}
<div className="flex flex-row gap-6 pt-6">
<VerificationCard
icon="/component-117.svg"
title={t("custody.smartContract")}
description={t("custody.smartContractDesc")}
buttonText={t("custody.viewReports")}
/>
<VerificationCard
icon="/component-119.svg"
title={t("custody.compliance")}
description={t("custody.complianceDesc")}
buttonText={t("custody.viewReports")}
/>
<VerificationCard
icon="/component-121.svg"
title={t("custody.proofOfReserves")}
description={t("custody.proofDesc")}
buttonText={t("custody.viewReports")}
/>
{/* Independent Verifications */}
<div className="flex-1 rounded-2xl border bg-[#f9fafb] dark:bg-gray-700 border-[#e5e7eb] dark:border-gray-600 p-6 flex flex-col">
<div className="flex flex-col gap-2">
<h3 className="text-body-default font-bold text-text-primary dark:text-white">
{t("custody.independentVerifications")}
</h3>
<p className="text-body-small font-regular text-[#9ca1af] dark:text-gray-400">
{t("custody.independentDesc")}
</p>
</div>
<div className="flex flex-col gap-2 mt-6">
<div className="rounded-2xl border bg-white dark:bg-gray-800 border-[#e5e7eb] dark:border-gray-600 p-4 flex items-center justify-between">
<div className="flex flex-col gap-0.5">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.attestationReport")}
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
November 2025
</span>
</div>
<Image src="/component-123.svg" alt="" width={24} height={24} />
</div>
<div className="rounded-2xl border bg-white dark:bg-gray-800 border-[#e5e7eb] dark:border-gray-600 p-4 flex items-center justify-between">
<div className="flex flex-col gap-0.5">
<span className="text-body-small font-bold text-text-primary dark:text-white">
{t("custody.attestationReport")}
</span>
<span className="text-caption-tiny font-regular text-[#9ca1af] dark:text-gray-400">
October 2025
</span>
</div>
<Image src="/component-124.svg" alt="" width={24} height={24} />
</div>
</div>
<button className="flex items-center gap-2 hover:opacity-80 transition-opacity mt-4">
<span className="text-[10px] font-bold leading-[150%] tracking-[0.01em] text-[#9ca1af] dark:text-gray-400">
{t("custody.viewAllArchive")}
</span>
<Image src="/component-125.svg" alt="" width={16} height={16} />
</button>
</div>
</div>
</div>
);
}

View File

@@ -1,9 +1,9 @@
import AssetCustodyVerification from "./AssetCustodyVerification";
export default function AssetCustodyVerificationTab() {
return (
<div className="flex flex-col gap-8 w-full">
<AssetCustodyVerification />
</div>
);
}
import AssetCustodyVerification from "./AssetCustodyVerification";
export default function AssetCustodyVerificationTab() {
return (
<div className="flex flex-col gap-8 w-full">
<AssetCustodyVerification />
</div>
);
}

View File

@@ -1,18 +1,18 @@
"use client";
import { useApp } from "@/contexts/AppContext";
export default function AssetDescriptionCard() {
const { t } = useApp();
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-4 h-[300px]">
<h3 className="text-body-large font-bold text-text-primary dark:text-white">
{t("description.title")}
</h3>
<div className="text-body-default font-regular text-text-primary dark:text-gray-300 leading-relaxed whitespace-pre-line flex-1 overflow-y-auto">
{t("description.content")}
</div>
</div>
);
}
"use client";
import { useApp } from "@/contexts/AppContext";
export default function AssetDescriptionCard() {
const { t } = useApp();
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-4 h-[300px]">
<h3 className="text-body-large font-bold text-text-primary dark:text-white">
{t("description.title")}
</h3>
<div className="text-body-default font-regular text-text-primary dark:text-gray-300 leading-relaxed whitespace-pre-line flex-1 overflow-y-auto">
{t("description.content")}
</div>
</div>
);
}

View File

@@ -1,9 +1,9 @@
import AssetDescriptionCard from "./AssetDescriptionCard";
export default function AssetDescriptionTab() {
return (
<div className="flex flex-col gap-8 w-full">
<AssetDescriptionCard />
</div>
);
}
import AssetDescriptionCard from "./AssetDescriptionCard";
export default function AssetDescriptionTab() {
return (
<div className="flex flex-col gap-8 w-full">
<AssetDescriptionCard />
</div>
);
}

View File

@@ -1,116 +1,116 @@
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface OverviewItemProps {
icon: string;
label: string;
value: string;
}
function OverviewItem({ icon, label, value }: OverviewItemProps) {
return (
<div className="flex items-center justify-between w-full">
<div className="flex items-center gap-1">
<div className="w-5 h-6 flex-shrink-0">
<Image src={icon} alt={label} width={20} height={24} />
</div>
<span className="text-body-small font-medium text-text-tertiary dark:text-gray-400">
{label}
</span>
</div>
<span className="text-body-small font-medium text-text-primary dark:text-white">
{value}
</span>
</div>
);
}
export default function AssetOverviewCard() {
const { t } = useApp();
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-6">
{/* Header */}
<div className="flex items-center justify-between">
<h3 className="text-body-large font-bold text-text-primary dark:text-white">
{t("assetOverview.title")}
</h3>
<div
className="rounded-full border flex items-center gap-2 px-3 py-1.5"
style={{
backgroundColor: "#fffbf5",
borderColor: "#ffedd5",
}}
>
<div
className="w-1.5 h-1.5 rounded-full flex-shrink-0"
style={{ backgroundColor: "#ffb933" }}
/>
<span
className="text-xs font-semibold leading-4"
style={{ color: "#ffb933" }}
>
{t("assetOverview.mediumRisk")}
</span>
</div>
</div>
{/* Overview Items */}
<div className="flex gap-12 w-full">
<div className="flex-1 flex flex-col gap-5">
<OverviewItem
icon="/component-11.svg"
label={t("assetOverview.underlyingAssets")}
value={t("assetOverview.usEquityIndex")}
/>
<OverviewItem
icon="/component-12.svg"
label={t("assetOverview.maturityRange")}
value="05 Feb 2026"
/>
<OverviewItem
icon="/component-13.svg"
label={t("assetOverview.cap")}
value="$50,000,000"
/>
</div>
<div className="flex-1 flex flex-col gap-5">
<OverviewItem
icon="/component-14.svg"
label={t("assetOverview.minInvestment")}
value="100 USDC"
/>
<div className="flex flex-col gap-3 w-full">
<OverviewItem
icon="/component-15.svg"
label={t("assetOverview.poolCapacity")}
value="75%"
/>
<div className="w-full h-2 bg-gray-200 dark:bg-gray-600 rounded-full overflow-hidden">
<div className="h-full bg-blue-500 rounded-full" style={{ width: "75%" }} />
</div>
</div>
</div>
</div>
{/* Divider */}
<div className="border-t border-border-gray dark:border-gray-700" />
{/* Current Price */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl p-4 flex items-center justify-between">
<div className="flex items-center gap-2">
<Image src="/component-16.svg" alt="Price" width={24} height={24} />
<span className="text-body-small font-medium text-text-tertiary dark:text-gray-400">
{t("assetOverview.currentPrice")}
</span>
</div>
<div className="text-[20px] font-bold leading-[140%]">
<span className="text-text-primary dark:text-white">1 GY-US = </span>
<span style={{ color: "#10b981" }}>1.04 USDC</span>
</div>
</div>
</div>
);
}
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface OverviewItemProps {
icon: string;
label: string;
value: string;
}
function OverviewItem({ icon, label, value }: OverviewItemProps) {
return (
<div className="flex items-center justify-between w-full">
<div className="flex items-center gap-1">
<div className="w-5 h-6 flex-shrink-0">
<Image src={icon} alt={label} width={20} height={24} />
</div>
<span className="text-body-small font-medium text-text-tertiary dark:text-gray-400">
{label}
</span>
</div>
<span className="text-body-small font-medium text-text-primary dark:text-white">
{value}
</span>
</div>
);
}
export default function AssetOverviewCard() {
const { t } = useApp();
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-6">
{/* Header */}
<div className="flex items-center justify-between">
<h3 className="text-body-large font-bold text-text-primary dark:text-white">
{t("assetOverview.title")}
</h3>
<div
className="rounded-full border flex items-center gap-2 px-3 py-1.5"
style={{
backgroundColor: "#fffbf5",
borderColor: "#ffedd5",
}}
>
<div
className="w-1.5 h-1.5 rounded-full flex-shrink-0"
style={{ backgroundColor: "#ffb933" }}
/>
<span
className="text-xs font-semibold leading-4"
style={{ color: "#ffb933" }}
>
{t("assetOverview.mediumRisk")}
</span>
</div>
</div>
{/* Overview Items */}
<div className="flex gap-12 w-full">
<div className="flex-1 flex flex-col gap-5">
<OverviewItem
icon="/component-11.svg"
label={t("assetOverview.underlyingAssets")}
value={t("assetOverview.usEquityIndex")}
/>
<OverviewItem
icon="/component-12.svg"
label={t("assetOverview.maturityRange")}
value="05 Feb 2026"
/>
<OverviewItem
icon="/component-13.svg"
label={t("assetOverview.cap")}
value="$50,000,000"
/>
</div>
<div className="flex-1 flex flex-col gap-5">
<OverviewItem
icon="/component-14.svg"
label={t("assetOverview.minInvestment")}
value="100 USDC"
/>
<div className="flex flex-col gap-3 w-full">
<OverviewItem
icon="/component-15.svg"
label={t("assetOverview.poolCapacity")}
value="75%"
/>
<div className="w-full h-2 bg-gray-200 dark:bg-gray-600 rounded-full overflow-hidden">
<div className="h-full bg-blue-500 rounded-full" style={{ width: "75%" }} />
</div>
</div>
</div>
</div>
{/* Divider */}
<div className="border-t border-border-gray dark:border-gray-700" />
{/* Current Price */}
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl p-4 flex items-center justify-between">
<div className="flex items-center gap-2">
<Image src="/component-16.svg" alt="Price" width={24} height={24} />
<span className="text-body-small font-medium text-text-tertiary dark:text-gray-400">
{t("assetOverview.currentPrice")}
</span>
</div>
<div className="text-[20px] font-bold leading-[140%]">
<span className="text-text-primary dark:text-white">1 GY-US = </span>
<span style={{ color: "#10b981" }}>1.04 USDC</span>
</div>
</div>
</div>
);
}

View File

@@ -1,39 +1,39 @@
import Image from "next/image";
interface BreadcrumbItem {
label: string;
href?: string;
}
interface BreadcrumbProps {
items: BreadcrumbItem[];
}
export default function Breadcrumb({ items }: BreadcrumbProps) {
return (
<nav className="flex items-center gap-[3px] h-5">
{items.map((item, index) => (
<div key={index} className="flex items-center gap-[3px]">
<span
className={`text-sm font-medium leading-[150%] ${
index === items.length - 1
? "text-text-primary font-bold"
: "text-text-tertiary"
}`}
>
{item.label}
</span>
{index < items.length - 1 && (
<Image
src="/icon-chevron-right.svg"
alt=""
width={14}
height={14}
className="flex-shrink-0"
/>
)}
</div>
))}
</nav>
);
}
import Image from "next/image";
interface BreadcrumbItem {
label: string;
href?: string;
}
interface BreadcrumbProps {
items: BreadcrumbItem[];
}
export default function Breadcrumb({ items }: BreadcrumbProps) {
return (
<nav className="flex items-center gap-[3px] h-5">
{items.map((item, index) => (
<div key={index} className="flex items-center gap-[3px]">
<span
className={`text-sm font-medium leading-[150%] ${
index === items.length - 1
? "text-text-primary font-bold"
: "text-text-tertiary"
}`}
>
{item.label}
</span>
{index < items.length - 1 && (
<Image
src="/icon-chevron-right.svg"
alt=""
width={14}
height={14}
className="flex-shrink-0"
/>
)}
</div>
))}
</nav>
);
}

View File

@@ -1,63 +1,63 @@
"use client";
import { useState } from "react";
import TabNavigation from "./TabNavigation";
import OverviewTab from "./OverviewTab";
import { useApp } from "@/contexts/AppContext";
export default function ContentSection() {
const { t } = useApp();
const tabs = [
{ id: "overview", label: t("tabs.overview") },
{ id: "asset-description", label: t("tabs.assetDescription") },
{ id: "analytics", label: t("tabs.analytics") },
{ id: "performance-analysis", label: t("tabs.performanceAnalysis") },
{ id: "asset-custody", label: t("tabs.assetCustody") },
];
const [activeTab, setActiveTab] = useState("overview");
const handleTabChange = (tabId: string) => {
// If clicking asset-description, performance-analysis, or asset-custody, scroll to that section
if (tabId === "asset-description" || tabId === "performance-analysis" || tabId === "asset-custody") {
setTimeout(() => {
const element = document.getElementById(tabId);
if (element) {
element.scrollIntoView({ behavior: "smooth", block: "start" });
}
}, 100);
// Keep active tab as overview
setActiveTab("overview");
} else {
setActiveTab(tabId);
}
};
// Show OverviewTab for overview, asset-description, analytics, performance-analysis, and asset-custody
const showOverview = ["overview", "asset-description", "analytics", "performance-analysis", "asset-custody"].includes(activeTab);
return (
<div className="flex flex-col gap-6 w-full">
{/* Tab Navigation */}
<TabNavigation
tabs={tabs}
defaultActiveId="overview"
onTabChange={handleTabChange}
/>
{/* Content Area */}
<div className="w-full">
{showOverview && <OverviewTab />}
{!showOverview && (
<div className="bg-bg-surface rounded-2xl border border-border-normal p-6">
<p className="text-text-tertiary">
{tabs.find((t) => t.id === activeTab)?.label} content will be
displayed here...
</p>
</div>
)}
</div>
</div>
);
}
"use client";
import { useState } from "react";
import TabNavigation from "./TabNavigation";
import OverviewTab from "./OverviewTab";
import { useApp } from "@/contexts/AppContext";
export default function ContentSection() {
const { t } = useApp();
const tabs = [
{ id: "overview", label: t("tabs.overview") },
{ id: "asset-description", label: t("tabs.assetDescription") },
{ id: "analytics", label: t("tabs.analytics") },
{ id: "performance-analysis", label: t("tabs.performanceAnalysis") },
{ id: "asset-custody", label: t("tabs.assetCustody") },
];
const [activeTab, setActiveTab] = useState("overview");
const handleTabChange = (tabId: string) => {
// If clicking asset-description, performance-analysis, or asset-custody, scroll to that section
if (tabId === "asset-description" || tabId === "performance-analysis" || tabId === "asset-custody") {
setTimeout(() => {
const element = document.getElementById(tabId);
if (element) {
element.scrollIntoView({ behavior: "smooth", block: "start" });
}
}, 100);
// Keep active tab as overview
setActiveTab("overview");
} else {
setActiveTab(tabId);
}
};
// Show OverviewTab for overview, asset-description, analytics, performance-analysis, and asset-custody
const showOverview = ["overview", "asset-description", "analytics", "performance-analysis", "asset-custody"].includes(activeTab);
return (
<div className="flex flex-col gap-6 w-full">
{/* Tab Navigation */}
<TabNavigation
tabs={tabs}
defaultActiveId="overview"
onTabChange={handleTabChange}
/>
{/* Content Area */}
<div className="w-full">
{showOverview && <OverviewTab />}
{!showOverview && (
<div className="bg-bg-surface rounded-2xl border border-border-normal p-6">
<p className="text-text-tertiary">
{tabs.find((t) => t.id === activeTab)?.label} content will be
displayed here...
</p>
</div>
)}
</div>
</div>
);
}

View File

@@ -1,22 +1,45 @@
"use client";
import { useApp } from "@/contexts/AppContext";
export default function LanguageSwitch() {
const { language, setLanguage } = useApp();
const toggleLanguage = () => {
setLanguage(language === "zh" ? "en" : "zh");
};
return (
<button
onClick={toggleLanguage}
className="bg-bg-surface dark:bg-gray-800 rounded-lg border border-border-normal dark:border-gray-700 px-3 py-2 flex items-center justify-center h-10 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<span className="text-sm font-medium text-text-primary dark:text-white">
{language === "zh" ? "中" : "EN"}
</span>
</button>
);
}
"use client";
import { useApp } from "@/contexts/AppContext";
import { Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button } from "@heroui/react";
export default function LanguageSwitch() {
const { language, setLanguage } = useApp();
const languages = [
{ key: "zh", label: "中文" },
{ key: "en", label: "English" },
];
const handleSelectionChange = (key: React.Key) => {
setLanguage(key as "zh" | "en");
};
return (
<Dropdown>
<DropdownTrigger>
<Button
variant="bordered"
className="bg-bg-surface dark:bg-gray-800 border-border-normal dark:border-gray-700 min-w-10 h-10 px-3 rounded-lg"
>
<span className="text-sm font-medium text-text-primary dark:text-white">
{language === "zh" ? "中" : "EN"}
</span>
</Button>
</DropdownTrigger>
<DropdownMenu
aria-label="Language selection"
selectedKeys={new Set([language])}
selectionMode="single"
onSelectionChange={(keys) => {
const key = Array.from(keys)[0];
if (key) handleSelectionChange(key);
}}
>
{languages.map((lang) => (
<DropdownItem key={lang.key}>{lang.label}</DropdownItem>
))}
</DropdownMenu>
</Dropdown>
);
}

View File

@@ -1,199 +1,184 @@
"use client";
import { useState } from "react";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
export default function MintSwapPanel() {
const { t } = useApp();
const [activeMode, setActiveMode] = useState<"mint" | "swap">("mint");
const [activeAction, setActiveAction] = useState<"deposit" | "withdraw">("deposit");
return (
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 flex flex-col">
{/* Mint/Swap Tabs */}
<div className="flex border-b border-border-gray dark:border-gray-700">
<button
onClick={() => setActiveMode("mint")}
className={`flex-1 h-[53px] flex items-center justify-center text-body-small font-bold rounded-tl-3xl transition-colors ${
activeMode === "mint"
? "bg-bg-subtle dark:bg-gray-700 border-b-2 border-text-primary dark:border-blue-500 text-[#0f172b] dark:text-white"
: "text-text-tertiary dark:text-gray-400"
}`}
>
{t("mintSwap.mint")}
</button>
<button
onClick={() => setActiveMode("swap")}
className={`flex-1 h-[53px] flex items-center justify-center text-body-small font-bold transition-colors ${
activeMode === "swap"
? "bg-bg-subtle dark:bg-gray-700 border-b-2 border-text-primary dark:border-blue-500 text-[#0f172b] dark:text-white"
: "text-text-tertiary dark:text-gray-400"
}`}
>
{t("mintSwap.swap")}
</button>
</div>
{/* Content */}
<div className="flex flex-col gap-6 p-6">
{/* Deposit/Withdraw Toggle */}
<div className="bg-[#f9fafb] dark:bg-gray-700 rounded-xl p-1 flex gap-0">
<button
onClick={() => setActiveAction("deposit")}
className={`flex-1 h-8 px-4 rounded-lg text-body-small transition-all ${
activeAction === "deposit"
? "bg-bg-surface dark:bg-gray-600 font-bold text-text-primary dark:text-white shadow-sm"
: "font-medium text-text-tertiary dark:text-gray-400"
}`}
>
{t("mintSwap.deposit")}
</button>
<button
onClick={() => setActiveAction("withdraw")}
className={`flex-1 h-8 px-4 rounded-lg text-body-small transition-all ${
activeAction === "withdraw"
? "bg-bg-surface dark:bg-gray-600 font-bold text-text-primary dark:text-white shadow-sm"
: "font-medium text-text-tertiary dark:text-gray-400"
}`}
>
{t("mintSwap.withdraw")}
</button>
</div>
{/* Input Area */}
<div className="flex flex-col gap-2">
<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-3">
{/* Label and Balance */}
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-[#4b5563] dark:text-gray-400">
{t("mintSwap.deposit")}
</span>
<div className="flex items-center gap-1">
<Image src="/icon7.svg" alt="" width={12} height={12} />
<span className="text-caption-tiny font-medium text-[#4b5563] dark:text-gray-400">
{t("mintSwap.balance")}: $12,500.00
</span>
<button className="rounded-full px-3 h-[22px] text-[10px] font-medium bg-[#e5e7eb] dark:bg-gray-600 text-[#111827] dark:text-white">
{t("mintSwap.max")}
</button>
</div>
</div>
{/* Input Row */}
<div className="flex items-center justify-between">
<button className="bg-bg-surface dark:bg-gray-600 rounded-full border border-border-normal dark:border-gray-500 px-2 h-[46px] flex items-center gap-2">
<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">USDC</span>
</button>
<div className="flex flex-col items-end">
<span className="text-heading-h3 font-bold text-[#d1d5db] dark:text-gray-500">
0.00
</span>
<span className="text-caption-tiny font-regular text-text-tertiary dark:text-gray-400">--</span>
</div>
</div>
</div>
</div>
{/* Estimated Returns */}
<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-2">
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-bold text-[#4b5563] dark:text-gray-300">
{t("mintSwap.estimatedReturns")}
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.estAPY")}
</span>
<span className="text-body-small font-bold text-[#ff6900] dark:text-orange-400">
22%
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.estReturns")}
</span>
<span className="text-body-small font-bold text-[#10b981] dark:text-green-400">
~ $0.50
</span>
</div>
</div>
{/* Transaction Summary */}
<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-2">
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-bold text-[#4b5563] dark:text-gray-300">
{t("mintSwap.transactionSummary")}
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.youGet")}
</span>
<span className="text-body-small font-bold text-[#10b981] dark:text-green-400">
9852.21 GYUS
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.salesPrice")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white">$1.04 USDC</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.fee")}
</span>
<span className="text-body-small font-bold text-[#dc2626] dark:text-red-400">
-$50 (0.5%)
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.gas")}
</span>
<span className="text-body-small font-bold text-[#dc2626] dark:text-red-400">
-$0.09
</span>
</div>
</div>
{/* Submit Button */}
<button
className="rounded-xl h-12 flex items-center justify-center gap-2 bg-[#9ca1af] dark:bg-gray-600"
disabled
>
<span className="text-lg font-bold text-white leading-7">
{t("mintSwap.approveDeposit")}
</span>
<Image src="/icon8.svg" alt="" width={20} height={20} />
</button>
{/* Terms */}
<div className="flex flex-col gap-0 text-center">
<div className="text-caption-tiny font-regular">
<span className="text-[#9ca1af] dark:text-gray-400">
{t("mintSwap.termsText")}{" "}
</span>
<span className="text-[#10b981] dark:text-green-400">
{t("mintSwap.termsOfService")}
</span>
<span className="text-[#9ca1af] dark:text-gray-400">
{" "}{t("mintSwap.and")}
</span>
</div>
<span className="text-caption-tiny font-regular text-[#10b981] dark:text-green-400">
{t("mintSwap.privacyPolicy")}
</span>
</div>
</div>
</div>
);
}
"use client";
import { useState } from "react";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
import { Tabs, Tab, Button } from "@heroui/react";
export default function MintSwapPanel() {
const { t } = useApp();
const [activeMode, setActiveMode] = useState<"mint" | "swap">("mint");
const [activeAction, setActiveAction] = useState<"deposit" | "withdraw">("deposit");
return (
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 flex flex-col overflow-hidden">
{/* Mint/Swap Tabs */}
<Tabs
selectedKey={activeMode}
onSelectionChange={(key) => setActiveMode(key as "mint" | "swap")}
variant="underlined"
classNames={{
base: "w-full",
tabList: "w-full gap-0 p-0 rounded-none border-b border-border-gray dark:border-gray-700",
cursor: "bg-text-primary dark:bg-blue-500 h-[2px]",
tab: "h-[53px] flex-1 rounded-none data-[selected=true]:bg-bg-subtle dark:data-[selected=true]:bg-gray-700",
tabContent: "text-body-small font-bold text-text-tertiary dark:text-gray-400 group-data-[selected=true]:text-[#0f172b] dark:group-data-[selected=true]:text-white",
}}
>
<Tab key="mint" title={t("mintSwap.mint")} />
<Tab key="swap" title={t("mintSwap.swap")} />
</Tabs>
{/* Content */}
<div className="flex flex-col gap-6 p-6">
{/* Deposit/Withdraw Toggle */}
<Tabs
selectedKey={activeAction}
onSelectionChange={(key) => setActiveAction(key as "deposit" | "withdraw")}
variant="solid"
classNames={{
base: "w-full",
tabList: "bg-[#f9fafb] dark:bg-gray-700 rounded-xl p-1 gap-0 w-full",
cursor: "bg-bg-surface dark:bg-gray-600 shadow-sm",
tab: "h-8 px-4",
tabContent: "text-body-small font-medium text-text-tertiary dark:text-gray-400 group-data-[selected=true]:font-bold group-data-[selected=true]:text-text-primary dark:group-data-[selected=true]:text-white",
}}
>
<Tab key="deposit" title={t("mintSwap.deposit")} />
<Tab key="withdraw" title={t("mintSwap.withdraw")} />
</Tabs>
{/* Input Area */}
<div className="flex flex-col gap-2">
<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-3">
{/* Label and Balance */}
<div className="flex items-center justify-between">
<span className="text-caption-tiny font-medium text-[#4b5563] dark:text-gray-400">
{t("mintSwap.deposit")}
</span>
<div className="flex items-center gap-1">
<Image src="/icon7.svg" alt="" width={12} height={12} />
<span className="text-caption-tiny font-medium text-[#4b5563] dark:text-gray-400">
{t("mintSwap.balance")}: $12,500.00
</span>
<button className="rounded-full px-3 h-[22px] text-[10px] font-medium bg-[#e5e7eb] dark:bg-gray-600 text-[#111827] dark:text-white">
{t("mintSwap.max")}
</button>
</div>
</div>
{/* Input Row */}
<div className="flex items-center justify-between">
<button className="bg-bg-surface dark:bg-gray-600 rounded-full border border-border-normal dark:border-gray-500 px-2 h-[46px] flex items-center gap-2">
<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">USDC</span>
</button>
<div className="flex flex-col items-end">
<span className="text-heading-h3 font-bold text-[#d1d5db] dark:text-gray-500">
0.00
</span>
<span className="text-caption-tiny font-regular text-text-tertiary dark:text-gray-400">--</span>
</div>
</div>
</div>
</div>
{/* Estimated Returns */}
<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-2">
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-bold text-[#4b5563] dark:text-gray-300">
{t("mintSwap.estimatedReturns")}
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.estAPY")}
</span>
<span className="text-body-small font-bold text-[#ff6900] dark:text-orange-400">
22%
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.estReturns")}
</span>
<span className="text-body-small font-bold text-[#10b981] dark:text-green-400">
~ $0.50
</span>
</div>
</div>
{/* Transaction Summary */}
<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-2">
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-bold text-[#4b5563] dark:text-gray-300">
{t("mintSwap.transactionSummary")}
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.youGet")}
</span>
<span className="text-body-small font-bold text-[#10b981] dark:text-green-400">
9852.21 GYUS
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.salesPrice")}
</span>
<span className="text-body-small font-bold text-text-primary dark:text-white">$1.04 USDC</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.fee")}
</span>
<span className="text-body-small font-bold text-[#dc2626] dark:text-red-400">
-$50 (0.5%)
</span>
</div>
<div className="flex items-center justify-between h-5">
<span className="text-body-small font-regular text-text-tertiary dark:text-gray-400">
{t("mintSwap.gas")}
</span>
<span className="text-body-small font-bold text-[#dc2626] dark:text-red-400">
-$0.09
</span>
</div>
</div>
{/* Submit Button */}
<Button
isDisabled
className="rounded-xl h-12 bg-[#9ca1af] dark:bg-gray-600 text-lg font-bold text-white"
endContent={<Image src="/icon8.svg" alt="" width={20} height={20} />}
>
{t("mintSwap.approveDeposit")}
</Button>
{/* Terms */}
<div className="flex flex-col gap-0 text-center">
<div className="text-caption-tiny font-regular">
<span className="text-[#9ca1af] dark:text-gray-400">
{t("mintSwap.termsText")}{" "}
</span>
<span className="text-[#10b981] dark:text-green-400">
{t("mintSwap.termsOfService")}
</span>
<span className="text-[#9ca1af] dark:text-gray-400">
{" "}{t("mintSwap.and")}
</span>
</div>
<span className="text-caption-tiny font-regular text-[#10b981] dark:text-green-400">
{t("mintSwap.privacyPolicy")}
</span>
</div>
</div>
</div>
);
}

View File

@@ -1,53 +1,53 @@
import Image from "next/image";
interface NavItemProps {
icon: string;
label: string;
isActive: boolean;
onClick: () => void;
}
export default function NavItem({ icon, label, isActive, onClick }: NavItemProps) {
return (
<button
onClick={onClick}
className={`
rounded-xl
pl-4
flex
items-center
gap-2
h-[42px]
w-full
overflow-hidden
transition-colors
${isActive
? 'bg-fill-secondary-click'
: 'hover:bg-gray-50'
}
`}
>
<div className="w-[22px] h-[22px] flex-shrink-0 relative">
<Image
src={icon}
alt={label}
width={22}
height={22}
className="w-full h-full"
/>
</div>
<span
className={`
text-sm
leading-[150%]
${isActive
? 'text-text-primary font-bold'
: 'text-text-tertiary font-medium'
}
`}
>
{label}
</span>
</button>
);
}
import Image from "next/image";
interface NavItemProps {
icon: string;
label: string;
isActive: boolean;
onClick: () => void;
}
export default function NavItem({ icon, label, isActive, onClick }: NavItemProps) {
return (
<button
onClick={onClick}
className={`
rounded-xl
pl-4
flex
items-center
gap-2
h-[42px]
w-full
overflow-hidden
transition-colors
${isActive
? 'bg-fill-secondary-click'
: 'hover:bg-gray-50'
}
`}
>
<div className="w-[22px] h-[22px] flex-shrink-0 relative">
<Image
src={icon}
alt={label}
width={22}
height={22}
className="w-full h-full"
/>
</div>
<span
className={`
text-sm
leading-[150%]
${isActive
? 'text-text-primary font-bold'
: 'text-text-tertiary font-medium'
}
`}
>
{label}
</span>
</button>
);
}

View File

@@ -1,55 +1,55 @@
import ProductHeader from "./ProductHeader";
import StatsCards from "./StatsCards";
import AssetOverviewCard from "./AssetOverviewCard";
import APYHistoryCard from "./APYHistoryCard";
import AssetDescriptionCard from "./AssetDescriptionCard";
import MintSwapPanel from "./MintSwapPanel";
import ProtocolInformation from "./ProtocolInformation";
import PerformanceAnalysis from "./PerformanceAnalysis";
import Season1Rewards from "./Season1Rewards";
import AssetCustodyVerification from "./AssetCustodyVerification";
export default function OverviewTab() {
return (
<div className="flex flex-col gap-8 w-full">
{/* Product Header */}
<ProductHeader />
{/* Stats Cards */}
<StatsCards />
{/* Main Content Grid */}
<div className="grid grid-cols-3 gap-8">
{/* Left Column - 2/3 width */}
<div className="col-span-2 flex flex-col gap-8">
<AssetOverviewCard />
<APYHistoryCard />
<div id="asset-description">
<AssetDescriptionCard />
</div>
</div>
{/* Right Column - 1/3 width */}
<div className="col-span-1">
<div className="sticky top-8 flex flex-col gap-8">
<MintSwapPanel />
<ProtocolInformation />
</div>
</div>
</div>
{/* Season 1 Rewards */}
<Season1Rewards />
{/* Performance Analysis */}
<div id="performance-analysis">
<PerformanceAnalysis />
</div>
{/* Asset Custody & Verification */}
<div id="asset-custody">
<AssetCustodyVerification />
</div>
</div>
);
}
import ProductHeader from "./ProductHeader";
import StatsCards from "./StatsCards";
import AssetOverviewCard from "./AssetOverviewCard";
import APYHistoryCard from "./APYHistoryCard";
import AssetDescriptionCard from "./AssetDescriptionCard";
import MintSwapPanel from "./MintSwapPanel";
import ProtocolInformation from "./ProtocolInformation";
import PerformanceAnalysis from "./PerformanceAnalysis";
import Season1Rewards from "./Season1Rewards";
import AssetCustodyVerification from "./AssetCustodyVerification";
export default function OverviewTab() {
return (
<div className="flex flex-col gap-8 w-full">
{/* Product Header */}
<ProductHeader />
{/* Stats Cards */}
<StatsCards />
{/* Main Content Grid */}
<div className="grid grid-cols-3 gap-8">
{/* Left Column - 2/3 width */}
<div className="col-span-2 flex flex-col gap-8">
<AssetOverviewCard />
<APYHistoryCard />
<div id="asset-description">
<AssetDescriptionCard />
</div>
</div>
{/* Right Column - 1/3 width */}
<div className="col-span-1">
<div className="sticky top-8 flex flex-col gap-8">
<MintSwapPanel />
<ProtocolInformation />
</div>
</div>
</div>
{/* Season 1 Rewards */}
<Season1Rewards />
{/* Performance Analysis */}
<div id="performance-analysis">
<PerformanceAnalysis />
</div>
{/* Asset Custody & Verification */}
<div id="asset-custody">
<AssetCustodyVerification />
</div>
</div>
);
}

View File

@@ -1,207 +1,207 @@
"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-blue-600 border-[#111827] dark:border-blue-600",
};
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-[#fcfcfd]";
} 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 items-end justify-end">
<span className={`text-body-small font-bold leading-[150%] ${valueTextStyle}`}>
{value}
</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>
);
}
"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-blue-600 border-[#111827] dark:border-blue-600",
};
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-[#fcfcfd]";
} 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 items-end justify-end">
<span className={`text-body-small font-bold leading-[150%] ${valueTextStyle}`}>
{value}
</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>
);
}

View File

@@ -1,9 +1,9 @@
import PerformanceAnalysis from "./PerformanceAnalysis";
export default function PerformanceAnalysisTab() {
return (
<div className="flex flex-col gap-8 w-full">
<PerformanceAnalysis />
</div>
);
}
import PerformanceAnalysis from "./PerformanceAnalysis";
export default function PerformanceAnalysisTab() {
return (
<div className="flex flex-col gap-8 w-full">
<PerformanceAnalysis />
</div>
);
}

View File

@@ -1,35 +1,35 @@
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
export default function ProductHeader() {
const { t } = useApp();
return (
<div className="flex flex-col gap-6">
{/* Product Title Section */}
<div className="flex items-start justify-between">
<div className="flex gap-6">
<div className="flex-shrink-0">
<Image src="/lr0.svg" alt="Product Logo" width={80} height={80} />
</div>
<div className="flex flex-col gap-2">
<h1 className="text-heading-h2 font-bold text-text-primary dark:text-white">
{t("product.gyUsEquityIndexToken")}
</h1>
<p className="text-body-default font-regular text-text-tertiary dark:text-gray-400">
High-Yield US Equity Quantitative Strategy - Institutional Grade RWA
</p>
</div>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-bg-subtle dark:bg-gray-700 rounded-lg border border-border-gray dark:border-gray-600">
<Image src="/group-9270.svg" alt="Contract" width={16} height={16} />
<span className="text-caption-tiny font-medium font-jetbrains text-text-tertiary dark:text-gray-400">
{t("product.contractAddress")}: 0x1b19...4f2c
</span>
</div>
</div>
</div>
);
}
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
export default function ProductHeader() {
const { t } = useApp();
return (
<div className="flex flex-col gap-6">
{/* Product Title Section */}
<div className="flex items-start justify-between">
<div className="flex gap-6">
<div className="flex-shrink-0">
<Image src="/lr0.svg" alt="Product Logo" width={80} height={80} />
</div>
<div className="flex flex-col gap-2">
<h1 className="text-heading-h2 font-bold text-text-primary dark:text-white">
{t("product.gyUsEquityIndexToken")}
</h1>
<p className="text-body-default font-regular text-text-tertiary dark:text-gray-400">
High-Yield US Equity Quantitative Strategy - Institutional Grade RWA
</p>
</div>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-bg-subtle dark:bg-gray-700 rounded-lg border border-border-gray dark:border-gray-600">
<Image src="/group-9270.svg" alt="Contract" width={16} height={16} />
<span className="text-caption-tiny font-medium font-jetbrains text-text-tertiary dark:text-gray-400">
{t("product.contractAddress")}: 0x1b19...4f2c
</span>
</div>
</div>
</div>
);
}

View File

@@ -1,53 +1,53 @@
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface ProtocolLinkProps {
icon: string;
label: string;
arrowIcon: string;
}
function ProtocolLink({ icon, label, arrowIcon }: ProtocolLinkProps) {
return (
<button className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 px-4 py-3.5 flex items-center justify-between w-full hover:bg-gray-50 dark:hover:bg-gray-600 transition-colors">
<div className="flex items-center gap-1">
<Image src={icon} alt="" width={20} height={24} />
<span className="text-body-small font-medium text-text-tertiary dark:text-gray-300">
{label}
</span>
</div>
<Image src={arrowIcon} alt="" width={20} height={24} />
</button>
);
}
export default function ProtocolInformation() {
const { t } = useApp();
return (
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 px-6 py-8 flex flex-col gap-4">
<h3 className="text-body-large font-bold text-text-primary dark:text-white">
{t("protocol.title")}
</h3>
<div className="flex flex-col gap-2">
<ProtocolLink
icon="/component-17.svg"
label={t("protocol.whitepaper")}
arrowIcon="/component-18.svg"
/>
<ProtocolLink
icon="/component-19.svg"
label={t("protocol.documentation")}
arrowIcon="/component-110.svg"
/>
<ProtocolLink
icon="/component-111.svg"
label={t("protocol.github")}
arrowIcon="/component-112.svg"
/>
</div>
</div>
);
}
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface ProtocolLinkProps {
icon: string;
label: string;
arrowIcon: string;
}
function ProtocolLink({ icon, label, arrowIcon }: ProtocolLinkProps) {
return (
<button className="bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 px-4 py-3.5 flex items-center justify-between w-full hover:bg-gray-50 dark:hover:bg-gray-600 transition-colors">
<div className="flex items-center gap-1">
<Image src={icon} alt="" width={20} height={24} />
<span className="text-body-small font-medium text-text-tertiary dark:text-gray-300">
{label}
</span>
</div>
<Image src={arrowIcon} alt="" width={20} height={24} />
</button>
);
}
export default function ProtocolInformation() {
const { t } = useApp();
return (
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 px-6 py-8 flex flex-col gap-4">
<h3 className="text-body-large font-bold text-text-primary dark:text-white">
{t("protocol.title")}
</h3>
<div className="flex flex-col gap-2">
<ProtocolLink
icon="/component-17.svg"
label={t("protocol.whitepaper")}
arrowIcon="/component-18.svg"
/>
<ProtocolLink
icon="/component-19.svg"
label={t("protocol.documentation")}
arrowIcon="/component-110.svg"
/>
<ProtocolLink
icon="/component-111.svg"
label={t("protocol.github")}
arrowIcon="/component-112.svg"
/>
</div>
</div>
);
}

13
components/Providers.tsx Normal file
View File

@@ -0,0 +1,13 @@
"use client";
import { HeroUIProvider } from "@heroui/react";
import { AppProvider } from "@/contexts/AppContext";
import { ReactNode } from "react";
export function Providers({ children }: { children: ReactNode }) {
return (
<HeroUIProvider>
<AppProvider>{children}</AppProvider>
</HeroUIProvider>
);
}

View File

@@ -1,101 +1,101 @@
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface RewardStatProps {
label: string;
value: string;
}
function RewardStat({ label, value }: RewardStatProps) {
return (
<div className="flex flex-col items-center gap-1.5">
<span
className="text-[24px] font-bold leading-[130%] dark:text-white"
style={{ color: "#111827", letterSpacing: "-0.005em" }}
>
{value}
</span>
<span
className="text-[10px] font-bold uppercase leading-[150%] text-center dark:text-gray-400"
style={{ color: "#9ca1af", letterSpacing: "0.05em" }}
>
{label}
</span>
</div>
);
}
export default function Season1Rewards() {
const { t } = useApp();
return (
<div
className="rounded-3xl border flex flex-col relative overflow-hidden"
style={{
background:
"radial-gradient(50% 50% at 100% 0%, rgba(255, 217, 100, 0.05) 0%, rgba(16, 185, 129, 0.05) 100%), #ffffff",
borderColor: "rgba(255, 255, 255, 0.6)",
paddingTop: "20px",
paddingBottom: "20px",
paddingLeft: "24px",
paddingRight: "24px",
}}
>
{/* Background Decoration */}
<div
className="absolute"
style={{ opacity: 0.5, right: "-15px", bottom: "-20px" }}
>
<Image
src="/component-113.svg"
alt=""
width={120}
height={144}
/>
</div>
{/* Content Container */}
<div className="flex flex-row items-center relative z-10" style={{ gap: "400px" }}>
{/* Left: Header and Description */}
<div className="flex flex-col gap-2 flex-shrink-0">
{/* Header */}
<div className="flex items-center gap-3">
<h3
className="text-[20px] font-bold leading-[140%] dark:text-white"
style={{ color: "#111827" }}
>
{t("rewards.season1")}
</h3>
<div
className="rounded-full px-2.5 py-1 flex items-center"
style={{ backgroundColor: "#111827" }}
>
<span
className="text-[10px] font-bold leading-4"
style={{ color: "#fcfcfd" }}
>
{t("rewards.live")}
</span>
</div>
</div>
{/* Description */}
<p
className="text-body-small font-medium dark:text-gray-400"
style={{ color: "#9ca1af" }}
>
{t("rewards.earnPoints")}
</p>
</div>
{/* Right: Stats */}
<div className="flex items-center justify-between flex-1">
<RewardStat label={t("rewards.yourPoints")} value="-" />
<RewardStat label={t("rewards.badgeBoost")} value="-" />
<RewardStat label={t("rewards.referrals")} value="-" />
</div>
</div>
</div>
);
}
"use client";
import Image from "next/image";
import { useApp } from "@/contexts/AppContext";
interface RewardStatProps {
label: string;
value: string;
}
function RewardStat({ label, value }: RewardStatProps) {
return (
<div className="flex flex-col items-center gap-1.5">
<span
className="text-[24px] font-bold leading-[130%] dark:text-white"
style={{ color: "#111827", letterSpacing: "-0.005em" }}
>
{value}
</span>
<span
className="text-[10px] font-bold uppercase leading-[150%] text-center dark:text-gray-400"
style={{ color: "#9ca1af", letterSpacing: "0.05em" }}
>
{label}
</span>
</div>
);
}
export default function Season1Rewards() {
const { t } = useApp();
return (
<div
className="rounded-3xl border flex flex-col relative overflow-hidden"
style={{
background:
"radial-gradient(50% 50% at 100% 0%, rgba(255, 217, 100, 0.05) 0%, rgba(16, 185, 129, 0.05) 100%), #ffffff",
borderColor: "rgba(255, 255, 255, 0.6)",
paddingTop: "20px",
paddingBottom: "20px",
paddingLeft: "24px",
paddingRight: "24px",
}}
>
{/* Background Decoration */}
<div
className="absolute"
style={{ opacity: 0.5, right: "-15px", bottom: "-20px" }}
>
<Image
src="/component-113.svg"
alt=""
width={120}
height={144}
/>
</div>
{/* Content Container */}
<div className="flex flex-row items-center relative z-10" style={{ gap: "400px" }}>
{/* Left: Header and Description */}
<div className="flex flex-col gap-2 flex-shrink-0">
{/* Header */}
<div className="flex items-center gap-3">
<h3
className="text-[20px] font-bold leading-[140%] dark:text-white"
style={{ color: "#111827" }}
>
{t("rewards.season1")}
</h3>
<div
className="rounded-full px-2.5 py-1 flex items-center"
style={{ backgroundColor: "#111827" }}
>
<span
className="text-[10px] font-bold leading-4"
style={{ color: "#fcfcfd" }}
>
{t("rewards.live")}
</span>
</div>
</div>
{/* Description */}
<p
className="text-body-small font-medium dark:text-gray-400"
style={{ color: "#9ca1af" }}
>
{t("rewards.earnPoints")}
</p>
</div>
{/* Right: Stats */}
<div className="flex items-center justify-between flex-1">
<RewardStat label={t("rewards.yourPoints")} value="-" />
<RewardStat label={t("rewards.badgeBoost")} value="-" />
<RewardStat label={t("rewards.referrals")} value="-" />
</div>
</div>
</div>
);
}

View File

@@ -1,80 +1,80 @@
"use client";
import Image from "next/image";
import { useState } from "react";
import NavItem from "./NavItem";
import { useApp } from "@/contexts/AppContext";
export default function Sidebar() {
const { t } = useApp();
const [activeItem, setActiveItem] = useState("Assets");
const navigationItems = [
{ icon: "/icon-assets.svg", label: t("nav.assets"), key: "Assets", path: "/" },
{ icon: "/icon-alp.svg", label: t("nav.alp"), key: "ALP", path: "/alp" },
{ icon: "/icon-swap.svg", label: t("nav.swap"), key: "Swap", path: "/swap" },
{ icon: "/icon-lending.svg", label: t("nav.lending"), key: "Lending", path: "/lending" },
{ icon: "/icon-transparency.svg", label: t("nav.transparency"), key: "Transparency", path: "/transparency" },
{ icon: "/icon-ecosystem.svg", label: t("nav.ecosystem"), key: "Ecosystem", path: "/ecosystem" },
{ icon: "/icon-points.svg", label: t("nav.points"), key: "Points", path: "/points" },
];
return (
<aside className="fixed left-0 top-0 bg-bg-surface dark:bg-gray-800 border-r border-border-normal dark:border-gray-700 flex flex-col items-center px-6 py-8 gap-8 h-screen w-[222px] overflow-y-auto">
{/* Logo */}
<div className="w-full h-10">
<Image
src="/logo.svg"
alt="ASSETX Logo"
width={174}
height={40}
className="w-full h-full"
/>
</div>
{/* Navigation */}
<nav className="flex flex-col gap-2 w-[174px]">
{navigationItems.map((item) => (
<NavItem
key={item.key}
icon={item.icon}
label={item.label}
isActive={activeItem === item.key}
onClick={() => setActiveItem(item.key)}
/>
))}
</nav>
{/* Spacer */}
<div className="flex-1" />
{/* Global TVL Section */}
<div className="w-full border-t border-border-gray dark:border-gray-700 pt-8">
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl p-4 flex flex-col gap-1 h-[85px]">
<p className="text-text-tertiary dark:text-gray-400 text-[10px] font-medium leading-[150%] tracking-[0.01em]">
{t("nav.globalTVL")}
</p>
<p className="text-text-primary dark:text-white text-base font-extrabold leading-[150%] font-jetbrains">
$465,000,000
</p>
</div>
{/* FAQs Link */}
<div className="rounded-xl flex items-center h-[42px] mt-8">
<div className="flex items-center gap-0">
<Image
src="/icon-faq.png"
alt="FAQ"
width={24}
height={24}
className="object-cover"
/>
<span className="text-text-primary dark:text-white text-sm font-bold leading-[150%]">
{t("nav.faqs")}
</span>
</div>
</div>
</div>
</aside>
);
}
"use client";
import Image from "next/image";
import { useState } from "react";
import NavItem from "./NavItem";
import { useApp } from "@/contexts/AppContext";
export default function Sidebar() {
const { t } = useApp();
const [activeItem, setActiveItem] = useState("Assets");
const navigationItems = [
{ icon: "/icon-assets.svg", label: t("nav.assets"), key: "Assets", path: "/" },
{ icon: "/icon-alp.svg", label: t("nav.alp"), key: "ALP", path: "/alp" },
{ icon: "/icon-swap.svg", label: t("nav.swap"), key: "Swap", path: "/swap" },
{ icon: "/icon-lending.svg", label: t("nav.lending"), key: "Lending", path: "/lending" },
{ icon: "/icon-transparency.svg", label: t("nav.transparency"), key: "Transparency", path: "/transparency" },
{ icon: "/icon-ecosystem.svg", label: t("nav.ecosystem"), key: "Ecosystem", path: "/ecosystem" },
{ icon: "/icon-points.svg", label: t("nav.points"), key: "Points", path: "/points" },
];
return (
<aside className="fixed left-0 top-0 bg-bg-surface dark:bg-gray-800 border-r border-border-normal dark:border-gray-700 flex flex-col items-center px-6 py-8 gap-8 h-screen w-[222px] overflow-y-auto">
{/* Logo */}
<div className="w-full h-10">
<Image
src="/logo.svg"
alt="ASSETX Logo"
width={174}
height={40}
className="w-full h-full"
/>
</div>
{/* Navigation */}
<nav className="flex flex-col gap-2 w-[174px]">
{navigationItems.map((item) => (
<NavItem
key={item.key}
icon={item.icon}
label={item.label}
isActive={activeItem === item.key}
onClick={() => setActiveItem(item.key)}
/>
))}
</nav>
{/* Spacer */}
<div className="flex-1" />
{/* Global TVL Section */}
<div className="w-full border-t border-border-gray dark:border-gray-700 pt-8">
<div className="bg-bg-subtle dark:bg-gray-700 rounded-xl p-4 flex flex-col gap-1 h-[85px]">
<p className="text-text-tertiary dark:text-gray-400 text-[10px] font-medium leading-[150%] tracking-[0.01em]">
{t("nav.globalTVL")}
</p>
<p className="text-text-primary dark:text-white text-base font-extrabold leading-[150%] font-jetbrains">
$465,000,000
</p>
</div>
{/* FAQs Link */}
<div className="rounded-xl flex items-center h-[42px] mt-8">
<div className="flex items-center gap-0">
<Image
src="/icon-faq.png"
alt="FAQ"
width={24}
height={24}
className="object-cover"
/>
<span className="text-text-primary dark:text-white text-sm font-bold leading-[150%]">
{t("nav.faqs")}
</span>
</div>
</div>
</div>
</aside>
);
}

View File

@@ -1,61 +1,61 @@
"use client";
import { useApp } from "@/contexts/AppContext";
interface StatCardProps {
label: string;
value: string;
change?: string;
changeColor?: string;
valueColor?: string;
}
function StatCard({
label,
value,
change,
changeColor = "text-green-500",
valueColor
}: StatCardProps) {
const getValueColor = () => {
if (valueColor) return valueColor;
if (label.includes("APY") || label.includes("年化")) return "#ff6900";
return "#111827";
};
return (
<div className="bg-bg-subtle dark:bg-gray-700 rounded-2xl border border-border-gray dark:border-gray-600 p-4 flex flex-col gap-2">
<p className="text-caption-tiny font-bold text-text-tertiary dark:text-gray-400 uppercase tracking-wider">
{label}
</p>
<p className="text-heading-h3 font-bold dark:text-white" style={{ color: getValueColor() }}>
{value}
</p>
{change && (
<p className={`text-caption-tiny font-medium ${changeColor} dark:text-gray-400`}>
{change}
</p>
)}
</div>
);
}
export default function StatsCards() {
const { t } = useApp();
return (
<div className="grid grid-cols-5 gap-4 w-full">
<StatCard label={t("stats.currentAPY")} value="22%" change="+2.5% WoW" changeColor="text-green-500" />
<StatCard label={t("stats.totalValueLocked")} value="$240.5M" change="+$2.3M Today" changeColor="text-green-500" />
<StatCard label="24h Volume" value="$12.8M" change="↑ 23% vs Avg" changeColor="text-green-500" />
<StatCard label={t("stats.yourBalance")} value="0.00" change="$0.00 USD" changeColor="text-text-tertiary" />
<StatCard
label={t("stats.yourEarnings")}
value="$0.00"
change="All Time"
changeColor="text-text-tertiary"
valueColor="#10b981"
/>
</div>
);
}
"use client";
import { useApp } from "@/contexts/AppContext";
interface StatCardProps {
label: string;
value: string;
change?: string;
changeColor?: string;
valueColor?: string;
}
function StatCard({
label,
value,
change,
changeColor = "text-green-500",
valueColor
}: StatCardProps) {
const getValueColor = () => {
if (valueColor) return valueColor;
if (label.includes("APY") || label.includes("年化")) return "#ff6900";
return "#111827";
};
return (
<div className="bg-bg-subtle dark:bg-gray-700 rounded-2xl border border-border-gray dark:border-gray-600 p-4 flex flex-col gap-2">
<p className="text-caption-tiny font-bold text-text-tertiary dark:text-gray-400 uppercase tracking-wider">
{label}
</p>
<p className="text-heading-h3 font-bold dark:text-white" style={{ color: getValueColor() }}>
{value}
</p>
{change && (
<p className={`text-caption-tiny font-medium ${changeColor} dark:text-gray-400`}>
{change}
</p>
)}
</div>
);
}
export default function StatsCards() {
const { t } = useApp();
return (
<div className="grid grid-cols-5 gap-4 w-full">
<StatCard label={t("stats.currentAPY")} value="22%" change="+2.5% WoW" changeColor="text-green-500" />
<StatCard label={t("stats.totalValueLocked")} value="$240.5M" change="+$2.3M Today" changeColor="text-green-500" />
<StatCard label="24h Volume" value="$12.8M" change="↑ 23% vs Avg" changeColor="text-green-500" />
<StatCard label={t("stats.yourBalance")} value="0.00" change="$0.00 USD" changeColor="text-text-tertiary" />
<StatCard
label={t("stats.yourEarnings")}
value="$0.00"
change="All Time"
changeColor="text-text-tertiary"
valueColor="#10b981"
/>
</div>
);
}

View File

@@ -1,55 +1,43 @@
"use client";
import { useState } from "react";
interface Tab {
id: string;
label: string;
}
interface TabNavigationProps {
tabs: Tab[];
defaultActiveId?: string;
onTabChange?: (tabId: string) => void;
}
export default function TabNavigation({
tabs,
defaultActiveId,
onTabChange,
}: TabNavigationProps) {
const [activeTab, setActiveTab] = useState(defaultActiveId || tabs[0]?.id);
const handleTabClick = (tabId: string) => {
setActiveTab(tabId);
onTabChange?.(tabId);
};
return (
<div className="flex items-center gap-8">
{tabs.map((tab) => {
const isActive = activeTab === tab.id;
return (
<button
key={tab.id}
onClick={() => handleTabClick(tab.id)}
className="flex flex-col gap-2 items-start"
>
<span
className={`text-sm font-bold leading-[150%] ${
isActive ? "text-text-primary dark:text-white" : "text-text-tertiary dark:text-gray-400"
}`}
>
{tab.label}
</span>
<div
className={`self-stretch border-t-2 -mt-[2px] ${
isActive ? "border-text-primary dark:border-white" : "border-transparent"
}`}
/>
</button>
);
})}
</div>
);
}
"use client";
import { Tabs, Tab } from "@heroui/react";
interface TabItem {
id: string;
label: string;
}
interface TabNavigationProps {
tabs: TabItem[];
defaultActiveId?: string;
onTabChange?: (tabId: string) => void;
}
export default function TabNavigation({
tabs,
defaultActiveId,
onTabChange,
}: TabNavigationProps) {
const handleSelectionChange = (key: React.Key) => {
onTabChange?.(key.toString());
};
return (
<Tabs
selectedKey={defaultActiveId || tabs[0]?.id}
onSelectionChange={handleSelectionChange}
variant="underlined"
classNames={{
base: "w-auto",
tabList: "gap-8 w-auto p-0",
cursor: "bg-text-primary dark:bg-white",
tab: "px-0 h-auto",
tabContent: "text-sm font-bold text-text-tertiary dark:text-gray-400 group-data-[selected=true]:text-text-primary dark:group-data-[selected=true]:text-white",
}}
>
{tabs.map((tab) => (
<Tab key={tab.id} title={tab.label} />
))}
</Tabs>
);
}

View File

@@ -1,46 +1,53 @@
"use client";
import { useApp } from "@/contexts/AppContext";
export default function ThemeSwitch() {
const { theme, setTheme } = useApp();
const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};
return (
<button
onClick={toggleTheme}
className="bg-bg-surface dark:bg-gray-800 rounded-lg border border-border-normal dark:border-gray-700 px-3 py-2 flex items-center justify-center h-10 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
{theme === "light" ? (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path
d="M10 15C12.7614 15 15 12.7614 15 10C15 7.23858 12.7614 5 10 5C7.23858 5 5 7.23858 5 10C5 12.7614 7.23858 15 10 15Z"
stroke="#111827"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M10 1V3M10 17V19M19 10H17M3 10H1M16.07 16.07L14.64 14.64M5.36 5.36L3.93 3.93M16.07 3.93L14.64 5.36M5.36 14.64L3.93 16.07"
stroke="#111827"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
) : (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path
d="M17 10.79C16.8427 12.4922 16.1039 14.0754 14.9116 15.2662C13.7192 16.4571 12.1503 17.1913 10.4501 17.3464C8.74989 17.5016 7.04992 17.0676 5.63182 16.1159C4.21372 15.1642 3.15973 13.7534 2.63564 12.1102C2.11155 10.467 2.14637 8.68739 2.73477 7.06725C3.32317 5.44711 4.43113 4.07931 5.88616 3.18637C7.3412 2.29343 9.05859 1.93047 10.7542 2.15507C12.4498 2.37967 13.9989 3.17747 15.16 4.41"
stroke="#111827"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)}
</button>
);
}
"use client";
import { useApp } from "@/contexts/AppContext";
import { Button } from "@heroui/react";
export default function ThemeSwitch() {
const { theme, setTheme } = useApp();
const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};
return (
<Button
isIconOnly
variant="bordered"
onPress={toggleTheme}
className="bg-bg-surface dark:bg-gray-800 border-border-normal dark:border-gray-700 min-w-10 h-10 rounded-lg"
aria-label={`Switch to ${theme === "light" ? "dark" : "light"} mode`}
>
{theme === "light" ? (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path
d="M10 15C12.7614 15 15 12.7614 15 10C15 7.23858 12.7614 5 10 5C7.23858 5 5 7.23858 5 10C5 12.7614 7.23858 15 10 15Z"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
className="text-text-primary dark:text-white"
/>
<path
d="M10 1V3M10 17V19M19 10H17M3 10H1M16.07 16.07L14.64 14.64M5.36 5.36L3.93 3.93M16.07 3.93L14.64 5.36M5.36 14.64L3.93 16.07"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
className="text-text-primary dark:text-white"
/>
</svg>
) : (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path
d="M17 10.79C16.8427 12.4922 16.1039 14.0754 14.9116 15.2662C13.7192 16.4571 12.1503 17.1913 10.4501 17.3464C8.74989 17.5016 7.04992 17.0676 5.63182 16.1159C4.21372 15.1642 3.15973 13.7534 2.63564 12.1102C2.11155 10.467 2.14637 8.68739 2.73477 7.06725C3.32317 5.44711 4.43113 4.07931 5.88616 3.18637C7.3412 2.29343 9.05859 1.93047 10.7542 2.15507C12.4498 2.37967 13.9989 3.17747 15.16 4.41"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
className="text-text-primary dark:text-white"
/>
</svg>
)}
</Button>
);
}

View File

@@ -1,50 +1,59 @@
import Image from "next/image";
import Breadcrumb from "./Breadcrumb";
import LanguageSwitch from "./LanguageSwitch";
import ThemeSwitch from "./ThemeSwitch";
export default function TopBar() {
const breadcrumbItems = [
{ label: "ASSETX" },
{ label: "Product" },
{ label: "Detail" },
];
return (
<div className="flex items-center justify-between w-full">
{/* Left: Breadcrumb */}
<div className="flex items-center gap-2">
<Breadcrumb items={breadcrumbItems} />
</div>
{/* Right: Actions */}
<div className="flex items-center gap-4">
{/* Language Switch */}
<LanguageSwitch />
{/* Theme Switch */}
<ThemeSwitch />
{/* Wallet Button */}
<button className="bg-bg-surface rounded-lg border border-border-normal px-2 py-2 flex items-center justify-center h-10">
<Image src="/icon-wallet.svg" alt="Wallet" width={20} height={20} />
<Image
src="/icon-notification.svg"
alt="Notification"
width={14}
height={14}
className="ml-1"
/>
</button>
{/* Address Button */}
<button className="bg-text-primary rounded-lg px-4 py-2 flex items-center justify-center gap-2 h-10 hover:bg-gray-800 transition-colors">
<Image src="/icon-copy.svg" alt="Copy" width={16} height={16} />
<span className="text-white text-sm font-bold font-jetbrains">
0x12...4F82
</span>
</button>
</div>
</div>
);
}
"use client";
import Image from "next/image";
import { Button } from "@heroui/react";
import Breadcrumb from "./Breadcrumb";
import LanguageSwitch from "./LanguageSwitch";
import ThemeSwitch from "./ThemeSwitch";
export default function TopBar() {
const breadcrumbItems = [
{ label: "ASSETX" },
{ label: "Product" },
{ label: "Detail" },
];
return (
<div className="flex items-center justify-between w-full">
{/* Left: Breadcrumb */}
<div className="flex items-center gap-2">
<Breadcrumb items={breadcrumbItems} />
</div>
{/* Right: Actions */}
<div className="flex items-center gap-4">
{/* Language Switch */}
<LanguageSwitch />
{/* Theme Switch */}
<ThemeSwitch />
{/* Wallet Button */}
<Button
isIconOnly
variant="bordered"
className="bg-bg-surface border-border-normal min-w-10 h-10 rounded-lg"
>
<div className="flex items-center justify-center">
<Image src="/icon-wallet.svg" alt="Wallet" width={20} height={20} />
<Image
src="/icon-notification.svg"
alt="Notification"
width={14}
height={14}
className="ml-1"
/>
</div>
</Button>
{/* Address Button */}
<Button
className="bg-text-primary text-white font-bold font-jetbrains text-sm h-10 px-4 rounded-lg"
startContent={<Image src="/icon-copy.svg" alt="Copy" width={16} height={16} />}
>
0x12...4F82
</Button>
</div>
</div>
);
}