Skip to content

Commit 22b51ad

Browse files
committed
Fix empty state markdown
1 parent a2ca118 commit 22b51ad

File tree

2 files changed

+81
-49
lines changed

2 files changed

+81
-49
lines changed

src/browser/components/pr-overview.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1870,7 +1870,15 @@ function CommentBox({
18701870
{/* Body */}
18711871
<div className="p-4">
18721872
{body ? (
1873-
<Markdown>{body}</Markdown>
1873+
<Markdown
1874+
emptyState={
1875+
<p className="text-sm text-muted-foreground italic">
1876+
No description provided.
1877+
</p>
1878+
}
1879+
>
1880+
{body}
1881+
</Markdown>
18741882
) : (
18751883
<p className="text-sm text-muted-foreground italic">
18761884
No description provided.

src/browser/ui/markdown.tsx

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip";
3737
interface MarkdownProps {
3838
children: string;
3939
className?: string;
40+
emptyState?: React.ReactNode;
4041
}
4142

4243
// Pattern to match @mentions (GitHub-style: @username)
@@ -46,7 +47,18 @@ const MENTION_REGEX = /@([a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38})/g;
4647
export const Markdown = memo(function Markdown({
4748
children,
4849
className,
50+
emptyState,
4951
}: MarkdownProps) {
52+
const containerRef = useRef<HTMLDivElement>(null);
53+
const [isEmpty, setIsEmpty] = useState(false);
54+
55+
// Check if rendered content is empty after mount
56+
useEffect(() => {
57+
if (containerRef.current && emptyState) {
58+
const text = containerRef.current.textContent?.trim() || "";
59+
setIsEmpty(text.length === 0);
60+
}
61+
}, [children, emptyState]);
5062
// Parse the content to find @mentions and wrap them
5163
const processedContent = useMemo(() => {
5264
// Split by @mentions but keep the mentions
@@ -81,7 +93,52 @@ export const Markdown = memo(function Markdown({
8193

8294
if (!hasMentions) {
8395
return (
84-
<div className={cn("markdown-body", className)}>
96+
<>
97+
{isEmpty && emptyState}
98+
<div
99+
ref={containerRef}
100+
className={cn("markdown-body", className, isEmpty && "hidden")}
101+
>
102+
<ReactMarkdown
103+
remarkPlugins={[remarkGfm, remarkGemoji]}
104+
rehypePlugins={[
105+
rehypeRaw,
106+
rehypeSanitize,
107+
[rehypeHighlight, { detect: true, ignoreMissing: true }],
108+
]}
109+
components={{
110+
// Custom link handling - open external links in new tab
111+
a: ({ href, children, ...props }) => {
112+
const isExternal = href?.startsWith("http");
113+
return (
114+
<a
115+
href={href}
116+
target={isExternal ? "_blank" : undefined}
117+
rel={isExternal ? "noopener noreferrer" : undefined}
118+
{...props}
119+
>
120+
{children}
121+
</a>
122+
);
123+
},
124+
}}
125+
>
126+
{children}
127+
</ReactMarkdown>
128+
</div>
129+
</>
130+
);
131+
}
132+
133+
// Render with mentions wrapped in hover cards
134+
// We need to process mentions within the markdown, so we'll use a custom component
135+
return (
136+
<>
137+
{isEmpty && emptyState}
138+
<div
139+
ref={containerRef}
140+
className={cn("markdown-body", className, isEmpty && "hidden")}
141+
>
85142
<ReactMarkdown
86143
remarkPlugins={[remarkGfm, remarkGemoji]}
87144
rehypePlugins={[
@@ -104,58 +161,25 @@ export const Markdown = memo(function Markdown({
104161
</a>
105162
);
106163
},
164+
// Process text nodes to find and wrap @mentions
165+
p: ({ children, ...props }) => {
166+
return <p {...props}>{processChildren(children)}</p>;
167+
},
168+
li: ({ children, ...props }) => {
169+
return <li {...props}>{processChildren(children)}</li>;
170+
},
171+
td: ({ children, ...props }) => {
172+
return <td {...props}>{processChildren(children)}</td>;
173+
},
174+
th: ({ children, ...props }) => {
175+
return <th {...props}>{processChildren(children)}</th>;
176+
},
107177
}}
108178
>
109179
{children}
110180
</ReactMarkdown>
111181
</div>
112-
);
113-
}
114-
115-
// Render with mentions wrapped in hover cards
116-
// We need to process mentions within the markdown, so we'll use a custom component
117-
return (
118-
<div className={cn("markdown-body", className)}>
119-
<ReactMarkdown
120-
remarkPlugins={[remarkGfm, remarkGemoji]}
121-
rehypePlugins={[
122-
rehypeRaw,
123-
rehypeSanitize,
124-
[rehypeHighlight, { detect: true, ignoreMissing: true }],
125-
]}
126-
components={{
127-
// Custom link handling - open external links in new tab
128-
a: ({ href, children, ...props }) => {
129-
const isExternal = href?.startsWith("http");
130-
return (
131-
<a
132-
href={href}
133-
target={isExternal ? "_blank" : undefined}
134-
rel={isExternal ? "noopener noreferrer" : undefined}
135-
{...props}
136-
>
137-
{children}
138-
</a>
139-
);
140-
},
141-
// Process text nodes to find and wrap @mentions
142-
p: ({ children, ...props }) => {
143-
return <p {...props}>{processChildren(children)}</p>;
144-
},
145-
li: ({ children, ...props }) => {
146-
return <li {...props}>{processChildren(children)}</li>;
147-
},
148-
td: ({ children, ...props }) => {
149-
return <td {...props}>{processChildren(children)}</td>;
150-
},
151-
th: ({ children, ...props }) => {
152-
return <th {...props}>{processChildren(children)}</th>;
153-
},
154-
}}
155-
>
156-
{children}
157-
</ReactMarkdown>
158-
</div>
182+
</>
159183
);
160184
});
161185

0 commit comments

Comments
 (0)