Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | import React from "react";
import { Newspaper } from "lucide-react";
import lozad from "lozad";
import RelatedCard from "@/components/RelatedCard";
import * as style from "./index.module.scss";
import { isBrowser } from "@/utils";
export type AllPost = {
title: string;
tags: string[];
date: string;
headerImage?: string;
slug: string;
};
const MAX_RELATED = 6;
const RelatedPosts = ({
title,
tags,
allPosts = [],
}: {
title: string;
tags: readonly (string | undefined)[];
allPosts: AllPost[];
}) => {
React.useEffect(() => {
if (isBrowser()) {
const observer = lozad(".lozad", {
rootMargin: "10px 0px",
threshold: 0.1,
enableAutoReload: true,
loaded(el) {
el.classList.add("loaded");
},
});
observer.observe();
}
}, []);
const currentTags = new Set(tags.filter(Boolean) as string[]);
const scored = allPosts
.filter((post) => post.title !== title)
.map((post) => {
let score = 0;
if (post.tags) {
for (const t of post.tags) {
if (currentTags.has(t)) score++;
}
}
return { post, score };
})
.filter(({ score }) => score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, MAX_RELATED);
if (scored.length === 0) return null;
return (
<div className={style.relatedPosts}>
<h2>
<Newspaper
size={18}
aria-hidden="true"
style={{ verticalAlign: "-0.125em" }}
/>
Related Posts
</h2>
{scored.map(({ post }) => (
<div key={post.slug}>
<RelatedCard
title={post.title}
tags={post.tags}
date={post.date}
headerImage={post.headerImage}
url={post.slug}
/>
</div>
))}
</div>
);
};
export default RelatedPosts;
|