Skip to content

Commit aa2693f

Browse files
authored
Merge pull request #2790 from generalaction/chat-ui-ff
fix: add mermaid open dialog to chat ui
2 parents 9705940 + abbeb9f commit aa2693f

4 files changed

Lines changed: 72 additions & 1 deletion

File tree

apps/emdash-desktop/src/renderer/features/conversations/acp/acp-chat-panel.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { AttachmentMimeType, AttachmentRef } from '@emdash/core/acp/client';
2-
import { ChatComposer, ImageViewerDialog } from '@emdash/ui/react/components';
2+
import { ChatComposer, ImageViewerDialog, MermaidViewerDialog } from '@emdash/ui/react/components';
33
import type {
44
CommandItem,
55
ComposerAgentOption,
@@ -631,6 +631,7 @@ export const AcpChatPanel = observer(function AcpChatPanel() {
631631
const [heroSlot, setHeroSlot] = useState<HTMLElement | null>(null);
632632
const [overlaySlot, setOverlaySlot] = useState<HTMLElement | null>(null);
633633
const [viewer, setViewer] = useState<{ src?: string; alt?: string } | null>(null);
634+
const [mermaidViewer, setMermaidViewer] = useState<{ svg: string | null } | null>(null);
634635
const placementConversationRef = useRef<string | null>(null);
635636
const placementWasEmptyRef = useRef<boolean | null>(null);
636637
// True while the scroll viewport is at the tail. Defaults to true so the
@@ -721,6 +722,11 @@ export const AcpChatPanel = observer(function AcpChatPanel() {
721722
},
722723
resolveAttachment: (attachment) =>
723724
store ? resolveAttachmentDataUrl(store, attachment.id) : Promise.resolve(null),
725+
onViewMermaid: (arg) => {
726+
setMermaidViewer({
727+
svg: store?.chatContext.sharedCaches.renderMermaid(arg.chart) ?? null,
728+
});
729+
},
724730
onOpenFile: (arg) => {
725731
if (!store) return;
726732
const open = arg.source === 'diff' ? openFileInAdjacentPane : openFileInTaskEditor;
@@ -844,6 +850,13 @@ export const AcpChatPanel = observer(function AcpChatPanel() {
844850
src={viewer?.src}
845851
alt={viewer?.alt}
846852
/>
853+
<MermaidViewerDialog
854+
open={!!mermaidViewer}
855+
onOpenChange={(open) => {
856+
if (!open) setMermaidViewer(null);
857+
}}
858+
svg={mermaidViewer?.svg ?? null}
859+
/>
847860
</div>
848861
);
849862
});

packages/ui/src/react/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ export type {
3030
} from './chat-composer/permission-band';
3131
export { ConfirmationDialog, type ConfirmationDialogProps } from './confirmation-dialog';
3232
export { ImageViewerDialog, type ImageViewerDialogProps } from './image-viewer';
33+
export { MermaidViewerDialog, type MermaidViewerDialogProps } from './mermaid-viewer';
3334
export { ComboboxPopover, type ComboboxPopoverProps } from './combobox-popover';
3435
export { UpdateCard, type UpdateCardProps, type UpdateStatus } from './update-card/update-card';
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Dialog } from '@/react/primitives/dialog';
2+
import * as styles from './mermaid-viewer-dialog.css';
3+
4+
export interface MermaidViewerDialogProps {
5+
open: boolean;
6+
onOpenChange: (open: boolean) => void;
7+
/** Pre-rendered Mermaid SVG markup; null when rendering failed. */
8+
svg: string | null;
9+
/** Human-readable title shown in the dialog header. */
10+
title?: string;
11+
}
12+
13+
export function MermaidViewerDialog({ open, onOpenChange, svg, title }: MermaidViewerDialogProps) {
14+
return (
15+
<Dialog.Root open={open} onOpenChange={onOpenChange}>
16+
<Dialog.Content size="xl">
17+
<Dialog.Header>
18+
<Dialog.Title>{title ?? 'Diagram'}</Dialog.Title>
19+
</Dialog.Header>
20+
<div className={styles.diagramContainer}>
21+
{svg ? (
22+
<div className={styles.diagram} dangerouslySetInnerHTML={{ __html: svg }} />
23+
) : (
24+
<p className={styles.unavailable}>Couldn&apos;t render diagram.</p>
25+
)}
26+
</div>
27+
</Dialog.Content>
28+
</Dialog.Root>
29+
);
30+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { globalStyle, style } from '@vanilla-extract/css';
2+
import { vars } from '@theme/core/contract/contract.css';
3+
import { tokenVars } from '@theme/tokens.css';
4+
5+
export const diagramContainer = style({
6+
minHeight: 0,
7+
flex: 1,
8+
overflow: 'auto',
9+
padding: '1rem',
10+
paddingTop: 0,
11+
});
12+
13+
export const diagram = style({
14+
minWidth: 0,
15+
});
16+
17+
globalStyle(`${diagram} svg`, {
18+
display: 'block',
19+
maxWidth: '100%',
20+
height: 'auto',
21+
margin: '0 auto',
22+
});
23+
24+
export const unavailable = style({
25+
fontSize: tokenVars.textSm,
26+
color: vars.foregroundMuted,
27+
});

0 commit comments

Comments
 (0)