BiNgoViewer 2.0.2__tar.gz → 2.0.3__tar.gz
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.
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/BiNgoViewer.egg-info/PKG-INFO +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/BiNgoViewer.egg-info/SOURCES.txt +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/PKG-INFO +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/__init__.py +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/cli.py +17 -20
- bingoviewer-2.0.2/bingoviewer/frontend_dist/assets/index-Dhy-wuVh.js → bingoviewer-2.0.3/bingoviewer/frontend_dist/assets/index-CzAKulXL.js +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/frontend_dist/index.html +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/main.py +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/pyproject.toml +1 -1
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/BiNgoViewer.egg-info/dependency_links.txt +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/BiNgoViewer.egg-info/entry_points.txt +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/BiNgoViewer.egg-info/requires.txt +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/BiNgoViewer.egg-info/top_level.txt +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/README.md +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/__main__.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/icon.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/install_shortcut.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/__init__.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/api/__init__.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/api/data.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/api/genome.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/api/tracks.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/readers/__init__.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/readers/annotation_reader.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/readers/bam_reader.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/readers/bigwig_reader.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/readers/genbank_reader.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/readers/genome_reader.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/readers/vcf_reader.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/bingoviewer/server/state.py +0 -0
- {bingoviewer-2.0.2 → bingoviewer-2.0.3}/setup.cfg +0 -0
|
@@ -12,7 +12,7 @@ bingoviewer/cli.py
|
|
|
12
12
|
bingoviewer/icon.py
|
|
13
13
|
bingoviewer/install_shortcut.py
|
|
14
14
|
bingoviewer/frontend_dist/index.html
|
|
15
|
-
bingoviewer/frontend_dist/assets/index-
|
|
15
|
+
bingoviewer/frontend_dist/assets/index-CzAKulXL.js
|
|
16
16
|
bingoviewer/server/__init__.py
|
|
17
17
|
bingoviewer/server/main.py
|
|
18
18
|
bingoviewer/server/state.py
|
|
@@ -132,25 +132,20 @@ def _record_update_check():
|
|
|
132
132
|
|
|
133
133
|
def _do_upgrade():
|
|
134
134
|
"""Run pip install --upgrade bingoviewer. Returns True on success."""
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
capture_output=True, text=True, timeout=120,
|
|
150
|
-
)
|
|
151
|
-
return result.returncode == 0
|
|
152
|
-
except Exception:
|
|
153
|
-
return False
|
|
135
|
+
cmds = [
|
|
136
|
+
[sys.executable, "-m", "pip", "install", "--upgrade", "bingoviewer"],
|
|
137
|
+
[sys.executable, "-m", "pip", "install", "--upgrade", "--user", "bingoviewer"],
|
|
138
|
+
]
|
|
139
|
+
for cmd in cmds:
|
|
140
|
+
try:
|
|
141
|
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
|
142
|
+
if result.returncode == 0:
|
|
143
|
+
return True
|
|
144
|
+
# Log the error for debugging
|
|
145
|
+
_log(f" pip failed: {result.stderr.strip()[:200]}")
|
|
146
|
+
except Exception as e:
|
|
147
|
+
_log(f" pip exception: {e}")
|
|
148
|
+
return False
|
|
154
149
|
|
|
155
150
|
|
|
156
151
|
def _log(msg):
|
|
@@ -426,7 +421,9 @@ def main():
|
|
|
426
421
|
print(f" BiNgo Genome Viewer updated to {ver}.")
|
|
427
422
|
print(f" Run 'bingo' to launch the new version.")
|
|
428
423
|
elif status == 'failed':
|
|
429
|
-
print(f" Update to {ver} failed.
|
|
424
|
+
print(f" Update to {ver} failed.")
|
|
425
|
+
print(f" Check ~/.bingoviewer/update.log for details.")
|
|
426
|
+
print(f" Or update manually:")
|
|
430
427
|
print(f" pip install --upgrade bingoviewer")
|
|
431
428
|
elif status == 'skip':
|
|
432
429
|
print(f" Could not reach PyPI. Check your internet connection.")
|
|
@@ -94,4 +94,4 @@ ${z.join(`
|
|
|
94
94
|
`)}
|
|
95
95
|
|
|
96
96
|
Tip: If files were moved, re-add them using the 📂 Path button.`):(x("Session restored"),setTimeout(()=>{x(null),e()},1200))}catch(O){h(O.message)}finally{m(!1)}}const B=yc(),D=oy(c);return a.jsx("div",{style:D.overlay,onClick:W=>{W.target===W.currentTarget&&e()},children:a.jsxs("div",{style:D.panel,children:[a.jsxs("div",{style:D.header,children:[a.jsx("span",{style:D.title,children:"Session"}),a.jsx("button",{style:D.closeBtn,onClick:e,children:"✕"})]}),a.jsxs("div",{style:D.body,children:[a.jsxs("div",{style:D.section,children:[a.jsx("div",{style:D.sectionTitle,children:"Save"}),a.jsx("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:a.jsx("button",{style:D.btn,onClick:k,disabled:!r||p,children:"Save to file"})}),a.jsx("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:"Session is also auto-saved to browser storage."})]}),a.jsxs("div",{style:D.section,children:[a.jsx("div",{style:D.sectionTitle,children:"Restore"}),a.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:[a.jsx("button",{style:D.btn,onClick:T,disabled:p,children:"Load from file"}),B&&a.jsx("button",{style:D.btn,onClick:R,disabled:p,children:"Restore last session"})]}),a.jsx("input",{ref:w,type:"file",accept:".json",style:{display:"none"},onChange:b}),B&&a.jsxs("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:["Last auto-save: ",new Date(B.savedAt).toLocaleString(),B.genome&&` — ${B.genome.name}`,B.tracks&&` — ${B.tracks.length} tracks`]})]}),v&&a.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#81c784"},children:v}),f&&a.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#ef9a9a",whiteSpace:"pre-wrap"},children:f})]}),a.jsx("div",{style:D.footer,children:a.jsx("button",{style:D.btn,onClick:e,children:"Close"})})]})})}function oy(e){return{overlay:{position:"fixed",inset:0,background:e.overlayBg,display:"flex",alignItems:"center",justifyContent:"center",zIndex:1e3},panel:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:0,minWidth:380,maxWidth:480,maxHeight:"80vh",display:"flex",flexDirection:"column",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},header:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"10px 16px",borderBottom:`1px solid ${e.border}`},title:{fontSize:14,fontWeight:700,color:e.textPrimary},closeBtn:{background:"none",border:"none",color:e.textSecondary,cursor:"pointer",fontSize:18,lineHeight:1,padding:"0 4px"},body:{padding:"8px 0",overflowY:"auto",flex:1},section:{padding:"8px 16px"},sectionTitle:{fontSize:11,color:e.textSecondary,textTransform:"uppercase",letterSpacing:1,marginBottom:6},btn:{background:e.btnBg,border:"none",borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600},footer:{display:"flex",justifyContent:"flex-end",padding:"10px 16px",borderTop:`1px solid ${e.border}`}}}const vn=[{target:"file-loader",title:"Load Files",description:"Select genome and track files using the file picker, drag and drop, or paste a local file path. Supported formats: FASTA, GenBank, BAM (+BAI), BigWig, WIG, BedGraph, VCF, BED, GTF, GFF.",position:"bottom"},{target:"nav-bar",title:"Navigation & Scrubber",description:"Switch chromosomes, type coordinates (chr1:1000-5000) to jump, zoom with -/+, and pan with ◀/▶. The blue scrubber bar shows your position — click or drag it to scroll across the entire chromosome.",position:"bottom"},{target:"track-area",title:"Track Interaction",description:"Left-click drag to pan, scroll to zoom. Right-click drag to select a region — hover the blue highlight for stats. Double-click a gene to zoom in with context. Hover features for detailed tooltips.",position:"inside"},{target:"skeleton-track-label",title:"Track Controls",description:"Drag ≡ to reorder tracks, click the color swatch to change colors, and click × to remove. Drag the bottom edge of a track to resize its height.",position:"right"},{target:"btn-settings",title:"Track Settings",description:"Select tracks and adjust: height, color, Y-axis scale (auto/manual/log), bar width, peak outline trace with color picker, show/hide bars, pointed arrows, and nucleotide display for BAM reads (shows A/C/G/T with mismatch highlighting when zoomed in).",position:"bottom",action:"open-settings"},{target:"header-btns",title:"Themes",description:"Choose from built-in themes (Dark, Light, Colorblind, Soft, High Contrast) or create a fully custom theme. Theme preferences persist across sessions.",position:"bottom",action:"open-theme"},{target:"btn-export",title:"Export Image",description:"Export your current view as SVG or PNG. The export respects all track settings including peak outlines, bar visibility, and scale labels.",position:"bottom"},{target:"header-btns",title:"Sessions",description:"Save Session exports your entire state (genome, tracks, region, zoom, colors, settings) as a JSON file. Restore it later or share with collaborators. Sessions also auto-save to your browser. An exit guard warns you before closing if you have unsaved work.",position:"bottom"},{target:"file-loader",title:"Large File Tips",description:"For large BAM files, use the 📂 Path button to paste a local file path — the server reads directly from disk without uploading. For large WIG files, convert to BigWig format for instant loading. The app checks for updates automatically in the background.",position:"bottom"}],wn=8,Sn=14,vt=340,ly=230,_r="rgba(0,0,0,0.55)";function iy({onClose:e,theme:t,onAction:n}){const[r,o]=j.useState(0),[l,i]=j.useState(null),[s,u]=j.useState(ly),c=j.useRef(null),g=vn[r],d=r===0,y=r===vn.length-1;j.useEffect(()=>{var b;const T=(b=vn[r])==null?void 0:b.action;T&&n&&n(T)},[r,n]);const E=j.useCallback(T=>{var R;((R=vn[T])==null?void 0:R.action)&&n&&n(null)},[n]),v=j.useCallback(()=>{E(r),r<vn.length-1?o(T=>T+1):e()},[r,e,E]),x=j.useCallback(()=>{E(r),r>0&&o(T=>T-1)},[r,E]);j.useEffect(()=>{function T(b){b.key==="Escape"?e():b.key==="ArrowRight"||b.key==="Enter"?v():b.key==="ArrowLeft"&&x()}return window.addEventListener("keydown",T),()=>window.removeEventListener("keydown",T)},[e,v,x]),j.useEffect(()=>{function T(){const b=document.querySelector(`[data-tour="${g.target}"]`);if(b){const R=b.getBoundingClientRect();i({top:R.top,left:R.left,width:R.width,height:R.height})}else i(null)}return T(),window.addEventListener("resize",T),window.addEventListener("scroll",T,!0),()=>{window.removeEventListener("resize",T),window.removeEventListener("scroll",T,!0)}},[g.target]),j.useEffect(()=>{c.current&&u(c.current.getBoundingClientRect().height)});const f=l?{top:l.top-wn,left:l.left-wn,width:l.width+wn*2,height:l.height+wn*2}:null;let h,p,m=null,w=vt/2;if(!l)h=(window.innerHeight-s)/2,p=(window.innerWidth-vt)/2;else{const T=g.position||"bottom",b=l.top+l.height+wn,R=l.top-wn,I=l.left+l.width+wn,B=l.left+l.width/2;T==="inside"?(h=l.top+Math.max(20,(l.height-s)/2),p=l.left+Math.max(16,(l.width-vt)/2)):T==="right"?(h=l.top+l.height/2-s/2,p=I+Sn,m="left",w=s/2,p+vt>window.innerWidth-12&&(h=b+Sn,p=B-vt/2,m="up",w=Math.max(20,Math.min(vt-20,B-p)))):(b+Sn+s<=window.innerHeight?(h=b+Sn,m="up"):R-Sn-s>=0?(h=R-Sn-s,m="down"):(h=b+Sn,m="up"),l.width<200?(p=Math.max(12,l.left+l.width-vt),p<12&&(p=12)):p=B-vt/2,w=Math.max(20,Math.min(vt-20,B-p))),p=Math.max(12,Math.min(window.innerWidth-vt-12,p)),h=Math.max(12,Math.min(window.innerHeight-s-12,h))}const k={card:{position:"fixed",top:h,left:p,width:vt,zIndex:10002,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:10,padding:"20px 24px 16px",color:t.textPrimary,boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},stepCounter:{fontSize:11,fontWeight:600,color:t.textTertiary,textTransform:"uppercase",letterSpacing:1.2,marginBottom:10},title:{fontSize:16,fontWeight:700,marginBottom:6,color:t.textPrimary},description:{fontSize:13,lineHeight:1.6,color:t.textSecondary,marginBottom:20},dots:{display:"flex",justifyContent:"center",gap:8,marginBottom:14},dot:T=>({width:7,height:7,borderRadius:"50%",background:T?"#42a5f5":t.borderStrong,cursor:"pointer"}),nav:{display:"flex",alignItems:"center",justifyContent:"space-between"},btnPrimary:{background:"#1976d2",border:"none",borderRadius:5,color:"#fff",padding:"6px 18px",cursor:"pointer",fontSize:12,fontWeight:600},btnSecondary:{background:t.btnBg,border:`1px solid ${t.borderStrong}`,borderRadius:5,color:t.btnText,padding:"6px 14px",cursor:"pointer",fontSize:12,fontWeight:600},btnDisabled:{background:t.btnBg,border:`1px solid ${t.border}`,borderRadius:5,color:t.textMuted,padding:"6px 14px",fontSize:12,fontWeight:600,cursor:"default",opacity:.5},skip:{background:"none",border:"none",color:t.textTertiary,fontSize:11,cursor:"pointer",textDecoration:"underline",padding:0},arrowUp:{position:"absolute",top:-7,left:w-7,width:0,height:0,borderLeft:"7px solid transparent",borderRight:"7px solid transparent",borderBottom:`7px solid ${t.panelBg}`},arrowDown:{position:"absolute",bottom:-7,left:w-7,width:0,height:0,borderLeft:"7px solid transparent",borderRight:"7px solid transparent",borderTop:`7px solid ${t.panelBg}`},arrowLeft:{position:"absolute",left:-7,top:w-7,width:0,height:0,borderTop:"7px solid transparent",borderBottom:"7px solid transparent",borderRight:`7px solid ${t.panelBg}`}};return a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4},onClick:e}),f?a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{position:"fixed",top:0,left:0,right:0,height:Math.max(0,f.top),background:_r,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:f.top+f.height,left:0,right:0,bottom:0,background:_r,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:f.top,left:0,width:Math.max(0,f.left),height:f.height,background:_r,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:f.top,left:f.left+f.width,right:0,height:f.height,background:_r,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:f.top,left:f.left,width:f.width,height:f.height,borderRadius:6,border:"2px solid rgba(255,255,255,0.22)",zIndex:10001,pointerEvents:"none",boxSizing:"border-box"}})]}):a.jsx("div",{style:{position:"fixed",inset:0,background:_r,zIndex:10001,pointerEvents:"none"}}),a.jsxs("div",{ref:c,style:k.card,onClick:T=>T.stopPropagation(),children:[m==="up"&&a.jsx("div",{style:k.arrowUp}),m==="down"&&a.jsx("div",{style:k.arrowDown}),m==="left"&&a.jsx("div",{style:k.arrowLeft}),a.jsxs("div",{style:k.stepCounter,children:["Step ",r+1," of ",vn.length]}),a.jsx("div",{style:k.title,children:g.title}),a.jsx("div",{style:k.description,children:g.description}),a.jsx("div",{style:k.dots,children:vn.map((T,b)=>a.jsx("div",{style:k.dot(b===r),onClick:()=>o(b)},b))}),a.jsxs("div",{style:k.nav,children:[a.jsx("button",{style:k.skip,onClick:e,children:"Skip Tour"}),a.jsxs("div",{style:{display:"flex",gap:8},children:[a.jsx("button",{style:d?k.btnDisabled:k.btnSecondary,onClick:x,disabled:d,children:"Previous"}),a.jsx("button",{style:k.btnPrimary,onClick:v,children:y?"Finish":"Next"})]})]})]})]})}function sy(){const{theme:e}=De(),{genome:t,region:n,navigateTo:r,zoom:o,pan:l}=Ze(),[i,s]=j.useState(""),u=j.useRef(null),c=j.useRef(!1),g=j.useMemo(()=>{if(!t)return{toShort:{},toLong:{}};const w={},k={};return t.chromosomes.forEach((T,b)=>{const R=`chr${b+1}`;w[T.name]=R,k[R.toLowerCase()]=T.name,k[T.name.toLowerCase()]=T.name}),{toShort:w,toLong:k}},[t]);j.useEffect(()=>{if(n){const w=g.toShort[n.chrom]||n.chrom;s(`${w}:${n.start.toLocaleString()}-${n.end.toLocaleString()}`)}},[n,g]);const d=j.useMemo(()=>{if(!t||!n)return 0;const w=t.chromosomes.find(k=>k.name===n.chrom);return w?w.length:0},[t,n==null?void 0:n.chrom]),y=j.useCallback(w=>{if(!u.current||!n||!d)return;const k=u.current.getBoundingClientRect(),T=Math.max(0,Math.min(1,(w-k.left)/k.width)),b=n.end-n.start,R=T*d;r(n.chrom,R-b/2,R+b/2)},[n,d,r]),E=j.useCallback(w=>{w.preventDefault(),c.current=!0,y(w.clientX);function k(b){c.current&&y(b.clientX)}function T(){c.current=!1,window.removeEventListener("mousemove",k),window.removeEventListener("mouseup",T),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="grabbing",document.body.style.userSelect="none",window.addEventListener("mousemove",k),window.addEventListener("mouseup",T)},[y]),v={bar:{background:e.headerBg,borderBottom:`1px solid ${e.border}`,padding:"6px 12px",display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},select:{background:e.inputBg,border:`1px solid ${e.borderAccent}`,borderRadius:4,color:e.textPrimary,padding:"4px 6px",fontSize:12},coordInput:{background:e.inputBg,border:`1px solid ${e.borderAccent}`,borderRadius:4,color:e.textPrimary,padding:"4px 8px",fontSize:12,width:220,fontFamily:"monospace"},btn:{background:e.btnBg,border:"none",borderRadius:4,color:e.btnText,padding:"4px 10px",cursor:"pointer",fontSize:13},info:{color:e.textSecondary,fontSize:11,marginLeft:8},scrubberWrap:{flex:1,minWidth:120,height:14,position:"relative",background:e.inputBg,borderRadius:7,border:`1px solid ${e.borderAccent}`,cursor:"pointer",overflow:"hidden"}};function x(w){if(!t)return;const k=t.chromosomes.find(T=>T.name===w.target.value);k&&r(k.name,0,Math.min(k.length,5e4))}function f(w){w.preventDefault();const T=i.replace(/,/g,"").trim().match(/^(\S+):(\d+)-(\d+)$/);if(T){const b=g.toLong[T[1].toLowerCase()]||T[1];r(b,parseInt(T[2]),parseInt(T[3]))}}if(!t)return a.jsx("div",{style:{...v.bar,opacity:.4},"data-tour":"nav-bar",children:a.jsx("span",{style:{fontSize:12,color:e.textMuted,fontStyle:"italic"},children:"Load a genome to enable navigation"})});const h=n?n.end-n.start:0;let p=0,m=100;return n&&d>0&&(p=n.start/d*100,m=Math.max(1,h/d*100)),a.jsxs("div",{style:v.bar,"data-tour":"nav-bar",children:[a.jsx("select",{style:v.select,value:(n==null?void 0:n.chrom)||"",onChange:x,children:t.chromosomes.map((w,k)=>a.jsxs("option",{value:w.name,children:["chr",k+1," ","—"," ",w.name," (",(w.length/1e3).toFixed(0)," kbp)"]},w.name))}),a.jsxs("form",{onSubmit:f,style:{display:"flex",gap:4},children:[a.jsx("input",{style:v.coordInput,value:i,onChange:w=>s(w.target.value),placeholder:"chr1:start-end"}),a.jsx("button",{style:v.btn,type:"submit",children:"Go"})]}),a.jsx("button",{style:v.btn,onClick:()=>o(2),title:"Zoom out",children:"-"}),a.jsx("button",{style:v.btn,onClick:()=>o(.5),title:"Zoom in",children:"+"}),a.jsx("button",{style:v.btn,onClick:()=>l(-h*.5),title:"Pan left",children:"◀"}),a.jsx("button",{style:v.btn,onClick:()=>l(h*.5),title:"Pan right",children:"▶"}),n&&d>0&&a.jsx("div",{ref:u,style:v.scrubberWrap,onMouseDown:E,title:"Drag to scroll across the chromosome",children:a.jsx("div",{style:{position:"absolute",left:`${p}%`,width:`${m}%`,top:1,bottom:1,background:"#42a5f5",borderRadius:6,minWidth:8,opacity:.7,transition:c.current?"none":"left 0.1s ease"}})}),n&&a.jsxs("span",{style:v.info,children:[h.toLocaleString()," bp"]})]})}function mp(e){const{region:t,zoom:n,navigateTo:r,setSelection:o,clearSelection:l}=Ze(),i=j.useRef(null),s=j.useRef(null),u=j.useRef(t);u.current=t,j.useEffect(()=>{const c=e.current;if(!c)return;function g(x){const f=u.current;if(f){if(x.button===2){x.preventDefault();const h=c.getBoundingClientRect(),p=(x.clientX-h.left)/h.width,m=f.start+p*(f.end-f.start);s.current={startX:x.clientX,startBp:m,region:{...f},containerWidth:h.width};return}x.button===0&&(l(),i.current={x:x.clientX,startRegion:{...f},containerWidth:c.offsetWidth||c.clientWidth||1})}}function d(x){if(s.current){const T=s.current,b=c.getBoundingClientRect(),R=Math.max(0,Math.min(1,(x.clientX-b.left)/b.width)),I=T.region.start+R*(T.region.end-T.region.start),B=Math.min(T.startBp,I),D=Math.max(T.startBp,I);Math.abs(D-B)>=1&&o({chrom:T.region.chrom,start:Math.floor(B),end:Math.ceil(D)});return}if(!i.current)return;const f=x.clientX-i.current.x,{chrom:h,start:p,end:m}=i.current.startRegion,w=(m-p)/i.current.containerWidth,k=-f*w;r(h,p+k,m+k)}function y(x){if(s.current){s.current=null;return}i.current=null}function E(x){x.preventDefault()}function v(x){x.preventDefault();const f=c.getBoundingClientRect(),h=(x.clientX-f.left)/f.width,p=x.deltaY>0?1.4:.7;n(p,h)}return c.addEventListener("mousedown",g),c.addEventListener("contextmenu",E),window.addEventListener("mousemove",d),window.addEventListener("mouseup",y),c.addEventListener("wheel",v,{passive:!1}),()=>{c.removeEventListener("mousedown",g),c.removeEventListener("contextmenu",E),window.removeEventListener("mousemove",d),window.removeEventListener("mouseup",y),c.removeEventListener("wheel",v)}},[n,r,o,l,e])}const kn=30;function ay({width:e}){const t=j.useRef(null),n=j.useRef(null),{region:r,selection:o}=Ze(),{theme:l}=De();return mp(t),j.useEffect(()=>{const i=n.current;if(!i||!r)return;const s=window.devicePixelRatio||1;i.width=e*s,i.height=kn*s;const u=i.getContext("2d");u.scale(s,s);const{start:c,end:g}=r,d=g-c;if(u.clearRect(0,0,e,kn),u.fillStyle=l.canvasBg,u.fillRect(0,0,e,kn),o&&o.chrom===r.chrom){const p=(o.start-c)/d,m=(o.end-c)/d,w=Math.max(0,p*e),k=Math.min(e,m*e);k-w>=1&&(u.fillStyle="rgba(100, 181, 246, 0.25)",u.fillRect(w,0,k-w,kn),u.strokeStyle="rgba(100, 181, 246, 0.6)",u.lineWidth=1,u.beginPath(),u.moveTo(w,0),u.lineTo(w,kn),u.moveTo(k,0),u.lineTo(k,kn),u.stroke())}const y=Math.min(10,Math.floor(e/80)),E=d/y,v=Math.pow(10,Math.floor(Math.log10(E))),x=[1,2,5,10].map(p=>p*v),f=x.find(p=>p>=E)||x[x.length-1],h=Math.ceil(c/f)*f;u.strokeStyle=l.rulerTick,u.fillStyle=l.rulerLabel,u.font="10px Arial, Helvetica, sans-serif",u.textAlign="center",u.beginPath(),u.moveTo(0,20),u.lineTo(e,20),u.lineWidth=1,u.stroke();for(let p=h;p<=g;p+=f){const m=(p-c)/d*e;u.beginPath(),u.moveTo(m,14),u.lineTo(m,20),u.stroke(),u.fillText(uy(p),m,11)}},[r,o,e,l]),a.jsx("div",{ref:t,style:{position:"relative"},children:a.jsx("canvas",{ref:n,style:{display:"block",width:"100%",height:kn}})})}function uy(e){return e>=1e6?`${(e/1e6).toFixed(2)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function Li(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),s=Math.min(e.length-1,r+t);for(let u=i;u<=s;u++)o+=e[u],l++;n[r]=o/l}return n}function Hn(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function cy({track:e,width:t,height:n,onWarning:r}){const o=j.useRef(null),{region:l}=Ze(),{theme:i}=De(),{data:s,loading:u,error:c}=Kl(e,l,t);return j.useEffect(()=>{var O,L;const g=o.current;if(!g)return;const d=window.devicePixelRatio||1;g.width=t*d,g.height=n*d;const y=g.getContext("2d");if(y.scale(d,d),y.clearRect(0,0,t,n),y.fillStyle=i.canvasBg,y.fillRect(0,0,t,n),u&&!((O=s==null?void 0:s.bins)!=null&&O.length)){y.fillStyle=i.textTertiary,y.font="11px Arial, Helvetica, sans-serif",y.fillText("Loading…",8,n/2+4),r&&r(null);return}if(c){y.fillStyle="#ef9a9a",y.font="11px Arial, Helvetica, sans-serif",y.fillText(typeof c=="string"?c:JSON.stringify(c),8,n/2+4),r&&r(null);return}if(!((L=s==null?void 0:s.bins)!=null&&L.length)){r&&r(null);return}const E=s.max_value||0,v=s.min_value||0,x=v<0,f=l.start,h=l.end-l.start,p=e.color||"#78909c",m=e.scaleMax!=null?e.scaleMax:null,w=e.scaleMin!=null?e.scaleMin:null,k=e.logScale===!0,T=e.barAutoWidth!==!1,b=e.barWidth||2,R=e.showOutline===!0,I=e.outlineColor||null,B=e.outlineSmooth||0,D=e.showBars!==!1,W=p,P=dy(p,-40),U=t/h;function $(C){return T?U>=1?Math.max(1,Math.min(U,C)):Math.max(1,C):Math.min(b,C)}if(x){const S=Math.round(n/2),N=S-12/2,z=n-S-12/2,A=m??(E||1),Y=w??(Math.abs(v)||1);if(y.strokeStyle=i.centerLine,y.lineWidth=1,y.beginPath(),y.moveTo(0,S),y.lineTo(t,S),y.stroke(),D)for(const Q of s.bins){const ne=(Q.end-Q.start)/h*t,fe=$(ne),Re=(Q.start-f)/h*t,Te=Q.forward!=null?Q.forward:Math.max(0,Q.value),et=Q.reverse!=null?Q.reverse:Math.min(0,Q.value);if(Te>0){const ue=k?Hn(Te,A):Te/A;y.fillStyle=W,y.fillRect(Re,S-ue*N,fe,ue*N)}if(et<0){const ue=k?Hn(Math.abs(et),Y):Math.abs(et)/Y;y.fillStyle=P,y.fillRect(Re,S,fe,ue*z)}}if(R&&s.bins.length>0){const Q=I||i.textPrimary||"#fff",ne=I||i.textPrimary||"#fff",fe=s.bins.map(se=>{const ye=se.forward!=null?se.forward:Math.max(0,se.value);return ye>0?k?Hn(ye,A):ye/A:0}),Re=s.bins.map(se=>{const ye=se.reverse!=null?se.reverse:Math.min(0,se.value);return ye<0?k?Hn(Math.abs(ye),Y):Math.abs(ye)/Y:0}),Te=Li(fe,B),et=Li(Re,B),ue=s.bins.map(se=>((se.start+se.end)/2-f)/h*t);Bi(y,ue,Te.map(se=>S-se*N),Q,B>0),Bi(y,ue,et.map(se=>S+se*z),ne,B>0)}const V=k?" log₂":"";Lr(y,`+${A.toFixed(1)}${V}`,2,2,i),Lr(y,`−${Y.toFixed(1)}${V}`,2,n-12,i),Lr(y,"0",2,S-6,i,!0)}else{const C=m??(E||1);if(D){y.fillStyle=W;for(const N of s.bins){const z=(N.end-N.start)/h*t,A=$(z),Y=(N.start-f)/h*t,Q=(k?Hn(N.value,C):N.value/C)*(n-14);y.fillRect(Y,n-Q-2,A,Q)}}if(R&&s.bins.length>0){const N=s.bins.map(V=>k?Hn(V.value,C):V.value/C),z=Li(N,B),A=s.bins.map(V=>((V.start+V.end)/2-f)/h*t),Y=z.map(V=>n-V*(n-14)-2);Bi(y,A,Y,I||i.textPrimary||"#fff",B>0)}const S=k?" log₂":"";Lr(y,`${C.toFixed(1)}${S}`,2,2,i),Lr(y,"0",2,n-12,i,!0)}if(r){const C=[];m!=null&&E>m&&C.push(`Bars clipped: max value ${E.toFixed(1)} exceeds scale ${m.toFixed(1)}`),x&&w!=null&&Math.abs(v)>w&&C.push(`Negative bars clipped: min value ${Math.abs(v).toFixed(1)} exceeds scale ${w.toFixed(1)}`),r(C.length>0?C.join(`
|
|
97
|
-
`):null)}},[s,u,c,t,n,l,e.color,e.scaleMax,e.scaleMin,e.logScale,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Bi(e,t,n,r,o){if(!(t.length<2)){if(e.beginPath(),e.moveTo(t[0],n[0]),o){for(let l=0;l<t.length-1;l++){const i=(t[l]+t[l+1])/2,s=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,s)}e.lineTo(t[t.length-1],n[n.length-1])}else for(let l=0;l<t.length;l++)e.lineTo(t[l],n[l]);e.strokeStyle=r,e.lineWidth=1.5,e.stroke()}}function Lr(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=e.measureText(t),s=2,u=i.width+s*2,c=12;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,u,c),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+s,r+1),e.textBaseline="alphabetic"}function dy(e,t){const n=e.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);if(!n)return e;const r=o=>Math.max(0,Math.min(255,o+t));return`rgb(${r(parseInt(n[1],16))},${r(parseInt(n[2],16))},${r(parseInt(n[3],16))})`}const vc=6,fy=8,py=14,hy=2,my="#9c27b0",gy={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},yy="#ffeb3b";function xy({track:e,width:t,height:n,onWarning:r}){const o=j.useRef(null),{region:l}=Ze(),{theme:i}=De(),{data:s,loading:u}=Kl(e,l,t),[c,g]=j.useState(null),d=j.useRef(null),y=e.showNucleotides!==!1,E=e.useArrows!==!1;return j.useEffect(()=>{if(!l||!y){g(null);return}const v=l.end-l.start;if(t/v<vc||v>2e3){g(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const f=Math.max(0,l.start-500),h=l.end+500,p=`${l.chrom}:${f}-${h}`;d.current!==p&&(d.current=p,dn.sequence(l.chrom,f,h).then(m=>{g({chrom:l.chrom,start:f,end:h,sequence:m.data.sequence})}).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,y]),j.useEffect(()=>{var I;const v=o.current;if(!v)return;const x=window.devicePixelRatio||1;v.width=t*x,v.height=n*x;const f=v.getContext("2d");if(f.scale(x,x),f.clearRect(0,0,t,n),f.fillStyle=i.canvasBg,f.fillRect(0,0,t,n),u&&!s){f.fillStyle=i.textTertiary,f.font="11px Arial, Helvetica, sans-serif",f.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!s){r&&r(null);return}const h=l.start,p=l.end-l.start;if(s.bins){const B=s.max_value||1,D=e.scaleMax!=null?e.scaleMax:B,W=e.color||"#78909c",P=e.barAutoWidth!==!1,U=e.barWidth||2,$=t/p;if(e.showBars!==!1){f.fillStyle=W;for(const O of s.bins){const L=(O.end-O.start)/p*t,C=P?$>=1?Math.max(1,Math.min($,L)):Math.max(1,L):Math.min(U,L),S=(O.start-h)/p*t,z=Math.min(1,O.value/D)*(n-14);f.fillRect(S,n-z-2,C,z)}}if(e.showOutline&&s.bins.length>0){const O=e.outlineSmooth||0,L=s.bins.map(A=>Math.min(1,A.value/D)),C=vy(L,O),S=s.bins.map(A=>((A.start+A.end)/2-h)/p*t),N=C.map(A=>n-A*(n-14)-2),z=e.outlineColor||i.textPrimary||"#fff";if(f.beginPath(),f.moveTo(S[0],N[0]),O>0){for(let A=0;A<S.length-1;A++)f.quadraticCurveTo(S[A],N[A],(S[A]+S[A+1])/2,(N[A]+N[A+1])/2);f.lineTo(S[S.length-1],N[N.length-1])}else for(let A=0;A<S.length;A++)f.lineTo(S[A],N[A]);f.strokeStyle=z,f.lineWidth=1.5,f.stroke()}wc(f,D.toFixed(1),2,2,i),wc(f,"0",2,n-12,i,!0),f.fillStyle="#ffb74d",f.font="10px Arial, Helvetica, sans-serif",f.textAlign="right",f.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&B>e.scaleMax?`Bars clipped: max value ${B.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((I=s.reads)!=null&&I.length)){f.fillStyle=i.textTertiary,f.font="11px Arial, Helvetica, sans-serif",f.fillText("No reads in region",8,n/2+4),r&&r(null);return}const m=B=>(B-h)/p*t,w=t/p,k=y&&w>=vc&&c!=null,T=k?py:fy,b=hy;let R=0;for(const B of s.reads){const D=B.row*(T+b)+2;if(D+T>n){R++;continue}const W=B.strand==="+"?"#90a4ae":"#f06292",P=B.segments;if(P&&P.length>0){const U=m(B.start),$=m(B.end);f.strokeStyle=W,f.lineWidth=1,f.beginPath(),f.moveTo(U,D+T/2),f.lineTo($,D+T/2),f.stroke();let O=0;for(const L of P)if(L.type==="M"){const C=m(L.start),S=Math.max(1,m(L.end)-C);if(f.fillStyle=W,f.fillRect(C,D,S,T),k&&B.sequence){const N=L.end-L.start;for(let z=0;z<N;z++){const A=L.start+z,Y=m(A),V=m(A+1)-Y,ne=(B.sequence[O+z]||"").toUpperCase();let fe="";c&&A>=c.start&&A<c.end&&(fe=(c.sequence[A-c.start]||"").toUpperCase());const Re=fe&&ne&&ne!==fe&&ne!=="N";Re&&(f.fillStyle=yy,f.fillRect(Y,D,V,T)),V>=6&&(f.fillStyle=Re?"#000":gy[ne]||"#999",f.font=`bold ${Math.min(11,V-1)}px monospace`,f.textAlign="center",f.textBaseline="middle",f.fillText(ne,Y+V/2,D+T/2))}O+=N}}else if(L.type==="D"){const C=m(L.start),S=m(L.end)-C;S>=1&&(f.strokeStyle=W,f.lineWidth=1,f.beginPath(),f.moveTo(C,D+T/2),f.lineTo(C+S,D+T/2),f.stroke())}else if(L.type==="N"){const C=m(L.start),S=m(L.end)-C;S>=2&&(f.setLineDash([2,2]),f.strokeStyle=W,f.lineWidth=1,f.beginPath(),f.moveTo(C,D+T/2),f.lineTo(C+S,D+T/2),f.stroke(),f.setLineDash([]))}else if(L.type==="I"){const C=m(L.pos);f.fillStyle=my,f.fillRect(C-1,D-1,2,T+2),k&&(O+=L.length)}else L.type==="S"&&k&&(O+=L.length)}else{const U=m(B.start),$=Math.max(2,m(B.end)-U);f.fillStyle=W,f.fillRect(U,D,$,T)}if(E){const U=m(B.start),$=Math.max(2,m(B.end)-U),O=Math.min(k?6:4,$/2);O>=2&&(f.fillStyle=i.canvasBg,B.strand==="+"?(f.beginPath(),f.moveTo(U+$,D+T/2),f.lineTo(U+$-O,D),f.lineTo(U+$-O,D+T),f.fill()):(f.beginPath(),f.moveTo(U,D+T/2),f.lineTo(U+O,D),f.lineTo(U+O,D+T),f.fill()))}if(!k&&!y){const U=m(B.start);Math.max(2,m(B.end)-U)>60&&(f.fillStyle=i.canvasBg,f.font="8px Arial, Helvetica, sans-serif",f.textAlign="left",f.fillText(B.name.slice(0,20),U+2,D+T-1))}}r&&r(R>0?`${R} read${R>1?"s":""} hidden — increase track height to show all`:null)},[s,u,t,n,l,c,e.color,e.scaleMax,e.scaleMin,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,e.showNucleotides,e.useArrows,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function vy(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),s=Math.min(e.length-1,r+t);for(let u=i;u<=s;u++)o+=e[u],l++;n[r]=o/l}return n}function wc(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,s=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,s,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const wy=16,Sy=22,ky=4,gp=8,Sc=6,by={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Cy({track:e,width:t,height:n,onWarning:r}){var I,B,D,W;const o=j.useRef(null),{region:l,navigateTo:i}=Ze(),{tracks:s}=Vt(),{theme:u}=De(),{data:c,loading:g,error:d}=Kl(e,l,t),y=e.useArrows!==!1,E=e.showNucleotides!==!1,v=j.useRef([]),[x,f]=j.useState(null),[h,p]=j.useState(null),m=j.useRef(null);j.useEffect(()=>{if(!l||!E){p(null);return}const P=l.end-l.start;if(t/P<Sc||P>2e3){p(null);return}if(h&&h.chrom===l.chrom&&h.start<=l.start&&h.end>=l.end)return;const $=Math.max(0,l.start-500),O=l.end+500,L=`${l.chrom}:${$}-${O}`;m.current!==L&&(m.current=L,dn.sequence(l.chrom,$,O).then(C=>p({chrom:l.chrom,start:$,end:O,sequence:C.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,E]),j.useEffect(()=>{var Y,V;const P=o.current;if(!P)return;const U=window.devicePixelRatio||1;P.width=t*U,P.height=n*U;const $=P.getContext("2d");if($.scale(U,U),$.clearRect(0,0,t,n),$.fillStyle=u.canvasBg,$.fillRect(0,0,t,n),v.current=[],g&&!((Y=c==null?void 0:c.features)!=null&&Y.length)){$.fillStyle=u.textTertiary,$.font="11px Arial, Helvetica, sans-serif",$.fillText("Loading…",8,n/2+4),r&&r(null);return}if(d){$.fillStyle="#ef9a9a",$.font="11px Arial, Helvetica, sans-serif",$.fillText(typeof d=="string"?d:JSON.stringify(d),8,n/2+4),r&&r(null);return}if(!((V=c==null?void 0:c.features)!=null&&V.length)){c&&($.fillStyle=u.textTertiary,$.font="11px Arial, Helvetica, sans-serif",$.fillText("No features in region",8,n/2+4)),r&&r(null);return}const O=l.end-l.start,L=t/O,C=E&&L>=Sc&&h!=null,S=C?Sy:wy,N=[],z=[];let A=0;for(const Q of c.features){let ne=N.findIndex(ue=>Q.start>=ue);ne===-1&&(ne=N.length),N[ne]=Q.end;const fe=(Q.start-l.start)/O*t,Re=Math.max(2,(Q.end-Q.start)/O*t),Te=ne*(S+ky)+2;if(Te+S>n){A++;continue}const et=bc(Q.feature_type,e,u);if(Q.sub_features&&Q.sub_features.length>0){$.fillStyle=et+"66",$.fillRect(fe,Te+S/2-1,Re,2);for(const ue of Q.sub_features){const se=(ue.start-l.start)/O*t,ye=Math.max(1,(ue.end-ue.start)/O*t),At=bc(ue.feature_type,e,u),Gt=ue.feature_type==="CDS"?S:S-6,yt=ue.feature_type==="CDS"?Te:Te+3;y?kc($,At,se,yt,ye,Gt,ue.strand||Q.strand):($.fillStyle=At,$.fillRect(se,yt,ye,Gt))}}else y?kc($,et,fe,Te,Re,S,Q.strand):($.fillStyle=et,$.fillRect(fe,Te,Re,S));if(C){const ue=Math.max(Q.start,l.start),se=Math.min(Q.end,l.end);for(let ye=ue;ye<se;ye++)if(h&&ye>=h.start&&ye<h.end){const At=(h.sequence[ye-h.start]||"").toUpperCase(),Gt=(ye-l.start)/O*t,yt=L;yt>=6&&($.fillStyle=by[At]||"#999",$.font=`bold ${Math.min(10,yt-1)}px monospace`,$.textAlign="center",$.textBaseline="middle",$.fillText(At,Gt+yt/2,Te+S/2))}}else if(Re>20){$.fillStyle="#fff",$.font="10px Arial, Helvetica, sans-serif",$.textAlign="left",$.textBaseline="alphabetic";const ue=Q.name||Q.feature_type,se=Math.floor((Re-(y?gp:0)-4)/6);se>0&&$.fillText(ue.slice(0,se),fe+3,Te+S-4)}z.push({feat:Q,x:fe,y:Te,w:Re,h:S})}v.current=z,r&&r(A>0?`${A} feature${A>1?"s":""} hidden — increase track height to show all`:null)},[c,g,d,t,n,l,h,e.color,e.annotationColors,y,e.showNucleotides,u]);const w=j.useCallback(P=>{const U=o.current;if(!U)return;const $=U.getBoundingClientRect(),O=(P.clientX-$.left)*(t/$.width),L=(P.clientY-$.top)*(n/$.height);for(const C of v.current)if(O>=C.x&&O<=C.x+C.w&&L>=C.y&&L<=C.y+C.h){const S=Math.min(P.clientX+14,window.innerWidth-300),N=Math.min(P.clientY+14,window.innerHeight-260);f({feat:C.feat,x:Math.max(4,S),y:Math.max(4,N)});return}f(null)},[t,n]),k=j.useCallback(()=>f(null),[]),T=j.useCallback(P=>{const U=o.current;if(!U||!l)return;const $=U.getBoundingClientRect(),O=(P.clientX-$.left)*(t/$.width),L=(P.clientY-$.top)*(n/$.height);for(const C of v.current)if(O>=C.x&&O<=C.x+C.w&&L>=C.y&&L<=C.y+C.h){const S=C.feat,z=(S.end-S.start)*.15/(1-.3),A=S.start-z,Y=S.end+z;i(l.chrom,A,Y),f(null);return}},[t,n,l,i]),b=x?Ty(x.feat,s,l==null?void 0:l.chrom):[],R=x?On.createPortal(a.jsxs("div",{style:{position:"fixed",left:x.x,top:x.y,background:u.tooltipBg,border:`1px solid ${u.tooltipBorder}`,borderRadius:4,padding:"6px 10px",color:u.textPrimary,fontSize:11,lineHeight:1.5,maxWidth:280,zIndex:1e4,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:[a.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:x.feat.name||x.feat.feature_type}),a.jsx(Kt,{label:"Type",value:x.feat.feature_type}),a.jsx(Kt,{label:"Strand",value:x.feat.strand||"."}),a.jsx(Kt,{label:"Location",value:`${x.feat.start.toLocaleString()}–${x.feat.end.toLocaleString()}`}),a.jsx(Kt,{label:"Length",value:`${(x.feat.end-x.feat.start).toLocaleString()} bp`}),((I=x.feat.attributes)==null?void 0:I.gene)&&x.feat.attributes.gene!==x.feat.name&&a.jsx(Kt,{label:"Gene",value:x.feat.attributes.gene}),((B=x.feat.attributes)==null?void 0:B.locus_tag)&&a.jsx(Kt,{label:"Locus",value:x.feat.attributes.locus_tag}),((D=x.feat.attributes)==null?void 0:D.product)&&a.jsx(Kt,{label:"Product",value:x.feat.attributes.product}),((W=x.feat.attributes)==null?void 0:W.note)&&a.jsx(Kt,{label:"Note",value:String(x.feat.attributes.note).slice(0,120)}),b.length>0&&a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:a.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),b.map(P=>a.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[a.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:P.name}),a.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:P.total.toFixed(1)})]},P.trackId))]})]}),document.body):null;return a.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:k,onDoubleClick:T}),R]})}function Kt({label:e,value:t}){return t?a.jsxs("div",{style:{display:"flex",gap:6},children:[a.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),a.jsx("span",{children:t})]}):null}function Ty(e,t,n){var o;if(!e||!n)return[];const r=[];for(const l of t){if(l.track_type!=="coverage"&&l.track_type!=="reads")continue;const i=I0(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let s=0;for(const u of i.bins){if(u.end<=e.start||u.start>=e.end)continue;const c=u.forward!=null?u.forward:Math.max(0,u.value||0),g=u.reverse!=null?Math.abs(u.reverse):Math.abs(Math.min(0,u.value||0));s+=c+g}s>0&&r.push({trackId:l.id,name:l.name,total:s})}return r}function kc(e,t,n,r,o,l,i){e.fillStyle=t;const s=Math.min(gp,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-s,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-s,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+s,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+s,r+l),e.lineTo(n,r+l/2),e.closePath()):e.rect(n,r,o,l),e.fill(),e.strokeStyle="rgba(0,0,0,0.25)",e.lineWidth=.5,e.stroke()}function bc(e,t,n){const r=t.annotationColors;switch(e==null?void 0:e.toLowerCase()){case"cds":return(r==null?void 0:r.cds)||(n==null?void 0:n.geneCds)||"#66bb6a";case"exon":return(r==null?void 0:r.exon)||(n==null?void 0:n.geneExon)||"#42a5f5";case"gene":return(r==null?void 0:r.gene)||(n==null?void 0:n.geneGene)||"#7e57c2";case"mrna":case"transcript":return(r==null?void 0:r.transcript)||(n==null?void 0:n.geneTranscript)||"#ab47bc";case"utr":case"3utr":case"5utr":return(r==null?void 0:r.utr)||(n==null?void 0:n.geneUtr)||"#26c6da";case"rrna":return(r==null?void 0:r.rrna)||(n==null?void 0:n.geneRrna)||"#ffa726";case"trna":return(r==null?void 0:r.trna)||(n==null?void 0:n.geneTrna)||"#ef5350";case"repeat_region":return(r==null?void 0:r.repeat)||(n==null?void 0:n.geneRepeat)||"#8d6e63";default:return(r==null?void 0:r.default)||t.color||(n==null?void 0:n.geneDefault)||"#80cbc4"}}function Ey({track:e,width:t,height:n,onWarning:r}){const o=j.useRef(null),{region:l}=Ze(),{theme:i}=De(),{data:s,loading:u}=Kl(e,l,t);return j.useEffect(()=>{var h,p;const c=o.current;if(!c)return;const g=window.devicePixelRatio||1;c.width=t*g,c.height=n*g;const d=c.getContext("2d");if(d.scale(g,g),d.clearRect(0,0,t,n),d.fillStyle=i.canvasBg,d.fillRect(0,0,t,n),u&&!((h=s==null?void 0:s.variants)!=null&&h.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((p=s==null?void 0:s.variants)!=null&&p.length)){s&&(d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("No variants in region",8,n/2+4)),r&&r(null);return}const y=l.end-l.start,E=e.barAutoWidth!==!1,v=e.barWidth||2,x=E?1:Math.max(.5,v),f=E?5:Math.max(2,v*2);for(const m of s.variants){const w=(m.pos-l.start)/y*t,k=jy(m.ref,m.alt);d.strokeStyle=k,d.lineWidth=x,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=k,d.beginPath(),d.arc(w,10,f,0,Math.PI*2),d.fill(),y<5e3&&(d.fillStyle=i.textPrimary,d.font="9px Arial, Helvetica, sans-serif",d.textAlign="center",d.fillText(`${m.ref}>${m.alt[0]||"?"}`,w,n-6))}if(r){const m=s.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[s,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function jy(e,t){const n=t[0]||"";return e.length===1&&n.length===1?"#ffb74d":n.length>e.length?"#81c784":n.length<e.length?"#e57373":"#b0bec5"}function Ry({message:e,theme:t}){const[n,r]=j.useState(!1),o=j.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return a.jsxs(a.Fragment,{children:[a.jsx("span",{ref:o,onMouseEnter:()=>r(!0),onMouseLeave:()=>r(!1),style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:12,height:12,borderRadius:"50%",background:"rgba(229, 57, 53, 0.85)",color:"#fff",fontSize:9,fontWeight:800,lineHeight:1,cursor:"default",flexShrink:0,fontFamily:"Arial, Helvetica, sans-serif"},children:"!"}),n&&l&&On.createPortal(a.jsx("div",{style:{position:"fixed",left:Math.min(l.right+6,window.innerWidth-220),top:l.top-4,background:t.tooltipBg||"#333",border:`1px solid ${t.tooltipBorder||"#555"}`,borderRadius:4,padding:"4px 8px",color:t.textPrimary||"#e0e0e0",fontSize:11,lineHeight:1.4,maxWidth:200,zIndex:10001,pointerEvents:"none",boxShadow:"0 3px 10px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",fontFamily:"Arial, Helvetica, sans-serif"},children:e}),document.body)]})}function Py({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=Ze(),{theme:s}=De(),[u,c]=j.useState(!1),[g,d]=j.useState({x:0,y:0}),y=j.useRef(null),E=j.useCallback(B=>{d({x:B.clientX,y:B.clientY}),c(!0)},[]),v=j.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const x=o.end-o.start;if(x<=0)return null;const f=(l.start-o.start)/x,h=(l.end-o.start)/x,p=Math.max(0,f*e),w=Math.min(e,h*e)-p;if(w<1)return null;const k=_y(l,n,r),T=l.end-l.start,b=260,R=Math.min(g.x+14,window.innerWidth-b-10),I=Math.min(g.y+14,window.innerHeight-200);return a.jsxs("div",{ref:y,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[a.jsx("div",{style:{position:"absolute",left:p,top:0,width:w,height:"100%",background:"rgba(100, 181, 246, 0.2)",borderLeft:"1px solid rgba(100, 181, 246, 0.6)",borderRight:"1px solid rgba(100, 181, 246, 0.6)",pointerEvents:"auto",cursor:"crosshair"},onMouseMove:E,onMouseLeave:v,onClick:B=>{B.stopPropagation(),i()}}),u&&On.createPortal(a.jsxs("div",{style:{position:"fixed",left:R,top:I,background:s.panelBg,border:`1px solid ${s.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:s.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:b},children:[a.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Length:"})," ",T.toLocaleString()," bp"]}),k.map((B,D)=>a.jsxs("div",{children:[a.jsxs("span",{style:{color:s.textSecondary},children:[B.label,":"]})," ",B.value]},D)),a.jsx("div",{style:{fontSize:9,color:s.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function _y(e,t,n){const r=[];if(!t)return r;if(n==="reads"&&t.reads){const o=t.reads.filter(i=>i.end>e.start&&i.start<e.end);r.push({label:"Reads in region",value:o.length.toLocaleString()});let l=0;for(const i of o)if(i.cigar){const s=i.cigar.match(/(\d+)I/g);if(s)for(const u of s)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((s,u)=>s+(u.mapq||0),0)/o.length;r.push({label:"Avg MAPQ",value:i.toFixed(1)})}}if((n==="coverage"||n==="reads")&&t.bins){const o=t.bins.filter(l=>l.end>e.start&&l.start<e.end);if(o.length>0){const l=o.map(c=>c.value),i=l.reduce((c,g)=>c+g,0)/l.length,s=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:s.toFixed(1)}),u!==s&&r.push({label:"Min coverage",value:u.toFixed(1)})}}if(n==="variants"&&t.variants){const o=t.variants.filter(l=>l.pos>=e.start&&l.pos<e.end);r.push({label:"Variants in region",value:o.length.toLocaleString()})}if((n==="annotations"||n==="genome_annotations")&&t.features){const o=t.features.filter(l=>l.end>e.start&&l.start<e.end);r.push({label:"Features in region",value:o.length.toLocaleString()})}return r}class Ly extends j.Component{constructor(t){super(t),this.state={hasError:!1,error:null}}static getDerivedStateFromError(t){return{hasError:!0,error:t}}render(){var t;return this.state.hasError?a.jsxs("div",{style:{padding:8,color:"#ef9a9a",fontSize:11},children:["Track error: ",((t=this.state.error)==null?void 0:t.message)||"Unknown error"]}):this.props.children}}function By({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:s,onDrop:u,onDragEnd:c}){const{theme:g}=De(),{updateTrack:d,removeTrack:y}=Vt(),E=j.useRef(null),v=j.useRef(null),[x,f]=j.useState(!1),[h,p]=j.useState(!1),[m,w]=j.useState(null),k=j.useRef(null),T=j.useRef(null),b=e.track_type==="annotations"||e.track_type==="genome_annotations";mp(E);const R=["#78909c","#66bb6a","#42a5f5","#ffa726","#f06292","#ab47bc","#26c6da","#ef5350","#8d6e63","#fff176","#ff8a65","#80cbc4","#9575cd","#aed581","#4dd0e1","#e57373","#ffb74d","#81c784","#64b5f6","#ce93d8"],I=t-n,B={row:{display:"flex",borderBottom:`1px solid ${g.border}`,minHeight:40},label:{width:n,minWidth:n,background:g.panelBg,borderRight:`1px solid ${g.border}`,display:"flex",flexDirection:"column",justifyContent:"center",padding:"4px 8px",overflow:"hidden",position:"relative"},trackName:{fontSize:11,color:g.trackName,fontWeight:600,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},trackType:{fontSize:10,color:g.textTertiary,marginTop:2},trackArea:{flex:1,overflow:"hidden",position:"relative"}},D=j.useCallback(P=>{P.preventDefault(),P.stopPropagation();const U=P.clientY,$=e.height;function O(C){const S=Math.max(30,Math.min(500,$+(C.clientY-U)));d(e.id,{height:S})}function L(){window.removeEventListener("mousemove",O),window.removeEventListener("mouseup",L),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",O),window.addEventListener("mouseup",L)},[e.id,e.height,d]);function W(){const P={track:e,width:I,height:e.height,onWarning:w};switch(e.track_type){case"reads":return a.jsx(xy,{...P});case"coverage":return a.jsx(cy,{...P});case"variants":return a.jsx(Ey,{...P});case"annotations":case"genome_annotations":return a.jsx(Cy,{...P});default:return a.jsx("div",{style:{padding:8,color:g.textTertiary,fontSize:11},children:"Unknown track type"})}}return a.jsxs("div",{style:{...B.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:P=>{P.preventDefault(),P.dataTransfer.dropEffect="move",s==null||s()},onDrop:P=>{P.preventDefault(),u==null||u()},onDragEnd:c,children:[a.jsxs("div",{style:B.label,children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsx("div",{draggable:!0,onDragStart:P=>{P.dataTransfer.effectAllowed="move",P.dataTransfer.setData("text/plain",e.id),i==null||i()},style:{cursor:"grab",color:g.textMuted,fontSize:14,lineHeight:1,userSelect:"none",flexShrink:0,padding:"0 2px"},title:"Drag to reorder tracks",children:"≡"}),a.jsx("div",{ref:k,children:b?a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:"#888",cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)",backgroundImage:"linear-gradient(135deg, #ef5350 25%, #66bb6a 25%, #66bb6a 50%, #42a5f5 50%, #42a5f5 75%, #ffa726 75%)"},title:"Click to customize annotation colors",onMouseDown:P=>{P.stopPropagation(),p(U=>!U)}}),h&&On.createPortal(a.jsx(Ny,{track:e,theme:g,anchorRef:k,onClose:()=>p(!1),onChange:(P,U)=>{const $={...e.annotationColors||{},[P]:U};d(e.id,{annotationColors:$})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:e.color,cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)"},title:"Click to pick color, double-click for full palette",onMouseDown:P=>{P.stopPropagation(),f(!0)},onDoubleClick:P=>{var U;P.stopPropagation(),f(!1),(U=T.current)==null||U.click()}}),a.jsx("input",{ref:T,type:"color",value:e.color||"#78909c",onChange:P=>d(e.id,{color:P.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),x&&On.createPortal(a.jsx("div",{style:{position:"fixed",left:k.current?k.current.getBoundingClientRect().left:0,top:k.current?k.current.getBoundingClientRect().bottom+4:0,zIndex:10001,background:g.panelBg,border:`1px solid ${g.borderAccent}`,borderRadius:4,padding:6,boxShadow:"0 4px 12px rgba(0,0,0,0.5)",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},onMouseLeave:()=>f(!1),children:R.map(P=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:P,cursor:"pointer",border:P===e.color?`2px solid ${g.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:P}),f(!1)}},P))}),document.body)]})}),a.jsx("div",{style:{...B.trackName,flex:1},title:e.name,children:e.name}),a.jsx("span",{title:"Remove track",onClick:P=>{P.stopPropagation(),y(e.id)},style:{color:"#e53935",fontSize:13,fontWeight:700,cursor:"pointer",lineHeight:1,flexShrink:0,padding:"0 2px",opacity:.7,transition:"opacity 0.15s"},onMouseEnter:P=>P.currentTarget.style.opacity="1",onMouseLeave:P=>P.currentTarget.style.opacity="0.7",children:"×"})]}),a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsxs("div",{style:B.trackType,children:[e.file_format," · ",e.track_type]}),m&&a.jsx(Ry,{message:m,theme:g})]}),r&&a.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]}),a.jsxs("div",{style:B.trackArea,ref:E,children:[a.jsx(Ly,{children:W()}),a.jsx(Py,{width:I,height:e.height,trackData:fp(e.id),trackType:e.track_type})]}),a.jsx("div",{ref:v,onMouseDown:D,title:"Drag to resize track height",style:{position:"absolute",left:0,right:0,bottom:-2,height:5,cursor:"ns-resize",zIndex:10,background:"transparent"},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]})}const My=[{key:"cds",label:"CDS"},{key:"exon",label:"Exon"},{key:"gene",label:"Gene"},{key:"transcript",label:"Transcript"},{key:"utr",label:"UTR"},{key:"rrna",label:"rRNA"},{key:"trna",label:"tRNA"},{key:"repeat",label:"Repeat"},{key:"default",label:"Other"}],Ay=["#66bb6a","#42a5f5","#7e57c2","#ab47bc","#26c6da","#ffa726","#ef5350","#8d6e63","#80cbc4","#78909c","#4caf50","#2196f3","#9c27b0","#e91e63","#00bcd4","#ff9800","#f44336","#795548","#009688","#607d8b","#aed581","#64b5f6","#ce93d8","#f06292","#4dd0e1"],$y={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Ny({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var d;const[i,s]=j.useState(null),u=e.annotationColors||{},c=(d=n.current)==null?void 0:d.getBoundingClientRect();function g(y){return u[y]||t[$y[y]]||k0[y]}return a.jsxs("div",{style:{position:"fixed",left:c?Math.min(c.left,window.innerWidth-220):0,top:c?c.bottom+4:0,zIndex:10001,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:6,padding:"8px 0",boxShadow:"0 6px 20px rgba(0,0,0,0.5)",width:210,maxHeight:340,overflowY:"auto"},onMouseLeave:r,children:[a.jsx("div",{style:{fontSize:10,fontWeight:700,color:t.textSecondary,textTransform:"uppercase",letterSpacing:1,padding:"0 10px 6px",borderBottom:`1px solid ${t.border}`,marginBottom:4},children:"Annotation Colors"}),My.map(({key:y,label:E})=>{const v=g(y);return a.jsxs("div",{children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:x=>x.currentTarget.style.background=t.selectedRow,onMouseLeave:x=>x.currentTarget.style.background="transparent",onClick:()=>s(i===y?null:y),children:[a.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:v,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0}}),a.jsx("span",{style:{flex:1},children:E}),a.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===y?"▲":"▼"})]}),i===y&&a.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Ay.map(x=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:x,cursor:"pointer",border:x===v?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(y,x),s(null)}},x))})]},y)}),a.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:a.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:y=>{y.currentTarget.style.color=t.textPrimary},onMouseLeave:y=>{y.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})})]})}function zy({labelWidth:e}){const{genome:t,region:n}=Ze(),{tracks:r}=Vt(),{theme:o,themeName:l,customTheme:i}=De(),[s,u]=j.useState(!1),[c,g]=j.useState(!1),d=!!t;j.useEffect(()=>{if(!d)return;function x(f){f.preventDefault(),f.returnValue=""}return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)},[d]),j.useEffect(()=>{if(!d)return;function x(f){(f.ctrlKey||f.metaKey)&&f.key==="w"&&(f.preventDefault(),u(!0))}return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[d]);const y=j.useCallback(()=>u(!1),[]),E=j.useCallback(()=>{window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[]),v=j.useCallback(()=>{g(!0);try{const x=Ma(t,n,r,l,i,e);Aa(x),hp(x)}catch{}g(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return s?a.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center"},onClick:y,children:a.jsxs("div",{style:{background:o.panelBg,border:`1px solid ${o.borderAccent}`,borderRadius:8,padding:"24px 28px",maxWidth:400,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.6)"},onClick:x=>x.stopPropagation(),children:[a.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),a.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",a.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),a.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[a.jsx("button",{onClick:y,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Return to App"}),a.jsx("button",{onClick:v,disabled:c,style:{background:o.btnBg,border:`1px solid ${o.borderStrong}`,borderRadius:4,color:o.btnText,padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:c?"Saving...":"Save Session & Exit"}),a.jsx("button",{onClick:E,style:{background:"transparent",border:`1px solid ${o.border}`,borderRadius:4,color:"#e57373",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Exit Without Saving"})]})]})}):null}const Cc="2.0.2";let Oy=0;function Tc({size:e=32}){const[t]=Ns.useState(()=>`blogo${++Oy}`);return a.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[a.jsxs("defs",{children:[a.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[a.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),a.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),a.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),a.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[a.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),a.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),a.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),a.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function Fy({theme:e,labelWidth:t}){return a.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[a.jsx("div",{"data-tour":"skeleton-track-label",style:{width:t,minWidth:t,background:e.panelBg,borderRight:`1px solid ${e.border}`,padding:"6px 8px",display:"flex",flexDirection:"column",justifyContent:"center",gap:4},children:a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[a.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),a.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),a.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),a.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),a.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function Iy(){const{theme:e}=De(),{genome:t,region:n,setGenome:r,navigateTo:o}=Ze(),{tracks:l,reorderTracks:i,addTrack:s,uploadTrack:u,commitTrack:c,discardTrack:g,addGenomeAnnotationTrack:d,restoreAnnotationTracks:y}=Vt(),E=j.useRef(null),[v,x]=j.useState(800),[f,h]=j.useState(!1),[p,m]=j.useState(!1),[w,k]=j.useState(!1),[T,b]=j.useState(!1),[R,I]=j.useState(!1),[B,D]=j.useState(!1),[W,P]=j.useState(140),[U,$]=j.useState(null),[O,L]=j.useState(null),[C,S]=j.useState(!1),[N,z]=j.useState(null),[A,Y]=j.useState(null),[V,Q]=j.useState(null),ne=j.useRef(0);ny(W),j.useEffect(()=>{const M=()=>fetch("/api/heartbeat").catch(()=>{});M();const K=setInterval(M,1e4);return()=>clearInterval(K)},[]);const fe=j.useRef(n==null?void 0:n.chrom);j.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==fe.current&&(fe.current=n.chrom,y())},[n==null?void 0:n.chrom,y]);const Re=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),Te=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),et=new Set([".bai"]);function ue(M){if(!M)return"";if(M.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const K=M.lastIndexOf(".");return K>=0?M.slice(K).toLowerCase():""}const se=j.useCallback(M=>{var K,q;M.preventDefault(),M.stopPropagation(),(q=(K=M.dataTransfer)==null?void 0:K.types)!=null&&q.includes("Files")&&(ne.current++,ne.current===1&&S(!0))},[]),ye=j.useCallback(M=>{var K,q;M.preventDefault(),M.stopPropagation(),(q=(K=M.dataTransfer)==null?void 0:K.types)!=null&&q.includes("Files")&&(ne.current--,ne.current<=0&&(ne.current=0,S(!1)))},[]),At=j.useCallback(M=>{M.preventDefault(),M.stopPropagation()},[]);function Gt(M){const K=M==null?void 0:M.compatibility;return K&&K.status!=="ok"&&K.status!=="no_genome"}const yt=j.useCallback(async M=>{var Le,tt,$a,Na,za;if(M.preventDefault(),M.stopPropagation(),ne.current=0,S(!1),!((tt=(Le=M.dataTransfer)==null?void 0:Le.types)!=null&&tt.includes("Files")))return;const K=Array.from(M.dataTransfer.files);if(!K.length)return;const q=[],X=[],re=[],le=[];for(const ve of K){const be=ue(ve.name),at=ve.name.toLowerCase();Re.has(be)?q.push(ve):Te.has(be)||be===".vcf.gz"?X.push(ve):et.has(be)||at.endsWith(".bam.bai")?re.push(ve):le.push(ve)}const $e=X.filter(ve=>ve.name.toLowerCase().endsWith(".bam")&&ve.size>50*1024*1024),xe=re.filter(ve=>ve.size>10*1024*1024);if($e.length||xe.length){const ve=[...$e,...xe].map(at=>at.name).join(", "),be=[...$e,...xe].reduce((at,So)=>at+So.size,0)/(1024*1024);z({error:`${ve} (${be.toFixed(0)} MB) — large files load faster via the Path button. Click 📂 Path in the toolbar and paste the file path instead of uploading.`}),setTimeout(()=>z(null),1e4);return}if(le.length&&!q.length&&!X.length&&!re.length){z({error:`Unsupported file${le.length>1?"s":""}: ${le.map(ve=>ve.name).join(", ")}`}),setTimeout(()=>z(null),4e3);return}try{if(q.length>0&&!t){z({msg:`Loading genome: ${q[0].name}...`});const be=(await dn.load(q[0])).data;if(be.name&&(be.name=Lt(be.name)),r(be),(($a=be.chromosomes)==null?void 0:$a.length)>0){const at=be.chromosomes[0];o(at.name,0,Math.min(at.length,5e4))}be.is_annotated&&d({id:"genome_annotations",name:`${be.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:be.annotated_chromosomes||null})}else q.length>0&&t&&Y({files:q});if(X.length>0){if(!t&&q.length===0){z({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>z(null),4e3);return}z({msg:`Loading ${X.length} track${X.length>1?"s":""}...`});const ve=[],be=[],at=[];for(const So of X)try{const xn=await u(So,void 0);Gt(xn)?be.push(xn):(c(xn),ve.push(xn))}catch(xn){at.push(`${So.name}: ${((za=(Na=xn.response)==null?void 0:Na.data)==null?void 0:za.detail)||xn.message}`)}if(at.length){z({error:at.join("; ")}),setTimeout(()=>z(null),5e3);return}be.length>0&&Q({tracks:be})}le.length?(z({error:`Skipped unsupported: ${le.map(ve=>ve.name).join(", ")}`}),setTimeout(()=>z(null),4e3)):(z({msg:"Files loaded"}),setTimeout(()=>z(null),2e3))}catch(ve){z({error:ve.message||"Drop failed"}),setTimeout(()=>z(null),5e3)}},[t,r,o,s,d]),ql=j.useCallback(async()=>{var K,q;if(!A)return;const M=A.files;Y(null);try{const X=[];for(const re of M){z({msg:`Adding chromosomes from ${re.name}...`});try{const $e=(await dn.addChromosomes(re)).data;$e.name&&($e.name=Lt($e.name)),r($e),$e.is_annotated&&d({id:"genome_annotations",name:`${$e.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:$e.annotated_chromosomes||null})}catch(le){X.push(`${re.name}: ${((q=(K=le.response)==null?void 0:K.data)==null?void 0:q.detail)||le.message}`)}}X.length?(z({error:X.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added chromosomes from ${M.length} file${M.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(X){z({error:X.message||"Failed to add chromosomes"}),setTimeout(()=>z(null),5e3)}},[A,r,d]),Xl=j.useCallback(async()=>{var K,q;if(!A)return;const M=A.files;Y(null);try{z({msg:`Loading ${M.length} track${M.length>1?"s":""}...`});const X=[];for(const re of M)try{await s(re,void 0)}catch(le){X.push(`${re.name}: ${((q=(K=le.response)==null?void 0:K.data)==null?void 0:q.detail)||le.message}`)}X.length?(z({error:X.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added ${M.length} track${M.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(X){z({error:X.message||"Failed to load tracks"}),setTimeout(()=>z(null),5e3)}},[A,s]),Yl=j.useCallback(async()=>{if(V){for(const M of V.tracks)await g(M.id);Q(null)}},[V,g]),yn=j.useCallback(()=>{if(V){for(const M of V.tracks)c(M);Q(null),z({msg:`Added ${V.tracks.length} track${V.tracks.length>1?"s":""}`}),setTimeout(()=>z(null),3e3)}},[V,c]),H=j.useCallback(M=>{M.preventDefault();const K=M.clientX,q=W;function X(le){P(Math.max(60,Math.min(400,q+(le.clientX-K))))}function re(){window.removeEventListener("mousemove",X),window.removeEventListener("mouseup",re),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ew-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",X),window.addEventListener("mouseup",re)},[W]);j.useEffect(()=>{if(!E.current)return;const M=new ResizeObserver(K=>{for(const q of K)x(q.contentRect.width)});return M.observe(E.current),()=>M.disconnect()},[]);const J=j.useCallback(M=>M.visible?!M.targetChromosomes||!(n!=null&&n.chrom)?!0:M.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),Z={app:{display:"flex",flexDirection:"column",height:"100vh",background:e.appBg,color:e.textPrimary},header:{background:e.headerBg,borderBottom:`2px solid ${e.borderAccent}`,padding:"8px 16px",display:"flex",alignItems:"center",justifyContent:"space-between"},headerLeft:{display:"flex",alignItems:"center",gap:12},title:{fontSize:18,fontWeight:700,color:e.textPrimary,letterSpacing:1},subtitle:{fontSize:11,color:e.textTertiary},headerBtns:{display:"flex",gap:8},btn:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600,display:"flex",alignItems:"center",gap:6},trackArea:{flex:1,overflowY:"auto",overflowX:"hidden",display:"flex",flexDirection:"column"},emptyState:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",flex:1,color:e.textMuted,gap:12},emptyTitle:{fontSize:22,fontWeight:300},emptyHint:{fontSize:13}};return a.jsxs("div",{style:Z.app,onDragEnter:se,onDragLeave:ye,onDragOver:At,onDrop:yt,children:[a.jsxs("div",{style:Z.header,children:[a.jsxs("div",{style:Z.headerLeft,children:[a.jsx(Tc,{size:34}),a.jsxs("div",{children:[a.jsx("div",{style:Z.title,children:"BiNgo Genome Viewer"}),t&&a.jsxs("div",{style:Z.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),a.jsx("button",{onClick:()=>I(!0),title:"About",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:"50%",width:20,height:20,display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",color:e.textSecondary,fontSize:12,fontWeight:700,lineHeight:1,padding:0,flexShrink:0},onMouseEnter:M=>{M.currentTarget.style.color=e.textPrimary,M.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:M=>{M.currentTarget.style.color=e.textSecondary,M.currentTarget.style.borderColor=e.border},children:"?"}),a.jsxs("button",{onClick:()=>D(!0),title:"Guided Tour",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:M=>{M.currentTarget.style.color=e.textPrimary,M.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:M=>{M.currentTarget.style.color=e.textSecondary,M.currentTarget.style.borderColor=e.border},children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[a.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),a.jsx("path",{d:"M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zM8 13.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"})]}),"Help"]})]}),a.jsxs("div",{style:Z.headerBtns,"data-tour":"header-btns",children:[a.jsxs("button",{style:Z.btn,onClick:()=>b(!0),title:"Save or restore a session",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.3",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:[a.jsx("path",{d:"M2 2h8v8H2z"}),a.jsx("path",{d:"M4 2v4h4V2"}),a.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),a.jsxs("button",{style:Z.btn,onClick:()=>m(!0),title:"Customize color theme",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[a.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),a.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),a.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),a.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),a.jsxs("button",{"data-tour":"btn-export",style:{...Z.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&k(!0)},title:"Export current view as SVG or PNG",children:[a.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:a.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),a.jsxs("button",{"data-tour":"btn-settings",style:{...Z.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&h(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),a.jsx(_0,{}),a.jsx(sy,{}),a.jsxs("div",{style:Z.trackArea,ref:E,"data-tour":"track-area",children:[l.filter(J).length===0&&a.jsx(Fy,{theme:e,labelWidth:W}),t?n?a.jsxs(a.Fragment,{children:[a.jsxs("div",{style:{display:"flex"},children:[a.jsx("div",{style:{width:W,minWidth:W,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:a.jsx("div",{onMouseDown:H,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:M=>M.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:M=>M.currentTarget.style.background="transparent"})}),a.jsx(ay,{width:v-W})]}),l.filter(J).map(M=>a.jsx(By,{track:M,containerWidth:v,labelWidth:W,onLabelResizeStart:H,isDragging:U===M.id,isDropTarget:O===M.id,onDragStart:()=>$(M.id),onDragOver:()=>L(M.id),onDrop:()=>{U&&U!==M.id&&i(U,M.id),$(null),L(null)},onDragEnd:()=>{$(null),L(null)}},M.id)),l.length===0&&a.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):a.jsx("div",{style:Z.emptyState,children:a.jsx("div",{style:Z.emptyHint,children:"Select a chromosome to begin"})}):a.jsxs("div",{style:Z.emptyState,children:[a.jsx("div",{style:Z.emptyTitle,children:"No genome loaded"}),a.jsx("div",{style:Z.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),f&&a.jsx(L0,{onClose:()=>h(!1)}),p&&a.jsx(A0,{onClose:()=>m(!1)}),w&&a.jsx(W0,{onClose:()=>k(!1)}),T&&a.jsx(ry,{onClose:()=>b(!1),labelWidth:W,setLabelWidth:P}),B&&a.jsx(iy,{onClose:()=>{D(!1),h(!1),m(!1)},theme:e,onAction:M=>{M==="open-settings"?(h(!0),m(!1)):M==="open-theme"?(m(!0),h(!1)):(h(!1),m(!1))}}),R&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>I(!1),children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.border}`,borderRadius:8,padding:"28px 36px",maxWidth:520,maxHeight:"85vh",overflowY:"auto",color:e.textPrimary,lineHeight:1.7},onClick:M=>M.stopPropagation(),children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[a.jsx(Tc,{size:44}),a.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",Cc]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,background:e.canvasBg,border:`1px solid ${e.border}`,borderRadius:4,padding:"10px 14px",fontFamily:"monospace",lineHeight:1.6,marginBottom:20,userSelect:"all"},children:["Ngo, B.M. (2026). BiNgo Genome Viewer (v",Cc,") [Software]."]}),a.jsxs("details",{style:{marginBottom:20},children:[a.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),a.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),a.jsxs("div",{children:[a.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",a.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),a.jsxs("div",{children:[a.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",a.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",a.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",a.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),a.jsxs("div",{children:[a.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",a.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),a.jsx("div",{children:"Early version testing and feedback:"}),a.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),a.jsx("div",{style:{textAlign:"right"},children:a.jsx("button",{onClick:()=>I(!1),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 18px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Close"})})]})}),A&&(()=>{const M=A.files.length>1,K=A.files.map(q=>q.name).join(", ");return a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:440,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:q=>q.stopPropagation(),children:[a.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",M?"s":""," detected"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[a.jsx("strong",{style:{color:e.textPrimary},children:K}),M?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",a.jsx("br",{}),"How would you like to handle ",M?"them":"it","?"]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:()=>Y(null),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsxs("button",{onClick:Xl,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Track",M?"s":""]}),a.jsxs("button",{onClick:ql,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",M?"s":""]})]})]})})})(),V&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:480,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:M=>M.stopPropagation(),children:[a.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[V.tracks.map(M=>{var K;return a.jsxs("div",{style:{marginBottom:6},children:[a.jsx("strong",{style:{color:e.textPrimary},children:M.name})," — ",((K=M.compatibility)==null?void 0:K.message)||"Possible mismatch with loaded genome"]},M.id)}),a.jsx("div",{style:{marginTop:8},children:V.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:Yl,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsx("button",{onClick:yn,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),C&&a.jsx("div",{style:{position:"fixed",inset:0,zIndex:9998,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:a.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[a.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),a.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),N&&a.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:N.error?"#c62828":e.panelBg,border:`1px solid ${N.error?"#e53935":e.borderAccent}`,color:N.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:N.error||N.msg}),t&&a.jsx(zy,{labelWidth:W})]})}function Dy(){return a.jsx(E0,{children:a.jsx(Wm,{children:a.jsx(b0,{children:a.jsx(Iy,{})})})})}Mi.createRoot(document.getElementById("root")).render(a.jsx(Ns.StrictMode,{children:a.jsx(Dy,{})}));
|
|
97
|
+
`):null)}},[s,u,c,t,n,l,e.color,e.scaleMax,e.scaleMin,e.logScale,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Bi(e,t,n,r,o){if(!(t.length<2)){if(e.beginPath(),e.moveTo(t[0],n[0]),o){for(let l=0;l<t.length-1;l++){const i=(t[l]+t[l+1])/2,s=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,s)}e.lineTo(t[t.length-1],n[n.length-1])}else for(let l=0;l<t.length;l++)e.lineTo(t[l],n[l]);e.strokeStyle=r,e.lineWidth=1.5,e.stroke()}}function Lr(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=e.measureText(t),s=2,u=i.width+s*2,c=12;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,u,c),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+s,r+1),e.textBaseline="alphabetic"}function dy(e,t){const n=e.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);if(!n)return e;const r=o=>Math.max(0,Math.min(255,o+t));return`rgb(${r(parseInt(n[1],16))},${r(parseInt(n[2],16))},${r(parseInt(n[3],16))})`}const vc=6,fy=8,py=14,hy=2,my="#9c27b0",gy={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},yy="#ffeb3b";function xy({track:e,width:t,height:n,onWarning:r}){const o=j.useRef(null),{region:l}=Ze(),{theme:i}=De(),{data:s,loading:u}=Kl(e,l,t),[c,g]=j.useState(null),d=j.useRef(null),y=e.showNucleotides!==!1,E=e.useArrows!==!1;return j.useEffect(()=>{if(!l||!y){g(null);return}const v=l.end-l.start;if(t/v<vc||v>2e3){g(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const f=Math.max(0,l.start-500),h=l.end+500,p=`${l.chrom}:${f}-${h}`;d.current!==p&&(d.current=p,dn.sequence(l.chrom,f,h).then(m=>{g({chrom:l.chrom,start:f,end:h,sequence:m.data.sequence})}).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,y]),j.useEffect(()=>{var I;const v=o.current;if(!v)return;const x=window.devicePixelRatio||1;v.width=t*x,v.height=n*x;const f=v.getContext("2d");if(f.scale(x,x),f.clearRect(0,0,t,n),f.fillStyle=i.canvasBg,f.fillRect(0,0,t,n),u&&!s){f.fillStyle=i.textTertiary,f.font="11px Arial, Helvetica, sans-serif",f.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!s){r&&r(null);return}const h=l.start,p=l.end-l.start;if(s.bins){const B=s.max_value||1,D=e.scaleMax!=null?e.scaleMax:B,W=e.color||"#78909c",P=e.barAutoWidth!==!1,U=e.barWidth||2,$=t/p;if(e.showBars!==!1){f.fillStyle=W;for(const O of s.bins){const L=(O.end-O.start)/p*t,C=P?$>=1?Math.max(1,Math.min($,L)):Math.max(1,L):Math.min(U,L),S=(O.start-h)/p*t,z=Math.min(1,O.value/D)*(n-14);f.fillRect(S,n-z-2,C,z)}}if(e.showOutline&&s.bins.length>0){const O=e.outlineSmooth||0,L=s.bins.map(A=>Math.min(1,A.value/D)),C=vy(L,O),S=s.bins.map(A=>((A.start+A.end)/2-h)/p*t),N=C.map(A=>n-A*(n-14)-2),z=e.outlineColor||i.textPrimary||"#fff";if(f.beginPath(),f.moveTo(S[0],N[0]),O>0){for(let A=0;A<S.length-1;A++)f.quadraticCurveTo(S[A],N[A],(S[A]+S[A+1])/2,(N[A]+N[A+1])/2);f.lineTo(S[S.length-1],N[N.length-1])}else for(let A=0;A<S.length;A++)f.lineTo(S[A],N[A]);f.strokeStyle=z,f.lineWidth=1.5,f.stroke()}wc(f,D.toFixed(1),2,2,i),wc(f,"0",2,n-12,i,!0),f.fillStyle="#ffb74d",f.font="10px Arial, Helvetica, sans-serif",f.textAlign="right",f.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&B>e.scaleMax?`Bars clipped: max value ${B.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((I=s.reads)!=null&&I.length)){f.fillStyle=i.textTertiary,f.font="11px Arial, Helvetica, sans-serif",f.fillText("No reads in region",8,n/2+4),r&&r(null);return}const m=B=>(B-h)/p*t,w=t/p,k=y&&w>=vc&&c!=null,T=k?py:fy,b=hy;let R=0;for(const B of s.reads){const D=B.row*(T+b)+2;if(D+T>n){R++;continue}const W=B.strand==="+"?"#90a4ae":"#f06292",P=B.segments;if(P&&P.length>0){const U=m(B.start),$=m(B.end);f.strokeStyle=W,f.lineWidth=1,f.beginPath(),f.moveTo(U,D+T/2),f.lineTo($,D+T/2),f.stroke();let O=0;for(const L of P)if(L.type==="M"){const C=m(L.start),S=Math.max(1,m(L.end)-C);if(f.fillStyle=W,f.fillRect(C,D,S,T),k&&B.sequence){const N=L.end-L.start;for(let z=0;z<N;z++){const A=L.start+z,Y=m(A),V=m(A+1)-Y,ne=(B.sequence[O+z]||"").toUpperCase();let fe="";c&&A>=c.start&&A<c.end&&(fe=(c.sequence[A-c.start]||"").toUpperCase());const Re=fe&&ne&&ne!==fe&&ne!=="N";Re&&(f.fillStyle=yy,f.fillRect(Y,D,V,T)),V>=6&&(f.fillStyle=Re?"#000":gy[ne]||"#999",f.font=`bold ${Math.min(11,V-1)}px monospace`,f.textAlign="center",f.textBaseline="middle",f.fillText(ne,Y+V/2,D+T/2))}O+=N}}else if(L.type==="D"){const C=m(L.start),S=m(L.end)-C;S>=1&&(f.strokeStyle=W,f.lineWidth=1,f.beginPath(),f.moveTo(C,D+T/2),f.lineTo(C+S,D+T/2),f.stroke())}else if(L.type==="N"){const C=m(L.start),S=m(L.end)-C;S>=2&&(f.setLineDash([2,2]),f.strokeStyle=W,f.lineWidth=1,f.beginPath(),f.moveTo(C,D+T/2),f.lineTo(C+S,D+T/2),f.stroke(),f.setLineDash([]))}else if(L.type==="I"){const C=m(L.pos);f.fillStyle=my,f.fillRect(C-1,D-1,2,T+2),k&&(O+=L.length)}else L.type==="S"&&k&&(O+=L.length)}else{const U=m(B.start),$=Math.max(2,m(B.end)-U);f.fillStyle=W,f.fillRect(U,D,$,T)}if(E){const U=m(B.start),$=Math.max(2,m(B.end)-U),O=Math.min(k?6:4,$/2);O>=2&&(f.fillStyle=i.canvasBg,B.strand==="+"?(f.beginPath(),f.moveTo(U+$,D+T/2),f.lineTo(U+$-O,D),f.lineTo(U+$-O,D+T),f.fill()):(f.beginPath(),f.moveTo(U,D+T/2),f.lineTo(U+O,D),f.lineTo(U+O,D+T),f.fill()))}if(!k&&!y){const U=m(B.start);Math.max(2,m(B.end)-U)>60&&(f.fillStyle=i.canvasBg,f.font="8px Arial, Helvetica, sans-serif",f.textAlign="left",f.fillText(B.name.slice(0,20),U+2,D+T-1))}}r&&r(R>0?`${R} read${R>1?"s":""} hidden — increase track height to show all`:null)},[s,u,t,n,l,c,e.color,e.scaleMax,e.scaleMin,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,e.showNucleotides,e.useArrows,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function vy(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),s=Math.min(e.length-1,r+t);for(let u=i;u<=s;u++)o+=e[u],l++;n[r]=o/l}return n}function wc(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,s=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,s,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const wy=16,Sy=22,ky=4,gp=8,Sc=6,by={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Cy({track:e,width:t,height:n,onWarning:r}){var I,B,D,W;const o=j.useRef(null),{region:l,navigateTo:i}=Ze(),{tracks:s}=Vt(),{theme:u}=De(),{data:c,loading:g,error:d}=Kl(e,l,t),y=e.useArrows!==!1,E=e.showNucleotides!==!1,v=j.useRef([]),[x,f]=j.useState(null),[h,p]=j.useState(null),m=j.useRef(null);j.useEffect(()=>{if(!l||!E){p(null);return}const P=l.end-l.start;if(t/P<Sc||P>2e3){p(null);return}if(h&&h.chrom===l.chrom&&h.start<=l.start&&h.end>=l.end)return;const $=Math.max(0,l.start-500),O=l.end+500,L=`${l.chrom}:${$}-${O}`;m.current!==L&&(m.current=L,dn.sequence(l.chrom,$,O).then(C=>p({chrom:l.chrom,start:$,end:O,sequence:C.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,E]),j.useEffect(()=>{var Y,V;const P=o.current;if(!P)return;const U=window.devicePixelRatio||1;P.width=t*U,P.height=n*U;const $=P.getContext("2d");if($.scale(U,U),$.clearRect(0,0,t,n),$.fillStyle=u.canvasBg,$.fillRect(0,0,t,n),v.current=[],g&&!((Y=c==null?void 0:c.features)!=null&&Y.length)){$.fillStyle=u.textTertiary,$.font="11px Arial, Helvetica, sans-serif",$.fillText("Loading…",8,n/2+4),r&&r(null);return}if(d){$.fillStyle="#ef9a9a",$.font="11px Arial, Helvetica, sans-serif",$.fillText(typeof d=="string"?d:JSON.stringify(d),8,n/2+4),r&&r(null);return}if(!((V=c==null?void 0:c.features)!=null&&V.length)){c&&($.fillStyle=u.textTertiary,$.font="11px Arial, Helvetica, sans-serif",$.fillText("No features in region",8,n/2+4)),r&&r(null);return}const O=l.end-l.start,L=t/O,C=E&&L>=Sc&&h!=null,S=C?Sy:wy,N=[],z=[];let A=0;for(const Q of c.features){let ne=N.findIndex(ue=>Q.start>=ue);ne===-1&&(ne=N.length),N[ne]=Q.end;const fe=(Q.start-l.start)/O*t,Re=Math.max(2,(Q.end-Q.start)/O*t),Te=ne*(S+ky)+2;if(Te+S>n){A++;continue}const et=bc(Q.feature_type,e,u);if(Q.sub_features&&Q.sub_features.length>0){$.fillStyle=et+"66",$.fillRect(fe,Te+S/2-1,Re,2);for(const ue of Q.sub_features){const se=(ue.start-l.start)/O*t,ye=Math.max(1,(ue.end-ue.start)/O*t),At=bc(ue.feature_type,e,u),Gt=ue.feature_type==="CDS"?S:S-6,yt=ue.feature_type==="CDS"?Te:Te+3;y?kc($,At,se,yt,ye,Gt,ue.strand||Q.strand):($.fillStyle=At,$.fillRect(se,yt,ye,Gt))}}else y?kc($,et,fe,Te,Re,S,Q.strand):($.fillStyle=et,$.fillRect(fe,Te,Re,S));if(C){const ue=Math.max(Q.start,l.start),se=Math.min(Q.end,l.end);for(let ye=ue;ye<se;ye++)if(h&&ye>=h.start&&ye<h.end){const At=(h.sequence[ye-h.start]||"").toUpperCase(),Gt=(ye-l.start)/O*t,yt=L;yt>=6&&($.fillStyle=by[At]||"#999",$.font=`bold ${Math.min(10,yt-1)}px monospace`,$.textAlign="center",$.textBaseline="middle",$.fillText(At,Gt+yt/2,Te+S/2))}}else if(Re>20){$.fillStyle="#fff",$.font="10px Arial, Helvetica, sans-serif",$.textAlign="left",$.textBaseline="alphabetic";const ue=Q.name||Q.feature_type,se=Math.floor((Re-(y?gp:0)-4)/6);se>0&&$.fillText(ue.slice(0,se),fe+3,Te+S-4)}z.push({feat:Q,x:fe,y:Te,w:Re,h:S})}v.current=z,r&&r(A>0?`${A} feature${A>1?"s":""} hidden — increase track height to show all`:null)},[c,g,d,t,n,l,h,e.color,e.annotationColors,y,e.showNucleotides,u]);const w=j.useCallback(P=>{const U=o.current;if(!U)return;const $=U.getBoundingClientRect(),O=(P.clientX-$.left)*(t/$.width),L=(P.clientY-$.top)*(n/$.height);for(const C of v.current)if(O>=C.x&&O<=C.x+C.w&&L>=C.y&&L<=C.y+C.h){const S=Math.min(P.clientX+14,window.innerWidth-300),N=Math.min(P.clientY+14,window.innerHeight-260);f({feat:C.feat,x:Math.max(4,S),y:Math.max(4,N)});return}f(null)},[t,n]),k=j.useCallback(()=>f(null),[]),T=j.useCallback(P=>{const U=o.current;if(!U||!l)return;const $=U.getBoundingClientRect(),O=(P.clientX-$.left)*(t/$.width),L=(P.clientY-$.top)*(n/$.height);for(const C of v.current)if(O>=C.x&&O<=C.x+C.w&&L>=C.y&&L<=C.y+C.h){const S=C.feat,z=(S.end-S.start)*.15/(1-.3),A=S.start-z,Y=S.end+z;i(l.chrom,A,Y),f(null);return}},[t,n,l,i]),b=x?Ty(x.feat,s,l==null?void 0:l.chrom):[],R=x?On.createPortal(a.jsxs("div",{style:{position:"fixed",left:x.x,top:x.y,background:u.tooltipBg,border:`1px solid ${u.tooltipBorder}`,borderRadius:4,padding:"6px 10px",color:u.textPrimary,fontSize:11,lineHeight:1.5,maxWidth:280,zIndex:1e4,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:[a.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:x.feat.name||x.feat.feature_type}),a.jsx(Kt,{label:"Type",value:x.feat.feature_type}),a.jsx(Kt,{label:"Strand",value:x.feat.strand||"."}),a.jsx(Kt,{label:"Location",value:`${x.feat.start.toLocaleString()}–${x.feat.end.toLocaleString()}`}),a.jsx(Kt,{label:"Length",value:`${(x.feat.end-x.feat.start).toLocaleString()} bp`}),((I=x.feat.attributes)==null?void 0:I.gene)&&x.feat.attributes.gene!==x.feat.name&&a.jsx(Kt,{label:"Gene",value:x.feat.attributes.gene}),((B=x.feat.attributes)==null?void 0:B.locus_tag)&&a.jsx(Kt,{label:"Locus",value:x.feat.attributes.locus_tag}),((D=x.feat.attributes)==null?void 0:D.product)&&a.jsx(Kt,{label:"Product",value:x.feat.attributes.product}),((W=x.feat.attributes)==null?void 0:W.note)&&a.jsx(Kt,{label:"Note",value:String(x.feat.attributes.note).slice(0,120)}),b.length>0&&a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:a.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),b.map(P=>a.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[a.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:P.name}),a.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:P.total.toFixed(1)})]},P.trackId))]})]}),document.body):null;return a.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:k,onDoubleClick:T}),R]})}function Kt({label:e,value:t}){return t?a.jsxs("div",{style:{display:"flex",gap:6},children:[a.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),a.jsx("span",{children:t})]}):null}function Ty(e,t,n){var o;if(!e||!n)return[];const r=[];for(const l of t){if(l.track_type!=="coverage"&&l.track_type!=="reads")continue;const i=I0(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let s=0;for(const u of i.bins){if(u.end<=e.start||u.start>=e.end)continue;const c=u.forward!=null?u.forward:Math.max(0,u.value||0),g=u.reverse!=null?Math.abs(u.reverse):Math.abs(Math.min(0,u.value||0));s+=c+g}s>0&&r.push({trackId:l.id,name:l.name,total:s})}return r}function kc(e,t,n,r,o,l,i){e.fillStyle=t;const s=Math.min(gp,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-s,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-s,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+s,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+s,r+l),e.lineTo(n,r+l/2),e.closePath()):e.rect(n,r,o,l),e.fill(),e.strokeStyle="rgba(0,0,0,0.25)",e.lineWidth=.5,e.stroke()}function bc(e,t,n){const r=t.annotationColors;switch(e==null?void 0:e.toLowerCase()){case"cds":return(r==null?void 0:r.cds)||(n==null?void 0:n.geneCds)||"#66bb6a";case"exon":return(r==null?void 0:r.exon)||(n==null?void 0:n.geneExon)||"#42a5f5";case"gene":return(r==null?void 0:r.gene)||(n==null?void 0:n.geneGene)||"#7e57c2";case"mrna":case"transcript":return(r==null?void 0:r.transcript)||(n==null?void 0:n.geneTranscript)||"#ab47bc";case"utr":case"3utr":case"5utr":return(r==null?void 0:r.utr)||(n==null?void 0:n.geneUtr)||"#26c6da";case"rrna":return(r==null?void 0:r.rrna)||(n==null?void 0:n.geneRrna)||"#ffa726";case"trna":return(r==null?void 0:r.trna)||(n==null?void 0:n.geneTrna)||"#ef5350";case"repeat_region":return(r==null?void 0:r.repeat)||(n==null?void 0:n.geneRepeat)||"#8d6e63";default:return(r==null?void 0:r.default)||t.color||(n==null?void 0:n.geneDefault)||"#80cbc4"}}function Ey({track:e,width:t,height:n,onWarning:r}){const o=j.useRef(null),{region:l}=Ze(),{theme:i}=De(),{data:s,loading:u}=Kl(e,l,t);return j.useEffect(()=>{var h,p;const c=o.current;if(!c)return;const g=window.devicePixelRatio||1;c.width=t*g,c.height=n*g;const d=c.getContext("2d");if(d.scale(g,g),d.clearRect(0,0,t,n),d.fillStyle=i.canvasBg,d.fillRect(0,0,t,n),u&&!((h=s==null?void 0:s.variants)!=null&&h.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((p=s==null?void 0:s.variants)!=null&&p.length)){s&&(d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("No variants in region",8,n/2+4)),r&&r(null);return}const y=l.end-l.start,E=e.barAutoWidth!==!1,v=e.barWidth||2,x=E?1:Math.max(.5,v),f=E?5:Math.max(2,v*2);for(const m of s.variants){const w=(m.pos-l.start)/y*t,k=jy(m.ref,m.alt);d.strokeStyle=k,d.lineWidth=x,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=k,d.beginPath(),d.arc(w,10,f,0,Math.PI*2),d.fill(),y<5e3&&(d.fillStyle=i.textPrimary,d.font="9px Arial, Helvetica, sans-serif",d.textAlign="center",d.fillText(`${m.ref}>${m.alt[0]||"?"}`,w,n-6))}if(r){const m=s.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[s,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function jy(e,t){const n=t[0]||"";return e.length===1&&n.length===1?"#ffb74d":n.length>e.length?"#81c784":n.length<e.length?"#e57373":"#b0bec5"}function Ry({message:e,theme:t}){const[n,r]=j.useState(!1),o=j.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return a.jsxs(a.Fragment,{children:[a.jsx("span",{ref:o,onMouseEnter:()=>r(!0),onMouseLeave:()=>r(!1),style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:12,height:12,borderRadius:"50%",background:"rgba(229, 57, 53, 0.85)",color:"#fff",fontSize:9,fontWeight:800,lineHeight:1,cursor:"default",flexShrink:0,fontFamily:"Arial, Helvetica, sans-serif"},children:"!"}),n&&l&&On.createPortal(a.jsx("div",{style:{position:"fixed",left:Math.min(l.right+6,window.innerWidth-220),top:l.top-4,background:t.tooltipBg||"#333",border:`1px solid ${t.tooltipBorder||"#555"}`,borderRadius:4,padding:"4px 8px",color:t.textPrimary||"#e0e0e0",fontSize:11,lineHeight:1.4,maxWidth:200,zIndex:10001,pointerEvents:"none",boxShadow:"0 3px 10px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",fontFamily:"Arial, Helvetica, sans-serif"},children:e}),document.body)]})}function Py({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=Ze(),{theme:s}=De(),[u,c]=j.useState(!1),[g,d]=j.useState({x:0,y:0}),y=j.useRef(null),E=j.useCallback(B=>{d({x:B.clientX,y:B.clientY}),c(!0)},[]),v=j.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const x=o.end-o.start;if(x<=0)return null;const f=(l.start-o.start)/x,h=(l.end-o.start)/x,p=Math.max(0,f*e),w=Math.min(e,h*e)-p;if(w<1)return null;const k=_y(l,n,r),T=l.end-l.start,b=260,R=Math.min(g.x+14,window.innerWidth-b-10),I=Math.min(g.y+14,window.innerHeight-200);return a.jsxs("div",{ref:y,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[a.jsx("div",{style:{position:"absolute",left:p,top:0,width:w,height:"100%",background:"rgba(100, 181, 246, 0.2)",borderLeft:"1px solid rgba(100, 181, 246, 0.6)",borderRight:"1px solid rgba(100, 181, 246, 0.6)",pointerEvents:"auto",cursor:"crosshair"},onMouseMove:E,onMouseLeave:v,onClick:B=>{B.stopPropagation(),i()}}),u&&On.createPortal(a.jsxs("div",{style:{position:"fixed",left:R,top:I,background:s.panelBg,border:`1px solid ${s.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:s.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:b},children:[a.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Length:"})," ",T.toLocaleString()," bp"]}),k.map((B,D)=>a.jsxs("div",{children:[a.jsxs("span",{style:{color:s.textSecondary},children:[B.label,":"]})," ",B.value]},D)),a.jsx("div",{style:{fontSize:9,color:s.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function _y(e,t,n){const r=[];if(!t)return r;if(n==="reads"&&t.reads){const o=t.reads.filter(i=>i.end>e.start&&i.start<e.end);r.push({label:"Reads in region",value:o.length.toLocaleString()});let l=0;for(const i of o)if(i.cigar){const s=i.cigar.match(/(\d+)I/g);if(s)for(const u of s)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((s,u)=>s+(u.mapq||0),0)/o.length;r.push({label:"Avg MAPQ",value:i.toFixed(1)})}}if((n==="coverage"||n==="reads")&&t.bins){const o=t.bins.filter(l=>l.end>e.start&&l.start<e.end);if(o.length>0){const l=o.map(c=>c.value),i=l.reduce((c,g)=>c+g,0)/l.length,s=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:s.toFixed(1)}),u!==s&&r.push({label:"Min coverage",value:u.toFixed(1)})}}if(n==="variants"&&t.variants){const o=t.variants.filter(l=>l.pos>=e.start&&l.pos<e.end);r.push({label:"Variants in region",value:o.length.toLocaleString()})}if((n==="annotations"||n==="genome_annotations")&&t.features){const o=t.features.filter(l=>l.end>e.start&&l.start<e.end);r.push({label:"Features in region",value:o.length.toLocaleString()})}return r}class Ly extends j.Component{constructor(t){super(t),this.state={hasError:!1,error:null}}static getDerivedStateFromError(t){return{hasError:!0,error:t}}render(){var t;return this.state.hasError?a.jsxs("div",{style:{padding:8,color:"#ef9a9a",fontSize:11},children:["Track error: ",((t=this.state.error)==null?void 0:t.message)||"Unknown error"]}):this.props.children}}function By({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:s,onDrop:u,onDragEnd:c}){const{theme:g}=De(),{updateTrack:d,removeTrack:y}=Vt(),E=j.useRef(null),v=j.useRef(null),[x,f]=j.useState(!1),[h,p]=j.useState(!1),[m,w]=j.useState(null),k=j.useRef(null),T=j.useRef(null),b=e.track_type==="annotations"||e.track_type==="genome_annotations";mp(E);const R=["#78909c","#66bb6a","#42a5f5","#ffa726","#f06292","#ab47bc","#26c6da","#ef5350","#8d6e63","#fff176","#ff8a65","#80cbc4","#9575cd","#aed581","#4dd0e1","#e57373","#ffb74d","#81c784","#64b5f6","#ce93d8"],I=t-n,B={row:{display:"flex",borderBottom:`1px solid ${g.border}`,minHeight:40},label:{width:n,minWidth:n,background:g.panelBg,borderRight:`1px solid ${g.border}`,display:"flex",flexDirection:"column",justifyContent:"center",padding:"4px 8px",overflow:"hidden",position:"relative"},trackName:{fontSize:11,color:g.trackName,fontWeight:600,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},trackType:{fontSize:10,color:g.textTertiary,marginTop:2},trackArea:{flex:1,overflow:"hidden",position:"relative"}},D=j.useCallback(P=>{P.preventDefault(),P.stopPropagation();const U=P.clientY,$=e.height;function O(C){const S=Math.max(30,Math.min(500,$+(C.clientY-U)));d(e.id,{height:S})}function L(){window.removeEventListener("mousemove",O),window.removeEventListener("mouseup",L),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",O),window.addEventListener("mouseup",L)},[e.id,e.height,d]);function W(){const P={track:e,width:I,height:e.height,onWarning:w};switch(e.track_type){case"reads":return a.jsx(xy,{...P});case"coverage":return a.jsx(cy,{...P});case"variants":return a.jsx(Ey,{...P});case"annotations":case"genome_annotations":return a.jsx(Cy,{...P});default:return a.jsx("div",{style:{padding:8,color:g.textTertiary,fontSize:11},children:"Unknown track type"})}}return a.jsxs("div",{style:{...B.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:P=>{P.preventDefault(),P.dataTransfer.dropEffect="move",s==null||s()},onDrop:P=>{P.preventDefault(),u==null||u()},onDragEnd:c,children:[a.jsxs("div",{style:B.label,children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsx("div",{draggable:!0,onDragStart:P=>{P.dataTransfer.effectAllowed="move",P.dataTransfer.setData("text/plain",e.id),i==null||i()},style:{cursor:"grab",color:g.textMuted,fontSize:14,lineHeight:1,userSelect:"none",flexShrink:0,padding:"0 2px"},title:"Drag to reorder tracks",children:"≡"}),a.jsx("div",{ref:k,children:b?a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:"#888",cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)",backgroundImage:"linear-gradient(135deg, #ef5350 25%, #66bb6a 25%, #66bb6a 50%, #42a5f5 50%, #42a5f5 75%, #ffa726 75%)"},title:"Click to customize annotation colors",onMouseDown:P=>{P.stopPropagation(),p(U=>!U)}}),h&&On.createPortal(a.jsx(Ny,{track:e,theme:g,anchorRef:k,onClose:()=>p(!1),onChange:(P,U)=>{const $={...e.annotationColors||{},[P]:U};d(e.id,{annotationColors:$})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:e.color,cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)"},title:"Click to pick color, double-click for full palette",onMouseDown:P=>{P.stopPropagation(),f(!0)},onDoubleClick:P=>{var U;P.stopPropagation(),f(!1),(U=T.current)==null||U.click()}}),a.jsx("input",{ref:T,type:"color",value:e.color||"#78909c",onChange:P=>d(e.id,{color:P.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),x&&On.createPortal(a.jsx("div",{style:{position:"fixed",left:k.current?k.current.getBoundingClientRect().left:0,top:k.current?k.current.getBoundingClientRect().bottom+4:0,zIndex:10001,background:g.panelBg,border:`1px solid ${g.borderAccent}`,borderRadius:4,padding:6,boxShadow:"0 4px 12px rgba(0,0,0,0.5)",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},onMouseLeave:()=>f(!1),children:R.map(P=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:P,cursor:"pointer",border:P===e.color?`2px solid ${g.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:P}),f(!1)}},P))}),document.body)]})}),a.jsx("div",{style:{...B.trackName,flex:1},title:e.name,children:e.name}),a.jsx("span",{title:"Remove track",onClick:P=>{P.stopPropagation(),y(e.id)},style:{color:"#e53935",fontSize:13,fontWeight:700,cursor:"pointer",lineHeight:1,flexShrink:0,padding:"0 2px",opacity:.7,transition:"opacity 0.15s"},onMouseEnter:P=>P.currentTarget.style.opacity="1",onMouseLeave:P=>P.currentTarget.style.opacity="0.7",children:"×"})]}),a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsxs("div",{style:B.trackType,children:[e.file_format," · ",e.track_type]}),m&&a.jsx(Ry,{message:m,theme:g})]}),r&&a.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]}),a.jsxs("div",{style:B.trackArea,ref:E,children:[a.jsx(Ly,{children:W()}),a.jsx(Py,{width:I,height:e.height,trackData:fp(e.id),trackType:e.track_type})]}),a.jsx("div",{ref:v,onMouseDown:D,title:"Drag to resize track height",style:{position:"absolute",left:0,right:0,bottom:-2,height:5,cursor:"ns-resize",zIndex:10,background:"transparent"},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]})}const My=[{key:"cds",label:"CDS"},{key:"exon",label:"Exon"},{key:"gene",label:"Gene"},{key:"transcript",label:"Transcript"},{key:"utr",label:"UTR"},{key:"rrna",label:"rRNA"},{key:"trna",label:"tRNA"},{key:"repeat",label:"Repeat"},{key:"default",label:"Other"}],Ay=["#66bb6a","#42a5f5","#7e57c2","#ab47bc","#26c6da","#ffa726","#ef5350","#8d6e63","#80cbc4","#78909c","#4caf50","#2196f3","#9c27b0","#e91e63","#00bcd4","#ff9800","#f44336","#795548","#009688","#607d8b","#aed581","#64b5f6","#ce93d8","#f06292","#4dd0e1"],$y={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Ny({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var d;const[i,s]=j.useState(null),u=e.annotationColors||{},c=(d=n.current)==null?void 0:d.getBoundingClientRect();function g(y){return u[y]||t[$y[y]]||k0[y]}return a.jsxs("div",{style:{position:"fixed",left:c?Math.min(c.left,window.innerWidth-220):0,top:c?c.bottom+4:0,zIndex:10001,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:6,padding:"8px 0",boxShadow:"0 6px 20px rgba(0,0,0,0.5)",width:210,maxHeight:340,overflowY:"auto"},onMouseLeave:r,children:[a.jsx("div",{style:{fontSize:10,fontWeight:700,color:t.textSecondary,textTransform:"uppercase",letterSpacing:1,padding:"0 10px 6px",borderBottom:`1px solid ${t.border}`,marginBottom:4},children:"Annotation Colors"}),My.map(({key:y,label:E})=>{const v=g(y);return a.jsxs("div",{children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:x=>x.currentTarget.style.background=t.selectedRow,onMouseLeave:x=>x.currentTarget.style.background="transparent",onClick:()=>s(i===y?null:y),children:[a.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:v,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0}}),a.jsx("span",{style:{flex:1},children:E}),a.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===y?"▲":"▼"})]}),i===y&&a.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Ay.map(x=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:x,cursor:"pointer",border:x===v?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(y,x),s(null)}},x))})]},y)}),a.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:a.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:y=>{y.currentTarget.style.color=t.textPrimary},onMouseLeave:y=>{y.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})})]})}function zy({labelWidth:e}){const{genome:t,region:n}=Ze(),{tracks:r}=Vt(),{theme:o,themeName:l,customTheme:i}=De(),[s,u]=j.useState(!1),[c,g]=j.useState(!1),d=!!t;j.useEffect(()=>{if(!d)return;function x(f){f.preventDefault(),f.returnValue=""}return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)},[d]),j.useEffect(()=>{if(!d)return;function x(f){(f.ctrlKey||f.metaKey)&&f.key==="w"&&(f.preventDefault(),u(!0))}return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[d]);const y=j.useCallback(()=>u(!1),[]),E=j.useCallback(()=>{window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[]),v=j.useCallback(()=>{g(!0);try{const x=Ma(t,n,r,l,i,e);Aa(x),hp(x)}catch{}g(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return s?a.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center"},onClick:y,children:a.jsxs("div",{style:{background:o.panelBg,border:`1px solid ${o.borderAccent}`,borderRadius:8,padding:"24px 28px",maxWidth:400,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.6)"},onClick:x=>x.stopPropagation(),children:[a.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),a.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",a.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),a.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[a.jsx("button",{onClick:y,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Return to App"}),a.jsx("button",{onClick:v,disabled:c,style:{background:o.btnBg,border:`1px solid ${o.borderStrong}`,borderRadius:4,color:o.btnText,padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:c?"Saving...":"Save Session & Exit"}),a.jsx("button",{onClick:E,style:{background:"transparent",border:`1px solid ${o.border}`,borderRadius:4,color:"#e57373",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Exit Without Saving"})]})]})}):null}const Cc="2.0.3";let Oy=0;function Tc({size:e=32}){const[t]=Ns.useState(()=>`blogo${++Oy}`);return a.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[a.jsxs("defs",{children:[a.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[a.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),a.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),a.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),a.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[a.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),a.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),a.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),a.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function Fy({theme:e,labelWidth:t}){return a.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[a.jsx("div",{"data-tour":"skeleton-track-label",style:{width:t,minWidth:t,background:e.panelBg,borderRight:`1px solid ${e.border}`,padding:"6px 8px",display:"flex",flexDirection:"column",justifyContent:"center",gap:4},children:a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[a.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),a.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),a.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),a.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),a.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function Iy(){const{theme:e}=De(),{genome:t,region:n,setGenome:r,navigateTo:o}=Ze(),{tracks:l,reorderTracks:i,addTrack:s,uploadTrack:u,commitTrack:c,discardTrack:g,addGenomeAnnotationTrack:d,restoreAnnotationTracks:y}=Vt(),E=j.useRef(null),[v,x]=j.useState(800),[f,h]=j.useState(!1),[p,m]=j.useState(!1),[w,k]=j.useState(!1),[T,b]=j.useState(!1),[R,I]=j.useState(!1),[B,D]=j.useState(!1),[W,P]=j.useState(140),[U,$]=j.useState(null),[O,L]=j.useState(null),[C,S]=j.useState(!1),[N,z]=j.useState(null),[A,Y]=j.useState(null),[V,Q]=j.useState(null),ne=j.useRef(0);ny(W),j.useEffect(()=>{const M=()=>fetch("/api/heartbeat").catch(()=>{});M();const K=setInterval(M,1e4);return()=>clearInterval(K)},[]);const fe=j.useRef(n==null?void 0:n.chrom);j.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==fe.current&&(fe.current=n.chrom,y())},[n==null?void 0:n.chrom,y]);const Re=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),Te=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),et=new Set([".bai"]);function ue(M){if(!M)return"";if(M.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const K=M.lastIndexOf(".");return K>=0?M.slice(K).toLowerCase():""}const se=j.useCallback(M=>{var K,q;M.preventDefault(),M.stopPropagation(),(q=(K=M.dataTransfer)==null?void 0:K.types)!=null&&q.includes("Files")&&(ne.current++,ne.current===1&&S(!0))},[]),ye=j.useCallback(M=>{var K,q;M.preventDefault(),M.stopPropagation(),(q=(K=M.dataTransfer)==null?void 0:K.types)!=null&&q.includes("Files")&&(ne.current--,ne.current<=0&&(ne.current=0,S(!1)))},[]),At=j.useCallback(M=>{M.preventDefault(),M.stopPropagation()},[]);function Gt(M){const K=M==null?void 0:M.compatibility;return K&&K.status!=="ok"&&K.status!=="no_genome"}const yt=j.useCallback(async M=>{var Le,tt,$a,Na,za;if(M.preventDefault(),M.stopPropagation(),ne.current=0,S(!1),!((tt=(Le=M.dataTransfer)==null?void 0:Le.types)!=null&&tt.includes("Files")))return;const K=Array.from(M.dataTransfer.files);if(!K.length)return;const q=[],X=[],re=[],le=[];for(const ve of K){const be=ue(ve.name),at=ve.name.toLowerCase();Re.has(be)?q.push(ve):Te.has(be)||be===".vcf.gz"?X.push(ve):et.has(be)||at.endsWith(".bam.bai")?re.push(ve):le.push(ve)}const $e=X.filter(ve=>ve.name.toLowerCase().endsWith(".bam")&&ve.size>50*1024*1024),xe=re.filter(ve=>ve.size>10*1024*1024);if($e.length||xe.length){const ve=[...$e,...xe].map(at=>at.name).join(", "),be=[...$e,...xe].reduce((at,So)=>at+So.size,0)/(1024*1024);z({error:`${ve} (${be.toFixed(0)} MB) — large files load faster via the Path button. Click 📂 Path in the toolbar and paste the file path instead of uploading.`}),setTimeout(()=>z(null),1e4);return}if(le.length&&!q.length&&!X.length&&!re.length){z({error:`Unsupported file${le.length>1?"s":""}: ${le.map(ve=>ve.name).join(", ")}`}),setTimeout(()=>z(null),4e3);return}try{if(q.length>0&&!t){z({msg:`Loading genome: ${q[0].name}...`});const be=(await dn.load(q[0])).data;if(be.name&&(be.name=Lt(be.name)),r(be),(($a=be.chromosomes)==null?void 0:$a.length)>0){const at=be.chromosomes[0];o(at.name,0,Math.min(at.length,5e4))}be.is_annotated&&d({id:"genome_annotations",name:`${be.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:be.annotated_chromosomes||null})}else q.length>0&&t&&Y({files:q});if(X.length>0){if(!t&&q.length===0){z({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>z(null),4e3);return}z({msg:`Loading ${X.length} track${X.length>1?"s":""}...`});const ve=[],be=[],at=[];for(const So of X)try{const xn=await u(So,void 0);Gt(xn)?be.push(xn):(c(xn),ve.push(xn))}catch(xn){at.push(`${So.name}: ${((za=(Na=xn.response)==null?void 0:Na.data)==null?void 0:za.detail)||xn.message}`)}if(at.length){z({error:at.join("; ")}),setTimeout(()=>z(null),5e3);return}be.length>0&&Q({tracks:be})}le.length?(z({error:`Skipped unsupported: ${le.map(ve=>ve.name).join(", ")}`}),setTimeout(()=>z(null),4e3)):(z({msg:"Files loaded"}),setTimeout(()=>z(null),2e3))}catch(ve){z({error:ve.message||"Drop failed"}),setTimeout(()=>z(null),5e3)}},[t,r,o,s,d]),ql=j.useCallback(async()=>{var K,q;if(!A)return;const M=A.files;Y(null);try{const X=[];for(const re of M){z({msg:`Adding chromosomes from ${re.name}...`});try{const $e=(await dn.addChromosomes(re)).data;$e.name&&($e.name=Lt($e.name)),r($e),$e.is_annotated&&d({id:"genome_annotations",name:`${$e.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:$e.annotated_chromosomes||null})}catch(le){X.push(`${re.name}: ${((q=(K=le.response)==null?void 0:K.data)==null?void 0:q.detail)||le.message}`)}}X.length?(z({error:X.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added chromosomes from ${M.length} file${M.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(X){z({error:X.message||"Failed to add chromosomes"}),setTimeout(()=>z(null),5e3)}},[A,r,d]),Xl=j.useCallback(async()=>{var K,q;if(!A)return;const M=A.files;Y(null);try{z({msg:`Loading ${M.length} track${M.length>1?"s":""}...`});const X=[];for(const re of M)try{await s(re,void 0)}catch(le){X.push(`${re.name}: ${((q=(K=le.response)==null?void 0:K.data)==null?void 0:q.detail)||le.message}`)}X.length?(z({error:X.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added ${M.length} track${M.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(X){z({error:X.message||"Failed to load tracks"}),setTimeout(()=>z(null),5e3)}},[A,s]),Yl=j.useCallback(async()=>{if(V){for(const M of V.tracks)await g(M.id);Q(null)}},[V,g]),yn=j.useCallback(()=>{if(V){for(const M of V.tracks)c(M);Q(null),z({msg:`Added ${V.tracks.length} track${V.tracks.length>1?"s":""}`}),setTimeout(()=>z(null),3e3)}},[V,c]),H=j.useCallback(M=>{M.preventDefault();const K=M.clientX,q=W;function X(le){P(Math.max(60,Math.min(400,q+(le.clientX-K))))}function re(){window.removeEventListener("mousemove",X),window.removeEventListener("mouseup",re),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ew-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",X),window.addEventListener("mouseup",re)},[W]);j.useEffect(()=>{if(!E.current)return;const M=new ResizeObserver(K=>{for(const q of K)x(q.contentRect.width)});return M.observe(E.current),()=>M.disconnect()},[]);const J=j.useCallback(M=>M.visible?!M.targetChromosomes||!(n!=null&&n.chrom)?!0:M.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),Z={app:{display:"flex",flexDirection:"column",height:"100vh",background:e.appBg,color:e.textPrimary},header:{background:e.headerBg,borderBottom:`2px solid ${e.borderAccent}`,padding:"8px 16px",display:"flex",alignItems:"center",justifyContent:"space-between"},headerLeft:{display:"flex",alignItems:"center",gap:12},title:{fontSize:18,fontWeight:700,color:e.textPrimary,letterSpacing:1},subtitle:{fontSize:11,color:e.textTertiary},headerBtns:{display:"flex",gap:8},btn:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600,display:"flex",alignItems:"center",gap:6},trackArea:{flex:1,overflowY:"auto",overflowX:"hidden",display:"flex",flexDirection:"column"},emptyState:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",flex:1,color:e.textMuted,gap:12},emptyTitle:{fontSize:22,fontWeight:300},emptyHint:{fontSize:13}};return a.jsxs("div",{style:Z.app,onDragEnter:se,onDragLeave:ye,onDragOver:At,onDrop:yt,children:[a.jsxs("div",{style:Z.header,children:[a.jsxs("div",{style:Z.headerLeft,children:[a.jsx(Tc,{size:34}),a.jsxs("div",{children:[a.jsx("div",{style:Z.title,children:"BiNgo Genome Viewer"}),t&&a.jsxs("div",{style:Z.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),a.jsx("button",{onClick:()=>I(!0),title:"About",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:"50%",width:20,height:20,display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",color:e.textSecondary,fontSize:12,fontWeight:700,lineHeight:1,padding:0,flexShrink:0},onMouseEnter:M=>{M.currentTarget.style.color=e.textPrimary,M.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:M=>{M.currentTarget.style.color=e.textSecondary,M.currentTarget.style.borderColor=e.border},children:"?"}),a.jsxs("button",{onClick:()=>D(!0),title:"Guided Tour",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:M=>{M.currentTarget.style.color=e.textPrimary,M.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:M=>{M.currentTarget.style.color=e.textSecondary,M.currentTarget.style.borderColor=e.border},children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[a.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),a.jsx("path",{d:"M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zM8 13.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"})]}),"Help"]})]}),a.jsxs("div",{style:Z.headerBtns,"data-tour":"header-btns",children:[a.jsxs("button",{style:Z.btn,onClick:()=>b(!0),title:"Save or restore a session",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.3",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:[a.jsx("path",{d:"M2 2h8v8H2z"}),a.jsx("path",{d:"M4 2v4h4V2"}),a.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),a.jsxs("button",{style:Z.btn,onClick:()=>m(!0),title:"Customize color theme",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[a.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),a.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),a.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),a.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),a.jsxs("button",{"data-tour":"btn-export",style:{...Z.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&k(!0)},title:"Export current view as SVG or PNG",children:[a.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:a.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),a.jsxs("button",{"data-tour":"btn-settings",style:{...Z.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&h(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),a.jsx(_0,{}),a.jsx(sy,{}),a.jsxs("div",{style:Z.trackArea,ref:E,"data-tour":"track-area",children:[l.filter(J).length===0&&a.jsx(Fy,{theme:e,labelWidth:W}),t?n?a.jsxs(a.Fragment,{children:[a.jsxs("div",{style:{display:"flex"},children:[a.jsx("div",{style:{width:W,minWidth:W,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:a.jsx("div",{onMouseDown:H,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:M=>M.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:M=>M.currentTarget.style.background="transparent"})}),a.jsx(ay,{width:v-W})]}),l.filter(J).map(M=>a.jsx(By,{track:M,containerWidth:v,labelWidth:W,onLabelResizeStart:H,isDragging:U===M.id,isDropTarget:O===M.id,onDragStart:()=>$(M.id),onDragOver:()=>L(M.id),onDrop:()=>{U&&U!==M.id&&i(U,M.id),$(null),L(null)},onDragEnd:()=>{$(null),L(null)}},M.id)),l.length===0&&a.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):a.jsx("div",{style:Z.emptyState,children:a.jsx("div",{style:Z.emptyHint,children:"Select a chromosome to begin"})}):a.jsxs("div",{style:Z.emptyState,children:[a.jsx("div",{style:Z.emptyTitle,children:"No genome loaded"}),a.jsx("div",{style:Z.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),f&&a.jsx(L0,{onClose:()=>h(!1)}),p&&a.jsx(A0,{onClose:()=>m(!1)}),w&&a.jsx(W0,{onClose:()=>k(!1)}),T&&a.jsx(ry,{onClose:()=>b(!1),labelWidth:W,setLabelWidth:P}),B&&a.jsx(iy,{onClose:()=>{D(!1),h(!1),m(!1)},theme:e,onAction:M=>{M==="open-settings"?(h(!0),m(!1)):M==="open-theme"?(m(!0),h(!1)):(h(!1),m(!1))}}),R&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>I(!1),children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.border}`,borderRadius:8,padding:"28px 36px",maxWidth:520,maxHeight:"85vh",overflowY:"auto",color:e.textPrimary,lineHeight:1.7},onClick:M=>M.stopPropagation(),children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[a.jsx(Tc,{size:44}),a.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",Cc]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,background:e.canvasBg,border:`1px solid ${e.border}`,borderRadius:4,padding:"10px 14px",fontFamily:"monospace",lineHeight:1.6,marginBottom:20,userSelect:"all"},children:["Ngo, B.M. (2026). BiNgo Genome Viewer (v",Cc,") [Software]."]}),a.jsxs("details",{style:{marginBottom:20},children:[a.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),a.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),a.jsxs("div",{children:[a.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",a.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),a.jsxs("div",{children:[a.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",a.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",a.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",a.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),a.jsxs("div",{children:[a.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",a.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),a.jsx("div",{children:"Early version testing and feedback:"}),a.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),a.jsx("div",{style:{textAlign:"right"},children:a.jsx("button",{onClick:()=>I(!1),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 18px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Close"})})]})}),A&&(()=>{const M=A.files.length>1,K=A.files.map(q=>q.name).join(", ");return a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:440,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:q=>q.stopPropagation(),children:[a.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",M?"s":""," detected"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[a.jsx("strong",{style:{color:e.textPrimary},children:K}),M?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",a.jsx("br",{}),"How would you like to handle ",M?"them":"it","?"]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:()=>Y(null),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsxs("button",{onClick:Xl,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Track",M?"s":""]}),a.jsxs("button",{onClick:ql,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",M?"s":""]})]})]})})})(),V&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:480,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:M=>M.stopPropagation(),children:[a.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[V.tracks.map(M=>{var K;return a.jsxs("div",{style:{marginBottom:6},children:[a.jsx("strong",{style:{color:e.textPrimary},children:M.name})," — ",((K=M.compatibility)==null?void 0:K.message)||"Possible mismatch with loaded genome"]},M.id)}),a.jsx("div",{style:{marginTop:8},children:V.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:Yl,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsx("button",{onClick:yn,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),C&&a.jsx("div",{style:{position:"fixed",inset:0,zIndex:9998,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:a.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[a.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),a.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),N&&a.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:N.error?"#c62828":e.panelBg,border:`1px solid ${N.error?"#e53935":e.borderAccent}`,color:N.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:N.error||N.msg}),t&&a.jsx(zy,{labelWidth:W})]})}function Dy(){return a.jsx(E0,{children:a.jsx(Wm,{children:a.jsx(b0,{children:a.jsx(Iy,{})})})})}Mi.createRoot(document.getElementById("root")).render(a.jsx(Ns.StrictMode,{children:a.jsx(Dy,{})}));
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
body { font-family: Arial, Helvetica, sans-serif; background: #1a1a1a; color: #e0e0e0; height: 100vh; overflow: hidden; }
|
|
11
11
|
#root { height: 100vh; display: flex; flex-direction: column; }
|
|
12
12
|
</style>
|
|
13
|
-
<script type="module" crossorigin src="/assets/index-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-CzAKulXL.js"></script>
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="root"></div>
|
|
@@ -24,7 +24,7 @@ from api.genome import router as genome_router
|
|
|
24
24
|
from api.tracks import router as tracks_router
|
|
25
25
|
from api.data import router as data_router
|
|
26
26
|
|
|
27
|
-
app = FastAPI(title="BiNgo Genome Viewer API", version="2.0.
|
|
27
|
+
app = FastAPI(title="BiNgo Genome Viewer API", version="2.0.3")
|
|
28
28
|
|
|
29
29
|
app.add_middleware(
|
|
30
30
|
CORSMiddleware,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|