2026-03-05 00:04:26 -06:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
2026-05-08 15:36:24 -05:00
< script src = "/assets/nav-prelude.js" ></ script >
< link rel = "modulepreload" href = "/assets/nav.js" />
2026-03-05 00:04:26 -06:00
< title > File Browser - Overlord</ title >
2026-04-18 21:16:29 -05:00
< link rel = "stylesheet" href = "/vendor/inter/400.css" />
< link rel = "stylesheet" href = "/vendor/inter/600.css" />
< link rel = "stylesheet" href = "/vendor/inter/700.css" />
2026-07-14 00:25:36 -05:00
< link rel = "stylesheet" href = "/assets/tailwind.css" />
2026-04-18 21:16:29 -05:00
< link rel = "stylesheet" href = "/vendor/fontawesome/css/all.min.css" />
< link rel = "stylesheet" href = "/vendor/highlight.js/atom-one-dark.min.css" />
2026-03-05 00:04:26 -06:00
< link rel = "stylesheet" href = "/assets/main.css" />
2026-04-01 13:49:41 -05:00
< link rel = "stylesheet" href = "/assets/custom.css" />
2026-04-18 21:16:29 -05:00
< script src = "/vendor/highlight.js/highlight.bundle.js" ></ script >
< script defer src = "/vendor/msgpackr/msgpackr.js" ></ script >
2026-03-05 15:25:52 -06:00
< link rel = "icon" type = "image/x-icon" href = "/assets/favicon.ico" />
2026-03-05 00:04:26 -06:00
< style >
. file-item : hover {
2026-07-14 00:25:36 -05:00
background-color : rgba ( 30 , 41 , 59 , 0.62 );
2026-03-05 00:04:26 -06:00
}
. file-item {
position : relative ;
2026-08-01 02:11:52 -05:00
transition :
background-color var ( -- motion - fast ) ease ,
box-shadow var ( -- motion - fast ) ease ,
border-color var ( -- motion - fast ) ease ;
2026-03-05 00:04:26 -06:00
}
. file-item . selected {
2026-07-14 00:25:36 -05:00
background-color : rgba ( 14 , 165 , 233 , 0.12 );
box-shadow : inset 3 px 0 0 rgb ( 56 189 248 );
2026-03-05 00:04:26 -06:00
}
. file-checkbox {
appearance : none ;
-webkit- appearance : none ;
position : absolute ;
2026-07-14 00:25:36 -05:00
left : 0.75 rem ;
top : 50 % ;
width : 16 px ;
height : 16 px ;
border : 1 px solid rgb ( 71 85 105 );
border-radius : 0.25 rem ;
2026-03-05 00:04:26 -06:00
background-color : rgba ( 100 , 116 , 139 , 0.3 );
2026-07-14 00:25:36 -05:00
transform : translateY ( -50 % );
2026-03-05 00:04:26 -06:00
cursor : pointer ;
transition : all 0.2 s ease ;
z-index : 1 ;
}
. file-checkbox : hover {
background-color : rgba ( 100 , 116 , 139 , 0.5 );
}
. file-checkbox : checked {
background-color : #3b82f6 ;
2026-07-14 00:25:36 -05:00
border-color : #60a5fa ;
box-shadow : inset 0 0 0 3 px #0f172a ;
2026-03-05 00:04:26 -06:00
}
. file-checkbox : checked : hover {
background-color : #2563eb ;
}
. context-menu {
2026-08-01 02:11:52 -05:00
display : block ;
2026-03-05 00:04:26 -06:00
position : fixed ;
z-index : 1000 ;
background-color : #1e293b ;
border : 1 px solid #334155 ;
border-radius : 0.5 rem ;
padding : 0.5 rem 0 ;
box-shadow : 0 10 px 15 px -3 px rgb ( 0 0 0 / 0.3 );
2026-08-01 02:11:52 -05:00
opacity : 0 ;
visibility : hidden ;
pointer-events : none ;
transform : translateY ( 4 px ) scale ( 0.96 );
transform-origin : top left ;
transition :
opacity var ( -- motion - fast ) ease ,
transform var ( -- motion - fast ) var ( -- motion - ease-out ),
visibility 0 s linear var ( -- motion - fast );
2026-03-05 00:04:26 -06:00
}
. context-menu . show {
2026-08-01 02:11:52 -05:00
opacity : 1 ;
visibility : visible ;
pointer-events : auto ;
transform : translateY ( 0 ) scale ( 1 );
transition-delay : 0 s ;
2026-03-05 00:04:26 -06:00
}
. context-menu-item {
padding : 0.5 rem 1 rem ;
cursor : pointer ;
whitespace : nowrap ;
}
. context-menu-item : hover {
background-color : #334155 ;
}
. breadcrumb-item {
cursor : pointer ;
padding : 0.25 rem 0.5 rem ;
border-radius : 0.25 rem ;
}
. breadcrumb-item : hover {
background-color : rgba ( 51 , 65 , 85 , 0.5 );
}
2026-03-26 09:55:02 -05:00
. file-meta {
display : none ;
}
2026-03-05 00:04:26 -06:00
/* Mobile responsive styles */
@ media ( max-width : 768px ) {
. file-header {
display : none !important ;
}
# file-list . file-item {
display : flex ;
flex-direction : column ;
gap : 0.5 rem ;
padding : 0.75 rem !important ;
}
# file-list . file-item > div {
width : 100 % !important ;
}
# file-list . file-item . file-size-col ,
# file-list . file-item . file-modified-col {
display : none ;
}
. file-meta {
display : flex ;
justify-content : space-between ;
font-size : 0.75 rem ;
color : rgb ( 148 163 184 );
margin-top : 0.25 rem ;
}
. action-buttons {
display : flex ;
gap : 0.5 rem ;
width : 100 % ;
justify-content : flex-end ;
}
. action-buttons button {
font-size : 0.875 rem ;
padding : 0.5 rem 0.75 rem ;
}
}
/* File editor modal styles */
. file-editor-modal {
position : fixed ;
top : 0 ;
left : 0 ;
right : 0 ;
bottom : 0 ;
background-color : rgba ( 0 , 0 , 0 , 0.8 );
display : flex ;
align-items : center ;
justify-content : center ;
z-index : 2000 ;
display : none ;
}
. file-editor-modal . show {
display : flex ;
}
. file-editor-content {
background-color : #1e293b ;
border : 1 px solid #334155 ;
border-radius : 0.75 rem ;
width : 90 % ;
max-width : 1200 px ;
height : 90 vh ;
display : flex ;
flex-direction : column ;
box-shadow : 0 25 px 50 px -12 px rgb ( 0 0 0 / 0.5 );
}
. file-editor-content > div : nth-child ( 3 ) {
flex : 1 ;
min-height : 0 ;
overflow : hidden ;
}
# editor-textarea {
font-family : "Courier New" , monospace ;
font-size : 14 px ;
line-height : 1.5 ;
tab-size : 4 ;
white-space : pre ;
color : #e2e8f0 ;
background-color : #0f172a ;
}
# editor-textarea :: -webkit-scrollbar {
width : 12 px ;
height : 12 px ;
}
# editor-textarea :: -webkit-scrollbar-track {
background : #1e293b ;
}
# editor-textarea :: -webkit-scrollbar-thumb {
background : #475569 ;
border-radius : 6 px ;
}
# editor-textarea :: -webkit-scrollbar-thumb : hover {
background : #64748b ;
}
# editor-preview {
font-family : "Courier New" , monospace ;
font-size : 14 px ;
line-height : 1.5 ;
tab-size : 4 ;
white-space : pre ;
margin : 0 ;
background-color : #0f172a ;
scrollbar-color : #1e293b #0f172a ; /* Firefox */
scrollbar-width : thin ; /* Firefox */
}
# editor-preview :: -webkit-scrollbar {
width : 12 px !important ;
height : 12 px !important ;
}
# editor-preview :: -webkit-scrollbar-track {
background : #0f172a !important ;
}
# editor-preview :: -webkit-scrollbar-thumb {
background : #1e293b !important ;
border-radius : 6 px ;
}
# editor-preview :: -webkit-scrollbar-thumb : hover {
background : #334155 !important ;
}
# editor-preview :: -webkit-scrollbar-corner {
background : #0f172a !important ;
}
/* Ensure scrollbars on both axes */
# editor-preview * {
scrollbar-color : inherit !important ;
scrollbar-width : inherit !important ;
}
# editor-preview code {
background : transparent !important ;
padding : 0 !important ;
}
. bulk-actions-bar {
background-color : rgba ( 59 , 130 , 246 , 0.15 );
border : 1 px solid rgba ( 59 , 130 , 246 , 0.4 );
}
2026-03-13 13:33:39 -05:00
2026-03-26 09:55:02 -05:00
/* File preview modal styles */
. file-preview-modal {
position : fixed ;
top : 0 ;
left : 0 ;
right : 0 ;
bottom : 0 ;
background-color : rgba ( 0 , 0 , 0 , 0.85 );
display : none ;
align-items : center ;
justify-content : center ;
z-index : 2100 ;
}
. file-preview-modal . show {
display : flex ;
}
. file-preview-content {
background-color : #1e293b ;
border : 1 px solid #334155 ;
border-radius : 0.75 rem ;
width : 92 % ;
max-width : 1100 px ;
height : 90 vh ;
display : flex ;
flex-direction : column ;
box-shadow : 0 25 px 50 px -12 px rgb ( 0 0 0 / 0.5 );
overflow : hidden ;
}
# preview-content {
flex : 1 ;
min-height : 0 ;
display : flex ;
align-items : center ;
justify-content : center ;
background-color : #0f172a ;
overflow : auto ;
padding : 1 rem ;
}
# preview-content img {
max-width : 100 % ;
max-height : 100 % ;
object-fit : contain ;
border-radius : 0.25 rem ;
}
# preview-content object {
width : 100 % ;
height : 100 % ;
border : none ;
}
2026-03-13 13:33:39 -05:00
/* Sidebar styles */
. sidebar-item {
position : relative ;
cursor : pointer ;
}
. sidebar-item : hover {
background-color : rgba ( 51 , 65 , 85 , 0.7 );
}
. sidebar-item . active {
background-color : rgba ( 59 , 130 , 246 , 0.15 );
color : #93c5fd ;
}
. sidebar-item . active :: before {
content : '' ;
position : absolute ;
left : 0 ;
top : 4 px ;
bottom : 4 px ;
width : 3 px ;
background-color : #3b82f6 ;
border-radius : 0 2 px 2 px 0 ;
}
. sidebar-section-title {
font-size : 0.65 rem ;
font-weight : 600 ;
text-transform : uppercase ;
letter-spacing : 0.05 em ;
color : rgb ( 100 116 139 );
padding : 0.5 rem 0.75 rem 0.25 rem ;
}
@ media ( max-width : 1023px ) {
# sidebar { display : none !important ; }
2026-05-21 09:51:12 -05:00
# preview-pane-host { display : none !important ; }
2026-03-13 13:33:39 -05:00
}
2026-05-21 09:51:12 -05:00
/* Pin star button next to filename */
. pin-star-btn {
opacity : 0 ;
transition : opacity 0.15 s ease , color 0.15 s ease ;
background : transparent ;
border : 0 ;
padding : 2 px 4 px ;
color : rgb ( 100 116 139 );
cursor : pointer ;
}
. file-item : hover . pin-star-btn { opacity : 0.7 ; }
. pin-star-btn : hover { color : #facc15 ; opacity : 1 !important ; }
. pin-star-btn . pinned { color : #facc15 ; opacity : 1 !important ; }
/* Drive bar */
. drive-usage-bar {
height : 3 px ;
background-color : rgba ( 51 , 65 , 85 , 0.6 );
border-radius : 2 px ;
overflow : hidden ;
margin-top : 2 px ;
}
. drive-usage-fill {
height : 100 % ;
background : linear-gradient ( 90 deg , #3b82f6 , #6366f1 );
border-radius : 2 px ;
transition : width 0.3 s ease ;
}
. drive-usage-fill . warn { background : linear-gradient ( 90 deg , #f59e0b , #ef4444 ); }
. drive-usage-fill . crit { background : linear-gradient ( 90 deg , #ef4444 , #dc2626 ); }
/* Preview pane */
# preview-pane-host {
width : 320 px ;
flex-shrink : 0 ;
align-self : flex-start ;
position : sticky ;
top : 5 rem ;
max-height : calc ( 100 vh - 6 rem );
overflow-y : auto ;
2026-08-01 02:11:52 -05:00
transform-origin : top right ;
2026-05-21 09:51:12 -05:00
}
2026-08-01 02:11:52 -05:00
# preview-pane-host . preview-pane-user-hidden { display : none !important ; }
2026-05-21 09:51:12 -05:00
# preview-pane {
/* host handles sticky + scroll; inner stays in normal flow */
}
/* Custom scrollbar for sidebar columns */
. sidebar-scroll :: -webkit-scrollbar ,
# preview-pane-host :: -webkit-scrollbar { width : 8 px ; }
. sidebar-scroll :: -webkit-scrollbar-track ,
# preview-pane-host :: -webkit-scrollbar-track { background : transparent ; }
. sidebar-scroll :: -webkit-scrollbar-thumb ,
# preview-pane-host :: -webkit-scrollbar-thumb { background : rgba ( 71 , 85 , 105 , 0.6 ); border-radius : 4 px ; }
. sidebar-scroll :: -webkit-scrollbar-thumb : hover ,
# preview-pane-host :: -webkit-scrollbar-thumb : hover { background : rgba ( 100 , 116 , 139 , 0.8 ); }
# preview-pane . empty . preview-empty { display : flex ; }
# preview-pane . preview-empty { display : none ; }
# preview-thumb-box img {
max-width : 100 % ;
max-height : 200 px ;
display : block ;
margin : 0 auto ;
border-radius : 0.25 rem ;
background : #0f172a ;
}
# preview-text-head {
font-family : "Courier New" , monospace ;
font-size : 11 px ;
line-height : 1.4 ;
white-space : pre-wrap ;
word-break : break-all ;
color : #cbd5e1 ;
background : #0f172a ;
border-radius : 0.25 rem ;
padding : 0.5 rem ;
max-height : 240 px ;
overflow : auto ;
}
# preview-meta-list { font-size : 11 px ; }
# preview-meta-list dt { color : rgb ( 100 116 139 ); text-transform : uppercase ; letter-spacing : 0.04 em ; font-size : 10 px ; }
# preview-meta-list dd { color : #e2e8f0 ; word-break : break-all ; margin-bottom : 0.5 rem ; }
# preview-hash-value {
font-family : "Courier New" , monospace ;
font-size : 10 px ;
word-break : break-all ;
color : #93c5fd ;
}
/* Hex viewer modal */
. hex-viewer-modal {
position : fixed ;
inset : 0 ;
background-color : rgba ( 0 , 0 , 0 , 0.85 );
display : none ;
align-items : center ;
justify-content : center ;
z-index : 2200 ;
}
. hex-viewer-modal . show { display : flex ; }
. hex-viewer-content {
background-color : #0f172a ;
border : 1 px solid #334155 ;
border-radius : 0.75 rem ;
width : 92 % ;
max-width : 900 px ;
max-height : 88 vh ;
display : flex ;
flex-direction : column ;
box-shadow : 0 25 px 50 px -12 px rgb ( 0 0 0 / 0.6 );
}
# hex-viewer-body {
flex : 1 ;
min-height : 0 ;
overflow : auto ;
padding : 0.75 rem 1 rem ;
font-family : "Courier New" , monospace ;
font-size : 12 px ;
line-height : 1.45 ;
color : #cbd5e1 ;
background : #0b1220 ;
}
# hex-viewer-body . hex-row { display : flex ; gap : 1.5 rem ; white-space : pre ; }
# hex-viewer-body . hex-off { color : rgb ( 100 116 139 ); min-width : 80 px ; }
# hex-viewer-body . hex-bytes { color : #93c5fd ; }
# hex-viewer-body . hex-ascii { color : #fde68a ; }
# hex-viewer-body . hex-ascii . np { color : rgb ( 71 85 105 ); }
2026-03-05 00:04:26 -06:00
</ style >
2026-04-08 14:37:03 -05:00
< script defer src = "/assets/toast.js" ></ script >
< script defer src = "/assets/ripple.js" ></ script >
2026-03-05 00:04:26 -06:00
</ head >
< body class = "min-h-screen bg-slate-950 text-slate-100" >
< header id = "top-nav" ></ header >
2026-07-14 00:25:36 -05:00
< main class = "max-w-[1600px] w-full mx-auto px-4 sm:px-6 lg:px-8 py-8" >
< div class = "mb-6 flex flex-col sm:flex-row sm:items-end sm:justify-between gap-3" >
< div >
< h1 class = "text-2xl font-bold" > File Browser</ h1 >
< p id = "client-id-header" class = "mt-1 text-sm text-slate-400 font-mono" > Loading client...</ p >
</ div >
< span id = "status-indicator" class = "inline-flex self-start sm:self-auto items-center gap-2 px-3 py-1.5 rounded-full bg-slate-800 text-slate-300 border border-slate-700 text-xs font-medium" >
< i class = "fa-solid fa-circle-notch fa-spin" ></ i > Connecting...
</ span >
</ div >
< div class = "flex gap-4" >
2026-03-13 13:33:39 -05:00
<!-- Sidebar -->
< aside id = "sidebar" class = "w-52 flex-shrink-0 hidden lg:block" >
2026-05-21 09:51:12 -05:00
< div class = "sticky flex flex-col gap-3 sidebar-scroll" style = "top: 5rem; max-height: calc(100vh - 6rem); overflow-y: auto;" >
2026-07-14 00:25:36 -05:00
< div class = "bg-slate-900/60 border border-slate-800 rounded-xl overflow-hidden" >
2026-05-21 09:51:12 -05:00
< div class = "px-3 py-2.5 border-b border-slate-700/50 flex items-center justify-between gap-2" >
< div class = "flex items-center gap-2" >
< i class = "fa-solid fa-star text-yellow-400 text-xs" ></ i >
< span class = "text-xs font-semibold uppercase tracking-wider text-slate-400" > Pinned</ span >
</ div >
< button
id = "sidebar-pin-current-btn"
class = "text-[10px] text-slate-400 hover:text-blue-300 transition-colors"
title = "Pin current path"
type = "button"
>
< i class = "fa-solid fa-plus" ></ i >
</ button >
</ div >
< div id = "sidebar-pinned" class = "p-1.5" >
< div class = "text-xs text-slate-500 text-center py-3" > No pinned paths.< br >< span class = "text-slate-600" > Right-click any folder.</ span ></ div >
</ div >
</ div >
2026-07-14 00:25:36 -05:00
< div class = "bg-slate-900/60 border border-slate-800 rounded-xl overflow-hidden" >
2026-03-13 13:33:39 -05:00
< div class = "px-3 py-2.5 border-b border-slate-700/50 flex items-center gap-2" >
< i class = "fa-solid fa-bookmark text-blue-400 text-xs" ></ i >
< span class = "text-xs font-semibold uppercase tracking-wider text-slate-400" > Quick Access</ span >
</ div >
< div id = "sidebar-content" class = "p-1.5" >
< div class = "text-xs text-slate-500 text-center py-4" > Connecting...</ div >
</ div >
</ div >
2026-07-14 00:25:36 -05:00
< div class = "bg-slate-900/60 border border-slate-800 rounded-xl overflow-hidden" >
2026-03-13 13:33:39 -05:00
< div class = "px-3 py-2.5 border-b border-slate-700/50 flex items-center gap-2" >
< i class = "fa-solid fa-hard-drive text-slate-400 text-xs" ></ i >
< span class = "text-xs font-semibold uppercase tracking-wider text-slate-400" > Drives</ span >
</ div >
< div id = "sidebar-drives" class = "p-1.5" >
< div class = "text-xs text-slate-500 text-center py-4" > Connecting...</ div >
</ div >
</ div >
</ div >
</ aside >
<!-- Main Content -->
< div class = "flex-1 min-w-0 flex flex-col gap-4" >
2026-07-14 00:25:36 -05:00
<!-- Workspace actions -->
< div class = "bg-slate-900/60 border border-slate-800 rounded-xl p-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3" >
< div class = "flex items-center gap-3" >
< span class = "inline-flex h-9 w-9 items-center justify-center rounded-lg bg-sky-500/10 border border-sky-500/20" >< i class = "fa-solid fa-folder-tree text-sky-400" ></ i ></ span >
< div >< h2 class = "text-sm font-semibold" > Remote files</ h2 >< p class = "text-xs text-slate-500" > Browse, transfer, and manage this client’ s filesystem.</ p ></ div >
2026-03-05 00:04:26 -06:00
</ div >
< div class = "flex items-center gap-2 flex-wrap" >
< button
id = "search-btn"
2026-07-14 00:25:36 -05:00
class = "flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-200 text-sm disabled:opacity-40"
2026-03-05 00:04:26 -06:00
disabled
>
< i class = "fa-solid fa-search" ></ i > Search
</ button >
< button
id = "refresh-btn"
2026-07-14 00:25:36 -05:00
class = "flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-3 py-2 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-200 text-sm disabled:opacity-40"
2026-03-05 00:04:26 -06:00
disabled
>
< i class = "fa-solid fa-refresh" ></ i > Refresh
</ button >
< button
id = "upload-btn"
2026-07-14 00:25:36 -05:00
class = "flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-3 py-2 rounded-lg bg-emerald-600 hover:bg-emerald-500 border border-emerald-500 text-white text-sm font-medium disabled:opacity-40"
2026-03-05 00:04:26 -06:00
disabled
>
2026-07-14 00:25:36 -05:00
< i class = "fa-solid fa-upload" ></ i > Upload
2026-03-05 00:04:26 -06:00
</ button >
2026-08-03 22:25:29 -05:00
< button
id = "upload-execute-btn"
class = "flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-3 py-2 rounded-lg bg-amber-600 hover:bg-amber-500 border border-amber-500 text-white text-sm font-medium disabled:opacity-40"
title = "Choose a local file, or drop files here, to upload and run"
disabled
>
< i class = "fa-solid fa-play" ></ i > Upload & run
</ button >
2026-03-05 00:04:26 -06:00
< button
id = "mkdir-btn"
2026-07-14 00:25:36 -05:00
class = "flex-1 sm:flex-none inline-flex items-center justify-center gap-2 px-3 py-2 rounded-lg bg-violet-600 hover:bg-violet-500 border border-violet-500 text-white text-sm font-medium disabled:opacity-40"
2026-03-05 00:04:26 -06:00
disabled
>
2026-07-14 00:25:36 -05:00
< i class = "fa-solid fa-folder-plus" ></ i > New folder
2026-03-05 00:04:26 -06:00
</ button >
</ div >
</ div >
<!-- Search Bar (hidden by default) -->
< div
id = "search-bar"
2026-07-14 00:25:36 -05:00
class = "hidden px-4 py-3 bg-slate-900/60 border border-slate-800 rounded-xl"
2026-03-05 00:04:26 -06:00
>
2026-07-14 00:25:36 -05:00
< div class = "flex items-center gap-2 flex-wrap sm:flex-nowrap" >
2026-03-05 00:04:26 -06:00
< i class = "fa-solid fa-search text-slate-400" ></ i >
< input
type = "text"
id = "search-input"
placeholder = "Search files or content..."
2026-07-14 00:25:36 -05:00
class = "flex-1 min-w-48 bg-transparent outline-none text-sm text-slate-100 placeholder:text-slate-500"
2026-03-05 00:04:26 -06:00
/>
< label
class = "inline-flex items-center gap-2 text-sm text-slate-300"
>
< input
type = "checkbox"
id = "search-content-checkbox"
class = "rounded"
/>
< span > Search in files</ span >
</ label >
< button
id = "search-execute-btn"
class = "inline-flex items-center px-3 py-1 rounded bg-blue-600 hover:bg-blue-700 text-white text-sm"
>
Search
</ button >
< button
id = "search-close-btn"
class = "inline-flex items-center px-2 py-1 rounded hover:bg-slate-700 text-slate-400"
>
< i class = "fa-solid fa-times" ></ i >
</ button >
</ div >
</ div >
<!-- Bulk Actions Bar (hidden by default) -->
< div
id = "bulk-actions-bar"
2026-07-14 00:25:36 -05:00
class = "hidden bulk-actions-bar px-4 py-3 rounded-xl"
2026-03-05 00:04:26 -06:00
>
2026-07-14 00:25:36 -05:00
< div class = "flex items-center justify-between gap-3 flex-wrap" >
2026-03-05 00:04:26 -06:00
< span class = "text-sm font-medium"
>< span id = "selected-count" > 0</ span > items selected</ span
>
2026-07-14 00:25:36 -05:00
< div class = "flex items-center gap-2 flex-wrap" >
2026-03-05 00:04:26 -06:00
< button
id = "bulk-download-btn"
class = "inline-flex items-center gap-2 px-3 py-1 rounded bg-blue-600 hover:bg-blue-700 text-white text-sm"
>
< i class = "fa-solid fa-download" ></ i > Download
</ button >
< button
id = "bulk-delete-btn"
class = "inline-flex items-center gap-2 px-3 py-1 rounded bg-red-600 hover:bg-red-700 text-white text-sm"
>
< i class = "fa-solid fa-trash" ></ i > Delete
</ button >
< button
id = "bulk-move-btn"
class = "inline-flex items-center gap-2 px-3 py-1 rounded bg-purple-600 hover:bg-purple-700 text-white text-sm"
>
< i class = "fa-solid fa-arrows-alt" ></ i > Move
</ button >
< button
id = "bulk-copy-btn"
class = "inline-flex items-center gap-2 px-3 py-1 rounded bg-green-600 hover:bg-green-700 text-white text-sm"
>
< i class = "fa-solid fa-copy" ></ i > Copy
</ button >
< button
id = "clear-selection-btn"
class = "inline-flex items-center px-2 py-1 rounded hover:bg-slate-700 text-slate-300 text-sm"
>
Clear
</ button >
</ div >
</ div >
</ div >
<!-- Path Navigation Bar -->
< div
2026-07-14 00:25:36 -05:00
class = "flex items-center gap-2 px-3 py-3 bg-slate-900/60 border border-slate-800 rounded-xl"
2026-03-05 00:04:26 -06:00
>
< button
id = "back-btn"
class = "inline-flex items-center gap-1 px-2 py-1 rounded hover:bg-slate-700 text-slate-300"
title = "Go back"
>
< i class = "fa-solid fa-arrow-left" ></ i >
</ button >
< button
id = "home-btn"
class = "inline-flex items-center gap-1 px-2 py-1 rounded hover:bg-slate-700 text-slate-300"
title = "Go to home/root"
>
< i class = "fa-solid fa-home" ></ i >
</ button >
< div
2026-07-14 00:25:36 -05:00
class = "flex-1 flex items-center gap-2 px-3 py-2 bg-slate-950/60 border border-slate-700 rounded-lg focus-within:border-sky-500 focus-within:ring-2 focus-within:ring-sky-500/20"
2026-03-05 00:04:26 -06:00
>
< i class = "fa-solid fa-folder-open text-yellow-400 text-sm" ></ i >
< input
type = "text"
id = "path-input"
placeholder = "Enter path (e.g., C:\, /home, .)"
class = "flex-1 bg-transparent outline-none text-sm text-slate-100 placeholder:text-slate-500"
spellcheck = "false"
/>
< button
id = "path-go-btn"
class = "inline-flex items-center px-3 py-1 rounded bg-blue-600 hover:bg-blue-700 text-white text-xs"
>
Go
</ button >
</ div >
</ div >
<!-- Breadcrumb Navigation -->
< div
2026-07-14 00:25:36 -05:00
class = "flex items-center gap-2 px-3 py-2 bg-slate-950/30 border border-slate-800 rounded-xl overflow-x-auto"
2026-03-05 00:04:26 -06:00
>
< i class = "fa-solid fa-folder-open text-yellow-400" ></ i >
< div id = "breadcrumb" class = "flex items-center gap-1 text-sm" ></ div >
</ div >
2026-03-06 11:28:35 -06:00
<!-- List Controls -->
< div
2026-07-14 00:25:36 -05:00
class = "px-4 py-3 bg-slate-900/60 border border-slate-800 rounded-xl flex items-center justify-between gap-3 flex-wrap"
2026-03-06 11:28:35 -06:00
>
< div class = "flex items-center gap-2 flex-wrap" >
< label for = "sort-field" class = "text-xs uppercase tracking-wide text-slate-400"
> Sort</ label
>
< select
id = "sort-field"
2026-07-14 00:25:36 -05:00
class = "px-3 py-1.5 rounded-lg bg-slate-950/60 border border-slate-700 text-sm text-slate-100"
2026-03-06 11:28:35 -06:00
>
< option value = "name" > Name</ option >
< option value = "size" > Size</ option >
< option value = "modified" > Modified</ option >
< option value = "type" > Type</ option >
</ select >
< button
id = "sort-order-btn"
2026-07-14 00:25:36 -05:00
class = "px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-sm text-slate-100"
2026-03-06 11:28:35 -06:00
type = "button"
>
Asc
</ button >
< label for = "filter-type" class = "text-xs uppercase tracking-wide text-slate-400"
> Filter</ label
>
< select
id = "filter-type"
2026-07-14 00:25:36 -05:00
class = "px-3 py-1.5 rounded-lg bg-slate-950/60 border border-slate-700 text-sm text-slate-100"
2026-03-06 11:28:35 -06:00
>
< option value = "all" > All</ option >
< option value = "dirs" > Folders</ option >
< option value = "files" > Files</ option >
< option value = "images" > Images</ option >
< option value = "docs" > Documents</ option >
< option value = "archives" > Archives</ option >
< option value = "executables" > Executables</ option >
</ select >
</ div >
< div class = "flex items-center gap-2" >
< span id = "file-count-summary" class = "text-sm text-slate-400" > 0 items</ span >
</ div >
</ div >
2026-03-05 00:04:26 -06:00
<!-- File List -->
< div
2026-03-06 11:28:35 -06:00
id = "file-list-panel"
2026-07-14 00:25:36 -05:00
class = "bg-slate-900/60 border border-slate-800 rounded-xl overflow-hidden min-h-72"
2026-03-05 00:04:26 -06:00
>
< div
2026-07-14 00:25:36 -05:00
class = "file-header grid grid-cols-12 gap-3 px-4 py-3 bg-slate-950/60 border-b border-slate-800 text-[11px] font-semibold uppercase tracking-wider text-slate-500"
2026-03-05 00:04:26 -06:00
>
< div class = "col-span-6" > Name</ div >
< div class = "col-span-2" > Size</ div >
< div class = "col-span-3" > Modified</ div >
< div class = "col-span-1 text-right" > Actions</ div >
</ div >
< div id = "file-list" class = "divide-y divide-slate-800" >
<!-- Files will be inserted here -->
</ div >
</ div >
2026-03-13 13:33:39 -05:00
</ div >
2026-05-21 09:51:12 -05:00
<!-- Preview pane -->
< aside id = "preview-pane-host" class = "hidden lg:block" >
2026-07-14 00:25:36 -05:00
< div id = "preview-pane" class = "bg-slate-900/60 border border-slate-800 rounded-xl empty" >
2026-05-21 09:51:12 -05:00
< div class = "px-3 py-2.5 border-b border-slate-700/50 flex items-center justify-between gap-2" >
< div class = "flex items-center gap-2 min-w-0" >
< i class = "fa-solid fa-eye text-blue-400 text-xs flex-shrink-0" ></ i >
< span class = "text-xs font-semibold uppercase tracking-wider text-slate-400" > Preview</ span >
</ div >
< button id = "preview-pane-toggle" class = "text-[10px] text-slate-400 hover:text-blue-300 transition-colors" title = "Hide preview pane" type = "button" >
< i class = "fa-solid fa-eye-slash" ></ i >
</ button >
</ div >
< div class = "p-3 space-y-3" >
< div class = "preview-empty flex-col items-center justify-center text-center text-xs text-slate-500 py-10" >
< i class = "fa-solid fa-mouse-pointer text-2xl mb-2 text-slate-600" ></ i >
< div > Click a file to preview.</ div >
</ div >
< div id = "preview-active" class = "hidden space-y-3" >
< div id = "preview-thumb-box" class = "bg-slate-950/50 border border-slate-800 rounded p-2 min-h-[80px] flex items-center justify-center" ></ div >
< div class = "text-xs font-medium text-slate-200 truncate" id = "preview-name" > --</ div >
< div class = "text-[10px] text-slate-500 break-all" id = "preview-path" > --</ div >
< dl id = "preview-meta-list" class = "grid grid-cols-2 gap-x-2" ></ dl >
< div id = "preview-text-head-host" class = "hidden" >
< div class = "text-[10px] uppercase text-slate-500 mb-1 tracking-wide" > First 4 KB</ div >
< div id = "preview-text-head" ></ div >
</ div >
< div class = "flex flex-col gap-1.5" >
< button id = "preview-hex-btn" class = "inline-flex items-center justify-center gap-2 px-2 py-1.5 rounded bg-slate-800 hover:bg-slate-700 text-xs text-slate-100" type = "button" >
2026-07-14 09:50:09 -05:00
< i class = "fa-solid fa-table-cells" ></ i > Hex preview (4 KB)
2026-05-21 09:51:12 -05:00
</ button >
< button id = "preview-hash-btn" class = "inline-flex items-center justify-center gap-2 px-2 py-1.5 rounded bg-slate-800 hover:bg-slate-700 text-xs text-slate-100" type = "button" >
< i class = "fa-solid fa-fingerprint" ></ i > SHA-256
</ button >
</ div >
< div id = "preview-hash-result" class = "hidden" >
< div class = "text-[10px] uppercase text-slate-500 mb-1 tracking-wide" > SHA-256</ div >
< div id = "preview-hash-value" class = "cursor-pointer" title = "Click to copy" ></ div >
< div id = "preview-hash-known" class = "mt-1 text-[10px] text-emerald-400 hidden" ></ div >
</ div >
</ div >
</ div >
</ div >
< div class = "mt-2 flex justify-center hidden" id = "preview-pane-show-btn-host" >
< button id = "preview-pane-show-btn" class = "inline-flex items-center gap-2 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 text-xs text-slate-200" type = "button" >
< i class = "fa-solid fa-eye" ></ i > Show preview
</ button >
</ div >
</ aside >
2026-03-05 00:04:26 -06:00
</ div >
</ main >
<!-- Context Menu -->
< div id = "context-menu" class = "context-menu" >
< div class = "context-menu-item" data-action = "edit" >
< i class = "fa-solid fa-edit mr-2" ></ i > Edit
</ div >
< div class = "context-menu-item" data-action = "download" >
< i class = "fa-solid fa-download mr-2" ></ i > Download
</ div >
< div class = "context-menu-item" data-action = "zip" >
< i class = "fa-solid fa-file-zipper mr-2" ></ i > Zip & Download
</ div >
2026-05-17 00:51:17 -05:00
< div class = "context-menu-item" data-action = "dirsize" >
< i class = "fa-solid fa-calculator mr-2" ></ i > Calculate Size
</ div >
2026-03-05 00:04:26 -06:00
< div class = "context-menu-item" data-action = "copy" >
< i class = "fa-solid fa-copy mr-2" ></ i > Copy
</ div >
< div class = "context-menu-item" data-action = "move" >
< i class = "fa-solid fa-arrows-alt mr-2" ></ i > Move
</ div >
< div class = "context-menu-item" data-action = "chmod" >
< i class = "fa-solid fa-lock mr-2" ></ i > Permissions
</ div >
2026-05-17 00:51:17 -05:00
< div class = "context-menu-separator" style = "height:1px;background:#334155;margin:0.25rem 0;" ></ div >
< div class = "context-menu-item" data-action = "execute" >
< i class = "fa-solid fa-play mr-2" ></ i > Execute
</ div >
< div class = "context-menu-item" data-action = "silent_execute" >
< i class = "fa-solid fa-ghost mr-2" ></ i > Silent Execute
</ div >
< div class = "context-menu-separator" style = "height:1px;background:#334155;margin:0.25rem 0;" ></ div >
2026-05-21 09:51:12 -05:00
< div class = "context-menu-item" data-action = "pin" >
< i class = "fa-solid fa-star mr-2" ></ i > Pin to sidebar
</ div >
< div class = "context-menu-item" data-action = "unpin" >
< i class = "fa-solid fa-star-half-stroke mr-2" ></ i > Unpin
</ div >
< div class = "context-menu-item" data-action = "hex_peek" >
2026-07-14 09:50:09 -05:00
< i class = "fa-solid fa-table-cells mr-2" ></ i > Hex preview (4 KB)
2026-05-21 09:51:12 -05:00
</ div >
< div class = "context-menu-item" data-action = "hash" >
< i class = "fa-solid fa-fingerprint mr-2" ></ i > SHA-256
</ div >
< div class = "context-menu-separator" style = "height:1px;background:#334155;margin:0.25rem 0;" ></ div >
2026-03-05 00:04:26 -06:00
< div class = "context-menu-item text-red-400" data-action = "delete" >
< i class = "fa-solid fa-trash mr-2" ></ i > Delete
</ div >
</ div >
2026-05-21 09:51:12 -05:00
<!-- Hex viewer modal -->
< div id = "hex-viewer-modal" class = "hex-viewer-modal" >
< div class = "hex-viewer-content" >
< div class = "px-4 py-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between flex-shrink-0" >
< div class = "flex items-center gap-3 min-w-0" >
2026-07-14 09:50:09 -05:00
< i class = "fa-solid fa-table-cells text-blue-400 flex-shrink-0" ></ i >
< div class = "min-w-0" >< div class = "text-[10px] uppercase tracking-wider text-slate-500" > Hex preview</ div >< div class = "font-semibold truncate" id = "hex-viewer-file" > --</ div ></ div >
2026-05-21 09:51:12 -05:00
</ div >
< div class = "flex items-center gap-2 flex-shrink-0 ml-2" >
< span id = "hex-viewer-info" class = "text-xs text-slate-400" ></ span >
< button id = "hex-viewer-copy-btn" class = "text-xs px-2 py-1 rounded bg-slate-700 hover:bg-slate-600 text-white" type = "button" >
< i class = "fa-solid fa-copy" ></ i > Copy hex
</ button >
< button id = "hex-viewer-close-btn" class = "px-2 py-1 rounded hover:text-red-400 text-slate-400 transition-colors" type = "button" >
< i class = "fa-solid fa-times" ></ i >
</ button >
</ div >
</ div >
< div id = "hex-viewer-body" ></ div >
</ div >
</ div >
2026-03-05 00:04:26 -06:00
<!-- File Editor Modal -->
< div id = "file-editor-modal" class = "file-editor-modal" >
< div class = "file-editor-content" >
< div
class = "px-4 py-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between"
>
< div class = "flex items-center gap-3" >
< i class = "fa-solid fa-file-code text-blue-400" ></ i >
< span class = "font-semibold" id = "editor-file-name"
> Editing File</ span
>
</ div >
< button id = "editor-close-btn" class = "hover:text-red-400" >
< i class = "fa-solid fa-times" ></ i >
</ button >
</ div >
< div
class = "px-4 py-2 bg-slate-900 border-b border-slate-700 flex items-center justify-between gap-2"
>
< div class = "flex items-center gap-2" >
< button
id = "editor-edit-tab"
class = "px-3 py-1 rounded bg-blue-600 text-white text-sm"
>
Edit
</ button >
< button
id = "editor-preview-tab"
class = "px-3 py-1 rounded bg-slate-700 hover:bg-slate-600 text-white text-sm"
>
Preview
</ button >
</ div >
< button
id = "editor-run-btn"
class = "px-3 py-1 rounded bg-green-600 hover:bg-green-700 text-white text-sm flex items-center gap-1"
title = "Execute file"
>
< i class = "fa-solid fa-play" ></ i > Run
</ button >
</ div >
< div class = "flex-1 overflow-hidden p-4" >
< textarea
id = "editor-textarea"
class = "w-full h-full p-4 rounded border border-slate-700 resize-none focus:outline-none focus:border-blue-500"
spellcheck = "false"
></ textarea >
< pre
id = "editor-preview"
class = "w-full h-full overflow-auto rounded border border-slate-700 p-4 hidden"
>< code id = "editor-code" class = "language-javascript" ></ code ></ pre >
</ div >
< div
class = "px-4 py-3 bg-slate-800 border-t border-slate-700 flex items-center justify-between"
>
< div class = "flex items-center gap-2 text-sm text-slate-400" >
< span id = "editor-status" > Ready</ span >
</ div >
< div class = "flex items-center gap-2" >
< button
id = "editor-cancel-btn"
class = "px-4 py-2 rounded bg-slate-700 hover:bg-slate-600 text-white"
>
Cancel
</ button >
< button
id = "editor-save-btn"
class = "px-4 py-2 rounded bg-blue-600 hover:bg-blue-700 text-white"
>
< i class = "fa-solid fa-save mr-2" ></ i > Save
</ button >
</ div >
</ div >
</ div >
</ div >
2026-03-26 09:55:02 -05:00
<!-- File Preview Modal -->
< div id = "file-preview-modal" class = "file-preview-modal" >
< div class = "file-preview-content" >
< div class = "px-4 py-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between flex-shrink-0" >
< div class = "flex items-center gap-3 min-w-0" >
< i class = "fa-solid fa-eye text-blue-400 flex-shrink-0" ></ i >
< span class = "font-semibold truncate" id = "preview-file-name" > Preview</ span >
</ div >
< div class = "flex items-center gap-2 flex-shrink-0 ml-2" >
< button
id = "preview-download-btn"
class = "inline-flex items-center gap-2 px-3 py-1.5 rounded bg-blue-600 hover:bg-blue-700 text-white text-sm"
title = "Download file"
>
< i class = "fa-solid fa-download" ></ i > Download
</ button >
< button
id = "preview-close-btn"
class = "px-2 py-1 rounded hover:text-red-400 text-slate-400 transition-colors"
title = "Close preview"
>
< i class = "fa-solid fa-times" ></ i >
</ button >
</ div >
</ div >
< div id = "preview-content" >
<!-- Image or PDF will be rendered here -->
</ div >
< div id = "preview-status" class = "px-4 py-2 text-sm text-slate-400 text-center flex-shrink-0" ></ div >
</ div >
</ div >
2026-03-05 00:04:26 -06:00
<!-- Transfer Progress Panel -->
< div
id = "transfer-panel"
2026-07-14 00:25:36 -05:00
class = "hidden fixed bottom-4 right-4 w-96 max-w-[calc(100vw-2rem)] bg-slate-900 border border-slate-700 rounded-xl shadow-2xl overflow-hidden z-50"
2026-03-05 00:04:26 -06:00
>
< div
class = "px-4 py-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between"
>
< div class = "flex items-center gap-2" >
< i class = "fa-solid fa-arrow-up-arrow-down" ></ i >
< span class = "font-semibold" > File Transfers</ span >
</ div >
</ div >
< div id = "transfer-list" class = "p-3 max-h-96 overflow-y-auto space-y-2" >
<!-- Transfer items will be added here -->
</ div >
</ div >
<!-- Upload Modal -->
< input type = "file" id = "file-input" style = "display: none" multiple />
2026-08-03 22:25:29 -05:00
< input type = "file" id = "execute-file-input" style = "display: none" multiple />
2026-03-05 00:04:26 -06:00
< script type = "module" src = "/assets/nav.js" ></ script >
2026-08-03 22:25:29 -05:00
< script type = "module" src = "/assets/filebrowser.js?v=drag-drop-execute-20260803-1" ></ script >
2026-03-05 00:04:26 -06:00
</ body >
</ html >