Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UXIT-2349] FFDW Add Author Bio #1277

Merged
merged 12 commits into from
Mar 20, 2025
15 changes: 15 additions & 0 deletions apps/ffdweb-site/src/app/digest/[slug]/components/AuthorsBio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { formatAuthors } from '@filecoin-foundation/utils/formatAuthors'
import type { AuthorExtended } from '@filecoin-foundation/utils/types/authorTypes'

type AuthorBioProps = {
authors: Array<AuthorExtended>
}

export function AuthorsBio({ authors }: AuthorBioProps) {
return (
<div className="flex flex-col gap-2 sm:w-2/3">
<h2 className="text-base font-bold">{formatAuthors({ authors })}</h2>
<p className="prose">{authors.map((author) => author.bio).join(' ')}</p>
</div>
)
}
4 changes: 4 additions & 0 deletions apps/ffdweb-site/src/app/digest/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { DigestArticleHeader } from '@filecoin-foundation/ui/DigestArticleHeader
import { PageLayout } from '@filecoin-foundation/ui/PageLayout'
import { ShareArticle } from '@filecoin-foundation/ui/ShareArticle'
import { StructuredDataScript } from '@filecoin-foundation/ui/StructuredDataScript'
import { formatAuthors } from '@filecoin-foundation/utils/formatAuthors'
import { type SlugParams } from '@filecoin-foundation/utils/types/paramsTypes'

import { PATHS } from '@/constants/paths'
Expand All @@ -19,6 +20,7 @@ import {
getDigestArticlesData,
} from '../utils/getDigestArticleData'

import { AuthorsBio } from './components/AuthorsBio'
import { generateStructuredData } from './utils/generateStructuredData'

type DigestArticleProps = {
Expand All @@ -30,6 +32,7 @@ export default async function DigestArticle(props: DigestArticleProps) {
const data = await getDigestArticleData(slug)

const { title, issueNumber, articleNumber, image, authors, content } = data
const hasAuthorBio = authors.some((author) => author.bio)

return (
<PageLayout>
Expand All @@ -46,6 +49,7 @@ export default async function DigestArticle(props: DigestArticleProps) {
}}
/>
{content && <MarkdownContent>{content}</MarkdownContent>}
{hasAuthorBio && <AuthorsBio authors={authors} />}
<ShareArticle
articleTitle={title}
path={`${PATHS.DIGEST.path}/${slug}`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ authors:
company: Starling Lab
image:
src: /assets/headshots/Adam_Rose.webp
bio: Adam Rose is the chief operating officer at Starling Lab, and serves as press rights chair for the Los Angeles Press Club.
- first-name: Basile
last-name: Simon
company: Starling Lab, Airwars
image:
src: /assets/headshots/Basile_Simon.webp
# bio: "Adam Rose is the chief operating officer at Starling Lab, and serves as press rights chair for the Los Angeles Press Club. Basile Simon leads the Lab’s research in law and criminal accountability, and is co-founder and advisor to Airwars. Both have spent most of their careers in journalism."
bio: Basile Simon leads the Lab’s research in law and criminal accountability, and is co-founder and advisor to Airwars. Both have spent most of their careers in journalism.
seo:
description: "From ancient clay tablets to modern blockchains, discover how new technologies are preserving crucial digital evidence of war crimes, human rights violations, and historical events for future generations."
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: Data Transfer Initiative
image:
src: /assets/headshots/Chris_Riley.webp
# bio: Chris Riley is the executive director of the nonprofit Data Transfer Initiative and a distinguished research fellow at the Annenberg Public Policy Center at the University of Pennsylvania; he holds a Ph.D. in computer science from Johns Hopkins University and a J.D. from Yale Law School.
bio: Chris Riley is the executive director of the nonprofit Data Transfer Initiative and a distinguished research fellow at the Annenberg Public Policy Center at the University of Pennsylvania; he holds a Ph.D. in computer science from Johns Hopkins University and a J.D. from Yale Law School.
seo:
description: Explore how data portability and unrestricted data flows enable true decentralization. Learn why reciprocal data transfer policies and user control are essential for decentralized systems.
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: Techdirt, Copia Institute
image:
src: /assets/headshots/Mike_Masnick.webp
# bio: Mike Masnick is the founder & editor of the popular Techdirt blog as well as the founder of the Silicon Valley think tank, the Copia Institute. In both roles, he explores the intersection of technology,innovation, policy, law, civil liberties, and economics.
bio: Mike Masnick is the founder & editor of the popular Techdirt blog as well as the founder of the Silicon Valley think tank, the Copia Institute. In both roles, he explores the intersection of technology,innovation, policy, law, civil liberties, and economics.
seo:
description: Discover how blending centralized infrastructure with decentralized innovation can transform technology, healthcare, and education, creating more efficient and adaptable systems.
---
Expand Down
2 changes: 1 addition & 1 deletion apps/ffdweb-site/src/content/digest/editors-letter.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: Techdirt, Copia Institute
image:
src: /assets/headshots/Mike_Masnick.webp
# bio: Mike Masnick is the founder & editor of the popular Techdirt blog as well as the founder of the Silicon Valley think tank, the Copia Institute. In both roles, he explores the intersection of technology, innovation, policy, law, civil liberties, and economics.
bio: Mike Masnick is the founder & editor of the popular Techdirt blog as well as the founder of the Silicon Valley think tank, the Copia Institute. In both roles, he explores the intersection of technology, innovation, policy, law, civil liberties, and economics.
seo:
description: "Mike Masnick introduces a magazine exploring decentralization's impact on cognitive liberty, privacy, blockchain, and the web's future through expert perspectives."
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ authors:
company: Fight for the Future, Quiet
image:
src: /assets/headshots/Holmes_Wilson.webp
# bio: Holmes Wilson is a co-founder of Fight for the Future and Quiet, a decentralized alternative to Slack and Discord built on Tor and IPFS.
bio: Holmes Wilson is a co-founder of Fight for the Future and Quiet, a decentralized alternative to Slack and Discord built on Tor and IPFS.
seo:
description: While free software has become ubiquitous, its goal of user control remains elusive due to cloud service dependencies. The solution lies in decentralization - making operational power as accessible as the code itself.
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: Blockchain Association
image:
src: /assets/headshots/Kristin_Smith.webp
# bio: "Kristin is CEO of Blockchain Association, the Washington, D.C.-based trade association representing more than 100 of the industry’s leading companies."
bio: "Kristin is CEO of Blockchain Association, the Washington, D.C.-based trade association representing more than 100 of the industry’s leading companies."
seo:
description: "Explore how different regions approach crypto regulation: from US enforcement actions to EU's MiCA legislation and China's CBDC. Learn how global policies shape the future of decentralized technology."
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: "Filecoin Foundation"
image:
src: /assets/headshots/Kurt_Opsahl.webp
# bio: Kurt Opsahl works to help build the legal and policy space in which the decentralized web can thrive.
bio: Kurt Opsahl works to help build the legal and policy space in which the decentralized web can thrive.
seo:
description: Explore why protecting code as a form of free speech is essential for software development, open-source projects, and the future of the decentralized web. Learn about landmark legal cases and global implications.
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: Digital Medusa
image:
src: /assets/headshots/Farzaneh_Badiei.webp
# bio: Farzaneh Badiei is a recovering academic and founded Digital Medusa to petrify the enemies of a global, interoperable Internet.
bio: Farzaneh Badiei is a recovering academic and founded Digital Medusa to petrify the enemies of a global, interoperable Internet.
seo:
description: Internet decentralization needs smart governance, not complex tech. Learn how practical steps and collective action can restore a more distributed digital infrastructure.
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: Filecoin Foundation for the Decentralized Web
image:
src: /assets/headshots/Danny_OBrien.webp
# bio: "Danny O'Brien is Senior Fellow and DWeb Strategy at Filecoin and tech journalist, developer and defender of online free speech, privacy and an open internet for more than 20 years, including over a decade's activism at the Electronic Frontier Foundation."
bio: "Danny O'Brien is Senior Fellow and DWeb Strategy at Filecoin and tech journalist, developer and defender of online free speech, privacy and an open internet for more than 20 years, including over a decade's activism at the Electronic Frontier Foundation."
seo:
description: Explore how personal technology and digital rights protect our fundamental freedom to think, learn, and grow independently in an increasingly centralized digital world.
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: DWeb Projects, COMPOST magazine, Hypha Worker Co-op
image:
src: /assets/headshots/Mai_Ishikawa_Sutton.webp
# bio: "Mai Ishikawa Sutton is a senior organizer with DWeb projects, co-founder of Distributed.Press and COMPOST magazine, and contributor to Hypha Worker Co-op."
bio: Mai Ishikawa Sutton is a senior organizer with DWeb projects, co-founder of Distributed.Press and COMPOST magazine, and contributor to Hypha Worker Co-op.
seo:
description: "Comparing DWeb and Web3's approaches to decentralization, focusing on the key question: who designs, controls, and benefits from these technologies?"
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: craphound.com
image:
src: /assets/headshots/Cory_Doctorow.webp
# bio: Cory Doctorow (craphound.com) is a science fiction author, activist and journalist. He is the author of many books, most recently RED TEAM BLUES, a science fiction crime thriller.
bio: Cory Doctorow (craphound.com) is a science fiction author, activist and journalist. He is the author of many books, most recently RED TEAM BLUES, a science fiction crime thriller.
seo:
description: "Digital platforms control users by constantly adjusting their systems while denying users the same power, leading to declining user experience and increased profits."
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors:
company: NBTV.media
image:
src: /assets/headshots/Naomi_Brockwell.webp
# bio: Naomi Brockwell is a tech journalist, creator of NBTV.media, and author of "Beginner's Introduction to Privacy"
bio: Naomi Brockwell is a tech journalist, creator of NBTV.media, and author of "Beginner's Introduction to Privacy"

seo:
description: "Privacy is essential for freedom and democracy. Learn how surveillance threatens our future and why privacy matters - even if you think you have 'nothing to hide.'"
Expand Down
7 changes: 2 additions & 5 deletions packages/ui/src/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import Image from 'next/image'

import { type Author } from '@filecoin-foundation/utils/types/authorTypes'
import { clsx } from 'clsx'

const IMAGE_SIZE = 32
const sharedAvatarStyle = 'rounded-full ring avatar-ring'

export type AvatarProps = {
firstName: string
lastName: string
image?: { src: string }
}
export type AvatarProps = Author

export function Avatar({ firstName, lastName, image }: AvatarProps) {
if (image) {
Expand Down
32 changes: 7 additions & 25 deletions packages/ui/src/AvatarGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Avatar, type AvatarProps } from './Avatar'
import { Avatar } from './Avatar'

type AuthorWithCompany = AvatarProps & {
company: string
}
import { formatAuthors } from '@filecoin-foundation/utils/formatAuthors'
import { type AuthorExtended } from '@filecoin-foundation/utils/types/authorTypes'

export type AvatarGroupProps = {
authors: Array<AuthorWithCompany>
authors: Array<AuthorExtended>
}

export function AvatarGroup({ authors }: AvatarGroupProps) {
Expand All @@ -21,26 +20,9 @@ export function AvatarGroup({ authors }: AvatarGroupProps) {
/>
))}
</div>
<span className="avatar-full-name text-sm">{formatAuthors(authors)}</span>
<span className="avatar-full-name text-sm">
{formatAuthors({ authors, showCompany: true })}
</span>
</div>
)
}

function formatAuthors(authors: Array<AuthorWithCompany>) {
return authors
.map((author, index) => {
const isLastAuthor = index === authors.length - 1
const isSecondToLastAuthor = index === authors.length - 2

let separator = ''
if (isSecondToLastAuthor && authors.length > 1) {
separator = ' & '
} else if (!isLastAuthor) {
separator = ', '
}

return `${author.firstName.trim()} ${author.lastName.trim()} (${author.company.trim()})${separator}`
})
.join('')
.trim()
}
1 change: 1 addition & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"./dateUtils": "./src/dateUtils.ts",
"./fileUtils": "./src/fileUtils.ts",
"./findOrThrow": "./src/findOrThrow.ts",
"./formatAuthors": "./src/formatAuthors.ts",
"./generateBlogPostStructuredData": "./src/generateBlogPostStructuredData.ts",
"./generateSitemap": "./src/generateSitemap.ts",
"./getAllMarkdownData": "./src/getAllMarkdownData.ts",
Expand Down
31 changes: 31 additions & 0 deletions packages/utils/src/formatAuthors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { type AuthorExtended } from '@filecoin-foundation/utils/types/authorTypes'

type FormatAuthorsProps = {
authors: Array<AuthorExtended>
showCompany?: boolean
}

export function formatAuthors({
authors,
showCompany = false,
}: FormatAuthorsProps) {
return authors
.map((author, index) => {
const isLastAuthor = index === authors.length - 1
const isSecondToLastAuthor = index === authors.length - 2

let separator = ''
if (isSecondToLastAuthor && authors.length > 1) {
separator = ' & '
} else if (!isLastAuthor) {
separator = ', '
}

const name = `${author.firstName.trim()} ${author.lastName.trim()}`
return showCompany
? `${name} (${author.company.trim()})${separator}`
: `${name}${separator}`
})
.join('')
.trim()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const DigestArticleFrontmatterSchema = DynamicBaseDataSchema.extend({
'last-name': z.string(),
image: ImagePropsSchema.optional(),
company: z.string(),
bio: z.string().optional(),
}),
),
content: z.string(),
Expand Down
10 changes: 10 additions & 0 deletions packages/utils/src/types/authorTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type Author = {
firstName: string
lastName: string
image?: { src: string }
}

export type AuthorExtended = Author & {
company: string
bio?: string
}