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:
@@ -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",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user