feat(ui): add infoheader component, improve quest map visuals
This commit is contained in:
@ -1,26 +1,12 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAuthStore } from "../../stores/authStore";
|
||||
import { CheckCircle, Flame, Gauge, Play, Search } from "lucide-react";
|
||||
import { CheckCircle, Play, Search } from "lucide-react";
|
||||
import { api } from "../../utils/api";
|
||||
import type { PracticeSheet } from "../../types/sheet";
|
||||
import { formatStatus } from "../../lib/utils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { SearchOverlay } from "../../components/SearchOverlay";
|
||||
import { PredictedScoreCard } from "../../components/PredictedScoreCard";
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "../../components/ui/avatar";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerTrigger,
|
||||
} from "../../components/ui/drawer";
|
||||
import { useExamConfigStore } from "../../stores/useExamConfigStore";
|
||||
import { QuestProgressCard } from "../../components/QuestProgressCard";
|
||||
|
||||
// somewhere in the Home JSX, above the sheets tabs:
|
||||
import { InfoHeader } from "../../components/InfoHeader";
|
||||
|
||||
// ─── Shared blob/dot background (same as break/results screens) ────────────────
|
||||
const DOTS = [
|
||||
@ -78,36 +64,6 @@ const STYLES = `
|
||||
gap: 1.75rem;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
.home-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
animation: hPopIn 0.4s cubic-bezier(0.34,1.56,0.64,1) both;
|
||||
}
|
||||
.home-header-left { display:flex;align-items:center;gap:0.75rem; }
|
||||
.home-user-name {
|
||||
font-size: 1.1rem; font-weight: 900; color: #1e1b4b; line-height:1.1;
|
||||
}
|
||||
.home-user-role {
|
||||
font-size: 0.72rem; font-weight: 700; letter-spacing:0.08em;
|
||||
text-transform: uppercase; color: #a855f7;
|
||||
}
|
||||
.home-header-right { display:flex;align-items:center;gap:0.6rem; }
|
||||
|
||||
/* Header action chips */
|
||||
.h-chip {
|
||||
display: flex; align-items: center; gap: 0.4rem;
|
||||
background: white; border: 2.5px solid #f3f4f6;
|
||||
border-radius: 100px; padding: 0.5rem 0.9rem;
|
||||
box-shadow: 0 3px 10px rgba(0,0,0,0.06);
|
||||
cursor: pointer; font-size:0.85rem; font-weight:800;
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
.h-chip:hover { transform:translateY(-2px);box-shadow:0 6px 14px rgba(0,0,0,0.08); }
|
||||
.h-chip.streak { border-color:#fecaca; background:#fff5f5; color:#ef4444; }
|
||||
.h-chip.score { border-color:#d9f99d; background:#f7ffe4; color:#65a30d; }
|
||||
|
||||
/* ── Section titles ── */
|
||||
.h-section-title {
|
||||
font-size: 1.2rem; font-weight: 900; color: #1e1b4b;
|
||||
@ -331,12 +287,11 @@ const TIPS = [
|
||||
];
|
||||
|
||||
// ─── Main component ───────────────────────────────────────────────────────────
|
||||
const PAGE_SIZE = 2;
|
||||
const PAGE_SIZE = 6;
|
||||
|
||||
export const Home = () => {
|
||||
const user = useAuthStore((state) => state.user);
|
||||
const navigate = useNavigate();
|
||||
const { userMetrics } = useExamConfigStore();
|
||||
|
||||
const [practiceSheets, setPracticeSheets] = useState<PracticeSheet[]>([]);
|
||||
const [notStartedSheets, setNotStartedSheets] = useState<PracticeSheet[]>([]);
|
||||
@ -397,15 +352,8 @@ export const Home = () => {
|
||||
setVisibleCount(PAGE_SIZE);
|
||||
};
|
||||
|
||||
const greeting =
|
||||
new Date().getHours() < 12
|
||||
? "Good morning"
|
||||
: new Date().getHours() < 17
|
||||
? "Good afternoon"
|
||||
: "Good evening";
|
||||
|
||||
return (
|
||||
<div className="home-screen pb-12">
|
||||
<div className="home-screen">
|
||||
<style>{STYLES}</style>
|
||||
|
||||
{/* Blobs */}
|
||||
@ -436,56 +384,10 @@ export const Home = () => {
|
||||
|
||||
<div className="home-inner">
|
||||
{/* ── Header ── */}
|
||||
<header className="home-header">
|
||||
<div className="home-header-left">
|
||||
<Avatar style={{ width: 48, height: 48 }}>
|
||||
<AvatarImage src={user?.avatar_url} />
|
||||
<AvatarFallback
|
||||
style={{
|
||||
fontWeight: 900,
|
||||
fontSize: "1.1rem",
|
||||
color: "white",
|
||||
textTransform: "uppercase",
|
||||
background: "linear-gradient(135deg,#a855f7,#7c3aed)",
|
||||
}}
|
||||
>
|
||||
{user?.name?.slice(0, 1)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="space-y-1">
|
||||
<p className="home-user-name">
|
||||
{greeting}, {user?.name?.split(" ")[0] || "Student"}
|
||||
</p>
|
||||
<p className="home-user-role">
|
||||
{user?.role === "STUDENT"
|
||||
? "Student"
|
||||
: user?.role === "ADMIN"
|
||||
? "Admin"
|
||||
: "Teacher"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="home-header-right">
|
||||
{/* Streak chip */}
|
||||
<div className="h-chip streak">
|
||||
<Flame size={18} style={{ fill: "#fca5a5" }} />
|
||||
<span>{userMetrics.streak}</span>
|
||||
</div>
|
||||
|
||||
{/* Score chip */}
|
||||
<Drawer direction="top">
|
||||
<DrawerTrigger asChild>
|
||||
<div className="h-chip score">
|
||||
<Gauge size={18} />
|
||||
</div>
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<PredictedScoreCard />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</div>
|
||||
</header>
|
||||
<InfoHeader
|
||||
mode="DEFAULT"
|
||||
onViewAll={() => navigate("/student/quests")}
|
||||
/>
|
||||
|
||||
{/* ── Search ── */}
|
||||
<div className="h-search-wrap h-anim h-anim-1">
|
||||
@ -499,7 +401,7 @@ export const Home = () => {
|
||||
onFocus={() => setIsSearchOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
<QuestProgressCard onViewAll={() => navigate("/student/quests")} />
|
||||
|
||||
{/* ── In progress ── */}
|
||||
<section className="h-anim h-anim-2">
|
||||
<p className="h-section-title">📌 Pick up where you left off</p>
|
||||
|
||||
Reference in New Issue
Block a user