@@ -1854,9 +1854,12 @@ function NodeCanvas() {
18541854 const initializeFromFolder = async () => {
18551855 try {
18561856 console.log('[NodeCanvas] Checking for stored folder on startup...');
1857+ console.log('[NodeCanvas Debug] Session Param:', new URLSearchParams(window.location.search).get('session'));
18571858
18581859 // Validate stored folder
1859- const { valid, folderHandle } = await folderPersistence.validateStoredFolder();
1860+ const validationResult = await folderPersistence.validateStoredFolder();
1861+ const { valid, folderHandle } = validationResult;
1862+ console.log('[NodeCanvas Debug] Folder Validation Result:', validationResult);
18601863
18611864 if (!valid || !folderHandle) {
18621865 console.log('[NodeCanvas] No valid stored folder found');
@@ -1944,7 +1947,27 @@ function NodeCanvas() {
19441947 !!universeLoadingError
19451948 );
19461949
1950+ // Debug logging for onboarding state
1951+ if (typeof window !== 'undefined') {
1952+ const params = new URLSearchParams(window.location.search);
1953+ console.log('[NodeCanvas Debug] Onboarding State Check:', {
1954+ url: window.location.href,
1955+ search: window.location.search,
1956+ sessionParam: params.get('session'),
1957+ storageKey: getStorageKey('redstring-alpha-welcome-seen'),
1958+ rawValue: localStorage.getItem(getStorageKey('redstring-alpha-welcome-seen')),
1959+ hasCompletedOnboarding,
1960+ suppressForGitFlow,
1961+ isUniverseLoading,
1962+ hasUniverseFile,
1963+ isUniverseLoaded,
1964+ universeLoadingError,
1965+ shouldShowOnboarding
1966+ });
1967+ }
1968+
19471969 if (shouldShowOnboarding && !showOnboardingModal) {
1970+ console.log('[NodeCanvas Debug] Showing onboarding modal!');
19481971 setShowOnboardingModal(true);
19491972 }
19501973 }, [isUniverseLoading, hasUniverseFile, isUniverseLoaded, universeLoadingError, showOnboardingModal]);
@@ -10581,6 +10604,12 @@ function NodeCanvas() {
1058110604 manhattanSourceSide = sSide;
1058210605 manhattanDestSide = dSide;
1058310606 }
10607+
10608+ // Calculate parallel edge path using centralized utility
10609+ const curveInfo = edgeCurveInfo.get(edge.id);
10610+ const parallelPath = calculateParallelEdgePath(startX, startY, endX, endY, curveInfo);
10611+ const useCurve = parallelPath.type === 'curve';
10612+
1058410613 return (
1058510614 <g key={`edge-above-${edge.id}-${idx}`}>
1058610615 {/* Main edge line - always same thickness */}
@@ -10602,54 +10631,32 @@ function NodeCanvas() {
1060210631 }}
1060310632 strokeLinecap="round"
1060410633 />
10605- ) : (() => {
10606- // Glow effect also needs curve for multi-edge pairs
10607- const curveInfo = edgeCurveInfo.get(edge.id);
10608- if (curveInfo && curveInfo.totalInPair > 1) {
10609- const { pairIndex, totalInPair } = curveInfo;
10610- const curveSpacing = 100;
10611- // Alternating direction logic matching utils
10612- const direction = pairIndex % 2 === 0 ? 1 : -1;
10613- const offsetMagnitude = Math.floor((pairIndex + 1) / 2) * curveSpacing;
10614- const perpOffset = direction * offsetMagnitude;
10615- const edgeDx = endX - startX;
10616- const edgeDy = endY - startY;
10617- const edgeLen = Math.sqrt(edgeDx * edgeDx + edgeDy * edgeDy);
10618- const perpX = edgeLen > 0 ? -edgeDy / edgeLen : 0;
10619- const perpY = edgeLen > 0 ? edgeDx / edgeLen : 0;
10620- const curveMidX = (startX + endX) / 2;
10621- const curveMidY = (startY + endY) / 2;
10622- const ctrlX = curveMidX + perpX * perpOffset;
10623- const ctrlY = curveMidY + perpY * perpOffset;
10624- return (
10625- <path
10626- d={`M ${startX} ${startY} Q ${ctrlX} ${ctrlY} ${endX} ${endY}`}
10627- fill="none"
10628- stroke={edgeColor}
10629- strokeWidth="12"
10630- opacity={isSelected ? "0.3" : "0.2"}
10631- style={{
10632- filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
10633- }}
10634- strokeLinecap="round"
10635- />
10636- );
10637- }
10638- return (
10639- <line
10640- x1={startX}
10641- y1={startY}
10642- x2={endX}
10643- y2={endY}
10644- stroke={edgeColor}
10645- strokeWidth="12"
10646- opacity={isSelected ? "0.3" : "0.2"}
10647- style={{
10648- filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
10649- }}
10650- />
10651- );
10652- })()
10634+ ) : useCurve ? (
10635+ <path
10636+ d={parallelPath.path}
10637+ fill="none"
10638+ stroke={edgeColor}
10639+ strokeWidth="12"
10640+ opacity={isSelected ? "0.3" : "0.2"}
10641+ style={{
10642+ filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
10643+ }}
10644+ strokeLinecap="round"
10645+ />
10646+ ) : (
10647+ <line
10648+ x1={startX}
10649+ y1={startY}
10650+ x2={endX}
10651+ y2={endY}
10652+ stroke={edgeColor}
10653+ strokeWidth="12"
10654+ opacity={isSelected ? "0.3" : "0.2"}
10655+ style={{
10656+ filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
10657+ }}
10658+ />
10659+ )
1065310660 )}
1065410661
1065510662 {(enableAutoRouting && (routingStyle === 'manhattan' || routingStyle === 'clean')) ? (
@@ -10673,54 +10680,26 @@ function NodeCanvas() {
1067310680 strokeLinecap="round"
1067410681 />
1067510682 </>
10676- ) : (() => {
10677- // Check if this edge needs curve offset (multiple edges between same nodes)
10678- const curveInfo = edgeCurveInfo.get(edge.id);
10679- if (curveInfo && curveInfo.totalInPair > 1) {
10680- // Calculate curve offset for parallel edges
10681- const { pairIndex, totalInPair } = curveInfo;
10682- const curveSpacing = 100; // Exaggerated curves
10683- const direction = pairIndex % 2 === 0 ? 1 : -1;
10684- const offsetMagnitude = Math.floor((pairIndex + 1) / 2) * curveSpacing;
10685- const perpOffset = direction * offsetMagnitude;
10686-
10687- // Calculate perpendicular direction
10688- const edgeDx = endX - startX;
10689- const edgeDy = endY - startY;
10690- const edgeLen = Math.sqrt(edgeDx * edgeDx + edgeDy * edgeDy);
10691- const perpX = edgeLen > 0 ? -edgeDy / edgeLen : 0;
10692- const perpY = edgeLen > 0 ? edgeDx / edgeLen : 0;
10693-
10694- // Control point at midpoint, offset perpendicular to edge
10695- const curveMidX = (startX + endX) / 2;
10696- const curveMidY = (startY + endY) / 2;
10697- const ctrlX = curveMidX + perpX * perpOffset;
10698- const ctrlY = curveMidY + perpY * perpOffset;
10699-
10700- return (
10701- <path
10702- d={`M ${startX} ${startY} Q ${ctrlX} ${ctrlY} ${endX} ${endY}`}
10703- fill="none"
10704- stroke={edgeColor}
10705- strokeWidth={showConnectionNames ? "16" : "6"}
10706- style={{ transition: 'stroke 0.2s ease' }}
10707- strokeLinecap="round"
10708- />
10709- );
10710- }
10711- // Single edge - render as straight line
10712- return (
10713- <line
10714- x1={startX}
10715- y1={startY}
10716- x2={endX}
10717- y2={endY}
10718- stroke={edgeColor}
10719- strokeWidth={showConnectionNames ? "16" : "6"}
10720- style={{ transition: 'stroke 0.2s ease' }}
10721- />
10722- );
10723- })()}
10683+ ) : useCurve ? (
10684+ <path
10685+ d={parallelPath.path}
10686+ fill="none"
10687+ stroke={edgeColor}
10688+ strokeWidth={showConnectionNames ? "16" : "6"}
10689+ style={{ transition: 'stroke 0.2s ease' }}
10690+ strokeLinecap="round"
10691+ />
10692+ ) : (
10693+ <line
10694+ x1={startX}
10695+ y1={startY}
10696+ x2={endX}
10697+ y2={endY}
10698+ stroke={edgeColor}
10699+ strokeWidth={showConnectionNames ? "16" : "6"}
10700+ style={{ transition: 'stroke 0.2s ease' }}
10701+ />
10702+ )}
1072410703
1072510704 {/* Connection name text - only show when enabled */}
1072610705 {showConnectionNames && (() => {
@@ -10740,31 +10719,10 @@ function NodeCanvas() {
1074010719 angle = 90;
1074110720 }
1074210721 } else {
10743- // Curve apex logic for labels
10744- const curveInfo = edgeCurveInfo.get(edge.id);
10745- if (curveInfo && curveInfo.totalInPair > 1) {
10746- const { pairIndex } = curveInfo;
10747- const curveSpacing = 100;
10748- const direction = pairIndex % 2 === 0 ? 1 : -1;
10749- const offsetMagnitude = Math.floor((pairIndex + 1) / 2) * curveSpacing;
10750- const perpOffset = direction * offsetMagnitude;
10751- const edgeDx = endX - startX;
10752- const edgeDy = endY - startY;
10753- const edgeLen = Math.sqrt(edgeDx * edgeDx + edgeDy * edgeDy);
10754- const perpX = edgeLen > 0 ? -edgeDy / edgeLen : 0;
10755- const perpY = edgeLen > 0 ? edgeDx / edgeLen : 0;
10756- const curveMidX = (startX + endX) / 2;
10757- const curveMidY = (startY + endY) / 2;
10758- const ctrlX = curveMidX + perpX * perpOffset;
10759- const ctrlY = curveMidY + perpY * perpOffset;
10760- midX = 0.25 * startX + 0.5 * ctrlX + 0.25 * endX;
10761- midY = 0.25 * startY + 0.5 * ctrlY + 0.25 * endY;
10762- angle = Math.atan2(edgeDy, edgeDx) * (180 / Math.PI);
10763- } else {
10764- midX = (x1 + x2) / 2;
10765- midY = (y1 + y2) / 2;
10766- angle = Math.atan2(y2 - y1, x2 - x1) * (180 / Math.PI);
10767- }
10722+ // Use utility-calculated apex for curves, midpoint for lines
10723+ midX = parallelPath.apexX;
10724+ midY = parallelPath.apexY;
10725+ angle = parallelPath.labelAngle;
1076810726 }
1076910727
1077010728 // Determine connection name to display
@@ -11736,6 +11694,12 @@ function NodeCanvas() {
1173611694 manhattanSourceSide = sSide;
1173711695 manhattanDestSide = dSide;
1173811696 }
11697+
11698+ // Calculate parallel edge path using centralized utility
11699+ const curveInfo = edgeCurveInfo.get(edge.id);
11700+ const parallelPath = calculateParallelEdgePath(startX, startY, endX, endY, curveInfo);
11701+ const useCurve = parallelPath.type === 'curve';
11702+
1173911703 return (
1174011704 <g key={`edge-above-${edge.id}-${idx}`}>
1174111705 {/* Main edge line - always same thickness */}
@@ -11757,54 +11721,32 @@ function NodeCanvas() {
1175711721 }}
1175811722 strokeLinecap="round"
1175911723 />
11760- ) : (() => {
11761- // Glow effect also needs curve for multi-edge pairs
11762- const curveInfo = edgeCurveInfo.get(edge.id);
11763- if (curveInfo && curveInfo.totalInPair > 1) {
11764- const { pairIndex, totalInPair } = curveInfo;
11765- const curveSpacing = 100;
11766- // Alternating direction logic matching utils
11767- const direction = pairIndex % 2 === 0 ? 1 : -1;
11768- const offsetMagnitude = Math.floor((pairIndex + 1) / 2) * curveSpacing;
11769- const perpOffset = direction * offsetMagnitude;
11770- const edgeDx = endX - startX;
11771- const edgeDy = endY - startY;
11772- const edgeLen = Math.sqrt(edgeDx * edgeDx + edgeDy * edgeDy);
11773- const perpX = edgeLen > 0 ? -edgeDy / edgeLen : 0;
11774- const perpY = edgeLen > 0 ? edgeDx / edgeLen : 0;
11775- const curveMidX = (startX + endX) / 2;
11776- const curveMidY = (startY + endY) / 2;
11777- const ctrlX = curveMidX + perpX * perpOffset;
11778- const ctrlY = curveMidY + perpY * perpOffset;
11779- return (
11780- <path
11781- d={`M ${startX} ${startY} Q ${ctrlX} ${ctrlY} ${endX} ${endY}`}
11782- fill="none"
11783- stroke={edgeColor}
11784- strokeWidth="12"
11785- opacity={isSelected ? "0.3" : "0.2"}
11786- style={{
11787- filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
11788- }}
11789- strokeLinecap="round"
11790- />
11791- );
11792- }
11793- return (
11794- <line
11795- x1={startX}
11796- y1={startY}
11797- x2={endX}
11798- y2={endY}
11799- stroke={edgeColor}
11800- strokeWidth="12"
11801- opacity={isSelected ? "0.3" : "0.2"}
11802- style={{
11803- filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
11804- }}
11805- />
11806- );
11807- })()
11724+ ) : useCurve ? (
11725+ <path
11726+ d={parallelPath.path}
11727+ fill="none"
11728+ stroke={edgeColor}
11729+ strokeWidth="12"
11730+ opacity={isSelected ? "0.3" : "0.2"}
11731+ style={{
11732+ filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
11733+ }}
11734+ strokeLinecap="round"
11735+ />
11736+ ) : (
11737+ <line
11738+ x1={startX}
11739+ y1={startY}
11740+ x2={endX}
11741+ y2={endY}
11742+ stroke={edgeColor}
11743+ strokeWidth="12"
11744+ opacity={isSelected ? "0.3" : "0.2"}
11745+ style={{
11746+ filter: `blur(3px) drop-shadow(0 0 8px ${edgeColor})`
11747+ }}
11748+ />
11749+ )
1180811750 )}
1180911751
1181011752 {(enableAutoRouting && (routingStyle === 'manhattan' || routingStyle === 'clean')) ? (
0 commit comments