feat(ui): add new ui

This commit is contained in:
shafin-r
2026-02-20 19:10:13 +06:00
parent 3c8f945539
commit 76d2108aec
16 changed files with 4263 additions and 1702 deletions

View File

@ -3,66 +3,174 @@ import { Home, BookOpen, Award, User, Video } from "lucide-react";
import { SidebarProvider, SidebarTrigger } from "../../components/ui/sidebar";
import { AppSidebar } from "../../components/AppSidebar";
export function StudentLayout() {
const navItems = [
{ to: "/student/home", icon: Home, label: "Home" },
{ to: "/student/practice", icon: BookOpen, label: "Practice" },
{ to: "/student/lessons", icon: Video, label: "Lessons" },
{ to: "/student/rewards", icon: Award, label: "Rewards" },
{ to: "/student/profile", icon: User, label: "Profile" },
];
const NAV_ITEMS = [
{
to: "/student/home",
icon: Home,
label: "Home",
color: "#f97316",
bg: "rgba(249,115,22,0.12)",
},
{
to: "/student/practice",
icon: BookOpen,
label: "Practice",
color: "#a855f7",
bg: "rgba(168,85,247,0.12)",
},
{
to: "/student/lessons",
icon: Video,
label: "Lessons",
color: "#0891b2",
bg: "rgba(8,145,178,0.12)",
},
{
to: "/student/rewards",
icon: Award,
label: "Rewards",
color: "#16a34a",
bg: "rgba(22,163,74,0.12)",
},
{
to: "/student/profile",
icon: User,
label: "Profile",
color: "#e11d48",
bg: "rgba(225,29,72,0.12)",
},
];
const STYLES = `
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@700;800;900&display=swap');
/* ── The floating island dock ── */
.sl-dock-wrap {
position: fixed;
bottom: calc(1.25rem + env(safe-area-inset-bottom));
left: 50%;
transform: translateX(-50%);
z-index: 20;
/* Frosted pill */
background: rgba(255, 251, 244, 0.72);
backdrop-filter: blur(24px) saturate(180%);
-webkit-backdrop-filter: blur(24px) saturate(180%);
border: 1.5px solid rgba(255,255,255,0.7);
border-radius: 100px;
box-shadow:
0 8px 32px rgba(0,0,0,0.12),
0 2px 8px rgba(0,0,0,0.06),
inset 0 1px 0 rgba(255,255,255,0.8);
padding: 0.45rem 0.5rem;
display: flex;
align-items: center;
gap: 0.15rem;
}
/* ── Each nav item ── */
.sl-dock-item {
display: flex;
align-items: center;
gap: 0;
border-radius: 100px;
padding: 0.5rem 0.6rem;
text-decoration: none;
border: none;
background: transparent;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition:
padding 0.35s cubic-bezier(0.34,1.56,0.64,1),
gap 0.35s cubic-bezier(0.34,1.56,0.64,1),
background 0.25s ease;
white-space: nowrap;
overflow: hidden;
}
.sl-dock-item:active { transform: scale(0.91); }
.sl-dock-item.active {
padding: 0.5rem 1rem 0.5rem 0.75rem;
gap: 0.45rem;
}
/* ── Icon circle ── */
.sl-dock-icon {
width: 32px; height: 32px; flex-shrink: 0;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
background: transparent;
transition: background 0.25s ease, transform 0.35s cubic-bezier(0.34,1.56,0.64,1);
}
.sl-dock-item.active .sl-dock-icon {
transform: scale(1.1);
}
/* ── Label (only visible when active) ── */
.sl-dock-label {
font-family: 'Nunito', sans-serif;
font-size: 0.8rem;
font-weight: 900;
letter-spacing: 0.01em;
max-width: 0;
opacity: 0;
overflow: hidden;
transition:
max-width 0.35s cubic-bezier(0.34,1.56,0.64,1),
opacity 0.25s ease 0.05s;
pointer-events: none;
}
.sl-dock-item.active .sl-dock-label {
max-width: 80px;
opacity: 1;
}
`;
export function StudentLayout() {
return (
<SidebarProvider>
<style>{STYLES}</style>
<div className="flex min-h-screen w-full overflow-x-hidden">
{/* Desktop Sidebar */}
<AppSidebar />
<div className="flex flex-col flex-1 min-w-0">
<SidebarTrigger className="hidden md:block" />
<main className="flex-1 pb-24 md:pb-0">
{/* Extra bottom padding so content clears the floating dock */}
<main className="flex-1 pb-32 md:pb-0">
<Outlet />
</main>
</div>
{/* Mobile bottom nav */}
<nav className="fixed bottom-0 left-0 right-0 rounded-t-4xl pt-2 bg-white border-t border-gray-200 shadow-4xl z-20 md:hidden">
<div className="max-w-7xl mx-auto px-2">
<div className="flex justify-around items-center">
{navItems.map((item) => (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
`flex flex-col items-center justify-center py-3 px-4 flex-1 transition-all duration-200 font-satoshi tracking-wide ${
isActive
? "text-indigo-600"
: "text-gray-500 hover:text-gray-700"
}`
}
>
{({ isActive }) => (
<>
<item.icon
size={24}
className={`mb-1 transition-transform ${
isActive ? "scale-110" : ""
}`}
strokeWidth={isActive ? 2.5 : 2}
/>
<span
className={`text-xs font-medium ${
isActive ? "font-semibold" : ""
}`}
>
{item.label}
</span>
</>
)}
</NavLink>
))}
</div>
</div>
{/* ── Floating island dock (mobile only) ── */}
<nav className="sl-dock-wrap md:hidden">
{NAV_ITEMS.map((item) => (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
`sl-dock-item${isActive ? " active" : ""}`
}
>
{({ isActive }) => (
<>
<div
className="sl-dock-icon"
style={{ background: isActive ? item.bg : "transparent" }}
>
<item.icon
size={18}
strokeWidth={isActive ? 2.5 : 1.75}
color={isActive ? item.color : "#94a3b8"}
/>
</div>
<span className="sl-dock-label" style={{ color: item.color }}>
{item.label}
</span>
</>
)}
</NavLink>
))}
</nav>
</div>
</SidebarProvider>