feat: Implement core user profile, dashboard, course browsing pages, common components, and internationalization.
This commit is contained in:
parent
01978f9438
commit
11d714c632
10 changed files with 289 additions and 99 deletions
|
|
@ -9,33 +9,35 @@ const route = useRoute();
|
|||
const { isAuthenticated } = useAuth(); // Optional if you need auth state
|
||||
const isSidebarOpen = defineModel<boolean>("open"); // Controlled by layout
|
||||
|
||||
const navItems = [
|
||||
const { t } = useI18n()
|
||||
|
||||
const navItems = computed(() => [
|
||||
{
|
||||
to: "/dashboard",
|
||||
label: "ภาพรวม",
|
||||
label: t('sidebar.overview'),
|
||||
icon: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z",
|
||||
},
|
||||
{
|
||||
to: "/dashboard/my-courses",
|
||||
label: "คอร์สของฉัน",
|
||||
label: t('sidebar.myCourses'),
|
||||
icon: "M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253",
|
||||
},
|
||||
{
|
||||
to: "/browse/discovery",
|
||||
label: "ค้นหาคอร์ส",
|
||||
label: t('sidebar.browseCourses'),
|
||||
icon: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z",
|
||||
},
|
||||
{
|
||||
to: "/dashboard/announcements",
|
||||
label: "ข่าวประกาศ",
|
||||
label: t('sidebar.announcements'),
|
||||
icon: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9",
|
||||
},
|
||||
{
|
||||
to: "/dashboard/profile",
|
||||
label: "บัญชีผู้ใช้",
|
||||
label: t('sidebar.profile'),
|
||||
icon: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z",
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
const isActive = (path: string) => {
|
||||
if (path === "/dashboard") return route.path === "/dashboard";
|
||||
|
|
|
|||
|
|
@ -47,13 +47,13 @@ onMounted(() => {
|
|||
<ul class="flex items-center gap-8 text-sm font-bold">
|
||||
<li>
|
||||
<NuxtLink to="/browse" class="text-slate-400 hover:text-white transition-colors relative group">
|
||||
คอร์สทั้งหมด
|
||||
{{ $t('landing.allCourses') }}
|
||||
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-blue-600 transition-all group-hover:w-full"/>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li>
|
||||
<NuxtLink to="/browse/discovery" class="text-slate-400 hover:text-white transition-colors relative group">
|
||||
ค้นพบ
|
||||
{{ $t('landing.discovery') }}
|
||||
<span class="absolute -bottom-1 left-0 w-0 h-0.5 bg-blue-600 transition-all group-hover:w-full"/>
|
||||
</NuxtLink>
|
||||
</li>
|
||||
|
|
@ -66,14 +66,14 @@ onMounted(() => {
|
|||
-->
|
||||
<div class="flex items-center gap-4">
|
||||
<template v-if="!isAuthenticated">
|
||||
<NuxtLink to="/auth/login" class="text-sm font-bold text-slate-300 hover:text-white px-4 py-2 transition-colors">เข้าสู่ระบบ</NuxtLink>
|
||||
<NuxtLink to="/auth/login" class="text-sm font-bold text-slate-300 hover:text-white px-4 py-2 transition-colors">{{ $t('auth.login') }}</NuxtLink>
|
||||
<NuxtLink to="/auth/register" class="btn-primary-premium shadow-lg shadow-blue-600/20">
|
||||
เริ่มต้นใช้งาน
|
||||
{{ $t('auth.getStarted') }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
<template v-else>
|
||||
<NuxtLink to="/dashboard" class="btn-primary-premium shadow-lg shadow-blue-600/20">
|
||||
เข้าสู่หน้าจัดการเรียน
|
||||
{{ $t('landing.goToDashboard') }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ const displayDescription = computed(() => getLocalizedText(props.description))
|
|||
class="absolute top-4 right-4 px-3 py-1 rounded-full text-xs font-black shadow-sm backdrop-blur-md transition-colors"
|
||||
:class="(price === 'Free' || price === 'ฟรี') ? 'bg-emerald-500 text-white shadow-emerald-500/30' : 'glass text-white'"
|
||||
>
|
||||
{{ price }}
|
||||
{{ (price === 'Free' || price === 'ฟรี') ? $t('course.free') : price }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -98,13 +98,13 @@ const displayDescription = computed(() => getLocalizedText(props.description))
|
|||
<!-- Rating & Lessons -->
|
||||
<div v-if="rating || lessons" class="flex items-center gap-4 text-[11px] font-bold mb-6 uppercase tracking-wider text-slate-500 dark:text-slate-400">
|
||||
<span v-if="rating" class="flex items-center gap-1"><span class="text-amber-400 text-sm">★</span> {{ rating }}</span>
|
||||
<span v-if="lessons" class="flex items-center gap-1"><span class="text-blue-400">📚</span> {{ lessons }} บทเรียน</span>
|
||||
<span v-if="lessons" class="flex items-center gap-1"><span class="text-blue-400">📚</span> {{ lessons }} {{ $t('course.lessonsUnit') }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Progress Bar -->
|
||||
<div v-if="progress !== undefined && !completed" class="mb-8 p-3 rounded-2xl" style="background-color: rgba(148, 163, 184, 0.1);">
|
||||
<div class="flex justify-between items-center text-[10px] font-black uppercase tracking-widest mb-1.5">
|
||||
<span style="color: var(--text-secondary);">Progress</span>
|
||||
<span style="color: var(--text-secondary);">{{ $t('course.progress') }}</span>
|
||||
<span class="text-blue-600">{{ progress }}%</span>
|
||||
</div>
|
||||
<div class="w-full h-1.5 bg-slate-300 dark:bg-slate-700 rounded-full overflow-hidden">
|
||||
|
|
@ -115,25 +115,25 @@ const displayDescription = computed(() => getLocalizedText(props.description))
|
|||
<!-- Completed Badge -->
|
||||
<div v-if="completed" class="mb-6">
|
||||
<span class="status-pill status-success text-[10px] font-black uppercase tracking-widest flex items-center justify-center gap-2">
|
||||
<span class="text-sm">✓</span> เรียนจบเรียบร้อย
|
||||
<span class="text-sm">✓</span> {{ $t('course.completed') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<button v-if="showViewDetails" class="btn-premium-primary w-full mt-auto dark:!text-white" @click="emit('viewDetails')">
|
||||
ดูรายละเอียด
|
||||
{{ $t('menu.viewDetails') }}
|
||||
</button>
|
||||
|
||||
<NuxtLink v-if="showContinue" to="/classroom/learning" class="btn-premium-primary w-full mt-auto shadow-lg shadow-blue-600/20">
|
||||
เรียนต่อทันที
|
||||
{{ $t('course.continueLearning') }}
|
||||
</NuxtLink>
|
||||
|
||||
<div v-if="completed && (showCertificate || showStudyAgain)" class="flex flex-col gap-2 mt-auto">
|
||||
<NuxtLink v-if="showStudyAgain" to="/classroom/learning" class="btn-premium-primary w-full dark:!text-white">
|
||||
ทบทวนบทเรียน
|
||||
{{ $t('course.studyAgain') }}
|
||||
</NuxtLink>
|
||||
<button v-if="showCertificate" class="btn-premium-success w-full shadow-lg shadow-emerald-600/20" @click="emit('viewCertificate')">
|
||||
ดาวน์โหลดประกาศนียบัตร
|
||||
{{ $t('course.downloadCertificate') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { ref, computed, onMounted } from 'vue'
|
|||
import { useAuth } from '~/composables/useAuth'
|
||||
|
||||
const { currentUser, logout } = useAuth()
|
||||
const { t } = useI18n()
|
||||
const isOpen = ref(false)
|
||||
const isDarkMode = ref(false)
|
||||
const menuRef = ref<HTMLDivElement | null>(null)
|
||||
|
|
@ -42,12 +43,13 @@ const userName = computed(() => {
|
|||
})
|
||||
|
||||
// Navigation menu definition
|
||||
const menuItems = [
|
||||
{ label: 'หน้าหลัก', to: '/dashboard' },
|
||||
{ label: 'รายการคอร์ส', to: '/browse/discovery' },
|
||||
{ label: 'คอร์สของฉัน', to: '/dashboard/my-courses' },
|
||||
{ label: 'ตั้งค่าบัญชี', to: '/dashboard/profile' }
|
||||
]
|
||||
// Navigation menu definition
|
||||
const menuItems = computed(() => [
|
||||
{ label: t('userMenu.home'), to: '/dashboard' },
|
||||
{ label: t('userMenu.courseList'), to: '/browse/discovery' },
|
||||
{ label: t('userMenu.myCourses'), to: '/dashboard/my-courses' },
|
||||
{ label: t('userMenu.settings'), to: '/dashboard/profile' }
|
||||
])
|
||||
|
||||
const handleNavigate = (path: string) => {
|
||||
navigateTo(path)
|
||||
|
|
@ -166,7 +168,7 @@ onMounted(() => {
|
|||
class="w-full flex items-center justify-between py-2"
|
||||
@click="toggleDarkMode"
|
||||
>
|
||||
<span class="text-sm font-medium text-slate-800 dark:text-white">โหมดกลางคืน</span>
|
||||
<span class="text-sm font-medium text-slate-800 dark:text-white">{{ $t('userMenu.darkMode') }}</span>
|
||||
<div
|
||||
:class="[
|
||||
'relative inline-flex h-6 w-11 items-center rounded-full transition-colors',
|
||||
|
|
@ -189,7 +191,7 @@ onMounted(() => {
|
|||
class="w-full px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 hover:bg-red-100 dark:hover:bg-red-900/40 rounded-lg font-medium transition-colors text-sm"
|
||||
@click="handleLogout"
|
||||
>
|
||||
ออกจากระบบ
|
||||
{{ $t('userMenu.logout') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue