Skip to content

Commit f27f3a9

Browse files
committed
Format links in bios
1 parent 1556b3b commit f27f3a9

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

src/app/conf/2025/_data.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ async function fetchData<T>(url: string): Promise<T> {
2121
"Content-Type": "application/json",
2222
"User-Agent": "GraphQL Conf / GraphQL Foundation",
2323
},
24+
cache: "force-cache",
2425
})
2526
const data = await response.json()
2627
return data
@@ -58,7 +59,7 @@ async function getSpeakers(): Promise<SchedSpeaker[]> {
5859
.map(user => {
5960
return {
6061
...user,
61-
about: stripHtml(user.about).result,
62+
about: preprocessDescription(user.about),
6263
}
6364
})
6465
.sort((a, b) => {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from "react"
2+
3+
const URL_REGEX = /https?:\/\/[^\s]+/g
4+
5+
export function formatDescription(text: string): React.ReactNode {
6+
const res: React.ReactNode[] = []
7+
8+
let lastIndex = 0
9+
let match: RegExpExecArray | null
10+
11+
while ((match = URL_REGEX.exec(text)) !== null) {
12+
if (match.index > lastIndex) {
13+
res.push(text.slice(lastIndex, match.index))
14+
}
15+
16+
res.push(
17+
<a
18+
href={match[0]}
19+
target="_blank"
20+
rel="noopener noreferrer"
21+
className="typography-link"
22+
>
23+
{match[0].replace(/^https?:\/\//, "")}
24+
</a>,
25+
)
26+
27+
lastIndex = match.index + match[0].length
28+
}
29+
30+
if (lastIndex < text.length) {
31+
res.push(text.slice(lastIndex))
32+
}
33+
34+
return <>{res}</>
35+
}

src/app/conf/2025/schedule/[id]/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { GET_TICKETS_LINK } from "../../links"
2121
import { CtaCardSection } from "../../components/cta-card-section"
2222
import { Button } from "@/app/conf/_design-system/button"
2323
import { SessionTags } from "../../components/session-tags"
24+
import { formatDescription } from "./format-description"
2425

2526
type SessionProps = { params: { id: string } }
2627

@@ -237,13 +238,13 @@ function Hr({ className }: { className?: string }) {
237238
}
238239

239240
function SessionDescription({ session }: { session: ScheduleSession }) {
241+
const formattedDescription = formatDescription(session.description || "")
240242

241-
242243
return (
243244
<div className="mt-8 flex gap-4 px-2 pb-8 max-lg:flex-col sm:px-3 lg:mt-16 lg:gap-8 xl:pb-16">
244245
<h3 className="typography-h2 min-w-[320px]">Session description</h3>
245246
<p className="typography-body-lg whitespace-pre-wrap">
246-
{session.description}
247+
{formattedDescription}
247248
</p>
248249
</div>
249250
)

0 commit comments

Comments
 (0)