feat: Implement initial e-learning platform frontend structure including dashboard, course management, authentication, and common UI components.

This commit is contained in:
supalerk-ar66 2026-02-27 10:05:33 +07:00
parent aceeb80d9a
commit ad11c6b7c5
44 changed files with 720 additions and 578 deletions

View file

@ -1,8 +1,8 @@
<script setup lang="ts">
/**
* @file reset-password.vue
* @description Reset Password Page.
* Allows user to set a new password after verifying their email link (simulated).
* @description หนาตงรหสผานใหม (Reset Password Page.
* อนญาตใหใชงรหสผานใหมหลงจากยนยนลงกเมล)
*/
definePageMeta({
@ -44,9 +44,9 @@ const handlePasswordInput = (field: keyof typeof resetForm, val: string) => {
resetForm[field] = val
if (/[\u0E00-\u0E7F]/.test(val)) {
if (field === 'password') errors.value.password = 'ห้ามใส่ภาษาไทย'
// We don't necessarily need to flag confirmPassword individually if it just needs to match, but let's be consistent if we want
// confirmPassword (We don't necessarily need to flag confirmPassword individually if it just needs to match, but let's be consistent if we want)
} else {
// Clear error if it was "Thai characters"
// "" (Clear error if it was "Thai characters")
if (field === 'password' && errors.value.password === 'ห้ามใส่ภาษาไทย') {
clearFieldError('password')
}
@ -63,7 +63,7 @@ onMounted(() => {
const resetPassword = async () => {
if (!validate(resetForm, resetRules)) return
// Extract token from query
// URL query (Extract token from query)
const token = route.query.token as string
if (!token) {
@ -92,7 +92,7 @@ const resetPassword = async () => {
<template>
<div class="relative min-h-screen w-full flex items-center justify-center p-4 overflow-hidden bg-slate-50 transition-colors">
<!-- ==========================================
BACKGROUND EFFECTS (Light Mode Only)
เอฟเฟกตนหล (แสดงเฉพาะโหมดสวาง) (BACKGROUND EFFECTS (Light Mode Only))
========================================== -->
<div class="fixed inset-0 overflow-hidden pointer-events-none -z-10">
<div class="absolute inset-0 bg-gradient-to-br from-white via-slate-50 to-blue-50/50"></div>
@ -101,11 +101,11 @@ const resetPassword = async () => {
</div>
<!-- ==========================================
RESET PASSWORD CARD
การดตงรหสผานใหม (RESET PASSWORD CARD)
========================================== -->
<div class="w-full max-w-[460px] relative z-10 slide-up">
<!-- Header / Logo -->
<!-- วข / โลโก (Header / Logo) -->
<div class="text-center mb-8">
<div class="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-gradient-to-tr from-blue-600 to-indigo-600 text-white shadow-lg shadow-blue-600/20 mb-6">
<span class="font-black text-2xl">E</span>
@ -116,10 +116,10 @@ const resetPassword = async () => {
<div class="bg-white rounded-[2rem] p-8 md:p-10 shadow-xl shadow-slate-200/50 border border-slate-100 relative overflow-hidden">
<!-- Form -->
<!-- ฟอร (Form) -->
<form @submit.prevent="resetPassword" class="flex flex-col gap-6">
<!-- New Password -->
<!-- รหสผานใหม (New Password) -->
<div>
<label class="block text-sm font-semibold text-slate-700 mb-2 ml-1">รหสผานใหม <span class="text-red-500">*</span></label>
<div class="relative group">
@ -145,7 +145,7 @@ const resetPassword = async () => {
<span v-if="errors.password" class="text-xs text-red-500 font-medium ml-1 mt-1 block slide-up-sm">{{ errors.password }}</span>
</div>
<!-- Confirm Password -->
<!-- นยนรหสผานใหม (Confirm Password) -->
<div>
<label class="block text-sm font-semibold text-slate-700 mb-2 ml-1">นยนรหสผานใหม <span class="text-red-500">*</span></label>
<div class="relative group">
@ -171,7 +171,7 @@ const resetPassword = async () => {
<span v-if="errors.confirmPassword" class="text-xs text-red-500 font-medium ml-1 mt-1 block slide-up-sm">{{ errors.confirmPassword }}</span>
</div>
<!-- Submit Button -->
<!-- มยนย (Submit Button) -->
<button
type="submit"
:disabled="isLoading"
@ -183,7 +183,7 @@ const resetPassword = async () => {
</form>
</div>
<!-- Back Link -->
<!-- งกอนกล (Back Link) -->
<div class="mt-8 text-center text-slate-500">
<NuxtLink to="/auth/login" class="inline-flex items-center gap-2 text-sm font-medium hover:text-slate-800 transition-colors group px-4 py-2 rounded-lg hover:bg-white/50">
<span class="group-hover:-translate-x-1 transition-transform"></span> กลบไปหนาเขาสระบบ