209 lines
9.8 KiB
Vue
209 lines
9.8 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* @file home.vue
|
|
* @description Dashboard / Home Page.
|
|
* Displays the user's dashboard with a welcome message, current learning progress, and course recommendations.
|
|
*/
|
|
|
|
definePageMeta({
|
|
layout: 'default',
|
|
middleware: 'auth'
|
|
})
|
|
|
|
useHead({
|
|
title: 'Dashboard - e-Learning'
|
|
})
|
|
|
|
// Mock data: Recent Course Progress
|
|
const recentCourse = {
|
|
title: 'เบื้องต้นการออกแบบ UX/UI',
|
|
lesson: 'บทที่ 3: พื้นฐานการวาดโครงร่าง (Wireframing Basics)',
|
|
progress: 65,
|
|
image: 'https://images.unsplash.com/photo-1586717791821-3f44a563de4c?w=400&auto=format&fit=crop&q=60'
|
|
}
|
|
|
|
// Mock data: Recommended Courses
|
|
const recommendedCourses = [
|
|
{
|
|
title: 'Advanced React Patterns',
|
|
category: 'Development',
|
|
duration: '4h 30m',
|
|
image: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&auto=format&fit=crop&q=60',
|
|
badge: 'New',
|
|
badgeType: 'success'
|
|
},
|
|
{
|
|
title: 'Data Science Fundamentals',
|
|
category: 'Data Science',
|
|
duration: '12h 0m',
|
|
image: 'https://images.unsplash.com/photo-1551288049-bbda38a0617f?w=400&auto=format&fit=crop&q=60',
|
|
badge: 'Popular',
|
|
badgeType: 'warning'
|
|
}
|
|
]
|
|
</script>
|
|
|
|
<template>
|
|
<div class="dashboard-container">
|
|
<!-- Welcome Header Section -->
|
|
<div class="welcome-section mb-10 overflow-hidden relative rounded-[2.5rem] p-10 md:p-14 text-white shadow-lg dark:shadow-2xl dark:shadow-blue-900/20 transition-all">
|
|
<div class="relative z-10 flex flex-col md:flex-row justify-between items-center gap-8">
|
|
<div>
|
|
<h1 class="text-4xl md:text-5xl font-black mb-3 slide-up tracking-tight text-white dark:text-white">ยินดีต้อนรับกลับ, สมชาย!</h1>
|
|
<p class="text-lg slide-up font-medium text-blue-100" style="animation-delay: 0.1s;">วันนี้เป็นวันที่ดีสำหรับการเรียนรู้สิ่งใหม่ๆ มาเก็บความรู้เพิ่มกันเถอะ</p>
|
|
</div>
|
|
<div class="stats-mini flex gap-6 slide-up" style="animation-delay: 0.2s;"/>
|
|
</div>
|
|
<!-- Decorative Background elements -->
|
|
<div class="absolute inset-0 bg-gradient-to-br from-blue-500 via-blue-600 to-indigo-700 dark:from-blue-600 dark:via-blue-700 dark:to-indigo-900 -z-0"/>
|
|
<div class="absolute -top-20 -right-20 w-80 h-80 bg-white/10 blur-[100px] rounded-full"/>
|
|
<div class="absolute -bottom-20 -left-20 w-80 h-80 bg-blue-400/20 blur-[100px] rounded-full"/>
|
|
</div>
|
|
|
|
<!-- Main Content Area -->
|
|
<div class="lg:col-span-12">
|
|
<!-- Section: Continue Learning -->
|
|
<div class="flex items-center justify-between mb-8">
|
|
<h2 class="text-2xl font-black flex items-center gap-3 tracking-tight text-slate-900 dark:text-white">
|
|
<span class="w-1.5 h-8 bg-blue-500 rounded-full shadow-[0_0_15px_rgba(59,130,246,0.5)]"/>
|
|
เรียนต่อจากเดิม
|
|
</h2>
|
|
<NuxtLink to="/classroom/learning" class="text-sm font-black text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 transition-colors uppercase tracking-widest">เข้าสู่บทเรียนเต็มตัว →</NuxtLink>
|
|
</div>
|
|
|
|
<!-- Featured Current Course Card -->
|
|
<div class="p-0 overflow-hidden group mb-12 border border-slate-200 dark:border-white/5 rounded-3xl shadow-sm dark:shadow-2xl transition-all hover:-translate-y-1 dark:hover:-translate-y-1" style="background-color: var(--bg-surface);">
|
|
<div class="flex flex-col md:flex-row">
|
|
<!-- Course Image -->
|
|
<div class="md:w-2/5 aspect-video md:aspect-auto overflow-hidden relative rounded-t-3xl md:rounded-l-3xl md:rounded-tr-none">
|
|
<img :src="recentCourse.image" :alt="recentCourse.title" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700" >
|
|
<div class="absolute inset-0 bg-gradient-to-t from-slate-900/30 via-transparent to-transparent opacity-40 dark:opacity-60 dark:from-[#0f172a]"/>
|
|
</div>
|
|
<!-- Course Details & Progress -->
|
|
<div class="p-8 md:p-10 flex-1 flex flex-col justify-center" style="background-color: var(--bg-surface);">
|
|
<span class="text-[10px] font-black uppercase tracking-[0.2em] text-blue-700 dark:text-blue-400 mb-3">Currently Learning</span>
|
|
<h3 class="text-3xl font-black mb-2 leading-tight text-slate-900 dark:text-white group-hover:text-blue-700 dark:group-hover:text-blue-400 transition-colors">{{ recentCourse.title }}</h3>
|
|
<p class="text-slate-700 dark:text-slate-400 text-base mb-8 font-medium">{{ recentCourse.lesson }}</p>
|
|
|
|
<!-- Progress Bar -->
|
|
<div class="mt-auto bg-slate-100 dark:bg-slate-900/50 p-6 rounded-3xl border border-slate-200 dark:border-white/5">
|
|
<div class="flex justify-between items-center mb-3">
|
|
<span class="text-xs font-black text-slate-800 dark:text-slate-500 uppercase tracking-widest">Progress</span>
|
|
<span class="text-sm font-black text-blue-700 dark:text-blue-400">{{ recentCourse.progress }}%</span>
|
|
</div>
|
|
<div class="h-2.5 w-full bg-slate-300 dark:bg-slate-700 rounded-full overflow-hidden shadow-inner">
|
|
<div class="h-full bg-gradient-to-r from-blue-600 to-blue-500 rounded-full shadow-[0_0_10px_rgba(59,130,246,0.3)] transition-all duration-1000" :style="{ width: `${recentCourse.progress}%` }"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section: Recommended Courses -->
|
|
<div class="mb-8">
|
|
<h2 class="text-2xl font-black flex items-center gap-3 tracking-tight text-slate-900 dark:text-white">
|
|
<span class="w-1.5 h-8 bg-emerald-500 rounded-full shadow-[0_0_15px_rgba(16,185,129,0.5)]"/>
|
|
คอร์สเรียนแนะนำ
|
|
</h2>
|
|
</div>
|
|
|
|
<!-- Recommended Grid -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
<div v-for="(course, idx) in recommendedCourses" :key="idx" class="p-0 overflow-hidden group border border-slate-200 dark:border-white/5 rounded-3xl shadow-sm dark:shadow-xl transition-all hover:-translate-y-1 dark:hover:-translate-y-1" style="background-color: var(--bg-surface);">
|
|
<div class="h-48 overflow-hidden relative rounded-t-3xl">
|
|
<img :src="course.image" :alt="course.title" class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700" >
|
|
<span v-if="course.badge" :class="`absolute top-5 left-5 status-pill status-${course.badgeType} shadow-lg font-black text-[9px]`">{{ course.badge }}</span>
|
|
<div class="absolute inset-x-0 bottom-0 h-1/2 bg-gradient-to-t from-slate-900/20 dark:from-[#1e293b] to-transparent"/>
|
|
</div>
|
|
<div class="p-7" style="background-color: var(--bg-surface);">
|
|
<div class="text-[10px] font-black text-slate-700 dark:text-slate-500 uppercase tracking-[0.2em] mb-2">{{ course.category }}</div>
|
|
<h4 class="font-black text-xl mb-6 text-slate-900 dark:text-white group-hover:text-blue-700 dark:group-hover:text-blue-400 transition-colors">{{ course.title }}</h4>
|
|
<div class="flex items-center justify-between">
|
|
<span class="text-xs font-bold text-slate-700 dark:text-slate-400 flex items-center gap-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-slate-600 dark:text-slate-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
|
{{ course.duration }}
|
|
</span>
|
|
<button class="text-[11px] font-black text-blue-700 dark:text-blue-500 uppercase tracking-widest hover:text-blue-800 dark:hover:text-blue-400 transition-colors">ดูรายละเอียด</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.dashboard-container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.card-premium {
|
|
background: #ffffff;
|
|
border-radius: 2.5rem;
|
|
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.card-premium:hover {
|
|
transform: translateY(-6px);
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
:global(.dark) .card-premium {
|
|
background: #1e293b;
|
|
box-shadow: 0 20px 50px -12px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
:global(.dark) .card-premium:hover {
|
|
box-shadow: 0 30px 60px -12px rgba(0, 0, 0, 0.6);
|
|
}
|
|
|
|
:global(.app-main) {
|
|
background-color: #ffffff;
|
|
color: #1e293b;
|
|
transition: background-color 0.2s, color 0.2s;
|
|
}
|
|
|
|
:global(.dark) :global(.app-main) {
|
|
background-color: #0f172a;
|
|
color: #f1f5f9;
|
|
}
|
|
|
|
.glass-bright {
|
|
background: rgba(255, 255, 255, 0.08);
|
|
backdrop-filter: blur(20px);
|
|
}
|
|
|
|
@keyframes slide-up {
|
|
from { opacity: 0; transform: translateY(30px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.slide-up {
|
|
animation: slide-up 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
.status-pill {
|
|
@apply px-4 py-1.5 rounded-full font-black uppercase tracking-widest border;
|
|
}
|
|
.status-success {
|
|
@apply bg-emerald-500/10 text-emerald-400 border-emerald-500/30;
|
|
}
|
|
.status-warning {
|
|
@apply bg-amber-500/10 text-amber-400 border-amber-500/30;
|
|
}
|
|
|
|
:global(.app-main) {
|
|
background-color: #ffffff;
|
|
color: #1e293b;
|
|
min-height: 100vh;
|
|
transition: background-color 0.2s, color 0.2s;
|
|
}
|
|
|
|
:global(.dark) :global(.app-main) {
|
|
background-color: #0f172a;
|
|
color: #f1f5f9;
|
|
}
|
|
</style>
|