style(mcp): align graph widget surface

This commit is contained in:
ishaanxgupta 2026-07-01 20:56:45 +05:30 committed by Ishaan Gupta
parent 0d7e231f2d
commit a8f364478a
3 changed files with 98 additions and 43 deletions

View file

@ -47,31 +47,48 @@ export function App() {
)
}
return <WidgetShell>{renderView(state.message, setView, setError)}</WidgetShell>
const isGraphView = state.message.view === "graph"
return (
<WidgetShell immersive={isGraphView}>
{renderView(state.message, setView, setError)}
</WidgetShell>
)
}
function WidgetShell({ children }: { children: ReactNode }) {
function WidgetShell({
children,
immersive = false,
}: {
children: ReactNode
immersive?: boolean
}) {
const shellClassName = immersive
? "mcp-widget-shell mcp-widget-shell-graph"
: "mcp-widget-shell"
return (
<div className="mcp-widget-shell">
<div className={shellClassName}>
<div aria-hidden className="mcp-widget-glow" />
<header aria-label="supermemory" className="mcp-widget-brand">
<span aria-hidden className="mcp-widget-brand-mark">
<svg role="img" viewBox="0 0 314 256">
<path
d="M313.728 100.982H197.297V0H159.68V109.567C159.68 121.205 164.284 132.381 172.466 140.615L267.535 236.283L294.134 209.517L223.917 138.858H313.75V101.004L313.728 100.982Z"
fill="currentColor"
/>
<path
d="M19.616 46.5043L89.8323 117.163H0V155.017H116.431V255.999H154.048V146.432C154.048 134.795 149.444 123.618 141.262 115.384L46.2144 19.7383L19.616 46.5043Z"
fill="currentColor"
/>
</svg>
</span>
<span className="mcp-widget-brand-copy">
<span className="mcp-widget-brand-name">supermemory</span>
<span className="mcp-widget-brand-mode">MCP</span>
</span>
</header>
{immersive ? null : (
<header aria-label="supermemory" className="mcp-widget-brand">
<span aria-hidden className="mcp-widget-brand-mark">
<svg role="img" viewBox="0 0 314 256">
<path
d="M313.728 100.982H197.297V0H159.68V109.567C159.68 121.205 164.284 132.381 172.466 140.615L267.535 236.283L294.134 209.517L223.917 138.858H313.75V101.004L313.728 100.982Z"
fill="currentColor"
/>
<path
d="M19.616 46.5043L89.8323 117.163H0V155.017H116.431V255.999H154.048V146.432C154.048 134.795 149.444 123.618 141.262 115.384L46.2144 19.7383L19.616 46.5043Z"
fill="currentColor"
/>
</svg>
</span>
<span className="mcp-widget-brand-copy">
<span className="mcp-widget-brand-name">supermemory</span>
<span className="mcp-widget-brand-mode">MCP</span>
</span>
</header>
)}
<main className="mcp-widget-content">{children}</main>
</div>
)

View file

@ -137,6 +137,45 @@
color: var(--text-primary);
}
.mcp-widget-shell-graph {
min-height: 420px;
background: #05080d;
}
.mcp-widget-shell-graph::before,
.mcp-widget-shell-graph::after {
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
content: "";
}
.mcp-widget-shell-graph::before {
background-image: radial-gradient(
circle at center,
rgba(105, 167, 240, 0.25) 1px,
transparent 1px
);
background-size: 32px 32px;
mask-image: radial-gradient(ellipse at center, black 60%, transparent 100%);
}
.mcp-widget-shell-graph::after {
background:
radial-gradient(
ellipse at 50% 112%,
rgba(75, 160, 250, 0.42) 0%,
rgba(20, 16, 255, 0.3) 34%,
transparent 66%
),
linear-gradient(180deg, rgba(5, 8, 13, 0) 0%, rgba(5, 8, 13, 0.2) 100%);
}
.mcp-widget-shell-graph .mcp-widget-glow {
display: none;
}
.mcp-widget-glow {
position: absolute;
right: -18%;
@ -214,6 +253,10 @@
z-index: 1;
}
.mcp-widget-shell-graph .mcp-widget-content {
min-height: inherit;
}
/* Spinner — kept as global because primitives can't easily express a CSS animation */
.spinner {
width: 24px;
@ -243,26 +286,13 @@
* minimize). Keeping it in flow with an explicit height avoids that entirely. */
.graph-view {
width: 100%;
aspect-ratio: 4 / 3;
aspect-ratio: 16 / 9;
/* Never collapse to 0 during a resize/transition a 0-size frame makes the
* package drop its "already fitted" flag and re-fit (a camera animation that
* reads as a re-layout). The floor keeps the size continuous. */
min-height: 280px;
min-height: 420px;
position: relative;
background:
linear-gradient(rgba(75, 160, 250, 0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(75, 160, 250, 0.035) 1px, transparent 1px),
radial-gradient(
circle at 50% 108%,
rgba(75, 160, 250, 0.22),
transparent 42%
),
var(--bg-primary);
background-size:
36px 36px,
36px 36px,
100% 100%,
100% 100%;
background: transparent;
}
.graph-view.fullscreen {

View file

@ -151,6 +151,14 @@ export function Graph({ documents, totalCount }: Props) {
// mid-session theme switch re-themes the canvas.
const theme = (ctx?.theme as string | undefined) ?? "light"
const colors = useGraphColors(theme)
const graphColors = useMemo<Partial<GraphThemeColors>>(
() => ({
...colors,
bg: "transparent",
edgeDerives: "#9ca3af",
}),
[colors],
)
const fullscreenSupported = useMemo(() => {
const modes = (
@ -185,11 +193,11 @@ export function Graph({ documents, totalCount }: Props) {
}, [mode, toggleFullscreen])
return (
<div className="relative px-(--page-header-px) pb-(--space-6) pt-(--space-4)">
<div className="relative">
<div
className={cn(
"graph-view overflow-hidden rounded-lg border border-border shadow-lg",
mode === "fullscreen" && "fullscreen rounded-none border-0",
"graph-view overflow-hidden",
mode === "fullscreen" && "fullscreen",
)}
>
{/* No remount on toggle. The CSS just resizes the container; the
@ -197,10 +205,10 @@ export function Graph({ documents, totalCount }: Props) {
positions stable, so expand/minimize is instant with no reload.
Theme is fed reactively via the colors prop. */}
<MemoryGraph
colors={colors}
colors={graphColors}
documents={graphDocuments}
totalCount={totalCount}
variant="console"
variant="consumer"
/>
</div>
{fullscreenSupported ? (
@ -208,7 +216,7 @@ export function Graph({ documents, totalCount }: Props) {
aria-label={
mode === "fullscreen" ? "Exit fullscreen" : "Enter fullscreen"
}
className="absolute top-4 right-4 z-40 inline-flex items-center justify-center w-9 h-9 rounded-md bg-bg-elevated/80 backdrop-blur border border-border text-text-secondary hover:text-text-primary hover:bg-bg-muted transition-colors"
className="absolute top-3 right-3 z-40 inline-flex items-center justify-center w-9 h-9 rounded-full bg-bg-elevated/90 backdrop-blur border border-border text-text-secondary hover:text-text-primary hover:bg-bg-muted transition-colors"
onClick={toggleFullscreen}
title={mode === "fullscreen" ? "Exit fullscreen" : "Fullscreen"}
type="button"