feat: Add initial pages and components for user dashboard, profile, course discovery, and classroom learning with i18n support.
All checks were successful
Build and Deploy Frontend Learner / Build Frontend Learner Docker Image (push) Successful in 47s
Build and Deploy Frontend Learner / Deploy E-learning Frontend Learner to Dev Server (push) Successful in 4s
Build and Deploy Frontend Learner / Notify Deployment Status (push) Successful in 1s

This commit is contained in:
supalerk-ar66 2026-02-20 14:58:18 +07:00
parent f26a94076c
commit e3873f616e
11 changed files with 1046 additions and 685 deletions

View file

@ -90,6 +90,7 @@ const isPlaying = ref(false)
const videoProgress = ref(0)
const currentTime = ref(0)
const duration = ref(0)
const activeTab = ref('content')
@ -604,60 +605,67 @@ onBeforeUnmount(() => {
</script>
<template>
<q-layout view="hHh LpR lFf" class="bg-[var(--bg-body)] text-[var(--text-main)]">
<q-layout view="hHh lpR lFf" class="bg-[var(--bg-body)] text-[var(--text-main)]">
<!-- Header -->
<q-header bordered class="bg-[var(--bg-surface)] border-b border-gray-200 dark:border-white/5 text-[var(--text-main)] h-14">
<q-toolbar>
<!-- Exit/Back Button -->
<q-btn
flat
rounded
no-caps
color="primary"
class="mr-4 bg-slate-100 dark:bg-slate-800 text-slate-900 dark:text-white font-bold hover:bg-slate-200"
@click="handleExit('/dashboard/my-courses')"
>
<q-icon name="close" size="18px" class="mr-1.5" />
<span class="hidden sm:inline">{{ $t('common.close') }}</span>
<q-tooltip>{{ $t('classroom.backToDashboard') }}</q-tooltip>
</q-btn>
<q-header bordered class="bg-[var(--bg-surface)] border-b border-gray-200 dark:border-white/5 text-[var(--text-main)] h-16">
<q-toolbar class="h-full px-4">
<!-- 1. Left Side: Back & Title -->
<div class="flex items-center gap-4 flex-grow overflow-hidden">
<!-- Back Button -->
<q-btn
flat
round
dense
color="primary"
class="bg-slate-100 dark:bg-slate-800 text-slate-900 dark:text-white hover:bg-slate-200 dark:hover:bg-slate-700 transition-colors"
@click="handleExit('/dashboard/my-courses')"
>
<q-icon name="arrow_back" size="20px" />
<q-tooltip>{{ $t('classroom.backToDashboard') }}</q-tooltip>
</q-btn>
<!-- Course Title -->
<div class="flex flex-col">
<!-- Sidebar Toggle (Clearer for Course Content) -->
<q-btn
flat
rounded
no-caps
class="mr-2 text-slate-900 dark:text-white hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors font-bold px-3"
@click="toggleSidebar"
>
<q-icon name="format_list_bulleted" size="18px" class="mr-1.5" />
<span class="hidden md:inline">{{ $t('classroom.curriculum') }}</span>
</q-btn>
<q-toolbar-title class="text-base font-bold text-left truncate text-slate-900 dark:text-white">
{{ courseData ? getLocalizedText(courseData.course.title) : $t('classroom.loadingTitle') }}
</q-toolbar-title>
<h1 class="text-base md:text-lg font-bold text-slate-900 dark:text-white truncate max-w-[200px] md:max-w-md leading-tight">
{{ courseData ? getLocalizedText(courseData.course.title) : $t('classroom.loadingTitle') }}
</h1>
</div>
</div>
<div class="flex items-center gap-2 pr-2">
<!-- Announcements Button -->
<!-- 2. Right Side: Actions -->
<div class="flex items-center gap-3">
<!-- Sidebar Toggle (Right Side) -->
<q-btn
flat
round
dense
class="text-slate-500 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
@click="toggleSidebar"
>
<q-icon name="menu_open" size="24px" class="transform rotate-180" />
<q-tooltip>{{ $t('classroom.curriculum') }}</q-tooltip>
</q-btn>
<!-- Announcements Button (Refined) -->
<q-btn
flat
round
dense
icon="campaign"
class="bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 hover:text-blue-600 dark:hover:text-blue-400 hover:bg-blue-50 dark:hover:bg-slate-700 transition-all relative overflow-visible"
@click="handleOpenAnnouncements"
class="text-slate-600 dark:text-slate-300 hover:text-blue-600 transition-colors"
>
<q-badge v-if="hasUnreadAnnouncements" color="red" floating rounded />
<q-icon name="campaign" size="22px" />
<!-- Red Dot Notification -->
<span v-if="hasUnreadAnnouncements" class="absolute top-2 right-2 w-2.5 h-2.5 bg-rose-500 border-2 border-white dark:border-slate-900 rounded-full"></span>
<q-tooltip>{{ $t('classroom.announcements') }}</q-tooltip>
</q-btn>
</div>
</q-toolbar>
</q-header>
<!-- Sidebar (Curriculum) -->
<!-- Sidebar (Curriculum) -->
<!-- Sidebar (Curriculum) - Positioned Right via component prop -->
<CurriculumSidebar
v-model="sidebarOpen"
:courseData="courseData"
@ -672,7 +680,7 @@ onBeforeUnmount(() => {
<q-page-container class="bg-white dark:bg-slate-900">
<q-page class="flex flex-col h-full bg-slate-50 dark:bg-[#0B0F1A]">
<!-- Video Player & Content Area -->
<div class="w-full max-w-7xl mx-auto p-4 md:p-6 flex-grow">
<div class="w-full h-full p-4 md:p-6 flex-grow overflow-y-auto">
<!-- 1. LOADING STATE (Comprehensive Skeleton) -->
<div v-if="isLessonLoading" class="animate-fade-in">
<!-- Video Skeleton -->