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">
|
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>
|
</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}
|
<span className="text-muted-foreground/60 truncate">{d.node.hash.slice(0, 12)}\u2026/</span>{d.currentPath}
|
||||||
</div>
|
</div>
|
||||||
<span className="flex items-center gap-1 text-[9px] uppercase tracking-wider shrink-0">
|
<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) => {
|
const onDragStart = useCallback((e: React.MouseEvent) => {
|
||||||
if ((e.target as HTMLElement).closest("button")) return;
|
if ((e.target as HTMLElement).closest("button")) return;
|
||||||
e.preventDefault(); onFocus(id);
|
e.preventDefault(); onFocus(id);
|
||||||
|
ref.current?.focus();
|
||||||
dragRef.current = { startX: e.clientX, startY: e.clientY, origX: x, origY: y };
|
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 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);
|
document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp);
|
||||||
}, [id, x, y, onUpdate, onFocus]);
|
}, [id, x, y, onUpdate, onFocus]);
|
||||||
|
|
||||||
const onResizeStart = useCallback((e: React.MouseEvent) => {
|
const onResizeStart = useCallback((e: React.MouseEvent) => {
|
||||||
e.preventDefault(); e.stopPropagation(); onFocus(id);
|
e.preventDefault(); e.stopPropagation(); onFocus(id);
|
||||||
resizeRef.current = { startX: e.clientX, startY: e.clientY, origW: w, origH: h };
|
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 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);
|
document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp);
|
||||||
}, [id, w, h, minW, minH, onUpdate, onFocus]);
|
}, [id, w, h, minW, minH, onUpdate, onFocus]);
|
||||||
|
|
||||||
|
|||||||
@@ -196,6 +196,11 @@
|
|||||||
letter-spacing: -0.01em;
|
letter-spacing: -0.01em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--primary-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@apply font-mono;
|
@apply font-mono;
|
||||||
}
|
}
|
||||||
@@ -413,6 +418,25 @@
|
|||||||
color: var(--foreground);
|
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 ── */
|
||||||
|
|
||||||
.editor-pointer {
|
.editor-pointer {
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ import BrowseNodeWindow from "@/components/browse/BrowseNodeWindow";
|
|||||||
import BrowseSearchBar from "@/components/browse/BrowseSearchBar";
|
import BrowseSearchBar from "@/components/browse/BrowseSearchBar";
|
||||||
import Loader from "@/components/shared/Loader";
|
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
|
// Main component
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -186,7 +194,7 @@ export default function BrowseView() {
|
|||||||
fitViewDelay: 1500,
|
fitViewDelay: 1500,
|
||||||
fitViewPadding: 0.2,
|
fitViewPadding: 0.2,
|
||||||
renderHoveredPointRing: true,
|
renderHoveredPointRing: true,
|
||||||
hoveredPointRingColor: "#ffffff",
|
hoveredPointRingColor: cssVarToHex("--primary"),
|
||||||
scalePointsOnZoom: true,
|
scalePointsOnZoom: true,
|
||||||
pointGreyoutOpacity: 0.1,
|
pointGreyoutOpacity: 0.1,
|
||||||
simulationGravity: 0.5,
|
simulationGravity: 0.5,
|
||||||
@@ -204,10 +212,16 @@ export default function BrowseView() {
|
|||||||
onMouseMove: (index, pointPosition) => {
|
onMouseMove: (index, pointPosition) => {
|
||||||
if (index === undefined || !pointPosition || !graphRef.current) {
|
if (index === undefined || !pointPosition || !graphRef.current) {
|
||||||
setHoveredLabel(null);
|
setHoveredLabel(null);
|
||||||
|
containerRef.current?.classList.remove("graph-node-hovered");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const entry = entriesRef.current[index];
|
const entry = entriesRef.current[index];
|
||||||
if (!entry) return;
|
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);
|
const screen = graphRef.current.spaceToScreenPosition(pointPosition);
|
||||||
setHoveredLabel({ text: entry.name, x: screen[0], y: screen[1] });
|
setHoveredLabel({ text: entry.name, x: screen[0], y: screen[1] });
|
||||||
},
|
},
|
||||||
@@ -238,6 +252,7 @@ export default function BrowseView() {
|
|||||||
simulationRepulsion: 0.5 + scale * 9.5,
|
simulationRepulsion: 0.5 + scale * 9.5,
|
||||||
simulationCluster: 1.0 - scale * 0.75,
|
simulationCluster: 1.0 - scale * 0.75,
|
||||||
simulationGravity: 0.25 + scale * 1.75,
|
simulationGravity: 0.25 + scale * 1.75,
|
||||||
|
hoveredPointRingColor: cssVarToHex("--primary"),
|
||||||
});
|
});
|
||||||
|
|
||||||
graph.setPointPositions(graphData.positions);
|
graph.setPointPositions(graphData.positions);
|
||||||
@@ -411,7 +426,7 @@ export default function BrowseView() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative overflow-hidden" style={{ height: "100%" }}>
|
<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 */}
|
{/* Hover label */}
|
||||||
{hoveredLabel && (
|
{hoveredLabel && (
|
||||||
|
|||||||
Reference in New Issue
Block a user