mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-09 22:31:10 +00:00
style(mcp): align graph widget surface
This commit is contained in:
parent
0d7e231f2d
commit
a8f364478a
3 changed files with 98 additions and 43 deletions
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue