mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-15 23:31:05 +00:00
Dim superseded (non-latest) memory nodes in graph
Memory nodes with isLatest=false are now visually dimmed: - Full-size nodes: 35% opacity with dashed border stroke - Zoomed-out dots: 35% opacity with thinner stroke - Selected/hovered superseded nodes render at full opacity so users can still inspect them
This commit is contained in:
parent
4750842b00
commit
190cf727f4
1 changed files with 88 additions and 24 deletions
|
|
@ -3,6 +3,7 @@ import type {
|
|||
GraphEdge,
|
||||
GraphNode,
|
||||
GraphThemeColors,
|
||||
MemoryNodeData,
|
||||
} from "../types"
|
||||
import type { ViewportState } from "./viewport"
|
||||
|
||||
|
|
@ -302,7 +303,13 @@ function drawNodes(
|
|||
colors: GraphThemeColors,
|
||||
): void {
|
||||
const margin = 60
|
||||
const memDots: { x: number; y: number; r: number; color: string }[] = []
|
||||
const memDots: {
|
||||
x: number
|
||||
y: number
|
||||
r: number
|
||||
color: string
|
||||
dimmed: boolean
|
||||
}[] = []
|
||||
const docDots: { x: number; y: number; s: number }[] = []
|
||||
|
||||
for (const node of nodes) {
|
||||
|
|
@ -326,11 +333,13 @@ function drawNodes(
|
|||
if (node.type === "document") {
|
||||
docDots.push({ x: screen.x, y: screen.y, s: Math.max(3, screenSize) })
|
||||
} else {
|
||||
const md = node.data as MemoryNodeData
|
||||
memDots.push({
|
||||
x: screen.x,
|
||||
y: screen.y,
|
||||
r: Math.max(2, screenSize * 0.45),
|
||||
color: node.borderColor || colors.memStrokeDefault,
|
||||
dimmed: md.isLatest === false,
|
||||
})
|
||||
}
|
||||
continue
|
||||
|
|
@ -391,34 +400,71 @@ function drawNodes(
|
|||
}
|
||||
|
||||
if (memDots.length > 0) {
|
||||
ctx.globalAlpha = dimAlpha
|
||||
// Draw normal (latest) memory dots
|
||||
const normalDots = memDots.filter((d) => !d.dimmed)
|
||||
const dimmedDots = memDots.filter((d) => d.dimmed)
|
||||
|
||||
ctx.fillStyle = colors.memFill
|
||||
ctx.beginPath()
|
||||
for (const d of memDots) {
|
||||
ctx.moveTo(d.x + d.r, d.y)
|
||||
ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2)
|
||||
}
|
||||
ctx.fill()
|
||||
|
||||
ctx.lineWidth = 1.5
|
||||
const byColor = new Map<string, typeof memDots>()
|
||||
for (const d of memDots) {
|
||||
let batch = byColor.get(d.color)
|
||||
if (!batch) {
|
||||
batch = []
|
||||
byColor.set(d.color, batch)
|
||||
}
|
||||
batch.push(d)
|
||||
}
|
||||
for (const [color, batch] of byColor) {
|
||||
ctx.strokeStyle = color
|
||||
if (normalDots.length > 0) {
|
||||
ctx.globalAlpha = dimAlpha
|
||||
ctx.fillStyle = colors.memFill
|
||||
ctx.beginPath()
|
||||
for (const d of batch) {
|
||||
for (const d of normalDots) {
|
||||
ctx.moveTo(d.x + d.r, d.y)
|
||||
ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2)
|
||||
}
|
||||
ctx.stroke()
|
||||
ctx.fill()
|
||||
|
||||
ctx.lineWidth = 1.5
|
||||
const byColor = new Map<string, typeof normalDots>()
|
||||
for (const d of normalDots) {
|
||||
let batch = byColor.get(d.color)
|
||||
if (!batch) {
|
||||
batch = []
|
||||
byColor.set(d.color, batch)
|
||||
}
|
||||
batch.push(d)
|
||||
}
|
||||
for (const [color, batch] of byColor) {
|
||||
ctx.strokeStyle = color
|
||||
ctx.beginPath()
|
||||
for (const d of batch) {
|
||||
ctx.moveTo(d.x + d.r, d.y)
|
||||
ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2)
|
||||
}
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
// Draw dimmed (superseded) memory dots at reduced opacity
|
||||
if (dimmedDots.length > 0) {
|
||||
ctx.globalAlpha = dimAlpha * 0.35
|
||||
ctx.fillStyle = colors.memFill
|
||||
ctx.beginPath()
|
||||
for (const d of dimmedDots) {
|
||||
ctx.moveTo(d.x + d.r, d.y)
|
||||
ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2)
|
||||
}
|
||||
ctx.fill()
|
||||
|
||||
ctx.lineWidth = 1
|
||||
const byColor = new Map<string, typeof dimmedDots>()
|
||||
for (const d of dimmedDots) {
|
||||
let batch = byColor.get(d.color)
|
||||
if (!batch) {
|
||||
batch = []
|
||||
byColor.set(d.color, batch)
|
||||
}
|
||||
batch.push(d)
|
||||
}
|
||||
for (const [color, batch] of byColor) {
|
||||
ctx.strokeStyle = color
|
||||
ctx.beginPath()
|
||||
for (const d of batch) {
|
||||
ctx.moveTo(d.x + d.r, d.y)
|
||||
ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2)
|
||||
}
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -475,8 +521,26 @@ function drawMemoryNode(
|
|||
_isHighlighted: boolean,
|
||||
colors: GraphThemeColors,
|
||||
): void {
|
||||
const memData = node.data as MemoryNodeData
|
||||
const isSuperseded = memData.isLatest === false
|
||||
const radius = size * 0.5
|
||||
|
||||
// Dim superseded (non-latest) memory nodes
|
||||
if (isSuperseded && !isSelected && !isHovered) {
|
||||
const prevAlpha = ctx.globalAlpha
|
||||
ctx.globalAlpha = prevAlpha * 0.35
|
||||
ctx.fillStyle = colors.memFill
|
||||
drawHexagon(ctx, sx, sy, radius)
|
||||
ctx.fill()
|
||||
ctx.strokeStyle = node.borderColor || colors.memStrokeDefault
|
||||
ctx.lineWidth = 1
|
||||
ctx.setLineDash([3, 3])
|
||||
ctx.stroke()
|
||||
ctx.setLineDash([])
|
||||
ctx.globalAlpha = prevAlpha
|
||||
return
|
||||
}
|
||||
|
||||
ctx.fillStyle = isHovered ? colors.memFillHover : colors.memFill
|
||||
drawHexagon(ctx, sx, sy, radius)
|
||||
ctx.fill()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue