Added timeline#20
Conversation
spandan11106
commented
May 28, 2026
- Time line added.
|
Skipping CodeAnt AI review — this PR is a back-merge between long-lived branches ( If you want to analyze this anyway (e.g. you resolved conflicts with new logic), comment |
There was a problem hiding this comment.
Pull request overview
Adds a static Gantt-style timeline component to the dashboard that visualizes a fixed program schedule (June 1 – July 12, 2025) with hover-highlighted track bars, a "Today" indicator, and a month-boundary divider. The component is inserted between DashboardStats and the module-progress section in Dashboard.jsx and is not wired to any backend data.
Changes:
- New
TimelineCalendarReact component rendering hard-coded tracks and date markers as a Gantt chart with mount-time bar animations and hover state. - New
timeline.cssstylesheet defining the section, card, axis, grid lines, and bar styles using existing global brand tokens. Dashboard.jsximports and renders<TimelineCalendar />below the stats row.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| frontend/src/pages/Dashboard.jsx | Imports TimelineCalendar and renders it between dashboard stats and module list. |
| frontend/src/components/dashboard/TimelineCalendar.jsx | New component with hard-coded date range, tracks, axis rendering, hover state, and mount animation. |
| frontend/src/components/dashboard/timeline.css | New stylesheet for the timeline section, card, axis, grid lines, and bars. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const TIMELINE_START = new Date(2025, 5, 1); // June 1 2025 | ||
| const TIMELINE_END = new Date(2025, 6, 12); // July 12 2025 | ||
|
|
||
| const MONTH_MARKERS = [ | ||
| { label: "JUNE", date: new Date(2025, 5, 1) }, | ||
| { label: "JULY", date: new Date(2025, 6, 1) }, | ||
| ]; | ||
|
|
||
| const DATE_LABELS = [ | ||
| { label: "01", date: new Date(2025, 5, 1) }, | ||
| { label: "8", date: new Date(2025, 5, 8) }, | ||
| { label: "14", date: new Date(2025, 5, 14) }, | ||
| { label: "22", date: new Date(2025, 5, 22) }, | ||
| { label: "28", date: new Date(2025, 5, 28) }, | ||
| { label: "01", date: new Date(2025, 6, 1) }, // July Start Month transition | ||
| { label: "05", date: new Date(2025, 6, 5) }, | ||
| { label: "12", date: new Date(2025, 6, 12) }, | ||
| ]; | ||
|
|
||
| const TRACKS = [ | ||
| { id: "html", label: "HTML / CSS / JS", start: new Date(2025, 5, 1), end: new Date(2025, 5, 14), color: "#E0E7FF" }, // Light Indigo | ||
| { id: "product", label: "Product Pro", start: new Date(2025, 5, 1), end: new Date(2025, 5, 22), color: "#E0F2FE" }, // Light Sky Blue | ||
| { id: "flutter", label: "Flutter", start: new Date(2025, 5, 1), end: new Date(2025, 5, 28), color: "#DBEAFE" }, // Light Blue | ||
| { id: "uiux", label: "UI/UX", start: new Date(2025, 5, 8), end: new Date(2025, 5, 28), color: "#F3E8FF" }, // Light Purple | ||
| { id: "viscom", label: "Vis-Com", start: new Date(2025, 5, 14), end: new Date(2025, 5, 22), color: "#FAE8FF" }, // Light Fuchsia | ||
| { id: "reactjs", label: "React JS", start: new Date(2025, 5, 14), end: new Date(2025, 5, 28), color: "#ECFDF5" }, // Light Emerald | ||
| { id: "nodejs", label: "Node JS", start: new Date(2025, 5, 22), end: new Date(2025, 6, 5), color: "#FEF3C7" }, // Light Amber | ||
| { id: "django", label: "Django", start: new Date(2025, 5, 22), end: new Date(2025, 6, 12), color: "#FFEDD5" }, // Light Orange | ||
| ]; | ||
|
|
||
| const TOTAL_MS = TIMELINE_END - TIMELINE_START; | ||
|
|
||
| function pct(date) { | ||
| return ((date - TIMELINE_START) / TOTAL_MS) * 100; | ||
| } | ||
|
|
||
| function clamp(v, lo, hi) { | ||
| return Math.max(lo, Math.min(hi, v)); | ||
| } | ||
|
|
||
| export function TimelineCalendar() { | ||
| const today = new Date(); | ||
| const showLine = today >= TIMELINE_START && today <= TIMELINE_END; | ||
| const todayPct = showLine ? clamp(pct(today), 0, 100) : null; |
| left: var(--tl-padding); | ||
| right: var(--tl-padding); |
| .tl-month-marker { | ||
| position: absolute; | ||
| transform: translateX(0); | ||
| font-size: 0.7rem; | ||
| font-weight: 800; | ||
| letter-spacing: 0.13em; | ||
| text-transform: uppercase; | ||
| color: var(--color-primary); | ||
| font-family: var(--font-body); | ||
| top: 50%; | ||
| transform: translateY(-50%); | ||
| } | ||
|
|
||
| /* Date row */ | ||
| .tl-axis--dates { | ||
| padding: 0.5rem var(--tl-padding) 0.5rem; | ||
| border-bottom: 2px solid var(--line-strong); | ||
| background: rgba(48, 62, 210, 0.03); | ||
| } | ||
|
|
||
| .tl-date-marker { | ||
| position: absolute; | ||
| transform: translateX(-50%); | ||
| font-size: 0.82rem; | ||
| font-weight: 700; | ||
| color: var(--text-strong); | ||
| font-family: var(--font-display); | ||
| top: 50%; | ||
| transform: translateX(-50%) translateY(-50%); | ||
| } |
| <div | ||
| ref={(el) => (barRefs.current[track.id] = el)} | ||
| className={`tl-bar${isHovered ? " tl-bar--hovered" : ""}`} | ||
| style={{ | ||
| left: `${left}%`, | ||
| width: `${width}%`, | ||
| background: track.color, | ||
| border: `1px solid rgba(27, 39, 180, 0.15)`, | ||
| boxShadow: isHovered | ||
| ? `0 6px 16px rgba(27, 39, 180, 0.15)` | ||
| : `0 2px 6px rgba(27, 39, 180, 0.05)`, | ||
| }} | ||
| onMouseEnter={() => setHovered(track.id)} | ||
| onMouseLeave={() => setHovered(null)} | ||
| > | ||
| <span className="tl-bar-label"> | ||
| {track.label} | ||
| </span> | ||
| </div> |