mirror of
https://github.com/ngthanhvu/kr-phim.git
synced 2026-08-10 16:07:47 +00:00
feat: implement movie detail page with multi-source support, library features, and responsive layout
This commit is contained in:
+46
-12
@@ -24,6 +24,36 @@ function watchHistoryLink(item: WatchHistoryItem) {
|
||||
}
|
||||
}
|
||||
|
||||
function formatWatchTime(seconds = 0) {
|
||||
const totalSeconds = Math.max(Math.floor(seconds), 0)
|
||||
const hours = Math.floor(totalSeconds / 3600)
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60)
|
||||
const remainingSeconds = totalSeconds % 60
|
||||
|
||||
if (hours) {
|
||||
return `${hours}:${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
return `${minutes}:${String(remainingSeconds).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
function watchProgressPercent(item: WatchHistoryItem) {
|
||||
if (!item.durationSeconds || !item.progressSeconds) return 6
|
||||
return Math.min(Math.max((item.progressSeconds / item.durationSeconds) * 100, 6), 100)
|
||||
}
|
||||
|
||||
function watchProgressLabel(item: WatchHistoryItem) {
|
||||
if (item.progressSeconds && item.durationSeconds) {
|
||||
return `${formatWatchTime(item.progressSeconds)} / ${formatWatchTime(item.durationSeconds)}`
|
||||
}
|
||||
|
||||
if (item.progressSeconds) {
|
||||
return `${formatWatchTime(item.progressSeconds)} đã xem`
|
||||
}
|
||||
|
||||
return item.episodeName || `Tập ${(item.episodeIndex || 0) + 1}`
|
||||
}
|
||||
|
||||
async function removeHistory() {
|
||||
await clearWatchHistory()
|
||||
historyItems.value = []
|
||||
@@ -46,7 +76,7 @@ useHead({
|
||||
<section class="mx-auto max-w-390 px-4 pb-16 pt-28 sm:px-6 lg:px-8 lg:pt-32 xl:px-10">
|
||||
<div class="mb-6 flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
|
||||
<div>
|
||||
<p class="text-sm font-black uppercase text-sky-300">Thành viên</p>
|
||||
<p class="text-sm font-black uppercase text-emerald-300">Thành viên</p>
|
||||
<h1 class="mt-2 text-3xl font-black sm:text-4xl">Lịch sử xem</h1>
|
||||
</div>
|
||||
<button v-if="historyItems.length" type="button"
|
||||
@@ -57,43 +87,47 @@ useHead({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-6">
|
||||
<div v-if="loading" class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6">
|
||||
<div v-for="item in 12" :key="item" class="aspect-2/3 animate-pulse rounded-md bg-white/10" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="historyItems.length" class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-6">
|
||||
<div v-else-if="historyItems.length" class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6">
|
||||
<NuxtLink v-for="item in historyItems" :key="`${item.source}-${item.slug}`" :to="watchHistoryLink(item)"
|
||||
class="group block min-w-0">
|
||||
<div
|
||||
class="relative aspect-2/3 overflow-hidden rounded-md bg-slate-900 shadow-xl shadow-black/25 ring-1 ring-white/10 transition duration-300 group-hover:-translate-y-1 group-hover:ring-sky-300/60">
|
||||
class="relative aspect-2/3 overflow-hidden rounded-md bg-slate-900 shadow-xl shadow-black/25 ring-1 ring-white/10 transition duration-300 group-hover:-translate-y-1 group-hover:ring-emerald-300/60">
|
||||
<img v-if="item.thumb || item.poster" :src="item.thumb || item.poster" :alt="item.name"
|
||||
class="h-full w-full object-cover transition duration-500 group-hover:scale-105">
|
||||
<div v-else class="grid h-full w-full place-items-center bg-white/8">
|
||||
<Clock3 class="size-10 text-sky-300" />
|
||||
<Clock3 class="size-10 text-emerald-300" />
|
||||
</div>
|
||||
<div class="absolute inset-x-0 bottom-0 h-1 bg-white/18">
|
||||
<span class="block h-full w-1/3 bg-sky-300" />
|
||||
<span class="block h-full bg-emerald-300" :style="{ width: `${watchProgressPercent(item)}%` }" />
|
||||
</div>
|
||||
<span class="absolute left-2 top-2 rounded bg-sky-400 px-2 py-1 text-xs font-black text-slate-950">
|
||||
<span
|
||||
class="absolute bottom-3 right-3 rounded bg-black/70 px-2 py-1 text-[11px] font-black text-white opacity-0 transition group-hover:opacity-100">
|
||||
Xem tiếp
|
||||
</span>
|
||||
<span class="absolute left-2 top-2 rounded bg-emerald-400 px-2 py-1 text-xs font-black text-slate-950">
|
||||
{{ item.episodeName || `Tập ${(item.episodeIndex || 0) + 1}` }}
|
||||
</span>
|
||||
</div>
|
||||
<h2 class="mt-3 truncate text-sm font-black">{{ item.name }}</h2>
|
||||
<p class="mt-1 truncate text-xs font-semibold text-slate-400">
|
||||
{{ item.episodeName || `Tập ${(item.episodeIndex || 0) + 1}` }}
|
||||
<h2 class="mt-3 line-clamp-1 text-center text-sm font-black text-white">{{ item.name }}</h2>
|
||||
<p class="mt-1 truncate text-center text-xs font-semibold text-slate-400">
|
||||
{{ watchProgressLabel(item) }}
|
||||
</p>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div v-else
|
||||
class="flex min-h-80 flex-col items-center justify-center rounded-lg border border-white/10 bg-white/6 p-6 text-center">
|
||||
<Clock3 class="size-12 text-sky-300" />
|
||||
<Clock3 class="size-12 text-emerald-300" />
|
||||
<h2 class="mt-4 text-xl font-black">Chưa có lịch sử xem</h2>
|
||||
<p class="mt-2 max-w-md text-sm leading-6 text-slate-300">
|
||||
Phim bạn đã xem sẽ xuất hiện ở đây để bạn có thể xem tiếp nhanh hơn.
|
||||
</p>
|
||||
<NuxtLink to="/phim"
|
||||
class="mt-5 inline-flex h-11 items-center justify-center rounded-md bg-sky-300 px-5 text-sm font-black text-slate-950 transition hover:bg-white">
|
||||
class="mt-5 inline-flex h-11 items-center justify-center rounded-md bg-emerald-300 px-5 text-sm font-black text-slate-950 transition hover:bg-white">
|
||||
Duyệt phim
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user