Skip to content

Commit 97afd3a

Browse files
Lesson Page UI (#31)
* Lesson Page mock ui * made some small changes * added some ui text * added attachments section --------- Co-authored-by: Joshua Silva <72359611+joshuasilva414@users.noreply.github.com>
1 parent f5587a5 commit 97afd3a

File tree

11 files changed

+1036
-48
lines changed

11 files changed

+1036
-48
lines changed

components.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"tailwind": {
77
"config": "",
88
"css": "src/app/globals.css",
9-
"baseColor": "zinc",
9+
"baseColor": "neutral",
1010
"cssVariables": true,
1111
"prefix": ""
1212
},

package.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,28 @@
1919
],
2020
"dependencies": {
2121
"@libsql/client": "^0.15.15",
22-
"@radix-ui/react-alert-dialog": "^1.1.15",
23-
"@radix-ui/react-avatar": "^1.1.10",
24-
"@radix-ui/react-dropdown-menu": "^2.1.16",
22+
"@radix-ui/react-aspect-ratio": "^1.1.7",
2523
"@radix-ui/react-checkbox": "^1.3.3",
26-
"@radix-ui/react-label": "^2.1.8",
27-
"@radix-ui/react-navigation-menu": "^1.2.14",
24+
"@radix-ui/react-dropdown-menu": "^2.1.16",
2825
"@radix-ui/react-progress": "^1.1.7",
26+
"@radix-ui/react-scroll-area": "^1.2.10",
27+
"@radix-ui/react-separator": "^1.1.7",
2928
"@radix-ui/react-slot": "^1.2.3",
29+
"@radix-ui/react-tabs": "^1.1.13",
3030
"better-auth": "^1.3.26",
3131
"class-variance-authority": "^0.7.1",
3232
"clsx": "^2.1.1",
3333
"drizzle-orm": "^0.44.6",
3434
"lucide-react": "^0.552.0",
3535
"next": "15.5.4",
3636
"next-safe-action": "8.0.11",
37-
"next-themes": "^0.4.6",
3837
"react": "19.1.0",
3938
"react-dom": "19.1.0",
4039
"react-hook-form": "^7.63.0",
41-
"sonner": "^2.0.7",
4240
"tailwind-merge": "^3.3.1",
41+
"web": "link:@libsql/client/web",
42+
"next-themes": "^0.4.6",
43+
"sonner": "^2.0.7",
4344
"zod": "^4.1.11"
4445
},
4546
"devDependencies": {
@@ -49,10 +50,12 @@
4950
"@types/node": "^20",
5051
"@types/react": "^19",
5152
"@types/react-dom": "^19",
53+
"autoprefixer": "^10.4.21",
5254
"dotenv": "^17.2.3",
5355
"drizzle-kit": "^0.31.5",
5456
"eslint": "^9",
5557
"eslint-config-next": "15.5.4",
58+
"postcss": "^8.5.6",
5659
"tailwindcss": "^4",
5760
"tsx": "^4.20.6",
5861
"tw-animate-css": "^1.4.0",

pnpm-lock.yaml

Lines changed: 535 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 246 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,246 @@
1-
export default async function Page({
2-
params,
3-
}: {
4-
params: Promise<{ courseId: string; lessonId: string }>;
5-
}) {
6-
const { courseId, lessonId } = await params;
7-
return <div>Managing lesson: {lessonId} for course {courseId}</div>;
8-
}
1+
"use client";
2+
import React from "react";
3+
import { Button } from "@/components/ui/button";
4+
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
5+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
6+
import { Badge } from "@/components/ui/badge";
7+
import { Progress } from "@/components/ui/progress";
8+
import { Input } from "@/components/ui/input";
9+
import { Textarea } from "@/components/ui/textarea";
10+
import { ScrollArea } from "@/components/ui/scroll-area";
11+
import { AspectRatio } from "@/components/ui/aspect-ratio";
12+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
13+
import { Play, Captions, Download, FileText, CheckCircle2, ChevronDown, ExternalLink, Paperclip, BookOpen, NotebookPen, ChevronLeft, ChevronRight } from "lucide-react";
14+
15+
/**
16+
* Framework-only lesson page using dummy data.
17+
* Drop this into a Next.js route like app/courses/[courseId]/[lessonId]/page.tsx and wire to real data later.
18+
*/
19+
export default function LessonPage() {
20+
// --- Dummy data until DB is wired ---
21+
const course = {
22+
id: "course-ux101",
23+
title: "Intro to Web Development",
24+
unitTitle: "Unit 1: Fundamentals",
25+
progress: 45,
26+
};
27+
28+
const lesson = {
29+
id: "lesson-10",
30+
number: 10,
31+
title: "Next.js Application fundamentals",
32+
duration: "14:36",
33+
summary:
34+
"Learn how to build a simple application with nextjs, from setting up the project to deploying it.",
35+
attachments: [
36+
{ id: "a1", name: "Slides", size: "2.3 MB" },
37+
{ id: "a2", name: "Lab ", size: "140 KB" },
38+
{ id: "a3", name: "Worksheet ", size: "410 KB" },
39+
],
40+
resources: [
41+
{ id: "r1", label: "Next js Tutorial", href: "#" },
42+
{ id: "r2", label: "Tailwindcss docs", href: "#" },
43+
],
44+
};
45+
46+
const unitLessons = [
47+
{ id: "l1", title: "What is a NextJs?", duration: "08:24", status: "done" },
48+
{ id: "l2", title: "Part 2", duration: "12:10", status: "done" },
49+
{ id: "l3", title: "Part 3", duration: "09:03", status: "done" },
50+
{ id: "l4", title: "Part 4", duration: "14:36", status: "current" },
51+
{ id: "l5", title: "Part 5", duration: "16:50", status: "locked" },
52+
];
53+
54+
return (
55+
<div className="min-h-screen bg-background text-foreground">
56+
{/* Page container without navbar/footer; those will be injected elsewhere */}
57+
<div className="mx-auto grid w-full max-w-7xl grid-cols-1 gap-6 p-4 md:grid-cols-[1fr_320px] md:p-8">
58+
{/* LEFT: Main content */}
59+
<div className="space-y-6">
60+
{/* Lesson header */}
61+
<div className="flex items-start justify-between gap-4">
62+
<div>
63+
<h1 className="text-2xl font-semibold tracking-tight sm:text-3xl">Lesson {lesson.number}: {lesson.title}</h1>
64+
<p className="mt-1 text-sm text-muted-foreground">{course.title}{course.unitTitle}{lesson.duration}</p>
65+
</div>
66+
<div className="flex items-center gap-2">
67+
<Badge variant="secondary">Draft UI</Badge>
68+
<DropdownMenu>
69+
<DropdownMenuTrigger asChild>
70+
<Button variant="outline" size="sm" className="gap-2">
71+
Actions <ChevronDown className="h-4 w-4" />
72+
</Button>
73+
</DropdownMenuTrigger>
74+
<DropdownMenuContent align="end">
75+
<DropdownMenuItem>Mark complete</DropdownMenuItem>
76+
<DropdownMenuItem>Report issue</DropdownMenuItem>
77+
<DropdownMenuItem>Bookmark</DropdownMenuItem>
78+
</DropdownMenuContent>
79+
</DropdownMenu>
80+
</div>
81+
</div>
82+
83+
{/* Media / Viewer */}
84+
<Card className="overflow-hidden">
85+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-0">
86+
<div className="space-y-1">
87+
<CardTitle className="text-xl">Lesson Viewer</CardTitle>
88+
<CardDescription>{lesson.summary}</CardDescription>
89+
</div>
90+
<div className="flex items-center gap-2">
91+
<Button size="sm" variant="secondary" className="gap-2"><Play className="h-4 w-4"/>Play</Button>
92+
<Button size="sm" variant="outline" className="gap-2"><ExternalLink className="h-4 w-4"/>Open in new tab</Button>
93+
</div>
94+
</CardHeader>
95+
<CardContent className="pt-4">
96+
{/* Video/Player placeholder */}
97+
<AspectRatio ratio={16/9} className="w-full overflow-hidden rounded-xl bg-muted/60 ring-1 ring-border">
98+
<div className="flex h-full w-full items-center justify-center">
99+
<div className="flex flex-col items-center">
100+
<div className="mb-3 inline-flex h-12 w-12 items-center justify-center rounded-full bg-primary/15">
101+
<Play className="h-6 w-6" />
102+
</div>
103+
<p className="text-sm text-muted-foreground">Video placeholder (wire to player later)</p>
104+
</div>
105+
</div>
106+
</AspectRatio>
107+
</CardContent>
108+
</Card>
109+
110+
<Tabs defaultValue="transcript" className="w-full">
111+
<TabsList className="grid w-full grid-cols-4">
112+
<TabsTrigger value="transcript" className="gap-2"><Captions className="h-4 w-4"/>Transcript</TabsTrigger>
113+
<TabsTrigger value="attachments" className="gap-2"><Paperclip className="h-4 w-4"/>Attachments</TabsTrigger>
114+
<TabsTrigger value="notes" className="gap-2"><NotebookPen className="h-4 w-4"/>Notes</TabsTrigger>
115+
<TabsTrigger value="resources" className="gap-2"><BookOpen className="h-4 w-4"/>Resources</TabsTrigger>
116+
</TabsList>
117+
118+
<TabsContent value="transcript" className="mt-4">
119+
<Card>
120+
<CardHeader>
121+
<CardTitle className="text-base">Lesson Transcript</CardTitle>
122+
</CardHeader>
123+
<CardContent>
124+
<p className="mb-2 text-sm leading-relaxed">
125+
Welcome to this lesson on React components. In this video, we will explore the fundamentals of building user interfaces using React. React is a popular JavaScript library for building interactive and dynamic web applications...
126+
</p>
127+
</CardContent>
128+
</Card>
129+
</TabsContent >
130+
{/* Attachments */}
131+
<TabsContent value="attachments" className="mt-4">
132+
<Card>
133+
<CardHeader>
134+
<CardTitle className="text-base">Lesson files</CardTitle>
135+
<CardDescription>Download reference materials for this lesson.</CardDescription>
136+
</CardHeader>
137+
<CardContent>
138+
<ul className="divide-y">
139+
{lesson.attachments.map((f) => (
140+
<li key={f.id} className="flex items-center justify-between py-3">
141+
<div className="flex items-center gap-3">
142+
<FileText className="h-5 w-5" />
143+
<div>
144+
<p className="text-sm font-medium leading-none">{f.name}</p>
145+
<p className="text-xs text-muted-foreground">{f.size}</p>
146+
</div>
147+
</div>
148+
<Button variant="outline" size="sm" className="gap-2" aria-disabled>
149+
<Download className="h-4 w-4"/> Download
150+
</Button>
151+
</li>
152+
))}
153+
</ul>
154+
</CardContent>
155+
</Card>
156+
</TabsContent>
157+
158+
<TabsContent value="notes" className="mt-4">
159+
<Card>
160+
<CardHeader>
161+
<CardTitle className="text-base">Attach notes</CardTitle>
162+
<CardDescription>Your notes are private. Autosave coming later.</CardDescription>
163+
</CardHeader>
164+
<CardContent className="space-y-3">
165+
<Input placeholder="Title (optional)" />
166+
<Textarea placeholder="Type your lesson notes here..." className="min-h-[160px] resize-y" />
167+
<div className="flex justify-end gap-2">
168+
<Button variant="outline">Clear</Button>
169+
<Button>Save draft</Button>
170+
</div>
171+
</CardContent>
172+
</Card>
173+
</TabsContent>
174+
<TabsContent value="resources" className="mt-4">
175+
<Card>
176+
<CardHeader>
177+
<CardTitle className="text-base">Extra resources</CardTitle>
178+
<CardDescription>Helpful links and references for deeper learning.</CardDescription>
179+
</CardHeader>
180+
<CardContent className="space-y-3">
181+
{lesson.resources.map((r) => (
182+
<a key={r.id} href={r.href} className="flex items-center justify-between rounded-md border p-3 transition hover:bg-muted/70">
183+
<span className="text-sm">{r.label}</span>
184+
<ExternalLink className="h-4 w-4" />
185+
</a>
186+
))}
187+
</CardContent>
188+
</Card>
189+
</TabsContent>
190+
</Tabs>
191+
192+
{/* Workspace mock (optional area from sketch) */}
193+
194+
195+
{/* Prev/Next navigation */}
196+
<div className="flex items-center justify-between">
197+
<Button variant="ghost" className="gap-2"><ChevronLeft className="h-4 w-4"/> Previous</Button>
198+
<Button className="gap-2">Next lesson <ChevronRight className="h-4 w-4"/></Button>
199+
</div>
200+
</div>
201+
202+
{/* RIGHT: Sidebar */}
203+
<aside className="space-y-4">
204+
<Card>
205+
<CardHeader className="pb-3">
206+
<div className="flex items-center justify-between">
207+
<CardTitle className="text-base">{course.unitTitle}</CardTitle>
208+
<Badge variant="secondary">{course.progress}%</Badge>
209+
</div>
210+
<CardDescription>Progress through the unit.</CardDescription>
211+
</CardHeader>
212+
<CardContent>
213+
<Progress value={course.progress} />
214+
</CardContent>
215+
</Card>
216+
217+
<Card>
218+
<CardHeader className="pb-2">
219+
<CardTitle className="text-base">Lessons</CardTitle>
220+
<CardDescription>Current lesson is highlighted.</CardDescription>
221+
</CardHeader>
222+
<CardContent className="p-0">
223+
<ScrollArea className="h-[420px]">
224+
<ul className="divide-y">
225+
{unitLessons.map((l) => (
226+
<li key={l.id} className={`flex items-center justify-between px-4 py-3 ${l.status === "current" ? "bg-muted/60" : ""}`}>
227+
<div className="min-w-0">
228+
<p className="truncate text-sm font-medium">{l.title}</p>
229+
<p className="text-xs text-muted-foreground">{l.duration}</p>
230+
</div>
231+
{l.status === "done" && <CheckCircle2 className="h-5 w-5 text-emerald-500" />}
232+
{l.status === "current" && <Badge>Now</Badge>}
233+
{l.status === "locked" && <Badge variant="secondary">Locked</Badge>}
234+
</li>
235+
))}
236+
</ul>
237+
</ScrollArea>
238+
</CardContent>
239+
</Card>
240+
241+
242+
</aside>
243+
</div>
244+
</div>
245+
);
246+
}

0 commit comments

Comments
 (0)