feat: Implement course discovery page with API integration, useCourse composable, and CourseCard component.

This commit is contained in:
supalerk-ar66 2026-01-16 10:26:33 +07:00
parent 2ffcc36fe4
commit 1d8acaf7d7
4 changed files with 39 additions and 23 deletions

View file

@ -8,7 +8,7 @@
interface CourseCardProps {
/** Course Title */
title: string
title: string | { th: string; en: string }
/** Difficulty Level (Beginner, Intermediate, etc.) */
level?: string
/** Visual type for level badge (color coding) */
@ -16,7 +16,7 @@ interface CourseCardProps {
/** Course Price (e.g., 'Free', '฿990') */
price?: string
/** Short description */
description?: string
description?: string | { th: string; en: string }
/** Rating score (e.g., '4.8') */
rating?: string
/** Number of lessons */
@ -37,13 +37,23 @@ interface CourseCardProps {
image?: string
}
defineProps<CourseCardProps>()
const props = defineProps<CourseCardProps>()
const emit = defineEmits<{
viewDetails: []
continue: []
viewCertificate: []
}>()
// Helper to get localized text
const getLocalizedText = (text: string | { th: string; en: string } | undefined) => {
if (!text) return ''
if (typeof text === 'string') return text
return text.th || text.en || ''
}
const displayTitle = computed(() => getLocalizedText(props.title))
const displayDescription = computed(() => getLocalizedText(props.description))
</script>
<template>
@ -52,7 +62,7 @@ const emit = defineEmits<{
<div class="thumbnail-wrapper relative h-44 overflow-hidden rounded-t-[1.5rem]">
<img
:src="image || 'https://images.unsplash.com/photo-1498050108023-c5249f4df085?w=400&q=80'"
:alt="title"
:alt="displayTitle"
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"
>
<div v-if="completed" class="absolute inset-0 bg-emerald-600/60 backdrop-blur-[2px] flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
@ -80,10 +90,10 @@ const emit = defineEmits<{
<!-- Content -->
<div class="p-6 flex flex-col flex-1">
<!-- Title -->
<h3 class="font-black text-lg mb-2 line-clamp-1 text-slate-900 dark:text-white group-hover:text-blue-400 transition-colors">{{ title }}</h3>
<h3 class="font-black text-lg mb-2 line-clamp-1 text-slate-900 dark:text-white group-hover:text-blue-400 transition-colors">{{ displayTitle }}</h3>
<!-- Description -->
<div v-if="description" class="text-sm mb-6 line-clamp-2 leading-relaxed text-slate-600 dark:text-slate-400">{{ description }}</div>
<div v-if="displayDescription" class="text-sm mb-6 line-clamp-2 leading-relaxed text-slate-600 dark:text-slate-400">{{ displayDescription }}</div>
<!-- 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">