Skip to content

Commit a3c76ac

Browse files
blog: support multiple authors for blog articles
Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
1 parent 2e6a3b5 commit a3c76ac

File tree

8 files changed

+119
-80
lines changed

8 files changed

+119
-80
lines changed

apps/web/content-collections.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const articles = defineCollection({
8686
display_title: z.string().optional(),
8787
meta_title: z.string().optional(),
8888
meta_description: z.string().optional(),
89-
author: z.string(),
89+
author: z.union([z.string(), z.array(z.string())]),
9090
date: z.string(),
9191
coverImage: z.string().optional(),
9292
featured: z.boolean().optional(),
@@ -122,7 +122,8 @@ const articles = defineCollection({
122122

123123
const slug = document._meta.path.replace(/\.mdx$/, "");
124124

125-
const author = document.author || "Char Team";
125+
const rawAuthor = document.author || "Char Team";
126+
const author = Array.isArray(rawAuthor) ? rawAuthor : [rawAuthor];
126127
const title = document.display_title || document.meta_title;
127128

128129
return {

apps/web/netlify/edge-functions/og.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,8 @@ function getAuthorAvatar(author: string): string {
443443
}
444444

445445
function renderBlogTemplate(params: z.infer<typeof blogSchema>) {
446-
const avatarUrl = getAuthorAvatar(params.author);
446+
const firstAuthor = params.author.split(",")[0]?.trim() || params.author;
447+
const avatarUrl = getAuthorAvatar(firstAuthor);
447448

448449
return (
449450
<div

apps/web/src/functions/github-content.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ function getDefaultFrontmatter(folder: string): string {
110110
meta_title: ""
111111
display_title: ""
112112
meta_description: ""
113-
author: "John Jeong"
113+
author:
114+
- "John Jeong"
114115
featured: false
115116
category: "Case Study"
116117
date: "${today}"
@@ -1299,7 +1300,7 @@ export async function savePublishedArticleToBranch(
12991300
_metadata: {
13001301
meta_title?: string;
13011302
display_title?: string;
1302-
author?: string;
1303+
author?: string | string[];
13031304
},
13041305
): Promise<{
13051306
success: boolean;
@@ -1417,7 +1418,7 @@ export async function publishArticle(
14171418
branchName: string,
14181419
metadata: {
14191420
meta_title?: string;
1420-
author?: string;
1421+
author?: string | string[];
14211422
date?: string;
14221423
category?: string;
14231424
},
@@ -1435,7 +1436,7 @@ export async function publishArticle(
14351436
const body = `## Article ${statusText}
14361437
14371438
**Title:** ${metadata.meta_title || "Untitled"}
1438-
**Author:** ${metadata.author || "Unknown"}
1439+
**Author:** ${Array.isArray(metadata.author) ? metadata.author.join(", ") : (metadata.author || "Unknown")}
14391440
**Date:** ${metadata.date || "Not set"}
14401441
**Category:** ${metadata.category || "Uncategorized"}
14411442

apps/web/src/routes/_view/blog/$slug.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ export const Route = createFileRoute("/_view/blog/$slug")({
2525
const relatedArticles = allArticles
2626
.filter((a) => a.slug !== article.slug)
2727
.sort((a, b) => {
28-
const aScore = a.author === article.author ? 1 : 0;
29-
const bScore = b.author === article.author ? 1 : 0;
28+
const aScore = a.author.some((name: string) => article.author.includes(name)) ? 1 : 0;
29+
const bScore = b.author.some((name: string) => article.author.includes(name)) ? 1 : 0;
3030
if (aScore !== bScore) {
3131
return bScore - aScore;
3232
}
@@ -49,7 +49,7 @@ export const Route = createFileRoute("/_view/blog/$slug")({
4949
const metaDescription = article.meta_description ?? "";
5050
const ogImage =
5151
article.coverImage ||
52-
`https://hyprnote.com/og?type=blog&title=${encodeURIComponent(title)}${article.author ? `&author=${encodeURIComponent(article.author)}` : ""}${article.date ? `&date=${encodeURIComponent(new Date(article.date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }))}` : ""}&v=1`;
52+
`https://hyprnote.com/og?type=blog&title=${encodeURIComponent(title)}${article.author.length > 0 ? `&author=${encodeURIComponent(article.author.join(", "))}` : ""}${article.date ? `&date=${encodeURIComponent(new Date(article.date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }))}` : ""}&v=1`;
5353

5454
return {
5555
meta: [
@@ -77,8 +77,8 @@ export const Route = createFileRoute("/_view/blog/$slug")({
7777
content: metaDescription,
7878
},
7979
{ name: "twitter:image", content: ogImage },
80-
...(article.author
81-
? [{ name: "author", content: article.author }]
80+
...(article.author.length > 0
81+
? [{ name: "author", content: article.author.join(", ") }]
8282
: []),
8383
{
8484
property: "article:published_time",
@@ -114,8 +114,6 @@ function Component() {
114114
}
115115

116116
function HeroSection({ article }: { article: any }) {
117-
const avatarUrl = AUTHOR_AVATARS[article.author];
118-
119117
return (
120118
<header className="py-12 lg:py-16 text-center px-4">
121119
<Link
@@ -136,16 +134,23 @@ function HeroSection({ article }: { article: any }) {
136134
{article.title}
137135
</h1>
138136

139-
{article.author && (
137+
{article.author.length > 0 && (
140138
<div className="flex items-center justify-center gap-3 mb-2">
141-
{avatarUrl && (
142-
<img
143-
src={avatarUrl}
144-
alt={article.author}
145-
className="w-8 h-8 rounded-full object-cover"
146-
/>
147-
)}
148-
<p className="text-base text-neutral-600">{article.author}</p>
139+
{article.author.map((name: string) => {
140+
const avatarUrl = AUTHOR_AVATARS[name];
141+
return (
142+
<div key={name} className="flex items-center gap-2">
143+
{avatarUrl && (
144+
<img
145+
src={avatarUrl}
146+
alt={name}
147+
className="w-8 h-8 rounded-full object-cover"
148+
/>
149+
)}
150+
<p className="text-base text-neutral-600">{name}</p>
151+
</div>
152+
);
153+
})}
149154
</div>
150155
)}
151156

apps/web/src/routes/_view/blog/index.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ function MostRecentFeaturedCard({ article }: { article: Article }) {
361361
const [coverImageLoaded, setCoverImageLoaded] = useState(false);
362362
const hasCoverImage = !coverImageError;
363363
const displayDate = article.date;
364-
const avatarUrl = AUTHOR_AVATARS[article.author];
364+
const avatarUrl = Array.isArray(article.author) && article.author.length > 0 ? AUTHOR_AVATARS[article.author[0]] : undefined;
365365

366366
return (
367367
<Link
@@ -410,11 +410,11 @@ function MostRecentFeaturedCard({ article }: { article: Article }) {
410410
{avatarUrl && (
411411
<img
412412
src={avatarUrl}
413-
alt={article.author}
413+
alt={Array.isArray(article.author) ? article.author.join(", ") : article.author}
414414
className="w-6 h-6 rounded-full object-cover"
415415
/>
416416
)}
417-
<span>{article.author}</span>
417+
<span>{Array.isArray(article.author) ? article.author.join(", ") : article.author}</span>
418418
<span>·</span>
419419
<time dateTime={displayDate}>
420420
{new Date(displayDate).toLocaleDateString("en-US", {
@@ -441,7 +441,7 @@ function OtherFeaturedCard({
441441
const [coverImageLoaded, setCoverImageLoaded] = useState(false);
442442
const hasCoverImage = !coverImageError;
443443
const displayDate = article.date;
444-
const avatarUrl = AUTHOR_AVATARS[article.author];
444+
const avatarUrl = Array.isArray(article.author) && article.author.length > 0 ? AUTHOR_AVATARS[article.author[0]] : undefined;
445445

446446
return (
447447
<Link
@@ -507,11 +507,11 @@ function OtherFeaturedCard({
507507
{avatarUrl && (
508508
<img
509509
src={avatarUrl}
510-
alt={article.author}
510+
alt={Array.isArray(article.author) ? article.author.join(", ") : article.author}
511511
className="w-5 h-5 rounded-full object-cover"
512512
/>
513513
)}
514-
<span className="truncate">{article.author}</span>
514+
<span className="truncate">{Array.isArray(article.author) ? article.author.join(", ") : article.author}</span>
515515
<span>·</span>
516516
<time dateTime={displayDate} className="shrink-0">
517517
{new Date(displayDate).toLocaleDateString("en-US", {
@@ -528,7 +528,7 @@ function OtherFeaturedCard({
528528

529529
function ArticleListItem({ article }: { article: Article }) {
530530
const displayDate = article.date;
531-
const avatarUrl = AUTHOR_AVATARS[article.author];
531+
const avatarUrl = Array.isArray(article.author) && article.author.length > 0 ? AUTHOR_AVATARS[article.author[0]] : undefined;
532532

533533
return (
534534
<Link
@@ -551,12 +551,12 @@ function ArticleListItem({ article }: { article: Article }) {
551551
{avatarUrl && (
552552
<img
553553
src={avatarUrl}
554-
alt={article.author}
554+
alt={Array.isArray(article.author) ? article.author.join(", ") : article.author}
555555
className="w-5 h-5 rounded-full object-cover"
556556
/>
557557
)}
558558
<span className="text-sm text-neutral-500 whitespace-nowrap">
559-
{article.author}
559+
{Array.isArray(article.author) ? article.author.join(", ") : article.author}
560560
</span>
561561
</div>
562562
</div>
@@ -570,7 +570,7 @@ function ArticleListItem({ article }: { article: Article }) {
570570
{avatarUrl && (
571571
<img
572572
src={avatarUrl}
573-
alt={article.author}
573+
alt={Array.isArray(article.author) ? article.author.join(", ") : article.author}
574574
className="w-5 h-5 rounded-full object-cover"
575575
/>
576576
)}

apps/web/src/routes/_view/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1736,7 +1736,7 @@ function BlogSection() {
17361736
{sortedArticles.map((article) => {
17371737
const ogImage =
17381738
article.coverImage ||
1739-
`https://hyprnote.com/og?type=blog&title=${encodeURIComponent(article.title ?? "")}${article.author ? `&author=${encodeURIComponent(article.author)}` : ""}${article.date ? `&date=${encodeURIComponent(new Date(article.date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }))}` : ""}&v=1`;
1739+
`https://hyprnote.com/og?type=blog&title=${encodeURIComponent(article.title ?? "")}${article.author.length > 0 ? `&author=${encodeURIComponent(article.author.join(", "))}` : ""}${article.date ? `&date=${encodeURIComponent(new Date(article.date).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }))}` : ""}&v=1`;
17401740

17411741
return (
17421742
<Link

0 commit comments

Comments
 (0)