From cba9ff1f576f633758588bbbf62f16e9e0521970 Mon Sep 17 00:00:00 2001
From: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
Date: Sun, 31 May 2026 23:02:43 +0800
Subject: [PATCH] fix(webui): simplify rendered source links
---
webui/src/components/MarkdownTextRenderer.tsx | 56 ++++++++++---------
.../src/tests/markdown-text-renderer.test.tsx | 26 ++++++++-
2 files changed, 53 insertions(+), 29 deletions(-)
diff --git a/webui/src/components/MarkdownTextRenderer.tsx b/webui/src/components/MarkdownTextRenderer.tsx
index 2a4c410c7..d3a664b92 100644
--- a/webui/src/components/MarkdownTextRenderer.tsx
+++ b/webui/src/components/MarkdownTextRenderer.tsx
@@ -30,9 +30,10 @@ type MarkdownAstNode = {
};
};
-type CitationLink = {
+type InlineLinkPreview = {
href: string;
origin: string;
+ prefix?: string;
title: string;
initials: string;
};
@@ -186,7 +187,7 @@ function nodeText(value: ReactNode): string {
.join("");
}
-function citationParts(value: ReactNode): { text: string; href?: string } {
+function linkPreviewParts(value: ReactNode): { text: string; href?: string } {
let text = "";
let href: string | undefined;
for (const child of Children.toArray(value)) {
@@ -201,21 +202,21 @@ function citationParts(value: ReactNode): { text: string; href?: string } {
if (!href && typeof props.href === "string" && /^https?:\/\//i.test(props.href)) {
href = props.href;
}
- const nested = citationParts(props.children);
+ const nested = linkPreviewParts(props.children);
text += nested.text;
href ||= nested.href;
}
return { text, href };
}
-function cleanCitationText(value: string): string {
+function cleanLinkPreviewText(value: string): string {
return value
.replace(/\s+/g, " ")
.replace(/^[\s"'“”‘’]+|[\s"'“”‘’]+$/g, "")
.trim();
}
-function citationInitials(value: string): string {
+function linkPreviewInitials(value: string): string {
const clean = value
.replace(/^https?:\/\//i, "")
.replace(/^www\./i, "")
@@ -225,8 +226,8 @@ function citationInitials(value: string): string {
.toUpperCase();
}
-function sourceLinkFromChildren(children: ReactNode): CitationLink | null {
- const { text: rawText, href } = citationParts(children);
+function inlineLinkPreviewFromChildren(children: ReactNode): InlineLinkPreview | null {
+ const { text: rawText, href } = linkPreviewParts(children);
if (!href) return null;
let url: URL;
@@ -246,50 +247,54 @@ function sourceLinkFromChildren(children: ReactNode): CitationLink | null {
if (!strippedUrl || strippedUrl.length < 4) return null;
const sourceMatch = /^(.*?)\s*(?:[—–]| - |:)\s*(.+)$/.exec(strippedUrl);
- const sourceLabel = sourceMatch?.[1] ? cleanCitationText(sourceMatch[1]) : undefined;
- const title = cleanCitationText(sourceMatch?.[2] ?? strippedUrl);
+ const prefix = sourceMatch?.[1] ? cleanLinkPreviewText(sourceMatch[1]) : undefined;
+ const title = cleanLinkPreviewText(sourceMatch?.[2] ?? strippedUrl);
if (!title || /^https?:\/\//i.test(title)) return null;
return {
href,
origin: url.origin,
+ prefix,
title,
- initials: citationInitials(sourceLabel || url.hostname),
+ initials: linkPreviewInitials(prefix || url.hostname),
};
}
-function CitationRow({ citation }: { citation: CitationLink }) {
+function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
+ const label = link.prefix
+ ? `${link.prefix} — ${link.title}`
+ : link.title;
return (
- {citation.initials}
+ {link.initials}
{
event.currentTarget.style.display = "none";
}}
/>
-
- {citation.title}
+
+ {label}
);
@@ -412,13 +417,12 @@ export default function MarkdownTextRenderer({
);
},
- li({ children: markdownChildren, className: itemClassName, node: _node }) {
- void _node;
- const citation = sourceLinkFromChildren(markdownChildren);
- if (citation) {
+ li({ children: markdownChildren, className: itemClassName }) {
+ const link = inlineLinkPreviewFromChildren(markdownChildren);
+ if (link) {
return (