Skip to content

blog: support multiple authors for blog articles#3965

Open
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1771056066-blog-author-list
Open

blog: support multiple authors for blog articles#3965
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1771056066-blog-author-list

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 14, 2026

blog: support multiple authors for blog articles

Summary

Changes the blog author field from a single string to an array of strings throughout the stack:

  • Schema (content-collections.ts): Accepts both string and string[] via z.union, normalizes to string[] in the transform for backward compatibility with existing articles
  • Admin UI: Rewrites AuthorSelect from a single-select dropdown to a multi-select with toggle behavior, checkmarks, and × remove buttons
  • Blog display ($slug.tsx): Renders multiple author avatars + names in the hero section; related article sorting uses some/includes overlap instead of strict equality
  • Blog listing (index.tsx, _view/index.tsx): Shows first author's avatar in card views, joins all names with commas for display text
  • Save API (save.ts): Outputs author as a YAML list in buildFrontmatter
  • GitHub content (github-content.ts): Updates default frontmatter template, function signatures, and PR body generation
  • OG image (og.tsx): Splits comma-joined author param to resolve first author's avatar

Review & Testing Checklist for Human

  • Test the admin multi-select UI: Open the admin collections editor, verify you can select/deselect multiple authors, that the × remove buttons work, and the dropdown closes on outside click. This was not visually tested.
  • Verify Google Docs import doesn't double-wrap authors: In FileEditor (line ~2720), setAuthor([data.frontmatter.author]) always wraps in an array — if the imported YAML already has an array-format author, this could produce [["name"]]. Test importing a doc.
  • Confirm existing single-author articles render correctly: The z.union + Array.isArray normalization handles backward compat, but verify a few existing articles load without errors on both the blog listing and individual article pages.
  • Check blog listing card design: Cards intentionally show only the first author's avatar but join all names as text — confirm this looks acceptable for multi-author posts.
  • Verify the OG image still generates: The blogSchema in og.tsx still expects author: z.string() (unchanged), and the caller now passes article.author.join(", "). Confirm OG images render correctly for articles.

Notes

Requested by: @ComputelessComputer
Link to Devin run


Open with Devin

Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@netlify
Copy link

netlify bot commented Feb 14, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit e141565
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/699032781bd08d0008f37324

@netlify
Copy link

netlify bot commented Feb 14, 2026

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit e141565
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/699032788d34880008af9abc
😎 Deploy Preview https://deploy-preview-3965--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Array rendered directly as text in mobile view of ArticleListItem

In the mobile view (sm:hidden) of ArticleListItem, article.author (now a string[]) is rendered directly inside a <span> without .join(). React renders arrays by concatenating elements without separators, so ["John Jeong", "Yujong Lee"] would display as John JeongYujong Lee instead of John Jeong, Yujong Lee.

Root Cause

At apps/web/src/routes/_view/blog/index.tsx:577, the code reads:

<span className="text-sm text-neutral-500">{article.author}</span>

This was not updated to use .join(", ") like the other occurrences in the same file (e.g., line 559 and line 417). The desktop view at line 559 correctly uses Array.isArray(article.author) ? article.author.join(", ") : article.author, but this mobile counterpart was missed.

Impact: Multi-author articles display author names concatenated without any separator in the mobile view of the blog listing page.

(Refers to line 577)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

if (data.frontmatter.meta_description)
setMetaDescription(data.frontmatter.meta_description);
if (data.frontmatter.author) setAuthor(data.frontmatter.author);
if (data.frontmatter.author) setAuthor([data.frontmatter.author]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Google Docs import always wraps author in array, risking double-wrapping

When importing from Google Docs in the FileEditor, setAuthor([data.frontmatter.author]) always wraps the returned author value in an array. If the import API ever returns an array-typed author (e.g., from YAML that already has a list), this would produce a nested array like [["name"]].

Root Cause

At apps/web/src/routes/admin/collections/index.tsx:2723:

if (data.frontmatter.author) setAuthor([data.frontmatter.author]);

The ImportResult interface at line 3262 types author as string, so currently this is safe at the TypeScript level. However, the actual API response could contain an array if the source document's YAML frontmatter has a list-format author. The code should normalize defensively, similar to how branchFileData.frontmatter.author is handled at line 2616:

author: Array.isArray(branchFileData.frontmatter.author) ? branchFileData.frontmatter.author : branchFileData.frontmatter.author ? [branchFileData.frontmatter.author] : undefined

Impact: If the Google Docs import returns an array author, the editor state would contain [["name"]] instead of ["name"], causing display and save issues.

Suggested change
if (data.frontmatter.author) setAuthor([data.frontmatter.author]);
if (data.frontmatter.author) setAuthor(Array.isArray(data.frontmatter.author) ? data.frontmatter.author : [data.frontmatter.author]);
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 0 new potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants