feat: add sorting by likes/plays and display stats on model profiles

- Added "Most Liked" and "Most Played" sorting options to video listing
- Display total likes and plays on model profile pages
- Show individual video like/play counts on model profile video cards
- Added i18n translation keys for new sort options

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Valknar XXX
2025-10-28 10:37:16 +01:00
parent 51dd7a159a
commit 54f0758196
3 changed files with 43 additions and 42 deletions

View File

@@ -274,6 +274,8 @@ export default {
trending: "Trending", trending: "Trending",
recent: "Most Recent", recent: "Most Recent",
popular: "Most Liked", popular: "Most Liked",
most_liked: "Most Liked",
most_played: "Most Played",
duration: "By Duration", duration: "By Duration",
name: "A-Z", name: "A-Z",
}, },

View File

@@ -27,6 +27,14 @@ let images = $derived(
thumbnail: getAssetUrl(p.id, "thumbnail"), thumbnail: getAssetUrl(p.id, "thumbnail"),
})), })),
); );
// Calculate total likes and plays from all videos
let totalLikes = $derived(
data.videos.reduce((sum, video) => sum + (video.likes_count || 0), 0)
);
let totalPlays = $derived(
data.videos.reduce((sum, video) => sum + (video.plays_count || 0), 0)
);
</script> </script>
<Meta <Meta
@@ -171,32 +179,26 @@ let images = $derived(
<!-- Stats --> <!-- Stats -->
<div <div
class="grid grid-cols-2 md:grid-cols-5 gap-4 mt-6 pt-6 border-t border-border/50" class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6 pt-6 border-t border-border/50"
> >
<!-- <div class="text-center">
<div class="text-2xl font-bold text-primary">
{data.model.subscribers}
</div>
<div class="text-sm text-muted-foreground">Followers</div>
</div> -->
<div class="text-center"> <div class="text-center">
<div class="text-2xl font-bold text-primary"> <div class="text-2xl font-bold text-primary">
{data.videos.length} {data.videos.length}
</div> </div>
<div class="text-sm text-muted-foreground">{$_('models.videos')}</div> <div class="text-sm text-muted-foreground">{$_('models.videos')}</div>
</div> </div>
<!-- <div class="text-center"> <div class="text-center">
<div class="text-2xl font-bold text-primary"> <div class="text-2xl font-bold text-primary">
{data.model.stats.totalViews} {totalLikes.toLocaleString()}
</div> </div>
<div class="text-sm text-muted-foreground">Total Views</div> <div class="text-sm text-muted-foreground">Total Likes</div>
</div> --> </div>
<!-- <div class="text-center"> <div class="text-center">
<div class="text-2xl font-bold text-primary"> <div class="text-2xl font-bold text-primary">
{data.model.stats.likes} {totalPlays.toLocaleString()}
</div>
<div class="text-sm text-muted-foreground">Total Plays</div>
</div> </div>
<div class="text-sm text-muted-foreground">Likes</div>
</div> -->
<div class="text-center"> <div class="text-center">
<div class="text-2xl font-bold text-primary"> <div class="text-2xl font-bold text-primary">
{data.commentsCount} {data.commentsCount}
@@ -267,15 +269,18 @@ let images = $derived(
> >
{video.title} {video.title}
</h3> </h3>
<!-- <div <div
class="flex items-center justify-between text-sm text-muted-foreground" class="flex items-center justify-between text-sm text-muted-foreground"
> >
<span>{video.views} views</span>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<HeartIcon class="w-4 h-4" /> <span class="icon-[ri--play-fill] w-4 h-4"></span>
{video.likes} {video.plays_count || 0}
</div>
<div class="flex items-center gap-1">
<span class="icon-[ri--heart-fill] w-4 h-4"></span>
{video.likes_count || 0}
</div>
</div> </div>
</div> -->
</CardContent> </CardContent>
</Card> </Card>
{/each} {/each}

View File

@@ -17,7 +17,7 @@ import { formatVideoDuration } from "$lib/utils";
const timeAgo = new TimeAgo("en"); const timeAgo = new TimeAgo("en");
let searchQuery = $state(""); let searchQuery = $state("");
let sortBy = $state("trending"); let sortBy = $state("recent");
let categoryFilter = $state("all"); let categoryFilter = $state("all");
let durationFilter = $state("all"); let durationFilter = $state("all");
@@ -42,20 +42,14 @@ const filteredVideos = $derived(() => {
return matchesSearch && matchesCategory && matchesDuration; return matchesSearch && matchesCategory && matchesDuration;
}) })
.sort((a, b) => { .sort((a, b) => {
// if (sortBy === "trending")
// return (
// parseInt(b.views.replace(/[^\d]/g, "")) -
// parseInt(a.views.replace(/[^\d]/g, ""))
// );
if (sortBy === "recent") if (sortBy === "recent")
return ( return (
new Date(b.upload_date).getTime() - new Date(a.upload_date).getTime() new Date(b.upload_date).getTime() - new Date(a.upload_date).getTime()
); );
// if (sortBy === "popular") if (sortBy === "most_liked")
// return ( return (b.likes_count || 0) - (a.likes_count || 0);
// parseInt(b.likes.replace(/[^\d]/g, "")) - if (sortBy === "most_played")
// parseInt(a.likes.replace(/[^\d]/g, "")) return (b.plays_count || 0) - (a.plays_count || 0);
// );
if (sortBy === "duration") return b.movie.duration - a.movie.duration; if (sortBy === "duration") return b.movie.duration - a.movie.duration;
return a.title.localeCompare(b.title); return a.title.localeCompare(b.title);
}); });
@@ -175,23 +169,23 @@ const filteredVideos = $derived(() => {
<SelectTrigger <SelectTrigger
class="w-full lg:w-48 bg-background/50 border-primary/20 focus:border-primary" class="w-full lg:w-48 bg-background/50 border-primary/20 focus:border-primary"
> >
{sortBy === 'trending' {sortBy === 'recent'
? $_('videos.sort.trending')
: sortBy === 'recent'
? $_('videos.sort.recent') ? $_('videos.sort.recent')
: sortBy === 'popular' : sortBy === 'most_liked'
? $_('videos.sort.popular') ? $_('videos.sort.most_liked')
: sortBy === 'most_played'
? $_('videos.sort.most_played')
: sortBy === 'duration' : sortBy === 'duration'
? $_('videos.sort.duration') ? $_('videos.sort.duration')
: $_('videos.sort.name')} : $_('videos.sort.name')}
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="trending"
>{$_('videos.sort.trending')}</SelectItem
>
<SelectItem value="recent">{$_('videos.sort.recent')}</SelectItem> <SelectItem value="recent">{$_('videos.sort.recent')}</SelectItem>
<SelectItem value="popular" <SelectItem value="most_liked"
>{$_('videos.sort.popular')}</SelectItem >{$_('videos.sort.most_liked')}</SelectItem
>
<SelectItem value="most_played"
>{$_('videos.sort.most_played')}</SelectItem
> >
<SelectItem value="duration" <SelectItem value="duration"
>{$_('videos.sort.duration')}</SelectItem >{$_('videos.sort.duration')}</SelectItem