Prjgressbar

This commit is contained in:
Tatyana 2025-08-06 13:00:10 +03:00
parent cc145c8804
commit a69916b87a
3 changed files with 60 additions and 36 deletions

View File

@ -3,16 +3,17 @@
import type React from "react" import type React from "react"
import { useHistory, useLocation } from "react-router-dom" import { useHistory, useLocation } from "react-router-dom"
const BottomNavigation: React.FC = () => { const BottomNavigation: React.FC = () => {
const history = useHistory() const history = useHistory()
const location = useLocation() const location = useLocation()
// Define SVG icons directly within the component // Define SVG icons directly within the component, with active state styling
const HomeIcon = ({ active }: { active: boolean }) => ( const HomeIcon = ({ active, size = 24 }: { active: boolean; size?: number }) => (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="24" width={size}
height="24" height={size}
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill={active ? "currentColor" : "none"} fill={active ? "currentColor" : "none"}
stroke={active ? "none" : "currentColor"} stroke={active ? "none" : "currentColor"}
@ -25,11 +26,11 @@ const BottomNavigation: React.FC = () => {
</svg> </svg>
) )
const CoursesIcon = ({ active }: { active: boolean }) => ( const CoursesIcon = ({ active, size = 24 }: { active: boolean; size?: number }) => (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="24" width={size}
height="24" height={size}
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill={active ? "currentColor" : "none"} fill={active ? "currentColor" : "none"}
stroke={active ? "none" : "currentColor"} stroke={active ? "none" : "currentColor"}
@ -42,11 +43,11 @@ const BottomNavigation: React.FC = () => {
</svg> </svg>
) )
const ExerciseIcon = ({ active }: { active: boolean }) => ( const ExerciseIcon = ({ active, size = 24 }: { active: boolean; size?: number }) => (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="24" width={size}
height="24" height={size}
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill={active ? "currentColor" : "none"} fill={active ? "currentColor" : "none"}
stroke={active ? "none" : "currentColor"} stroke={active ? "none" : "currentColor"}
@ -60,11 +61,11 @@ const BottomNavigation: React.FC = () => {
</svg> </svg>
) )
const SettingsIcon = ({ active }: { active: boolean }) => ( const SettingsIcon = ({ active, size = 24 }: { active: boolean; size?: number }) => (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="24" width={size}
height="24" height={size}
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill={active ? "currentColor" : "none"} fill={active ? "currentColor" : "none"}
stroke={active ? "none" : "currentColor"} stroke={active ? "none" : "currentColor"}
@ -90,8 +91,8 @@ const BottomNavigation: React.FC = () => {
} }
return ( return (
<div className="fixed bottom-0 left-0 right-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C] p-4 z-50 shadow-lg"> <div className="fixed bottom-0 left-0 right-0 bg-gradient-to-br from-[#3ABBC7] to-[#0D212C] p-4 z-50 shadow-lg rounded-t-3xl">
<div className="flex justify-around items-center max-w-md mx-auto"> <nav className="flex justify-around items-center max-w-md mx-auto">
{navItems.map((item) => { {navItems.map((item) => {
const active = isActive(item.path) const active = isActive(item.path)
const IconComponent = item.icon const IconComponent = item.icon
@ -99,37 +100,36 @@ const BottomNavigation: React.FC = () => {
<button <button
key={item.path} key={item.path}
onClick={() => history.push(item.path)} onClick={() => history.push(item.path)}
className="relative flex flex-col items-center justify-center w-24 h-24 overflow-hidden" 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) */} {/* Active state background (glassmorphism rectangle) */}
<div <div
className={`absolute glass-morphism rounded-2xl shadow-md className={`absolute rounded-2xl shadow-md transition-all duration-300 ease-out bg-white/10 backdrop-blur-md border border-white/20 ${
transition-all duration-300 ease-out active ? "opacity-100 scale-100 w-20 h-20 top-0" : "opacity-0 scale-0 w-0 h-0 top-0"
${active ? "opacity-100 scale-100 w-20 h-20 -top-4" : "opacity-0 scale-0 w-0 h-0 top-0"}`} }`}
/> />
{/* Icon and Label container */} {/* Icon and Label container */}
<div <div
className={`relative z-10 flex flex-col items-center justify-center className={`relative z-10 flex flex-col items-center justify-center transition-all duration-300 ease-out ${
transition-all duration-300 ease-out active ? "text-[#2BACBE] translate-y-[-10px]" : "text-white/70 translate-y-0 group-hover:text-white"
${active ? "text-[#2BACBE] translate-y-[-24px]" : "text-white/70 translate-y-0 group-hover:text-white"}`} }`}
> >
<div className="mb-1"> <div className="mb-1">
<IconComponent active={active} /> <IconComponent active={active} size={24} />
</div> </div>
<span className="text-xs font-medium">{item.label}</span> <span className="text-xs font-medium">{item.label}</span>
<span className="sr-only">{item.label}</span>
</div> </div>
{/* Bottom circle with glow */} {/* Bottom circle with glow */}
<div <div
className={`absolute w-2 h-2 rounded-full border-2 border-white shadow-lg shadow-[#2BACBE]/50 animate-pulse className={`absolute w-2 h-2 rounded-full border-2 border-white shadow-lg shadow-[#2BACBE]/50 animate-pulse transition-all duration-300 ease-out ${
transition-all duration-300 ease-out active ? "opacity-100 scale-100 translate-y-[32px]" : "opacity-0 scale-0 translate-y-[0px]"
${active ? "opacity-100 scale-100 translate-y-[36px]" : "opacity-0 scale-0 translate-y-[0px]"}`} }`}
/> />
</button> </button>
) )
})} })}
</div> </nav>
</div> </div>
) )
} }

View File

@ -23,7 +23,7 @@ const CircularProgressDisplay: React.FC<CircularProgressDisplayProps> = ({
const exercisesStrokeDashoffset = circumference - (exercisesProgress / 100) * circumference const exercisesStrokeDashoffset = circumference - (exercisesProgress / 100) * circumference
return ( return (
<div className="relative w-32 h-32 mx-auto flex items-center justify-center"> <div className="relative w-40 h-40 mx-auto flex items-center justify-center">
<svg className="w-full h-full" viewBox="0 0 100 100"> <svg className="w-full h-full" viewBox="0 0 100 100">
{/* Overall Progress Background Circle */} {/* Overall Progress Background Circle */}
<circle <circle
@ -36,9 +36,9 @@ const CircularProgressDisplay: React.FC<CircularProgressDisplayProps> = ({
cy="50" cy="50"
/> />
{/* Courses Ring (Blue) */}
<circle <circle
className="text-blue-500" className="text-orange-400"
strokeWidth="8" strokeWidth="8"
strokeDasharray={circumference} strokeDasharray={circumference}
strokeDashoffset={coursesStrokeDashoffset} strokeDashoffset={coursesStrokeDashoffset}
@ -51,9 +51,9 @@ const CircularProgressDisplay: React.FC<CircularProgressDisplayProps> = ({
transform="rotate(-90 50 50)" transform="rotate(-90 50 50)"
/> />
{/* Exercises Ring (Green) */}
<circle <circle
className="text-green-500" className="text-cyan-400"
strokeWidth="8" strokeWidth="8"
strokeDasharray={circumference} strokeDasharray={circumference}
strokeDashoffset={exercisesStrokeDashoffset} strokeDashoffset={exercisesStrokeDashoffset}
@ -67,8 +67,8 @@ const CircularProgressDisplay: React.FC<CircularProgressDisplayProps> = ({
/> />
</svg> </svg>
<div className="absolute text-center"> <div className="absolute text-center">
<div className="text-3xl font-black text-gray-800">{overallProgress}%</div> <div className="text-3xl font-black text-gray-600">{overallProgress}%</div>
<div className="text-xs text-gray-600 font-semibold">Общий прогресс</div>
</div> </div>
</div> </div>
) )

24
src/components/Icons.tsx Normal file
View File

@ -0,0 +1,24 @@
import type React from "react"
// Your custom Home icon component
export const CustomHomeIcon = ({ active, size = 24 }: { active: boolean; size?: number }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill={active ? "currentColor" : "none"} // Fill when active
stroke={active ? "none" : "currentColor"} // Stroke when inactive
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
);
// You can add other custom icons here if needed in the future
// export const CustomAnotherIcon = ({ active, size = 24 }: { active: boolean; size?: number }) => (
// <svg>...</svg>
// );