feat: improvements
This commit is contained in:
@@ -47,7 +47,9 @@ export default function BrowseNodeWindow({
|
||||
className="w-5 h-5 flex items-center justify-center rounded text-[10px] text-muted-foreground hover:text-foreground disabled:opacity-30 disabled:cursor-default transition-colors" title="Reload">
|
||||
↻
|
||||
</button>
|
||||
<div className="flex-1 flex items-center h-5 px-2 bg-background/60 border border-border rounded text-[10px] font-mono text-foreground/80 truncate">
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
|
||||
<div className="flex-1 flex items-center h-5 px-2 bg-background/60 border border-border rounded text-[10px] font-mono text-foreground/80 truncate cursor-text"
|
||||
onClick={(e) => { if (e.target === e.currentTarget) { const sel = window.getSelection(); if (sel) { const range = document.createRange(); range.selectNodeContents(e.currentTarget); sel.removeAllRanges(); sel.addRange(range); } } }}>
|
||||
<span className="text-muted-foreground/60 truncate">{d.node.hash.slice(0, 12)}\u2026/</span>{d.currentPath}
|
||||
</div>
|
||||
<span className="flex items-center gap-1 text-[9px] uppercase tracking-wider shrink-0">
|
||||
|
||||
@@ -44,17 +44,20 @@ export default function FloatingWindow({
|
||||
const onDragStart = useCallback((e: React.MouseEvent) => {
|
||||
if ((e.target as HTMLElement).closest("button")) return;
|
||||
e.preventDefault(); onFocus(id);
|
||||
ref.current?.focus();
|
||||
dragRef.current = { startX: e.clientX, startY: e.clientY, origX: x, origY: y };
|
||||
document.documentElement.classList.add("cursor-grabbing");
|
||||
const onMove = (ev: MouseEvent) => { if (!dragRef.current) return; onUpdate(id, { x: dragRef.current.origX + (ev.clientX - dragRef.current.startX), y: Math.max(0, dragRef.current.origY + (ev.clientY - dragRef.current.startY)) }); };
|
||||
const onUp = () => { dragRef.current = null; document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); };
|
||||
const onUp = () => { dragRef.current = null; document.documentElement.classList.remove("cursor-grabbing"); document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); };
|
||||
document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp);
|
||||
}, [id, x, y, onUpdate, onFocus]);
|
||||
|
||||
const onResizeStart = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault(); e.stopPropagation(); onFocus(id);
|
||||
resizeRef.current = { startX: e.clientX, startY: e.clientY, origW: w, origH: h };
|
||||
document.documentElement.classList.add("cursor-nwse-resize");
|
||||
const onMove = (ev: MouseEvent) => { if (!resizeRef.current) return; onUpdate(id, { w: Math.max(minW, resizeRef.current.origW + (ev.clientX - resizeRef.current.startX)), h: Math.max(minH, resizeRef.current.origH + (ev.clientY - resizeRef.current.startY)) }); };
|
||||
const onUp = () => { resizeRef.current = null; document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); };
|
||||
const onUp = () => { resizeRef.current = null; document.documentElement.classList.remove("cursor-nwse-resize"); document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); };
|
||||
document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp);
|
||||
}, [id, w, h, minW, minH, onUpdate, onFocus]);
|
||||
|
||||
|
||||
@@ -196,6 +196,11 @@
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
|
||||
html {
|
||||
@apply font-mono;
|
||||
}
|
||||
@@ -413,6 +418,25 @@
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
/* ── Global drag cursors ── */
|
||||
.cursor-grabbing, .cursor-grabbing * {
|
||||
cursor: grabbing !important;
|
||||
}
|
||||
.cursor-nwse-resize, .cursor-nwse-resize * {
|
||||
cursor: nwse-resize !important;
|
||||
}
|
||||
|
||||
/* ── Graph cursors ── */
|
||||
.graph-canvas canvas {
|
||||
cursor: grab !important;
|
||||
}
|
||||
.graph-canvas canvas:active {
|
||||
cursor: grabbing !important;
|
||||
}
|
||||
.graph-canvas.graph-node-hovered canvas {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
/* ── Editor Pointer ── */
|
||||
|
||||
.editor-pointer {
|
||||
|
||||
@@ -10,6 +10,14 @@ import BrowseNodeWindow from "@/components/browse/BrowseNodeWindow";
|
||||
import BrowseSearchBar from "@/components/browse/BrowseSearchBar";
|
||||
import Loader from "@/components/shared/Loader";
|
||||
|
||||
function cssVarToHex(varName: string): string {
|
||||
const raw = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
|
||||
if (!raw) return "#888888";
|
||||
const ctx = document.createElement("canvas").getContext("2d")!;
|
||||
ctx.fillStyle = raw;
|
||||
return ctx.fillStyle;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main component
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -186,7 +194,7 @@ export default function BrowseView() {
|
||||
fitViewDelay: 1500,
|
||||
fitViewPadding: 0.2,
|
||||
renderHoveredPointRing: true,
|
||||
hoveredPointRingColor: "#ffffff",
|
||||
hoveredPointRingColor: cssVarToHex("--primary"),
|
||||
scalePointsOnZoom: true,
|
||||
pointGreyoutOpacity: 0.1,
|
||||
simulationGravity: 0.5,
|
||||
@@ -204,10 +212,16 @@ export default function BrowseView() {
|
||||
onMouseMove: (index, pointPosition) => {
|
||||
if (index === undefined || !pointPosition || !graphRef.current) {
|
||||
setHoveredLabel(null);
|
||||
containerRef.current?.classList.remove("graph-node-hovered");
|
||||
return;
|
||||
}
|
||||
const entry = entriesRef.current[index];
|
||||
if (!entry) return;
|
||||
if (entry.type !== "interface") {
|
||||
containerRef.current?.classList.add("graph-node-hovered");
|
||||
} else {
|
||||
containerRef.current?.classList.remove("graph-node-hovered");
|
||||
}
|
||||
const screen = graphRef.current.spaceToScreenPosition(pointPosition);
|
||||
setHoveredLabel({ text: entry.name, x: screen[0], y: screen[1] });
|
||||
},
|
||||
@@ -238,6 +252,7 @@ export default function BrowseView() {
|
||||
simulationRepulsion: 0.5 + scale * 9.5,
|
||||
simulationCluster: 1.0 - scale * 0.75,
|
||||
simulationGravity: 0.25 + scale * 1.75,
|
||||
hoveredPointRingColor: cssVarToHex("--primary"),
|
||||
});
|
||||
|
||||
graph.setPointPositions(graphData.positions);
|
||||
@@ -411,7 +426,7 @@ export default function BrowseView() {
|
||||
|
||||
return (
|
||||
<div className="relative overflow-hidden" style={{ height: "100%" }}>
|
||||
<div ref={containerRef} className="absolute inset-0" />
|
||||
<div ref={containerRef} className="absolute inset-0 graph-canvas" />
|
||||
|
||||
{/* Hover label */}
|
||||
{hoveredLabel && (
|
||||
|
||||
Reference in New Issue
Block a user