81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
"use client"
|
|
|
|
import type React from "react"
|
|
import { useHistory, useLocation } from "react-router-dom"
|
|
|
|
import { getRouteHome } from "../shared/consts/router"
|
|
import { getRouteCourses } from "../shared/consts/router"
|
|
import { getRouteCourseExercises } from "../shared/consts/router"
|
|
import { getRouteSettings } from "../shared/consts/router"
|
|
|
|
import { HomeIcon } from "./icons/HomeIcon"
|
|
import { CoursesIcon } from "./icons/CoursesIcon"
|
|
import { ExerciseIcon } from "./icons/ExerciseIcon"
|
|
import { SettingsIcon } from "./icons/SettingsIcon"
|
|
|
|
|
|
const BottomNavigation: React.FC = () => {
|
|
const history = useHistory()
|
|
const location = useLocation()
|
|
|
|
const navItems = [
|
|
{ path: getRouteHome(), icon: HomeIcon, label: "Домой" },
|
|
{ path: getRouteCourses(), icon: CoursesIcon, label: "Курсы" },
|
|
{ path: getRouteCourseExercises(":id"), icon: ExerciseIcon, label: "Тренировка" },
|
|
{ path: getRouteSettings(), icon: SettingsIcon, label: "Меню" },
|
|
]
|
|
|
|
const isActive = (path: string) => {
|
|
// Проверка на совпадение или включение
|
|
return location.pathname === path || location.pathname.startsWith(path)
|
|
}
|
|
|
|
return (
|
|
<div className="fixed bottom-0 left-0 right-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C] px-4 pt-4 pb-8 z-50 shadow-lg rounded-t-3xl">
|
|
<nav className="flex justify-around items-center max-w-md mx-auto">
|
|
{navItems.map((item) => {
|
|
const active = isActive(item.path)
|
|
const IconComponent = item.icon
|
|
return (
|
|
<button
|
|
key={item.path}
|
|
onClick={() => history.push(item.path)}
|
|
className="relative flex flex-col items-center justify-center w-24 h-24 overflow-hidden group focus:outline-none focus-visible:ring-1 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-[#0D212C]"
|
|
>
|
|
{/* Active state background (glassmorphism rectangle) */}
|
|
<div
|
|
className={`absolute rounded-2xl shadow-md transition-all duration-300 ease-out bg-white/60 backdrop-blur-md border border-white/20 ${
|
|
active ? "opacity-100 scale-100 w-20 h-20 top-2" : "opacity-0 scale-0 w-0 h-0 top-0"
|
|
}`}
|
|
/>
|
|
{/* Icon and Label container */}
|
|
<div
|
|
className={`relative z-10 flex flex-col items-center justify-center transition-all duration-300 ease-out ${
|
|
active ? "text-[#145058]" : "text-white/70 translate-y-0 group-hover:text-white"
|
|
}`}
|
|
>
|
|
<div className="mb-1">
|
|
<IconComponent active={active} size={34} />
|
|
</div>
|
|
<span className="text-xs font-medium">{item.label}</span>
|
|
<span className="sr-only">{item.label}</span>
|
|
</div>
|
|
{/* Bottom circle with glow */}
|
|
<div
|
|
className={`absolute w-4 h-4 rounded-full border-1 border-cyan-900 shadow-lg shadow-[#2BACBE]/50 animate-pulse transition-all duration-300 ease-out ${
|
|
active ? "opacity-100 scale-100 translate-y-[40px]" : "opacity-0 scale-0"
|
|
}`}
|
|
>
|
|
{/* Внутренний маленький круг */}
|
|
<div className="w-3 h-3 bg-cyan-900 rounded-full mt-[1px] ml-[1px]" />
|
|
</div>
|
|
</button>
|
|
)
|
|
})}
|
|
</nav>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default BottomNavigation
|