feat: related content and featured cross-content sidebar widgets

- Add excludeId arg to videos and articles GraphQL resolvers
- Add excludeId + featured params to getVideos/getArticles services
- Video page: fetch related videos by tag + featured article in parallel
- Article page: fetch related articles by category + featured video in parallel
- Implement sidebar widgets with thumbnails, metadata, hover interactions
- Add videos.related and magazine.related i18n keys
- Seed dummy articles (spotlight, interview, psychology) and videos with
  overlapping tags for testing related content

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 18:35:04 +01:00
parent 6d1726ee97
commit 91951667e3
8 changed files with 251 additions and 85 deletions

View File

@@ -1,18 +1,25 @@
import { error } from "@sveltejs/kit";
import { getCommentsForVideo, getVideoBySlug, getVideoLikeStatus } from "$lib/services.js";
import {
getCommentsForVideo,
getVideoBySlug,
getVideoLikeStatus,
getVideos,
getArticles,
} from "$lib/services.js";
export async function load({ fetch, params, locals }) {
const video = await getVideoBySlug(params.slug, fetch);
const comments = await getCommentsForVideo(video.id, fetch);
let likeStatus = { liked: false };
if (locals.authStatus.authenticated) {
try {
likeStatus = await getVideoLikeStatus(video.id, fetch);
} catch (error) {
console.error("Failed to get like status:", error);
}
}
const [comments, likeStatus, relatedVideos, featuredArticle] = await Promise.all([
getCommentsForVideo(video.id, fetch),
locals.authStatus.authenticated
? getVideoLikeStatus(video.id, fetch).catch(() => ({ liked: false }))
: Promise.resolve({ liked: false }),
video.tags?.length
? getVideos({ tag: video.tags[0], excludeId: video.id, limit: 5 }, fetch)
: Promise.resolve({ items: [], total: 0 }),
getArticles({ featured: true, limit: 1 }, fetch),
]);
try {
return {
@@ -20,6 +27,8 @@ export async function load({ fetch, params, locals }) {
comments,
authStatus: locals.authStatus,
likeStatus,
relatedVideos: relatedVideos.items,
featuredArticle: featuredArticle.items[0] ?? null,
};
} catch {
error(404, "Video not found");