SC CODE: Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("var_header_name", "js2.js")
31 STORE("var_header_description", "")
32 STORE("var_header_icon", "")
33 STORE("dURL", "")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "/")
36 STORE("fileCheckC", "2c47d9ed7fd512dd3c2afe6857b54c8983b15170ea04ca09d601e27c2d82c1b5")
37 STORE("fileCheckS", "0bd7afb02edc952d84239b00c383124b0422916add3e0c07aa9899c8deacf78e")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
onClick:e=>{e.stopPropagation();onSelect(node.id)},
onMouseEnter:()=>setHov(true),onMouseLeave:()=>setHov(false)},
h('button',{onClick:e=>{e.stopPropagation();onRemove(node.id)},style:{position:'absolute',top:4,left:4,zIndex:50,opacity:hov?1:0,transition:'opacity 0.2s',background:'rgba(0,0,0,0.70)',border:'1px solid rgba(255,255,255,0.15)',borderRadius:'50%',padding:3,color:'rgba(255,255,255,0.55)',cursor:'pointer',display:'flex'}},h('svg',{xmlns:'http://www.w3.org/2000/svg',width:8,height:8,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:2.5},h('path',{d:'M18 6 6 18M6 6l12 12'}))),
h('button',{onClick:e=>{e.stopPropagation();onAddConnection(node.id)},style:{position:'absolute',top:4,right:4,zIndex:50,opacity:hov?1:0,transition:'opacity 0.2s',background:'rgba(0,0,0,0.70)',border:`1px solid rgba(224,123,57,0.40)`,borderRadius:'50%',padding:3,color:UI.orange,cursor:'pointer',display:'flex'}},h('svg',{xmlns:'http://www.w3.org/2000/svg',width:8,height:8,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:2.5},h('path',{d:'M12 5v14M5 12h14'}))),
h('div',{style:{width:'100%',height:112,overflow:'hidden',position:'relative',background:'#050a12'}},
h(SmartPortrait,{name:node.name,image:node.image}),
h('div',{style:{position:'absolute',bottom:0,left:0,right:0,height:28,background:`linear-gradient(transparent,${cardBg})`,pointerEvents:'none'}}),
node.isGhost&&h('div',{style:{position:'absolute',inset:0,display:'flex',alignItems:'center',justifyContent:'center',background:'rgba(0,0,0,0.55)'}},h(Icon,{name:'alert-triangle',size:15,color:'#f59e0b'}))
),
h('div',{style:{padding:'8px 10px 10px',borderTop:'1px solid rgba(255,255,255,0.06)'}},
h('p',{style:{fontFamily:'Syne,sans-serif',fontSize:13,fontWeight:700,color:'rgba(255,255,255,0.88)',margin:'0 0 3px',lineHeight:1.2,letterSpacing:'-0.01em',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}},node.name),
h('p',{style:{fontFamily:'Syne,sans-serif',fontSize:9,fontWeight:600,color:isCentral?UI.orange:'rgba(255,255,255,0.38)',textTransform:'uppercase',letterSpacing:'0.10em',margin:0,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}},node.role)
)
),
isSelected&&h('div',{style:{marginTop:5,display:'flex',justifyContent:'center'}},
h('button',{onClick:e=>{e.stopPropagation();onExpand(node.id)},style:{display:'flex',alignItems:'center',gap:4,padding:'3px 10px',fontFamily:'Syne,sans-serif',fontSize:9,fontWeight:700,letterSpacing:'0.10em',textTransform:'uppercase',color:'rgba(255,255,255,0.55)',background:'rgba(0,0,0,0.50)',border:'1px solid rgba(255,255,255,0.13)',borderRadius:3,cursor:'pointer'}},
h(Icon,{name:'more-horizontal',size:10}),' Uitbreiden'
)
)
);
}
// -- EDGE RENDERER --
function EdgeRenderer({edges,nodes,selectedEdgeId,hoveredEdgeId,onEdgeClick,onEdgeHover}){
const nodeMap=useMemo(()=>new Map(nodes.map(n=>[n.id,n])),[nodes]);
const [pulse,setPulse]=useState(0);
useEffect(()=>{
let raf;const tick=()=>{setPulse(p=>(p+0.004)%1);raf=requestAnimationFrame(tick)};
raf=requestAnimationFrame(tick);return()=>cancelAnimationFrame(raf);
},[]);
const hovEdge=edges.find(e=>e.id===hoveredEdgeId)??null;
return h('div',null,
h('svg',{style:{position:'absolute',inset:0,width:'100%',height:'100%',pointerEvents:'none',zIndex:10,overflow:'visible'}},
edges.map(edge=>{
const src=nodeMap.get(edge.from),tgt=nodeMap.get(edge.to);if(!src||!tgt)return null;
const isActive=edge.id===selectedEdgeId||edge.id===hoveredEdgeId;
const isVerified=edge.status==='verified',isRumor=edge.status==='unverified';
const color=getEdgeColor(edge.status,edge.confidence,1);
const glowColor=getEdgeColor(edge.status,edge.confidence,0.35);
const x1=src.x+CARD_W/2,y1=src.y+75,x2=tgt.x+CARD_W/2,y2=tgt.y+75;
const mx=(x1+x2)/2,my=(y1+y2)/2;
const glowOp=isActive?0.45:isVerified?0.22:0.08;
const glowW=isActive?10:isVerified?7:4;
const lineOp=isActive?1:isVerified?0.80:0.45;
const lineW=isActive?3.5:isVerified?2:1.5;
const px=x1+(x2-x1)*pulse,py=y1+(y2-y1)*pulse;
return h('g',{key:edge.id},
h('line',{x1,y1,x2,y2,stroke:'transparent',strokeWidth:24,style:{pointerEvents:'auto',cursor:'pointer'},onMouseEnter:()=>onEdgeHover(edge.id),onMouseLeave:()=>onEdgeHover(null),onClick:e=>onEdgeClick(e,edge.id)}),
h('line',{x1,y1,x2,y2,stroke:glowColor,strokeWidth:glowW,strokeLinecap:'round',opacity:glowOp}),
h('line',{x1,y1,x2,y2,stroke:color,strokeWidth:lineW,strokeLinecap:'round',strokeDasharray:isRumor?'7,6':'0',opacity:lineOp}),
isVerified&&h('circle',{cx:px,cy:py,r:isActive?3:2.5,fill:color,opacity:isActive?0.80:0.50}),
isActive&&h('circle',{cx:mx,cy:my,r:5,fill:color,opacity:0.95})
);
})
),
hovEdge&&(()=>{
const src=nodeMap.get(hovEdge.from),tgt=nodeMap.get(hovEdge.to);if(!src||!tgt)return null;
const mx=(src.x+CARD_W/2+tgt.x+CARD_W/2)/2,my=(src.y+75+tgt.y+75)/2-22;
const color=getEdgeColor(hovEdge.status,hovEdge.confidence,1);
return h('div',{style:{position:'absolute',left:mx,top:my,transform:'translate(-50%,-100%)',zIndex:40,pointerEvents:'none'}},
h('div',{style:{background:'rgba(4,7,21,0.92)',border:`1px solid ${getEdgeColor(hovEdge.status,hovEdge.confidence,0.5)}`,borderRadius:8,padding:'6px 12px',backdropFilter:'blur(12px)',whiteSpace:'nowrap'}},
h('div',{style:{display:'flex',alignItems:'center',gap:8,fontSize:11}},
h('span',{style:{width:8,height:8,borderRadius:'50%',display:'inline-block',background:color,flexShrink:0}}),
h('span',{style:{fontWeight:600,color:'rgba(255,255,255,0.9)',fontFamily:'Syne,sans-serif'}},hovEdge.label),
h('span',{style:{color:'rgba(255,255,255,0.45)',fontFamily:'JetBrains Mono,monospace',fontSize:10}},hovEdge.confidence+'%')
)
)
);
})()
);
}
// -- DETAILS PANEL --
function DetailsPanel({selNode,selEdge,nodes}){
const nm=useMemo(()=>new Map(nodes.map(n=>[n.id,n])),[nodes]);
if(!selNode&&!selEdge) return h('div',{style:{flex:1,display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',color:'rgba(255,255,255,0.4)',fontSize:13,padding:'0 32px',gap:16}},
h(Icon,{name:'search',size:40,color:'rgba(255,255,255,0.2)'}),
h('p',{style:{textAlign:'center',lineHeight:1.7,fontFamily:'Syne,sans-serif'}},'Selecteer een entiteit of verbindingslijn om details te bekijken')
);
return h('div',{style:{flex:1,overflowY:'auto',padding:24,display:'flex',flexDirection:'column',gap:24}},
selEdge&&h('div',null,
h('div',{style:{display:'flex',alignItems:'center',gap:8,marginBottom:12,flexWrap:'wrap'}},
h('span',{style:{padding:'2px 8px',borderRadius:4,border:`1px solid ${getStatusBorder(selEdge.status)}`,background:getStatusStyle(selEdge.status),fontSize:11,fontWeight:700,textTransform:'uppercase',letterSpacing:'0.08em',color:getStatusText(selEdge.status),fontFamily:'Syne,sans-serif'}},getStatusLabel(selEdge.status)),
h('span',{style:{color:'rgba(255,255,255,0.3)',fontSize:12}},'*'),
h('span',{style:{color:'rgba(255,255,255,0.55)',fontSize:12,fontFamily:'JetBrains Mono,monospace'}},selEdge.confidence+'% vertrouwen')
),
h('h2',{className:'serif',style:{fontSize:20,fontWeight:700,color:'rgba(255,255,255,0.92)',lineHeight:1.3,marginBottom:4}},selEdge.label),
h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.45)',fontFamily:'Syne,sans-serif'}},nm.get(selEdge.from)?.name,' -> ',nm.get(selEdge.to)?.name),
selEdge.description&&h('div',{style:{padding:16,borderRadius:10,border:`1px solid ${UI.cardBorder}`,background:UI.cardBg,position:'relative',marginTop:16}},
h(Icon,{name:'paperclip',size:14,color:'rgba(255,255,255,0.25)',style:{position:'absolute',top:12,right:12}}),
h('p',{className:'serif',style:{fontSize:13,color:'rgba(255,255,255,0.80)',fontStyle:'italic',lineHeight:1.7}},'"',selEdge.description,'"')
),
h('div',{style:{marginTop:20}},
h('h3',{style:{fontSize:11,fontWeight:700,color:'rgba(255,255,255,0.35)',textTransform:'uppercase',letterSpacing:'0.18em',marginBottom:12,fontFamily:'Syne,sans-serif'}},'Bronnen (',selEdge.sources.length,')'),
selEdge.sources.length===0
?h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.35)',fontStyle:'italic',fontFamily:'Syne,sans-serif'}},'Nog geen bronnen.')
:h('div',{style:{display:'flex',flexDirection:'column',gap:8}},
selEdge.sources.map(src=>h('div',{key:src.id,style:{padding:12,borderRadius:10,border:`1px solid ${UI.cardBorder}`,background:UI.cardBg,display:'flex',gap:10}},
h('span',{style:{padding:'2px 6px',borderRadius:3,border:`1px solid ${getTierBorder(src.tier)}`,background:getTierBg(src.tier),fontSize:10,fontWeight:700,color:getTierText(src.tier),flexShrink:0,alignSelf:'flex-start',marginTop:2,fontFamily:'Syne,sans-serif'}},src.tier),
h('div',null,
h('p',{style:{fontSize:13,fontWeight:600,color:'rgba(255,255,255,0.88)',fontFamily:'Syne,sans-serif'}},src.title),
(src.publisher||src.date)&&h('p',{style:{fontSize:11,color:'rgba(255,255,255,0.42)',marginTop:4,fontFamily:'JetBrains Mono,monospace'}},src.publisher,src.date&&' * '+src.date)
)
))
)
),
h('div',{style:{padding:16,borderRadius:10,border:'1px solid rgba(59,130,246,0.2)',background:'rgba(59,130,246,0.06)',marginTop:4}},
h('h3',{style:{fontSize:11,fontWeight:700,color:'rgba(59,130,246,0.8)',textTransform:'uppercase',letterSpacing:'0.18em',marginBottom:12,display:'flex',alignItems:'center',gap:8,fontFamily:'Syne,sans-serif'}},h(Icon,{name:'shield',size:12,color:'rgba(59,130,246,0.8)'}),' Community Verificatie'),
h('div',{style:{display:'flex',gap:8}},
h('button',{style:{flex:1,padding:'6px 0',fontSize:12,fontWeight:600,borderRadius:8,background:'rgba(34,197,94,0.15)',border:'1px solid rgba(34,197,94,0.35)',color:'rgba(34,197,94,0.9)',cursor:'pointer',fontFamily:'Syne,sans-serif'}},h('span',null,'v Bevestigen')),
h('button',{style:{flex:1,padding:'6px 0',fontSize:12,fontWeight:600,borderRadius:8,background:'rgba(245,158,11,0.15)',border:'1px solid rgba(245,158,11,0.35)',color:'rgba(245,158,11,0.9)',cursor:'pointer',fontFamily:'Syne,sans-serif'}},h('span',null,'(!) Betwisten')),
h('button',{style:{flex:1,padding:'6px 0',fontSize:12,fontWeight:600,borderRadius:8,background:'rgba(239,68,68,0.15)',border:'1px solid rgba(239,68,68,0.35)',color:'rgba(239,68,68,0.9)',cursor:'pointer',fontFamily:'Syne,sans-serif'}},h('span',null,'? Onwaar'))
)
)
),
selNode&&!selEdge&&h('div',null,
h('div',{style:{display:'flex',alignItems:'flex-start',gap:16}},
h('div',{style:{width:64,height:64,borderRadius:10,border:`1px solid ${UI.cardBorder}`,overflow:'hidden',flexShrink:0,background:'rgba(0,0,0,0.22)'}},h(SmartPortrait,{name:selNode.name})),
h('div',null,
h('span',{style:{fontSize:10,padding:'2px 6px',borderRadius:4,border:`1px solid ${UI.cardBorder}`,textTransform:'uppercase',fontWeight:600,letterSpacing:'0.08em',color:'rgba(255,255,255,0.55)',background:UI.cardBg,fontFamily:'Syne,sans-serif'}},selNode.type),
h('h2',{className:'serif',style:{fontSize:24,fontWeight:700,color:'rgba(255,255,255,0.92)',lineHeight:1.2,marginTop:6}},selNode.name),
selNode.role&&h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.55)',marginTop:4,fontFamily:'Syne,sans-serif'}},selNode.role)
)
),
selNode.description&&h('div',null,
h('h3',{style:{fontSize:11,fontWeight:700,color:'rgba(255,255,255,0.35)',textTransform:'uppercase',letterSpacing:'0.18em',marginBottom:8,fontFamily:'Syne,sans-serif'}},'Achtergrond'),
h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.75)',lineHeight:1.7,fontFamily:'Syne,sans-serif'}},selNode.description)
),
h('p',{style:{fontSize:11,color:'rgba(255,255,255,0.30)',fontFamily:'Syne,sans-serif'}},'Tip: klik op een verbindingslijn voor bronnen en verificatiestatus.')
)
);
}
// -- TIMELINE VIEW --
function TimelineView({dossier,selectedEdgeId,onSelectEdge}){
const nm=useMemo(()=>new Map(dossier.nodes.map(n=>[n.id,n])),[dossier]);
const events=useMemo(()=>[...dossier.edges].map(e=>{
const dateStr=e.sources[0]?.date??'1990-01-01',year=parseInt(dateStr.split('-')[0]??'1990',10);
const seed=e.id.split('').reduce((a,c)=>a+c.charCodeAt(0),0);
return{...e,year,dateStr,rotation:(seed%7)-3.5,yOffset:(seed%4)*40};
}).sort((a,b)=>a.dateStr.localeCompare(b.dateStr)),[dossier]);
return h('div',{style:{position:'absolute',inset:0,top:HEADER_H,overflowX:'auto',overflowY:'hidden',display:'flex',alignItems:'flex-end'}},
h('div',{className:'no-sb',style:{position:'relative',height:'100%',padding:'0 40vw',display:'flex',alignItems:'flex-end',minWidth:'max-content'}},
h('div',{style:{position:'absolute',left:0,right:0,height:1,background:'rgba(255,255,255,0.20)',pointerEvents:'none',bottom:AXIS_BOTTOM}}),
events.map(ev=>{
const isActive=ev.id===selectedEdgeId;
const pinH=120+ev.yOffset;
const src=nm.get(ev.from),tgt=nm.get(ev.to);
return h('div',{key:ev.id,style:{position:'relative',flexShrink:0,margin:'0 24px',width:200}},
h('div',{style:{position:'absolute',left:'50%',transform:'translateX(-50%)',display:'flex',flexDirection:'column',alignItems:'center',bottom:AXIS_BOTTOM-8}},
h('div',{style:{width:1,height:16,background:'rgba(255,255,255,0.30)'}}),
h('span',{style:{marginTop:4,fontSize:9,fontFamily:'JetBrains Mono,monospace',color:'rgba(255,255,255,0.40)'}},ev.year)
),
h('div',{style:{position:'absolute',left:'50%',transform:'translateX(-50%)',width:1,bottom:AXIS_BOTTOM,height:pinH,background:isActive?UI.orange:'rgba(245,158,11,0.35)',opacity:isActive?1:0.6}}),
h('div',{onClick:e=>{e.stopPropagation();onSelectEdge(ev.id)},style:{position:'absolute',left:'50%',transform:`translateX(-50%) rotate(${isActive?0:ev.rotation}deg) ${isActive?'scale(1.08) translateY(-8px)':''}`,transformOrigin:'50% 100%',bottom:AXIS_BOTTOM+pinH,width:195,cursor:'pointer',transition:'all 0.3s',zIndex:isActive?50:1}},
h('div',{style:{background:'#f5f0e8',padding:8,paddingBottom:24,boxShadow:'0 12px 32px rgba(0,0,0,0.55)',border:'1px solid rgba(255,255,255,0.2)',position:'relative'}},
h('div',{style:{position:'absolute',top:-10,left:'50%',transform:'translateX(-50%) rotate(-1deg)',width:48,height:20,background:'rgba(251,243,194,0.7)',border:'1px solid rgba(251,243,194,0.5)'}}),
h('div',{style:{aspectRatio:'1',background:'#cbd5e1',marginBottom:8,overflow:'hidden',position:'relative',display:'grid',gridTemplateColumns:'1fr 1fr',height:120}},
h('div',{style:{position:'relative',borderRight:'1px solid rgba(255,255,255,0.4)'}},h(SmartPortrait,{name:src?.name??'?'})),
h('div',{style:{position:'relative'}},h(SmartPortrait,{name:tgt?.name??'?'})),
h('div',{style:{position:'absolute',top:6,right:6,padding:'2px 6px',fontSize:8,fontWeight:700,textTransform:'uppercase',letterSpacing:'0.08em',border:'1px solid',background:ev.status==='verified'?'rgba(209,250,229,0.95)':ev.status==='contested'?'rgba(254,243,199,0.95)':'rgba(254,226,226,0.95)',borderColor:ev.status==='verified'?'#16a34a':ev.status==='contested'?'#d97706':'#dc2626',color:ev.status==='verified'?'#14532d':ev.status==='contested'?'#78350f':'#7f1d1d',fontFamily:'Syne,sans-serif'}},ev.status)
),
h('div',{style:{fontFamily:'sans-serif',color:'#2d1f0e',padding:'0 4px'}},
h('div',{style:{display:'flex',justifyContent:'space-between',alignItems:'baseline',borderBottom:'1px solid #d6cfc3',paddingBottom:4,marginBottom:6}},
h('span',{style:{fontSize:9,fontFamily:'JetBrains Mono,monospace',color:'#78716c'}},ev.dateStr),
h('span',{style:{fontSize:9,fontWeight:700,color:'#b45309'}},ev.confidence+'%')
),
h('h3',{className:'serif',style:{fontSize:13,fontWeight:700,lineHeight:1.3,WebkitLineClamp:2,overflow:'hidden',display:'-webkit-box',WebkitBoxOrient:'vertical'}},ev.label),
ev.description&&h('p',{style:{fontSize:10,color:'#57534e',marginTop:4,lineHeight:1.4,fontStyle:'italic',WebkitLineClamp:2,overflow:'hidden',display:'-webkit-box',WebkitBoxOrient:'vertical'}},'"',ev.description,'"')
)
)
)
);
})
)
);
}
// -- DOSSIERS OVERLAY --
function DossiersOverlay({dossiers,currentId,onSelect}){
*/ |
| SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("var_header_name", "js2.js")
31 STORE("var_header_description", "")
32 STORE("var_header_icon", "")
33 STORE("dURL", "")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "/")
36 STORE("fileCheckC", "2c47d9ed7fd512dd3c2afe6857b54c8983b15170ea04ca09d601e27c2d82c1b5")
37 STORE("fileCheckS", "0bd7afb02edc952d84239b00c383124b0422916add3e0c07aa9899c8deacf78e")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
onClick:e=>{e.stopPropagation();onSelect(node.id)},
onMouseEnter:()=>setHov(true),onMouseLeave:()=>setHov(false)},
h('button',{onClick:e=>{e.stopPropagation();onRemove(node.id)},style:{position:'absolute',top:4,left:4,zIndex:50,opacity:hov?1:0,transition:'opacity 0.2s',background:'rgba(0,0,0,0.70)',border:'1px solid rgba(255,255,255,0.15)',borderRadius:'50%',padding:3,color:'rgba(255,255,255,0.55)',cursor:'pointer',display:'flex'}},h('svg',{xmlns:'http://www.w3.org/2000/svg',width:8,height:8,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:2.5},h('path',{d:'M18 6 6 18M6 6l12 12'}))),
h('button',{onClick:e=>{e.stopPropagation();onAddConnection(node.id)},style:{position:'absolute',top:4,right:4,zIndex:50,opacity:hov?1:0,transition:'opacity 0.2s',background:'rgba(0,0,0,0.70)',border:`1px solid rgba(224,123,57,0.40)`,borderRadius:'50%',padding:3,color:UI.orange,cursor:'pointer',display:'flex'}},h('svg',{xmlns:'http://www.w3.org/2000/svg',width:8,height:8,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:2.5},h('path',{d:'M12 5v14M5 12h14'}))),
h('div',{style:{width:'100%',height:112,overflow:'hidden',position:'relative',background:'#050a12'}},
h(SmartPortrait,{name:node.name,image:node.image}),
h('div',{style:{position:'absolute',bottom:0,left:0,right:0,height:28,background:`linear-gradient(transparent,${cardBg})`,pointerEvents:'none'}}),
node.isGhost&&h('div',{style:{position:'absolute',inset:0,display:'flex',alignItems:'center',justifyContent:'center',background:'rgba(0,0,0,0.55)'}},h(Icon,{name:'alert-triangle',size:15,color:'#f59e0b'}))
),
h('div',{style:{padding:'8px 10px 10px',borderTop:'1px solid rgba(255,255,255,0.06)'}},
h('p',{style:{fontFamily:'Syne,sans-serif',fontSize:13,fontWeight:700,color:'rgba(255,255,255,0.88)',margin:'0 0 3px',lineHeight:1.2,letterSpacing:'-0.01em',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}},node.name),
h('p',{style:{fontFamily:'Syne,sans-serif',fontSize:9,fontWeight:600,color:isCentral?UI.orange:'rgba(255,255,255,0.38)',textTransform:'uppercase',letterSpacing:'0.10em',margin:0,overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}},node.role)
)
),
isSelected&&h('div',{style:{marginTop:5,display:'flex',justifyContent:'center'}},
h('button',{onClick:e=>{e.stopPropagation();onExpand(node.id)},style:{display:'flex',alignItems:'center',gap:4,padding:'3px 10px',fontFamily:'Syne,sans-serif',fontSize:9,fontWeight:700,letterSpacing:'0.10em',textTransform:'uppercase',color:'rgba(255,255,255,0.55)',background:'rgba(0,0,0,0.50)',border:'1px solid rgba(255,255,255,0.13)',borderRadius:3,cursor:'pointer'}},
h(Icon,{name:'more-horizontal',size:10}),' Uitbreiden'
)
)
);
}
// -- EDGE RENDERER --
function EdgeRenderer({edges,nodes,selectedEdgeId,hoveredEdgeId,onEdgeClick,onEdgeHover}){
const nodeMap=useMemo(()=>new Map(nodes.map(n=>[n.id,n])),[nodes]);
const [pulse,setPulse]=useState(0);
useEffect(()=>{
let raf;const tick=()=>{setPulse(p=>(p+0.004)%1);raf=requestAnimationFrame(tick)};
raf=requestAnimationFrame(tick);return()=>cancelAnimationFrame(raf);
},[]);
const hovEdge=edges.find(e=>e.id===hoveredEdgeId)??null;
return h('div',null,
h('svg',{style:{position:'absolute',inset:0,width:'100%',height:'100%',pointerEvents:'none',zIndex:10,overflow:'visible'}},
edges.map(edge=>{
const src=nodeMap.get(edge.from),tgt=nodeMap.get(edge.to);if(!src||!tgt)return null;
const isActive=edge.id===selectedEdgeId||edge.id===hoveredEdgeId;
const isVerified=edge.status==='verified',isRumor=edge.status==='unverified';
const color=getEdgeColor(edge.status,edge.confidence,1);
const glowColor=getEdgeColor(edge.status,edge.confidence,0.35);
const x1=src.x+CARD_W/2,y1=src.y+75,x2=tgt.x+CARD_W/2,y2=tgt.y+75;
const mx=(x1+x2)/2,my=(y1+y2)/2;
const glowOp=isActive?0.45:isVerified?0.22:0.08;
const glowW=isActive?10:isVerified?7:4;
const lineOp=isActive?1:isVerified?0.80:0.45;
const lineW=isActive?3.5:isVerified?2:1.5;
const px=x1+(x2-x1)*pulse,py=y1+(y2-y1)*pulse;
return h('g',{key:edge.id},
h('line',{x1,y1,x2,y2,stroke:'transparent',strokeWidth:24,style:{pointerEvents:'auto',cursor:'pointer'},onMouseEnter:()=>onEdgeHover(edge.id),onMouseLeave:()=>onEdgeHover(null),onClick:e=>onEdgeClick(e,edge.id)}),
h('line',{x1,y1,x2,y2,stroke:glowColor,strokeWidth:glowW,strokeLinecap:'round',opacity:glowOp}),
h('line',{x1,y1,x2,y2,stroke:color,strokeWidth:lineW,strokeLinecap:'round',strokeDasharray:isRumor?'7,6':'0',opacity:lineOp}),
isVerified&&h('circle',{cx:px,cy:py,r:isActive?3:2.5,fill:color,opacity:isActive?0.80:0.50}),
isActive&&h('circle',{cx:mx,cy:my,r:5,fill:color,opacity:0.95})
);
})
),
hovEdge&&(()=>{
const src=nodeMap.get(hovEdge.from),tgt=nodeMap.get(hovEdge.to);if(!src||!tgt)return null;
const mx=(src.x+CARD_W/2+tgt.x+CARD_W/2)/2,my=(src.y+75+tgt.y+75)/2-22;
const color=getEdgeColor(hovEdge.status,hovEdge.confidence,1);
return h('div',{style:{position:'absolute',left:mx,top:my,transform:'translate(-50%,-100%)',zIndex:40,pointerEvents:'none'}},
h('div',{style:{background:'rgba(4,7,21,0.92)',border:`1px solid ${getEdgeColor(hovEdge.status,hovEdge.confidence,0.5)}`,borderRadius:8,padding:'6px 12px',backdropFilter:'blur(12px)',whiteSpace:'nowrap'}},
h('div',{style:{display:'flex',alignItems:'center',gap:8,fontSize:11}},
h('span',{style:{width:8,height:8,borderRadius:'50%',display:'inline-block',background:color,flexShrink:0}}),
h('span',{style:{fontWeight:600,color:'rgba(255,255,255,0.9)',fontFamily:'Syne,sans-serif'}},hovEdge.label),
h('span',{style:{color:'rgba(255,255,255,0.45)',fontFamily:'JetBrains Mono,monospace',fontSize:10}},hovEdge.confidence+'%')
)
)
);
})()
);
}
// -- DETAILS PANEL --
function DetailsPanel({selNode,selEdge,nodes}){
const nm=useMemo(()=>new Map(nodes.map(n=>[n.id,n])),[nodes]);
if(!selNode&&!selEdge) return h('div',{style:{flex:1,display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',color:'rgba(255,255,255,0.4)',fontSize:13,padding:'0 32px',gap:16}},
h(Icon,{name:'search',size:40,color:'rgba(255,255,255,0.2)'}),
h('p',{style:{textAlign:'center',lineHeight:1.7,fontFamily:'Syne,sans-serif'}},'Selecteer een entiteit of verbindingslijn om details te bekijken')
);
return h('div',{style:{flex:1,overflowY:'auto',padding:24,display:'flex',flexDirection:'column',gap:24}},
selEdge&&h('div',null,
h('div',{style:{display:'flex',alignItems:'center',gap:8,marginBottom:12,flexWrap:'wrap'}},
h('span',{style:{padding:'2px 8px',borderRadius:4,border:`1px solid ${getStatusBorder(selEdge.status)}`,background:getStatusStyle(selEdge.status),fontSize:11,fontWeight:700,textTransform:'uppercase',letterSpacing:'0.08em',color:getStatusText(selEdge.status),fontFamily:'Syne,sans-serif'}},getStatusLabel(selEdge.status)),
h('span',{style:{color:'rgba(255,255,255,0.3)',fontSize:12}},'*'),
h('span',{style:{color:'rgba(255,255,255,0.55)',fontSize:12,fontFamily:'JetBrains Mono,monospace'}},selEdge.confidence+'% vertrouwen')
),
h('h2',{className:'serif',style:{fontSize:20,fontWeight:700,color:'rgba(255,255,255,0.92)',lineHeight:1.3,marginBottom:4}},selEdge.label),
h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.45)',fontFamily:'Syne,sans-serif'}},nm.get(selEdge.from)?.name,' -> ',nm.get(selEdge.to)?.name),
selEdge.description&&h('div',{style:{padding:16,borderRadius:10,border:`1px solid ${UI.cardBorder}`,background:UI.cardBg,position:'relative',marginTop:16}},
h(Icon,{name:'paperclip',size:14,color:'rgba(255,255,255,0.25)',style:{position:'absolute',top:12,right:12}}),
h('p',{className:'serif',style:{fontSize:13,color:'rgba(255,255,255,0.80)',fontStyle:'italic',lineHeight:1.7}},'"',selEdge.description,'"')
),
h('div',{style:{marginTop:20}},
h('h3',{style:{fontSize:11,fontWeight:700,color:'rgba(255,255,255,0.35)',textTransform:'uppercase',letterSpacing:'0.18em',marginBottom:12,fontFamily:'Syne,sans-serif'}},'Bronnen (',selEdge.sources.length,')'),
selEdge.sources.length===0
?h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.35)',fontStyle:'italic',fontFamily:'Syne,sans-serif'}},'Nog geen bronnen.')
:h('div',{style:{display:'flex',flexDirection:'column',gap:8}},
selEdge.sources.map(src=>h('div',{key:src.id,style:{padding:12,borderRadius:10,border:`1px solid ${UI.cardBorder}`,background:UI.cardBg,display:'flex',gap:10}},
h('span',{style:{padding:'2px 6px',borderRadius:3,border:`1px solid ${getTierBorder(src.tier)}`,background:getTierBg(src.tier),fontSize:10,fontWeight:700,color:getTierText(src.tier),flexShrink:0,alignSelf:'flex-start',marginTop:2,fontFamily:'Syne,sans-serif'}},src.tier),
h('div',null,
h('p',{style:{fontSize:13,fontWeight:600,color:'rgba(255,255,255,0.88)',fontFamily:'Syne,sans-serif'}},src.title),
(src.publisher||src.date)&&h('p',{style:{fontSize:11,color:'rgba(255,255,255,0.42)',marginTop:4,fontFamily:'JetBrains Mono,monospace'}},src.publisher,src.date&&' * '+src.date)
)
))
)
),
h('div',{style:{padding:16,borderRadius:10,border:'1px solid rgba(59,130,246,0.2)',background:'rgba(59,130,246,0.06)',marginTop:4}},
h('h3',{style:{fontSize:11,fontWeight:700,color:'rgba(59,130,246,0.8)',textTransform:'uppercase',letterSpacing:'0.18em',marginBottom:12,display:'flex',alignItems:'center',gap:8,fontFamily:'Syne,sans-serif'}},h(Icon,{name:'shield',size:12,color:'rgba(59,130,246,0.8)'}),' Community Verificatie'),
h('div',{style:{display:'flex',gap:8}},
h('button',{style:{flex:1,padding:'6px 0',fontSize:12,fontWeight:600,borderRadius:8,background:'rgba(34,197,94,0.15)',border:'1px solid rgba(34,197,94,0.35)',color:'rgba(34,197,94,0.9)',cursor:'pointer',fontFamily:'Syne,sans-serif'}},h('span',null,'v Bevestigen')),
h('button',{style:{flex:1,padding:'6px 0',fontSize:12,fontWeight:600,borderRadius:8,background:'rgba(245,158,11,0.15)',border:'1px solid rgba(245,158,11,0.35)',color:'rgba(245,158,11,0.9)',cursor:'pointer',fontFamily:'Syne,sans-serif'}},h('span',null,'(!) Betwisten')),
h('button',{style:{flex:1,padding:'6px 0',fontSize:12,fontWeight:600,borderRadius:8,background:'rgba(239,68,68,0.15)',border:'1px solid rgba(239,68,68,0.35)',color:'rgba(239,68,68,0.9)',cursor:'pointer',fontFamily:'Syne,sans-serif'}},h('span',null,'? Onwaar'))
)
)
),
selNode&&!selEdge&&h('div',null,
h('div',{style:{display:'flex',alignItems:'flex-start',gap:16}},
h('div',{style:{width:64,height:64,borderRadius:10,border:`1px solid ${UI.cardBorder}`,overflow:'hidden',flexShrink:0,background:'rgba(0,0,0,0.22)'}},h(SmartPortrait,{name:selNode.name})),
h('div',null,
h('span',{style:{fontSize:10,padding:'2px 6px',borderRadius:4,border:`1px solid ${UI.cardBorder}`,textTransform:'uppercase',fontWeight:600,letterSpacing:'0.08em',color:'rgba(255,255,255,0.55)',background:UI.cardBg,fontFamily:'Syne,sans-serif'}},selNode.type),
h('h2',{className:'serif',style:{fontSize:24,fontWeight:700,color:'rgba(255,255,255,0.92)',lineHeight:1.2,marginTop:6}},selNode.name),
selNode.role&&h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.55)',marginTop:4,fontFamily:'Syne,sans-serif'}},selNode.role)
)
),
selNode.description&&h('div',null,
h('h3',{style:{fontSize:11,fontWeight:700,color:'rgba(255,255,255,0.35)',textTransform:'uppercase',letterSpacing:'0.18em',marginBottom:8,fontFamily:'Syne,sans-serif'}},'Achtergrond'),
h('p',{style:{fontSize:13,color:'rgba(255,255,255,0.75)',lineHeight:1.7,fontFamily:'Syne,sans-serif'}},selNode.description)
),
h('p',{style:{fontSize:11,color:'rgba(255,255,255,0.30)',fontFamily:'Syne,sans-serif'}},'Tip: klik op een verbindingslijn voor bronnen en verificatiestatus.')
)
);
}
// -- TIMELINE VIEW --
function TimelineView({dossier,selectedEdgeId,onSelectEdge}){
const nm=useMemo(()=>new Map(dossier.nodes.map(n=>[n.id,n])),[dossier]);
const events=useMemo(()=>[...dossier.edges].map(e=>{
const dateStr=e.sources[0]?.date??'1990-01-01',year=parseInt(dateStr.split('-')[0]??'1990',10);
const seed=e.id.split('').reduce((a,c)=>a+c.charCodeAt(0),0);
return{...e,year,dateStr,rotation:(seed%7)-3.5,yOffset:(seed%4)*40};
}).sort((a,b)=>a.dateStr.localeCompare(b.dateStr)),[dossier]);
return h('div',{style:{position:'absolute',inset:0,top:HEADER_H,overflowX:'auto',overflowY:'hidden',display:'flex',alignItems:'flex-end'}},
h('div',{className:'no-sb',style:{position:'relative',height:'100%',padding:'0 40vw',display:'flex',alignItems:'flex-end',minWidth:'max-content'}},
h('div',{style:{position:'absolute',left:0,right:0,height:1,background:'rgba(255,255,255,0.20)',pointerEvents:'none',bottom:AXIS_BOTTOM}}),
events.map(ev=>{
const isActive=ev.id===selectedEdgeId;
const pinH=120+ev.yOffset;
const src=nm.get(ev.from),tgt=nm.get(ev.to);
return h('div',{key:ev.id,style:{position:'relative',flexShrink:0,margin:'0 24px',width:200}},
h('div',{style:{position:'absolute',left:'50%',transform:'translateX(-50%)',display:'flex',flexDirection:'column',alignItems:'center',bottom:AXIS_BOTTOM-8}},
h('div',{style:{width:1,height:16,background:'rgba(255,255,255,0.30)'}}),
h('span',{style:{marginTop:4,fontSize:9,fontFamily:'JetBrains Mono,monospace',color:'rgba(255,255,255,0.40)'}},ev.year)
),
h('div',{style:{position:'absolute',left:'50%',transform:'translateX(-50%)',width:1,bottom:AXIS_BOTTOM,height:pinH,background:isActive?UI.orange:'rgba(245,158,11,0.35)',opacity:isActive?1:0.6}}),
h('div',{onClick:e=>{e.stopPropagation();onSelectEdge(ev.id)},style:{position:'absolute',left:'50%',transform:`translateX(-50%) rotate(${isActive?0:ev.rotation}deg) ${isActive?'scale(1.08) translateY(-8px)':''}`,transformOrigin:'50% 100%',bottom:AXIS_BOTTOM+pinH,width:195,cursor:'pointer',transition:'all 0.3s',zIndex:isActive?50:1}},
h('div',{style:{background:'#f5f0e8',padding:8,paddingBottom:24,boxShadow:'0 12px 32px rgba(0,0,0,0.55)',border:'1px solid rgba(255,255,255,0.2)',position:'relative'}},
h('div',{style:{position:'absolute',top:-10,left:'50%',transform:'translateX(-50%) rotate(-1deg)',width:48,height:20,background:'rgba(251,243,194,0.7)',border:'1px solid rgba(251,243,194,0.5)'}}),
h('div',{style:{aspectRatio:'1',background:'#cbd5e1',marginBottom:8,overflow:'hidden',position:'relative',display:'grid',gridTemplateColumns:'1fr 1fr',height:120}},
h('div',{style:{position:'relative',borderRight:'1px solid rgba(255,255,255,0.4)'}},h(SmartPortrait,{name:src?.name??'?'})),
h('div',{style:{position:'relative'}},h(SmartPortrait,{name:tgt?.name??'?'})),
h('div',{style:{position:'absolute',top:6,right:6,padding:'2px 6px',fontSize:8,fontWeight:700,textTransform:'uppercase',letterSpacing:'0.08em',border:'1px solid',background:ev.status==='verified'?'rgba(209,250,229,0.95)':ev.status==='contested'?'rgba(254,243,199,0.95)':'rgba(254,226,226,0.95)',borderColor:ev.status==='verified'?'#16a34a':ev.status==='contested'?'#d97706':'#dc2626',color:ev.status==='verified'?'#14532d':ev.status==='contested'?'#78350f':'#7f1d1d',fontFamily:'Syne,sans-serif'}},ev.status)
),
h('div',{style:{fontFamily:'sans-serif',color:'#2d1f0e',padding:'0 4px'}},
h('div',{style:{display:'flex',justifyContent:'space-between',alignItems:'baseline',borderBottom:'1px solid #d6cfc3',paddingBottom:4,marginBottom:6}},
h('span',{style:{fontSize:9,fontFamily:'JetBrains Mono,monospace',color:'#78716c'}},ev.dateStr),
h('span',{style:{fontSize:9,fontWeight:700,color:'#b45309'}},ev.confidence+'%')
),
h('h3',{className:'serif',style:{fontSize:13,fontWeight:700,lineHeight:1.3,WebkitLineClamp:2,overflow:'hidden',display:'-webkit-box',WebkitBoxOrient:'vertical'}},ev.label),
ev.description&&h('p',{style:{fontSize:10,color:'#57534e',marginTop:4,lineHeight:1.4,fontStyle:'italic',WebkitLineClamp:2,overflow:'hidden',display:'-webkit-box',WebkitBoxOrient:'vertical'}},'"',ev.description,'"')
)
)
)
);
})
)
);
}
// -- DOSSIERS OVERLAY --
function DossiersOverlay({dossiers,currentId,onSelect}){
*/'] |