@robotaccomplice/architext 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/THIRD_PARTY_NOTICES.md +59 -0
- package/docs/architecture/ROUTING_FRAMEWORK_COMPARISON.md +284 -0
- package/docs/architecture/ROUTING_PLAN.md +480 -0
- package/docs/architext/dist/assets/index-DMbdxljw.js +51 -0
- package/docs/architext/dist/assets/index-DvokFPhn.css +1 -0
- package/docs/architext/dist/assets/planningWorker-DY_nEecj.js +1 -0
- package/docs/architext/dist/index.html +2 -2
- package/docs/architext/src/main.tsx +450 -556
- package/docs/architext/src/routing/planDiagram.js +208 -0
- package/docs/architext/src/routing/planningWorker.js +15 -0
- package/docs/architext/src/routing/routeEdges.js +1484 -0
- package/docs/architext/src/styles.css +180 -1
- package/docs/architext/tsconfig.json +1 -2
- package/docs/assets/screenshots/architext-c4.png +0 -0
- package/docs/assets/screenshots/architext-data-risks.png +0 -0
- package/docs/assets/screenshots/architext-flows.png +0 -0
- package/docs/assets/screenshots/architext-sequence.png +0 -0
- package/package.json +9 -4
- package/docs/architext/dist/assets/index-BWZ6sEpA.js +0 -51
- package/docs/architext/dist/assets/index-iWLms0Pa.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{color-scheme:dark;--bg: #0c0e11;--surface: #111316;--panel: #1a1c1f;--panel-2: #1e2023;--panel-3: #282a2d;--ink: #e2e2e6;--muted: #b9cacb;--dim: #849495;--line: #3b494b;--line-strong: #849495;--blue: #00dbe9;--green: #2ff801;--yellow: #fed639;--red: #ffb4ab;--purple: #9f8cff;--cyan: #00dbe9;--orange: #fed639;--pink: #ff9db7;--shadow: none;--font-headline: "Hanken Grotesk", "Arial Narrow", Inter, ui-sans-serif, system-ui, sans-serif;--font-body: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono: "JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", monospace;font-family:var(--font-body)}*{box-sizing:border-box}html,body,#root{height:100%}body{margin:0;background:var(--bg);color:var(--ink)}button,input,select{font:inherit}button,select,input{color:var(--ink);background:var(--panel-2);border:1px solid var(--line);border-radius:0}button,select{cursor:pointer}button:hover,button:focus,select:hover,select:focus,input:focus{border-color:var(--blue);outline:1px solid rgba(0,219,233,.32);outline-offset:1px}.app{height:100%;display:grid;grid-template-columns:320px minmax(0,1fr) 390px;grid-template-rows:auto minmax(0,1fr);gap:8px;padding:8px;overflow:hidden}.app.left-collapsed{grid-template-columns:52px minmax(0,1fr) 390px}.app.right-collapsed{grid-template-columns:320px minmax(0,1fr) 52px}.app.left-collapsed.right-collapsed,.app.diagram-focused{grid-template-columns:52px minmax(0,1fr) 52px}.topbar{grid-column:1 / -1;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:10px 12px;border:1px solid var(--line);border-radius:0;background:var(--surface);box-shadow:var(--shadow)}.topbar h1,.topbar p,.diagram-header h2,.diagram-header p,.steps h2,.steps p,.details h2,.details p{margin:0}.topbar>div:first-child{min-width:0}.topbar>div:first-child p:not(.eyebrow){overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.topbar h1{font-family:var(--font-headline);font-size:22px;letter-spacing:-.02em}.project-title-line,.diagram-title-line{display:flex;min-width:0;align-items:baseline;gap:10px}.project-title-line p,.diagram-title-line p{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.topbar p,.diagram-header p,.steps p,.details p,.muted{color:var(--muted);line-height:1.45}.eyebrow{color:var(--blue);font-family:var(--font-mono);font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.topbar-actions{display:flex;align-items:center;gap:8px}.topbar-actions button,.topbar-actions select{min-height:36px;padding:7px 10px}.mode-tabs{display:flex;flex-wrap:wrap;gap:2px;justify-content:flex-end}.mode-tabs button{min-width:74px;padding:7px 9px;border-color:transparent;border-bottom-color:var(--line);color:var(--muted);background:transparent;font-family:var(--font-mono);font-size:12px;letter-spacing:.05em}.mode-tabs button.active{border-color:transparent;border-bottom-color:var(--blue);color:var(--ink);background:var(--panel-2)}.left-nav,.diagram-area,.details{position:relative;min-height:0;border:1px solid var(--line);border-radius:0;background:var(--panel);box-shadow:var(--shadow)}.diagram-area{overflow:hidden}.left-nav{grid-column:1;grid-row:2}.diagram-area{grid-column:2;grid-row:2}.details{grid-column:3;grid-row:2}.left-nav{display:grid;grid-template-rows:auto minmax(0,1fr)}.panel-rail{height:100%;display:grid;place-items:center;color:var(--muted);font-size:11px;font-weight:800;letter-spacing:.16em;text-transform:uppercase;writing-mode:vertical-rl;transform:rotate(180deg);-webkit-user-select:none;user-select:none}.side-toggle{position:absolute;z-index:20;top:16px;width:24px;height:40px;display:grid;place-items:center;padding:0;border-radius:0;border:1px solid var(--line);color:var(--blue);background:var(--surface);box-shadow:none;font-family:var(--font-mono);font-weight:900;line-height:1}.side-toggle:hover{background:var(--panel-3);box-shadow:inset 0 0 0 1px #00dbe940}.side-toggle:after{position:absolute;top:50%;min-width:max-content;padding:4px 6px;border:1px solid var(--line);border-radius:0;color:var(--ink);background:var(--bg);box-shadow:none;content:attr(data-tooltip);font-family:var(--font-mono);font-size:11px;font-weight:700;opacity:0;pointer-events:none;transform:translateY(-50%);transition:opacity .12s ease}.side-toggle:hover:after{opacity:1}.left-side-toggle,.app.left-collapsed .left-side-toggle{right:-12px}.right-side-toggle,.app.right-collapsed .right-side-toggle{left:-12px}.left-side-toggle:after{left:36px}.right-side-toggle:after{right:36px}.panel-head{padding:10px 12px;border-bottom:1px solid var(--line)}.panel-head h2{margin:0 0 8px;font-family:var(--font-mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase}.panel-head p{margin:6px 0 0;color:var(--muted);font-size:11px;line-height:1.4}.panel-head input{width:100%;min-height:30px;padding:6px 8px;border-width:0 0 1px;font-family:var(--font-mono);font-size:12px}.flow-list{overflow:auto}.flow-list{padding:8px}.entity-list{min-height:0;overflow:auto;padding:8px}.entity-list h3{margin:8px 0 5px;color:var(--muted);font-family:var(--font-mono);font-size:.72rem;letter-spacing:.08em;text-transform:uppercase}.flow-card,.entity-card{width:100%;display:grid;gap:4px;margin-bottom:6px;padding:8px;text-align:left;background:var(--panel-2)}.entity-card.passive{cursor:default}.flow-card.active,.entity-card.active{border-color:var(--blue);border-left:4px solid var(--blue);background:#102024}.flow-card strong,.entity-card strong,.step-card strong,.node-card strong,.mini-record strong{display:block}.flow-card strong,.entity-card strong,.step-card strong,.node-card strong,.c4-node strong,.mini-record strong{font-family:var(--font-mono)}.flow-card span,.entity-card span,.node-card span,.step-card span{color:var(--muted);font-size:11px;line-height:1.3}.diagram-area{display:grid;grid-template-rows:auto minmax(0,1fr) auto;overflow:hidden}.diagram-header,.steps{padding:8px 10px}.diagram-header{display:flex;align-items:center;justify-content:space-between;gap:10px;border-bottom:1px solid var(--line);background:var(--surface)}.diagram-header h2{font-family:var(--font-headline);font-size:20px;letter-spacing:-.02em}.diagram-header p{font-size:13px}.diagram-controls{display:flex;flex:0 0 auto;align-items:center;gap:6px}.routing-style-control{display:inline-flex;overflow:hidden;border:1px solid var(--line)}.routing-style-control button{border:0;border-right:1px solid var(--line);background:var(--panel)}.routing-style-control button:last-child{border-right:0}.routing-style-control button.active{background:var(--blue);color:#fff}.diagram-controls button{min-height:28px;padding:4px 7px;font-family:var(--font-mono);font-size:11px}.diagram-controls span{min-width:44px;color:var(--muted);font-family:var(--font-mono);font-size:11px;text-align:center}.legend{position:relative;color:var(--muted);font-family:var(--font-mono);font-size:11px}.legend summary{min-height:28px;padding:5px 8px;border:1px solid var(--line);color:var(--blue);list-style:none;cursor:pointer}.legend summary::-webkit-details-marker{display:none}.legend>div{position:absolute;z-index:15;right:0;top:calc(100% + 4px);display:grid;grid-template-columns:repeat(2,max-content);gap:7px 10px;min-width:260px;padding:10px;border:1px solid var(--line);background:var(--panel-2)}.legend span{display:inline-flex;align-items:center;gap:5px}.dot{width:9px;height:9px;border-radius:0;background:var(--muted)}.diagram-viewport{min-width:0;min-height:0;overflow:hidden}.map-shell{position:relative;width:100%;height:100%;min-width:0;min-height:0;overflow:auto;background:radial-gradient(circle,rgba(59,73,75,.5) 1px,transparent 1px),var(--bg);background-size:32px 32px}.diagram-canvas{position:relative;min-width:100%;min-height:100%}.routing-loading-overlay,.routing-planning-error{position:absolute;left:50%;top:50%;z-index:20;display:inline-flex;align-items:center;gap:10px;max-width:min(360px,calc(100% - 32px));padding:10px 12px;color:var(--ink);background:#111316eb;border:1px solid rgba(0,219,233,.42);border-radius:8px;box-shadow:0 8px 30px #0000003d;transform:translate(-50%,-50%);font-size:13px;font-weight:800;pointer-events:none}.routing-spinner{width:16px;height:16px;flex:0 0 auto;border:2px solid rgba(185,202,203,.32);border-top-color:var(--blue);border-radius:50%;animation:routing-spin .8s linear infinite}.routing-planning-error{flex-direction:column;align-items:flex-start;min-width:min(360px,calc(100% - 32px));border-color:#ffb4ab8f;color:var(--red);pointer-events:auto}.routing-planning-error span{color:var(--ink);font-weight:500}@keyframes routing-spin{to{transform:rotate(360deg)}}.flow-lines{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;overflow:visible}.flow-edge,.relationship-edge{cursor:pointer;pointer-events:all}.flow-edge:focus,.relationship-edge:focus{outline:none}.flow-line{fill:none;stroke:var(--blue);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;opacity:.9}.structural-line{fill:none;stroke:var(--muted);stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:6 6;opacity:.85}.relationship-label{fill:var(--muted);paint-order:stroke;stroke:#0b0f16;stroke-width:4px;font-family:var(--font-mono);font-size:10px;font-weight:800;text-anchor:middle}.relationship-edge.selected .structural-line,.relationship-edge.selected .c4-relationship{stroke:var(--blue)}.flow-lines marker path{fill:var(--blue)}#arrowhead-selected path,#sequence-arrowhead-selected path{fill:var(--blue)}.flow-edge.selected .flow-line{stroke:var(--blue)}.flow-edge.selected .flow-step-dot{fill:var(--blue)}.flow-step-dot{fill:var(--blue);stroke:#002022;stroke-width:1}.flow-step-label{fill:#002022;font-family:var(--font-mono);font-size:11px;font-weight:900;text-anchor:middle;pointer-events:none}.sequence-shell{background:radial-gradient(circle,rgba(59,73,75,.5) 1px,transparent 1px),var(--bg);background-size:32px 32px}.sequence-participant-rail{position:sticky;z-index:8;top:0;height:58px;min-width:100%;background:#0c0e11f0;border-bottom:1px solid var(--line)}.sequence-participant-card{position:absolute;top:9px;height:38px;display:grid;gap:1px;padding:5px 7px;text-align:center;background:var(--panel-2);border-color:var(--line-strong)}.sequence-participant-card strong{overflow:hidden;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.sequence-participant-card span{color:var(--dim);font-family:var(--font-mono);font-size:10px}.sequence-canvas{display:block;min-width:100%;min-height:100%}.sequence-participant{fill:var(--panel-2);stroke:var(--line-strong);stroke-width:1.5}.sequence-title{fill:var(--ink);font-family:var(--font-mono);font-size:11px;font-weight:800;text-anchor:middle}.sequence-kind,.sequence-data{fill:var(--muted);font-family:var(--font-mono);font-size:10px;text-anchor:middle}.lifeline{stroke:var(--line-strong);stroke-width:1.5;stroke-dasharray:4 5}.sequence-message{cursor:pointer}.sequence-line{stroke:var(--blue);stroke-width:1.8;stroke-linecap:round}.sequence-message.async .sequence-line{stroke-dasharray:7 5}.sequence-message.persistence .sequence-line{stroke:var(--green)}.sequence-message.response .sequence-line{stroke:var(--cyan)}.sequence-canvas marker path{fill:var(--blue)}#sequence-arrowhead-response path{fill:var(--cyan)}#sequence-arrowhead-persistence path{fill:var(--green)}#sequence-arrowhead-selected path{fill:var(--blue)}.sequence-step-dot{fill:var(--blue);stroke:#002022;stroke-width:1}.sequence-step-label{fill:#002022;font-family:var(--font-mono);font-size:11px;font-weight:900;text-anchor:middle}.sequence-action{fill:var(--ink);font-family:var(--font-mono);font-size:11px;font-weight:800;text-anchor:middle;paint-order:stroke;stroke:#0b0f16;stroke-width:3px}.sequence-message.selected .sequence-line{stroke:var(--blue)}.sequence-message.selected .sequence-step-dot{fill:var(--blue)}.lane-column{position:absolute;top:14px;border-left:1px dashed var(--line);pointer-events:none}.lane-column h3{margin:0;padding-left:8px;color:var(--muted);font-family:var(--font-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase}.node-card{position:absolute;display:grid;align-content:center;gap:2px;padding:5px 7px;text-align:left;opacity:.45;border-left-width:3px;overflow:hidden;font-family:var(--font-mono)}.node-card strong,.c4-node strong{font-size:12px;line-height:1.15}.node-card strong{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:2}.node-card.in-flow{opacity:1;border-color:var(--blue)}.node-card.selected{background:#102024;box-shadow:inset 0 0 0 1px #00dbe973}.node-card.actor{border-left-color:var(--pink)}.node-card.software-system{border-left-color:var(--cyan)}.node-card.client{border-left-color:var(--blue)}.node-card.service,.node-card.worker{border-left-color:var(--purple)}.node-card.queue{border-left-color:var(--orange)}.node-card.data-store{border-left-color:var(--green)}.node-card.external-service{border-left-color:var(--muted)}.c4-shell{background:var(--bg)}.c4-canvas{position:relative;min-width:100%;min-height:100%}.c4-boundary{position:absolute;top:54px;right:34px;bottom:34px;left:34px;border:1px dashed rgba(0,219,233,.26);border-radius:0;pointer-events:none}.c4-boundary span{position:absolute;top:-12px;left:18px;padding:2px 8px;color:var(--cyan);background:var(--bg);font-family:var(--font-mono);font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.c4-lane-label{position:absolute;color:var(--muted);font-family:var(--font-mono);font-size:11px;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.c4-node{position:absolute;display:grid;gap:3px;padding:8px;text-align:left;border-color:var(--line-strong);border-left-width:3px;background:var(--panel-2);overflow:hidden}.c4-node.selected{border-color:var(--blue);background:#102024}.c4-node small{display:-webkit-box;overflow:hidden;color:var(--muted);font-size:10px;line-height:1.25;-webkit-box-orient:vertical;-webkit-line-clamp:3}.c4-relationship{fill:none;stroke:var(--muted);stroke-width:1.4;stroke-dasharray:6 6;opacity:.76}.c4-lines marker path{fill:var(--muted)}#c4-arrowhead-selected path{fill:var(--blue)}.c4-label{fill:var(--ink)}.edge-strip{position:sticky;left:0;bottom:0;display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:6px 8px;border-top:1px solid var(--line);background:#0c0e11f2;overflow:visible}.edge-chip,.edge-count{flex:0 0 auto;color:var(--muted);border:1px solid var(--line);border-radius:0;padding:3px 6px;font-family:var(--font-mono);font-size:11px}.edge-chip{color:var(--blue);background:transparent}.edge-chip.active{color:#002022;background:var(--blue);border-color:var(--blue)}.routing-debug-panel{position:sticky;left:0;bottom:0;display:grid;gap:8px;max-height:220px;padding:8px;border-top:1px solid var(--line-strong);background:#090b0ef7;overflow:auto;font-family:var(--font-mono);font-size:11px}.routing-debug-geometry{pointer-events:none}.routing-debug-node{fill:none;stroke:#facc1580;stroke-dasharray:3 3;stroke-width:1}.routing-debug-label{fill:#22d3ee1f;stroke:#22d3eecc;stroke-width:1}.routing-debug-point{fill:var(--orange);stroke:#111827;stroke-width:1}.routing-debug-route.warned .routing-debug-point{fill:#f87171}.routing-debug-summary,.routing-debug-warnings,.routing-debug-routes{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.routing-debug-summary strong,.routing-debug-summary span,.routing-debug-warnings span,.routing-debug-routes details{border:1px solid var(--line);padding:3px 6px;background:#12181ccc}.routing-debug-summary strong{color:var(--cyan)}.routing-debug-warnings span{color:var(--orange)}.routing-debug-routes details{min-width:190px}.routing-debug-routes summary{display:flex;justify-content:space-between;gap:8px;cursor:pointer}.routing-debug-routes dl{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:3px 8px;margin:6px 0 0}.routing-debug-routes dt,.routing-debug-routes dd{margin:0}.routing-debug-routes dt{color:var(--muted)}.routing-debug-routes dd{color:var(--ink);text-align:right}.steps{border-top:1px solid var(--line);background:var(--surface)}.steps.collapsed{padding-block:6px}.steps-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:4px}.steps-title-line{display:flex;min-width:0;align-items:baseline;gap:10px}.steps-head h2{flex:0 0 auto;font-family:var(--font-headline);font-size:18px}.steps-title-line p{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.steps-actions{display:inline-flex;align-items:center;gap:6px}.step-list{display:flex;gap:6px;margin-top:6px;overflow-x:auto;padding-bottom:2px}.step-card{flex:0 0 190px;display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-rows:auto auto;gap:3px 8px;min-height:36px;padding:6px;text-align:left}.step-card strong{overflow:hidden;font-size:11px;line-height:1.25;text-overflow:ellipsis}.step-card span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.step-card.active{border-color:var(--blue);background:#102024}.step-number{grid-row:1 / span 2;display:inline-grid;place-items:center;width:20px;height:20px;border-radius:0;color:#002022;background:var(--blue);font-family:var(--font-mono);font-weight:900}.step-card .step-number{color:#001719;background:#7df4ff}.details{padding:0}.detail-content{height:100%;overflow:auto;padding:0 12px 12px}.detail-sticky{position:sticky;z-index:5;top:0;padding:12px 0 8px;border-bottom:1px solid rgba(0,219,233,.32);background:linear-gradient(90deg,rgba(0,219,233,.11),transparent 34%),#1a1c1ffa}.detail-content h2{margin:4px 0 6px;font-family:var(--font-headline);font-size:20px;letter-spacing:-.02em}.badge-row{display:flex;flex-wrap:wrap;gap:4px;margin:8px 0}.detail-index{display:flex;gap:4px;margin-top:8px;overflow-x:auto;padding-bottom:2px}.detail-index a{flex:0 0 auto;--section-accent: var(--blue);padding:3px 6px;border:1px solid color-mix(in srgb,var(--section-accent) 35%,var(--line));color:color-mix(in srgb,var(--section-accent) 70%,var(--muted));background:color-mix(in srgb,var(--section-accent) 5%,transparent);font-family:var(--font-mono);font-size:11px;text-decoration:none}.detail-index a:hover,.detail-index a:focus{color:var(--ink);border-color:var(--section-accent, var(--blue));background:color-mix(in srgb,var(--section-accent, var(--blue)) 12%,transparent)}.detail-index a[href="#summary"]{--section-accent: var(--blue)}.detail-index a[href="#runtime"]{--section-accent: var(--green)}.detail-index a[href="#interfaces"]{--section-accent: var(--cyan)}.detail-index a[href="#data"]{--section-accent: var(--purple)}.detail-index a[href="#security"]{--section-accent: var(--yellow)}.detail-index a[href="#observability"]{--section-accent: #7df4ff}.detail-index a[href="#risks"]{--section-accent: var(--red)}.detail-index a[href="#decisions"]{--section-accent: #b9cacb}.detail-index a[href="#verification"]{--section-accent: var(--green)}.badge{display:inline-flex;align-items:center;gap:5px;width:fit-content;min-height:18px;margin-right:4px;margin-top:4px;padding:2px 5px;border:1px solid var(--line);border-radius:0;color:var(--muted);background:var(--panel-2);font-family:var(--font-mono);font-size:10px;font-weight:700;text-transform:uppercase}.badge:before{width:6px;height:6px;background:currentColor;content:""}.badge.implemented,.badge.low{color:var(--green);border-color:#2ff80173}.badge.partial,.badge.medium,.badge.planned,.badge.high{color:var(--yellow);border-color:#fed63973}.badge.critical{color:var(--red);border-color:#ffb4ab73}.detail-section{--section-accent: var(--line-strong);position:relative;padding:10px 0 10px 10px;border-top:1px solid var(--line);border-left:2px solid color-mix(in srgb,var(--section-accent) 60%,transparent);background:linear-gradient(90deg,color-mix(in srgb,var(--section-accent) 7%,transparent),transparent 42%)}.detail-section#summary{--section-accent: var(--blue)}.detail-section#runtime{--section-accent: var(--green)}.detail-section#interfaces{--section-accent: var(--cyan)}.detail-section#data{--section-accent: var(--purple)}.detail-section#security{--section-accent: var(--yellow)}.detail-section#observability{--section-accent: #7df4ff}.detail-section#risks{--section-accent: var(--red)}.detail-section#decisions{--section-accent: #b9cacb}.detail-section#verification{--section-accent: var(--green)}.detail-section h3{margin:0 0 6px;color:var(--section-accent);font-family:var(--font-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase}.detail-section h3:before{display:inline-block;width:7px;height:7px;margin-right:7px;background:currentColor;content:""}.detail-section ul{margin:0;padding-left:18px}.detail-section li{margin:3px 0;color:var(--muted);line-height:1.35}.text-link{display:block;width:100%;margin:4px 0;padding:6px;text-align:left}.mini-record,.data-class{margin-top:8px;padding:8px;border:1px solid var(--line);border-radius:0;background:var(--panel-2)}.mini-record p,.data-class p{margin-top:6px}.path-pair{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:6px;align-items:center;margin:10px 0}.path-pair button{padding:7px}.filter-row{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.filter-row button{min-height:24px;padding:3px 6px;color:var(--muted);font-family:var(--font-mono);font-size:10px;text-transform:uppercase}.filter-row button.active{color:#002022;border-color:var(--blue);background:var(--blue)}.loading,.fatal{min-height:100%;display:grid;place-items:center;padding:24px}.fatal{place-items:start}.fatal pre{max-width:1100px;overflow:auto;padding:16px;border:1px solid var(--red);border-radius:0;color:var(--red);background:#1d1014}::-webkit-scrollbar{width:4px;height:4px}::-webkit-scrollbar-thumb{background:var(--line);border-radius:0}::-webkit-scrollbar-track{background:transparent}@media(max-width:900px){.app,.app.left-collapsed,.app.right-collapsed,.app.left-collapsed.right-collapsed{grid-template-columns:1fr;grid-template-rows:auto auto minmax(480px,1fr) auto;overflow:auto}.left-nav,.diagram-area,.details{grid-column:1;grid-row:auto}.left-nav,.details{max-height:420px}.side-toggle{display:none}.topbar,.diagram-header{flex-direction:column;align-items:stretch}.mode-tabs,.legend{justify-content:flex-start}}@media(max-width:760px){.app,.app.left-collapsed,.app.right-collapsed,.app.left-collapsed.right-collapsed{padding:8px;gap:8px}.app.left-collapsed,.app.right-collapsed,.app.left-collapsed.right-collapsed{grid-template-rows:auto auto minmax(520px,1fr) auto}.app.left-collapsed .left-nav,.app.right-collapsed .details{min-height:48px;max-height:56px}.side-toggle{display:grid}.details{max-height:70vh}.step-card{flex-basis:260px}.diagram-controls{flex-wrap:wrap}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";const wt=["left","right","top","bottom"],et=new Map;function Lt(t,n){return n==="left"?{x:t.x,y:t.y+t.height/2}:n==="right"?{x:t.x+t.width,y:t.y+t.height/2}:n==="top"?{x:t.x+t.width/2,y:t.y}:{x:t.x+t.width/2,y:t.y+t.height}}function vt(t){return t==="left"?{x:-1,y:0}:t==="right"?{x:1,y:0}:t==="top"?{x:0,y:-1}:{x:0,y:1}}function St(t){return t==="left"||t==="right"?{x:0,y:1}:{x:1,y:0}}function Rt(t,n,o){return Math.min(o,Math.max(n,t))}function At(t){const n=t%7,o=Math.floor(t/7);return(n-3)*6+o*6*7}function Ft(t,n,o=18,s=0){const e=Lt(t,n),a=vt(n),x=(n==="left"||n==="right"?t.height:t.width)/2-8,y=Rt(s,-x,x),r=St(n),u={x:e.x+r.x*y,y:e.y+r.y*y};return{anchor:u,port:{x:u.x+a.x*o,y:u.y+a.y*o}}}function _t(t,n,o){const s=(n==="left"||n==="right"?t.height:t.width)/2-8;return[...new Set(o.map(e=>Math.round(Rt(e,-s,s))))].map(e=>Ft(t,n,18,e))}function Ht(t,n){const o=Math.max(n.x-t.x,0,t.x-(n.x+n.width)),s=Math.max(n.y-t.y,0,t.y-(n.y+n.height));return o*o+s*s}function it(t){const n=[];for(let o=0;o<t.length-1;o+=1){const s=t[o],e=t[o+1];for(let a=1;a<=10;a+=1){const x=a/10;n.push({x:s.x+(e.x-s.x)*x,y:s.y+(e.y-s.y)*x})}}return n}function It(t,n,o=10){const s=[];for(let e=1;e<=o;e+=1){const a=e/o;s.push({x:t.x+(n.x-t.x)*a,y:t.y+(n.y-t.y)*a})}return s}function Wt(t,n,o,s){const e=1-s;return{x:e**2*t.x+2*e*s*n.x+s**2*o.x,y:e**2*t.y+2*e*s*n.y+s**2*o.y}}function Gt(t,n,o,s=12){const e=[];for(let a=1;a<=s;a+=1)e.push(Wt(t,n,o,a/s));return e}function zt(t,n){return t.reduce((o,s)=>{const e=Math.hypot(o.x-n.x,o.y-n.y);return Math.hypot(s.x-n.x,s.y-n.y)<e?s:o},t[0]??n)}function jt(t,n){const o=Math.max(t.x-(n.x+n.width),n.x-(t.x+t.width),0),s=Math.max(t.y-(n.y+n.height),n.y-(t.y+t.height),0);return Math.hypot(o,s)}function mt(t,n,o=0){return t.x<n.x+n.width+o&&t.x+t.width>n.x-o&&t.y<n.y+n.height+o&&t.y+t.height>n.y-o}function $t(t){if(!t.length)return{x:0,y:0,width:0,height:0};let n=t[0].x,o=t[0].x,s=t[0].y,e=t[0].y;for(let a=1;a<t.length;a+=1){const x=t[a];n=Math.min(n,x.x),o=Math.max(o,x.x),s=Math.min(s,x.y),e=Math.max(e,x.y)}return{x:n,y:s,width:o-n,height:e-s}}function Qt(t,n){if(!n)return null;const o=n.label??n.id??"",s=Math.max(24,Math.min(180,o.length*6+12)),e=n.relationshipType==="flow"||n.stepId?24:18;return{x:t.x-s/2,y:t.y-e/2,width:s,height:e}}function Tt(t){return[...new Set(t.map(n=>Math.round(n)))]}function Vt(){const t=[],n=(e,a)=>{const x=t[e];t[e]=t[a],t[a]=x};return{get size(){return t.length},push:e=>{t.push(e);let a=t.length-1;for(;a>0;){const x=Math.floor((a-1)/2);if(t[x].distance<=t[a].distance)break;n(x,a),a=x}},pop:()=>{if(t.length===0)return null;const e=t[0],a=t.pop();if(t.length>0){t[0]=a;let x=0;for(;;){const y=x*2+1,r=y+1;let u=x;if(y<t.length&&t[y].distance<t[u].distance&&(u=y),r<t.length&&t[r].distance<t[u].distance&&(u=r),u===x)break;n(x,u),x=u}}return e}}}function Yt(t,n,o,s=0){const e=o.x-s,a=o.x+o.width+s,x=o.y-s,y=o.y+o.height+s,r=Math.min(t.x,n.x),u=Math.max(t.x,n.x),k=Math.min(t.y,n.y),B=Math.max(t.y,n.y);return t.y===n.y?t.y>x&&t.y<y&&u>e&&r<a:t.x===n.x?t.x>e&&t.x<a&&B>x&&k<y:!1}function Xt(t,n,o,s){const e=Math.min(t.x,n.x),a=Math.max(t.x,n.x),x=Math.min(o.y,s.y),y=Math.max(o.y,s.y),r=o.x,u=t.y;return r<=e+6||r>=a-6||u<=x+6||u>=y-6?null:{x:r,y:u}}function Kt(t,n){const o=new Map;for(let s=0;s<t.length-1;s+=1){const e=t[s],a=t[s+1];if(!(e.x!==a.x&&e.y!==a.y))for(const x of n)for(let y=0;y<x.points.length-1;y+=1){const r=x.points[y],u=x.points[y+1];if(!(r.x!==u.x&&r.y!==u.y)){if(e.y===a.y&&r.x===u.x){const k=Xt(e,a,r,u);if(k){const B=Math.sign(a.x-e.x);o.set(s,[...o.get(s)??[],{...k,direction:B}])}}else if(e.x===a.x&&r.y===u.y){const k=Xt(r,u,e,a);if(k){const B=Math.sign(a.y-e.y);o.set(s,[...o.get(s)??[],{...k,direction:B}])}}}}}return o}function Jt(){const t=[],n=[],o=new Set,s=new Set;return{add:(y,r)=>{var k;if(!((k=y==null?void 0:y.points)!=null&&k.length))return;o.add(`${y.points[0].x},${y.points[0].y}`);const u=y.points.at(-1);s.add(`${u.x},${u.y}`);for(let B=0;B<y.points.length-1;B+=1){const v=y.points[B],P=y.points[B+1];v.y===P.y?t.push({routeIndex:r,y:v.y,minX:Math.min(v.x,P.x),maxX:Math.max(v.x,P.x),start:v,end:P}):v.x===P.x&&n.push({routeIndex:r,x:v.x,minY:Math.min(v.y,P.y),maxY:Math.max(v.y,P.y),start:v,end:P})}},crossingStats:y=>{const r=new Map;for(let B=0;B<y.length-1;B+=1){const v=y[B],P=y[B+1];if(!(v.x!==P.x&&v.y!==P.y))if(v.y===P.y){const Y=Math.min(v.x,P.x),E=Math.max(v.x,P.x);for(const T of n)T.x>Y+6&&T.x<E-6&&v.y>T.minY+6&&v.y<T.maxY-6&&r.set(T.routeIndex,(r.get(T.routeIndex)??0)+1)}else{const Y=Math.min(v.y,P.y),E=Math.max(v.y,P.y);for(const T of t)v.x>T.minX+6&&v.x<T.maxX-6&&T.y>Y+6&&T.y<E-6&&r.set(T.routeIndex,(r.get(T.routeIndex)??0)+1)}}const u=[...r.values()].reduce((B,v)=>B+v,0),k=[...r.values()].reduce((B,v)=>B+Math.max(0,v-1),0);return{total:u,repeated:k}},hasStackedEndpoint:y=>{var k;if(!((k=y==null?void 0:y.points)!=null&&k.length))return!1;const r=y.points[0],u=y.points.at(-1);return o.has(`${r.x},${r.y}`)||s.has(`${u.x},${u.y}`)}}}function Zt(t,n){const o=Kt(t,n);if(o.size===0)return at(t);const s=[`M ${t[0].x} ${t[0].y}`];for(let e=0;e<t.length-1;e+=1){const a=t[e],x=t[e+1],y=(o.get(e)??[]).sort((r,u)=>a.x===x.x?Math.abs(r.y-a.y)-Math.abs(u.y-a.y):Math.abs(r.x-a.x)-Math.abs(u.x-a.x));for(const r of y)if(a.y===x.y){const u={x:r.x-r.direction*6,y:r.y},k={x:r.x+r.direction*6,y:r.y};s.push(`L ${u.x} ${u.y}`),s.push(`Q ${r.x} ${r.y-6*1.6} ${k.x} ${k.y}`)}else{const u={x:r.x,y:r.y-r.direction*6},k={x:r.x,y:r.y+r.direction*6};s.push(`L ${u.x} ${u.y}`),s.push(`Q ${r.x+6*1.6} ${r.y} ${k.x} ${k.y}`)}s.push(`L ${x.x} ${x.y}`)}return s.join(" ")}function ut(t){const n=[];for(const s of t){const e=n[n.length-1];(!e||e.x!==s.x||e.y!==s.y)&&n.push(s)}const o=[];for(let s=0;s<n.length;s+=1){const e=n[s],a=o[o.length-1],x=o[o.length-2];s!==2&&s!==n.length-1&&a&&x&&(x.x===a.x&&a.x===e.x||x.y===a.y&&a.y===e.y)?o[o.length-1]=e:o.push(e)}return o}function at(t){return t.map((n,o)=>`${o===0?"M":"L"} ${n.x} ${n.y}`).join(" ")}function K(t){let n=0;for(let o=1;o<t.length-1;o+=1){const s=t[o-1],e=t[o],a=t[o+1];(s.x===e.x&&e.x!==a.x||s.y===e.y&&e.y!==a.y)&&(n+=1)}return n}function ft(t){let n=0;for(let o=1;o<t.length-2;o+=1){const s=t[o-1],e=t[o],a=t[o+1],x=t[o+2],y=Math.hypot(a.x-e.x,a.y-e.y),r=s.y===e.y&&a.y===x.y&&e.x===a.x,u=s.x===e.x&&a.x===x.x&&e.y===a.y;(r||u)&&y<36&&(n+=1)}return n}function kt(t){let n=0;for(let o=0;o<t.length-1;o+=1)n+=Math.hypot(t[o+1].x-t[o].x,t[o+1].y-t[o].y);return n}function qt(t){return Object.values(t).reduce((n,o)=>n+o,0)}function gt(t,n){const o={lengthCost:0,boundaryCost:0,nodeClearanceCost:0,edgeProximityCost:0,labelNodeClearanceCost:0,pointCountCost:0,bendCost:0,doglegCost:0,perimeterFallbackCost:0,perimeterLengthCost:0,directnessReward:0,crossingCost:0,repeatedCrossingCost:0,monotonicBacktrackCost:0,fanOutDirectionCost:0,endpointStackCost:0,...n};return{...t,qualityCosts:o,cost:qt(o)}}function Nt(t){if(kt(t.samples)>=70)return t;const o=t.points[0],s=t.points.every(a=>a.x===o.x),e=t.points.every(a=>a.y===o.y);return s?{...t,labelX:t.labelX+28}:e?{...t,labelY:t.labelY-22}:t}function Et(t,n,o){const s={x:n.x+n.width/2,y:n.y+n.height/2},e={x:o.x+o.width/2,y:o.y+o.height/2},a=Math.sign(e.x-s.x),x=Math.sign(e.y-s.y);let y=0;for(let r=0;r<t.length-1;r+=1){const u=t[r],k=t[r+1],B=k.x-u.x,v=k.y-u.y;a!==0&&Math.sign(B)===-a&&(y+=Math.abs(B)*18),x!==0&&Math.sign(v)===-x&&(y+=Math.abs(v)*18)}return y}function tn(t,n=14){if(t.length<3)return{d:at(t),samples:it(t)};const o=[`M ${t[0].x} ${t[0].y}`],s=[];let e=t[0];for(let x=1;x<t.length-1;x+=1){const y=t[x-1],r=t[x],u=t[x+1],k=Math.hypot(r.x-y.x,r.y-y.y),B=Math.hypot(u.x-r.x,u.y-r.y),v=Math.min(n,k/2,B/2);if(v<=0||k===0||B===0){o.push(`L ${r.x} ${r.y}`),s.push(...It(e,r)),e=r;continue}const P={x:r.x-(r.x-y.x)/k*v,y:r.y-(r.y-y.y)/k*v},Y={x:r.x+(u.x-r.x)/B*v,y:r.y+(u.y-r.y)/B*v};o.push(`L ${P.x} ${P.y}`),o.push(`Q ${r.x} ${r.y} ${Y.x} ${Y.y}`),s.push(...It(e,P)),s.push(...Gt(P,r,Y)),e=Y}const a=t[t.length-1];return o.push(`L ${a.x} ${a.y}`),s.push(...It(e,a)),{d:o.join(" "),samples:s}}function nn(t,n,o){if(n==="curved"){const s=tn(t.points),e=zt(s.samples,{x:t.labelX,y:t.labelY});return Nt({...t,...s,sampleBounds:$t(s.samples),labelX:e.x,labelY:e.y,style:n})}return Nt({...t,d:Zt(t.points,o),sampleBounds:$t(t.samples),style:"orthogonal"})}function Pt(t){return Array.from(t.entries()).sort(([n],[o])=>String(n).localeCompare(String(o)))}function on(t){return JSON.stringify({relationships:t.relationships.map(n=>({id:n.id,from:n.from,to:n.to,label:n.label,relationshipType:n.relationshipType,stepId:n.stepId,flowId:n.flowId})),visibleNodeIds:Array.from(t.visibleNodeIds).sort(),nodeRects:Pt(t.nodeRects),laneIndexByNode:Pt(t.laneIndexByNode),rowIndexByNode:Pt(t.rowIndexByNode),canvasWidth:t.canvasWidth,canvasHeight:t.canvasHeight,marginY:t.marginY,scoreEdgeProximity:!!t.scoreEdgeProximity})}function sn(t){const n=et.get(t);return n?(et.delete(t),et.set(t,n),n):null}function en(t,n){for(et.set(t,n);et.size>12;)et.delete(et.keys().next().value)}function an(t){const n=new Set(t.visibleNodeIds),o=c=>t.nodeRects.get(c),s=Array.from(n).map(o).filter(Boolean),e=new Map,a=t.stats??null,x=(c,i)=>{const d=`${c}\0${i}`,f=e.get(d);if(f)return f;const w=Array.from(n).filter(I=>I!==c&&I!==i).map(o).filter(Boolean);return e.set(d,w),w},y=(c,i,d,f,w,I)=>{const p=x(d,f),h=$t(c),b=p.filter(m=>mt(h,m,30)),C=Qt(i,I),g=p.filter(m=>{const R={x:i.x,y:i.y,width:0,height:0};return mt(R,m,34)||C&&mt(C,m,6)}),D={lengthCost:0,boundaryCost:0,nodeClearanceCost:0,edgeProximityCost:0,labelNodeClearanceCost:0};for(let m=0;m<c.length-1;m+=1)D.lengthCost+=Math.hypot(c[m+1].x-c[m].x,c[m+1].y-c[m].y);for(const m of c){(m.y<30||m.x<16||m.x>t.canvasWidth-16||m.y>t.canvasHeight-16)&&(D.boundaryCost+=14e3);for(const R of b){const O=Ht(m,R);if(O<900){const N=Math.sqrt(O);N<14&&(D.nodeClearanceCost+=12e3),D.nodeClearanceCost+=(30-N)*120}}if(t.scoreEdgeProximity)for(const R of w)for(let O=0;O<R.length;O+=2){const N=R[O],Q=Math.hypot(m.x-N.x,m.y-N.y);Q<26&&(D.edgeProximityCost+=450),Q<12&&(D.edgeProximityCost+=1600)}}for(const m of g)Ht(i,m)<1156&&(D.labelNodeClearanceCost+=24e3),C&&mt(C,m,6)&&(D.labelNodeClearanceCost+=6e4);return D},r=(c,i,d,f=0)=>{let w=0;for(const I of x(i,d)){let p=!1;for(let h=0;h<c.points.length-1;h+=1)if(Yt(c.points[h],c.points[h+1],I,f)){p=!0;break}p&&(w+=1)}return w},u=(c,i,d,f,w,I,p,h,b)=>{a&&(a.gridRouteCalls=(a.gridRouteCalls??0)+1);const C=h.port,g=b.port,D=o(i),m=o(d),R=x(i,d),O=10,N=24,Q=t.canvasWidth-24,rt=30,Ct=t.canvasHeight-24,ht=($,M,H,L)=>$.add(Math.min(L,Math.max(H,Math.round(M)))),xt=new Set([Math.round(C.x),Math.round(g.x),N,Q]),yt=new Set([Math.round(C.y),Math.round(g.y),rt,Ct]);for(const $ of R)ht(xt,$.x-O-I,N,Q),ht(xt,$.x+$.width+O+I,N,Q),ht(yt,$.y-O-I,rt,Ct),ht(yt,$.y+$.height+O+I,rt,Ct);const F=[...xt].sort(($,M)=>$-M),X=[...yt].sort(($,M)=>$-M),q=[],nt=new Map;for(const $ of F)for(const M of X){const H=`${$},${M}`;nt.set(H,q.length),q.push({x:$,y:M})}const dt=$=>`${Math.round($.x)},${Math.round($.y)}`,S=nt.get(dt(C)),l=nt.get(dt(g));if(S===void 0||l===void 0)return null;const A=Array.from({length:q.length},()=>[]),G=new Map(X.map($=>[$,R.filter(M=>$>M.y-O&&$<M.y+M.height+O)])),U=new Map(F.map($=>[$,R.filter(M=>$>M.x-O&&$<M.x+M.width+O)])),V=($,M,H)=>{const L=Math.min(M,H),z=Math.max(M,H);return(G.get($)??[]).every(j=>z<=j.x-O||L>=j.x+j.width+O)},Bt=($,M,H)=>{const L=Math.min(M,H),z=Math.max(M,H);return(U.get($)??[]).every(j=>z<=j.y-O||L>=j.y+j.height+O)};for(const $ of X)for(let M=0;M<F.length-1;M+=1){const H=nt.get(`${F[M]},${$}`),L=nt.get(`${F[M+1]},${$}`);if(V($,F[M],F[M+1])){const z=Math.abs(F[M+1]-F[M]);A[H].push([L,z]),A[L].push([H,z])}}for(const $ of F)for(let M=0;M<X.length-1;M+=1){const H=nt.get(`${$},${X[M]}`),L=nt.get(`${$},${X[M+1]}`);if(Bt($,X[M],X[M+1])){const z=Math.abs(X[M+1]-X[M]);A[H].push([L,z]),A[L].push([H,z])}}const ot=new Array(q.length).fill(1/0),ct=new Array(q.length).fill(-1),Dt=new Uint8Array(q.length),Mt=Vt();for(ot[S]=0,Mt.push({index:S,distance:0});Mt.size>0;){const $=Mt.pop();if(!$||$.distance!==ot[$.index])continue;const M=$.index;if(M===l)break;if(!Dt[M]){Dt[M]=1;for(const[H,L]of A[M]){if(Dt[H])continue;const z=ct[M]>=0&&(q[ct[M]].x!==q[M].x&&q[M].x!==q[H].x||q[ct[M]].y!==q[M].y&&q[M].y!==q[H].y)?18:0,j=ot[M]+L+z;j<ot[H]&&(ot[H]=j,ct[H]=M,Mt.push({index:H,distance:j}))}}}if(!Number.isFinite(ot[l]))return null;const Ut=[];for(let $=l;$!==-1;$=ct[$])Ut.unshift(q[$]);const st=ut([h.anchor,...Ut,b.anchor]),bt=it(st),Ot=bt[Math.floor(bt.length/2)]??{x:(C.x+g.x)/2,y:(C.y+g.y)/2},yn=Et(st,D,m);return gt({d:at(st),labelX:Ot.x,labelY:Ot.y,bends:K(st),samples:bt,points:st},{...y(bt,Ot,i,d,p,c),pointCountCost:st.length*24,bendCost:K(st)*420,doglegCost:ft(st)*14e3,monotonicBacktrackCost:yn})},k=(c,i,d,f,w,I,p,h)=>{const b=p.port,C=h.port,g=f==="left"?24+w:f==="right"?t.canvasWidth-24-w:f==="top"?30+w:t.canvasHeight-24-w,D=f==="left"||f==="right"?[p.anchor,b,{x:g,y:b.y},{x:g,y:C.y},C,h.anchor]:[p.anchor,b,{x:b.x,y:g},{x:C.x,y:g},C,h.anchor],m=ut(D),R=it(m),O=R[Math.floor(R.length/2)]??{x:(b.x+C.x)/2,y:(b.y+C.y)/2};return gt({d:at(m),labelX:O.x,labelY:O.y,bends:K(m),samples:R,points:m},{...y(R,O,i,d,I,c),perimeterFallbackCost:7e3,perimeterLengthCost:kt(R)*8,pointCountCost:m.length*24,bendCost:K(m)*420,doglegCost:ft(m)*14e3})},B=(c,i,d,f,w,I,p)=>{const h=[{x:24+f,y:30+f},{x:t.canvasWidth-24-f,y:30+f},{x:24+f,y:t.canvasHeight-24-f},{x:t.canvasWidth-24-f,y:t.canvasHeight-24-f}],b=I.port,C=p.port;return h.flatMap(g=>[[I.anchor,b,{x:g.x,y:b.y},g,{x:g.x,y:C.y},C,p.anchor],[I.anchor,b,{x:b.x,y:g.y},g,{x:C.x,y:g.y},C,p.anchor]]).map(g=>{const D=ut(g),m=it(D),R=D[0],O=D[D.length-1],N=m[Math.floor(m.length/2)]??{x:(R.x+O.x)/2,y:(R.y+O.y)/2};return gt({d:at(D),labelX:N.x,labelY:N.y,bends:K(D),samples:m,points:D},{...y(m,N,i,d,w,c),perimeterFallbackCost:12e3,perimeterLengthCost:kt(m)*10,pointCountCost:D.length*24,bendCost:K(D)*420,doglegCost:ft(D)*14e3})})},v=(c,i,d,f,w,I,p,h)=>{const b=vt(f),C=vt(w),g=p.port.y===h.port.y&&b.y===0&&C.y===0,D=p.port.x===h.port.x&&b.x===0&&C.x===0;if(!g&&!D)return null;const m=ut([p.anchor,p.port,h.port,h.anchor]),R=it(m),O=R[Math.floor(R.length/2)]??{x:(p.anchor.x+h.anchor.x)/2,y:(p.anchor.y+h.anchor.y)/2};return gt({d:at(m),labelX:O.x,labelY:O.y,bends:K(m),samples:R,points:m},{...y(R,O,i,d,I,c),directnessReward:-2e3,doglegCost:ft(m)*14e3})},P=(c,i,d,f,w,I,p)=>{const h=w.port,b=I.port,C=p.axis==="x"?[w.anchor,h,{x:p.value,y:h.y},{x:p.value,y:b.y},b,I.anchor]:[w.anchor,h,{x:h.x,y:p.value},{x:b.x,y:p.value},b,I.anchor],g=ut(C);if(!x(i,d).every(O=>g.slice(0,-1).every((N,Q)=>!Yt(N,g[Q+1],O,10))))return null;const m=it(g),R=m[Math.floor(m.length/2)]??{x:(h.x+b.x)/2,y:(h.y+b.y)/2};return gt({d:at(g),labelX:R.x,labelY:R.y,bends:K(g),samples:m,points:g},{...y(m,R,i,d,f,c),pointCountCost:g.length*24,bendCost:K(g)*420,doglegCost:ft(g)*14e3,monotonicBacktrackCost:Et(g,o(i),o(d))})},Y=(c,i)=>{const d=[],f=Math.min(c.y,i.y)+Math.min(c.height,i.height),w=Math.max(c.y,i.y);w-f>36&&d.push({axis:"y",value:Math.round((f+w)/2)});const I=Math.min(c.x,i.x)+Math.min(c.width,i.width),p=Math.max(c.x,i.x);return p-I>36&&d.push({axis:"x",value:Math.round((I+p)/2)}),d},E=c=>{const i=new Set;return c.filter(d=>{const f=`${d.axis}:${d.value}`;return i.has(f)?!1:(i.add(f),!0)})},J=(()=>{const i=t.canvasWidth-24,d=30,f=t.canvasHeight-24,w=Tt(s.flatMap(h=>[h.x,h.x+h.width])).sort((h,b)=>h-b),I=Tt(s.flatMap(h=>[h.y,h.y+h.height])).sort((h,b)=>h-b),p=[];for(let h=0;h<w.length-1;h+=1){const b=w[h],C=w[h+1];if(C-b>30){const g=Math.round((b+C)/2);g>24&&g<i&&p.push({axis:"x",value:g})}}for(let h=0;h<I.length-1;h+=1){const b=I[h],C=I[h+1];if(C-b>30){const g=Math.round((b+C)/2);g>d&&g<f&&p.push({axis:"y",value:g})}}return p})(),Z=(c,i)=>{const d=Math.min(c.x,i.x)-36,f=Math.max(c.x+c.width,i.x+i.width)+36,w=Math.min(c.y,i.y)-36,I=Math.max(c.y+c.height,i.y+i.height)+36,p={x:(c.x+c.width/2+i.x+i.width/2)/2,y:(c.y+c.height/2+i.y+i.height/2)/2},h=J.filter(C=>C.axis==="x"?C.value>=d&&C.value<=f:C.value>=w&&C.value<=I),b=C=>h.filter(g=>g.axis===C).sort((g,D)=>Math.abs(g.value-p[C])-Math.abs(D.value-p[C])).slice(0,6);return E([...Y(c,i),...b("x"),...b("y")])},W=(c,i,d,f,w,I="cheap")=>{const p={x:c.x+c.width/2,y:c.y+c.height/2},h={x:i.x+i.width/2,y:i.y+i.height/2},b=St(d),C=St(f),g=b.y!==0?h.y-p.y:h.x-p.x,D=C.y!==0?p.y-h.y:p.x-h.x,m=I==="grid"?[0,w.from,w.to]:[0,w.from,w.to,w.from+g,w.to+D];return{starts:_t(c,d,m),ends:_t(i,f,m)}},lt=(c,i)=>{const d={x:c.x+c.width/2,y:c.y+c.height/2},f={x:i.x+i.width/2,y:i.y+i.height/2},w=f.x>=d.x?["right","left"]:["left","right"],I=f.y>=d.y?["bottom","top"]:["top","bottom"],p=[Math.abs(f.x-d.x)>=Math.abs(f.y-d.y)?w:I,Math.abs(f.x-d.x)>=Math.abs(f.y-d.y)?I:w,["left","right"],["right","left"],["top","bottom"],["bottom","top"],["left","left"],["right","right"],["top","top"],["bottom","bottom"]],h=new Set;return p.filter(([b,C])=>{const g=`${b}:${C}`;return h.has(g)?!1:(h.add(g),!0)})},tt=c=>{const i=[],d=new Set,f=(w,I)=>{if(!w||!I)return;const p=`${w.anchor.x},${w.anchor.y}:${I.anchor.x},${I.anchor.y}`;d.has(p)||(d.add(p),i.push([w,I]))};for(const w of c.starts)for(const I of c.ends)f(w,I);return i};return{edgePath:(c,i,d,f,w,I,p)=>{const{from:h,to:b}=c,C=o(h),g=o(b);t.laneIndexByNode.get(h),t.laneIndexByNode.get(b);const D=[],m=new Set,R=S=>{if(!S)return;const l=S.points.map(A=>`${A.x},${A.y}`).join("|");m.has(l)||(m.add(l),D.push(S))},O=Z(C,g),N=lt(C,g),Q=wt.flatMap(S=>wt.map(l=>[S,l])),rt=d*40+i%2*10,Ct=Math.min(C.y,g.y),ht=Math.max(C.y+C.height,g.y+g.height),xt=S=>{S.forEach(l=>{const A=l.samples.some(V=>V.y<Ct-4),G=l.samples.some(V=>V.y>ht+4);l.collisions=r(l,h,b,0),l.paddedCollisions=r(l,h,b,8);const U=I.crossingStats(l.points);l.crossings=U.total,l.repeatedCrossings=U.repeated,l.qualityCosts.crossingCost=U.total*3e3,l.qualityCosts.repeatedCrossingCost=U.repeated*4e4,l.qualityCosts.endpointStackCost=I.hasStackedEndpoint(l)?9e4:0,d%2===1&&A&&(l.qualityCosts.fanOutDirectionCost=(l.qualityCosts.fanOutDirectionCost??0)+25e3),d%2===1&&!G&&(l.qualityCosts.fanOutDirectionCost=(l.qualityCosts.fanOutDirectionCost??0)+4e3),d%2===0&&G&&(l.qualityCosts.fanOutDirectionCost=(l.qualityCosts.fanOutDirectionCost??0)+600),l.cost=qt(l.qualityCosts)})},yt=S=>S.sort((l,A)=>l.collisions-A.collisions||l.paddedCollisions-A.paddedCollisions||l.repeatedCrossings-A.repeatedCrossings||l.crossings-A.crossings||(l.qualityCosts.monotonicBacktrackCost>0?1:0)-(A.qualityCosts.monotonicBacktrackCost>0?1:0)||(l.qualityCosts.endpointStackCost>0?1:0)-(A.qualityCosts.endpointStackCost>0?1:0)||(l.qualityCosts.perimeterFallbackCost>0?1:0)-(A.qualityCosts.perimeterFallbackCost>0?1:0)||l.bends-A.bends||l.cost-A.cost),F=S=>S.collisions===0&&S.paddedCollisions===0&&S.repeatedCrossings===0&&S.crossings===0&&S.qualityCosts.endpointStackCost===0&&S.qualityCosts.perimeterFallbackCost===0&&S.qualityCosts.doglegCost===0,X=[],q=S=>{if(!S)return;const l=S.points.map(A=>`${A.x},${A.y}`).join("|");m.has(l)||(m.add(l),X.push(S))};(S=>{S.forEach(([l,A])=>{const G=W(C,g,l,A,p);for(const[U,V]of tt(G)){const Bt=v(c,h,b,l,A,f,U,V);q(Bt);for(const ot of O){const ct=P(c,h,b,f,U,V,ot);q(ct)}}})})(Q),xt(X);const dt=X.some(F);if(a&&(a.edgesPlanned=(a.edgesPlanned??0)+1,a.cheapCandidateCount=(a.cheapCandidateCount??0)+X.length,!dt)){a.gridEscalations=(a.gridEscalations??0)+1;const S=yt([...X])[0],l=a.cheapRejectionReasons??{};S?(S.collisions>0&&(l.collisions=(l.collisions??0)+1),S.paddedCollisions>0&&(l.paddedCollisions=(l.paddedCollisions??0)+1),S.repeatedCrossings>0&&(l.repeatedCrossings=(l.repeatedCrossings??0)+1),S.crossings>0&&(l.crossings=(l.crossings??0)+1),S.qualityCosts.endpointStackCost>0&&(l.endpointStack=(l.endpointStack??0)+1),S.qualityCosts.doglegCost>0&&(l.dogleg=(l.dogleg??0)+1)):l.noCandidate=(l.noCandidate??0)+1,a.cheapRejectionReasons=l}return dt?D.push(...X):(D.push(...X),N.forEach(([S,l])=>{const A=W(C,g,S,l,p,"grid");for(const[G,U]of tt(A)){const V=u(c,h,b,S,l,rt,f,G,U);R(V)}})),dt||wt.forEach(S=>{const l=W(C,g,S,S,p);for(const[A,G]of tt(l)){R(k(c,h,b,S,rt,f,A,G));for(const U of B(c,h,b,rt,f,A,G))R(U)}}),xt(D.filter(S=>S.collisions===void 0)),yt(D).map(S=>{const l=[];return(S.collisions>0||S.paddedCollisions>0)&&l.push({code:"least-bad-route",message:"No clean route was available for the current node arrangement."}),S.repeatedCrossings>0&&l.push({code:"repeated-route-crossing",message:"Selected route crosses the same existing route more than once."}),S.qualityCosts.perimeterFallbackCost>0&&l.push({code:"perimeter-fallback-route",message:"Selected route used a perimeter fallback instead of an interior corridor."}),jt(C,g)<36&&l.push({code:"nodes-too-close",message:"Source and target nodes are too close for clean connector routing."}),{...S,warnings:l}})[0]}}}function rn(t){const n=[],o=[],s=Jt(),e=new Map,a=new Map,x=on(t),y=sn(x),r=y??[],u=y?null:an(t),k=t.style==="curved"?"curved":"orthogonal";y||(t.relationships.forEach((P,Y)=>{if(!t.laneIndexByNode.has(P.from)||!t.laneIndexByNode.has(P.to))return;const E=[P.from,P.to].sort().join("<->"),T=e.get(E)??0;e.set(E,T+1);const J=a.get(P.from)??0,Z=a.get(P.to)??0;a.set(P.from,J+1),a.set(P.to,Z+1);const W=u.edgePath(P,Y,T,n,o,s,{from:At(J),to:At(Z)});r.push([P.id,W]),n.push(W.samples),o.push(W),s.add(W,o.length-1)}),en(x,r));const B=new Map,v=[];for(const[P,Y]of r){const E=nn(Y,k,v);B.set(P,E),v.push(E)}return B}function cn(t,n,o){const s=o.label??o.id??"",e=Math.max(24,Math.min(180,s.length*6+12)),a=o.relationshipType==="flow"||o.stepId?24:18;return{x:t-e/2,y:n-a/2,width:e,height:a}}function pt(t,n,o=0){return t.x<n.x+n.width+o&&t.x+t.width>n.x-o&&t.y<n.y+n.height+o&&t.y+t.height>n.y-o}function ln(t){const n=[];for(const o of[0,-24,24,-48,48,-72,72,-96,96,-120,120,-144,144,-168,168,-192,192])for(const s of[0,36,-36,64,-64,96,-96,128,-128])n.push([s,o]);return n.sort((o,s)=>Math.hypot(o[0],o[1])-Math.hypot(s[0],s[1])).map(([o,s])=>({x:t.labelX+o,y:t.labelY+s}))}function hn(t,n,o,s,e,a){return ln(t).map((r,u)=>{const k=cn(r.x,r.y,n),B={labelMovementCost:Math.hypot(r.x-t.labelX,r.y-t.labelY),labelSearchOrderCost:u*4,labelBoundaryCost:0,labelNodeConflictCost:0,labelConflictCost:0};(k.x<8||k.y<8||k.x+k.width>e-8||k.y+k.height>a-8)&&(B.labelBoundaryCost+=1e5);for(const[v,P]of o)v===n.from||v===n.to||pt(k,P,4)&&(B.labelNodeConflictCost+=8e4);for(const v of s)pt(k,v,2)&&(B.labelConflictCost+=2e4);return{candidate:r,box:k,cost:Object.values(B).reduce((v,P)=>v+P,0),qualityCosts:B}}).sort((r,u)=>r.cost-u.cost)[0]}function xn(t){const n=t.nodeWidth,o=t.nodeHeight,s=t.laneWidth,e=t.rowGap,a=t.marginX,x=t.marginY,y=new Set(t.visibleNodeIds),r=new Map,u=new Map;t.view.lanes.forEach((_,c)=>{_.nodeIds.forEach((i,d)=>{y.has(i)&&(r.set(i,c),u.set(i,d))})});const k=Math.max(...t.view.lanes.map(_=>_.nodeIds.filter(c=>y.has(c)).length),1),B=Math.max(t.minCanvasWidth,a*2+t.view.lanes.length*s+t.canvasExtraWidth),v=Math.max(t.minCanvasHeight,x+k*e+t.canvasExtraHeight),P=_=>({x:a+(r.get(_)??0)*s,y:x+(u.get(_)??0)*e}),Y=new Map(Array.from(y).map(_=>{const c=P(_);return[_,{x:c.x,y:c.y,width:n,height:o}]})),E=rn({relationships:t.relationships,visibleNodeIds:y,nodeRects:Y,laneIndexByNode:r,rowIndexByNode:u,canvasWidth:B,canvasHeight:v,marginY:x,style:t.style,stats:t.stats}),T=new Map(t.relationships.map(_=>[_.id,_])),J=new Map,Z=new Map,W=[];for(const[_,c]of E){const i=T.get(_);if(i){const d=hn(c,i,Y,W,B,v),f={...c.qualityCosts,labelMovementCost:0,labelSearchOrderCost:0,labelBoundaryCost:0,labelNodeConflictCost:0,labelConflictCost:0,...d.qualityCosts},w={...c,labelX:d.candidate.x,labelY:d.candidate.y,qualityCosts:f,cost:Object.values(f).reduce((I,p)=>I+p,0)};J.set(_,w),Z.set(_,d.box),W.push(d.box)}else J.set(_,c)}const lt=[];for(const[_,c]of J)for(const i of c.warnings??[])lt.push({...i,relationshipId:_});for(const[_,c]of Z){const i=T.get(_);for(const[d,f]of Y)d===(i==null?void 0:i.from)||d===(i==null?void 0:i.to)||pt(c,f,4)&<.push({code:"label-over-node",message:"Route label overlaps a non-endpoint node.",relationshipId:_,nodeId:d})}const tt=[...Z];for(let _=0;_<tt.length;_+=1){const[c,i]=tt[_];for(let d=_+1;d<tt.length;d+=1){const[f,w]=tt[d];pt(i,w,2)&<.push({code:"label-over-label",message:"Route label overlaps another route label.",relationshipId:c,otherRelationshipId:f})}}return{canvasWidth:B,canvasHeight:v,nodeWidth:n,nodeHeight:o,laneWidth:s,rowGap:e,marginX:a,marginY:x,visibleNodeIds:y,laneIndexByNode:r,rowIndexByNode:u,nodeRects:Y,routes:J,labelBoxes:Z,warnings:lt,positionFor:P}}self.onmessage=t=>{const{key:n,input:o}=t.data;try{const s=xn(o),{positionFor:e,...a}=s;self.postMessage({key:n,plan:a})}catch(s){self.postMessage({key:n,error:s instanceof Error?s.message:String(s)})}}})();
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/compass.svg" />
|
|
7
7
|
<title>Architext</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DMbdxljw.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DvokFPhn.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|