Ionosphere.tv
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: OG and Twitter meta tags for all pages

- Global: site name, description, metadataBase
- Talk pages: title, speakers, article type
- Speaker pages: name, talk count
- Concept pages: name, description or talk count

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+64
+13
apps/ionosphere/src/app/concepts/[rkey]/page.tsx
··· 1 + import type { Metadata } from "next"; 1 2 import { getConcept, getConcepts, getTalks } from "@/lib/api"; 2 3 import TalksListContent from "@/app/talks/TalksListContent"; 3 4 4 5 export async function generateStaticParams() { 5 6 const { concepts } = await getConcepts(); 6 7 return concepts.map((c: any) => ({ rkey: c.rkey })); 8 + } 9 + 10 + export async function generateMetadata({ params }: { params: Promise<{ rkey: string }> }): Promise<Metadata> { 11 + const { rkey } = await params; 12 + const { concept, talks } = await getConcept(rkey); 13 + const description = concept.description || `${concept.name} — mentioned in ${talks.length} talk${talks.length !== 1 ? "s" : ""} at ATmosphereConf 2026`; 14 + return { 15 + title: `${concept.name} — Ionosphere`, 16 + description, 17 + openGraph: { title: concept.name, description, url: `https://ionosphere.tv/concepts/${rkey}` }, 18 + twitter: { card: "summary", title: concept.name, description }, 19 + }; 7 20 } 8 21 9 22 export default async function ConceptPage({ params }: { params: Promise<{ rkey: string }> }) {
+13
apps/ionosphere/src/app/layout.tsx
··· 6 6 export const metadata: Metadata = { 7 7 title: "Ionosphere", 8 8 description: "Semantically enriched conference video archive for ATmosphereConf 2026", 9 + metadataBase: new URL("https://ionosphere.tv"), 10 + openGraph: { 11 + title: "Ionosphere", 12 + description: "Semantically enriched conference video archive for ATmosphereConf 2026", 13 + url: "https://ionosphere.tv", 14 + siteName: "Ionosphere", 15 + type: "website", 16 + }, 17 + twitter: { 18 + card: "summary", 19 + title: "Ionosphere", 20 + description: "Semantically enriched conference video archive for ATmosphereConf 2026", 21 + }, 9 22 }; 10 23 11 24 export default function RootLayout({ children }: { children: React.ReactNode }) {
+13
apps/ionosphere/src/app/speakers/[rkey]/page.tsx
··· 1 + import type { Metadata } from "next"; 1 2 import { getSpeaker, getSpeakers, getTalks } from "@/lib/api"; 2 3 import TalksListContent from "@/app/talks/TalksListContent"; 3 4 4 5 export async function generateStaticParams() { 5 6 const { speakers } = await getSpeakers(); 6 7 return speakers.map((s: any) => ({ rkey: s.rkey })); 8 + } 9 + 10 + export async function generateMetadata({ params }: { params: Promise<{ rkey: string }> }): Promise<Metadata> { 11 + const { rkey } = await params; 12 + const { speaker, talks } = await getSpeaker(rkey); 13 + const description = `${talks.length} talk${talks.length !== 1 ? "s" : ""} by ${speaker.name} at ATmosphereConf 2026`; 14 + return { 15 + title: `${speaker.name} — Ionosphere`, 16 + description, 17 + openGraph: { title: speaker.name, description, url: `https://ionosphere.tv/speakers/${rkey}` }, 18 + twitter: { card: "summary", title: speaker.name, description }, 19 + }; 7 20 } 8 21 9 22 export default async function SpeakerPage({ params }: { params: Promise<{ rkey: string }> }) {
+25
apps/ionosphere/src/app/talks/[rkey]/page.tsx
··· 1 + import type { Metadata } from "next"; 1 2 import { getTalk, getTalks } from "@/lib/api"; 2 3 import TalkContent from "./TalkContent"; 3 4 4 5 export async function generateStaticParams() { 5 6 const { talks } = await getTalks(); 6 7 return talks.map((t: any) => ({ rkey: t.rkey })); 8 + } 9 + 10 + export async function generateMetadata({ params }: { params: Promise<{ rkey: string }> }): Promise<Metadata> { 11 + const { rkey } = await params; 12 + const { talk, speakers } = await getTalk(rkey); 13 + const speakerNames = speakers.map((s: any) => s.name).join(", "); 14 + const description = speakerNames 15 + ? `${talk.title} by ${speakerNames} — ATmosphereConf 2026` 16 + : `${talk.title} — ATmosphereConf 2026`; 17 + return { 18 + title: `${talk.title} — Ionosphere`, 19 + description, 20 + openGraph: { 21 + title: talk.title, 22 + description, 23 + url: `https://ionosphere.tv/talks/${rkey}`, 24 + type: "article", 25 + }, 26 + twitter: { 27 + card: "summary", 28 + title: talk.title, 29 + description, 30 + }, 31 + }; 7 32 } 8 33 9 34 export default async function TalkPage({ params }: { params: Promise<{ rkey: string }> }) {