- Document to memory
+ {labels.documentToMemoryEdge}
diff --git a/packages/memory-graph/src/components/loading-indicator.tsx b/packages/memory-graph/src/components/loading-indicator.tsx
index 37ddc82ee..8d550eb98 100644
--- a/packages/memory-graph/src/components/loading-indicator.tsx
+++ b/packages/memory-graph/src/components/loading-indicator.tsx
@@ -1,5 +1,10 @@
import { memo } from "react"
-import type { GraphThemeColors, LoadingIndicatorProps } from "../types"
+import { DEFAULT_LABELS } from "../constants"
+import type {
+ GraphThemeColors,
+ LoadingIndicatorProps,
+ ResolvedMemoryGraphLabels,
+} from "../types"
const spinKeyframes = `
@keyframes mg-spin {
@@ -18,70 +23,82 @@ function injectSpinStyle() {
}
export const LoadingIndicator = memo<
- LoadingIndicatorProps & { colors?: GraphThemeColors }
->(({ isLoading, isLoadingMore, totalLoaded, colors }) => {
- if (!isLoading && !isLoadingMore) return null
+ LoadingIndicatorProps & {
+ colors?: GraphThemeColors
+ labels?: ResolvedMemoryGraphLabels
+ }
+>(
+ ({
+ isLoading,
+ isLoadingMore,
+ totalLoaded,
+ colors,
+ labels = DEFAULT_LABELS,
+ }) => {
+ if (!isLoading && !isLoadingMore) return null
- injectSpinStyle()
+ injectSpinStyle()
- const containerStyle: React.CSSProperties = {
- position: "absolute",
- zIndex: 30,
- overflow: "hidden",
- top: 16,
- left: 16,
- borderRadius: 12,
- border: `1px solid ${colors?.controlBorder ?? "#2A2F36"}`,
- backgroundColor: colors?.controlBg ?? "#1a1f29",
- paddingLeft: 16,
- paddingRight: 16,
- paddingTop: 12,
- paddingBottom: 12,
- boxShadow: "0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1)",
- }
+ const containerStyle: React.CSSProperties = {
+ position: "absolute",
+ zIndex: 30,
+ overflow: "hidden",
+ top: 16,
+ left: 16,
+ borderRadius: 12,
+ border: `1px solid ${colors?.controlBorder ?? "#2A2F36"}`,
+ backgroundColor: colors?.controlBg ?? "#1a1f29",
+ paddingLeft: 16,
+ paddingRight: 16,
+ paddingTop: 12,
+ paddingBottom: 12,
+ boxShadow:
+ "0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1)",
+ }
- const flexStyle: React.CSSProperties = {
- display: "flex",
- alignItems: "center",
- gap: 8,
- }
+ const flexStyle: React.CSSProperties = {
+ display: "flex",
+ alignItems: "center",
+ gap: 8,
+ }
- const spinnerStyle: React.CSSProperties = {
- width: 16,
- height: 16,
- animation: "mg-spin 1s linear infinite",
- color: colors?.accent ?? "#3B73B8",
- flexShrink: 0,
- }
+ const spinnerStyle: React.CSSProperties = {
+ width: 16,
+ height: 16,
+ animation: "mg-spin 1s linear infinite",
+ color: colors?.accent ?? "#3B73B8",
+ flexShrink: 0,
+ }
- const textStyle: React.CSSProperties = {
- fontSize: 14,
- color: colors?.textSecondary ?? "#e2e8f0",
- }
+ const textStyle: React.CSSProperties = {
+ fontSize: 14,
+ color: colors?.textSecondary ?? "#e2e8f0",
+ }
- return (
-
-
-
-
- {isLoading
- ? "Loading memory graph..."
- : `Loading more documents... (${totalLoaded})`}
-
+ return (
+
+
+
+
+ {isLoading
+ ? "Loading memory graph..."
+ : labels.loadingMoreDocuments(totalLoaded)}
+
+
-
- )
-})
+ )
+ },
+)
LoadingIndicator.displayName = "LoadingIndicator"
diff --git a/packages/memory-graph/src/components/memory-graph.tsx b/packages/memory-graph/src/components/memory-graph.tsx
index 048e1a1c3..9d0c2ef65 100644
--- a/packages/memory-graph/src/components/memory-graph.tsx
+++ b/packages/memory-graph/src/components/memory-graph.tsx
@@ -3,6 +3,7 @@ import {
DENSE_GRAPH_STATIC_THRESHOLD,
ForceSimulation,
} from "../canvas/simulation"
+import { DEFAULT_HOVER_POPOVER_Z_INDEX, DEFAULT_LABELS } from "../constants"
import { VersionChainIndex } from "../canvas/version-chain"
import type { ViewportState } from "../canvas/viewport"
import { useGraphData } from "../hooks/use-graph-data"
@@ -11,6 +12,7 @@ import type {
GraphApiDocument,
GraphThemeColors,
MemoryGraphProps,
+ ResolvedMemoryGraphLabels,
} from "../types"
import { GraphCanvas } from "./graph-canvas"
import { Legend } from "./legend"
@@ -37,7 +39,15 @@ export function MemoryGraph({
colors: colorOverrides,
totalCount,
onOpenDocument,
+ labels: labelOverrides,
+ layering,
}: MemoryGraphProps) {
+ const resolvedLabels = useMemo
(
+ () => ({ ...DEFAULT_LABELS, ...labelOverrides }),
+ [labelOverrides],
+ )
+ const hoverPopoverZIndex =
+ layering?.hoverPopoverZIndex ?? DEFAULT_HOVER_POPOVER_Z_INDEX
const resolvedColors = useGraphTheme(colorOverrides)
const colors = useMemo(
() =>
@@ -397,8 +407,8 @@ export function MemoryGraph({
}, [containerSize.width, graphFitHeight])
// Wrap onOpenDocument to dismiss the popover before opening the modal.
- // Without this, the popover (z-index: 100) stays mounted on top of the
- // document modal (z-50), obscuring it and intercepting clicks.
+ // Without this, the popover overlay stays mounted on top of the
+ // document modal, obscuring it and intercepting clicks.
const handleOpenDocument = useCallback(
(documentId: string) => {
setSelectedNode(null)
@@ -748,6 +758,7 @@ export function MemoryGraph({
@@ -783,7 +794,9 @@ export function MemoryGraph({
void
onNavigatePrev?: () => void
onNavigateUp?: () => void
@@ -310,6 +314,8 @@ export const NodeHoverPopover = memo(
containerBounds,
versionChain,
colors,
+ labels = DEFAULT_LABELS,
+ zIndex = DEFAULT_HOVER_POPOVER_Z_INDEX,
onNavigateNext,
onNavigatePrev,
onNavigateUp,
@@ -419,7 +425,7 @@ export const NodeHoverPopover = memo(
left: 0,
right: 0,
bottom: 0,
- zIndex: 100,
+ zIndex,
}
const svgStyle: React.CSSProperties = {
@@ -605,7 +611,7 @@ export const NodeHoverPopover = memo(
color: colors.popoverTextSecondary,
}}
>
- {docData?.type || "document"}
+ {docData?.type || labels.documentTypeFallback}
(
color: colors.popoverTextSecondary,
}}
>
- {docData?.memories?.length ?? 0} memories
+ {labels.memoryCount(docData?.memories?.length ?? 0)}
>
)}
@@ -623,7 +629,11 @@ export const NodeHoverPopover = memo(
{isMemory ? (
) : (
-
+
)}
@@ -633,7 +643,7 @@ export const NodeHoverPopover = memo