Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/lib/components/BadgeDisplay.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@
<!-- Badge display area -->
{#if displayBadges.length === 0}
<div class="flex flex-col items-center justify-center text-center">
<div class="mb-2 h-32 opacity-40">
<div class="mb-2 h-28 opacity-40">
<img src="/badges/locked-badge.png" alt="No badges yet" class="h-full w-full" />
</div>
<h3 class="h4 mb-2">No Badges Yet</h3>
<p class="text-sm">Complete modules to start collecting badges!</p>
</div>
{:else}
<!-- Badge grid -->
<div class="mb-4 grid grid-cols-2 gap-4 md:grid-cols-3 pb-2 lg:grid-cols-5">
<div class="mb-4 grid grid-cols-2 gap-4 pb-2 md:grid-cols-3 lg:grid-cols-5">
{#each displayBadges as badge, i (badge.id)}
<div
class="flex flex-col items-center text-center"
Expand All @@ -48,7 +48,7 @@
easing: quintOut
}}
>
<div class="avatar badge-container mb-2 h-32 p-1">
<div class="avatar badge-container mb-2 h-28 p-1">
<img src={badge.image} alt={badge.title} class="h-full w-full object-cover" />
</div>
<h3 class="line-clamp-1 text-sm font-bold">{badge.title}</h3>
Expand Down
152 changes: 101 additions & 51 deletions src/lib/components/ModuleSidebar.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<script lang="ts">
import {
type subjects,
type modules as modulesType,
type lessons,
type studentProgress
import type {
subjects,
modules as modulesType,
lessons,
studentProgress
} from '$lib/server/db/schema';
import { onMount } from 'svelte';

// Props
let {
Expand All @@ -25,11 +26,21 @@

// Track expanded state for each module
let expandedModules = $state<Record<number, boolean>>({});
let previousModuleId = $state<number | null>(null);

// Initialize expanded state for current module
// Update expanded modules when currentModuleId changes
$effect(() => {
if (currentModuleId && !expandedModules[currentModuleId]) {
if (currentModuleId && currentModuleId !== previousModuleId) {
// Close previous module if different from current
if (previousModuleId && previousModuleId !== currentModuleId) {
expandedModules[previousModuleId] = false;
}

// Open current module
expandedModules[currentModuleId] = true;

// Update previous module reference
previousModuleId = currentModuleId;
}
});

Expand All @@ -41,37 +52,46 @@
// Get lessons for a specific module
function getLessonsForModule(moduleId: number) {
return allLessons
.filter((lesson: { moduleId: number; }) => lesson.moduleId === moduleId)
.sort((a: { orderInModule: any; }, b: { orderInModule: any; }) => (a?.orderInModule || 0) - (b?.orderInModule || 0));
.filter((lesson: { moduleId: number }) => lesson.moduleId === moduleId)
.sort(
(a: { orderInModule: any }, b: { orderInModule: any }) =>
(a?.orderInModule || 0) - (b?.orderInModule || 0)
);
}

// Check if a lesson is completed
function isLessonCompleted(lessonId: number) {
// Explicitly check if progress entry exists AND its completedAt is not null
return progress[lessonId] != null && progress[lessonId].completedAt !== null;
}
</script>

<div class="w-64 h-full rounded-lg bg-surface-100 dark:bg-surface-800 flex flex-col">
<div class="p-2 flex flex-col h-full">
<h2 class="mb-4 text-center text-lg font-semibold flex-shrink-0">Lessons</h2>
<div class="flex h-full w-64 flex-col rounded-lg bg-surface-50 shadow-md dark:bg-surface-800">
<div class="flex h-full flex-col p-3">
<header class="mb-3 border-b border-surface-200 pb-3 dark:border-surface-700">
<h2 class="text-center text-lg font-semibold">{subject?.name || 'Lessons'}</h2>
</header>

<!-- Module list -->
<div class="overflow-y-auto flex-1">
<ul class="space-y-2">
<div class="flex-1 overflow-y-auto pr-1">
<ul class="space-y-3">
{#each modules as module (module.id)}
<li class="rounded-lg bg-surface-200 dark:bg-surface-700">
{@const isActive = module.id === currentModuleId}

<li
class="overflow-hidden rounded-lg bg-surface-100 shadow-sm dark:bg-surface-700
{isActive ? 'ring-1 ring-tertiary-500' : ''}"
>
<!-- Module header -->
<button
class="flex w-full cursor-pointer items-center justify-between rounded-md p-2 text-left
{module.id === currentModuleId
? 'bg-secondary-400 dark:bg-secondary-500'
: 'bg-tertiary-500 dark:bg-tertiary-700'}"
class="flex w-full cursor-pointer items-center justify-between p-3 text-left
{isActive
? 'bg-tertiary-500 text-white dark:bg-tertiary-700'
: 'hover:bg-tertiary-200 dark:hover:bg-tertiary-800'}"
onclick={() => toggleModule(module.id)}
aria-expanded={expandedModules[module.id]}
>
<span class="font-semibold">{module.name || 'Module'}</span>
<div class="flex items-center">
<span class="truncate font-medium">{module.name || 'Module'}</span>
<div class="ml-1 flex-shrink-0">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
Expand All @@ -82,8 +102,12 @@
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="transition-transform duration-300"
style="transform: {expandedModules[module.id]
? 'rotate(180deg)'
: 'rotate(0deg)'}"
>
<path d={expandedModules[module.id] ? 'M18 15l-6-6-6 6' : 'M6 9l6 6 6-6'} />
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</div>
</button>
Expand All @@ -98,49 +122,75 @@
{@const isCompleted = isLessonCompleted(lesson.id)}
{@const isCurrent = lesson.id === currentLessonId}

<li
class="cursor-pointer rounded p-2 {isCurrent
? 'bg-tertiary-300 dark:bg-tertiary-900'
: isCompleted
? 'bg-green-100 hover:bg-green-200 dark:bg-green-900 dark:hover:bg-green-800'
: 'hover:bg-tertiary-100 dark:hover:bg-tertiary-800'}"
>
<li>
<a
href={`/lessons/subject/${subject?.id || ''}/module/${module.id || ''}/lesson/${lesson.id || ''}`}
class="flex w-full items-center justify-between text-left"
class="flex items-center rounded-md p-2 text-left transition-colors
{isCurrent
? 'bg-tertiary-200 font-medium dark:bg-tertiary-900'
: isCompleted
? 'hover:bg-surface-200 dark:hover:bg-surface-600'
: 'hover:bg-surface-200 dark:hover:bg-surface-600'}"
>
<span class="truncate pr-2">{lesson.title || 'Lesson'}</span>
{#if isCompleted}
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="flex-shrink-0"
>
<path d="M20 6L9 17l-5-5" />
</svg>
{/if}
<div class="mr-2 flex-shrink-0">
{#if isCompleted}
<div
class="flex h-5 w-5 items-center justify-center rounded-full bg-success-600 dark:bg-success-700"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"
viewBox="0 0 24 24"
fill="none"
stroke="white"
stroke-width="3"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</div>
{:else}
<div
class="h-5 w-5 rounded-full border-2 border-surface-300 dark:border-surface-500
{isCurrent ? 'border-tertiary-500 dark:border-tertiary-400' : ''}"
></div>
{/if}
</div>
<span class="truncate text-sm">{lesson.title || 'Lesson'}</span>
</a>
</li>
{/each}
</ul>
{:else}
<div class="p-2 text-center text-sm italic text-gray-500">No lessons available</div>
<div class="p-3 text-center text-sm italic text-gray-500">No lessons available</div>
{/if}
{/if}
</li>
{/each}
</ul>

{#if modules.length === 0}
<div class="mt-4 text-center text-gray-500">No modules available</div>
<div class="p-4 text-center text-gray-500">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="mx-auto mb-2 text-gray-400"
>
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
<polyline points="13 2 13 9 20 9"></polyline>
</svg>
<p>No modules available</p>
</div>
{/if}
</div>
</div>
</div>
</div>
2 changes: 1 addition & 1 deletion src/routes/learn-more/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
/>
</svg>
</div>
<h3 class="mb-2 text-xl font-bold">Four Core Modules</h3>
<h3 class="mb-2 text-xl font-bold">Four Core Subjects</h3>
<p class="text-gray-300">
Stack your pancakes with HTML, CSS, JavaScript, and Backend Development modules
</p>
Expand Down