From 92ceb7f27ae43ead5983119899ee15f97dc6fe35 Mon Sep 17 00:00:00 2001 From: Chris Arter Date: Fri, 8 May 2026 12:39:42 -0400 Subject: [PATCH] feat(components): port footnotes (server-rendered) --- src/components/Footnotes.tsx | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/components/Footnotes.tsx diff --git a/src/components/Footnotes.tsx b/src/components/Footnotes.tsx new file mode 100644 index 0000000..ec83e2d --- /dev/null +++ b/src/components/Footnotes.tsx @@ -0,0 +1,64 @@ +// src/components/Footnotes.tsx +// Server component — walks the Lexical AST for citation links. +// The original Astro impl collected `.source-citation` anchors from rendered HTML. +// Here we walk the AST for link nodes that carry `data-source-url` metadata. +// None of the 42 imported posts use this pattern, so this renders nothing for now +// but is wired up for future content. + +type LexicalNode = { + type: string + url?: string + fields?: { url?: string; 'data-source-url'?: string; [key: string]: unknown } + children?: LexicalNode[] + [key: string]: unknown +} + +interface Citation { + url: string + text: string +} + +function textOf(node: LexicalNode): string { + if (node.type === 'text') return (node.text as string | undefined) ?? '' + return (node.children ?? []).map(textOf).join('') +} + +function walkForCitations(nodes: LexicalNode[], acc: Citation[] = []): Citation[] { + for (const node of nodes) { + if (node.type === 'link') { + const sourceUrl = + (node.fields?.['data-source-url'] as string | undefined) ?? + (node['data-source-url'] as string | undefined) + if (sourceUrl) { + acc.push({ url: sourceUrl, text: textOf(node) || sourceUrl }) + } + } + if (node.children?.length) walkForCitations(node.children, acc) + } + return acc +} + +interface FootnotesProps { + value?: { root: { children: LexicalNode[] } } | null +} + +export function Footnotes({ value }: FootnotesProps) { + if (!value?.root?.children) return null + const citations = walkForCitations(value.root.children) + if (citations.length === 0) return null + + return ( + + ) +} -- 2.51.2