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,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>
);
}