Initial commit: NexusArchitect Professional Workstation Overhaul

This commit is contained in:
Debian
2026-04-24 20:27:22 +02:00
commit f3e94c4f42
193 changed files with 5809 additions and 0 deletions
@@ -0,0 +1,204 @@
import * as d3 from 'https://esm.sh/d3@7';
let simulation;
let zoomBehavior;
let svgElement;
export function mount(containerId, data, dotNetHelper) {
const container = document.getElementById(containerId);
if (!container) return;
const width = container.clientWidth || 400;
const height = container.clientHeight || 400;
// Create SVG
svgElement = d3.select(container).append("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", "100%")
.attr("height", "100%");
// Radial gradient for Nebula effect
const defs = svgElement.append("defs");
const radialGradient = defs.append("radialGradient")
.attr("id", "nebulaGlow")
.attr("cx", "50%")
.attr("cy", "50%")
.attr("r", "50%");
radialGradient.append("stop").attr("offset", "0%").attr("stop-color", "var(--nexus-neon)").attr("stop-opacity", 1);
radialGradient.append("stop").attr("offset", "100%").attr("stop-color", "var(--nexus-neon)").attr("stop-opacity", 0);
// Root Group for Zoom
const rootGroup = svgElement.append("g").attr("class", "zoom-containment");
// Badge Element (TU JESTEŚ)
const badge = rootGroup.append("g")
.attr("class", "active-badge")
.style("display", "none");
badge.append("rect")
.attr("x", -35)
.attr("y", -35)
.attr("width", 70)
.attr("height", 20)
.attr("rx", 10)
.attr("fill", "var(--nexus-neon)");
badge.append("text")
.text("TU JESTEŚ")
.attr("text-anchor", "middle")
.attr("y", -21)
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("font-size", "0.6rem");
// Attach Zoom Behavior
zoomBehavior = d3.zoom()
.scaleExtent([0.5, 4])
.on("zoom", (e) => rootGroup.attr("transform", e.transform));
// Apply zoom but disable wheel interaction
svgElement.call(zoomBehavior)
.on("wheel.zoom", null);
// Subtle Link Distance & Charge
simulation = d3.forceSimulation(data.nodes)
.force("link", d3.forceLink(data.links).id(d => d.id).distance(100))
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collide", d3.forceCollide().radius(40));
// Links
const link = rootGroup.append("g")
.selectAll("path")
.data(data.links)
.join("path")
.attr("stroke", "rgba(255,255,255,0.1)")
.attr("fill", "none")
.attr("stroke-width", 1.5);
// Nodes
const node = rootGroup.append("g")
.selectAll("g")
.data(data.nodes)
.join("g")
.style("cursor", "pointer")
.on("click", (e, d) => {
// Remove active state from all, add to clicked
node.selectAll(".node-pill").classed("nexus-node-active", false);
d3.select(e.currentTarget).select(".node-pill").classed("nexus-node-active", true);
// Show badge
badge.style("display", "block").datum(d);
dotNetHelper.invokeMethodAsync('OnNodeClicked', d.id);
})
.call(drag(simulation));
// Outer glow for nodes
node.append("circle")
.attr("r", 30)
.attr("fill", "url(#nebulaGlow)")
.attr("opacity", d => d.id === 'root' ? 0.6 : 0.2);
// Pill shape
node.append("rect")
.attr("class", "node-pill")
.attr("x", d => -(d.label.length * 4 + 10))
.attr("y", -12)
.attr("width", d => d.label.length * 8 + 20)
.attr("height", 24)
.attr("rx", 12)
.attr("fill", "rgba(30, 30, 30, 0.8)")
.attr("stroke", "rgba(255, 255, 255, 0.1)")
.attr("stroke-width", 1);
// Labels
node.append("text")
.text(d => d.label)
.attr("text-anchor", "middle")
.attr("y", 4)
.attr("fill", "#ccc")
.attr("font-family", "var(--nexus-font-sans)")
.attr("font-size", "0.8rem");
simulation.on("tick", () => {
link.attr("d", d => {
const dx = d.target.x - d.source.x;
const dy = d.target.y - d.source.y;
const dr = Math.sqrt(dx * dx + dy * dy);
return `M${d.source.x},${d.source.y}A${dr},${dr} 0 0,1 ${d.target.x},${d.target.y}`;
});
node.attr("transform", d => `translate(${d.x},${d.y})`);
const activeData = badge.datum();
if (activeData) {
badge.attr("transform", `translate(${activeData.x},${activeData.y})`);
}
});
}
function drag(simulation) {
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
export function unmount(containerId) {
if (simulation) {
simulation.stop();
}
const container = document.getElementById(containerId);
if (container) {
container.innerHTML = ''; // clear svg
}
}
export function scrollToNode(id) {
const el = document.getElementById(id);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
export function pause() {
if (simulation) {
simulation.stop();
}
}
export function zoomIn() {
if (svgElement && zoomBehavior) {
svgElement.transition().duration(300).call(zoomBehavior.scaleBy, 1.3);
}
}
export function zoomOut() {
if (svgElement && zoomBehavior) {
svgElement.transition().duration(300).call(zoomBehavior.scaleBy, 0.7);
}
}
export function zoomReset() {
if (svgElement && zoomBehavior) {
svgElement.transition().duration(500).call(zoomBehavior.transform, d3.zoomIdentity);
}
}