ED:Font color
This commit is contained in:
parent
d8d3dff2e7
commit
563564ee58
14 changed files with 162 additions and 83 deletions
|
|
@ -1 +1 @@
|
|||
{"id":"dev","timestamp":1768276905519}
|
||||
{"id":"dev","timestamp":1768360747858}
|
||||
|
|
@ -1 +1 @@
|
|||
{"id":"dev","timestamp":1768276905519,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
|
||||
{"id":"dev","timestamp":1768360747858,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"date": "2026-01-13T04:01:52.330Z",
|
||||
"date": "2026-01-14T03:19:14.221Z",
|
||||
"preset": "nitro-dev",
|
||||
"framework": {
|
||||
"name": "nuxt",
|
||||
|
|
@ -9,9 +9,9 @@
|
|||
"nitro": "2.12.8"
|
||||
},
|
||||
"dev": {
|
||||
"pid": 17152,
|
||||
"pid": 16832,
|
||||
"workerAddress": {
|
||||
"socketPath": "\\\\.\\pipe\\nitro-worker-17152-1-1-4801.sock"
|
||||
"socketPath": "\\\\.\\pipe\\nitro-worker-16832-1-1-6766.sock"
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Frontend-Learner/.nuxt/nuxt.d.ts
vendored
2
Frontend-Learner/.nuxt/nuxt.d.ts
vendored
|
|
@ -1,7 +1,7 @@
|
|||
/// <reference types="quasar" />
|
||||
/// <reference types="@nuxtjs/tailwindcss" />
|
||||
/// <reference types="nuxt-quasar-ui" />
|
||||
/// <reference types="@nuxt/devtools" />
|
||||
/// <reference types="@nuxtjs/tailwindcss" />
|
||||
/// <reference types="@nuxt/telemetry" />
|
||||
/// <reference path="types/builder-env.d.ts" />
|
||||
/// <reference types="nuxt" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 13/1/2569 11:47:48
|
||||
// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at 14/1/2569 10:19:11
|
||||
import "@nuxtjs/tailwindcss/config-ctx"
|
||||
import configMerger from "@nuxtjs/tailwindcss/merger";
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,10 @@ const emit = defineEmits<{
|
|||
{{ level }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="price" class="absolute top-4 right-4 glass px-3 py-1 rounded-full text-xs font-black text-white shadow-sm">
|
||||
<div v-if="price"
|
||||
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 }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -107,7 +110,7 @@ const emit = defineEmits<{
|
|||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<button v-if="showViewDetails" class="btn-premium-secondary w-full mt-auto" @click="emit('viewDetails')">
|
||||
<button v-if="showViewDetails" class="btn-premium-primary w-full mt-auto dark:!text-white" @click="emit('viewDetails')">
|
||||
ดูรายละเอียด
|
||||
</button>
|
||||
|
||||
|
|
@ -116,7 +119,7 @@ const emit = defineEmits<{
|
|||
</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-secondary w-full">
|
||||
<NuxtLink v-if="showStudyAgain" to="/classroom/learning" class="btn-premium-primary w-full dark:!text-white">
|
||||
ทบทวนบทเรียน
|
||||
</NuxtLink>
|
||||
<button v-if="showCertificate" class="btn-premium-success w-full shadow-lg shadow-emerald-600/20" @click="emit('viewCertificate')">
|
||||
|
|
@ -172,6 +175,7 @@ const emit = defineEmits<{
|
|||
font-size: 0.875rem;
|
||||
border: 1px solid var(--border-color);
|
||||
transition: all 0.3s ease;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-premium-secondary:hover {
|
||||
background: var(--bg-body);
|
||||
|
|
@ -180,14 +184,15 @@ const emit = defineEmits<{
|
|||
}
|
||||
|
||||
:global(.dark) .btn-premium-secondary {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #e2e8f0;
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
background: rgba(34, 211, 238, 0.1);
|
||||
color: #22d3ee !important;
|
||||
border-color: rgba(34, 211, 238, 0.3) !important;
|
||||
}
|
||||
|
||||
:global(.dark) .btn-premium-secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
background: rgba(34, 211, 238, 0.2);
|
||||
border-color: #22d3ee !important;
|
||||
color: #67e8f9 !important;
|
||||
}
|
||||
|
||||
.btn-premium-success {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ const filteredCourses = computed(() => {
|
|||
<div v-if="!showDetail">
|
||||
<!-- Search & Filters Header -->
|
||||
<div class="flex justify-between items-center mb-6" style="flex-wrap: wrap; gap: 16px;">
|
||||
<h1 style="font-size: 28px; font-weight: 700; color: #000000;">รายการคอร์สทั้งหมด</h1>
|
||||
<h1 class="text-[28px] font-bold text-slate-900 dark:text-white">รายการคอร์สทั้งหมด</h1>
|
||||
<div class="flex gap-3" style="flex-wrap: wrap;">
|
||||
<!-- Search Input -->
|
||||
<div class="relative">
|
||||
|
|
@ -212,7 +212,7 @@ const filteredCourses = computed(() => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<h1 style="font-size: 32px; font-weight: 700; margin-bottom: 16px; color: #000000;">เบื้องต้นการออกแบบ UX/UI</h1>
|
||||
<h1 class="text-[32px] font-bold mb-4 text-slate-900 dark:text-white">เบื้องต้นการออกแบบ UX/UI</h1>
|
||||
<p class="text-slate-700 dark:text-slate-400 mb-6" style="font-size: 1.1em; line-height: 1.7;">
|
||||
เนื้อหาครอบคลุมทุกอย่างตั้งแต่การวิจัยผู้ใช้ (User Research) ไปจนถึงการทำต้นแบบความละเอียดสูง (High-fidelity Prototyping)
|
||||
เหมาะสำหรับผู้เริ่มต้นที่ต้องการเข้าสู่สายงานออกแบบผลิตภัณฑ์
|
||||
|
|
@ -220,7 +220,7 @@ const filteredCourses = computed(() => {
|
|||
|
||||
<!-- Learning Objectives -->
|
||||
<div class="card mb-6">
|
||||
<h3 class="font-bold mb-4" style="color: #000000;">สิ่งที่คุณจะได้เรียนรู้</h3>
|
||||
<h3 class="font-bold mb-4 text-slate-900 dark:text-white">สิ่งที่คุณจะได้เรียนรู้</h3>
|
||||
<ul class="grid-12" style="grid-template-columns: 1fr 1fr; gap: 12px;">
|
||||
<li class="flex gap-2 text-sm"><span style="color: var(--success);">✓</span> วิธีการวิจัยผู้ใช้ (User Research)</li>
|
||||
<li class="flex gap-2 text-sm"><span style="color: var(--success);">✓</span> การวาดโครงร่างและทำต้นแบบ</li>
|
||||
|
|
@ -231,11 +231,11 @@ const filteredCourses = computed(() => {
|
|||
|
||||
<!-- Course Syllabus / Outline -->
|
||||
<div class="card">
|
||||
<h3 class="font-bold mb-4" style="color: #000000;">เนื้อหาในคอร์ส</h3>
|
||||
<h3 class="font-bold mb-4 text-slate-900 dark:text-white">เนื้อหาในคอร์ส</h3>
|
||||
<!-- Chapter 1 -->
|
||||
<div class="mb-4">
|
||||
<div class="flex justify-between p-4 rounded mb-2" style="background: #f3f4f6; border: 1px solid #e5e7eb;">
|
||||
<span class="font-bold" style="color: #000000;">01. บทนำ</span>
|
||||
<span class="font-bold text-slate-900 dark:text-slate-900">01. บทนำ</span>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-400">3 บทเรียน</span>
|
||||
</div>
|
||||
<div style="padding-left: 16px;">
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ const chapters = [
|
|||
{
|
||||
title: '02. วิธีการวิจัย',
|
||||
lessons: [
|
||||
{ id: '2.1', title: 'การสัมภาษณ์ผู้ใช้', icon: '🔒', status: 'locked' },
|
||||
{ id: '2.2', title: 'การสร้าง Persona', icon: '🔒', status: 'locked' },
|
||||
{ id: '2.1', title: 'การสัมภาษณ์ผู้ใช้', icon: '', status: 'locked' },
|
||||
{ id: '2.2', title: 'การสร้าง Persona', icon: '', status: 'locked' },
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -93,12 +93,12 @@ const seek = (e: MouseEvent) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="learning-shell font-main antialiased selection:bg-blue-500/30">
|
||||
<div class="learning-shell font-main antialiased selection:bg-blue-500/30 dark:!bg-[#0F172A] dark:!text-slate-200 transition-colors">
|
||||
<!-- Header: Custom top bar for learning context -->
|
||||
<header class="learning-header px-2 md:px-4 h-14 md:h-[56px] border-b border-white/5 flex items-center justify-between gap-2 md:gap-4">
|
||||
<header class="learning-header px-2 md:px-4 h-14 md:h-[56px] border-b border-slate-200 dark:border-white/5 flex items-center justify-between gap-2 md:gap-4 dark:!bg-slate-800 transition-colors">
|
||||
<div class="flex items-center gap-1 md:gap-6 min-w-0 flex-1">
|
||||
<!-- Mobile Sidebar Toggle -->
|
||||
<button class="md:hidden text-white p-2 hover:bg-white/5 rounded-lg flex-shrink-0" @click="toggleSidebar">
|
||||
<button class="md:hidden text-slate-900 dark:text-white p-2 hover:bg-slate-100 dark:hover:bg-white/5 rounded-lg flex-shrink-0 transition-colors" @click="toggleSidebar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" /></svg>
|
||||
</button>
|
||||
<!-- Back Navigation -->
|
||||
|
|
@ -106,7 +106,7 @@ const seek = (e: MouseEvent) => {
|
|||
<span class="text-lg md:text-base">←</span>
|
||||
<span class="hidden md:inline text-[11px] font-bold">กลับไปหน้าหลัก</span>
|
||||
</NuxtLink>
|
||||
<div class="w-[1px] h-4 bg-white/10 hidden md:block flex-shrink-0"/>
|
||||
<div class="w-[1px] h-4 bg-slate-200 dark:bg-white/10 hidden md:block flex-shrink-0"/>
|
||||
<h1 class="text-[13px] md:text-sm font-black text-slate-900 dark:text-white tracking-tight truncate min-w-0 pr-2">เบื้องต้นการออกแบบ UX/UI</h1>
|
||||
</div>
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ const seek = (e: MouseEvent) => {
|
|||
</header>
|
||||
|
||||
<!-- Sidebar: Course Curriculum list -->
|
||||
<aside class="learning-sidebar" :class="{ 'open': sidebarOpen }">
|
||||
<aside class="learning-sidebar dark:!bg-gray-900 dark:!border-r-white/5 transition-colors" :class="{ 'open': sidebarOpen }">
|
||||
<div class="py-2">
|
||||
<!-- Announcements Tab Trigger -->
|
||||
<div
|
||||
|
|
@ -134,17 +134,17 @@ const seek = (e: MouseEvent) => {
|
|||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-lg" style="color: #ff3366;">📢</span>
|
||||
<span class="font-black text-[12px] tracking-tight">ประกาศในคอร์ส</span>
|
||||
<span class="font-black text-[12px] tracking-tight dark:!text-white">ประกาศในคอร์ส</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chapters & Lessons List -->
|
||||
<div v-for="chapter in chapters" :key="chapter.title" class="mt-4">
|
||||
<div class="chapter-header px-4 py-2">{{ chapter.title }}</div>
|
||||
<div class="chapter-header px-4 py-2 dark:!bg-slate-900 dark:!text-white dark:!border-b-white/5">{{ chapter.title }}</div>
|
||||
<div
|
||||
v-for="lesson in chapter.lessons"
|
||||
:key="lesson.id"
|
||||
class="lesson-item px-4"
|
||||
class="lesson-item px-4 dark:!text-slate-300 dark:!border-b-white/5 hover:dark:!bg-white/5 hover:dark:!text-white transition-colors"
|
||||
:class="{
|
||||
'active-lesson': currentLessonId === lesson.id && activeTab === 'details',
|
||||
'completed': lesson.status === 'completed',
|
||||
|
|
@ -161,7 +161,7 @@ const seek = (e: MouseEvent) => {
|
|||
|
||||
<!-- Exam Link -->
|
||||
<div class="mt-8 border-t border-white/5 pt-2">
|
||||
<div class="chapter-header px-4 py-2 uppercase tracking-widest text-[10px]">03. แบบทดสอบท้ายบท</div>
|
||||
<div class="chapter-header px-4 py-2 uppercase tracking-widest text-[10px] dark:!bg-slate-900 dark:!text-white dark:!border-b-white/5">03. แบบทดสอบท้ายบท</div>
|
||||
<NuxtLink to="/classroom/quiz" class="lesson-item px-4 no-underline cursor-pointer">
|
||||
<span class="text-[12px] font-medium text-slate-900 dark:text-slate-200 group-hover:text-black dark:group-hover:text-white transition-colors">ข้อสอบปลายภาค</span>
|
||||
<span class="text-xs opacity-50">📄</span>
|
||||
|
|
@ -174,7 +174,7 @@ const seek = (e: MouseEvent) => {
|
|||
<div v-if="sidebarOpen" class="fixed inset-0 bg-black/60 backdrop-blur-sm z-[85] md:hidden" @click="toggleSidebar"/>
|
||||
|
||||
<!-- Main View Area -->
|
||||
<div class="main-container custom-scrollbar overflow-x-hidden pt-6">
|
||||
<div class="main-container custom-scrollbar overflow-x-hidden pt-6 dark:!bg-[#0B0F1A] transition-colors">
|
||||
<main class="w-full max-w-7xl mx-auto px-4 md:px-8 pb-10 md:pb-20">
|
||||
<!-- Tab Content: Announcements (Center Aligned) -->
|
||||
<div v-if="activeTab === 'announcements'" class="animate-fade-in max-w-4xl mx-auto space-y-8 pt-8 md:pt-14">
|
||||
|
|
@ -243,21 +243,21 @@ const seek = (e: MouseEvent) => {
|
|||
</div>
|
||||
|
||||
<!-- Lesson Notes Card -->
|
||||
<div class="rounded-2xl bg-white dark:bg-slate-800/60 border border-slate-200 dark:border-slate-700 p-6 md:p-10 shadow-sm dark:shadow-xl transition-colors">
|
||||
<h3 class="text-[11px] md:text-[12px] font-black text-slate-900 dark:text-slate-100 mb-6 uppercase tracking-[0.2em] border-b border-slate-200 dark:border-slate-700 pb-4">บันทึกบทเรียน</h3>
|
||||
<div class="text-[15px] md:text-[16px] text-slate-700 dark:text-slate-200 leading-relaxed font-medium space-y-6">
|
||||
<div class="rounded-2xl bg-white dark:!bg-slate-800 border border-slate-200 dark:border-slate-700 p-6 md:p-10 shadow-sm dark:shadow-xl transition-colors">
|
||||
<h3 class="text-[14px] md:text-[16px] font-black text-slate-900 dark:text-slate-50 mb-6 uppercase tracking-[0.2em] border-b border-slate-200 dark:border-slate-600 pb-4">บันทึกบทเรียน</h3>
|
||||
<div class="text-[16px] md:text-[18px] text-slate-700 dark:text-slate-200 leading-relaxed font-medium space-y-6">
|
||||
<p>การ Wireframe คือการจำลองโครงสร้างพื้นฐานของหน้าจอ (Layout) โดยเน้นไปที่การจัดวางตำแหน่งปุ่มและเนื้อหาสำคัญเพื่อวางโครงสร้างก่อนลงมือดีไซน์จริง</p>
|
||||
|
||||
<div class="bg-slate-50 dark:bg-slate-800/40 border border-slate-200 dark:border-slate-700 border-l-4 border-l-blue-500 p-6 rounded-r-2xl">
|
||||
<div class="font-black text-blue-700 dark:text-blue-400 text-[12px] uppercase tracking-wider mb-3">ประเด็นสำคัญ:</div>
|
||||
<div class="bg-slate-50 dark:bg-slate-700/50 border border-slate-200 dark:border-slate-600 border-l-4 border-l-blue-500 p-6 rounded-r-2xl">
|
||||
<div class="font-black text-blue-700 dark:text-blue-300 text-[14px] md:text-[16px] uppercase tracking-wider mb-3">ประเด็นสำคัญ:</div>
|
||||
<ul class="space-y-4">
|
||||
<li class="flex gap-4 items-start">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 mt-2 flex-shrink-0"/>
|
||||
<span class="text-slate-700 dark:text-slate-300">ความละเอียดต่ำ (Low-fidelity) ช่วยให้โฟกัสที่การใช้งาน (Functionality) เป็นหลัก</span>
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 mt-2.5 flex-shrink-0"/>
|
||||
<span class="text-slate-700 dark:text-slate-100">ความละเอียดต่ำ (Low-fidelity) ช่วยให้โฟกัสที่การใช้งาน (Functionality) เป็นหลัก</span>
|
||||
</li>
|
||||
<li class="flex gap-4 items-start">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 mt-2 flex-shrink-0"/>
|
||||
<span class="text-slate-700 dark:text-slate-300">ช่วยในการสื่อสารไอเดียกับ Stakeholders ให้เห็นภาพตรงกัน</span>
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-blue-500 mt-2.5 flex-shrink-0"/>
|
||||
<span class="text-slate-700 dark:text-slate-100">ช่วยในการสื่อสารไอเดียกับ Stakeholders ให้เห็นภาพตรงกัน</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -268,27 +268,27 @@ const seek = (e: MouseEvent) => {
|
|||
<!-- Right Side: Resources + Actions (4/12) -->
|
||||
<div class="md:col-span-4 space-y-6 md:sticky md:top-6">
|
||||
<!-- Resources Card -->
|
||||
<div class="rounded-2xl bg-white dark:bg-slate-800/60 border border-slate-200 dark:border-slate-700 p-6 md:p-8 shadow-sm dark:shadow-xl transition-colors">
|
||||
<h3 class="text-[11px] md:text-[12px] font-black text-slate-900 dark:text-slate-100 mb-6 uppercase tracking-[0.2em] border-b border-slate-200 dark:border-slate-700 pb-4">เอกสารประกอบ</h3>
|
||||
<div class="rounded-2xl bg-white dark:!bg-slate-800 border border-slate-200 dark:border-slate-700 p-6 md:p-8 shadow-sm dark:shadow-xl transition-colors">
|
||||
<h3 class="text-[14px] md:text-[16px] font-black text-slate-900 dark:text-slate-100 mb-6 uppercase tracking-[0.2em] border-b border-slate-200 dark:border-slate-700 pb-4">เอกสารประกอบ</h3>
|
||||
<div class="space-y-3">
|
||||
<!-- Attachment Row -->
|
||||
<div class="flex items-center justify-between p-4 bg-slate-50 dark:bg-slate-800/40 rounded-2xl border border-slate-200 dark:border-slate-700 group hover:bg-slate-100 dark:hover:bg-slate-700/40 transition-all cursor-pointer min-w-0">
|
||||
<div class="flex items-center justify-between p-4 bg-slate-50 dark:bg-slate-700/50 rounded-2xl border border-slate-200 dark:border-slate-600 group hover:bg-slate-100 dark:hover:bg-slate-600/50 transition-all cursor-pointer min-w-0">
|
||||
<div class="flex items-center gap-3 min-w-0 flex-1">
|
||||
<span class="text-xl flex-shrink-0">📄</span>
|
||||
<div class="flex flex-col min-w-0">
|
||||
<span class="text-[12px] font-bold text-slate-800 dark:text-slate-100 truncate pr-2">สไลด์ประกอบการสอน.pdf</span>
|
||||
<span class="text-[9px] font-black text-slate-500 dark:text-slate-400 uppercase">2.4 MB</span>
|
||||
<span class="text-[14px] font-bold text-slate-800 dark:text-slate-100 truncate pr-2">สไลด์ประกอบการสอน.pdf</span>
|
||||
<span class="text-[11px] font-black text-slate-500 dark:text-slate-400 uppercase">2.4 MB</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="w-8 h-8 rounded-full flex items-center justify-center bg-slate-100 dark:bg-slate-700/50 group-hover:bg-blue-600 text-slate-600 dark:text-slate-400 group-hover:text-white transition-all text-xs flex-shrink-0">↓</button>
|
||||
</div>
|
||||
<!-- Attachment Row -->
|
||||
<div class="flex items-center justify-between p-4 bg-slate-50 dark:bg-slate-800/40 rounded-2xl border border-slate-200 dark:border-slate-700 group hover:bg-slate-100 dark:hover:bg-slate-700/40 transition-all cursor-pointer min-w-0">
|
||||
<div class="flex items-center justify-between p-4 bg-slate-50 dark:bg-slate-700/50 rounded-2xl border border-slate-200 dark:border-slate-600 group hover:bg-slate-100 dark:hover:bg-slate-600/50 transition-all cursor-pointer min-w-0">
|
||||
<div class="flex items-center gap-3 min-w-0 flex-1">
|
||||
<span class="text-xl flex-shrink-0">📁</span>
|
||||
<div class="flex flex-col min-w-0">
|
||||
<span class="text-[12px] font-bold text-slate-800 dark:text-slate-100 truncate pr-2">ไฟล์แบบฝึกหัด.zip</span>
|
||||
<span class="text-[9px] font-black text-slate-500 dark:text-slate-400 uppercase">15 MB</span>
|
||||
<span class="text-[14px] font-bold text-slate-800 dark:text-slate-100 truncate pr-2">ไฟล์แบบฝึกหัด.zip</span>
|
||||
<span class="text-[11px] font-black text-slate-500 dark:text-slate-400 uppercase">15 MB</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="w-8 h-8 rounded-full flex items-center justify-center bg-slate-100 dark:bg-slate-700/50 group-hover:bg-blue-600 text-slate-600 dark:text-slate-400 group-hover:text-white transition-all text-xs flex-shrink-0">↓</button>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ onUnmounted(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="quiz-shell min-h-screen bg-white dark:bg-[#0b0f1a] text-slate-900 dark:text-slate-200 antialiased selection:bg-blue-500/20 transition-colors">
|
||||
<div class="quiz-shell min-h-screen bg-white dark:bg-[#0b0f1a] text-slate-900 dark:text-slate-200 font-main antialiased selection:bg-blue-500/20 transition-colors">
|
||||
<!-- Header: Precise matching of the image -->
|
||||
<header class="h-14 bg-white dark:bg-[#161b22] fixed top-0 inset-x-0 z-[100] flex items-center px-6 border-b border-slate-300 dark:border-white/5 transition-colors">
|
||||
<div class="flex items-center">
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ useHead({
|
|||
<template>
|
||||
<div>
|
||||
<!-- Page Header -->
|
||||
<h1 style="font-size: 28px; font-weight: 700; margin-bottom: 24px;">ประกาศ</h1>
|
||||
<h1 class="text-[28px] font-bold mb-6 text-slate-900 dark:text-white">ประกาศ</h1>
|
||||
|
||||
<!--
|
||||
Main Layout: 12-column Grid
|
||||
|
|
@ -40,7 +40,7 @@ useHead({
|
|||
<span class="status-pill status-warning">สำคัญ</span>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-400">24 ธ.ค. 2024</span>
|
||||
</div>
|
||||
<h2 class="font-bold mb-4" style="font-size: 1.25rem;">แจ้งปิดปรับปรุงระบบ</h2>
|
||||
<h2 class="text-xl font-bold mb-4 text-slate-900 dark:text-white">แจ้งปิดปรับปรุงระบบ</h2>
|
||||
<p class="mb-4">เราจะทำการปิดปรับปรุงระบบในวันที่ 25 ธ.ค. เวลา 02:00 - 04:00 น. ขออภัยในความไม่สะดวก</p>
|
||||
<!-- Attachment Block -->
|
||||
<div class="flex items-center gap-2 p-3 rounded" style="background: var(--neutral-50); border: 1px solid var(--border-color); width: fit-content;">
|
||||
|
|
@ -53,7 +53,7 @@ useHead({
|
|||
<div class="flex justify-between items-start mb-2" style="flex-wrap: wrap; gap: 8px;">
|
||||
<div>
|
||||
<span class="status-pill status-neutral mb-2">เบื้องต้นการออกแบบ UX/UI</span>
|
||||
<h3 class="font-bold">เริ่มเปิดหลักสูตรเดือนมกราคมแล้ว!</h3>
|
||||
<h3 class="font-bold text-slate-900 dark:text-white">เริ่มเปิดหลักสูตรเดือนมกราคมแล้ว!</h3>
|
||||
</div>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-400">23 ธ.ค. 2024</span>
|
||||
</div>
|
||||
|
|
@ -66,7 +66,7 @@ useHead({
|
|||
<div class="flex justify-between items-start mb-2" style="flex-wrap: wrap; gap: 8px;">
|
||||
<div>
|
||||
<span class="status-pill status-neutral mb-2">การเข้าถึงเว็บ (WCAG)</span>
|
||||
<h3 class="font-bold">ดาวน์โหลดเอกสารประกอบการเรียนได้แล้ว</h3>
|
||||
<h3 class="font-bold text-slate-900 dark:text-white">ดาวน์โหลดเอกสารประกอบการเรียนได้แล้ว</h3>
|
||||
</div>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-400">22 ธ.ค. 2024</span>
|
||||
</div>
|
||||
|
|
@ -82,7 +82,7 @@ useHead({
|
|||
<div class="flex justify-between items-start mb-2" style="flex-wrap: wrap; gap: 8px;">
|
||||
<div>
|
||||
<span class="status-pill status-neutral mb-2">รูปแบบ React ขั้นสูง</span>
|
||||
<h3 class="font-bold">อัปเดตบทเรียนใหม่: React Server Components</h3>
|
||||
<h3 class="font-bold text-slate-900 dark:text-white">อัปเดตบทเรียนใหม่: React Server Components</h3>
|
||||
</div>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-400">21 ธ.ค. 2024</span>
|
||||
</div>
|
||||
|
|
@ -93,7 +93,7 @@ useHead({
|
|||
<!-- Announcement: General New Course -->
|
||||
<div class="card mb-4">
|
||||
<div class="flex justify-between items-start mb-2" style="flex-wrap: wrap; gap: 8px;">
|
||||
<h3 class="font-bold">คอร์สใหม่: Advanced Python</h3>
|
||||
<h3 class="font-bold text-slate-900 dark:text-white">คอร์สใหม่: Advanced Python</h3>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-400">20 ธ.ค. 2024</span>
|
||||
</div>
|
||||
<p class="text-slate-700 dark:text-slate-300 mb-2">พบกับคอร์สใหม่ล่าสุด เรียนรู้โครงสร้างข้อมูล Python...</p>
|
||||
|
|
@ -103,7 +103,7 @@ useHead({
|
|||
<!-- Announcement: Platform Update -->
|
||||
<div class="card mb-4">
|
||||
<div class="flex justify-between items-start mb-2" style="flex-wrap: wrap; gap: 8px;">
|
||||
<h3 class="font-bold">ยินดีต้อนรับสู่ดีไซน์ใหม่!</h3>
|
||||
<h3 class="font-bold text-slate-900 dark:text-white">ยินดีต้อนรับสู่ดีไซน์ใหม่!</h3>
|
||||
<span class="text-sm text-slate-600 dark:text-slate-400">15 ธ.ค. 2024</span>
|
||||
</div>
|
||||
<p class="text-slate-700 dark:text-slate-300 mb-2">เราปรับโฉมใหม่ไฉไลกว่าเดิม เพื่อการใช้งานที่ดียิ่งขึ้น...</p>
|
||||
|
|
@ -117,7 +117,7 @@ useHead({
|
|||
========================================== -->
|
||||
<div class="col-span-4">
|
||||
<div class="card">
|
||||
<h3 class="font-bold mb-4">หมวดหมู่</h3>
|
||||
<h3 class="font-bold mb-4 text-slate-900 dark:text-white">หมวดหมู่</h3>
|
||||
<ul class="flex flex-col gap-2">
|
||||
<!-- Filter Option: All -->
|
||||
<li class="flex justify-between items-center p-2 rounded cursor-pointer" style="background: var(--neutral-50);">
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ const recommendedCourses = [
|
|||
|
||||
<!-- Section: Recommended Courses -->
|
||||
<div class="mb-8">
|
||||
<h2 class="text-2xl font-black flex items-center gap-3 tracking-tight text-black dark:text-white">
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ const downloadCertificate = () => {
|
|||
<div>
|
||||
<!-- Page Header & Filters -->
|
||||
<div class="flex justify-between items-center mb-6 mobile-stack">
|
||||
<h1 style="font-size: 28px; font-weight: 700;">คอร์สของฉัน</h1>
|
||||
<h1 class="text-[28px] font-bold text-slate-900 dark:text-white">คอร์สของฉัน</h1>
|
||||
<!-- Filter Tabs -->
|
||||
<div class="flex gap-2" style="overflow-x: auto; padding-bottom: 4px; width: 100%; justify-content: flex-start;">
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ useHead({
|
|||
})
|
||||
|
||||
const { currentUser } = useAuth()
|
||||
const { errors, validate, clearFieldError } = useFormValidation()
|
||||
const isEditing = ref(false)
|
||||
|
||||
// User Profile Data Management
|
||||
|
|
@ -23,17 +24,37 @@ const userData = ref({
|
|||
firstName: currentUser.value.firstName,
|
||||
lastName: currentUser.value.lastName,
|
||||
email: currentUser.value.email,
|
||||
phone: '081-234-5678',
|
||||
phone: '0812345678',
|
||||
joinDate: '12 ธ.ค. 2024',
|
||||
studentId: 'STU 68203',
|
||||
photoURL: '', // Added missing property
|
||||
prefix: 'นาย' // Added missing property
|
||||
photoURL: '',
|
||||
prefix: 'นาย'
|
||||
})
|
||||
|
||||
// Password Form (Separate from userData for security/logic)
|
||||
const passwordForm = reactive({
|
||||
currentPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
})
|
||||
|
||||
// Validation Rules
|
||||
const validationRules = {
|
||||
firstName: { rules: { required: true }, label: 'ชื่อ' },
|
||||
lastName: { rules: { required: true }, label: 'นามสกุล' },
|
||||
email: { rules: { required: true, email: true }, label: 'อีเมล' },
|
||||
phone: { rules: { required: true, pattern: /^0[0-9]{8,9}$/ }, label: 'เบอร์โทรศัพท์' },
|
||||
newPassword: { rules: { minLength: 6 }, label: 'รหัสผ่านใหม่' },
|
||||
confirmPassword: { rules: { match: 'newPassword' }, label: 'ยืนยันรหัสผ่าน' }
|
||||
}
|
||||
|
||||
const fileInput = ref<HTMLInputElement | null>(null)
|
||||
|
||||
const toggleEdit = (edit: boolean) => {
|
||||
isEditing.value = edit
|
||||
// Clear errors when toggling modes
|
||||
if(edit === false) {
|
||||
// Logic to reset form if canceling could go here
|
||||
}
|
||||
}
|
||||
|
||||
const triggerUpload = () => {
|
||||
|
|
@ -54,9 +75,20 @@ const handleFileUpload = (event: Event) => {
|
|||
|
||||
// Save Profile Updates (Mock Implementation)
|
||||
const saveProfile = () => {
|
||||
// Combine data for validation
|
||||
const formData = {
|
||||
...userData.value,
|
||||
...passwordForm
|
||||
}
|
||||
|
||||
if (!validate(formData, validationRules)) return
|
||||
|
||||
currentUser.value.firstName = userData.value.firstName
|
||||
currentUser.value.lastName = userData.value.lastName
|
||||
currentUser.value.email = userData.value.email
|
||||
|
||||
// Successful save
|
||||
alert('บันทึกข้อมูลเรียบร้อยแล้ว')
|
||||
isEditing.value = false
|
||||
}
|
||||
</script>
|
||||
|
|
@ -95,7 +127,7 @@ const saveProfile = () => {
|
|||
</div>
|
||||
<div class="pb-2">
|
||||
<h2 class="text-3xl font-black text-white mb-1">{{ userData.firstName }} {{ userData.lastName }}</h2>
|
||||
<p class="text-slate-400 font-bold uppercase tracking-widest text-[10px]">Student ID: STU-88293</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -157,7 +189,7 @@ const saveProfile = () => {
|
|||
<!-- Form Inputs -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-10">
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">คำนำหน้า</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">คำนำหน้า</label>
|
||||
<select v-model="userData.prefix" class="premium-input w-full">
|
||||
<option>นาย</option>
|
||||
<option>นาง</option>
|
||||
|
|
@ -166,21 +198,49 @@ const saveProfile = () => {
|
|||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">ชื่อ</label>
|
||||
<input v-model="userData.firstName" type="text" class="premium-input w-full">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">ชื่อ</label>
|
||||
<input
|
||||
v-model="userData.firstName"
|
||||
type="text"
|
||||
class="premium-input w-full"
|
||||
:class="{ '!border-red-500': errors.firstName }"
|
||||
@input="clearFieldError('firstName')"
|
||||
>
|
||||
<span v-if="errors.firstName" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.firstName }}</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">นามสกุล</label>
|
||||
<input v-model="userData.lastName" type="text" class="premium-input w-full">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">นามสกุล</label>
|
||||
<input
|
||||
v-model="userData.lastName"
|
||||
type="text"
|
||||
class="premium-input w-full"
|
||||
:class="{ '!border-red-500': errors.lastName }"
|
||||
@input="clearFieldError('lastName')"
|
||||
>
|
||||
<span v-if="errors.lastName" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.lastName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">อีเมล</label>
|
||||
<input v-model="userData.email" type="email" class="premium-input w-full">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">อีเมล</label>
|
||||
<input
|
||||
v-model="userData.email"
|
||||
type="email"
|
||||
class="premium-input w-full"
|
||||
:class="{ '!border-red-500': errors.email }"
|
||||
@input="clearFieldError('email')"
|
||||
>
|
||||
<span v-if="errors.email" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.email }}</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">เบอร์โทรศัพท์</label>
|
||||
<input v-model="userData.phone" type="text" class="premium-input w-full">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">เบอร์โทรศัพท์</label>
|
||||
<input
|
||||
v-model="userData.phone"
|
||||
type="text"
|
||||
class="premium-input w-full"
|
||||
:class="{ '!border-red-500': errors.phone }"
|
||||
@input="clearFieldError('phone')"
|
||||
>
|
||||
<span v-if="errors.phone" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.phone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -189,16 +249,30 @@ const saveProfile = () => {
|
|||
<h3 class="text-lg font-black text-white mb-6">ความปลอดภัย</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">รหัสผ่านปัจจุบัน</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">รหัสผ่านปัจจุบัน</label>
|
||||
<input type="password" class="premium-input w-full" placeholder="••••••••">
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">รหัสผ่านใหม่</label>
|
||||
<input type="password" class="premium-input w-full">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">รหัสผ่านใหม่</label>
|
||||
<input
|
||||
v-model="passwordForm.newPassword"
|
||||
type="password"
|
||||
class="premium-input w-full"
|
||||
:class="{ '!border-red-500': errors.newPassword }"
|
||||
@input="clearFieldError('newPassword')"
|
||||
>
|
||||
<span v-if="errors.newPassword" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.newPassword }}</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-400">ยืนยันรหัสผ่านใหม่</label>
|
||||
<input type="password" class="premium-input w-full">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-300">ยืนยันรหัสผ่านใหม่</label>
|
||||
<input
|
||||
v-model="passwordForm.confirmPassword"
|
||||
type="password"
|
||||
class="premium-input w-full"
|
||||
:class="{ '!border-red-500': errors.confirmPassword }"
|
||||
@input="clearFieldError('confirmPassword')"
|
||||
>
|
||||
<span v-if="errors.confirmPassword" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.confirmPassword }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -225,14 +299,14 @@ const saveProfile = () => {
|
|||
}
|
||||
|
||||
.info-group .label {
|
||||
@apply text-xs font-black uppercase tracking-widest text-slate-400 block mb-2;
|
||||
@apply text-xs font-black uppercase tracking-widest text-slate-300 block mb-2;
|
||||
}
|
||||
.info-group .value {
|
||||
@apply text-lg font-bold text-white;
|
||||
}
|
||||
|
||||
.premium-input {
|
||||
@apply bg-slate-100 dark:bg-slate-800/50 border border-slate-300 dark:border-white/5 rounded-2xl px-6 py-3.5 text-slate-900 dark:text-white focus:border-blue-500 outline-none transition-all;
|
||||
@apply bg-slate-100 dark:bg-slate-900 border border-slate-300 dark:border-white/10 rounded-2xl px-6 py-3.5 text-slate-900 dark:text-white focus:border-blue-500 outline-none transition-all placeholder:text-slate-400;
|
||||
}
|
||||
|
||||
.btn-premium-edit {
|
||||
|
|
@ -240,7 +314,7 @@ const saveProfile = () => {
|
|||
}
|
||||
|
||||
.btn-upload {
|
||||
@apply px-6 py-2.5 bg-white dark:bg-white text-slate-900 dark:text-slate-900 rounded-xl text-xs font-black hover:bg-blue-50 transition-all;
|
||||
@apply px-6 py-2.5 bg-blue-600 text-white rounded-xl text-xs font-black hover:bg-blue-500 transition-all shadow-lg shadow-blue-600/20;
|
||||
}
|
||||
|
||||
.btn-save-premium {
|
||||
|
|
@ -248,7 +322,7 @@ const saveProfile = () => {
|
|||
}
|
||||
|
||||
.btn-cancel-premium {
|
||||
@apply bg-slate-200 dark:bg-slate-800 text-slate-900 dark:text-slate-400 rounded-2xl py-4 font-black hover:bg-slate-300 dark:hover:bg-slate-700 dark:hover:text-white transition-all;
|
||||
@apply bg-slate-200 dark:bg-slate-700 text-slate-900 dark:text-white rounded-2xl py-4 font-black hover:bg-slate-300 dark:hover:bg-slate-600 transition-all;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue