feat: introduce core e-learning frontend pages and components for dashboard, profile, classroom, and layout.
This commit is contained in:
parent
3f93dc8ab5
commit
eb248f7ca2
12 changed files with 137 additions and 135 deletions
|
|
@ -41,22 +41,7 @@ const getLocalizedText = (text: any) => {
|
|||
>
|
||||
<div v-if="courseData" class="h-full scroll">
|
||||
<q-list class="pb-10">
|
||||
<!-- Announcements Sidebar Item -->
|
||||
<q-item
|
||||
clickable
|
||||
v-ripple
|
||||
@click="emit('open-announcements')"
|
||||
class="bg-blue-50 dark:bg-blue-900/10 border-b border-blue-100 dark:border-blue-900/20"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label class="font-bold text-slate-800 dark:text-blue-200 text-sm pl-2">
|
||||
{{ $t('classroom.announcements', 'ประกาศในคอร์ส') }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side v-if="hasUnreadAnnouncements">
|
||||
<q-badge color="red" rounded label="New" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
|
||||
<template v-for="chapter in courseData.chapters" :key="chapter.id">
|
||||
<q-item-label header class="bg-slate-100 dark:bg-slate-800 text-[var(--text-main)] font-bold sticky top-0 z-10 border-b dark:border-white/5 text-sm py-4">
|
||||
|
|
|
|||
|
|
@ -32,11 +32,14 @@ const searchText = ref('')
|
|||
/>
|
||||
|
||||
<!-- Branding -->
|
||||
<div class="flex items-center gap-2 cursor-pointer" @click="navigateTo('/dashboard')">
|
||||
<div class="w-8 h-8 rounded-lg bg-blue-600 flex items-center justify-center text-white font-bold">
|
||||
<div class="flex items-center gap-3 cursor-pointer group" @click="navigateTo('/dashboard')">
|
||||
<div class="w-10 h-10 rounded-xl bg-blue-600 flex items-center justify-center text-white font-black shadow-lg shadow-blue-600/30 group-hover:scale-110 transition-transform">
|
||||
E
|
||||
</div>
|
||||
<span class="font-bold text-xl text-blue-600 dark:text-blue-400 hidden xs:block">e-Learning</span>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-black text-lg leading-none tracking-tight text-slate-900 dark:text-white group-hover:text-blue-600 transition-colors">E-Learning</span>
|
||||
<span class="text-[10px] font-bold uppercase tracking-[0.2em] leading-none mt-1 text-slate-500 dark:text-slate-400">Platform</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-space />
|
||||
|
|
|
|||
|
|
@ -48,50 +48,94 @@ const handleNavigate = (path: string) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col h-full bg-transparent">
|
||||
<!-- Branding Area (Optional if not in Header) -->
|
||||
<div class="flex flex-col h-full bg-white dark:bg-[#1e293b] border-r border-slate-200 dark:border-slate-700">
|
||||
|
||||
<q-list padding class="text-slate-600 dark:text-slate-300 flex-grow">
|
||||
|
||||
|
||||
<!-- Branding / Logo Area -->
|
||||
<div class="px-6 py-8 flex items-center gap-3 cursor-pointer group" @click="handleNavigate('/dashboard')">
|
||||
<div class="w-10 h-10 rounded-xl bg-blue-600 flex items-center justify-center text-white font-black shadow-lg shadow-blue-600/30 group-hover:scale-110 transition-transform">
|
||||
E
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-black text-lg leading-none tracking-tight text-slate-900 dark:text-white">E-Learning</span>
|
||||
<span class="text-[10px] font-bold uppercase tracking-[0.2em] leading-none mt-1 text-slate-500">Platform</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Items -->
|
||||
<q-list padding class="text-slate-600 dark:text-slate-300 flex-grow px-3">
|
||||
<q-item
|
||||
v-for="item in navItems"
|
||||
:key="item.to"
|
||||
clickable
|
||||
v-ripple
|
||||
@click="handleNavigate(item.to)"
|
||||
class="rounded-r-full mr-2 text-slate-700 dark:text-slate-200 hover:bg-slate-100 dark:hover:bg-white/5"
|
||||
:class="{ 'q-router-link--active': $route.path === item.to || ($route.path === '/dashboard' && item.to === '/dashboard') }"
|
||||
class="rounded-xl mb-1 text-slate-700 dark:text-slate-200 hover:bg-slate-100 dark:hover:bg-white/5"
|
||||
:class="{ 'sidebar-item--active': $route.path === item.to || ($route.path === '/dashboard' && item.to === '/dashboard') }"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="item.icon" />
|
||||
<q-icon :name="item.icon" size="22px" />
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ item.label }}</q-item-label>
|
||||
<q-item-label class="font-bold text-sm">{{ item.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
|
||||
<!-- Footer / Version -->
|
||||
<div class="mt-auto p-4 text-xs text-center opacity-50 pb-8">
|
||||
<p>e-Learning v0.1.0</p>
|
||||
<p>© 2026</p>
|
||||
<!-- Sidebar Bottom: Logout & Version -->
|
||||
<div class="p-4 border-t border-slate-100 dark:border-slate-700/50">
|
||||
<q-btn
|
||||
flat
|
||||
rounded
|
||||
class="w-full text-slate-500 hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-900/10 transition-all font-bold"
|
||||
no-caps
|
||||
@click="() => useAuth().logout()"
|
||||
>
|
||||
<q-icon name="logout" size="20px" class="mr-3" />
|
||||
{{ t('auth.logout') }}
|
||||
</q-btn>
|
||||
|
||||
<div class="mt-4 px-4 text-center">
|
||||
<p class="text-[10px] font-black uppercase tracking-[0.2em] text-slate-400">Version 0.1.0 (Alpha)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* Light Mode Active State */
|
||||
.q-item.q-router-link--active {
|
||||
background: rgb(239 246 255); /* blue-50 */
|
||||
color: rgb(29 78 216); /* blue-700 */
|
||||
font-weight: 700;
|
||||
/* Active State styling for Sidebar items */
|
||||
.sidebar-item--active {
|
||||
background: rgb(239 246 255) !important; /* blue-50 */
|
||||
color: rgb(29 78 216) !important; /* blue-700 */
|
||||
}
|
||||
|
||||
.sidebar-item--active .q-icon {
|
||||
color: rgb(37 99 235) !important; /* blue-600 */
|
||||
}
|
||||
|
||||
/* Vertical indicator for active item */
|
||||
.sidebar-item--active::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -12px;
|
||||
top: 15%;
|
||||
height: 70%;
|
||||
width: 4px;
|
||||
background: #2563eb;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
/* Dark Mode Active State */
|
||||
.dark .q-item.q-router-link--active {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: rgb(147 197 253); /* blue-300 */
|
||||
.dark .sidebar-item--active {
|
||||
background: rgba(37, 99, 235, 0.15) !important;
|
||||
color: rgb(147 197 253) !important; /* blue-300 */
|
||||
}
|
||||
|
||||
.dark .sidebar-item--active .q-icon {
|
||||
color: rgb(96 165 250) !important; /* blue-400 */
|
||||
}
|
||||
|
||||
.dark .sidebar-item--active::after {
|
||||
background: #60a5fa;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue