@@ -12,25 +12,45 @@ function selectNode(node) {
1212 }
1313
1414 if ( node . data . quest_type ) content += `<div style="margin: 10px 0; background: rgba(255,255,255,0.05); padding: 8px; border-radius: 4px;"><strong>Quest Type:</strong> ${ node . data . quest_type } </div>` ;
15- if ( node . data . primary_stat ) content += `<div style="margin: 10px 0; background: rgba(255,255,255,0.05); padding: 8px; border-radius: 4px;"><strong>Primary Stat:</strong> ${ node . data . primary_stat } </div>` ;
1615
16+ // Categorize Edges
17+ const consumeTypes = [ 'consumes' , 'requires_stat' , 'requires_ability' , 'requires_quest' ] ;
18+ const produceTypes = [ 'rewards' , 'stat_rewards' , 'provides_ability' , 'unlocks_cadence' , 'unlocks_location' ] ;
19+
1720 const upstream = allEdges . filter ( e => e . target === node . id ) ;
18- if ( upstream . length > 0 ) {
19- content += '<h4 style="border-bottom: 1px solid #30363d;">Requirements</h4><ul>' ;
20- upstream . forEach ( r => { const src = nodeMap . get ( r . source ) ; content += `<li>${ src ? src . name : r . source } <span style="font-size:11px;">(${ r . type } )</span></li>` ; } ) ;
21+ const downstream = allEdges . filter ( e => e . source === node . id ) ;
22+
23+ // Sidebar: Requirements / Consumes
24+ const consumes = upstream . filter ( e => consumeTypes . includes ( e . type ) ) ;
25+ if ( consumes . length > 0 ) {
26+ content += '<h4 style="border-bottom: 1px solid #30363d; margin-bottom: 10px;">Consumes / Requires</h4><ul>' ;
27+ consumes . forEach ( e => {
28+ const src = nodeMap . get ( e . source ) ;
29+ content += `<li style="margin-bottom: 4px;">${ src ? src . name : e . source } <span style="font-size:11px; opacity:0.6;">(${ e . type } )</span></li>` ;
30+ } ) ;
2131 content += '</ul>' ;
2232 }
23- const downstream = allEdges . filter ( e => e . source === node . id ) ;
24- if ( downstream . length > 0 ) {
25- content += '<h4 style="border-bottom: 1px solid #30363d;">Unlocks</h4><ul>' ;
26- downstream . forEach ( u => { const tgt = nodeMap . get ( u . target ) ; content += `<li>${ tgt ? tgt . name : u . target } <span style="font-size:11px;">(${ u . type } )</span></li>` ; } ) ;
33+
34+ // Sidebar: Produces / Unlocks
35+ const produces = downstream . filter ( e => produceTypes . includes ( e . type ) ) ;
36+ if ( produces . length > 0 ) {
37+ content += '<h4 style="border-bottom: 1px solid #30363d; margin-bottom: 10px;">Produces / Unlocks</h4><ul>' ;
38+ produces . forEach ( e => {
39+ const tgt = nodeMap . get ( e . target ) ;
40+ content += `<li style="margin-bottom: 4px;">${ tgt ? tgt . name : e . target } <span style="font-size:11px; opacity:0.6;">(${ e . type } )</span></li>` ;
41+ } ) ;
2742 content += '</ul>' ;
2843 }
44+
2945 document . getElementById ( 'side-content' ) . innerHTML = content ;
3046 highlightPaths ( node . id ) ;
3147}
3248
3349function highlightPaths ( targetId ) {
50+ // Reset all previous highlights
51+ document . querySelectorAll ( '.node' ) . forEach ( el => el . classList . remove ( 'dimmed' , 'highlighted' ) ) ;
52+ document . querySelectorAll ( '.edge' ) . forEach ( el => el . classList . remove ( 'dimmed' , 'highlighted-up' , 'highlighted-down' ) ) ;
53+
3454 const upN = new Set ( ) , downN = new Set ( ) , upE = new Set ( ) , downE = new Set ( ) ;
3555 const traceUp = ( id ) => { allEdges . forEach ( e => { if ( e . target === id && ! upE . has ( e . id ) ) { upE . add ( e . id ) ; upN . add ( e . source ) ; traceUp ( e . source ) ; } } ) ; } ;
3656 const traceDown = ( id ) => { allEdges . forEach ( e => { if ( e . source === id && ! downE . has ( e . id ) ) { downE . add ( e . id ) ; downN . add ( e . target ) ; traceDown ( e . target ) ; } } ) ; } ;
@@ -41,7 +61,6 @@ function highlightPaths(targetId) {
4161 const idAttr = el . getAttribute ( 'id' ) ;
4262 const nodeId = idAttr . replace ( 'node-' , '' ) ;
4363
44- el . classList . remove ( 'dimmed' , 'highlighted' ) ;
4564 if ( nodeId === targetId || nodeId . includes ( targetId ) || upN . has ( nodeId ) || downN . has ( nodeId ) ) {
4665 el . classList . add ( 'highlighted' ) ;
4766 } else {
@@ -52,14 +71,29 @@ function highlightPaths(targetId) {
5271 const visibleEdges = document . querySelectorAll ( '.edge' ) ;
5372 visibleEdges . forEach ( el => {
5473 const edgeId = el . getAttribute ( 'id' ) ;
55- el . classList . remove ( 'dimmed' , 'highlighted-up' , 'highlighted-down' ) ;
74+ // Check if edge is part of the flow
5675 if ( upE . has ( edgeId ) || upE . some ( ue => edgeId . includes ( ue ) ) ) el . classList . add ( 'highlighted-up' ) ;
5776 else if ( downE . has ( edgeId ) || downE . some ( de => edgeId . includes ( de ) ) ) el . classList . add ( 'highlighted-down' ) ;
5877 else el . classList . add ( 'dimmed' ) ;
5978 } ) ;
6079}
6180
81+
6282function setupInteractions ( ) {
83+ document . getElementById ( 'btn-standard' ) . addEventListener ( 'click' , ( ) => {
84+ currentView = 'standard' ;
85+ document . getElementById ( 'btn-standard' ) . classList . add ( 'active' ) ;
86+ document . getElementById ( 'btn-advanced' ) . classList . remove ( 'active' ) ;
87+ renderQuestFlow ( ) ;
88+ } ) ;
89+
90+ document . getElementById ( 'btn-advanced' ) . addEventListener ( 'click' , ( ) => {
91+ currentView = 'advanced' ;
92+ document . getElementById ( 'btn-advanced' ) . classList . add ( 'active' ) ;
93+ document . getElementById ( 'btn-standard' ) . classList . remove ( 'active' ) ;
94+ renderQuestFlow ( ) ;
95+ } ) ;
96+
6397 let isDragging = false , startPos = { x : 0 , y : 0 } ;
6498 svg . addEventListener ( 'mousedown' , e => {
6599 if ( e . target === svg || e . target . closest ( '#tiers-layer' ) ) {
0 commit comments