Zero-copy FTP/HTTP Daemon compatible with all POSIX systems
| 1 | <!DOCTYPE html> |
| 2 | <html lang="en" data-theme="ps5"> |
| 3 | |
| 4 | <head> |
| 5 | <meta charset="UTF-8"> |
| 6 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 7 | <title>zftpd | File Explorer</title> |
| 8 | <!-- CSRF_TOKEN --> |
| 9 | <link rel="preconnect" href="https://fonts.googleapis.com"> |
| 10 | <link |
| 11 | href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Syne:wght@700;800&display=swap" |
| 12 | rel="stylesheet"> |
| 13 | <style> |
| 14 | /* ══ THEMES ═══════════════════════════════════════════════════════ */ |
| 15 | :root, |
| 16 | [data-theme="ps5"] { |
| 17 | --bg: #080b10; |
| 18 | --sf: #101520; |
| 19 | --sf2: #171d28; |
| 20 | --sf3: #1e2535; |
| 21 | --bd: #1e2d40; |
| 22 | --bd2: #273550; |
| 23 | --ac: #2b8cff; |
| 24 | --ac2: #00c2ff; |
| 25 | --acR: 43, 140, 255; |
| 26 | --tx: #dce8f8; |
| 27 | --tx2: #7a94b8; |
| 28 | --tx3: #445a78; |
| 29 | --ok: #2ecc71; |
| 30 | --wn: #f0a500; |
| 31 | --er: #ff5f57; |
| 32 | --tg: rgba(43, 140, 255, .12); |
| 33 | --tgb: rgba(43, 140, 255, .3); |
| 34 | --tl: #2b8cff; |
| 35 | --gw: rgba(43, 140, 255, .08); |
| 36 | } |
| 37 | |
| 38 | [data-theme="matrix"] { |
| 39 | --bg: #030804; |
| 40 | --sf: #07100a; |
| 41 | --sf2: #0b160d; |
| 42 | --sf3: #101c12; |
| 43 | --bd: #132a16; |
| 44 | --bd2: #1c4022; |
| 45 | --ac: #00e639; |
| 46 | --ac2: #a8ff3e; |
| 47 | --acR: 0, 230, 57; |
| 48 | --tx: #c8f5cc; |
| 49 | --tx2: #56a060; |
| 50 | --tx3: #2e6035; |
| 51 | --ok: #00e639; |
| 52 | --wn: #d4ff00; |
| 53 | --er: #ff3333; |
| 54 | --tg: rgba(0, 230, 57, .1); |
| 55 | --tgb: rgba(0, 230, 57, .3); |
| 56 | --tl: #00e639; |
| 57 | --gw: rgba(0, 230, 57, .05); |
| 58 | } |
| 59 | |
| 60 | [data-theme="sunset"] { |
| 61 | --bg: #0c080f; |
| 62 | --sf: #16101e; |
| 63 | --sf2: #1e1528; |
| 64 | --sf3: #261b32; |
| 65 | --bd: #2e1f40; |
| 66 | --bd2: #44285c; |
| 67 | --ac: #ff6535; |
| 68 | --ac2: #ff2d78; |
| 69 | --acR: 255, 101, 53; |
| 70 | --tx: #f2e4ff; |
| 71 | --tx2: #a87ac4; |
| 72 | --tx3: #6e4a8c; |
| 73 | --ok: #80ff44; |
| 74 | --wn: #ffcc00; |
| 75 | --er: #ff2d78; |
| 76 | --tg: rgba(255, 101, 53, .12); |
| 77 | --tgb: rgba(255, 101, 53, .3); |
| 78 | --tl: #ff6535; |
| 79 | --gw: rgba(255, 101, 53, .07); |
| 80 | } |
| 81 | |
| 82 | [data-theme="arctic"] { |
| 83 | --bg: #060a0d; |
| 84 | --sf: #0b1218; |
| 85 | --sf2: #101a22; |
| 86 | --sf3: #16222e; |
| 87 | --bd: #162232; |
| 88 | --bd2: #1e3048; |
| 89 | --ac: #00d4ff; |
| 90 | --ac2: #00ffcc; |
| 91 | --acR: 0, 212, 255; |
| 92 | --tx: #d4eef8; |
| 93 | --tx2: #5aaccc; |
| 94 | --tx3: #2e7090; |
| 95 | --ok: #00ffcc; |
| 96 | --wn: #ffee00; |
| 97 | --er: #ff4466; |
| 98 | --tg: rgba(0, 212, 255, .1); |
| 99 | --tgb: rgba(0, 212, 255, .28); |
| 100 | --tl: #00d4ff; |
| 101 | --gw: rgba(0, 212, 255, .06); |
| 102 | } |
| 103 | |
| 104 | [data-theme="neon"] { |
| 105 | --bg: #07040e; |
| 106 | --sf: #0e0a1c; |
| 107 | --sf2: #150f26; |
| 108 | --sf3: #1c1432; |
| 109 | --bd: #241a40; |
| 110 | --bd2: #352560; |
| 111 | --ac: #c800ff; |
| 112 | --ac2: #ff00cc; |
| 113 | --acR: 200, 0, 255; |
| 114 | --tx: #eddeff; |
| 115 | --tx2: #9a70cc; |
| 116 | --tx3: #5e3d8a; |
| 117 | --ok: #44ff88; |
| 118 | --wn: #ffaa00; |
| 119 | --er: #ff3344; |
| 120 | --tg: rgba(200, 0, 255, .1); |
| 121 | --tgb: rgba(200, 0, 255, .28); |
| 122 | --tl: #c800ff; |
| 123 | --gw: rgba(200, 0, 255, .06); |
| 124 | } |
| 125 | |
| 126 | [data-theme="amber"] { |
| 127 | --bg: #090700; |
| 128 | --sf: #120e00; |
| 129 | --sf2: #1a1400; |
| 130 | --sf3: #221b00; |
| 131 | --bd: #2e2200; |
| 132 | --bd2: #453300; |
| 133 | --ac: #ffb700; |
| 134 | --ac2: #ff8c00; |
| 135 | --acR: 255, 183, 0; |
| 136 | --tx: #fff4cc; |
| 137 | --tx2: #c49a00; |
| 138 | --tx3: #7a5e00; |
| 139 | --ok: #88ff44; |
| 140 | --wn: #ff8c00; |
| 141 | --er: #ff4422; |
| 142 | --tg: rgba(255, 183, 0, .12); |
| 143 | --tgb: rgba(255, 183, 0, .3); |
| 144 | --tl: #ffb700; |
| 145 | --gw: rgba(255, 183, 0, .07); |
| 146 | } |
| 147 | |
| 148 | /* ══ RESET ════════════════════════════════════════════════════════ */ |
| 149 | *, |
| 150 | *::before, |
| 151 | *::after { |
| 152 | margin: 0; |
| 153 | padding: 0; |
| 154 | box-sizing: border-box |
| 155 | } |
| 156 | |
| 157 | html { |
| 158 | scroll-behavior: smooth |
| 159 | } |
| 160 | |
| 161 | body { |
| 162 | font-family: 'JetBrains Mono', monospace; |
| 163 | background: var(--bg); |
| 164 | color: var(--tx); |
| 165 | min-height: 100vh; |
| 166 | overflow-x: hidden |
| 167 | } |
| 168 | |
| 169 | ::-webkit-scrollbar { |
| 170 | width: 5px; |
| 171 | height: 5px |
| 172 | } |
| 173 | |
| 174 | ::-webkit-scrollbar-track { |
| 175 | background: var(--bg) |
| 176 | } |
| 177 | |
| 178 | ::-webkit-scrollbar-thumb { |
| 179 | background: var(--bd2); |
| 180 | border-radius: 3px |
| 181 | } |
| 182 | |
| 183 | ::-webkit-scrollbar-thumb:hover { |
| 184 | background: var(--ac) |
| 185 | } |
| 186 | |
| 187 | svg { |
| 188 | display: inline-block; |
| 189 | vertical-align: middle; |
| 190 | flex-shrink: 0 |
| 191 | } |
| 192 | |
| 193 | /* ══ TOPBAR ═══════════════════════════════════════════════════════ */ |
| 194 | .topbar { |
| 195 | position: sticky; |
| 196 | top: 0; |
| 197 | z-index: 200; |
| 198 | display: flex; |
| 199 | align-items: center; |
| 200 | gap: 10px; |
| 201 | padding: 0 20px; |
| 202 | height: 58px; |
| 203 | background: var(--sf); |
| 204 | border-bottom: 1.5px solid var(--tl); |
| 205 | box-shadow: 0 2px 20px rgba(0, 0, 0, .45); |
| 206 | } |
| 207 | |
| 208 | .topbar-left { |
| 209 | display: flex; |
| 210 | align-items: center; |
| 211 | gap: 14px; |
| 212 | min-width: 0; |
| 213 | flex: 1 |
| 214 | } |
| 215 | |
| 216 | .brand { |
| 217 | display: flex; |
| 218 | align-items: center; |
| 219 | gap: 10px; |
| 220 | flex-shrink: 0 |
| 221 | } |
| 222 | |
| 223 | .brand-logo { |
| 224 | width: 38px; |
| 225 | height: 38px; |
| 226 | object-fit: contain; |
| 227 | filter: drop-shadow(0 0 10px rgba(43, 140, 255, .5)) |
| 228 | } |
| 229 | |
| 230 | .brand-text { |
| 231 | line-height: 1 |
| 232 | } |
| 233 | |
| 234 | .brand-title { |
| 235 | font-family: 'Syne', sans-serif; |
| 236 | font-weight: 800; |
| 237 | font-size: 16px; |
| 238 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 239 | -webkit-background-clip: text; |
| 240 | -webkit-text-fill-color: transparent; |
| 241 | background-clip: text; |
| 242 | white-space: nowrap; |
| 243 | letter-spacing: -.01em; |
| 244 | } |
| 245 | |
| 246 | .brand-sub { |
| 247 | font-size: 9px; |
| 248 | color: var(--tx3); |
| 249 | margin-top: 2px; |
| 250 | letter-spacing: .06em; |
| 251 | text-transform: uppercase |
| 252 | } |
| 253 | |
| 254 | .topbar-right { |
| 255 | display: flex; |
| 256 | align-items: center; |
| 257 | gap: 8px; |
| 258 | flex-shrink: 0 |
| 259 | } |
| 260 | |
| 261 | /* ══ STATUS ═══════════════════════════════════════════════════════ */ |
| 262 | .status-pill { |
| 263 | display: flex; |
| 264 | align-items: center; |
| 265 | gap: 6px; |
| 266 | font-size: 11px; |
| 267 | font-weight: 600; |
| 268 | padding: 5px 11px; |
| 269 | border-radius: 999px; |
| 270 | border: 1px solid var(--bd2); |
| 271 | background: var(--sf2); |
| 272 | transition: color .2s; |
| 273 | white-space: nowrap; |
| 274 | } |
| 275 | |
| 276 | .sdot { |
| 277 | width: 6px; |
| 278 | height: 6px; |
| 279 | border-radius: 50%; |
| 280 | flex-shrink: 0; |
| 281 | background: var(--tx3); |
| 282 | transition: all .2s |
| 283 | } |
| 284 | |
| 285 | .status-ok .sdot { |
| 286 | background: var(--ok); |
| 287 | box-shadow: 0 0 7px var(--ok) |
| 288 | } |
| 289 | |
| 290 | .status-bad .sdot { |
| 291 | background: var(--er); |
| 292 | box-shadow: 0 0 7px var(--er) |
| 293 | } |
| 294 | |
| 295 | .status-ok { |
| 296 | color: var(--ok) |
| 297 | } |
| 298 | |
| 299 | .status-bad { |
| 300 | color: var(--er) |
| 301 | } |
| 302 | |
| 303 | /* ══ STATS ════════════════════════════════════════════════════════ */ |
| 304 | .stats-w { |
| 305 | display: flex; |
| 306 | align-items: stretch; |
| 307 | background: var(--sf2); |
| 308 | border: 1px solid var(--bd2); |
| 309 | border-radius: 10px; |
| 310 | overflow: hidden; |
| 311 | cursor: pointer; |
| 312 | transition: border-color .15s; |
| 313 | position: relative; |
| 314 | } |
| 315 | |
| 316 | .stats-w:hover { |
| 317 | border-color: var(--ac) |
| 318 | } |
| 319 | |
| 320 | .sc { |
| 321 | display: flex; |
| 322 | flex-direction: column; |
| 323 | align-items: center; |
| 324 | justify-content: center; |
| 325 | gap: 1px; |
| 326 | padding: 5px 11px; |
| 327 | border-right: 1px solid var(--bd); |
| 328 | min-width: 55px |
| 329 | } |
| 330 | |
| 331 | .sc[data-k="disk"] { |
| 332 | min-width: 112px |
| 333 | } |
| 334 | |
| 335 | .sc[data-k="disk"] .sv { |
| 336 | font-size: 10px |
| 337 | } |
| 338 | |
| 339 | .sc:last-child { |
| 340 | border-right: none |
| 341 | } |
| 342 | |
| 343 | .sl { |
| 344 | font-size: 8px; |
| 345 | color: var(--tx3); |
| 346 | text-transform: uppercase; |
| 347 | letter-spacing: .08em; |
| 348 | white-space: nowrap |
| 349 | } |
| 350 | |
| 351 | .sv { |
| 352 | font-size: 11px; |
| 353 | font-weight: 700; |
| 354 | color: var(--tx); |
| 355 | line-height: 1.2 |
| 356 | } |
| 357 | |
| 358 | .sv.ok { |
| 359 | color: var(--ok) |
| 360 | } |
| 361 | |
| 362 | .sv.wn { |
| 363 | color: var(--wn) |
| 364 | } |
| 365 | |
| 366 | .sv.er { |
| 367 | color: var(--er) |
| 368 | } |
| 369 | |
| 370 | .sc-donut { |
| 371 | display: flex; |
| 372 | align-items: center; |
| 373 | justify-content: center; |
| 374 | padding: 5px 10px; |
| 375 | border-right: 1px solid var(--bd) |
| 376 | } |
| 377 | |
| 378 | .dw { |
| 379 | position: relative; |
| 380 | width: 28px; |
| 381 | height: 28px |
| 382 | } |
| 383 | |
| 384 | .dw svg { |
| 385 | transform: rotate(-90deg) |
| 386 | } |
| 387 | |
| 388 | .d-track { |
| 389 | fill: none; |
| 390 | stroke: var(--bd2); |
| 391 | stroke-width: 4.5 |
| 392 | } |
| 393 | |
| 394 | .d-fill { |
| 395 | fill: none; |
| 396 | stroke-width: 4.5; |
| 397 | stroke-linecap: round; |
| 398 | transition: stroke-dashoffset .7s cubic-bezier(.4, 0, .2, 1) |
| 399 | } |
| 400 | |
| 401 | .d-ctr { |
| 402 | position: absolute; |
| 403 | inset: 0; |
| 404 | display: flex; |
| 405 | align-items: center; |
| 406 | justify-content: center; |
| 407 | font-size: 7px; |
| 408 | font-weight: 700; |
| 409 | color: var(--ac) |
| 410 | } |
| 411 | |
| 412 | .stats-panel { |
| 413 | position: absolute; |
| 414 | top: calc(100% + 10px); |
| 415 | right: 0; |
| 416 | width: 276px; |
| 417 | background: var(--sf); |
| 418 | border: 1px solid var(--bd2); |
| 419 | border-radius: 14px; |
| 420 | padding: 16px; |
| 421 | box-shadow: 0 20px 60px rgba(0, 0, 0, .6); |
| 422 | display: none; |
| 423 | z-index: 500; |
| 424 | animation: popIn .15s ease; |
| 425 | } |
| 426 | |
| 427 | .stats-panel.show { |
| 428 | display: block |
| 429 | } |
| 430 | |
| 431 | .sp-hd { |
| 432 | font-family: 'Syne', sans-serif; |
| 433 | font-size: 12px; |
| 434 | font-weight: 700; |
| 435 | color: var(--ac); |
| 436 | margin-bottom: 14px; |
| 437 | display: flex; |
| 438 | align-items: center; |
| 439 | gap: 6px |
| 440 | } |
| 441 | |
| 442 | .sp-row { |
| 443 | display: flex; |
| 444 | align-items: center; |
| 445 | gap: 8px; |
| 446 | margin-bottom: 9px |
| 447 | } |
| 448 | |
| 449 | .sp-row.hi { |
| 450 | box-shadow: inset 0 0 0 1px var(--ac); |
| 451 | border-radius: 10px; |
| 452 | padding: 4px 6px; |
| 453 | margin-left: -6px; |
| 454 | margin-right: -6px |
| 455 | } |
| 456 | |
| 457 | .sp-lb { |
| 458 | font-size: 10px; |
| 459 | color: var(--tx2); |
| 460 | white-space: nowrap; |
| 461 | min-width: 68px |
| 462 | } |
| 463 | |
| 464 | .sp-vl { |
| 465 | font-size: 11px; |
| 466 | font-weight: 700; |
| 467 | color: var(--tx); |
| 468 | margin-left: auto; |
| 469 | white-space: nowrap |
| 470 | } |
| 471 | |
| 472 | .sp-bar { |
| 473 | height: 3px; |
| 474 | flex: 1; |
| 475 | background: var(--bd); |
| 476 | border-radius: 999px; |
| 477 | overflow: hidden; |
| 478 | min-width: 30px |
| 479 | } |
| 480 | |
| 481 | .sp-bf { |
| 482 | height: 100%; |
| 483 | border-radius: 999px; |
| 484 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 485 | transition: width .5s ease |
| 486 | } |
| 487 | |
| 488 | .sp-bf.hot { |
| 489 | background: linear-gradient(90deg, var(--wn), #ff6600) |
| 490 | } |
| 491 | |
| 492 | .sp-bf.full { |
| 493 | background: linear-gradient(90deg, var(--wn), var(--er)) |
| 494 | } |
| 495 | |
| 496 | .sp-div { |
| 497 | height: 1px; |
| 498 | background: var(--bd); |
| 499 | margin: 10px 0 |
| 500 | } |
| 501 | |
| 502 | /* ══ THEME DROPDOWN ═══════════════════════════════════════════════ */ |
| 503 | .theme-btn { |
| 504 | display: flex; |
| 505 | align-items: center; |
| 506 | gap: 7px; |
| 507 | border: 1px solid var(--bd2); |
| 508 | background: var(--sf2); |
| 509 | color: var(--tx2); |
| 510 | border-radius: 8px; |
| 511 | padding: 6px 11px; |
| 512 | font-family: inherit; |
| 513 | font-size: 11px; |
| 514 | font-weight: 600; |
| 515 | cursor: pointer; |
| 516 | transition: all .15s; |
| 517 | white-space: nowrap; |
| 518 | } |
| 519 | |
| 520 | .theme-btn:hover { |
| 521 | border-color: var(--ac); |
| 522 | color: var(--tx) |
| 523 | } |
| 524 | |
| 525 | .t-swatch { |
| 526 | width: 10px; |
| 527 | height: 10px; |
| 528 | border-radius: 50%; |
| 529 | flex-shrink: 0; |
| 530 | border: 1.5px solid rgba(255, 255, 255, .2) |
| 531 | } |
| 532 | |
| 533 | .t-arr { |
| 534 | transition: transform .15s; |
| 535 | color: var(--tx3) |
| 536 | } |
| 537 | |
| 538 | .theme-btn.open .t-arr { |
| 539 | transform: rotate(180deg) |
| 540 | } |
| 541 | |
| 542 | .theme-dd { |
| 543 | position: absolute; |
| 544 | top: calc(100% + 8px); |
| 545 | right: 0; |
| 546 | min-width: 210px; |
| 547 | background: var(--sf); |
| 548 | border: 1px solid var(--bd2); |
| 549 | border-radius: 14px; |
| 550 | padding: 8px; |
| 551 | box-shadow: 0 24px 64px rgba(0, 0, 0, .7); |
| 552 | display: none; |
| 553 | z-index: 600; |
| 554 | animation: popIn .15s ease; |
| 555 | } |
| 556 | |
| 557 | .theme-dd.show { |
| 558 | display: block |
| 559 | } |
| 560 | |
| 561 | .td-hd { |
| 562 | font-size: 9px; |
| 563 | color: var(--tx3); |
| 564 | text-transform: uppercase; |
| 565 | letter-spacing: .1em; |
| 566 | padding: 4px 8px 8px; |
| 567 | border-bottom: 1px solid var(--bd); |
| 568 | margin-bottom: 6px |
| 569 | } |
| 570 | |
| 571 | .td-item { |
| 572 | display: flex; |
| 573 | align-items: center; |
| 574 | gap: 10px; |
| 575 | padding: 8px 10px; |
| 576 | border-radius: 8px; |
| 577 | cursor: pointer; |
| 578 | color: var(--tx2); |
| 579 | transition: all .1s; |
| 580 | } |
| 581 | |
| 582 | .td-item:hover { |
| 583 | background: var(--sf2); |
| 584 | color: var(--tx) |
| 585 | } |
| 586 | |
| 587 | .td-item.active { |
| 588 | background: var(--gw); |
| 589 | color: var(--ac) |
| 590 | } |
| 591 | |
| 592 | .td-sw { |
| 593 | width: 26px; |
| 594 | height: 26px; |
| 595 | border-radius: 7px; |
| 596 | flex-shrink: 0; |
| 597 | border: 1px solid rgba(255, 255, 255, .1); |
| 598 | display: flex; |
| 599 | align-items: center; |
| 600 | justify-content: center |
| 601 | } |
| 602 | |
| 603 | .td-info { |
| 604 | display: flex; |
| 605 | flex-direction: column; |
| 606 | gap: 1px; |
| 607 | flex: 1; |
| 608 | min-width: 0 |
| 609 | } |
| 610 | |
| 611 | .td-nm { |
| 612 | font-weight: 600; |
| 613 | font-size: 12px |
| 614 | } |
| 615 | |
| 616 | .td-ds { |
| 617 | font-size: 10px; |
| 618 | color: var(--tx3) |
| 619 | } |
| 620 | |
| 621 | .td-ck { |
| 622 | color: var(--ac); |
| 623 | opacity: 0; |
| 624 | transition: opacity .1s; |
| 625 | flex-shrink: 0 |
| 626 | } |
| 627 | |
| 628 | .theme-dd .td-item.active .td-ck { |
| 629 | display: block |
| 630 | } |
| 631 | |
| 632 | .theme-switcher { |
| 633 | position: relative; |
| 634 | display: flex; |
| 635 | align-items: center; |
| 636 | } |
| 637 | |
| 638 | .theme-select-mobile { |
| 639 | display: none; |
| 640 | background: var(--sf2); |
| 641 | color: var(--tx); |
| 642 | border: 1px solid var(--bd); |
| 643 | border-radius: 8px; |
| 644 | padding: 6px 28px 6px 10px; |
| 645 | font-size: 12px; |
| 646 | font-family: 'JetBrains Mono', monospace; |
| 647 | appearance: none; |
| 648 | width: 120px; |
| 649 | } |
| 650 | |
| 651 | .theme-select-mobile:focus { |
| 652 | outline: 2px solid var(--ac); |
| 653 | outline-offset: 2px; |
| 654 | } |
| 655 | |
| 656 | @media (hover: none) and (pointer: coarse) { |
| 657 | .theme-btn { |
| 658 | display: none; |
| 659 | } |
| 660 | |
| 661 | .theme-select-mobile { |
| 662 | display: block; |
| 663 | } |
| 664 | |
| 665 | .theme-switcher { |
| 666 | margin-left: auto; |
| 667 | } |
| 668 | } |
| 669 | |
| 670 | /* ══ TOOLBAR ══════════════════════════════════════════════════════ */ |
| 671 | .toolbar { |
| 672 | display: flex; |
| 673 | align-items: center; |
| 674 | gap: 6px; |
| 675 | padding: 8px 20px; |
| 676 | background: var(--sf); |
| 677 | border-bottom: 1px solid var(--bd); |
| 678 | flex-wrap: wrap; |
| 679 | } |
| 680 | |
| 681 | .btn { |
| 682 | display: flex; |
| 683 | align-items: center; |
| 684 | gap: 5px; |
| 685 | border: 1px solid var(--bd2); |
| 686 | background: var(--sf2); |
| 687 | color: var(--tx2); |
| 688 | border-radius: 7px; |
| 689 | padding: 6px 11px; |
| 690 | font-size: 11px; |
| 691 | font-family: inherit; |
| 692 | font-weight: 600; |
| 693 | cursor: pointer; |
| 694 | transition: border-color .15s, background .15s, color .15s, transform .1s; |
| 695 | white-space: nowrap; |
| 696 | } |
| 697 | |
| 698 | .btn:hover { |
| 699 | border-color: var(--ac); |
| 700 | background: var(--sf3); |
| 701 | color: var(--tx) |
| 702 | } |
| 703 | |
| 704 | .btn:active { |
| 705 | transform: translateY(1px) |
| 706 | } |
| 707 | |
| 708 | .vg { |
| 709 | display: flex; |
| 710 | align-items: center; |
| 711 | border: 1px solid var(--bd2); |
| 712 | border-radius: 7px; |
| 713 | overflow: hidden |
| 714 | } |
| 715 | |
| 716 | .vg .vb { |
| 717 | background: var(--sf2); |
| 718 | color: var(--tx3); |
| 719 | border: none; |
| 720 | padding: 6px 10px; |
| 721 | cursor: pointer; |
| 722 | transition: background .1s, color .1s; |
| 723 | line-height: 1; |
| 724 | border-right: 1px solid var(--bd); |
| 725 | display: flex; |
| 726 | align-items: center; |
| 727 | justify-content: center; |
| 728 | } |
| 729 | |
| 730 | .vg .vb:last-child { |
| 731 | border-right: none |
| 732 | } |
| 733 | |
| 734 | .vg .vb:hover { |
| 735 | background: var(--sf3); |
| 736 | color: var(--tx) |
| 737 | } |
| 738 | |
| 739 | .vg .vb.active { |
| 740 | background: var(--gw); |
| 741 | color: var(--ac) |
| 742 | } |
| 743 | |
| 744 | .tb-sep { |
| 745 | width: 1px; |
| 746 | height: 22px; |
| 747 | background: var(--bd); |
| 748 | flex-shrink: 0; |
| 749 | margin: 0 2px |
| 750 | } |
| 751 | |
| 752 | .spacer { |
| 753 | flex: 1; |
| 754 | min-width: 8px |
| 755 | } |
| 756 | |
| 757 | .search-wrap { |
| 758 | position: relative; |
| 759 | display: flex; |
| 760 | align-items: center |
| 761 | } |
| 762 | |
| 763 | .search-ico { |
| 764 | position: absolute; |
| 765 | left: 9px; |
| 766 | pointer-events: none; |
| 767 | color: var(--tx3) |
| 768 | } |
| 769 | |
| 770 | .search { |
| 771 | width: 260px; |
| 772 | max-width: 48vw; |
| 773 | border: 1px solid var(--bd2); |
| 774 | background: var(--bg); |
| 775 | color: var(--tx); |
| 776 | border-radius: 7px; |
| 777 | padding: 6px 10px 6px 30px; |
| 778 | font-size: 11px; |
| 779 | font-family: inherit; |
| 780 | outline: none; |
| 781 | transition: border-color .15s; |
| 782 | } |
| 783 | |
| 784 | .search:focus { |
| 785 | border-color: var(--ac) |
| 786 | } |
| 787 | |
| 788 | .search::placeholder { |
| 789 | color: var(--tx3) |
| 790 | } |
| 791 | |
| 792 | /* ══ BREADCRUMB ═══════════════════════════════════════════════════ */ |
| 793 | .breadcrumb { |
| 794 | display: flex; |
| 795 | align-items: center; |
| 796 | gap: 2px; |
| 797 | padding: 6px 20px; |
| 798 | border-bottom: 1px solid var(--bd); |
| 799 | overflow-x: auto; |
| 800 | scrollbar-width: none; |
| 801 | background: var(--sf); |
| 802 | } |
| 803 | |
| 804 | .breadcrumb::-webkit-scrollbar { |
| 805 | display: none |
| 806 | } |
| 807 | |
| 808 | .crumb { |
| 809 | display: flex; |
| 810 | align-items: center; |
| 811 | gap: 5px; |
| 812 | color: var(--tx3); |
| 813 | font-size: 11px; |
| 814 | cursor: pointer; |
| 815 | padding: 3px 8px; |
| 816 | border-radius: 5px; |
| 817 | white-space: nowrap; |
| 818 | transition: color .1s, background .1s; |
| 819 | } |
| 820 | |
| 821 | .crumb:hover { |
| 822 | color: var(--tx); |
| 823 | background: var(--sf2) |
| 824 | } |
| 825 | |
| 826 | .crumb.act { |
| 827 | color: var(--ac); |
| 828 | font-weight: 600; |
| 829 | background: var(--gw) |
| 830 | } |
| 831 | |
| 832 | .cr-sep { |
| 833 | color: var(--bd2); |
| 834 | font-size: 11px; |
| 835 | user-select: none; |
| 836 | padding: 0 1px |
| 837 | } |
| 838 | |
| 839 | /* ══ CONTENT ══════════════════════════════════════════════════════ */ |
| 840 | .content { |
| 841 | padding: 14px 20px; |
| 842 | min-height: calc(100vh - 180px) |
| 843 | } |
| 844 | |
| 845 | .fl-header { |
| 846 | display: flex; |
| 847 | align-items: center; |
| 848 | margin-bottom: 12px |
| 849 | } |
| 850 | |
| 851 | .fl-count { |
| 852 | font-size: 11px; |
| 853 | color: var(--tx3) |
| 854 | } |
| 855 | |
| 856 | .fl-count b { |
| 857 | color: var(--ac); |
| 858 | font-weight: 700 |
| 859 | } |
| 860 | |
| 861 | /* File type icon wrappers */ |
| 862 | .fi-wrap { |
| 863 | width: 100%; |
| 864 | height: 100%; |
| 865 | display: flex; |
| 866 | align-items: center; |
| 867 | justify-content: center; |
| 868 | } |
| 869 | |
| 870 | /* Category colors */ |
| 871 | .fi-dir { |
| 872 | color: #4da6ff |
| 873 | } |
| 874 | |
| 875 | .fi-code { |
| 876 | color: #f7c948 |
| 877 | } |
| 878 | |
| 879 | .fi-web { |
| 880 | color: #4fc3f7 |
| 881 | } |
| 882 | |
| 883 | .fi-style { |
| 884 | color: #f06292 |
| 885 | } |
| 886 | |
| 887 | .fi-data { |
| 888 | color: #81c784 |
| 889 | } |
| 890 | |
| 891 | .fi-doc { |
| 892 | color: #90caf9 |
| 893 | } |
| 894 | |
| 895 | .fi-img { |
| 896 | color: #ce93d8 |
| 897 | } |
| 898 | |
| 899 | .fi-video { |
| 900 | color: #ff8a65 |
| 901 | } |
| 902 | |
| 903 | .fi-audio { |
| 904 | color: #a5d6a7 |
| 905 | } |
| 906 | |
| 907 | .fi-arch { |
| 908 | color: #ffb74d |
| 909 | } |
| 910 | |
| 911 | .fi-script { |
| 912 | color: #80cbc4 |
| 913 | } |
| 914 | |
| 915 | .fi-bin { |
| 916 | color: #ef9a9a |
| 917 | } |
| 918 | |
| 919 | .fi-db { |
| 920 | color: #80deea |
| 921 | } |
| 922 | |
| 923 | .fi-lock { |
| 924 | color: #ffe082 |
| 925 | } |
| 926 | |
| 927 | .fi-log { |
| 928 | color: #b0bec5 |
| 929 | } |
| 930 | |
| 931 | .fi-sheet { |
| 932 | color: #a5d6a7 |
| 933 | } |
| 934 | |
| 935 | .fi-slide { |
| 936 | color: #ffab40 |
| 937 | } |
| 938 | |
| 939 | .fi-generic { |
| 940 | color: var(--tx2) |
| 941 | } |
| 942 | |
| 943 | /* EXT + SIZE badges */ |
| 944 | .xb { |
| 945 | display: inline-flex; |
| 946 | align-items: center; |
| 947 | padding: 1px 6px; |
| 948 | border-radius: 4px; |
| 949 | font-size: 9px; |
| 950 | font-weight: 700; |
| 951 | letter-spacing: .04em; |
| 952 | text-transform: uppercase; |
| 953 | border: 1px solid var(--tgb); |
| 954 | background: var(--tg); |
| 955 | color: var(--ac); |
| 956 | white-space: nowrap; |
| 957 | flex-shrink: 0; |
| 958 | line-height: 1.7; |
| 959 | } |
| 960 | |
| 961 | .sb { |
| 962 | font-size: 10px; |
| 963 | color: var(--tx2); |
| 964 | white-space: nowrap; |
| 965 | flex-shrink: 0; |
| 966 | font-weight: 500 |
| 967 | } |
| 968 | |
| 969 | .db { |
| 970 | font-size: 10px; |
| 971 | color: var(--tx3); |
| 972 | white-space: nowrap; |
| 973 | flex-shrink: 0 |
| 974 | } |
| 975 | |
| 976 | /* ══ GRID VIEW ════════════════════════════════════════════════════ */ |
| 977 | .fl.vg-grid { |
| 978 | display: grid; |
| 979 | grid-template-columns: repeat(auto-fill, minmax(152px, 1fr)); |
| 980 | gap: 9px |
| 981 | } |
| 982 | |
| 983 | .fl.vg-grid .card { |
| 984 | display: flex; |
| 985 | flex-direction: column; |
| 986 | align-items: center; |
| 987 | gap: 8px; |
| 988 | padding: 16px 12px 11px; |
| 989 | border: 1px solid var(--bd); |
| 990 | background: var(--sf); |
| 991 | border-radius: 13px; |
| 992 | cursor: pointer; |
| 993 | text-align: center; |
| 994 | transition: border-color .15s, background .15s, transform .2s, box-shadow .2s; |
| 995 | position: relative; |
| 996 | overflow: hidden; |
| 997 | } |
| 998 | |
| 999 | .fl.vg-grid .card::before { |
| 1000 | content: ''; |
| 1001 | position: absolute; |
| 1002 | inset: 0; |
| 1003 | opacity: 0; |
| 1004 | pointer-events: none; |
| 1005 | background: radial-gradient(ellipse at 50% -10%, rgba(var(--acR), .18), transparent 65%); |
| 1006 | transition: opacity .2s; |
| 1007 | } |
| 1008 | |
| 1009 | .fl.vg-grid .card:hover { |
| 1010 | border-color: var(--ac); |
| 1011 | background: var(--sf2); |
| 1012 | transform: translateY(-3px); |
| 1013 | box-shadow: 0 10px 32px rgba(0, 0, 0, .4), 0 0 0 1px rgba(var(--acR), .35); |
| 1014 | } |
| 1015 | |
| 1016 | .fl.vg-grid .card:hover::before { |
| 1017 | opacity: 1 |
| 1018 | } |
| 1019 | |
| 1020 | .c-ico { |
| 1021 | width: 50px; |
| 1022 | height: 50px; |
| 1023 | border-radius: 13px; |
| 1024 | display: flex; |
| 1025 | align-items: center; |
| 1026 | justify-content: center; |
| 1027 | background: var(--gw); |
| 1028 | border: 1px solid rgba(255, 255, 255, .06); |
| 1029 | } |
| 1030 | |
| 1031 | .c-name { |
| 1032 | font-size: 12px; |
| 1033 | font-weight: 600; |
| 1034 | width: 100%; |
| 1035 | overflow: hidden; |
| 1036 | text-overflow: ellipsis; |
| 1037 | white-space: nowrap |
| 1038 | } |
| 1039 | |
| 1040 | .c-meta { |
| 1041 | display: flex; |
| 1042 | align-items: center; |
| 1043 | justify-content: center; |
| 1044 | gap: 5px; |
| 1045 | flex-wrap: wrap; |
| 1046 | width: 100%; |
| 1047 | min-height: 18px |
| 1048 | } |
| 1049 | |
| 1050 | /* ══ LIST VIEW ════════════════════════════════════════════════════ */ |
| 1051 | .fl.vg-list { |
| 1052 | display: flex; |
| 1053 | flex-direction: column; |
| 1054 | gap: 3px |
| 1055 | } |
| 1056 | |
| 1057 | .fl.vg-list .card { |
| 1058 | display: flex; |
| 1059 | align-items: center; |
| 1060 | gap: 10px; |
| 1061 | padding: 9px 14px; |
| 1062 | border: 1px solid var(--bd); |
| 1063 | background: var(--sf); |
| 1064 | border-radius: 9px; |
| 1065 | cursor: pointer; |
| 1066 | transition: border-color .12s, background .12s; |
| 1067 | } |
| 1068 | |
| 1069 | .fl.vg-list .card:hover { |
| 1070 | border-color: var(--ac); |
| 1071 | background: var(--sf2) |
| 1072 | } |
| 1073 | |
| 1074 | .fl.vg-list .c-ico { |
| 1075 | width: 32px; |
| 1076 | height: 32px; |
| 1077 | border-radius: 8px; |
| 1078 | flex-shrink: 0; |
| 1079 | background: var(--gw); |
| 1080 | border: 1px solid rgba(255, 255, 255, .05) |
| 1081 | } |
| 1082 | |
| 1083 | .fl.vg-list .c-name { |
| 1084 | font-size: 13px; |
| 1085 | font-weight: 600; |
| 1086 | flex: 1; |
| 1087 | overflow: hidden; |
| 1088 | text-overflow: ellipsis; |
| 1089 | white-space: nowrap |
| 1090 | } |
| 1091 | |
| 1092 | .c-right { |
| 1093 | display: flex; |
| 1094 | align-items: center; |
| 1095 | gap: 8px; |
| 1096 | flex-shrink: 0 |
| 1097 | } |
| 1098 | |
| 1099 | /* ══ DETAILS VIEW ═════════════════════════════════════════════════ */ |
| 1100 | .fl.vg-details { |
| 1101 | display: block |
| 1102 | } |
| 1103 | |
| 1104 | .dtbl { |
| 1105 | width: 100%; |
| 1106 | border-collapse: collapse |
| 1107 | } |
| 1108 | |
| 1109 | .dtbl thead th { |
| 1110 | text-align: left; |
| 1111 | font-size: 10px; |
| 1112 | font-weight: 600; |
| 1113 | color: var(--tx3); |
| 1114 | text-transform: uppercase; |
| 1115 | letter-spacing: .08em; |
| 1116 | padding: 8px 14px; |
| 1117 | border-bottom: 1px solid var(--bd2); |
| 1118 | cursor: pointer; |
| 1119 | user-select: none; |
| 1120 | white-space: nowrap; |
| 1121 | } |
| 1122 | |
| 1123 | .dtbl thead th:hover { |
| 1124 | color: var(--ac) |
| 1125 | } |
| 1126 | |
| 1127 | .sort-a { |
| 1128 | color: var(--ac); |
| 1129 | margin-left: 3px; |
| 1130 | font-size: 10px |
| 1131 | } |
| 1132 | |
| 1133 | .dtbl tbody tr { |
| 1134 | border-bottom: 1px solid var(--bd); |
| 1135 | cursor: pointer; |
| 1136 | transition: background .1s |
| 1137 | } |
| 1138 | |
| 1139 | .dtbl tbody tr:hover { |
| 1140 | background: var(--sf2) |
| 1141 | } |
| 1142 | |
| 1143 | .dtbl tbody td { |
| 1144 | padding: 9px 14px; |
| 1145 | font-size: 12px; |
| 1146 | vertical-align: middle |
| 1147 | } |
| 1148 | |
| 1149 | .t-ic { |
| 1150 | width: 36px; |
| 1151 | text-align: center |
| 1152 | } |
| 1153 | |
| 1154 | .t-nm { |
| 1155 | font-weight: 600; |
| 1156 | max-width: 280px; |
| 1157 | overflow: hidden; |
| 1158 | text-overflow: ellipsis; |
| 1159 | white-space: nowrap |
| 1160 | } |
| 1161 | |
| 1162 | .t-ex { |
| 1163 | width: 72px |
| 1164 | } |
| 1165 | |
| 1166 | .t-sz { |
| 1167 | width: 88px; |
| 1168 | color: var(--tx2); |
| 1169 | white-space: nowrap |
| 1170 | } |
| 1171 | |
| 1172 | .t-dt { |
| 1173 | color: var(--tx2); |
| 1174 | white-space: nowrap; |
| 1175 | font-size: 11px |
| 1176 | } |
| 1177 | |
| 1178 | .t-tp { |
| 1179 | width: 76px; |
| 1180 | color: var(--tx3); |
| 1181 | font-size: 11px; |
| 1182 | white-space: nowrap |
| 1183 | } |
| 1184 | |
| 1185 | /* ══ STATES ═══════════════════════════════════════════════════════ */ |
| 1186 | .s-card { |
| 1187 | grid-column: 1/-1; |
| 1188 | display: flex; |
| 1189 | flex-direction: column; |
| 1190 | align-items: center; |
| 1191 | justify-content: center; |
| 1192 | gap: 10px; |
| 1193 | padding: 52px 24px; |
| 1194 | border-radius: 14px; |
| 1195 | border: 1px solid var(--bd); |
| 1196 | background: var(--sf); |
| 1197 | color: var(--tx2); |
| 1198 | font-size: 13px; |
| 1199 | } |
| 1200 | |
| 1201 | .s-ico { |
| 1202 | opacity: .4; |
| 1203 | color: var(--tx2) |
| 1204 | } |
| 1205 | |
| 1206 | .s-err { |
| 1207 | border-color: rgba(255, 95, 87, .28); |
| 1208 | background: rgba(255, 95, 87, .05); |
| 1209 | color: #ffb0ab |
| 1210 | } |
| 1211 | |
| 1212 | .s-err .s-ico { |
| 1213 | opacity: .9; |
| 1214 | color: #ff8080 |
| 1215 | } |
| 1216 | |
| 1217 | @keyframes spin { |
| 1218 | to { |
| 1219 | transform: rotate(360deg) |
| 1220 | } |
| 1221 | } |
| 1222 | |
| 1223 | .loader { |
| 1224 | width: 22px; |
| 1225 | height: 22px; |
| 1226 | border-radius: 50%; |
| 1227 | border: 2px solid var(--bd2); |
| 1228 | border-top-color: var(--ac); |
| 1229 | animation: spin .7s linear infinite |
| 1230 | } |
| 1231 | |
| 1232 | /* ══ CTX MENU ═════════════════════════════════════════════════════ */ |
| 1233 | .ctx { |
| 1234 | position: fixed; |
| 1235 | z-index: 9999; |
| 1236 | background: var(--sf); |
| 1237 | border: 1px solid var(--bd2); |
| 1238 | border-radius: 12px; |
| 1239 | padding: 6px; |
| 1240 | min-width: 194px; |
| 1241 | box-shadow: 0 20px 60px rgba(0, 0, 0, .75); |
| 1242 | display: none |
| 1243 | } |
| 1244 | |
| 1245 | .ctx.on { |
| 1246 | display: block; |
| 1247 | animation: popIn .12s ease |
| 1248 | } |
| 1249 | |
| 1250 | @keyframes popIn { |
| 1251 | from { |
| 1252 | opacity: 0; |
| 1253 | transform: scale(.95) translateY(-4px) |
| 1254 | } |
| 1255 | |
| 1256 | to { |
| 1257 | opacity: 1; |
| 1258 | transform: none |
| 1259 | } |
| 1260 | } |
| 1261 | |
| 1262 | .ci { |
| 1263 | display: flex; |
| 1264 | align-items: center; |
| 1265 | gap: 9px; |
| 1266 | padding: 8px 10px; |
| 1267 | border-radius: 7px; |
| 1268 | cursor: pointer; |
| 1269 | font-size: 12px; |
| 1270 | font-weight: 500; |
| 1271 | color: var(--tx2); |
| 1272 | transition: background .1s, color .1s |
| 1273 | } |
| 1274 | |
| 1275 | .ci:hover { |
| 1276 | background: var(--sf2); |
| 1277 | color: var(--tx) |
| 1278 | } |
| 1279 | |
| 1280 | .ci.red:hover { |
| 1281 | background: rgba(255, 95, 87, .1); |
| 1282 | color: var(--er) |
| 1283 | } |
| 1284 | |
| 1285 | .ci-i { |
| 1286 | width: 18px; |
| 1287 | height: 18px; |
| 1288 | display: flex; |
| 1289 | align-items: center; |
| 1290 | justify-content: center; |
| 1291 | flex-shrink: 0 |
| 1292 | } |
| 1293 | |
| 1294 | .ci-l { |
| 1295 | flex: 1 |
| 1296 | } |
| 1297 | |
| 1298 | .c-sec { |
| 1299 | padding: 4px 10px 5px; |
| 1300 | font-size: 9px; |
| 1301 | color: var(--tx3); |
| 1302 | text-transform: uppercase; |
| 1303 | letter-spacing: .1em; |
| 1304 | white-space: nowrap; |
| 1305 | overflow: hidden; |
| 1306 | text-overflow: ellipsis; |
| 1307 | max-width: 192px |
| 1308 | } |
| 1309 | |
| 1310 | .c-sep { |
| 1311 | height: 1px; |
| 1312 | background: var(--bd); |
| 1313 | margin: 4px 0 |
| 1314 | } |
| 1315 | |
| 1316 | /* ══ DROP ═════════════════════════════════════════════════════════ */ |
| 1317 | .drop { |
| 1318 | position: fixed; |
| 1319 | inset: 0; |
| 1320 | display: none; |
| 1321 | align-items: center; |
| 1322 | justify-content: center; |
| 1323 | background: rgba(8, 11, 16, .82); |
| 1324 | backdrop-filter: blur(8px); |
| 1325 | z-index: 300 |
| 1326 | } |
| 1327 | |
| 1328 | .drop.on { |
| 1329 | display: flex; |
| 1330 | animation: fadeIn .15s ease |
| 1331 | } |
| 1332 | |
| 1333 | .drop-card { |
| 1334 | width: min(460px, 88vw); |
| 1335 | text-align: center; |
| 1336 | border: 2px dashed var(--ac); |
| 1337 | border-radius: 20px; |
| 1338 | padding: 32px 24px; |
| 1339 | background: var(--sf) |
| 1340 | } |
| 1341 | |
| 1342 | .d-ico { |
| 1343 | margin-bottom: 14px; |
| 1344 | opacity: .85; |
| 1345 | color: var(--ac) |
| 1346 | } |
| 1347 | |
| 1348 | .d-title { |
| 1349 | font-family: 'Syne', sans-serif; |
| 1350 | font-weight: 800; |
| 1351 | font-size: 20px; |
| 1352 | margin-bottom: 6px |
| 1353 | } |
| 1354 | |
| 1355 | .d-sub { |
| 1356 | color: var(--tx2); |
| 1357 | font-size: 12px; |
| 1358 | margin-bottom: 16px |
| 1359 | } |
| 1360 | |
| 1361 | .d-bar { |
| 1362 | height: 6px; |
| 1363 | border-radius: 999px; |
| 1364 | background: var(--bd); |
| 1365 | overflow: hidden |
| 1366 | } |
| 1367 | |
| 1368 | .d-bf { |
| 1369 | height: 100%; |
| 1370 | width: 0%; |
| 1371 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 1372 | transition: width .1s ease |
| 1373 | } |
| 1374 | |
| 1375 | .drop-close { |
| 1376 | position: absolute; |
| 1377 | top: 12px; |
| 1378 | right: 12px; |
| 1379 | background: none; |
| 1380 | border: none; |
| 1381 | color: var(--tx2); |
| 1382 | font-size: 24px; |
| 1383 | cursor: pointer; |
| 1384 | padding: 0; |
| 1385 | width: 28px; |
| 1386 | height: 28px; |
| 1387 | display: flex; |
| 1388 | align-items: center; |
| 1389 | justify-content: center; |
| 1390 | border-radius: 6px; |
| 1391 | transition: all .15s ease |
| 1392 | } |
| 1393 | |
| 1394 | .drop-close:hover { |
| 1395 | background: var(--bd); |
| 1396 | color: var(--tx) |
| 1397 | } |
| 1398 | |
| 1399 | .drop-card { |
| 1400 | position: relative |
| 1401 | } |
| 1402 | |
| 1403 | .d-stats { |
| 1404 | margin-top: 16px; |
| 1405 | padding-top: 16px; |
| 1406 | border-top: 1px solid var(--bd); |
| 1407 | text-align: left; |
| 1408 | font-size: 12px |
| 1409 | } |
| 1410 | |
| 1411 | .d-stat-row { |
| 1412 | display: flex; |
| 1413 | justify-content: space-between; |
| 1414 | align-items: center; |
| 1415 | margin-bottom: 8px; |
| 1416 | gap: 12px |
| 1417 | } |
| 1418 | |
| 1419 | .d-stat-row:last-child { |
| 1420 | margin-bottom: 0 |
| 1421 | } |
| 1422 | |
| 1423 | .d-stat-label { |
| 1424 | color: var(--tx2); |
| 1425 | font-weight: 600; |
| 1426 | min-width: 50px |
| 1427 | } |
| 1428 | |
| 1429 | .d-stat-val { |
| 1430 | color: var(--tx); |
| 1431 | font-family: 'JetBrains Mono', monospace; |
| 1432 | font-weight: 500; |
| 1433 | text-align: right; |
| 1434 | flex: 1 |
| 1435 | } |
| 1436 | |
| 1437 | /* ══ TOAST ════════════════════════════════════════════════════════ */ |
| 1438 | .toast { |
| 1439 | position: fixed; |
| 1440 | bottom: 20px; |
| 1441 | right: 20px; |
| 1442 | z-index: 9000; |
| 1443 | display: flex; |
| 1444 | align-items: center; |
| 1445 | gap: 8px; |
| 1446 | padding: 9px 14px; |
| 1447 | border-radius: 10px; |
| 1448 | background: var(--sf); |
| 1449 | border: 1px solid var(--bd2); |
| 1450 | font-size: 11px; |
| 1451 | font-weight: 600; |
| 1452 | box-shadow: 0 8px 32px rgba(0, 0, 0, .5); |
| 1453 | animation: notifIn .2s ease; |
| 1454 | max-width: 300px |
| 1455 | } |
| 1456 | |
| 1457 | .toast.ok { |
| 1458 | border-color: var(--ok); |
| 1459 | color: var(--ok) |
| 1460 | } |
| 1461 | |
| 1462 | .toast.er { |
| 1463 | border-color: var(--er); |
| 1464 | color: var(--er) |
| 1465 | } |
| 1466 | |
| 1467 | @keyframes notifIn { |
| 1468 | from { |
| 1469 | opacity: 0; |
| 1470 | transform: translateY(8px) |
| 1471 | } |
| 1472 | |
| 1473 | to { |
| 1474 | opacity: 1; |
| 1475 | transform: none |
| 1476 | } |
| 1477 | } |
| 1478 | |
| 1479 | @keyframes fadeIn { |
| 1480 | from { |
| 1481 | opacity: 0 |
| 1482 | } |
| 1483 | |
| 1484 | to { |
| 1485 | opacity: 1 |
| 1486 | } |
| 1487 | } |
| 1488 | |
| 1489 | /* ══ SEND-TO MODAL ════════════════════════════════════════════════ */ |
| 1490 | .send-modal { |
| 1491 | position: fixed; |
| 1492 | inset: 0; |
| 1493 | z-index: 10000; |
| 1494 | display: none; |
| 1495 | align-items: center; |
| 1496 | justify-content: center; |
| 1497 | background: rgba(8, 11, 16, .78); |
| 1498 | backdrop-filter: blur(6px); |
| 1499 | } |
| 1500 | |
| 1501 | .send-modal.on { |
| 1502 | display: flex; |
| 1503 | animation: fadeIn .15s ease |
| 1504 | } |
| 1505 | |
| 1506 | .sm-panel { |
| 1507 | width: min(520px, 90vw); |
| 1508 | max-height: 76vh; |
| 1509 | display: flex; |
| 1510 | flex-direction: column; |
| 1511 | background: var(--sf); |
| 1512 | border: 1px solid var(--bd2); |
| 1513 | border-radius: 16px; |
| 1514 | box-shadow: 0 28px 80px rgba(0, 0, 0, .7); |
| 1515 | overflow: hidden; |
| 1516 | } |
| 1517 | |
| 1518 | .sm-header { |
| 1519 | display: flex; |
| 1520 | align-items: center; |
| 1521 | gap: 10px; |
| 1522 | padding: 14px 18px; |
| 1523 | border-bottom: 1px solid var(--bd); |
| 1524 | font-family: 'Syne', sans-serif; |
| 1525 | font-size: 14px; |
| 1526 | font-weight: 700; |
| 1527 | color: var(--ac); |
| 1528 | } |
| 1529 | |
| 1530 | .sm-header .sm-close { |
| 1531 | margin-left: auto; |
| 1532 | background: none; |
| 1533 | border: none; |
| 1534 | color: var(--tx3); |
| 1535 | cursor: pointer; |
| 1536 | font-size: 18px; |
| 1537 | line-height: 1; |
| 1538 | padding: 4px; |
| 1539 | } |
| 1540 | |
| 1541 | .sm-header .sm-close:hover { |
| 1542 | color: var(--er) |
| 1543 | } |
| 1544 | |
| 1545 | .sm-crumb { |
| 1546 | display: flex; |
| 1547 | align-items: center; |
| 1548 | gap: 2px; |
| 1549 | padding: 8px 18px; |
| 1550 | border-bottom: 1px solid var(--bd); |
| 1551 | overflow-x: auto; |
| 1552 | scrollbar-width: none; |
| 1553 | background: var(--sf2); |
| 1554 | } |
| 1555 | |
| 1556 | .sm-crumb::-webkit-scrollbar { |
| 1557 | display: none |
| 1558 | } |
| 1559 | |
| 1560 | .sm-body { |
| 1561 | flex: 1; |
| 1562 | overflow-y: auto; |
| 1563 | padding: 6px 0; |
| 1564 | min-height: 180px; |
| 1565 | max-height: 46vh; |
| 1566 | } |
| 1567 | |
| 1568 | .sm-row { |
| 1569 | display: flex; |
| 1570 | align-items: center; |
| 1571 | gap: 10px; |
| 1572 | padding: 9px 18px; |
| 1573 | cursor: pointer; |
| 1574 | color: var(--tx2); |
| 1575 | transition: background .1s, color .1s; |
| 1576 | } |
| 1577 | |
| 1578 | .sm-row:hover { |
| 1579 | background: var(--sf2); |
| 1580 | color: var(--tx) |
| 1581 | } |
| 1582 | |
| 1583 | .sm-row.active { |
| 1584 | background: var(--gw); |
| 1585 | color: var(--ac) |
| 1586 | } |
| 1587 | |
| 1588 | .sm-row-ico { |
| 1589 | width: 22px; |
| 1590 | height: 22px; |
| 1591 | display: flex; |
| 1592 | align-items: center; |
| 1593 | justify-content: center; |
| 1594 | color: #4da6ff; |
| 1595 | flex-shrink: 0 |
| 1596 | } |
| 1597 | |
| 1598 | .sm-row-name { |
| 1599 | font-size: 12px; |
| 1600 | font-weight: 600; |
| 1601 | overflow: hidden; |
| 1602 | text-overflow: ellipsis; |
| 1603 | white-space: nowrap |
| 1604 | } |
| 1605 | |
| 1606 | .sm-empty { |
| 1607 | padding: 28px; |
| 1608 | text-align: center; |
| 1609 | color: var(--tx3); |
| 1610 | font-size: 12px |
| 1611 | } |
| 1612 | |
| 1613 | .sm-footer { |
| 1614 | display: flex; |
| 1615 | align-items: center; |
| 1616 | justify-content: flex-end; |
| 1617 | gap: 8px; |
| 1618 | padding: 12px 18px; |
| 1619 | border-top: 1px solid var(--bd); |
| 1620 | } |
| 1621 | |
| 1622 | .sm-footer .btn.primary { |
| 1623 | background: var(--ac); |
| 1624 | color: #fff; |
| 1625 | border-color: var(--ac); |
| 1626 | } |
| 1627 | |
| 1628 | .sm-footer .btn.primary:hover { |
| 1629 | filter: brightness(1.15) |
| 1630 | } |
| 1631 | |
| 1632 | /* ══ TRANSFER TRAY ═══════════════════════════════════════════════ */ |
| 1633 | .xfer-tray { |
| 1634 | position: fixed; |
| 1635 | bottom: 20px; |
| 1636 | right: 20px; |
| 1637 | z-index: 8500; |
| 1638 | display: flex; |
| 1639 | flex-direction: column; |
| 1640 | gap: 8px; |
| 1641 | pointer-events: none; |
| 1642 | max-width: 340px; |
| 1643 | } |
| 1644 | |
| 1645 | .xfer-card { |
| 1646 | pointer-events: auto; |
| 1647 | background: var(--sf); |
| 1648 | border: 1px solid var(--bd2); |
| 1649 | border-radius: 12px; |
| 1650 | padding: 12px 14px; |
| 1651 | box-shadow: 0 10px 40px rgba(0, 0, 0, .55); |
| 1652 | animation: notifIn .2s ease; |
| 1653 | min-width: 280px; |
| 1654 | } |
| 1655 | |
| 1656 | .xc-top { |
| 1657 | display: flex; |
| 1658 | align-items: center; |
| 1659 | gap: 8px; |
| 1660 | margin-bottom: 4px |
| 1661 | } |
| 1662 | |
| 1663 | .xc-op { |
| 1664 | font-size: 11px; |
| 1665 | font-weight: 700; |
| 1666 | color: var(--ac); |
| 1667 | text-transform: uppercase; |
| 1668 | letter-spacing: .06em |
| 1669 | } |
| 1670 | |
| 1671 | .xc-speed { |
| 1672 | margin-left: auto; |
| 1673 | font-size: 11px; |
| 1674 | font-weight: 600; |
| 1675 | color: var(--tx2) |
| 1676 | } |
| 1677 | |
| 1678 | .xc-time { |
| 1679 | font-size: 11px; |
| 1680 | color: var(--tx3); |
| 1681 | margin-left: 4px |
| 1682 | } |
| 1683 | |
| 1684 | .xc-pct { |
| 1685 | font-size: 11px; |
| 1686 | font-weight: 700; |
| 1687 | color: var(--ok) |
| 1688 | } |
| 1689 | |
| 1690 | .xc-name { |
| 1691 | font-size: 12px; |
| 1692 | color: var(--tx); |
| 1693 | font-weight: 600; |
| 1694 | overflow: hidden; |
| 1695 | text-overflow: ellipsis; |
| 1696 | white-space: nowrap; |
| 1697 | margin-bottom: 2px |
| 1698 | } |
| 1699 | |
| 1700 | .xc-dest { |
| 1701 | font-size: 11px; |
| 1702 | color: var(--tx2); |
| 1703 | overflow: hidden; |
| 1704 | text-overflow: ellipsis; |
| 1705 | white-space: nowrap; |
| 1706 | margin-bottom: 6px; |
| 1707 | opacity: .75 |
| 1708 | } |
| 1709 | |
| 1710 | .xc-dest .xc-arrow { |
| 1711 | color: var(--ac); |
| 1712 | font-weight: 700 |
| 1713 | } |
| 1714 | |
| 1715 | .xc-bar { |
| 1716 | height: 5px; |
| 1717 | border-radius: 999px; |
| 1718 | background: var(--bd); |
| 1719 | overflow: hidden; |
| 1720 | margin-bottom: 8px |
| 1721 | } |
| 1722 | |
| 1723 | .xc-bf { |
| 1724 | height: 100%; |
| 1725 | border-radius: 999px; |
| 1726 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 1727 | transition: width .15s ease |
| 1728 | } |
| 1729 | |
| 1730 | .xc-btns { |
| 1731 | display: flex; |
| 1732 | gap: 6px; |
| 1733 | justify-content: center |
| 1734 | } |
| 1735 | |
| 1736 | .xc-btn { |
| 1737 | display: flex; |
| 1738 | align-items: center; |
| 1739 | justify-content: center; |
| 1740 | gap: 5px; |
| 1741 | padding: 5px 16px; |
| 1742 | border-radius: 7px; |
| 1743 | font-family: inherit; |
| 1744 | font-size: 11px; |
| 1745 | font-weight: 700; |
| 1746 | cursor: pointer; |
| 1747 | transition: all .12s; |
| 1748 | border: none; |
| 1749 | } |
| 1750 | |
| 1751 | .xc-btn.pause { |
| 1752 | background: var(--sf2); |
| 1753 | color: var(--wn); |
| 1754 | border: 1px solid var(--bd2) |
| 1755 | } |
| 1756 | |
| 1757 | .xc-btn.pause:hover { |
| 1758 | background: var(--sf3); |
| 1759 | border-color: var(--wn) |
| 1760 | } |
| 1761 | |
| 1762 | .xc-btn.cancel { |
| 1763 | background: rgba(255, 95, 87, .12); |
| 1764 | color: var(--er); |
| 1765 | border: 1px solid rgba(255, 95, 87, .25) |
| 1766 | } |
| 1767 | |
| 1768 | .xc-btn.cancel:hover { |
| 1769 | background: rgba(255, 95, 87, .22) |
| 1770 | } |
| 1771 | |
| 1772 | /* ══ INDETERMINATE PROGRESS BAR ════════════════════════════════ */ |
| 1773 | @keyframes xferPulse { |
| 1774 | 0% { |
| 1775 | left: -40%; |
| 1776 | width: 40% |
| 1777 | } |
| 1778 | |
| 1779 | 50% { |
| 1780 | left: 30%; |
| 1781 | width: 50% |
| 1782 | } |
| 1783 | |
| 1784 | 100% { |
| 1785 | left: 100%; |
| 1786 | width: 40% |
| 1787 | } |
| 1788 | } |
| 1789 | |
| 1790 | .xc-bf.indeterminate { |
| 1791 | position: relative; |
| 1792 | width: 100% !important; |
| 1793 | background: var(--bd); |
| 1794 | } |
| 1795 | |
| 1796 | .xc-bf.indeterminate::after { |
| 1797 | content: ''; |
| 1798 | position: absolute; |
| 1799 | top: 0; |
| 1800 | bottom: 0; |
| 1801 | border-radius: 999px; |
| 1802 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 1803 | animation: xferPulse 1.5s ease-in-out infinite; |
| 1804 | } |
| 1805 | |
| 1806 | /* ══ MOBILE ACTION BUTTON (three-dot) ═════════════════════════ */ |
| 1807 | .c-action { |
| 1808 | display: none; |
| 1809 | /* hidden on desktop */ |
| 1810 | align-items: center; |
| 1811 | justify-content: center; |
| 1812 | width: 28px; |
| 1813 | height: 28px; |
| 1814 | border-radius: 6px; |
| 1815 | border: 1px solid var(--bd2); |
| 1816 | background: var(--sf2); |
| 1817 | color: var(--tx2); |
| 1818 | font-size: 16px; |
| 1819 | font-weight: 700; |
| 1820 | cursor: pointer; |
| 1821 | flex-shrink: 0; |
| 1822 | line-height: 1; |
| 1823 | letter-spacing: 1px; |
| 1824 | } |
| 1825 | |
| 1826 | .c-action:hover { |
| 1827 | border-color: var(--ac); |
| 1828 | color: var(--tx) |
| 1829 | } |
| 1830 | |
| 1831 | /* ══ RESPONSIVE — MOBILE ══════════════════════════════════════ */ |
| 1832 | @media (max-width: 768px) { |
| 1833 | |
| 1834 | /* ── Topbar ── */ |
| 1835 | .topbar { |
| 1836 | flex-wrap: wrap; |
| 1837 | height: auto; |
| 1838 | padding: 8px 12px; |
| 1839 | gap: 6px; |
| 1840 | } |
| 1841 | |
| 1842 | .topbar-left { |
| 1843 | flex: 0 0 auto; |
| 1844 | min-width: 0; |
| 1845 | } |
| 1846 | |
| 1847 | .brand-sub { |
| 1848 | display: none |
| 1849 | } |
| 1850 | |
| 1851 | .brand-logo { |
| 1852 | width: 30px; |
| 1853 | height: 30px |
| 1854 | } |
| 1855 | |
| 1856 | .brand-title { |
| 1857 | font-size: 14px |
| 1858 | } |
| 1859 | |
| 1860 | .topbar-right { |
| 1861 | flex: 1 1 auto; |
| 1862 | justify-content: flex-end; |
| 1863 | overflow-x: auto; |
| 1864 | gap: 5px; |
| 1865 | } |
| 1866 | |
| 1867 | .stats-w { |
| 1868 | order: 1 |
| 1869 | } |
| 1870 | |
| 1871 | .sc { |
| 1872 | padding: 3px 7px; |
| 1873 | min-width: 40px |
| 1874 | } |
| 1875 | |
| 1876 | .sc[data-k="disk"] { |
| 1877 | min-width: 80px |
| 1878 | } |
| 1879 | |
| 1880 | .sc[data-k="disk"] .sv { |
| 1881 | font-size: 9px |
| 1882 | } |
| 1883 | |
| 1884 | .sl { |
| 1885 | font-size: 7px |
| 1886 | } |
| 1887 | |
| 1888 | .sv { |
| 1889 | font-size: 10px |
| 1890 | } |
| 1891 | |
| 1892 | .sc-donut { |
| 1893 | padding: 3px 6px |
| 1894 | } |
| 1895 | |
| 1896 | .dw { |
| 1897 | width: 24px; |
| 1898 | height: 24px |
| 1899 | } |
| 1900 | |
| 1901 | .d-ctr { |
| 1902 | font-size: 6px |
| 1903 | } |
| 1904 | |
| 1905 | .theme-btn { |
| 1906 | padding: 4px 7px; |
| 1907 | font-size: 10px |
| 1908 | } |
| 1909 | |
| 1910 | .status-pill { |
| 1911 | font-size: 10px; |
| 1912 | padding: 3px 8px; |
| 1913 | order: 2 |
| 1914 | } |
| 1915 | |
| 1916 | /* ── Toolbar ── */ |
| 1917 | .toolbar { |
| 1918 | padding: 6px 12px; |
| 1919 | gap: 4px |
| 1920 | } |
| 1921 | |
| 1922 | .btn { |
| 1923 | padding: 5px 8px; |
| 1924 | font-size: 10px |
| 1925 | } |
| 1926 | |
| 1927 | .search { |
| 1928 | width: 100%; |
| 1929 | max-width: none |
| 1930 | } |
| 1931 | |
| 1932 | .search-wrap { |
| 1933 | flex: 1 1 100%; |
| 1934 | order: 10 |
| 1935 | } |
| 1936 | |
| 1937 | /* ── Breadcrumb ── */ |
| 1938 | .breadcrumb { |
| 1939 | padding: 4px 12px |
| 1940 | } |
| 1941 | |
| 1942 | .crumb { |
| 1943 | font-size: 10px; |
| 1944 | padding: 2px 6px |
| 1945 | } |
| 1946 | |
| 1947 | /* ── Content ── */ |
| 1948 | .content { |
| 1949 | padding: 10px 12px |
| 1950 | } |
| 1951 | |
| 1952 | .fl.vg-grid { |
| 1953 | grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); |
| 1954 | gap: 6px |
| 1955 | } |
| 1956 | |
| 1957 | .fl.vg-grid .card { |
| 1958 | padding: 12px 8px 8px |
| 1959 | } |
| 1960 | |
| 1961 | .c-ico { |
| 1962 | width: 40px; |
| 1963 | height: 40px |
| 1964 | } |
| 1965 | |
| 1966 | .c-name { |
| 1967 | font-size: 11px |
| 1968 | } |
| 1969 | |
| 1970 | .c-meta { |
| 1971 | font-size: 9px |
| 1972 | } |
| 1973 | |
| 1974 | /* ── Show mobile action button ── */ |
| 1975 | .c-action { |
| 1976 | display: flex |
| 1977 | } |
| 1978 | |
| 1979 | /* ── Transfer tray ── */ |
| 1980 | .xfer-tray { |
| 1981 | left: 10px; |
| 1982 | right: 10px; |
| 1983 | max-width: none; |
| 1984 | bottom: 10px |
| 1985 | } |
| 1986 | |
| 1987 | .xfer-card { |
| 1988 | min-width: 0 |
| 1989 | } |
| 1990 | |
| 1991 | /* ── Context menu ── */ |
| 1992 | .ctx { |
| 1993 | min-width: 170px |
| 1994 | } |
| 1995 | |
| 1996 | /* ── Send-to modal ── */ |
| 1997 | .sm-panel { |
| 1998 | width: 96vw; |
| 1999 | max-height: 82vh |
| 2000 | } |
| 2001 | |
| 2002 | /* ── Stats panel ── */ |
| 2003 | .stats-panel { |
| 2004 | right: -40px; |
| 2005 | width: 260px |
| 2006 | } |
| 2007 | } |
| 2008 | |
| 2009 | @media (max-width: 400px) { |
| 2010 | .topbar-right { |
| 2011 | flex-wrap: nowrap |
| 2012 | } |
| 2013 | |
| 2014 | .sc[data-k="disk"] .sv { |
| 2015 | font-size: 8px |
| 2016 | } |
| 2017 | |
| 2018 | .fl.vg-grid { |
| 2019 | grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)) |
| 2020 | } |
| 2021 | } |
| 2022 | |
| 2023 | /* ══ STATS MODAL ══════════════════════════════════════════════ */ |
| 2024 | @keyframes smSlideUp { |
| 2025 | from { |
| 2026 | opacity: 0; |
| 2027 | transform: translateY(40px) |
| 2028 | } |
| 2029 | |
| 2030 | to { |
| 2031 | opacity: 1; |
| 2032 | transform: translateY(0) |
| 2033 | } |
| 2034 | } |
| 2035 | |
| 2036 | @keyframes smSlideDown { |
| 2037 | from { |
| 2038 | opacity: 1; |
| 2039 | transform: translateY(0) |
| 2040 | } |
| 2041 | |
| 2042 | to { |
| 2043 | opacity: 0; |
| 2044 | transform: translateY(40px) |
| 2045 | } |
| 2046 | } |
| 2047 | |
| 2048 | @keyframes smFadeTab { |
| 2049 | from { |
| 2050 | opacity: 0 |
| 2051 | } |
| 2052 | |
| 2053 | to { |
| 2054 | opacity: 1 |
| 2055 | } |
| 2056 | } |
| 2057 | |
| 2058 | @keyframes smPulse { |
| 2059 | |
| 2060 | 0%, |
| 2061 | 100% { |
| 2062 | opacity: 1 |
| 2063 | } |
| 2064 | |
| 2065 | 50% { |
| 2066 | opacity: .3 |
| 2067 | } |
| 2068 | } |
| 2069 | |
| 2070 | @keyframes smToastIn { |
| 2071 | from { |
| 2072 | opacity: 0; |
| 2073 | transform: translateX(60px) |
| 2074 | } |
| 2075 | |
| 2076 | to { |
| 2077 | opacity: 1; |
| 2078 | transform: translateX(0) |
| 2079 | } |
| 2080 | } |
| 2081 | |
| 2082 | @keyframes smToastOut { |
| 2083 | from { |
| 2084 | opacity: 1; |
| 2085 | transform: translateX(0) |
| 2086 | } |
| 2087 | |
| 2088 | to { |
| 2089 | opacity: 0; |
| 2090 | transform: translateX(60px) |
| 2091 | } |
| 2092 | } |
| 2093 | |
| 2094 | .smo-overlay { |
| 2095 | position: fixed; |
| 2096 | inset: 0; |
| 2097 | z-index: 5000; |
| 2098 | background: rgba(0, 0, 0, .72); |
| 2099 | backdrop-filter: blur(6px); |
| 2100 | display: flex; |
| 2101 | align-items: flex-end; |
| 2102 | justify-content: center; |
| 2103 | padding: 0; |
| 2104 | opacity: 0; |
| 2105 | pointer-events: none; |
| 2106 | transition: opacity .28s ease; |
| 2107 | } |
| 2108 | |
| 2109 | .smo-overlay.smo-open { |
| 2110 | opacity: 1; |
| 2111 | pointer-events: auto; |
| 2112 | } |
| 2113 | |
| 2114 | .smo-modal { |
| 2115 | width: 100%; |
| 2116 | max-width: 1280px; |
| 2117 | height: 88vh; |
| 2118 | max-height: 900px; |
| 2119 | display: flex; |
| 2120 | flex-direction: column; |
| 2121 | background: var(--sf); |
| 2122 | border: 1px solid var(--bd2); |
| 2123 | border-radius: 18px 18px 0 0; |
| 2124 | box-shadow: 0 -20px 80px rgba(0, 0, 0, .6); |
| 2125 | overflow: hidden; |
| 2126 | transform: translateY(40px); |
| 2127 | opacity: 0; |
| 2128 | transition: transform .28s cubic-bezier(.22, 1, .36, 1), opacity .28s ease; |
| 2129 | } |
| 2130 | |
| 2131 | .smo-overlay.smo-open .smo-modal { |
| 2132 | transform: translateY(0); |
| 2133 | opacity: 1; |
| 2134 | } |
| 2135 | |
| 2136 | .smo-modal.smo-closing { |
| 2137 | transform: translateY(40px); |
| 2138 | opacity: 0; |
| 2139 | transition: transform .2s ease-in, opacity .2s ease-in; |
| 2140 | } |
| 2141 | |
| 2142 | /* ── Modal header ── */ |
| 2143 | .smo-head { |
| 2144 | display: flex; |
| 2145 | align-items: center; |
| 2146 | gap: 10px; |
| 2147 | padding: 14px 20px 0; |
| 2148 | flex-shrink: 0; |
| 2149 | } |
| 2150 | |
| 2151 | .smo-title { |
| 2152 | font-family: 'Syne', sans-serif; |
| 2153 | font-size: 15px; |
| 2154 | font-weight: 800; |
| 2155 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 2156 | -webkit-background-clip: text; |
| 2157 | -webkit-text-fill-color: transparent; |
| 2158 | background-clip: text; |
| 2159 | letter-spacing: -.01em; |
| 2160 | } |
| 2161 | |
| 2162 | .smo-head-btns { |
| 2163 | margin-left: auto; |
| 2164 | display: flex; |
| 2165 | gap: 6px; |
| 2166 | } |
| 2167 | |
| 2168 | .smo-btn-icon { |
| 2169 | background: none; |
| 2170 | border: 1px solid var(--bd2); |
| 2171 | color: var(--tx2); |
| 2172 | border-radius: 7px; |
| 2173 | width: 30px; |
| 2174 | height: 30px; |
| 2175 | display: flex; |
| 2176 | align-items: center; |
| 2177 | justify-content: center; |
| 2178 | cursor: pointer; |
| 2179 | font-size: 14px; |
| 2180 | transition: border-color .15s, color .15s; |
| 2181 | font-family: inherit; |
| 2182 | } |
| 2183 | |
| 2184 | .smo-btn-icon:hover { |
| 2185 | border-color: var(--ac); |
| 2186 | color: var(--tx); |
| 2187 | } |
| 2188 | |
| 2189 | .smo-btn-icon.smo-close:hover { |
| 2190 | border-color: var(--er); |
| 2191 | color: var(--er); |
| 2192 | } |
| 2193 | |
| 2194 | /* ── Tabs ── */ |
| 2195 | .smo-tabs { |
| 2196 | display: flex; |
| 2197 | gap: 2px; |
| 2198 | padding: 10px 20px 0; |
| 2199 | border-bottom: 1px solid var(--bd); |
| 2200 | flex-shrink: 0; |
| 2201 | } |
| 2202 | |
| 2203 | .smo-tab { |
| 2204 | padding: 7px 16px; |
| 2205 | font-size: 11px; |
| 2206 | font-weight: 600; |
| 2207 | color: var(--tx2); |
| 2208 | border-radius: 7px 7px 0 0; |
| 2209 | cursor: pointer; |
| 2210 | border: 1px solid transparent; |
| 2211 | border-bottom: none; |
| 2212 | margin-bottom: -1px; |
| 2213 | background: none; |
| 2214 | font-family: inherit; |
| 2215 | letter-spacing: .04em; |
| 2216 | text-transform: uppercase; |
| 2217 | transition: color .15s, background .15s; |
| 2218 | white-space: nowrap; |
| 2219 | } |
| 2220 | |
| 2221 | .smo-tab:hover { |
| 2222 | color: var(--tx); |
| 2223 | background: var(--sf2); |
| 2224 | } |
| 2225 | |
| 2226 | .smo-tab.smo-tab-active { |
| 2227 | color: var(--ac); |
| 2228 | background: var(--sf2); |
| 2229 | border-color: var(--bd); |
| 2230 | border-bottom-color: var(--sf2); |
| 2231 | } |
| 2232 | |
| 2233 | /* ── Body ── */ |
| 2234 | .smo-body { |
| 2235 | flex: 1; |
| 2236 | overflow-y: auto; |
| 2237 | padding: 18px 20px; |
| 2238 | } |
| 2239 | |
| 2240 | .smo-section { |
| 2241 | display: none; |
| 2242 | animation: smFadeTab .15s ease; |
| 2243 | } |
| 2244 | |
| 2245 | .smo-section.smo-active { |
| 2246 | display: block; |
| 2247 | } |
| 2248 | |
| 2249 | /* ── Footer ── */ |
| 2250 | .smo-footer { |
| 2251 | display: flex; |
| 2252 | align-items: center; |
| 2253 | gap: 10px; |
| 2254 | padding: 10px 20px; |
| 2255 | border-top: 1px solid var(--bd); |
| 2256 | font-size: 11px; |
| 2257 | color: var(--tx2); |
| 2258 | flex-shrink: 0; |
| 2259 | } |
| 2260 | |
| 2261 | .smo-live-dot { |
| 2262 | width: 7px; |
| 2263 | height: 7px; |
| 2264 | border-radius: 50%; |
| 2265 | background: var(--ok); |
| 2266 | box-shadow: 0 0 6px var(--ok); |
| 2267 | animation: smPulse 2s ease-in-out infinite; |
| 2268 | flex-shrink: 0; |
| 2269 | } |
| 2270 | |
| 2271 | .smo-ts { |
| 2272 | color: var(--tx3); |
| 2273 | } |
| 2274 | |
| 2275 | .smo-refresh-btn { |
| 2276 | margin-left: auto; |
| 2277 | display: flex; |
| 2278 | align-items: center; |
| 2279 | gap: 5px; |
| 2280 | background: var(--sf2); |
| 2281 | border: 1px solid var(--bd2); |
| 2282 | color: var(--tx2); |
| 2283 | border-radius: 7px; |
| 2284 | padding: 5px 11px; |
| 2285 | font-size: 11px; |
| 2286 | font-family: inherit; |
| 2287 | font-weight: 600; |
| 2288 | cursor: pointer; |
| 2289 | transition: border-color .15s, color .15s; |
| 2290 | } |
| 2291 | |
| 2292 | .smo-refresh-btn:hover { |
| 2293 | border-color: var(--ac); |
| 2294 | color: var(--tx); |
| 2295 | } |
| 2296 | |
| 2297 | /* ── Cards ── */ |
| 2298 | .smo-card { |
| 2299 | background: var(--sf2); |
| 2300 | border: 1px solid var(--bd); |
| 2301 | border-radius: 13px; |
| 2302 | padding: 16px; |
| 2303 | } |
| 2304 | |
| 2305 | .smo-card-title { |
| 2306 | font-size: 10px; |
| 2307 | font-weight: 700; |
| 2308 | color: var(--tx3); |
| 2309 | text-transform: uppercase; |
| 2310 | letter-spacing: .1em; |
| 2311 | margin-bottom: 12px; |
| 2312 | display: flex; |
| 2313 | align-items: center; |
| 2314 | gap: 6px; |
| 2315 | } |
| 2316 | |
| 2317 | /* ── Two/three column layouts ── */ |
| 2318 | .smo-grid-2 { |
| 2319 | display: grid; |
| 2320 | grid-template-columns: 1fr 1fr; |
| 2321 | gap: 14px; |
| 2322 | } |
| 2323 | |
| 2324 | .smo-grid-3 { |
| 2325 | display: grid; |
| 2326 | grid-template-columns: 1fr 1fr 1fr; |
| 2327 | gap: 14px; |
| 2328 | margin-top: 14px; |
| 2329 | } |
| 2330 | |
| 2331 | .smo-grid-system { |
| 2332 | display: grid; |
| 2333 | grid-template-columns: 1fr 1fr; |
| 2334 | gap: 14px; |
| 2335 | } |
| 2336 | |
| 2337 | /* ── Gauge ── */ |
| 2338 | .smo-gauge { |
| 2339 | display: flex; |
| 2340 | flex-direction: column; |
| 2341 | align-items: center; |
| 2342 | gap: 14px; |
| 2343 | } |
| 2344 | |
| 2345 | .smo-gauge-wrap { |
| 2346 | position: relative; |
| 2347 | width: 120px; |
| 2348 | height: 120px; |
| 2349 | } |
| 2350 | |
| 2351 | .smo-gauge-wrap svg { |
| 2352 | transform: rotate(-90deg); |
| 2353 | } |
| 2354 | |
| 2355 | .smo-gauge-center { |
| 2356 | position: absolute; |
| 2357 | inset: 0; |
| 2358 | display: flex; |
| 2359 | flex-direction: column; |
| 2360 | align-items: center; |
| 2361 | justify-content: center; |
| 2362 | gap: 2px; |
| 2363 | } |
| 2364 | |
| 2365 | .smo-gauge-pct { |
| 2366 | font-size: 22px; |
| 2367 | font-weight: 700; |
| 2368 | color: var(--ac); |
| 2369 | line-height: 1; |
| 2370 | } |
| 2371 | |
| 2372 | .smo-gauge-label { |
| 2373 | font-size: 9px; |
| 2374 | color: var(--tx3); |
| 2375 | text-transform: uppercase; |
| 2376 | letter-spacing: .08em; |
| 2377 | } |
| 2378 | |
| 2379 | /* ── Segmented bar ── */ |
| 2380 | .smo-seg-bar { |
| 2381 | width: 100%; |
| 2382 | height: 8px; |
| 2383 | border-radius: 999px; |
| 2384 | overflow: hidden; |
| 2385 | display: flex; |
| 2386 | background: var(--bd); |
| 2387 | } |
| 2388 | |
| 2389 | .smo-seg-used { |
| 2390 | background: var(--ac); |
| 2391 | transition: width .6s ease; |
| 2392 | } |
| 2393 | |
| 2394 | .smo-seg-cache { |
| 2395 | background: var(--wn); |
| 2396 | transition: width .6s ease; |
| 2397 | } |
| 2398 | |
| 2399 | .smo-seg-free { |
| 2400 | background: var(--bd2); |
| 2401 | flex: 1; |
| 2402 | } |
| 2403 | |
| 2404 | /* ── Generic bar ── */ |
| 2405 | .smo-bar { |
| 2406 | height: 6px; |
| 2407 | border-radius: 999px; |
| 2408 | background: var(--bd); |
| 2409 | overflow: hidden; |
| 2410 | margin-top: 8px; |
| 2411 | } |
| 2412 | |
| 2413 | .smo-bar-fill { |
| 2414 | height: 100%; |
| 2415 | border-radius: 999px; |
| 2416 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 2417 | transition: width .6s ease; |
| 2418 | width: 0%; |
| 2419 | } |
| 2420 | |
| 2421 | .smo-bar-fill.ok { |
| 2422 | background: linear-gradient(90deg, var(--ok), #16a34a); |
| 2423 | } |
| 2424 | |
| 2425 | .smo-bar-fill.wn { |
| 2426 | background: linear-gradient(90deg, var(--wn), #d97706); |
| 2427 | } |
| 2428 | |
| 2429 | .smo-bar-fill.cr { |
| 2430 | background: linear-gradient(90deg, var(--er), #dc2626); |
| 2431 | } |
| 2432 | |
| 2433 | /* ── Sparkline ── */ |
| 2434 | .smo-sparkline { |
| 2435 | width: 100%; |
| 2436 | overflow: hidden; |
| 2437 | } |
| 2438 | |
| 2439 | .smo-sparkline svg { |
| 2440 | display: block; |
| 2441 | overflow: visible; |
| 2442 | } |
| 2443 | |
| 2444 | /* ── Metric cards row ── */ |
| 2445 | .smo-metric { |
| 2446 | display: flex; |
| 2447 | flex-direction: column; |
| 2448 | gap: 4px; |
| 2449 | } |
| 2450 | |
| 2451 | .smo-metric-label { |
| 2452 | font-size: 10px; |
| 2453 | color: var(--tx3); |
| 2454 | text-transform: uppercase; |
| 2455 | letter-spacing: .08em; |
| 2456 | } |
| 2457 | |
| 2458 | .smo-metric-val { |
| 2459 | font-size: 20px; |
| 2460 | font-weight: 700; |
| 2461 | color: var(--tx); |
| 2462 | line-height: 1.1; |
| 2463 | } |
| 2464 | |
| 2465 | .smo-metric-sub { |
| 2466 | font-size: 10px; |
| 2467 | color: var(--tx2); |
| 2468 | } |
| 2469 | |
| 2470 | /* ── Disk bar ── */ |
| 2471 | .smo-disk-bar { |
| 2472 | height: 10px; |
| 2473 | border-radius: 999px; |
| 2474 | background: var(--bd); |
| 2475 | overflow: hidden; |
| 2476 | margin: 10px 0; |
| 2477 | } |
| 2478 | |
| 2479 | .smo-disk-bar-fill { |
| 2480 | height: 100%; |
| 2481 | border-radius: 999px; |
| 2482 | background: linear-gradient(90deg, var(--ok), #16a34a); |
| 2483 | transition: width .6s ease; |
| 2484 | } |
| 2485 | |
| 2486 | .smo-disk-bar-fill.wn { |
| 2487 | background: linear-gradient(90deg, var(--wn), #d97706); |
| 2488 | } |
| 2489 | |
| 2490 | .smo-disk-bar-fill.cr { |
| 2491 | background: linear-gradient(90deg, var(--er), #dc2626); |
| 2492 | } |
| 2493 | |
| 2494 | .smo-disk-info { |
| 2495 | display: flex; |
| 2496 | justify-content: space-between; |
| 2497 | font-size: 11px; |
| 2498 | color: var(--tx2); |
| 2499 | margin-bottom: 4px; |
| 2500 | } |
| 2501 | |
| 2502 | .smo-disk-info b { |
| 2503 | color: var(--tx); |
| 2504 | } |
| 2505 | |
| 2506 | /* ── Treemap ── */ |
| 2507 | .smo-treemap { |
| 2508 | width: 100%; |
| 2509 | border-radius: 10px; |
| 2510 | overflow: hidden; |
| 2511 | cursor: pointer; |
| 2512 | background: var(--bg); |
| 2513 | min-height: 220px; |
| 2514 | } |
| 2515 | |
| 2516 | .smo-treemap svg { |
| 2517 | display: block; |
| 2518 | } |
| 2519 | |
| 2520 | .smo-tm-node { |
| 2521 | cursor: pointer; |
| 2522 | } |
| 2523 | |
| 2524 | .smo-tm-node rect { |
| 2525 | rx: 3; |
| 2526 | transition: filter .15s; |
| 2527 | } |
| 2528 | |
| 2529 | .smo-tm-node:hover rect { |
| 2530 | filter: brightness(1.25); |
| 2531 | } |
| 2532 | |
| 2533 | /* Treemap tooltip */ |
| 2534 | .smo-tm-tip { |
| 2535 | position: fixed; |
| 2536 | z-index: 9999; |
| 2537 | background: var(--sf); |
| 2538 | border: 1px solid var(--bd2); |
| 2539 | border-radius: 10px; |
| 2540 | padding: 9px 13px; |
| 2541 | font-size: 11px; |
| 2542 | pointer-events: none; |
| 2543 | box-shadow: 0 10px 40px rgba(0, 0, 0, .5); |
| 2544 | opacity: 0; |
| 2545 | transition: opacity .1s; |
| 2546 | max-width: 200px; |
| 2547 | } |
| 2548 | |
| 2549 | .smo-tm-tip.visible { |
| 2550 | opacity: 1; |
| 2551 | } |
| 2552 | |
| 2553 | .smo-tm-tip-name { |
| 2554 | font-weight: 700; |
| 2555 | color: var(--tx); |
| 2556 | margin-bottom: 2px; |
| 2557 | } |
| 2558 | |
| 2559 | .smo-tm-tip-size { |
| 2560 | color: var(--ac); |
| 2561 | } |
| 2562 | |
| 2563 | .smo-tm-tip-pct { |
| 2564 | color: var(--tx2); |
| 2565 | font-size: 10px; |
| 2566 | } |
| 2567 | |
| 2568 | .smo-tm-tip-hint { |
| 2569 | color: var(--tx3); |
| 2570 | font-size: 10px; |
| 2571 | margin-top: 4px; |
| 2572 | } |
| 2573 | |
| 2574 | /* Breadcrumb inside disk tab */ |
| 2575 | .smo-breadcrumb { |
| 2576 | display: flex; |
| 2577 | align-items: center; |
| 2578 | gap: 4px; |
| 2579 | flex-wrap: wrap; |
| 2580 | margin-bottom: 10px; |
| 2581 | } |
| 2582 | |
| 2583 | .smo-crumb { |
| 2584 | font-size: 11px; |
| 2585 | color: var(--tx2); |
| 2586 | cursor: pointer; |
| 2587 | padding: 2px 6px; |
| 2588 | border-radius: 5px; |
| 2589 | transition: color .1s, background .1s; |
| 2590 | white-space: nowrap; |
| 2591 | } |
| 2592 | |
| 2593 | .smo-crumb:hover { |
| 2594 | color: var(--ac); |
| 2595 | background: var(--gw); |
| 2596 | } |
| 2597 | |
| 2598 | .smo-crumb.smo-crumb-act { |
| 2599 | color: var(--ac); |
| 2600 | font-weight: 600; |
| 2601 | } |
| 2602 | |
| 2603 | .smo-crumb-sep { |
| 2604 | color: var(--bd2); |
| 2605 | font-size: 11px; |
| 2606 | } |
| 2607 | |
| 2608 | /* Top-10 list */ |
| 2609 | .smo-top-list { |
| 2610 | width: 100%; |
| 2611 | border-collapse: collapse; |
| 2612 | } |
| 2613 | |
| 2614 | .smo-top-list td { |
| 2615 | padding: 5px 6px; |
| 2616 | font-size: 11px; |
| 2617 | vertical-align: middle; |
| 2618 | } |
| 2619 | |
| 2620 | .smo-top-list tr:hover td { |
| 2621 | background: var(--sf3); |
| 2622 | border-radius: 6px; |
| 2623 | } |
| 2624 | |
| 2625 | .smo-top-num { |
| 2626 | color: var(--tx3); |
| 2627 | width: 22px; |
| 2628 | } |
| 2629 | |
| 2630 | .smo-top-name { |
| 2631 | color: var(--tx); |
| 2632 | font-weight: 600; |
| 2633 | max-width: 130px; |
| 2634 | overflow: hidden; |
| 2635 | text-overflow: ellipsis; |
| 2636 | white-space: nowrap; |
| 2637 | } |
| 2638 | |
| 2639 | .smo-top-size { |
| 2640 | color: var(--tx2); |
| 2641 | white-space: nowrap; |
| 2642 | width: 70px; |
| 2643 | text-align: right; |
| 2644 | } |
| 2645 | |
| 2646 | .smo-top-bar { |
| 2647 | width: 100px; |
| 2648 | } |
| 2649 | |
| 2650 | .smo-top-bar-inner { |
| 2651 | height: 4px; |
| 2652 | border-radius: 999px; |
| 2653 | background: var(--ac); |
| 2654 | transition: width .5s ease; |
| 2655 | } |
| 2656 | |
| 2657 | /* Treemap legend */ |
| 2658 | .smo-tm-legend { |
| 2659 | display: flex; |
| 2660 | flex-wrap: wrap; |
| 2661 | gap: 8px 14px; |
| 2662 | margin-top: 8px; |
| 2663 | font-size: 10px; |
| 2664 | color: var(--tx2); |
| 2665 | } |
| 2666 | |
| 2667 | .smo-tm-legend-item { |
| 2668 | display: flex; |
| 2669 | align-items: center; |
| 2670 | gap: 5px; |
| 2671 | } |
| 2672 | |
| 2673 | .smo-tm-legend-dot { |
| 2674 | width: 9px; |
| 2675 | height: 9px; |
| 2676 | border-radius: 2px; |
| 2677 | flex-shrink: 0; |
| 2678 | } |
| 2679 | |
| 2680 | /* ── Process table ── */ |
| 2681 | .smo-proc-header { |
| 2682 | display: flex; |
| 2683 | align-items: center; |
| 2684 | gap: 10px; |
| 2685 | margin-bottom: 12px; |
| 2686 | flex-wrap: wrap; |
| 2687 | } |
| 2688 | |
| 2689 | .smo-proc-total { |
| 2690 | font-size: 11px; |
| 2691 | color: var(--tx2); |
| 2692 | } |
| 2693 | |
| 2694 | .smo-proc-total b { |
| 2695 | color: var(--ac); |
| 2696 | } |
| 2697 | |
| 2698 | .smo-proc-search { |
| 2699 | display: flex; |
| 2700 | align-items: center; |
| 2701 | gap: 6px; |
| 2702 | background: var(--bg); |
| 2703 | border: 1px solid var(--bd2); |
| 2704 | border-radius: 7px; |
| 2705 | padding: 5px 10px; |
| 2706 | } |
| 2707 | |
| 2708 | .smo-proc-search-inp { |
| 2709 | background: none; |
| 2710 | border: none; |
| 2711 | color: var(--tx); |
| 2712 | font-family: inherit; |
| 2713 | font-size: 11px; |
| 2714 | outline: none; |
| 2715 | width: 180px; |
| 2716 | } |
| 2717 | |
| 2718 | .smo-proc-search-inp::placeholder { |
| 2719 | color: var(--tx3); |
| 2720 | } |
| 2721 | |
| 2722 | .smo-proc-sort-wrap { |
| 2723 | display: flex; |
| 2724 | align-items: center; |
| 2725 | gap: 6px; |
| 2726 | font-size: 11px; |
| 2727 | color: var(--tx2); |
| 2728 | margin-left: auto; |
| 2729 | } |
| 2730 | |
| 2731 | .smo-proc-sort-sel { |
| 2732 | background: var(--sf2); |
| 2733 | border: 1px solid var(--bd2); |
| 2734 | color: var(--tx); |
| 2735 | border-radius: 7px; |
| 2736 | padding: 5px 8px; |
| 2737 | font-size: 11px; |
| 2738 | font-family: inherit; |
| 2739 | cursor: pointer; |
| 2740 | outline: none; |
| 2741 | } |
| 2742 | |
| 2743 | .smo-table { |
| 2744 | width: 100%; |
| 2745 | border-collapse: collapse; |
| 2746 | font-size: 11px; |
| 2747 | } |
| 2748 | |
| 2749 | .smo-table thead th { |
| 2750 | text-align: left; |
| 2751 | padding: 7px 10px; |
| 2752 | font-size: 10px; |
| 2753 | font-weight: 700; |
| 2754 | color: var(--tx3); |
| 2755 | text-transform: uppercase; |
| 2756 | letter-spacing: .08em; |
| 2757 | border-bottom: 1px solid var(--bd2); |
| 2758 | cursor: pointer; |
| 2759 | user-select: none; |
| 2760 | white-space: nowrap; |
| 2761 | } |
| 2762 | |
| 2763 | .smo-table thead th:hover { |
| 2764 | color: var(--ac); |
| 2765 | } |
| 2766 | |
| 2767 | .smo-table thead th.sort-active { |
| 2768 | color: var(--ac); |
| 2769 | } |
| 2770 | |
| 2771 | .smo-table tbody tr { |
| 2772 | border-bottom: 1px solid var(--bd); |
| 2773 | transition: background .1s, opacity .3s, max-height .3s; |
| 2774 | } |
| 2775 | |
| 2776 | .smo-table tbody tr:hover { |
| 2777 | background: var(--sf2); |
| 2778 | } |
| 2779 | |
| 2780 | .smo-table tbody tr.smo-row-hot { |
| 2781 | background: rgba(239, 68, 68, .07); |
| 2782 | } |
| 2783 | |
| 2784 | .smo-table tbody tr.smo-row-hot:hover { |
| 2785 | background: rgba(239, 68, 68, .12); |
| 2786 | } |
| 2787 | |
| 2788 | .smo-table tbody tr.smo-row-dying { |
| 2789 | opacity: 0; |
| 2790 | pointer-events: none; |
| 2791 | transition: opacity .3s ease; |
| 2792 | } |
| 2793 | |
| 2794 | .smo-table tbody td { |
| 2795 | padding: 7px 10px; |
| 2796 | vertical-align: middle; |
| 2797 | } |
| 2798 | |
| 2799 | .smo-pid { |
| 2800 | color: var(--tx3); |
| 2801 | font-size: 10px; |
| 2802 | width: 48px; |
| 2803 | } |
| 2804 | |
| 2805 | .smo-name { |
| 2806 | font-weight: 600; |
| 2807 | max-width: 160px; |
| 2808 | overflow: hidden; |
| 2809 | text-overflow: ellipsis; |
| 2810 | white-space: nowrap; |
| 2811 | } |
| 2812 | |
| 2813 | .smo-user { |
| 2814 | color: var(--tx2); |
| 2815 | max-width: 80px; |
| 2816 | overflow: hidden; |
| 2817 | text-overflow: ellipsis; |
| 2818 | white-space: nowrap; |
| 2819 | } |
| 2820 | |
| 2821 | .smo-cpu { |
| 2822 | font-weight: 700; |
| 2823 | width: 55px; |
| 2824 | } |
| 2825 | |
| 2826 | .smo-mem { |
| 2827 | color: var(--tx2); |
| 2828 | width: 65px; |
| 2829 | } |
| 2830 | |
| 2831 | .smo-stat { |
| 2832 | width: 60px; |
| 2833 | } |
| 2834 | |
| 2835 | .smo-act { |
| 2836 | width: 80px; |
| 2837 | } |
| 2838 | |
| 2839 | .smo-cpu.hot { |
| 2840 | color: var(--er); |
| 2841 | } |
| 2842 | |
| 2843 | .smo-badge { |
| 2844 | display: inline-flex; |
| 2845 | align-items: center; |
| 2846 | gap: 4px; |
| 2847 | padding: 2px 7px; |
| 2848 | border-radius: 999px; |
| 2849 | font-size: 10px; |
| 2850 | font-weight: 700; |
| 2851 | cursor: pointer; |
| 2852 | border: none; |
| 2853 | font-family: inherit; |
| 2854 | transition: filter .15s; |
| 2855 | } |
| 2856 | |
| 2857 | .smo-badge:hover { |
| 2858 | filter: brightness(1.2); |
| 2859 | } |
| 2860 | |
| 2861 | .smo-badge-kill { |
| 2862 | background: rgba(34, 197, 94, .15); |
| 2863 | color: #22c55e; |
| 2864 | border: 1px solid rgba(34, 197, 94, .3); |
| 2865 | cursor: pointer; |
| 2866 | } |
| 2867 | |
| 2868 | .smo-badge-sys { |
| 2869 | background: rgba(100, 116, 139, .15); |
| 2870 | color: #94a3b8; |
| 2871 | border: 1px solid rgba(100, 116, 139, .25); |
| 2872 | cursor: default; |
| 2873 | } |
| 2874 | |
| 2875 | .smo-badge-zmb { |
| 2876 | background: rgba(245, 158, 11, .15); |
| 2877 | color: var(--wn); |
| 2878 | border: 1px solid rgba(245, 158, 11, .3); |
| 2879 | cursor: default; |
| 2880 | } |
| 2881 | |
| 2882 | .smo-status-running { |
| 2883 | color: var(--ok); |
| 2884 | } |
| 2885 | |
| 2886 | .smo-status-sleep { |
| 2887 | color: var(--tx3); |
| 2888 | } |
| 2889 | |
| 2890 | .smo-status-zombie { |
| 2891 | color: var(--wn); |
| 2892 | } |
| 2893 | |
| 2894 | .smo-load-more { |
| 2895 | display: block; |
| 2896 | width: 100%; |
| 2897 | margin-top: 10px; |
| 2898 | background: var(--sf2); |
| 2899 | border: 1px solid var(--bd2); |
| 2900 | color: var(--tx2); |
| 2901 | border-radius: 9px; |
| 2902 | padding: 9px; |
| 2903 | font-size: 11px; |
| 2904 | font-family: inherit; |
| 2905 | cursor: pointer; |
| 2906 | transition: border-color .15s, color .15s; |
| 2907 | } |
| 2908 | |
| 2909 | .smo-load-more:hover { |
| 2910 | border-color: var(--ac); |
| 2911 | color: var(--tx); |
| 2912 | } |
| 2913 | |
| 2914 | /* ── Kill confirm modal ── */ |
| 2915 | .smo-kill-overlay { |
| 2916 | position: fixed; |
| 2917 | inset: 0; |
| 2918 | z-index: 7000; |
| 2919 | background: rgba(0, 0, 0, .55); |
| 2920 | display: flex; |
| 2921 | align-items: center; |
| 2922 | justify-content: center; |
| 2923 | display: none; |
| 2924 | } |
| 2925 | |
| 2926 | .smo-kill-overlay.on { |
| 2927 | display: flex; |
| 2928 | animation: fadeIn .15s ease; |
| 2929 | } |
| 2930 | |
| 2931 | .smo-kill-panel { |
| 2932 | width: min(400px, 90vw); |
| 2933 | background: var(--sf); |
| 2934 | border: 1px solid var(--bd2); |
| 2935 | border-radius: 16px; |
| 2936 | box-shadow: 0 24px 80px rgba(0, 0, 0, .7); |
| 2937 | overflow: hidden; |
| 2938 | } |
| 2939 | |
| 2940 | .smo-kill-head { |
| 2941 | padding: 14px 18px; |
| 2942 | border-bottom: 1px solid var(--bd); |
| 2943 | font-family: 'Syne', sans-serif; |
| 2944 | font-weight: 700; |
| 2945 | font-size: 14px; |
| 2946 | color: var(--er); |
| 2947 | display: flex; |
| 2948 | align-items: center; |
| 2949 | gap: 8px; |
| 2950 | } |
| 2951 | |
| 2952 | .smo-kill-body { |
| 2953 | padding: 18px; |
| 2954 | font-size: 12px; |
| 2955 | color: var(--tx2); |
| 2956 | line-height: 1.7; |
| 2957 | } |
| 2958 | |
| 2959 | .smo-kill-body b { |
| 2960 | color: var(--tx); |
| 2961 | } |
| 2962 | |
| 2963 | .smo-kill-warn { |
| 2964 | margin-top: 12px; |
| 2965 | padding: 8px 12px; |
| 2966 | border-radius: 8px; |
| 2967 | background: rgba(239, 68, 68, .08); |
| 2968 | border: 1px solid rgba(239, 68, 68, .2); |
| 2969 | color: var(--er); |
| 2970 | font-size: 11px; |
| 2971 | } |
| 2972 | |
| 2973 | .smo-kill-foot { |
| 2974 | padding: 12px 18px; |
| 2975 | border-top: 1px solid var(--bd); |
| 2976 | display: flex; |
| 2977 | gap: 8px; |
| 2978 | justify-content: flex-end; |
| 2979 | } |
| 2980 | |
| 2981 | .smo-kill-cancel { |
| 2982 | background: var(--sf2); |
| 2983 | border: 1px solid var(--bd2); |
| 2984 | color: var(--tx2); |
| 2985 | border-radius: 8px; |
| 2986 | padding: 7px 16px; |
| 2987 | font-size: 11px; |
| 2988 | font-family: inherit; |
| 2989 | font-weight: 600; |
| 2990 | cursor: pointer; |
| 2991 | transition: all .15s; |
| 2992 | } |
| 2993 | |
| 2994 | .smo-kill-cancel:hover { |
| 2995 | border-color: var(--ac); |
| 2996 | color: var(--tx); |
| 2997 | } |
| 2998 | |
| 2999 | .smo-kill-confirm { |
| 3000 | background: rgba(239, 68, 68, .15); |
| 3001 | border: 1px solid rgba(239, 68, 68, .35); |
| 3002 | color: var(--er); |
| 3003 | border-radius: 8px; |
| 3004 | padding: 7px 16px; |
| 3005 | font-size: 11px; |
| 3006 | font-family: inherit; |
| 3007 | font-weight: 700; |
| 3008 | cursor: pointer; |
| 3009 | transition: all .15s; |
| 3010 | } |
| 3011 | |
| 3012 | .smo-kill-confirm:hover { |
| 3013 | background: rgba(239, 68, 68, .3); |
| 3014 | } |
| 3015 | |
| 3016 | /* ── System tab ── */ |
| 3017 | .smo-temp-badge { |
| 3018 | display: inline-flex; |
| 3019 | align-items: center; |
| 3020 | gap: 5px; |
| 3021 | padding: 3px 10px; |
| 3022 | border-radius: 999px; |
| 3023 | font-size: 11px; |
| 3024 | font-weight: 700; |
| 3025 | margin-left: 8px; |
| 3026 | } |
| 3027 | |
| 3028 | .smo-temp-ok { |
| 3029 | background: rgba(34, 197, 94, .15); |
| 3030 | color: #22c55e; |
| 3031 | } |
| 3032 | |
| 3033 | .smo-temp-warn { |
| 3034 | background: rgba(245, 158, 11, .15); |
| 3035 | color: var(--wn); |
| 3036 | } |
| 3037 | |
| 3038 | .smo-temp-crit { |
| 3039 | background: rgba(239, 68, 68, .15); |
| 3040 | color: var(--er); |
| 3041 | } |
| 3042 | |
| 3043 | .smo-temp-legend { |
| 3044 | margin-top: 12px; |
| 3045 | display: flex; |
| 3046 | flex-direction: column; |
| 3047 | gap: 4px; |
| 3048 | font-size: 10px; |
| 3049 | color: var(--tx2); |
| 3050 | } |
| 3051 | |
| 3052 | .smo-temp-legend-item { |
| 3053 | display: flex; |
| 3054 | align-items: center; |
| 3055 | gap: 6px; |
| 3056 | } |
| 3057 | |
| 3058 | .smo-legend-dot { |
| 3059 | width: 7px; |
| 3060 | height: 7px; |
| 3061 | border-radius: 50%; |
| 3062 | flex-shrink: 0; |
| 3063 | } |
| 3064 | |
| 3065 | .smo-net-row { |
| 3066 | display: flex; |
| 3067 | align-items: center; |
| 3068 | gap: 10px; |
| 3069 | margin-bottom: 8px; |
| 3070 | } |
| 3071 | |
| 3072 | .smo-net-label { |
| 3073 | font-size: 11px; |
| 3074 | color: var(--tx2); |
| 3075 | width: 90px; |
| 3076 | flex-shrink: 0; |
| 3077 | } |
| 3078 | |
| 3079 | .smo-net-val { |
| 3080 | font-size: 12px; |
| 3081 | font-weight: 700; |
| 3082 | color: var(--tx); |
| 3083 | width: 80px; |
| 3084 | } |
| 3085 | |
| 3086 | .smo-net-bar { |
| 3087 | flex: 1; |
| 3088 | height: 5px; |
| 3089 | border-radius: 999px; |
| 3090 | background: var(--bd); |
| 3091 | overflow: hidden; |
| 3092 | } |
| 3093 | |
| 3094 | .smo-net-bar-fill { |
| 3095 | height: 100%; |
| 3096 | border-radius: 999px; |
| 3097 | background: linear-gradient(90deg, var(--ac), var(--ac2)); |
| 3098 | transition: width .6s ease; |
| 3099 | } |
| 3100 | |
| 3101 | .smo-sys-kv { |
| 3102 | display: flex; |
| 3103 | justify-content: space-between; |
| 3104 | padding: 5px 0; |
| 3105 | border-bottom: 1px solid var(--bd); |
| 3106 | font-size: 11px; |
| 3107 | } |
| 3108 | |
| 3109 | .smo-sys-kv:last-child { |
| 3110 | border-bottom: none; |
| 3111 | } |
| 3112 | |
| 3113 | .smo-sys-k { |
| 3114 | color: var(--tx2); |
| 3115 | } |
| 3116 | |
| 3117 | .smo-sys-v { |
| 3118 | color: var(--tx); |
| 3119 | font-weight: 600; |
| 3120 | } |
| 3121 | |
| 3122 | /* ── Toast ── */ |
| 3123 | .smo-toast-wrap { |
| 3124 | position: fixed; |
| 3125 | bottom: 24px; |
| 3126 | right: 24px; |
| 3127 | z-index: 9500; |
| 3128 | display: flex; |
| 3129 | flex-direction: column; |
| 3130 | gap: 8px; |
| 3131 | pointer-events: none; |
| 3132 | } |
| 3133 | |
| 3134 | .smo-toast { |
| 3135 | pointer-events: auto; |
| 3136 | display: flex; |
| 3137 | align-items: center; |
| 3138 | gap: 8px; |
| 3139 | padding: 9px 14px; |
| 3140 | border-radius: 10px; |
| 3141 | background: var(--sf); |
| 3142 | border: 1px solid var(--bd2); |
| 3143 | font-size: 11px; |
| 3144 | font-weight: 600; |
| 3145 | box-shadow: 0 8px 32px rgba(0, 0, 0, .5); |
| 3146 | max-width: 280px; |
| 3147 | animation: smToastIn .2s ease; |
| 3148 | } |
| 3149 | |
| 3150 | .smo-toast.ok { |
| 3151 | border-color: var(--ok); |
| 3152 | color: var(--ok); |
| 3153 | } |
| 3154 | |
| 3155 | .smo-toast.er { |
| 3156 | border-color: var(--er); |
| 3157 | color: var(--er); |
| 3158 | } |
| 3159 | |
| 3160 | .smo-toast.wn { |
| 3161 | border-color: var(--wn); |
| 3162 | color: var(--wn); |
| 3163 | } |
| 3164 | |
| 3165 | /* ── Responsive ── */ |
| 3166 | @media (max-width: 860px) { |
| 3167 | |
| 3168 | .smo-grid-2, |
| 3169 | .smo-grid-system { |
| 3170 | grid-template-columns: 1fr; |
| 3171 | } |
| 3172 | |
| 3173 | .smo-grid-3 { |
| 3174 | grid-template-columns: 1fr; |
| 3175 | } |
| 3176 | |
| 3177 | .smo-modal { |
| 3178 | height: 94vh; |
| 3179 | border-radius: 14px 14px 0 0; |
| 3180 | } |
| 3181 | |
| 3182 | .smo-proc-search-inp { |
| 3183 | width: 120px; |
| 3184 | } |
| 3185 | |
| 3186 | .smo-top-bar { |
| 3187 | display: none; |
| 3188 | } |
| 3189 | } |
| 3190 | |
| 3191 | @media (max-width: 560px) { |
| 3192 | .smo-tabs { |
| 3193 | overflow-x: auto; |
| 3194 | scrollbar-width: none; |
| 3195 | } |
| 3196 | |
| 3197 | .smo-tabs::-webkit-scrollbar { |
| 3198 | display: none; |
| 3199 | } |
| 3200 | |
| 3201 | .smo-tab { |
| 3202 | padding: 6px 10px; |
| 3203 | font-size: 10px; |
| 3204 | } |
| 3205 | |
| 3206 | .smo-table { |
| 3207 | font-size: 10px; |
| 3208 | } |
| 3209 | |
| 3210 | .smo-table td { |
| 3211 | padding: 5px 6px; |
| 3212 | } |
| 3213 | |
| 3214 | .smo-user, |
| 3215 | .smo-stat { |
| 3216 | display: none; |
| 3217 | } |
| 3218 | } |
| 3219 | </style> |
| 3220 | </head> |
| 3221 | |
| 3222 | <body> |
| 3223 | |
| 3224 | <!-- TOPBAR --> |
| 3225 | <header class="topbar"> |
| 3226 | <div class="topbar-left"> |
| 3227 | <div class="brand"> |
| 3228 | <img class="brand-logo" |
| 3229 | src="data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCARCB9ADASIAAhEBAxEB/8QAHQABAAEFAQEBAAAAAAAAAAAAAAcDBAUGCAIBCf/EAGEQAAEDAwEEBAgGCwoMBQQBBQABAgMEBREGBxIhMRNBUWEIFCIycYGR0RVCUqGxwRYjM0NicpKTlLLSGCRTVFVWdIKD4Rc0NTZERUZjZISiwgklJ3N1Jjdl8ChXlaPi8f/EABsBAQADAQEBAQAAAAAAAAAAAAACAwQBBQYH/8QAOREBAAIBAwMDAgMIAQQBBQEAAAECAwQREgUhMRNBUSIyBhRhFUJDUnGBkaFTFiOx0TMkRGLB4fD/2gAMAwEAAhEDEQA/AOMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/Z" |
| 3230 | alt="zftpd"> |
| 3231 | <div class="brand-text"> |
| 3232 | <div class="brand-title">zftpd</div> |
| 3233 | <div class="brand-sub">Zero-copy FTP Daemon</div> |
| 3234 | </div> |
| 3235 | </div> |
| 3236 | </div> |
| 3237 | <div class="topbar-right"> |
| 3238 | <!-- Stats widget --> |
| 3239 | <div class="stats-w" id="stats-w"> |
| 3240 | <div class="sc-donut"> |
| 3241 | <div class="dw"> |
| 3242 | <svg width="28" height="28" viewBox="0 0 28 28"> |
| 3243 | <circle class="d-track" cx="14" cy="14" r="11" /> |
| 3244 | <circle class="d-fill" id="d-fill" cx="14" cy="14" r="11" stroke="var(--ac)" stroke-dasharray="69.12" |
| 3245 | stroke-dashoffset="69.12" /> |
| 3246 | </svg> |
| 3247 | <div class="d-ctr" id="d-pct">0%</div> |
| 3248 | </div> |
| 3249 | </div> |
| 3250 | <div class="sc" data-k="disk"> |
| 3251 | <div class="sl">Disk</div> |
| 3252 | <div class="sv" id="s-disk">—</div> |
| 3253 | </div> |
| 3254 | <div class="sc" data-k="temp"> |
| 3255 | <div class="sl">Temp</div> |
| 3256 | <div class="sv" id="s-temp">—</div> |
| 3257 | </div> |
| 3258 | <div class="sc" data-k="items"> |
| 3259 | <div class="sl">Items</div> |
| 3260 | <div class="sv ok" id="s-files">0</div> |
| 3261 | </div> |
| 3262 | <div class="stats-panel" id="stats-panel"> |
| 3263 | <div class="sp-hd"> |
| 3264 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> |
| 3265 | <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" /> |
| 3266 | </svg> |
| 3267 | System Status |
| 3268 | </div> |
| 3269 | <div class="sp-row"><span class="sp-lb">Disk Used</span> |
| 3270 | <div class="sp-bar"> |
| 3271 | <div class="sp-bf" id="sp-db" style="width:0%"></div> |
| 3272 | </div><span class="sp-vl" id="sp-du">—</span> |
| 3273 | </div> |
| 3274 | <div class="sp-row"><span class="sp-lb">Free</span><span class="sp-vl" id="sp-df">—</span></div> |
| 3275 | <div class="sp-row"><span class="sp-lb">Total</span><span class="sp-vl" id="sp-dt">—</span></div> |
| 3276 | <div class="sp-div"></div> |
| 3277 | <div class="sp-row"><span class="sp-lb">CPU Temp</span> |
| 3278 | <div class="sp-bar"> |
| 3279 | <div class="sp-bf" id="sp-tb" style="width:0%"></div> |
| 3280 | </div><span class="sp-vl" id="sp-tv">—</span> |
| 3281 | </div> |
| 3282 | <div class="sp-row"><span class="sp-lb">Uptime</span><span class="sp-vl" id="sp-up">—</span></div> |
| 3283 | <div class="sp-div"></div> |
| 3284 | <div class="sp-row"><span class="sp-lb">Items in dir</span><span class="sp-vl" id="sp-fi">0</span></div> |
| 3285 | <div class="sp-row"><span class="sp-lb">Path</span><span class="sp-vl" id="sp-pt" |
| 3286 | style="max-width:128px;overflow:hidden;text-overflow:ellipsis">/</span></div> |
| 3287 | </div> |
| 3288 | </div> |
| 3289 | <!-- Theme dropdown --> |
| 3290 | <div class="theme-switcher"> |
| 3291 | <button class="theme-btn" id="theme-btn" type="button"> |
| 3292 | <span class="t-swatch" id="t-sw" style="background:#2b8cff"></span> |
| 3293 | <span id="t-nm">PS5</span> |
| 3294 | <svg class="t-arr" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" |
| 3295 | stroke-width="3" stroke-linecap="round"> |
| 3296 | <polyline points="6 9 12 15 18 9" /> |
| 3297 | </svg> |
| 3298 | </button> |
| 3299 | <div class="theme-dd" id="theme-dd"> |
| 3300 | <div class="td-hd">Select Theme</div> |
| 3301 | </div> |
| 3302 | <select id="theme-select" class="theme-select-mobile" aria-label="Theme"></select> |
| 3303 | </div> |
| 3304 | <!-- Status --> |
| 3305 | <div id="status" class="status-pill status-ok"><span class="sdot"></span>Connected</div> |
| 3306 | </div> |
| 3307 | </header> |
| 3308 | |
| 3309 | <!-- TOOLBAR --> |
| 3310 | <section class="toolbar"> |
| 3311 | <button id="btn-up" class="btn" type="button"> |
| 3312 | <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" |
| 3313 | stroke-linecap="round"> |
| 3314 | <polyline points="18 15 12 9 6 15" /> |
| 3315 | </svg>Up |
| 3316 | </button> |
| 3317 | <button id="btn-ref" class="btn" type="button"> |
| 3318 | <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" |
| 3319 | stroke-linecap="round"> |
| 3320 | <polyline points="23 4 23 10 17 10" /> |
| 3321 | <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" /> |
| 3322 | </svg>Refresh |
| 3323 | </button> |
| 3324 | <div class="tb-sep"></div> |
| 3325 | <div class="vg" role="group"> |
| 3326 | <button class="vb active" id="vb-grid" title="Grid"> |
| 3327 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| 3328 | <rect x="3" y="3" width="7" height="7" /> |
| 3329 | <rect x="14" y="3" width="7" height="7" /> |
| 3330 | <rect x="14" y="14" width="7" height="7" /> |
| 3331 | <rect x="3" y="14" width="7" height="7" /> |
| 3332 | </svg> |
| 3333 | </button> |
| 3334 | <button class="vb" id="vb-list" title="List"> |
| 3335 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| 3336 | <line x1="8" y1="6" x2="21" y2="6" /> |
| 3337 | <line x1="8" y1="12" x2="21" y2="12" /> |
| 3338 | <line x1="8" y1="18" x2="21" y2="18" /> |
| 3339 | <line x1="3" y1="6" x2="3.01" y2="6" /> |
| 3340 | <line x1="3" y1="12" x2="3.01" y2="12" /> |
| 3341 | <line x1="3" y1="18" x2="3.01" y2="18" /> |
| 3342 | </svg> |
| 3343 | </button> |
| 3344 | <button class="vb" id="vb-details" title="Details"> |
| 3345 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
| 3346 | <line x1="3" y1="6" x2="21" y2="6" /> |
| 3347 | <line x1="3" y1="10" x2="21" y2="10" /> |
| 3348 | <line x1="3" y1="14" x2="21" y2="14" /> |
| 3349 | <line x1="3" y1="18" x2="21" y2="18" /> |
| 3350 | </svg> |
| 3351 | </button> |
| 3352 | </div> |
| 3353 | <div class="spacer"></div> |
| 3354 | <div class="search-wrap"> |
| 3355 | <svg class="search-ico" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" |
| 3356 | stroke-width="2.5" stroke-linecap="round"> |
| 3357 | <circle cx="11" cy="11" r="8" /> |
| 3358 | <path d="m21 21-4.35-4.35" /> |
| 3359 | </svg> |
| 3360 | <input id="search" class="search" type="text" placeholder="Search files and folders…" autocomplete="off" |
| 3361 | spellcheck="false"> |
| 3362 | </div> |
| 3363 | </section> |
| 3364 | |
| 3365 | <!-- BREADCRUMB --> |
| 3366 | <nav id="breadcrumb" class="breadcrumb"></nav> |
| 3367 | |
| 3368 | <!-- CONTENT --> |
| 3369 | <main class="content"> |
| 3370 | <div class="fl-header"> |
| 3371 | <div class="fl-count" id="fl-cnt"></div> |
| 3372 | </div> |
| 3373 | <div id="file-list" class="fl vg-grid"></div> |
| 3374 | </main> |
| 3375 | |
| 3376 | <input id="file-input" type="file" multiple style="display:none"> |
| 3377 | <input id="folder-input" type="file" multiple webkitdirectory style="display:none"> |
| 3378 | |
| 3379 | <!-- DROP --> |
| 3380 | <div id="drop" class="drop"> |
| 3381 | <div class="drop-card"> |
| 3382 | <button class="drop-close" id="drop-close" type="button">×</button> |
| 3383 | <div class="d-ico"> |
| 3384 | <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" |
| 3385 | stroke-linecap="round"> |
| 3386 | <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> |
| 3387 | <polyline points="17 8 12 3 7 8" /> |
| 3388 | <line x1="12" y1="3" x2="12" y2="15" /> |
| 3389 | </svg> |
| 3390 | </div> |
| 3391 | <div class="d-title">Drop to Upload</div> |
| 3392 | <div id="d-sub" class="d-sub">Release files to start uploading</div> |
| 3393 | <div class="d-bar"> |
| 3394 | <div id="d-bf" class="d-bf"></div> |
| 3395 | </div> |
| 3396 | <div id="d-stats" class="d-stats" style="display:none"> |
| 3397 | <div class="d-stat-row"><span class="d-stat-label">To:</span> <span id="d-to" class="d-stat-val"></span></div> |
| 3398 | <div class="d-stat-row"><span class="d-stat-label">Speed:</span> <span id="d-speed" class="d-stat-val"></span> |
| 3399 | </div> |
| 3400 | <div class="d-stat-row"><span class="d-stat-label">Time:</span> <span id="d-time" class="d-stat-val"></span> |
| 3401 | </div> |
| 3402 | </div> |
| 3403 | </div> |
| 3404 | </div> |
| 3405 | |
| 3406 | <!-- CONTEXT MENU --> |
| 3407 | <div id="ctx" class="ctx"></div> |
| 3408 | |
| 3409 | <!-- SEND-TO MODAL ──────────────────────────────────────────── --> |
| 3410 | <div id="send-modal" class="send-modal"> |
| 3411 | <div class="sm-panel"> |
| 3412 | <div class="sm-header"> |
| 3413 | <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" |
| 3414 | stroke-linecap="round"> |
| 3415 | <path d="M22 2L11 13" /> |
| 3416 | <path d="M22 2L15 22L11 13L2 9L22 2" /> |
| 3417 | </svg> |
| 3418 | Send to… |
| 3419 | <button class="sm-close" id="sm-close" type="button">×</button> |
| 3420 | </div> |
| 3421 | <nav id="sm-crumb" class="sm-crumb"></nav> |
| 3422 | <div id="sm-body" class="sm-body"></div> |
| 3423 | <div class="sm-footer"> |
| 3424 | <button class="btn" id="sm-cancel" type="button">Cancel</button> |
| 3425 | <button class="btn primary" id="sm-send" type="button"> |
| 3426 | <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" |
| 3427 | stroke-linecap="round"> |
| 3428 | <path d="M22 2L11 13" /> |
| 3429 | <path d="M22 2L15 22L11 13L2 9L22 2" /> |
| 3430 | </svg> |
| 3431 | Send Here |
| 3432 | </button> |
| 3433 | </div> |
| 3434 | </div> |
| 3435 | </div> |
| 3436 | |
| 3437 | <!-- TRANSFER TRAY ─────────────────────────────────────────── --> |
| 3438 | <div id="xfer-tray" class="xfer-tray"></div> |
| 3439 | |
| 3440 | <!-- STATS MONITOR MODAL ─────────────────────────────────────── --> |
| 3441 | <div id="smo-overlay" class="smo-overlay" role="dialog" aria-modal="true" aria-label="System Monitor"> |
| 3442 | <div id="smo-modal" class="smo-modal"> |
| 3443 | |
| 3444 | <!-- Header --> |
| 3445 | <div class="smo-head"> |
| 3446 | <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3447 | stroke-linecap="round" style="color:var(--ac)"> |
| 3448 | <polyline points="22 12 18 12 15 21 9 3 6 12 2 12" /> |
| 3449 | </svg> |
| 3450 | <span class="smo-title">System Monitor</span> |
| 3451 | <div class="smo-head-btns"> |
| 3452 | <button class="smo-btn-icon" id="smo-popout" title="Open in new tab" type="button">↗</button> |
| 3453 | <button class="smo-btn-icon smo-close" id="smo-close" title="Close" type="button">×</button> |
| 3454 | </div> |
| 3455 | </div> |
| 3456 | |
| 3457 | <!-- Tabs --> |
| 3458 | <div class="smo-tabs" role="tablist"> |
| 3459 | <button class="smo-tab smo-tab-active" data-tab="ram" role="tab" type="button"> |
| 3460 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3461 | stroke-linecap="round" stroke-linejoin="round"> |
| 3462 | <rect x="2" y="7" width="20" height="14" rx="2" ry="2" /> |
| 3463 | <path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16" /> |
| 3464 | </svg> |
| 3465 | RAM |
| 3466 | </button> |
| 3467 | <button class="smo-tab" data-tab="disk" role="tab" type="button"> |
| 3468 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3469 | stroke-linecap="round" stroke-linejoin="round"> |
| 3470 | <circle cx="12" cy="12" r="1" /> |
| 3471 | <path |
| 3472 | d="M12 1v6m6.66-1.31-4.24 4.24m5.97 5.97h-6m1.31 6.66-4.24-4.24m-5.97 5.97v-6M1 12.34l4.24-4.24M5.31 5.65 1 1" /> |
| 3473 | </svg> |
| 3474 | Disk |
| 3475 | </button> |
| 3476 | <button class="smo-tab" data-tab="proc" role="tab" type="button"> |
| 3477 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3478 | stroke-linecap="round" stroke-linejoin="round"> |
| 3479 | <circle cx="12" cy="12" r="1" /> |
| 3480 | <circle cx="19" cy="12" r="1" /> |
| 3481 | <circle cx="5" cy="12" r="1" /> |
| 3482 | </svg> |
| 3483 | Processes |
| 3484 | </button> |
| 3485 | <button class="smo-tab" data-tab="sys" role="tab" type="button"> |
| 3486 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3487 | stroke-linecap="round" stroke-linejoin="round"> |
| 3488 | <rect x="2" y="3" width="20" height="14" rx="2" ry="2" /> |
| 3489 | <line x1="2" y1="17" x2="22" y2="17" /> |
| 3490 | </svg> |
| 3491 | System |
| 3492 | </button> |
| 3493 | </div> |
| 3494 | |
| 3495 | <!-- Body --> |
| 3496 | <div class="smo-body" id="smo-body"> |
| 3497 | |
| 3498 | <!-- TAB: RAM ───────────────────────── --> |
| 3499 | <div class="smo-section smo-active" id="smo-tab-ram"> |
| 3500 | <div class="smo-grid-2"> |
| 3501 | <!-- Left: gauge + segmented bar --> |
| 3502 | <div class="smo-card smo-gauge"> |
| 3503 | <div class="smo-gauge-wrap"> |
| 3504 | <svg width="120" height="120" viewBox="0 0 120 120"> |
| 3505 | <circle class="d-track" cx="60" cy="60" r="50" fill="none" stroke="var(--bd2)" stroke-width="10" /> |
| 3506 | <circle id="smo-ram-arc" cx="60" cy="60" r="50" fill="none" stroke="var(--ac)" stroke-width="10" |
| 3507 | stroke-linecap="round" stroke-dasharray="314.16" stroke-dashoffset="314.16" |
| 3508 | style="transition:stroke-dashoffset .7s cubic-bezier(.4,0,.2,1)" /> |
| 3509 | </svg> |
| 3510 | <div class="smo-gauge-center"> |
| 3511 | <span class="smo-gauge-pct" id="smo-ram-pct">0%</span> |
| 3512 | <span class="smo-gauge-label">used</span> |
| 3513 | </div> |
| 3514 | </div> |
| 3515 | <div style="width:100%"> |
| 3516 | <div class="smo-seg-bar" id="smo-ram-segbar"> |
| 3517 | <div class="smo-seg-used" id="smo-ram-seg-used" style="width:0%"></div> |
| 3518 | <div class="smo-seg-cache" id="smo-ram-seg-cache" style="width:0%"></div> |
| 3519 | <div class="smo-seg-free"></div> |
| 3520 | </div> |
| 3521 | <div style="display:flex;gap:14px;margin-top:7px;font-size:10px;color:var(--tx2)"> |
| 3522 | <span><span |
| 3523 | style="display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--ac);margin-right:4px;vertical-align:middle"></span>Used</span> |
| 3524 | <span><span |
| 3525 | style="display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--wn);margin-right:4px;vertical-align:middle"></span>Cache</span> |
| 3526 | <span><span |
| 3527 | style="display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--bd2);margin-right:4px;vertical-align:middle"></span>Free</span> |
| 3528 | </div> |
| 3529 | </div> |
| 3530 | </div> |
| 3531 | <!-- Right: sparkline --> |
| 3532 | <div class="smo-card"> |
| 3533 | <div class="smo-card-title">Usage History (60s)</div> |
| 3534 | <div class="smo-sparkline" id="smo-ram-sparkline" style="height:160px"></div> |
| 3535 | </div> |
| 3536 | </div> |
| 3537 | <!-- Metric cards row --> |
| 3538 | <div class="smo-grid-3"> |
| 3539 | <div class="smo-card smo-metric"> |
| 3540 | <div class="smo-metric-label">Used</div> |
| 3541 | <div class="smo-metric-val" id="smo-ram-used">—</div> |
| 3542 | <div class="smo-metric-sub" id="smo-ram-used-sub"></div> |
| 3543 | </div> |
| 3544 | <div class="smo-card smo-metric"> |
| 3545 | <div class="smo-metric-label">Cache / Buffer</div> |
| 3546 | <div class="smo-metric-val" id="smo-ram-cache">—</div> |
| 3547 | <div class="smo-metric-sub" id="smo-ram-cache-sub"></div> |
| 3548 | </div> |
| 3549 | <div class="smo-card smo-metric"> |
| 3550 | <div class="smo-metric-label">Free</div> |
| 3551 | <div class="smo-metric-val" id="smo-ram-free">—</div> |
| 3552 | <div class="smo-metric-sub" id="smo-ram-free-sub">Total: <span id="smo-ram-total">—</span></div> |
| 3553 | </div> |
| 3554 | </div> |
| 3555 | </div> |
| 3556 | |
| 3557 | <!-- TAB: DISK ──────────────────────── --> |
| 3558 | <div class="smo-section" id="smo-tab-disk"> |
| 3559 | <!-- Global bar --> |
| 3560 | <div class="smo-card" style="margin-bottom:14px"> |
| 3561 | <div style="display:flex;align-items:center;gap:8px;margin-bottom:4px"> |
| 3562 | <span class="smo-card-title" style="margin-bottom:0">Disk Usage</span> |
| 3563 | <span style="margin-left:auto;font-size:11px;color:var(--tx2)">Path: <b id="smo-disk-path" |
| 3564 | style="color:var(--tx)">/</b></span> |
| 3565 | </div> |
| 3566 | <div class="smo-disk-info"> |
| 3567 | <span>Used: <b id="smo-disk-used">—</b></span> |
| 3568 | <span>Free: <b id="smo-disk-free">—</b> / <b id="smo-disk-total">—</b></span> |
| 3569 | </div> |
| 3570 | <div class="smo-disk-bar"> |
| 3571 | <div class="smo-disk-bar-fill" id="smo-disk-bar-fill" style="width:0%"></div> |
| 3572 | </div> |
| 3573 | </div> |
| 3574 | <!-- Treemap + Top-10 --> |
| 3575 | <div class="smo-grid-2"> |
| 3576 | <!-- Treemap --> |
| 3577 | <div class="smo-card"> |
| 3578 | <div class="smo-card-title">Directory Map</div> |
| 3579 | <div class="smo-breadcrumb" id="smo-tm-breadcrumb"></div> |
| 3580 | <div class="smo-treemap" id="smo-treemap"></div> |
| 3581 | <div class="smo-tm-legend" id="smo-tm-legend"> |
| 3582 | <div class="smo-tm-legend-item"> |
| 3583 | <div class="smo-tm-legend-dot" style="background:#4da6ff"></div>Folders |
| 3584 | </div> |
| 3585 | <div class="smo-tm-legend-item"> |
| 3586 | <div class="smo-tm-legend-dot" style="background:#ff8a65"></div>Video |
| 3587 | </div> |
| 3588 | <div class="smo-tm-legend-item"> |
| 3589 | <div class="smo-tm-legend-dot" style="background:#ce93d8"></div>Images |
| 3590 | </div> |
| 3591 | <div class="smo-tm-legend-item"> |
| 3592 | <div class="smo-tm-legend-dot" style="background:#ffb74d"></div>Archives |
| 3593 | </div> |
| 3594 | <div class="smo-tm-legend-item"> |
| 3595 | <div class="smo-tm-legend-dot" style="background:#80cbc4"></div>Code |
| 3596 | </div> |
| 3597 | <div class="smo-tm-legend-item"> |
| 3598 | <div class="smo-tm-legend-dot" style="background:#90caf9"></div>Docs |
| 3599 | </div> |
| 3600 | <div class="smo-tm-legend-item"> |
| 3601 | <div class="smo-tm-legend-dot" style="background:#546e7a"></div>Other |
| 3602 | </div> |
| 3603 | </div> |
| 3604 | </div> |
| 3605 | <!-- Top 10 --> |
| 3606 | <div class="smo-card"> |
| 3607 | <div class="smo-card-title">Top Directories by Size</div> |
| 3608 | <table class="smo-top-list" id="smo-top-list"> |
| 3609 | <tbody></tbody> |
| 3610 | </table> |
| 3611 | </div> |
| 3612 | </div> |
| 3613 | </div> |
| 3614 | |
| 3615 | <!-- TAB: PROCESSES ─────────────────── --> |
| 3616 | <div class="smo-section" id="smo-tab-proc"> |
| 3617 | <div class="smo-proc-header"> |
| 3618 | <span class="smo-proc-total">Total: <b id="smo-proc-count">—</b> processes</span> |
| 3619 | <div class="smo-proc-search"> |
| 3620 | <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" |
| 3621 | stroke-linecap="round" style="color:var(--tx3)"> |
| 3622 | <circle cx="11" cy="11" r="8" /> |
| 3623 | <path d="m21 21-4.35-4.35" /> |
| 3624 | </svg> |
| 3625 | <input class="smo-proc-search-inp" id="smo-proc-q" type="text" placeholder="Search process…" |
| 3626 | autocomplete="off" spellcheck="false"> |
| 3627 | </div> |
| 3628 | <div class="smo-proc-sort-wrap"> |
| 3629 | Sort: |
| 3630 | <select class="smo-proc-sort-sel" id="smo-proc-sort"> |
| 3631 | <option value="cpu">CPU %</option> |
| 3632 | <option value="mem_mb">RAM</option> |
| 3633 | <option value="pid">PID</option> |
| 3634 | <option value="name">Name</option> |
| 3635 | </select> |
| 3636 | </div> |
| 3637 | </div> |
| 3638 | <div style="overflow-x:auto"> |
| 3639 | <table class="smo-table" id="smo-proc-table"> |
| 3640 | <thead> |
| 3641 | <tr> |
| 3642 | <th class="smo-pid" data-col="pid">PID</th> |
| 3643 | <th data-col="name">Name</th> |
| 3644 | <th class="smo-user" data-col="user">User</th> |
| 3645 | <th class="smo-cpu" data-col="cpu">CPU %</th> |
| 3646 | <th class="smo-mem" data-col="mem_mb">RAM</th> |
| 3647 | <th class="smo-stat" data-col="status">Status</th> |
| 3648 | <th class="smo-act">Action</th> |
| 3649 | </tr> |
| 3650 | </thead> |
| 3651 | <tbody id="smo-proc-tbody"></tbody> |
| 3652 | </table> |
| 3653 | </div> |
| 3654 | <button class="smo-load-more" id="smo-proc-more" style="display:none">Load 20 more…</button> |
| 3655 | </div> |
| 3656 | |
| 3657 | <!-- TAB: SYSTEM ────────────────────── --> |
| 3658 | <div class="smo-section" id="smo-tab-sys"> |
| 3659 | <div class="smo-grid-system" style="margin-bottom:14px"> |
| 3660 | <!-- CPU Temp --> |
| 3661 | <div class="smo-card"> |
| 3662 | <div class="smo-card-title"> |
| 3663 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3664 | stroke-linecap="round" stroke-linejoin="round" style="display:inline;margin-right:6px"> |
| 3665 | <path |
| 3666 | d="M14 14.76v1.3a2 2 0 0 1-2 2h-.5a2 2 0 0 1-2-2v-1.3m4 0a2 2 0 0 0-4 0m4 0h.5a2 2 0 0 1 2 2v.5a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-.5a2 2 0 0 1 2-2h.5M7 10a5 5 0 0 1 10 0" /> |
| 3667 | <line x1="12" y1="2" x2="12" y2="6" /> |
| 3668 | </svg> |
| 3669 | CPU Temperature |
| 3670 | <span class="smo-temp-badge smo-temp-ok" id="smo-temp-badge">● OK</span> |
| 3671 | </div> |
| 3672 | <div style="font-size:28px;font-weight:700;color:var(--tx);margin-bottom:8px"> |
| 3673 | <span id="smo-temp-val">—</span> |
| 3674 | </div> |
| 3675 | <div class="smo-bar"> |
| 3676 | <div class="smo-bar-fill" id="smo-temp-bar" style="width:0%"></div> |
| 3677 | </div> |
| 3678 | <div class="smo-sparkline" id="smo-temp-sparkline" style="height:80px;margin-top:12px"></div> |
| 3679 | <div class="smo-temp-legend"> |
| 3680 | <div class="smo-temp-legend-item"> |
| 3681 | <div class="smo-legend-dot" style="background:#22c55e"></div><60°C — OK |
| 3682 | </div> |
| 3683 | <div class="smo-temp-legend-item"> |
| 3684 | <div class="smo-legend-dot" style="background:var(--wn)"></div>60–80°C — WARN |
| 3685 | </div> |
| 3686 | <div class="smo-temp-legend-item"> |
| 3687 | <div class="smo-legend-dot" style="background:var(--er)"></div>>80°C — CRIT |
| 3688 | </div> |
| 3689 | </div> |
| 3690 | </div> |
| 3691 | <!-- Right column: Uptime + Dir --> |
| 3692 | <div style="display:flex;flex-direction:column;gap:14px"> |
| 3693 | <div class="smo-card"> |
| 3694 | <div class="smo-card-title"> |
| 3695 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3696 | stroke-linecap="round" stroke-linejoin="round" style="display:inline;margin-right:6px"> |
| 3697 | <circle cx="12" cy="12" r="9" /> |
| 3698 | <polyline points="12 6 12 12 16 14" /> |
| 3699 | </svg> |
| 3700 | Uptime |
| 3701 | </div> |
| 3702 | <div style="font-size:16px;font-weight:700;color:var(--tx);margin-bottom:6px" id="smo-uptime-val">— |
| 3703 | </div> |
| 3704 | <div class="smo-sys-kv"><span class="smo-sys-k">Boot time</span><span class="smo-sys-v" |
| 3705 | id="smo-boot-time">—</span></div> |
| 3706 | </div> |
| 3707 | <div class="smo-card"> |
| 3708 | <div class="smo-card-title"> |
| 3709 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3710 | stroke-linecap="round" stroke-linejoin="round" style="display:inline;margin-right:6px"> |
| 3711 | <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" /> |
| 3712 | </svg> |
| 3713 | Current Directory |
| 3714 | </div> |
| 3715 | <div class="smo-sys-kv"><span class="smo-sys-k">Path</span><span class="smo-sys-v" id="smo-sys-path" |
| 3716 | style="max-width:180px;overflow:hidden;text-overflow:ellipsis">—</span></div> |
| 3717 | <div class="smo-sys-kv"><span class="smo-sys-k">Items</span><span class="smo-sys-v" |
| 3718 | id="smo-sys-items">—</span></div> |
| 3719 | </div> |
| 3720 | </div> |
| 3721 | </div> |
| 3722 | <!-- Network --> |
| 3723 | <div class="smo-card" id="smo-net-card" style="display:none"> |
| 3724 | <div class="smo-card-title"> |
| 3725 | <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3726 | stroke-linecap="round" stroke-linejoin="round" style="display:inline;margin-right:6px"> |
| 3727 | <circle cx="12" cy="12" r="10" /> |
| 3728 | <path d="M12 16v-4m0-4v4" /> |
| 3729 | </svg> |
| 3730 | Network |
| 3731 | </div> |
| 3732 | <div class="smo-net-row"> |
| 3733 | <span class="smo-net-label"> |
| 3734 | <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3735 | stroke-linecap="round" stroke-linejoin="round" style="display:inline;margin-right:4px"> |
| 3736 | <polyline points="23 4 23 10 17 10" /> |
| 3737 | <polyline points="1 20 1 14 7 14" /> |
| 3738 | <path d="M3.51 9a9 9 0 0 1 14.85-3.36M20.49 15a9 9 0 0 1-14.85 3.36" /> |
| 3739 | </svg> |
| 3740 | Upload |
| 3741 | </span> |
| 3742 | <span class="smo-net-val" id="smo-net-up">—</span> |
| 3743 | <div class="smo-net-bar"> |
| 3744 | <div class="smo-net-bar-fill" id="smo-net-up-bar" style="width:0%"></div> |
| 3745 | </div> |
| 3746 | </div> |
| 3747 | <div class="smo-net-row"> |
| 3748 | <span class="smo-net-label"> |
| 3749 | <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
| 3750 | stroke-linecap="round" stroke-linejoin="round" style="display:inline;margin-right:4px"> |
| 3751 | <polyline points="23 4 23 10 17 10" /> |
| 3752 | <polyline points="1 20 1 14 7 14" /> |
| 3753 | <path d="M3.51 9a9 9 0 0 1 14.85-3.36M20.49 15a9 9 0 0 1-14.85 3.36" /> |
| 3754 | </svg> |
| 3755 | Download |
| 3756 | </span> |
| 3757 | <span class="smo-net-val" id="smo-net-down">—</span> |
| 3758 | <div class="smo-net-bar"> |
| 3759 | <div class="smo-net-bar-fill" id="smo-net-down-bar" style="width:0%"></div> |
| 3760 | </div> |
| 3761 | </div> |
| 3762 | <div style="font-size:10px;color:var(--tx3);margin-top:6px" id="smo-net-iface"></div> |
| 3763 | </div> |
| 3764 | </div> |
| 3765 | |
| 3766 | </div><!-- /smo-body --> |
| 3767 | |
| 3768 | <!-- Footer --> |
| 3769 | <div class="smo-footer"> |
| 3770 | <div class="smo-live-dot"></div> |
| 3771 | <span>Live</span> |
| 3772 | <span class="smo-ts">Last update: <span id="smo-ts">—</span></span> |
| 3773 | <button class="smo-refresh-btn" id="smo-refresh-btn" type="button"> |
| 3774 | <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" |
| 3775 | stroke-linecap="round"> |
| 3776 | <polyline points="23 4 23 10 17 10" /> |
| 3777 | <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" /> |
| 3778 | </svg> |
| 3779 | Refresh now |
| 3780 | </button> |
| 3781 | </div> |
| 3782 | |
| 3783 | </div><!-- /smo-modal --> |
| 3784 | </div><!-- /smo-overlay --> |
| 3785 | |
| 3786 | <!-- KILL CONFIRM MODAL --> |
| 3787 | <div id="smo-kill-overlay" class="smo-kill-overlay"> |
| 3788 | <div class="smo-kill-panel"> |
| 3789 | <div class="smo-kill-head"> |
| 3790 | <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" |
| 3791 | stroke-linecap="round"> |
| 3792 | <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /> |
| 3793 | <line x1="12" y1="9" x2="12" y2="13" /> |
| 3794 | <line x1="12" y1="17" x2="12.01" y2="17" /> |
| 3795 | </svg> |
| 3796 | Confirm Termination |
| 3797 | </div> |
| 3798 | <div class="smo-kill-body"> |
| 3799 | Terminate this process?<br> |
| 3800 | Name: <b id="smo-kill-name">—</b><br> |
| 3801 | PID: <b id="smo-kill-pid">—</b><br> |
| 3802 | User: <b id="smo-kill-user">—</b> |
| 3803 | <div class="smo-kill-warn">⚠ This operation is irreversible.</div> |
| 3804 | </div> |
| 3805 | <div class="smo-kill-foot"> |
| 3806 | <button class="smo-kill-cancel" id="smo-kill-cancel" type="button">Cancel</button> |
| 3807 | <button class="smo-kill-confirm" id="smo-kill-do" type="button">Terminate →</button> |
| 3808 | </div> |
| 3809 | </div> |
| 3810 | </div> |
| 3811 | |
| 3812 | <!-- STATS MODAL TOAST WRAP --> |
| 3813 | <div id="smo-toast-wrap" class="smo-toast-wrap"></div> |
| 3814 | |
| 3815 | <!-- TREEMAP TOOLTIP --> |
| 3816 | <div id="smo-tm-tip" class="smo-tm-tip"> |
| 3817 | <div class="smo-tm-tip-name" id="smo-tm-tip-name"></div> |
| 3818 | <div class="smo-tm-tip-size" id="smo-tm-tip-size"></div> |
| 3819 | <div class="smo-tm-tip-pct" id="smo-tm-tip-pct"></div> |
| 3820 | <div class="smo-tm-tip-hint" id="smo-tm-tip-hint">Click to drill down</div> |
| 3821 | </div> |
| 3822 | |
| 3823 | |
| 3824 | <script> |
| 3825 | 'use strict'; |
| 3826 | var D = document, $ = D.getElementById.bind(D), E = encodeURIComponent; |
| 3827 | var S = { path: '/', entries: [], view: 'grid', sort: 'name', sortAsc: true, statsTimer: null }; |
| 3828 | var THEMES = [ |
| 3829 | { id: 'ps5', name: 'PS5', desc: 'Deep ocean blue', sw: '#2b8cff' }, |
| 3830 | { id: 'matrix', name: 'Matrix', desc: 'Terminal phosphor', sw: '#00e639' }, |
| 3831 | { id: 'sunset', name: 'Sunset', desc: 'Warm neon dusk', sw: '#ff6535' }, |
| 3832 | { id: 'arctic', name: 'Arctic', desc: 'Glacier cyan', sw: '#00d4ff' }, |
| 3833 | { id: 'neon', name: 'Neon', desc: 'Club lights purple', sw: '#c800ff' }, |
| 3834 | { id: 'amber', name: 'Amber', desc: 'Retro CRT amber', sw: '#ffb700' }, |
| 3835 | ]; |
| 3836 | |
| 3837 | /* ── SVG ICONS ── */ |
| 3838 | var ICO = { |
| 3839 | folder: '<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>', |
| 3840 | file: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>', |
| 3841 | code: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>', |
| 3842 | web: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>', |
| 3843 | style: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="2"/><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/></svg>', |
| 3844 | data: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>', |
| 3845 | image: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>', |
| 3846 | video: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>', |
| 3847 | audio: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>', |
| 3848 | archive: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><polyline points="21 8 21 21 3 21 3 8"/><rect x="1" y="3" width="22" height="5"/><line x1="10" y1="12" x2="14" y2="12"/></svg>', |
| 3849 | script: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>', |
| 3850 | binary: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="2" width="16" height="20" rx="2"/><line x1="8" y1="10" x2="16" y2="10"/><line x1="8" y1="14" x2="16" y2="14"/><line x1="8" y1="18" x2="12" y2="18"/></svg>', |
| 3851 | db: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>', |
| 3852 | key: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>', |
| 3853 | log: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><line x1="10" y1="9" x2="8" y2="9"/></svg>', |
| 3854 | sheet: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/></svg>', |
| 3855 | doc: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><line x1="10" y1="9" x2="8" y2="9"/></svg>', |
| 3856 | slide: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>', |
| 3857 | /* small icons for ctx menu / breadcrumb / buttons */ |
| 3858 | home: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>', |
| 3859 | download: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>', |
| 3860 | opendir: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>', |
| 3861 | rename: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>', |
| 3862 | trash: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>', |
| 3863 | newfile: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/><line x1="12" y1="13" x2="12" y2="19"/><line x1="9" y1="16" x2="15" y2="16"/></svg>', |
| 3864 | newfolder: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/><line x1="12" y1="11" x2="12" y2="17"/><line x1="9" y1="14" x2="15" y2="14"/></svg>', |
| 3865 | upload: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>', |
| 3866 | refresh: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>', |
| 3867 | check: '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><polyline points="20 6 9 17 4 12"/></svg>', |
| 3868 | send: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 2L11 13"/><path d="M22 2L15 22L11 13L2 9L22 2"/></svg>', |
| 3869 | pause: '<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="4" width="4" height="16" rx="1"/><rect x="14" y="4" width="4" height="16" rx="1"/></svg>', |
| 3870 | xcancel: '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>', |
| 3871 | }; |
| 3872 | |
| 3873 | /* Map extension → {svg, cls} */ |
| 3874 | function fileIcon(x) { |
| 3875 | if (x.type === 'directory') return { html: ICO.folder, cls: 'fi-dir' }; |
| 3876 | var e = extOf(x.name); |
| 3877 | var codeExts = { js: 1, mjs: 1, cjs: 1, ts: 1, tsx: 1, jsx: 1, py: 1, go: 1, rs: 1, c: 1, cpp: 1, h: 1, hpp: 1, java: 1, rb: 1, php: 1, lua: 1, r: 1, swift: 1, kt: 1, cs: 1, scala: 1 }; |
| 3878 | var webExts = { html: 1, htm: 1 }; |
| 3879 | var styleExts = { css: 1, scss: 1, sass: 1, less: 1, styl: 1 }; |
| 3880 | var dataExts = { json: 1, xml: 1, yaml: 1, yml: 1, toml: 1, ini: 1, cfg: 1, conf: 1, env: 1 }; |
| 3881 | var docExts = { md: 1, txt: 1, rst: 1, pdf: 1 }; |
| 3882 | var imgExts = { png: 1, jpg: 1, jpeg: 1, gif: 1, svg: 1, webp: 1, ico: 1, bmp: 1, tiff: 1, avif: 1 }; |
| 3883 | var vidExts = { mp4: 1, mkv: 1, avi: 1, mov: 1, webm: 1, flv: 1, wmv: 1, m4v: 1 }; |
| 3884 | var audExts = { mp3: 1, wav: 1, flac: 1, ogg: 1, m4a: 1, aac: 1, opus: 1, wma: 1 }; |
| 3885 | var archExts = { zip: 1, tar: 1, gz: 1, bz2: 1, xz: 1, rar: 1, '7z': 1, zst: 1 }; |
| 3886 | var scriptExts = { sh: 1, bash: 1, zsh: 1, fish: 1, ps1: 1, bat: 1, cmd: 1 }; |
| 3887 | var binExts = { exe: 1, bin: 1, deb: 1, rpm: 1, dmg: 1, iso: 1, app: 1, apk: 1 }; |
| 3888 | var dbExts = { db: 1, sql: 1, sqlite: 1, sqlite3: 1, mdb: 1 }; |
| 3889 | var keyExts = { key: 1, pem: 1, cert: 1, crt: 1, p12: 1, pfx: 1 }; |
| 3890 | var logExts = { log: 1, lock: 1 }; |
| 3891 | var sheetExts = { csv: 1, xlsx: 1, xls: 1, tsv: 1, ods: 1 }; |
| 3892 | var docxExts = { doc: 1, docx: 1, rtf: 1, odt: 1 }; |
| 3893 | var slideExts = { ppt: 1, pptx: 1, odp: 1 }; |
| 3894 | |
| 3895 | if (codeExts[e]) return { html: ICO.code, cls: 'fi-code' }; |
| 3896 | if (webExts[e]) return { html: ICO.web, cls: 'fi-web' }; |
| 3897 | if (styleExts[e]) return { html: ICO.style, cls: 'fi-style' }; |
| 3898 | if (dataExts[e]) return { html: ICO.data, cls: 'fi-data' }; |
| 3899 | if (docExts[e]) return { html: ICO.doc, cls: 'fi-doc' }; |
| 3900 | if (imgExts[e]) return { html: ICO.image, cls: 'fi-img' }; |
| 3901 | if (vidExts[e]) return { html: ICO.video, cls: 'fi-video' }; |
| 3902 | if (audExts[e]) return { html: ICO.audio, cls: 'fi-audio' }; |
| 3903 | if (archExts[e]) return { html: ICO.archive, cls: 'fi-arch' }; |
| 3904 | if (scriptExts[e]) return { html: ICO.script, cls: 'fi-script' }; |
| 3905 | if (binExts[e]) return { html: ICO.binary, cls: 'fi-bin' }; |
| 3906 | if (dbExts[e]) return { html: ICO.db, cls: 'fi-db' }; |
| 3907 | if (keyExts[e]) return { html: ICO.key, cls: 'fi-lock' }; |
| 3908 | if (logExts[e]) return { html: ICO.log, cls: 'fi-log' }; |
| 3909 | if (sheetExts[e]) return { html: ICO.sheet, cls: 'fi-sheet' }; |
| 3910 | if (docxExts[e]) return { html: ICO.doc, cls: 'fi-doc' }; |
| 3911 | if (slideExts[e]) return { html: ICO.slide, cls: 'fi-slide' }; |
| 3912 | return { html: ICO.file, cls: 'fi-generic' }; |
| 3913 | } |
| 3914 | |
| 3915 | /* ── HELPERS ── */ |
| 3916 | function csrf() { var m = D.querySelector('meta[name="csrf-token"]'); return m ? m.content : '' } |
| 3917 | function norm(p) { if (typeof p !== 'string' || !p) return '/'; if (p[0] !== '/') p = '/' + p; if (p.length > 1 && p[p.length - 1] === '/') p = p.slice(0, -1); return p } |
| 3918 | function parent(p) { p = norm(p); if (p === '/') return null; var i = p.lastIndexOf('/'); return i <= 0 ? '/' : p.slice(0, i) } |
| 3919 | function join(n) { return S.path === '/' ? '/' + n : S.path + '/' + n } |
| 3920 | function bytes(b) { if (typeof b !== 'number' || b < 0) return '—'; if (b === 0) return '0 B'; var u = ['B', 'KB', 'MB', 'GB', 'TB'], i = Math.min(Math.floor(Math.log(b) / Math.log(1024)), 4); return (b / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0) + ' ' + u[i] } |
| 3921 | function relDate(ts) { if (!ts) return '—'; var d = new Date(ts * 1000); if (isNaN(d.getTime())) return '—'; var diff = Math.floor((Date.now() - d) / 1000); if (diff < 60) return 'just now'; if (diff < 3600) return Math.floor(diff / 60) + 'm ago'; if (diff < 86400) return Math.floor(diff / 3600) + 'h ago'; if (diff < 604800) return Math.floor(diff / 86400) + 'd ago'; return d.toLocaleDateString(undefined, { day: '2-digit', month: 'short', year: 'numeric' }) } |
| 3922 | function extOf(n) { if (!n || typeof n !== 'string') return ''; var p = n.split('.'); return p.length < 2 ? '' : p[p.length - 1].toLowerCase() } |
| 3923 | |
| 3924 | /* ── STATUS / TOAST ── */ |
| 3925 | var _transferActive = 0; |
| 3926 | function setTransferActive(active) { |
| 3927 | _transferActive = active ? 1 : 0; |
| 3928 | if (_transferActive) { |
| 3929 | window.onbeforeunload = function () { return 'Transfer in progress'; }; |
| 3930 | } else { |
| 3931 | window.onbeforeunload = null; |
| 3932 | } |
| 3933 | } |
| 3934 | function ensureTransferIdle(action) { |
| 3935 | if (_transferActive) { |
| 3936 | toast('Wait until the transfer is complete', 'wn'); |
| 3937 | if (typeof action === 'function') action(); |
| 3938 | return false; |
| 3939 | } |
| 3940 | return true; |
| 3941 | } |
| 3942 | function setStatus(t, ok) { var x = $('status'); if (!x) return; x.innerHTML = '<span class="sdot"></span>' + t; x.className = 'status-pill ' + (ok ? 'status-ok' : 'status-bad') } |
| 3943 | var _nt = null; |
| 3944 | function toast(m, t) { var o = D.querySelector('.toast'); if (o) o.remove(); var el = D.createElement('div'); el.className = 'toast ' + (t || ''); el.textContent = (t === 'ok' ? '✓ ' : t === 'er' ? '✕ ' : '') + m; D.body.appendChild(el); clearTimeout(_nt); _nt = setTimeout(function () { if (el.parentNode) el.remove() }, 3000) } |
| 3945 | |
| 3946 | /* ── DROP ── */ |
| 3947 | var _dd = 0; |
| 3948 | var _dropStats = { to: '', speed: 0, time: 0 }; |
| 3949 | function showDrop(t, p, stats) { |
| 3950 | if (typeof t === 'string') $('d-sub').textContent = t; |
| 3951 | if (typeof p === 'number') $('d-bf').style.width = Math.max(0, Math.min(100, p)) + '%'; |
| 3952 | if (stats && typeof stats === 'object') { |
| 3953 | _dropStats = stats; |
| 3954 | var dStats = $('d-stats'); |
| 3955 | if (dStats) { |
| 3956 | $('d-to').textContent = stats.to || ''; |
| 3957 | $('d-speed').textContent = stats.speed > 0 ? (stats.speed / 1024 / 1024).toFixed(2) + ' MB/s' : '—'; |
| 3958 | var mins = Math.floor(stats.time / 60), secs = Math.floor(stats.time % 60); |
| 3959 | $('d-time').textContent = mins > 0 ? mins + 'm ' + secs + 's' : secs + 's'; |
| 3960 | dStats.style.display = 'block'; |
| 3961 | } |
| 3962 | } |
| 3963 | $('drop').classList.add('on'); |
| 3964 | } |
| 3965 | function hideDrop() { |
| 3966 | $('drop').classList.remove('on'); |
| 3967 | $('d-sub').textContent = 'Release files to start uploading'; |
| 3968 | $('d-bf').style.width = '0%'; |
| 3969 | var dStats = $('d-stats'); |
| 3970 | if (dStats) dStats.style.display = 'none'; |
| 3971 | } |
| 3972 | |
| 3973 | /* ── BREADCRUMB ── */ |
| 3974 | function renderBC() { |
| 3975 | var b = $('breadcrumb'); if (!b) return; b.innerHTML = ''; |
| 3976 | var root = D.createElement('span'); root.className = 'crumb' + (S.path === '/' ? ' act' : ''); |
| 3977 | root.innerHTML = ICO.home + ' Root'; |
| 3978 | root.onclick = function () { nav('/') }; b.appendChild(root); |
| 3979 | var parts = norm(S.path).split('/'), acc = ''; |
| 3980 | for (var i = 0; i < parts.length; i++) { |
| 3981 | var p = parts[i]; if (!p) continue; acc += '/' + p; |
| 3982 | var sep = D.createElement('span'); sep.className = 'cr-sep'; sep.textContent = '/'; b.appendChild(sep); |
| 3983 | var seg = D.createElement('span'); seg.className = 'crumb' + (acc === S.path ? ' act' : ''); seg.textContent = p; |
| 3984 | (function (cp) { seg.onclick = function () { nav(cp) } }(acc)); b.appendChild(seg); |
| 3985 | } |
| 3986 | } |
| 3987 | |
| 3988 | /* ── RENDER LIST ── */ |
| 3989 | function render(q) { |
| 3990 | var fl = $('file-list'); if (!fl) return; |
| 3991 | fl.className = 'fl vg-' + S.view; fl.innerHTML = ''; |
| 3992 | var qr = (typeof q === 'string') ? q.trim().toLowerCase() : ''; |
| 3993 | var en = S.entries || []; |
| 3994 | if (!en.length) { fl.appendChild(stateCard('empty', 'Empty directory', false)); updCount(0, 0); return } |
| 3995 | var vis = en.filter(function (x) { |
| 3996 | var nm = (typeof x.name === 'string') ? x.name : String(x.name == null ? '' : x.name); |
| 3997 | return !qr || nm.toLowerCase().indexOf(qr) >= 0 |
| 3998 | }); |
| 3999 | if (!vis.length) { fl.appendChild(stateCard('search', 'No results for "' + qr + '"', false)); updCount(0, en.length); return } |
| 4000 | vis.sort(function (a, b) { |
| 4001 | var ad = (a.type === 'directory') ? 0 : 1, bd = (b.type === 'directory') ? 0 : 1; |
| 4002 | if (ad !== bd) return ad - bd; |
| 4003 | var av = a[S.sort], bv = b[S.sort]; |
| 4004 | var an = (typeof av === 'number'), bn = (typeof bv === 'number'); |
| 4005 | if (an && bn) { |
| 4006 | var cn = av - bv; return S.sortAsc ? cn : -cn; |
| 4007 | } |
| 4008 | av = (typeof av === 'string') ? av : String(av == null ? '' : av); |
| 4009 | bv = (typeof bv === 'string') ? bv : String(bv == null ? '' : bv); |
| 4010 | av = av.toLowerCase(); bv = bv.toLowerCase(); |
| 4011 | var c = (av < bv) ? -1 : (av > bv) ? 1 : 0; return S.sortAsc ? c : -c; |
| 4012 | }); |
| 4013 | updCount(vis.length, en.length); |
| 4014 | if (S.view === 'details') { renderDetails(fl, vis) } else { vis.forEach(function (x) { fl.appendChild(buildCard(x)) }) } |
| 4015 | /* fire lazy size fetch for all visible directories */ |
| 4016 | _dirSizeToken++; |
| 4017 | var _tok = _dirSizeToken; |
| 4018 | var visibleDirs = vis.filter(function (x) { return x.type === 'directory'; }); |
| 4019 | if (visibleDirs.length) { setTimeout(function () { fetchDirSizes(visibleDirs, _tok); }, 0); } |
| 4020 | } |
| 4021 | |
| 4022 | function stateCard(type, msg, isErr) { |
| 4023 | var el = D.createElement('div'); el.className = 's-card' + (isErr ? ' s-err' : ''); |
| 4024 | var icoDiv = D.createElement('div'); icoDiv.className = 's-ico'; |
| 4025 | if (type === 'empty') { icoDiv.innerHTML = '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>' } |
| 4026 | else if (type === 'search') { icoDiv.innerHTML = '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>' } |
| 4027 | else { icoDiv.innerHTML = '<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>' } |
| 4028 | var txt = D.createElement('div'); txt.textContent = msg; |
| 4029 | el.appendChild(icoDiv); el.appendChild(txt); return el; |
| 4030 | } |
| 4031 | |
| 4032 | function updCount(v, t) { |
| 4033 | var el = $('fl-cnt'); if (!el) return; |
| 4034 | if (t === 0) { el.textContent = ''; return } |
| 4035 | el.innerHTML = 'Showing <b>' + v + '</b> of <b>' + t + '</b> items'; |
| 4036 | var sf = $('s-files'); if (sf) sf.textContent = String(t); |
| 4037 | var spf = $('sp-fi'); if (spf) spf.textContent = String(t); |
| 4038 | } |
| 4039 | |
| 4040 | function buildCard(x) { |
| 4041 | var isDir = (x.type === 'directory'), path = join(x.name), ex = isDir ? '' : extOf(x.name); |
| 4042 | var fi = fileIcon(x); |
| 4043 | var c = D.createElement('div'); c.className = 'card'; |
| 4044 | |
| 4045 | var ico = D.createElement('div'); ico.className = 'c-ico ' + fi.cls; ico.innerHTML = fi.html; |
| 4046 | var nm = D.createElement('div'); nm.className = 'c-name'; nm.title = x.name; nm.textContent = x.name; |
| 4047 | |
| 4048 | if (S.view === 'grid') { |
| 4049 | var meta = D.createElement('div'); meta.className = 'c-meta'; |
| 4050 | if (!isDir && ex) { var eb = D.createElement('span'); eb.className = 'xb'; eb.textContent = ex; meta.appendChild(eb) } |
| 4051 | var sb = D.createElement('span'); sb.className = 'sb'; sb.textContent = bytes(x.size); if (isDir) { sb.setAttribute('data-dirpath', path); } meta.appendChild(sb); |
| 4052 | c.appendChild(ico); c.appendChild(nm); c.appendChild(meta); |
| 4053 | } else { |
| 4054 | var right = D.createElement('div'); right.className = 'c-right'; |
| 4055 | if (!isDir && ex) { var eb2 = D.createElement('span'); eb2.className = 'xb'; eb2.textContent = ex; right.appendChild(eb2) } |
| 4056 | var sb2 = D.createElement('span'); sb2.className = 'sb'; sb2.textContent = bytes(x.size); if (isDir) { sb2.setAttribute('data-dirpath', path); } right.appendChild(sb2); |
| 4057 | if (x.modified) { var db = D.createElement('span'); db.className = 'db'; db.textContent = relDate(x.modified); right.appendChild(db) } |
| 4058 | c.appendChild(ico); c.appendChild(nm); c.appendChild(right); |
| 4059 | } |
| 4060 | /* ── Mobile: three-dot action button ── */ |
| 4061 | var actBtn = D.createElement('button'); actBtn.className = 'c-action'; actBtn.type = 'button'; |
| 4062 | actBtn.innerHTML = '⋮'; actBtn.title = 'Actions'; |
| 4063 | if (S.view === 'grid') { c.appendChild(actBtn); } else { var rightWrap = c.querySelector('.c-right'); if (rightWrap) rightWrap.prepend(actBtn); else c.appendChild(actBtn); } |
| 4064 | |
| 4065 | (function (entry, p, dir) { |
| 4066 | c.onclick = function (ev) { |
| 4067 | if (ev.target.closest && ev.target.closest('.c-action')) return; /* ignore action btn clicks */ |
| 4068 | dir ? nav(p) : (location.href = '/api/download?path=' + E(p)); |
| 4069 | }; |
| 4070 | c.oncontextmenu = function (ev) { ev.preventDefault(); showCtx(ev, entry, p, dir) }; |
| 4071 | actBtn.onclick = function (ev) { |
| 4072 | ev.stopPropagation(); |
| 4073 | /* Use button bounding rect for menu position */ |
| 4074 | var r = actBtn.getBoundingClientRect(); |
| 4075 | showCtx({ clientX: r.left, clientY: r.bottom + 4, preventDefault: function () { } }, entry, p, dir); |
| 4076 | }; |
| 4077 | /* ── Long-press (touch-hold) for mobile context menu ── */ |
| 4078 | var _lpt = null; |
| 4079 | c.addEventListener('touchstart', function (ev) { |
| 4080 | _lpt = setTimeout(function () { |
| 4081 | _lpt = null; |
| 4082 | var t = ev.touches[0]; |
| 4083 | showCtx({ clientX: t.clientX, clientY: t.clientY, preventDefault: function () { } }, entry, p, dir); |
| 4084 | }, 500); |
| 4085 | }, { passive: true }); |
| 4086 | c.addEventListener('touchend', function () { if (_lpt) { clearTimeout(_lpt); _lpt = null; } }, { passive: true }); |
| 4087 | c.addEventListener('touchmove', function () { if (_lpt) { clearTimeout(_lpt); _lpt = null; } }, { passive: true }); |
| 4088 | }(x, path, isDir)); |
| 4089 | return c; |
| 4090 | } |
| 4091 | |
| 4092 | function renderDetails(fl, items) { |
| 4093 | var tbl = D.createElement('table'); tbl.className = 'dtbl'; |
| 4094 | var thead = D.createElement('thead'), hr = D.createElement('tr'); |
| 4095 | [{ l: '', k: '', s: 0, cls: 't-ic' }, { l: 'Name', k: 'name', s: 1, cls: 't-nm' }, { l: 'Ext', k: '', s: 0, cls: 't-ex' }, |
| 4096 | { l: 'Size', k: 'size', s: 1, cls: 't-sz' }, { l: 'Type', k: 'type', s: 1, cls: 't-tp' }, { l: 'Modified', k: 'modified', s: 1, cls: 't-dt' } |
| 4097 | ].forEach(function (col) { |
| 4098 | var th = D.createElement('th'); th.className = col.cls || ''; |
| 4099 | th.innerHTML = col.l + (col.s && col.k && S.sort === col.k ? '<span class="sort-a">' + (S.sortAsc ? '▲' : '▼') + '</span>' : ''); |
| 4100 | if (col.s && col.k) { (function (k) { th.onclick = function () { S.sort === k ? S.sortAsc = !S.sortAsc : (S.sort = k, S.sortAsc = true); render($('search').value) } }(col.k)) } |
| 4101 | hr.appendChild(th); |
| 4102 | }); |
| 4103 | thead.appendChild(hr); tbl.appendChild(thead); |
| 4104 | var tbody = D.createElement('tbody'); |
| 4105 | items.forEach(function (x) { |
| 4106 | var isDir = (x.type === 'directory'), path = join(x.name), ex = isDir ? '' : extOf(x.name); |
| 4107 | var fi = fileIcon(x); |
| 4108 | var tr = D.createElement('tr'); |
| 4109 | var tdIc = D.createElement('td'); tdIc.className = 't-ic'; |
| 4110 | var iw = D.createElement('div'); iw.className = 'fi-wrap ' + fi.cls; iw.style.width = '24px'; iw.style.height = '24px'; iw.innerHTML = fi.html; |
| 4111 | tdIc.appendChild(iw); |
| 4112 | var tdNm = D.createElement('td'); tdNm.className = 't-nm'; tdNm.textContent = x.name; |
| 4113 | var tdEx = D.createElement('td'); tdEx.className = 't-ex'; |
| 4114 | if (ex) { var eb = D.createElement('span'); eb.className = 'xb'; eb.textContent = ex; tdEx.appendChild(eb) } |
| 4115 | var tdSz = D.createElement('td'); tdSz.className = 't-sz'; tdSz.textContent = bytes(x.size); if (isDir) { tdSz.setAttribute('data-dirpath', path); } |
| 4116 | var tdTp = D.createElement('td'); tdTp.className = 't-tp'; tdTp.textContent = isDir ? 'Folder' : (ex.toUpperCase() || 'File'); |
| 4117 | var tdDt = D.createElement('td'); tdDt.className = 't-dt'; tdDt.textContent = relDate(x.modified); |
| 4118 | tr.appendChild(tdIc); tr.appendChild(tdNm); tr.appendChild(tdEx); tr.appendChild(tdSz); tr.appendChild(tdTp); tr.appendChild(tdDt); |
| 4119 | (function (entry, p, dir) { |
| 4120 | tr.onclick = function () { dir ? nav(p) : (location.href = '/api/download?path=' + E(p)) }; |
| 4121 | tr.oncontextmenu = function (ev) { ev.preventDefault(); showCtx(ev, entry, p, dir) }; |
| 4122 | }(x, path, isDir)); |
| 4123 | tbody.appendChild(tr); |
| 4124 | }); |
| 4125 | tbl.appendChild(tbody); fl.appendChild(tbl); |
| 4126 | } |
| 4127 | |
| 4128 | /* ── LAZY DIR SIZES ── */ |
| 4129 | var _dirSizeToken = 0; |
| 4130 | /** |
| 4131 | * Fetch directory sizes with concurrency limit (max 2 parallel) |
| 4132 | * to avoid overwhelming the server on deep USB/exFAT trees. |
| 4133 | * Stops if the user navigates away (stale token check). |
| 4134 | * Partial sizes (server hit time/entry budget) shown with ~ prefix. |
| 4135 | */ |
| 4136 | var DIR_SIZE_CONCURRENCY = 2; |
| 4137 | function fetchDirSizes(dirs, token) { |
| 4138 | if (!dirs || !dirs.length) return; |
| 4139 | var idx = 0, active = 0; |
| 4140 | |
| 4141 | function next() { |
| 4142 | while (active < DIR_SIZE_CONCURRENCY && idx < dirs.length) { |
| 4143 | if (token !== _dirSizeToken) return; |
| 4144 | (function (entry) { |
| 4145 | var p = join(entry.name); |
| 4146 | var sel = '[data-dirpath="' + p.replace(/"/g, '\\"') + '"]'; |
| 4147 | var els = D.querySelectorAll(sel); |
| 4148 | for (var j = 0; j < els.length; j++) { els[j].textContent = '\u27F3'; els[j].style.opacity = '0.6'; } |
| 4149 | |
| 4150 | active++; |
| 4151 | fetch('/api/dirsize?path=' + E(p)) |
| 4152 | .then(function (r) { return r.ok ? r.json() : null }) |
| 4153 | .then(function (d) { |
| 4154 | if (!d || typeof d.size !== 'number') return; |
| 4155 | if (token !== _dirSizeToken) return; |
| 4156 | for (var i = 0; i < S.entries.length; i++) { |
| 4157 | if (S.entries[i].name === entry.name) { S.entries[i].size = d.size; break; } |
| 4158 | } |
| 4159 | var label = d.partial ? ('~' + bytes(d.size)) : bytes(d.size); |
| 4160 | var els2 = D.querySelectorAll(sel); |
| 4161 | for (var j = 0; j < els2.length; j++) { els2[j].textContent = label; els2[j].style.opacity = '1'; } |
| 4162 | }) |
| 4163 | .catch(function () { |
| 4164 | var els3 = D.querySelectorAll(sel); |
| 4165 | for (var j = 0; j < els3.length; j++) { els3[j].textContent = '\u2014'; els3[j].style.opacity = '1'; } |
| 4166 | }) |
| 4167 | .then(function () { active--; next(); }); |
| 4168 | })(dirs[idx++]); |
| 4169 | } |
| 4170 | } |
| 4171 | next(); |
| 4172 | } |
| 4173 | |
| 4174 | /* ── CACHE HELPERS ── */ |
| 4175 | var _syncTimer = null; |
| 4176 | function getCacheKey(path) { return 'zftpd_list_' + path } |
| 4177 | /** |
| 4178 | * DISABLED: localStorage caching removed to prevent stale/ghost data. |
| 4179 | * Always fetch fresh listings from server to ensure UI consistency. |
| 4180 | */ |
| 4181 | function getCachedListing(path) { |
| 4182 | return null; /* Always fetch fresh from server */ |
| 4183 | } |
| 4184 | function setCachedListing(path, data) { |
| 4185 | /* No-op: caching disabled */ |
| 4186 | } |
| 4187 | /** |
| 4188 | * Fix #1 — invalidate the localStorage cache for a directory. |
| 4189 | * |
| 4190 | * WHY: nav() shows cached entries immediately before fetching fresh data. |
| 4191 | * After a delete, rename, or create the cache is stale, so the deleted/old |
| 4192 | * entries would flash on screen until the background fetch completed. |
| 4193 | * Removing the cache key forces nav() to show the loading spinner and only |
| 4194 | * render once the server confirms the new state. |
| 4195 | * |
| 4196 | * @param {string} path The directory whose cache entry should be removed. |
| 4197 | */ |
| 4198 | function invalidateCache(path) { |
| 4199 | try { localStorage.removeItem(getCacheKey(path)); } catch (e) { /* ignore */ } |
| 4200 | } |
| 4201 | function cleanupCache() { |
| 4202 | try { |
| 4203 | var keys = []; |
| 4204 | for (var i = 0; i < localStorage.length; i++) { |
| 4205 | var k = localStorage.key(i); |
| 4206 | if (k && k.indexOf('zftpd_list_') === 0) { |
| 4207 | keys.push(k); |
| 4208 | } |
| 4209 | } |
| 4210 | /* Keep only the 50 most recent entries (FIFO removal) */ |
| 4211 | if (keys.length > 50) { |
| 4212 | for (var j = 0; j < keys.length - 50; j++) { |
| 4213 | localStorage.removeItem(keys[j]); |
| 4214 | } |
| 4215 | } |
| 4216 | } catch (e) { /* ignore */ } |
| 4217 | } |
| 4218 | function mergeEntries(cached, fresh) { |
| 4219 | if (!Array.isArray(fresh)) return cached; |
| 4220 | var map = {}; |
| 4221 | for (var i = 0; i < fresh.length; i++) { |
| 4222 | map[fresh[i].name] = fresh[i]; |
| 4223 | } |
| 4224 | for (var j = 0; j < cached.length; j++) { |
| 4225 | var name = cached[j].name; |
| 4226 | if (map[name]) { |
| 4227 | if (map[name].mtime !== cached[j].mtime || map[name].size !== cached[j].size) { |
| 4228 | cached[j] = map[name]; |
| 4229 | } |
| 4230 | } |
| 4231 | } |
| 4232 | for (var k in map) { |
| 4233 | var found = false; |
| 4234 | for (var m = 0; m < cached.length; m++) { |
| 4235 | if (cached[m].name === k) { found = true; break } |
| 4236 | } |
| 4237 | if (!found) cached.push(map[k]); |
| 4238 | } |
| 4239 | cached.sort(function (a, b) { return (a.name || '').localeCompare(b.name || '') }); |
| 4240 | return cached; |
| 4241 | } |
| 4242 | function backgroundSync() { |
| 4243 | var path = S.path; |
| 4244 | if (!path) return; |
| 4245 | var cached = getCachedListing(path); |
| 4246 | if (!cached || !cached.entries) return; |
| 4247 | |
| 4248 | fetch('/api/list?path=' + E(path)) |
| 4249 | .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json() }) |
| 4250 | .then(function (d) { |
| 4251 | if (!d || !Array.isArray(d.entries)) return; |
| 4252 | var entries = mergeEntries(cached.entries, d.entries); |
| 4253 | var changed = false; |
| 4254 | for (var i = 0; i < entries.length; i++) { |
| 4255 | if (entries[i].mtime !== (cached.entries[i] && cached.entries[i].mtime) || |
| 4256 | entries[i].size !== (cached.entries[i] && cached.entries[i].size)) { |
| 4257 | changed = true; |
| 4258 | break; |
| 4259 | } |
| 4260 | } |
| 4261 | if (changed || entries.length !== cached.entries.length) { |
| 4262 | S.entries = entries; |
| 4263 | setCachedListing(path, { entries: entries }); |
| 4264 | render($('search').value); |
| 4265 | } |
| 4266 | }) |
| 4267 | .catch(function () { /* ignore background sync errors */ }); |
| 4268 | } |
| 4269 | |
| 4270 | /* ── NAVIGATE ── */ |
| 4271 | function nav(path) { |
| 4272 | if (_transferActive) { toast('Wait until the transfer is complete', 'wn'); return; } |
| 4273 | if (typeof path !== 'string') return; |
| 4274 | var prev = S.path, next = norm(path); |
| 4275 | var fl = $('file-list'); |
| 4276 | var cached = getCachedListing(next); |
| 4277 | |
| 4278 | /* Clear previous sync timer */ |
| 4279 | if (_syncTimer) clearInterval(_syncTimer); |
| 4280 | |
| 4281 | /* Show cached data immediately if available */ |
| 4282 | if (cached && cached.entries) { |
| 4283 | S.path = next; |
| 4284 | var cp = $('current-path'); if (cp) cp.textContent = S.path; |
| 4285 | var spt = $('sp-pt'); if (spt) spt.textContent = S.path; |
| 4286 | S.entries = cached.entries; |
| 4287 | renderBC(); render($('search').value); setStatus('Connected', true); refreshStats(); |
| 4288 | if (fl) fl.className = 'fl vg-' + S.view; |
| 4289 | } else { |
| 4290 | /* No cache, show loading spinner */ |
| 4291 | if (fl) { fl.className = 'fl vg-' + S.view; fl.innerHTML = '<div class="s-card"><div class="loader"></div><div>Loading\u2026</div></div>' } |
| 4292 | } |
| 4293 | var fc = $('fl-cnt'); if (fc) fc.textContent = ''; |
| 4294 | |
| 4295 | /* Fetch fresh data in background */ |
| 4296 | fetch('/api/list?path=' + E(next)) |
| 4297 | .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json() }) |
| 4298 | .then(function (d) { |
| 4299 | if (!d || !Array.isArray(d.entries)) throw new Error('Invalid response'); |
| 4300 | var entries = d.entries; |
| 4301 | |
| 4302 | /* Merge with cached data to preserve sorting/filtering */ |
| 4303 | if (cached && cached.entries) { |
| 4304 | entries = mergeEntries(cached.entries, entries); |
| 4305 | } |
| 4306 | |
| 4307 | /* Update state and cache */ |
| 4308 | S.path = next; |
| 4309 | var cp = $('current-path'); if (cp) cp.textContent = S.path; |
| 4310 | var spt = $('sp-pt'); if (spt) spt.textContent = S.path; |
| 4311 | S.entries = entries; |
| 4312 | setCachedListing(next, { entries: entries }); |
| 4313 | |
| 4314 | /* Render if not already rendered from cache */ |
| 4315 | if (!cached || !cached.entries) { |
| 4316 | renderBC(); render($('search').value); |
| 4317 | } else { |
| 4318 | render($('search').value); |
| 4319 | } |
| 4320 | setStatus('Connected', true); refreshStats(); |
| 4321 | |
| 4322 | /* Start background sync timer (every 30 seconds) */ |
| 4323 | if (_syncTimer) clearInterval(_syncTimer); |
| 4324 | _syncTimer = setInterval(backgroundSync, 30000); |
| 4325 | }) |
| 4326 | .catch(function (e) { |
| 4327 | if (e && e.message === 'HTTP 403') { toast('Directory bloccata per sicurezza', 'wn'); setStatus('Connected', true); nav(prev); return } |
| 4328 | if (!cached || !cached.entries) { |
| 4329 | var fl2 = $('file-list'); if (fl2) { fl2.innerHTML = ''; fl2.appendChild(stateCard('error', 'Failed to load directory', true)) } |
| 4330 | setStatus('Error', false); |
| 4331 | } |
| 4332 | toast('Load failed: ' + e.message, 'er') |
| 4333 | }); |
| 4334 | } |
| 4335 | |
| 4336 | /* ── UPLOAD (with transfer card, parallel) ── */ |
| 4337 | function upload(files) { |
| 4338 | if (!files || !files.length) return; |
| 4339 | if (!ensureTransferIdle()) return; |
| 4340 | setTransferActive(true); |
| 4341 | var arr = Array.prototype.slice.call(files); |
| 4342 | var totalSize = 0, totalLoaded = 0; |
| 4343 | for (var i = 0; i < arr.length; i++) { totalSize += arr[i].size; } |
| 4344 | |
| 4345 | var activeUploads = 0, nextIdx = 0, completed = 0; |
| 4346 | var startT = Date.now(); |
| 4347 | var MAX_PARALLEL = 8; |
| 4348 | |
| 4349 | function startNextUpload() { |
| 4350 | if (nextIdx >= arr.length) return; |
| 4351 | if (activeUploads >= MAX_PARALLEL) return; |
| 4352 | |
| 4353 | activeUploads++; |
| 4354 | var idx = nextIdx++; |
| 4355 | var f = arr[idx]; |
| 4356 | |
| 4357 | /* Extract directory and filename from webkitRelativePath (for folder uploads) */ |
| 4358 | var relPath = f.webkitRelativePath || f.name; |
| 4359 | var lastSlash = relPath.lastIndexOf('/'); |
| 4360 | var dirPart = lastSlash > 0 ? relPath.substring(0, lastSlash) : ''; |
| 4361 | var namePart = lastSlash > 0 ? relPath.substring(lastSlash + 1) : relPath; |
| 4362 | var uploadPath = dirPart ? (S.path === '/' ? '/' + dirPart : S.path + '/' + dirPart) : S.path; |
| 4363 | |
| 4364 | var xhr = new XMLHttpRequest(); |
| 4365 | xhr.open('POST', '/api/upload?path=' + E(uploadPath) + '&name=' + E(namePart), true); |
| 4366 | var tok = csrf(); if (tok) xhr.setRequestHeader('X-CSRF-Token', tok); |
| 4367 | |
| 4368 | /* ─── transfer card ─── */ |
| 4369 | var card = xferCardCreate('UPLOADING\u2026', relPath, f.size, uploadPath); |
| 4370 | var fileLoaded = 0; |
| 4371 | |
| 4372 | xhr.upload.onprogress = function (ev) { |
| 4373 | if (!ev.lengthComputable) return; |
| 4374 | var delta = ev.loaded - fileLoaded; |
| 4375 | fileLoaded = ev.loaded; |
| 4376 | totalLoaded += delta; |
| 4377 | var pct = totalSize > 0 ? Math.floor(totalLoaded / totalSize * 100) : 0; |
| 4378 | var elapsed = (Date.now() - startT) / 1000; |
| 4379 | var speed = elapsed > 0 ? totalLoaded / elapsed : 0; |
| 4380 | showDrop(null, pct, { to: S.path, speed: speed, time: elapsed }); |
| 4381 | xferCardUpdate(card, Math.floor(ev.loaded / ev.total * 100), speed, elapsed); |
| 4382 | }; |
| 4383 | |
| 4384 | xhr.onload = function () { |
| 4385 | activeUploads--; |
| 4386 | if (xhr.status >= 200 && xhr.status < 300) { |
| 4387 | xferCardUpdate(card, 100, 0, 0); |
| 4388 | xferCardDone(card); |
| 4389 | completed++; |
| 4390 | if (completed === arr.length) { |
| 4391 | hideDrop(); invalidateCache(S.path); setTransferActive(false); nav(S.path); toast('Uploaded ' + arr.length + ' file(s)', 'ok'); |
| 4392 | } else { |
| 4393 | startNextUpload(); |
| 4394 | } |
| 4395 | } else { |
| 4396 | var errMsg = 'HTTP ' + xhr.status; |
| 4397 | try { |
| 4398 | var resp = JSON.parse(xhr.responseText); |
| 4399 | if (resp && resp.error) errMsg = resp.error; |
| 4400 | } catch (e) { } |
| 4401 | setStatus('Error', false); setTransferActive(false); toast('Upload failed: ' + errMsg + ' (' + relPath + ')', 'er'); |
| 4402 | xferCardDone(card); setTimeout(hideDrop, 800); |
| 4403 | } |
| 4404 | }; |
| 4405 | |
| 4406 | xhr.onerror = function () { |
| 4407 | activeUploads--; |
| 4408 | setStatus('Error', false); setTransferActive(false); toast('Upload failed: Network error (' + relPath + ')', 'er'); |
| 4409 | xferCardDone(card); setTimeout(hideDrop, 800); |
| 4410 | }; |
| 4411 | |
| 4412 | card._xhr = xhr; card._paused = false; card._file = f; card._idx = idx; |
| 4413 | xhr.send(f); |
| 4414 | |
| 4415 | /* Start next upload if we haven't reached MAX_PARALLEL yet */ |
| 4416 | if (activeUploads < MAX_PARALLEL && nextIdx < arr.length) { |
| 4417 | startNextUpload(); |
| 4418 | } |
| 4419 | } |
| 4420 | |
| 4421 | setStatus('Uploading\u2026', false); |
| 4422 | startNextUpload(); |
| 4423 | } |
| 4424 | |
| 4425 | /* ── FILE OPS ── */ |
| 4426 | function mkFile() { |
| 4427 | var n = prompt('New file name:'); if (!n || !n.trim()) return; n = n.trim(); |
| 4428 | fetch('/api/create_file?path=' + E(S.path) + '&name=' + E(n), { method: 'POST', headers: { 'Content-Type': 'text/plain', 'X-CSRF-Token': csrf() }, body: '' }) |
| 4429 | .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json() }).then(function () { invalidateCache(S.path); nav(S.path); toast('Created: ' + n, 'ok') }).catch(function (e) { toast('Create failed: ' + e.message, 'er') }) |
| 4430 | } |
| 4431 | function mkDir() { |
| 4432 | var n = prompt('New folder name:'); if (!n || !n.trim()) return; n = n.trim(); |
| 4433 | fetch('/api/create_dir?path=' + E(S.path) + '&name=' + E(n), { method: 'POST', headers: { 'X-CSRF-Token': csrf() } }) |
| 4434 | .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json() }).then(function () { invalidateCache(S.path); nav(S.path); toast('Folder created: ' + n, 'ok') }).catch(function (e) { toast('Folder failed: ' + e.message, 'er') }) |
| 4435 | } |
| 4436 | function del(p, n) { |
| 4437 | /* Find entry to check if it's a directory */ |
| 4438 | var entry = null; |
| 4439 | for (var i = 0; i < S.entries.length; i++) { |
| 4440 | if (S.entries[i].name === n) { entry = S.entries[i]; break } |
| 4441 | } |
| 4442 | var isDir = entry && entry.type === 'dir'; |
| 4443 | |
| 4444 | var msg = isDir ? 'Delete folder "' + n + '" and all contents? This cannot be undone.' : 'Delete "' + n + '"? This cannot be undone.'; |
| 4445 | if (!confirm(msg)) return; |
| 4446 | |
| 4447 | var url = '/api/delete?path=' + E(p); |
| 4448 | if (isDir) url += '&recursive=1'; |
| 4449 | |
| 4450 | fetch(url, { method: 'POST', headers: { 'X-CSRF-Token': csrf() } }) |
| 4451 | .then(function (r) { |
| 4452 | if (r.status === 409) { |
| 4453 | /* Non-empty directory without recursive flag — ask for confirmation */ |
| 4454 | if (confirm('Folder is not empty. Delete all contents?')) { |
| 4455 | return fetch('/api/delete?path=' + E(p) + '&recursive=1', { method: 'POST', headers: { 'X-CSRF-Token': csrf() } }); |
| 4456 | } else { |
| 4457 | throw new Error('Cancelled'); |
| 4458 | } |
| 4459 | } |
| 4460 | if (!r.ok) throw new Error('HTTP ' + r.status); |
| 4461 | return r.json(); |
| 4462 | }) |
| 4463 | .then(function () { invalidateCache(S.path); nav(S.path); toast('Deleted: ' + n, 'ok') }) |
| 4464 | .catch(function (e) { if (e.message !== 'Cancelled') toast('Delete failed: ' + e.message, 'er') }) |
| 4465 | } |
| 4466 | function ren(p, old) { |
| 4467 | var n = prompt('Rename to:', old); if (!n || n.trim() === old || !n.trim()) return; n = n.trim(); |
| 4468 | fetch('/api/rename?path=' + E(p) + '&name=' + E(n), { method: 'POST', headers: { 'X-CSRF-Token': csrf() } }) |
| 4469 | .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json() }).then(function () { invalidateCache(S.path); nav(S.path); toast('Renamed to: ' + n, 'ok') }).catch(function (e) { toast('Rename failed: ' + e.message, 'er') }) |
| 4470 | } |
| 4471 | |
| 4472 | /* ── CONTEXT MENU ── */ |
| 4473 | function showCtx(ev, entry, p, isDir) { |
| 4474 | var m = $('ctx'); if (!m) return; m.innerHTML = ''; |
| 4475 | if (entry) { |
| 4476 | addSec(m, (isDir ? ICO.opendir : ICO.file) + ' ' + entry.name); |
| 4477 | if (!isDir) addItem(m, ICO.download, 'Download', false, function () { location.href = '/api/download?path=' + E(p) }); |
| 4478 | else addItem(m, ICO.opendir, 'Open Folder', false, function () { nav(p) }); |
| 4479 | addItem(m, ICO.send, 'Send to\u2026', false, function () { showSendToModal(entry, p) }); |
| 4480 | addItem(m, ICO.rename, 'Rename', false, function () { ren(p, entry.name) }); |
| 4481 | addSep(m); |
| 4482 | addItem(m, ICO.trash, 'Delete', true, function () { del(p, entry.name) }); |
| 4483 | } else { |
| 4484 | addSec(m, ICO.newfolder + ' ' + (S.path === '/' ? 'Root' : S.path.split('/').pop())); |
| 4485 | addItem(m, ICO.newfile, 'New File', false, mkFile); |
| 4486 | addItem(m, ICO.newfolder, 'New Folder', false, mkDir); |
| 4487 | addSep(m); |
| 4488 | addItem(m, ICO.upload, 'Upload File', false, function () { $('file-input').click() }); |
| 4489 | addItem(m, ICO.upload, 'Upload Folder', false, function () { $('folder-input').click() }); |
| 4490 | addSep(m); |
| 4491 | addItem(m, ICO.refresh, 'Refresh', false, function () { nav(S.path) }); |
| 4492 | } |
| 4493 | var vw = window.innerWidth || 800, vh = window.innerHeight || 600; |
| 4494 | m.style.left = Math.min(ev.clientX, vw - 202) + 'px'; |
| 4495 | m.style.top = Math.min(ev.clientY, vh - 240) + 'px'; |
| 4496 | m.classList.add('on'); |
| 4497 | } |
| 4498 | function addSec(m, h) { var el = D.createElement('div'); el.className = 'c-sec'; el.innerHTML = h; m.appendChild(el) } |
| 4499 | function addSep(m) { var s = D.createElement('div'); s.className = 'c-sep'; m.appendChild(s) } |
| 4500 | function addItem(m, ico, l, red, fn) { |
| 4501 | var el = D.createElement('div'); el.className = 'ci' + (red ? ' red' : ''); |
| 4502 | el.innerHTML = '<span class="ci-i">' + ico + '</span><span class="ci-l">' + l + '</span>'; |
| 4503 | el.onclick = function () { hideCtx(); fn() }; m.appendChild(el); |
| 4504 | } |
| 4505 | function hideCtx() { var m = $('ctx'); if (m) m.classList.remove('on') } |
| 4506 | |
| 4507 | /* ═══════════════════════════════════════════════════════════════ |
| 4508 | * SEND-TO MODAL |
| 4509 | * |
| 4510 | * Opens a folder-browser overlay. The user navigates to the |
| 4511 | * desired destination directory, then clicks "Send Here". |
| 4512 | * The file/folder is moved via POST /api/rename. |
| 4513 | * |
| 4514 | * ┌──────────────────────────────────────┐ |
| 4515 | * │ Send to… [X] │ |
| 4516 | * │ / > data > homebrew │ ← breadcrumb |
| 4517 | * │ ┌──────────────────────────────────┐ │ |
| 4518 | * │ │ 📁 apps │ │ ← folder rows |
| 4519 | * │ │ 📁 games │ │ |
| 4520 | * │ │ 📁 media │ │ |
| 4521 | * │ └──────────────────────────────────┘ │ |
| 4522 | * │ [Cancel] [Send Here] │ |
| 4523 | * └──────────────────────────────────────┘ |
| 4524 | * ═══════════════════════════════════════════════════════════════ */ |
| 4525 | var _smSrc = null; /* {entry, srcPath} currently being moved */ |
| 4526 | var _smPath = '/'; /* path currently shown inside the modal */ |
| 4527 | |
| 4528 | function showSendToModal(entry, srcPath) { |
| 4529 | _smSrc = { entry: entry, srcPath: srcPath }; |
| 4530 | /* Always start browsing from root so the user sees the full tree */ |
| 4531 | _smPath = '/'; |
| 4532 | $('send-modal').classList.add('on'); |
| 4533 | smNav(_smPath); |
| 4534 | } |
| 4535 | function hideSendToModal() { |
| 4536 | $('send-modal').classList.remove('on'); |
| 4537 | _smSrc = null; |
| 4538 | } |
| 4539 | |
| 4540 | /* Navigate inside the modal */ |
| 4541 | function smNav(path) { |
| 4542 | _smPath = norm(path); |
| 4543 | smRenderCrumb(); |
| 4544 | var body = $('sm-body'); |
| 4545 | body.innerHTML = '<div class="sm-empty"><div class="loader"></div></div>'; |
| 4546 | fetch('/api/list?path=' + E(_smPath)) |
| 4547 | .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json() }) |
| 4548 | .then(function (d) { |
| 4549 | var entries = (d && Array.isArray(d.entries)) ? d.entries : []; |
| 4550 | var dirs = entries.filter(function (x) { return x.type === 'directory' }); |
| 4551 | dirs.sort(function (a, b) { |
| 4552 | var an = (a.name || '').toLowerCase(), bn = (b.name || '').toLowerCase(); |
| 4553 | return an < bn ? -1 : an > bn ? 1 : 0; |
| 4554 | }); |
| 4555 | body.innerHTML = ''; |
| 4556 | if (!dirs.length) { |
| 4557 | body.innerHTML = '<div class="sm-empty">No sub-folders here</div>'; |
| 4558 | return; |
| 4559 | } |
| 4560 | dirs.forEach(function (d) { |
| 4561 | var row = D.createElement('div'); row.className = 'sm-row'; |
| 4562 | row.innerHTML = '<div class="sm-row-ico">' + ICO.folder + '</div>' + |
| 4563 | '<div class="sm-row-name">' + d.name + '</div>'; |
| 4564 | row.ondblclick = function () { smNav(_smPath === '/' ? '/' + d.name : _smPath + '/' + d.name) }; |
| 4565 | row.onclick = function () { |
| 4566 | var prev = body.querySelector('.sm-row.active'); |
| 4567 | if (prev) prev.classList.remove('active'); |
| 4568 | row.classList.add('active'); |
| 4569 | }; |
| 4570 | body.appendChild(row); |
| 4571 | }); |
| 4572 | }) |
| 4573 | .catch(function (e) { |
| 4574 | body.innerHTML = '<div class="sm-empty" style="color:var(--er)">Failed to load: ' + e.message + '</div>'; |
| 4575 | }); |
| 4576 | } |
| 4577 | |
| 4578 | /* Breadcrumb inside the modal */ |
| 4579 | function smRenderCrumb() { |
| 4580 | var bc = $('sm-crumb'); bc.innerHTML = ''; |
| 4581 | var root = D.createElement('span'); root.className = 'crumb' + (_smPath === '/' ? ' act' : ''); |
| 4582 | root.innerHTML = ICO.home + ' Root'; |
| 4583 | root.onclick = function () { smNav('/') }; bc.appendChild(root); |
| 4584 | var parts = norm(_smPath).split('/'), acc = ''; |
| 4585 | for (var i = 0; i < parts.length; i++) { |
| 4586 | var p = parts[i]; if (!p) continue; acc += '/' + p; |
| 4587 | var sep = D.createElement('span'); sep.className = 'cr-sep'; sep.textContent = '/'; bc.appendChild(sep); |
| 4588 | var seg = D.createElement('span'); seg.className = 'crumb' + (acc === _smPath ? ' act' : ''); seg.textContent = p; |
| 4589 | (function (cp) { seg.onclick = function () { smNav(cp) } }(acc)); bc.appendChild(seg); |
| 4590 | } |
| 4591 | } |
| 4592 | |
| 4593 | /* Execute the move */ |
| 4594 | function sendTo() { |
| 4595 | if (!_smSrc) return; |
| 4596 | if (!ensureTransferIdle()) return; |
| 4597 | var src = _smSrc.srcPath; |
| 4598 | var destDir = _smPath; |
| 4599 | var name = _smSrc.entry.name; |
| 4600 | var totalBytes = _smSrc.entry.size || 0; |
| 4601 | var dest = destDir === '/' ? '/' + name : destDir + '/' + name; |
| 4602 | if (norm(dest) === norm(src)) { toast('Source and destination are the same', 'wn'); return } |
| 4603 | |
| 4604 | /* Save data BEFORE closing the modal (which nullifies _smSrc) */ |
| 4605 | var card = xferCardCreate('COPYING\u2026', name, totalBytes, destDir); |
| 4606 | card._isServerCopy = true; |
| 4607 | hideSendToModal(); |
| 4608 | setTransferActive(true); |
| 4609 | |
| 4610 | var startT = Date.now(); |
| 4611 | |
| 4612 | /* |
| 4613 | * POST /api/copy returns immediately (async=true). |
| 4614 | * The actual copy runs in a background pthread. |
| 4615 | * We poll /api/copy_progress every 500ms for: |
| 4616 | * - Real-time progress (bytes_copied, speed) |
| 4617 | * - Completion detection (done=true) |
| 4618 | * - Error detection (error=true) |
| 4619 | */ |
| 4620 | fetch('/api/copy?path=' + E(src) + '&dst=' + E(destDir) + '&totalsize=' + totalBytes, { method: 'POST', headers: { 'X-CSRF-Token': csrf() } }) |
| 4621 | .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json() }) |
| 4622 | .then(function () { |
| 4623 | /* Copy started — begin progress polling */ |
| 4624 | var pollTimer = setInterval(function () { |
| 4625 | fetch('/api/copy_progress') |
| 4626 | .then(function (r) { return r.json() }) |
| 4627 | .then(function (d) { |
| 4628 | if (!d) return; |
| 4629 | var elapsed = (Date.now() - startT) / 1000; |
| 4630 | var speed = elapsed > 0 ? d.bytes_copied / elapsed : 0; |
| 4631 | |
| 4632 | if (d.done) { |
| 4633 | /* Copy finished (success or error) */ |
| 4634 | clearInterval(pollTimer); |
| 4635 | if (d.error) { |
| 4636 | xferCardDone(card); |
| 4637 | setTransferActive(false); |
| 4638 | var errReason = (function (c, en) { |
| 4639 | var m = { |
| 4640 | '-2': 'Out of memory', '-10': 'Cannot open file', '-11': 'Read error (USB)', |
| 4641 | '-12': 'Write error', '-13': 'Stat failed', '-14': 'Cannot open dir', |
| 4642 | '-17': 'Source not found', '-18': 'Permission denied', '-99': 'Unknown error' |
| 4643 | }; |
| 4644 | var enoMap = { |
| 4645 | '1': 'EPERM', '2': 'ENOENT', '5': 'EIO', '12': 'ENOMEM', '13': 'EACCES', |
| 4646 | '17': 'EEXIST', '22': 'EINVAL', '28': 'ENOSPC', '30': 'EROFS' |
| 4647 | }; |
| 4648 | /* Show specific human-readable reason for common cases */ |
| 4649 | if (c === -12 && en === 28) return 'Disk full \u2014 not enough space on destination'; |
| 4650 | if (c === -12 && en === 12) return 'Out of memory \u2014 system low on RAM'; |
| 4651 | if (c === -12 && en === 30) return 'Read-only filesystem'; |
| 4652 | var r = m[String(c)] || ('err ' + c); |
| 4653 | if (en) r += ' (errno ' + en + (enoMap[String(en)] ? '=' + enoMap[String(en)] : '') + ')'; |
| 4654 | return r; |
| 4655 | })(d.error_code, d.error_errno); |
| 4656 | toast('Copy failed: ' + name + ' \u2014 ' + errReason, 'er'); |
| 4657 | } else { |
| 4658 | xferCardUpdate(card, 100, speed, elapsed); |
| 4659 | xferCardDone(card); |
| 4660 | invalidateCache(S.path); |
| 4661 | invalidateCache(destDir); |
| 4662 | setTransferActive(false); |
| 4663 | nav(S.path); toast('Copied: ' + name, 'ok'); |
| 4664 | } |
| 4665 | return; |
| 4666 | } |
| 4667 | |
| 4668 | /* In-progress update */ |
| 4669 | var pct = (d.total_bytes > 0) |
| 4670 | ? Math.min(99, Math.floor(d.bytes_copied / d.total_bytes * 100)) |
| 4671 | : 0; |
| 4672 | xferCardUpdate(card, pct, speed, elapsed); |
| 4673 | }) |
| 4674 | .catch(function () { /* ignore transient poll errors */ }); |
| 4675 | }, 500); |
| 4676 | }) |
| 4677 | .catch(function (e) { |
| 4678 | xferCardDone(card); |
| 4679 | setTransferActive(false); |
| 4680 | toast('Copy failed: ' + e.message, 'er'); |
| 4681 | }); |
| 4682 | } |
| 4683 | |
| 4684 | /* ═══════════════════════════════════════════════════════════════ |
| 4685 | * TRANSFER TRAY — cards showing active transfers |
| 4686 | * |
| 4687 | * ┌──────────────────────────────────────┐ |
| 4688 | * │ COPYING… 217.9 MB/s 2s 54% │ |
| 4689 | * │ Arkanoid.exfat │ |
| 4690 | * │ ████████████████░░░░░░░░░░░░░░░░░░░ │ |
| 4691 | * │ [⏸ Pause] [✕ Cancel] │ |
| 4692 | * └──────────────────────────────────────┘ |
| 4693 | * ═══════════════════════════════════════════════════════════════ */ |
| 4694 | |
| 4695 | function xferCardCreate(opLabel, fileName, totalBytes, destPath) { |
| 4696 | var tray = $('xfer-tray'); |
| 4697 | var card = D.createElement('div'); card.className = 'xfer-card'; |
| 4698 | /* Destination info: show where the file/folder is going */ |
| 4699 | var destHtml = destPath |
| 4700 | ? '<div class="xc-dest"><span class="xc-arrow">\u2192</span> ' + destPath + '</div>' |
| 4701 | : ''; |
| 4702 | card.innerHTML = |
| 4703 | '<div class="xc-top">' + |
| 4704 | '<span class="xc-op">' + opLabel + '</span>' + |
| 4705 | '<span class="xc-speed"></span>' + |
| 4706 | '<span class="xc-time"></span>' + |
| 4707 | '<span class="xc-pct">0%</span>' + |
| 4708 | '</div>' + |
| 4709 | '<div class="xc-name">' + fileName + '</div>' + |
| 4710 | destHtml + |
| 4711 | '<div class="xc-bar"><div class="xc-bf" style="width:0%"></div></div>' + |
| 4712 | '<div class="xc-btns">' + |
| 4713 | '<button class="xc-btn pause">' + ICO.pause + ' Pause</button>' + |
| 4714 | '<button class="xc-btn cancel">' + ICO.xcancel + ' Cancel</button>' + |
| 4715 | '</div>'; |
| 4716 | card._totalBytes = totalBytes; |
| 4717 | card._isPaused = false; |
| 4718 | /* Pause button — server-side copy: POST /api/copy_pause (toggle) */ |
| 4719 | var pauseBtn = card.querySelector('.xc-btn.pause'); |
| 4720 | pauseBtn.onclick = function () { |
| 4721 | if (card._isServerCopy) { |
| 4722 | /* Toggle pause via server API */ |
| 4723 | fetch('/api/copy_pause', { method: 'POST', headers: { 'X-CSRF-Token': csrf() } }) |
| 4724 | .then(function (r) { return r.json() }) |
| 4725 | .then(function (d) { |
| 4726 | if (d && d.ok) { |
| 4727 | card._isPaused = !!d.paused; |
| 4728 | if (card._isPaused) { |
| 4729 | pauseBtn.innerHTML = ICO.pause + ' Resume'; |
| 4730 | pauseBtn.classList.add('active'); |
| 4731 | var opEl = card.querySelector('.xc-op'); |
| 4732 | if (opEl) opEl.textContent = 'PAUSED'; |
| 4733 | toast('Transfer paused', 'wn'); |
| 4734 | } else { |
| 4735 | pauseBtn.innerHTML = ICO.pause + ' Pause'; |
| 4736 | pauseBtn.classList.remove('active'); |
| 4737 | var opEl2 = card.querySelector('.xc-op'); |
| 4738 | if (opEl2) opEl2.textContent = 'COPYING\u2026'; |
| 4739 | toast('Transfer resumed', 'ok'); |
| 4740 | } |
| 4741 | } |
| 4742 | }) |
| 4743 | .catch(function () { toast('Pause failed', 'er') }); |
| 4744 | } else if (card._xhr) { |
| 4745 | card._xhr.abort(); |
| 4746 | card._isPaused = true; |
| 4747 | pauseBtn.innerHTML = ICO.pause + ' Paused'; |
| 4748 | pauseBtn.style.opacity = '0.5'; |
| 4749 | toast('Upload aborted (browser cannot pause uploads)', 'wn'); |
| 4750 | } |
| 4751 | }; |
| 4752 | /* Cancel button */ |
| 4753 | card.querySelector('.xc-btn.cancel').onclick = function () { |
| 4754 | if (card._isServerCopy) { |
| 4755 | fetch('/api/copy_cancel', { method: 'POST', headers: { 'X-CSRF-Token': csrf() } }) |
| 4756 | .catch(function () { }); |
| 4757 | } |
| 4758 | if (card._xhr) { card._xhr.abort(); } |
| 4759 | xferCardDone(card); |
| 4760 | toast('Transfer cancelled', 'wn'); |
| 4761 | }; |
| 4762 | tray.appendChild(card); |
| 4763 | return card; |
| 4764 | } |
| 4765 | |
| 4766 | /* Update card progress */ |
| 4767 | function xferCardUpdate(card, pct, speedBps, elapsedSec) { |
| 4768 | if (!card || !card.parentNode) return; |
| 4769 | var bf = card.querySelector('.xc-bf'); |
| 4770 | if (bf) bf.style.width = pct + '%'; |
| 4771 | var pctEl = card.querySelector('.xc-pct'); |
| 4772 | if (pctEl) pctEl.textContent = pct + '%'; |
| 4773 | var speedEl = card.querySelector('.xc-speed'); |
| 4774 | if (speedEl && speedBps > 0) speedEl.textContent = bytes(speedBps) + '/s'; |
| 4775 | var timeEl = card.querySelector('.xc-time'); |
| 4776 | if (timeEl && elapsedSec > 0) { |
| 4777 | var s = Math.floor(elapsedSec); |
| 4778 | if (s >= 3600) { |
| 4779 | timeEl.textContent = Math.floor(s / 3600) + 'h ' + Math.floor((s % 3600) / 60) + 'm'; |
| 4780 | } else if (s >= 60) { |
| 4781 | timeEl.textContent = Math.floor(s / 60) + 'm ' + (s % 60) + 's'; |
| 4782 | } else { |
| 4783 | timeEl.textContent = s + 's'; |
| 4784 | } |
| 4785 | } |
| 4786 | } |
| 4787 | |
| 4788 | /* Remove card after a short delay */ |
| 4789 | function xferCardDone(card) { |
| 4790 | if (!card) return; |
| 4791 | xferCardClearIndeterminate(card); |
| 4792 | var bf = card.querySelector('.xc-bf'); |
| 4793 | if (bf) bf.style.width = '100%'; |
| 4794 | var btns = card.querySelector('.xc-btns'); |
| 4795 | if (btns) btns.style.display = 'none'; |
| 4796 | var op = card.querySelector('.xc-op'); |
| 4797 | if (op) op.textContent = 'DONE'; |
| 4798 | setTimeout(function () { if (card.parentNode) card.parentNode.removeChild(card) }, 2500); |
| 4799 | } |
| 4800 | |
| 4801 | /* Set indeterminate pulsing bar (for server-side ops without progress) */ |
| 4802 | function xferCardSetIndeterminate(card) { |
| 4803 | if (!card) return; |
| 4804 | var bf = card.querySelector('.xc-bf'); |
| 4805 | if (bf) { bf.classList.add('indeterminate'); bf.style.width = '100%'; } |
| 4806 | var pctEl = card.querySelector('.xc-pct'); |
| 4807 | if (pctEl) pctEl.textContent = '\u2026'; |
| 4808 | var speedEl = card.querySelector('.xc-speed'); |
| 4809 | if (speedEl) speedEl.textContent = 'server-side'; |
| 4810 | } |
| 4811 | function xferCardClearIndeterminate(card) { |
| 4812 | if (!card) return; |
| 4813 | var bf = card.querySelector('.xc-bf'); |
| 4814 | if (bf) { bf.classList.remove('indeterminate'); bf.style.width = '0%'; } |
| 4815 | } |
| 4816 | |
| 4817 | /* ── STATS ── */ |
| 4818 | function refreshStats() { |
| 4819 | fetch('/api/stats?path=' + E(S.path)).then(function (r) { if (!r.ok) throw new Error(); return r.json() }).then(updateStats) |
| 4820 | .catch(function () { updateStats({ items_in_dir: (S.entries || []).length, path: S.path }) }); |
| 4821 | } |
| 4822 | function updateStats(d) { |
| 4823 | if (!d || typeof d !== 'object') return; |
| 4824 | var hasDisk = (typeof d.disk_used === 'number') && (typeof d.disk_total === 'number') && d.disk_total > 0; |
| 4825 | var used = hasDisk ? d.disk_used : 0; |
| 4826 | var total = hasDisk ? d.disk_total : 1; |
| 4827 | var free = Math.max(0, total - used), pct = hasDisk ? Math.min(100, Math.floor(used / total * 100)) : 0; |
| 4828 | var CIRC = 69.12, df = $('d-fill'), dp = $('d-pct'); |
| 4829 | if (df) { df.style.strokeDashoffset = hasDisk ? String(CIRC - pct / 100 * CIRC) : String(CIRC); df.style.stroke = pct > 80 ? 'var(--wn)' : 'var(--ac)' } |
| 4830 | if (dp) dp.textContent = hasDisk ? pct + '%' : '—'; |
| 4831 | function set(id, v) { var el = $(id); if (el) el.textContent = v } |
| 4832 | var sd = $('s-disk'); if (sd) { sd.textContent = hasDisk ? bytes(used) + ' / ' + bytes(total) : '—'; sd.title = hasDisk ? (sd.textContent + (typeof d.disk_path === 'string' && d.disk_path ? (' (' + d.disk_path + ')') : '')) : '' } |
| 4833 | set('sp-du', hasDisk ? bytes(used) + ' / ' + bytes(total) : '—'); |
| 4834 | set('sp-df', hasDisk ? bytes(free) : '—'); |
| 4835 | set('sp-dt', hasDisk ? bytes(total) : '—'); |
| 4836 | var sdb = $('sp-db'); if (sdb) { sdb.style.width = pct + '%'; sdb.className = 'sp-bf' + (pct > 80 ? ' full' : '') } |
| 4837 | if (typeof d.items_in_dir === 'number') { set('s-files', String(d.items_in_dir)); set('sp-fi', String(d.items_in_dir)) } |
| 4838 | if (typeof d.path === 'string') { set('sp-pt', d.path) } |
| 4839 | var temp = typeof d.cpu_temp === 'number' ? d.cpu_temp : null; |
| 4840 | if (temp !== null) { |
| 4841 | var hot = temp > 65; |
| 4842 | var st = $('s-temp'); if (st) { st.textContent = temp + '\u00b0C'; st.className = 'sv ' + (hot ? 'wn' : 'ok') } |
| 4843 | set('sp-tv', temp + '\u00b0C'); |
| 4844 | var stb = $('sp-tb'); if (stb) { stb.style.width = Math.min(100, temp) + '%'; stb.className = 'sp-bf' + (hot ? ' hot' : '') } |
| 4845 | } |
| 4846 | if (typeof d.uptime === 'number') { |
| 4847 | var diff = Math.max(0, Math.floor(Date.now() / 1000) - d.uptime); |
| 4848 | set('sp-up', Math.floor(diff / 86400) + 'd ' + Math.floor((diff % 86400) / 3600) + 'h ' + Math.floor((diff % 3600) / 60) + 'm'); |
| 4849 | } |
| 4850 | } |
| 4851 | |
| 4852 | /* ── VIEW ── */ |
| 4853 | function setView(v) { |
| 4854 | if (!{ grid: 1, list: 1, details: 1 }[v]) return; S.view = v; |
| 4855 | ['grid', 'list', 'details'].forEach(function (x) { var b = $('vb-' + x); if (b) b.classList.toggle('active', x === v) }); |
| 4856 | render($('search').value); |
| 4857 | try { localStorage.setItem('zftpd_view', v) } catch (e) { } |
| 4858 | } |
| 4859 | |
| 4860 | /* ── THEME ── */ |
| 4861 | function buildThemeDd() { |
| 4862 | var dd = $('theme-dd'); if (!dd) return; |
| 4863 | dd.innerHTML = '<div class="td-hd">Select Theme</div>'; |
| 4864 | var cur = D.documentElement.getAttribute('data-theme') || 'ps5'; |
| 4865 | THEMES.forEach(function (t) { |
| 4866 | var el = D.createElement('div'); el.className = 'td-item' + (t.id === cur ? ' active' : ''); |
| 4867 | el.innerHTML = '<div class="td-sw" style="background:' + t.sw + '"></div>' + |
| 4868 | '<div class="td-info"><div class="td-nm">' + t.name + '</div><div class="td-ds">' + t.desc + '</div></div>' + |
| 4869 | '<span class="td-ck">' + ICO.check + '</span>'; |
| 4870 | el.onclick = function () { setTheme(t.id); closeThemeDd() }; |
| 4871 | dd.appendChild(el); |
| 4872 | }); |
| 4873 | } |
| 4874 | function setTheme(id) { |
| 4875 | var ids = THEMES.map(function (t) { return t.id }); |
| 4876 | var theme = ids.indexOf(id) >= 0 ? id : 'ps5'; |
| 4877 | D.documentElement.setAttribute('data-theme', theme); |
| 4878 | var t = THEMES.filter(function (x) { return x.id === theme })[0] || THEMES[0]; |
| 4879 | var sw = $('t-sw'); if (sw) sw.style.background = t.sw; |
| 4880 | var tn = $('t-nm'); if (tn) tn.textContent = t.name; |
| 4881 | var ts = $('theme-select'); if (ts) ts.value = theme; |
| 4882 | buildThemeDd(); |
| 4883 | try { localStorage.setItem('zftpd_theme', theme) } catch (e) { } |
| 4884 | } |
| 4885 | function buildThemeSelect() { |
| 4886 | var sel = $('theme-select'); if (!sel) return; |
| 4887 | sel.innerHTML = ''; |
| 4888 | THEMES.forEach(function (t) { |
| 4889 | var opt = D.createElement('option'); |
| 4890 | opt.value = t.id; |
| 4891 | opt.textContent = t.name; |
| 4892 | sel.appendChild(opt); |
| 4893 | }); |
| 4894 | var cur = D.documentElement.getAttribute('data-theme') || 'ps5'; |
| 4895 | sel.value = cur; |
| 4896 | sel.onchange = function () { setTheme(this.value); }; |
| 4897 | } |
| 4898 | function closeThemeDd() { var dd = $('theme-dd'), btn = $('theme-btn'); if (dd) dd.classList.remove('show'); if (btn) btn.classList.remove('open') } |
| 4899 | function toggleThemeDd() { var dd = $('theme-dd'), btn = $('theme-btn'); buildThemeDd(); dd.classList.toggle('show'); btn.classList.toggle('open', dd.classList.contains('show')) } |
| 4900 | |
| 4901 | /* ── INIT ── */ |
| 4902 | D.addEventListener('DOMContentLoaded', function () { |
| 4903 | try { var sv = localStorage.getItem('zftpd_view'); if (sv) S.view = sv; var st = localStorage.getItem('zftpd_theme'); if (st) setTheme(st) } catch (e) { } |
| 4904 | cleanupCache(); |
| 4905 | setView(S.view); buildThemeDd(); buildThemeSelect(); |
| 4906 | |
| 4907 | var bl = D.querySelector('.brand-logo'); if (bl) bl.src = 'zftpd-logo.png'; |
| 4908 | |
| 4909 | var bu = $('btn-up'); if (bu) bu.onclick = function () { var p = parent(S.path); if (p !== null) nav(p) }; |
| 4910 | var br = $('btn-ref'); if (br) br.onclick = function () { nav(S.path) }; |
| 4911 | var sr = $('search'); if (sr) sr.oninput = function () { render(this.value) }; |
| 4912 | var fi = $('file-input'); if (fi) fi.onchange = function (e) { upload(e.target.files); e.target.value = '' }; |
| 4913 | var fo = $('folder-input'); if (fo) fo.onchange = function (e) { upload(e.target.files); e.target.value = '' }; |
| 4914 | var dc = $('drop-close'); if (dc) dc.onclick = function () { hideDrop() }; |
| 4915 | |
| 4916 | /* Preload root directory to avoid slowdowns on first navigation */ |
| 4917 | fetch('/api/list?path=/') |
| 4918 | .then(function (r) { return r.ok ? r.json() : null }) |
| 4919 | .catch(function () { /* ignore preload errors */ }); |
| 4920 | |
| 4921 | ['grid', 'list', 'details'].forEach(function (v) { var b = $('vb-' + v); if (b) b.onclick = function () { setView(v) } }); |
| 4922 | |
| 4923 | var tb = $('theme-btn'); if (tb) tb.onclick = function (e) { e.stopPropagation(); toggleThemeDd() }; |
| 4924 | var sw = $('stats-w'), sp = $('stats-panel'); |
| 4925 | if (sw) { |
| 4926 | sw.onclick = function (e) { |
| 4927 | e.stopPropagation(); |
| 4928 | if (typeof window.smoOpen === 'function') window.smoOpen(); |
| 4929 | }; |
| 4930 | var scs = sw.querySelectorAll('.sc'); |
| 4931 | for (var i = 0; i < scs.length; i++) { |
| 4932 | scs[i].onclick = function (e) { |
| 4933 | e.stopPropagation(); |
| 4934 | if (typeof window.smoOpen === 'function') window.smoOpen(); |
| 4935 | }; |
| 4936 | } |
| 4937 | } |
| 4938 | |
| 4939 | D.addEventListener('dragenter', function (e) { e.preventDefault(); _dd++; showDrop('Drop files to upload', null) }); |
| 4940 | D.addEventListener('dragover', function (e) { e.preventDefault() }); |
| 4941 | D.addEventListener('dragleave', function (e) { e.preventDefault(); _dd = Math.max(0, _dd - 1); if (!_dd) hideDrop() }); |
| 4942 | D.addEventListener('drop', function (e) { e.preventDefault(); _dd = 0; upload(e.dataTransfer.files) }); |
| 4943 | |
| 4944 | /* Send-To modal buttons */ |
| 4945 | var smSendBtn = $('sm-send'); if (smSendBtn) smSendBtn.onclick = sendTo; |
| 4946 | var smCancelBtn = $('sm-cancel'); if (smCancelBtn) smCancelBtn.onclick = hideSendToModal; |
| 4947 | var smCloseBtn = $('sm-close'); if (smCloseBtn) smCloseBtn.onclick = hideSendToModal; |
| 4948 | /* Click on modal backdrop closes it */ |
| 4949 | var smOverlay = $('send-modal'); |
| 4950 | if (smOverlay) smOverlay.addEventListener('click', function (e) { if (e.target === smOverlay) hideSendToModal() }); |
| 4951 | |
| 4952 | D.addEventListener('contextmenu', function (e) { |
| 4953 | var t = e.target, inCard = false; |
| 4954 | while (t && t !== D.body) { if (t.classList && (t.classList.contains('card') || t.tagName === 'TR')) { inCard = true; break } t = t.parentNode } |
| 4955 | if (!inCard) { e.preventDefault(); showCtx(e, null, null, false) } |
| 4956 | }); |
| 4957 | D.addEventListener('click', function () { hideCtx(); closeThemeDd(); var sp2 = $('stats-panel'); if (sp2) sp2.classList.remove('show') }); |
| 4958 | D.addEventListener('keydown', function (e) { if (e.key === 'Escape') { hideCtx(); closeThemeDd(); hideSendToModal(); var sp3 = $('stats-panel'); if (sp3) sp3.classList.remove('show') } }); |
| 4959 | |
| 4960 | S.statsTimer = setInterval(refreshStats, 15000); |
| 4961 | S.path = '/'; |
| 4962 | nav('/'); |
| 4963 | |
| 4964 | }); |
| 4965 | |
| 4966 | /* ══════════════════════════════════════════════════════════════ |
| 4967 | * STATS MONITOR MODAL (namespace: smo) |
| 4968 | * ══════════════════════════════════════════════════════════════ */ |
| 4969 | ; (function () { |
| 4970 | 'use strict'; |
| 4971 | |
| 4972 | /* ── State ── */ |
| 4973 | var _open = false; |
| 4974 | var _tab = 'ram'; |
| 4975 | var _polls = []; /* active setInterval IDs */ |
| 4976 | var _focusTrap = null; |
| 4977 | |
| 4978 | /* RAM history ring-buffer (60 points) */ |
| 4979 | var _ramHist = []; |
| 4980 | var _tempHist = []; |
| 4981 | var _RAM_MAX = 60; |
| 4982 | |
| 4983 | /* Disk treemap */ |
| 4984 | var _tmPath = '/'; |
| 4985 | var _tmStack = []; |
| 4986 | var _tmData = null; |
| 4987 | |
| 4988 | /* Processes */ |
| 4989 | var _procs = []; |
| 4990 | var _procPage = 20; |
| 4991 | var _procOffset = 0; |
| 4992 | var _procSort = 'cpu'; |
| 4993 | var _procSortAsc = false; |
| 4994 | var _procQuery = ''; |
| 4995 | |
| 4996 | /* Kill confirm */ |
| 4997 | var _killTarget = null; |
| 4998 | |
| 4999 | /* Network peak tracking */ |
| 5000 | var _netPeak = 1024 * 1024; /* 1 MB/s initial scale */ |
| 5001 | |
| 5002 | /* ── Helpers ── */ |
| 5003 | function smo$(id) { return document.getElementById(id); } |
| 5004 | function smoBytes(b) { |
| 5005 | if (typeof b !== 'number' || b < 0) return '—'; |
| 5006 | if (b === 0) return '0 B'; |
| 5007 | var u = ['B', 'KB', 'MB', 'GB', 'TB'], i = Math.min(Math.floor(Math.log(b) / Math.log(1024)), 4); |
| 5008 | return (b / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0) + ' ' + u[i]; |
| 5009 | } |
| 5010 | function smoBps(b) { |
| 5011 | return smoBytes(b) + '/s'; |
| 5012 | } |
| 5013 | function smoUptime(s) { |
| 5014 | s = Math.max(0, Math.floor(s)); |
| 5015 | var d = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600), m = Math.floor((s % 3600) / 60); |
| 5016 | var parts = []; |
| 5017 | if (d) parts.push(d + ' day' + (d !== 1 ? 's' : '')); |
| 5018 | if (h) parts.push(h + 'h'); |
| 5019 | parts.push(m + 'm'); |
| 5020 | return parts.join(', '); |
| 5021 | } |
| 5022 | function smoFmt(ts) { |
| 5023 | if (!ts) return '—'; |
| 5024 | var d = new Date(ts * 1000); |
| 5025 | if (isNaN(d)) return '—'; |
| 5026 | return d.toLocaleString(); |
| 5027 | } |
| 5028 | function smoNow() { |
| 5029 | return new Date().toLocaleTimeString(); |
| 5030 | } |
| 5031 | |
| 5032 | /* ── Toast ── */ |
| 5033 | function smoToast(msg, type) { |
| 5034 | var wrap = smo$('smo-toast-wrap'); if (!wrap) return; |
| 5035 | var el = document.createElement('div'); |
| 5036 | el.className = 'smo-toast ' + (type || ''); |
| 5037 | el.textContent = (type === 'ok' ? '✓ ' : type === 'er' ? '✕ ' : '') + msg; |
| 5038 | wrap.appendChild(el); |
| 5039 | setTimeout(function () { |
| 5040 | el.style.animation = 'smToastOut .2s ease forwards'; |
| 5041 | setTimeout(function () { if (el.parentNode) el.parentNode.removeChild(el); }, 220); |
| 5042 | }, 3000); |
| 5043 | } |
| 5044 | |
| 5045 | /* ── Timestamp footer ── */ |
| 5046 | function smoUpdTs() { |
| 5047 | var el = smo$('smo-ts'); if (el) el.textContent = smoNow(); |
| 5048 | } |
| 5049 | |
| 5050 | /* ── Open / Close ── */ |
| 5051 | function smoOpen() { |
| 5052 | if (_open) return; |
| 5053 | _open = true; |
| 5054 | var ov = smo$('smo-overlay'); if (!ov) return; |
| 5055 | ov.classList.add('smo-open'); |
| 5056 | smoSwitchTab(_tab); |
| 5057 | smoStartPolls(); |
| 5058 | document.addEventListener('keydown', smoKeydown); |
| 5059 | /* focus trap: find first focusable */ |
| 5060 | var focusable = ov.querySelectorAll('button,input,select,a[href]'); |
| 5061 | if (focusable.length) focusable[0].focus(); |
| 5062 | } |
| 5063 | |
| 5064 | window.smoOpen = function () { smoOpen(); }; |
| 5065 | |
| 5066 | function smoClose() { |
| 5067 | if (!_open) return; |
| 5068 | _open = false; |
| 5069 | var ov = smo$('smo-overlay'), m = smo$('smo-modal'); |
| 5070 | if (m) m.classList.add('smo-closing'); |
| 5071 | smoStopPolls(); |
| 5072 | document.removeEventListener('keydown', smoKeydown); |
| 5073 | setTimeout(function () { |
| 5074 | if (ov) ov.classList.remove('smo-open'); |
| 5075 | if (m) m.classList.remove('smo-closing'); |
| 5076 | }, 220); |
| 5077 | } |
| 5078 | |
| 5079 | function smoKeydown(e) { |
| 5080 | if (e.key === 'Escape') { smoClose(); return; } |
| 5081 | /* focus trap */ |
| 5082 | if (e.key === 'Tab') { |
| 5083 | var ov = smo$('smo-overlay'); if (!ov) return; |
| 5084 | var focusable = Array.prototype.slice.call( |
| 5085 | ov.querySelectorAll('button:not([disabled]),input,select,a[href],[tabindex]:not([tabindex="-1"])') |
| 5086 | ); |
| 5087 | if (!focusable.length) return; |
| 5088 | var idx = focusable.indexOf(document.activeElement); |
| 5089 | if (e.shiftKey) { |
| 5090 | if (idx <= 0) { e.preventDefault(); focusable[focusable.length - 1].focus(); } |
| 5091 | } else { |
| 5092 | if (idx === focusable.length - 1) { e.preventDefault(); focusable[0].focus(); } |
| 5093 | } |
| 5094 | } |
| 5095 | } |
| 5096 | |
| 5097 | /* ── Tabs ── */ |
| 5098 | function smoSwitchTab(tab) { |
| 5099 | _tab = tab; |
| 5100 | var tabs = document.querySelectorAll('.smo-tab'); |
| 5101 | for (var i = 0; i < tabs.length; i++) { |
| 5102 | var t = tabs[i]; |
| 5103 | t.classList.toggle('smo-tab-active', t.getAttribute('data-tab') === tab); |
| 5104 | } |
| 5105 | var secs = document.querySelectorAll('.smo-section'); |
| 5106 | for (var j = 0; j < secs.length; j++) { |
| 5107 | secs[j].classList.toggle('smo-active', secs[j].id === 'smo-tab-' + tab); |
| 5108 | } |
| 5109 | /* Trigger immediate data fetch for tab-specific data */ |
| 5110 | if (tab === 'disk' && !_tmData) smoLoadDiskTree(_tmPath); |
| 5111 | if (tab === 'proc' && _open) smoFetchProcs(); |
| 5112 | } |
| 5113 | |
| 5114 | /* ── Polling management ── */ |
| 5115 | function smoStartPolls() { |
| 5116 | smoFetchAll(); |
| 5117 | _polls.push(setInterval(smoFetchAll, 3000)); |
| 5118 | } |
| 5119 | function smoStopPolls() { |
| 5120 | for (var i = 0; i < _polls.length; i++) clearInterval(_polls[i]); |
| 5121 | _polls = []; |
| 5122 | } |
| 5123 | function smoFetchAll() { |
| 5124 | smoFetchRAM(); |
| 5125 | smoFetchSystem(); |
| 5126 | smoFetchDiskInfo(); |
| 5127 | if (_tab === 'proc') smoFetchProcs(); |
| 5128 | smoUpdTs(); |
| 5129 | } |
| 5130 | |
| 5131 | /* ══ TAB 1: RAM ══════════════════════════════════════════════ */ |
| 5132 | function smoFetchRAM() { |
| 5133 | fetch('/api/stats/ram') |
| 5134 | .then(function (r) { return r.ok ? r.json() : Promise.reject(r.status); }) |
| 5135 | .then(smoUpdateRAM) |
| 5136 | .catch(function () { /* placeholder values already shown */ }); |
| 5137 | } |
| 5138 | |
| 5139 | function smoUpdateRAM(d) { |
| 5140 | if (!d) return; |
| 5141 | var used = d.used || 0; |
| 5142 | var cached = (d.cached || 0) + (d.buffers || 0); |
| 5143 | var free = d.free || 0; |
| 5144 | var total = d.total || (used + cached + free) || 1; |
| 5145 | var pct = Math.min(100, Math.round(used / total * 100)); |
| 5146 | var cachedPct = Math.min(100 - pct, Math.round(cached / total * 100)); |
| 5147 | var CIRC = 314.16; |
| 5148 | |
| 5149 | /* Gauge */ |
| 5150 | var arc = smo$('smo-ram-arc'); |
| 5151 | if (arc) { |
| 5152 | arc.style.strokeDashoffset = String(CIRC - pct / 100 * CIRC); |
| 5153 | arc.style.stroke = pct > 80 ? 'var(--er)' : pct > 60 ? 'var(--wn)' : 'var(--ac)'; |
| 5154 | } |
| 5155 | var pctEl = smo$('smo-ram-pct'); if (pctEl) pctEl.textContent = pct + '%'; |
| 5156 | |
| 5157 | /* Segmented bar */ |
| 5158 | var su = smo$('smo-ram-seg-used'); if (su) su.style.width = pct + '%'; |
| 5159 | var sc = smo$('smo-ram-seg-cache'); if (sc) sc.style.width = cachedPct + '%'; |
| 5160 | |
| 5161 | /* Metrics */ |
| 5162 | var ru = smo$('smo-ram-used'); if (ru) ru.textContent = smoBytes(used); |
| 5163 | var rc = smo$('smo-ram-cache'); if (rc) rc.textContent = smoBytes(cached); |
| 5164 | var rf = smo$('smo-ram-free'); if (rf) rf.textContent = smoBytes(free); |
| 5165 | var rt = smo$('smo-ram-total'); if (rt) rt.textContent = smoBytes(total); |
| 5166 | var rsub = smo$('smo-ram-used-sub'); if (rsub) rsub.textContent = pct + '% of total'; |
| 5167 | |
| 5168 | /* History */ |
| 5169 | _ramHist.push(pct); |
| 5170 | if (_ramHist.length > _RAM_MAX) _ramHist.shift(); |
| 5171 | smoDrawSparkline('smo-ram-sparkline', _ramHist, 'var(--ac)', 0, 100); |
| 5172 | } |
| 5173 | |
| 5174 | /* ══ TAB 2: DISK ════════════════════════════════════════════ */ |
| 5175 | function smoFetchDiskInfo() { |
| 5176 | fetch('/api/disk/info') |
| 5177 | .then(function (r) { return r.ok ? r.json() : Promise.reject(r.status); }) |
| 5178 | .then(smoUpdateDiskInfo) |
| 5179 | .catch(function () { }); |
| 5180 | } |
| 5181 | |
| 5182 | function smoUpdateDiskInfo(d) { |
| 5183 | if (!d) return; |
| 5184 | var used = d.used || 0; |
| 5185 | var free = d.free || 0; |
| 5186 | var total = d.total || (used + free) || 1; |
| 5187 | var pct = Math.min(100, Math.round(used / total * 100)); |
| 5188 | var cls = pct > 85 ? 'cr' : pct > 70 ? 'wn' : ''; |
| 5189 | |
| 5190 | var du = smo$('smo-disk-used'); if (du) du.textContent = smoBytes(used); |
| 5191 | var df = smo$('smo-disk-free'); if (df) df.textContent = smoBytes(free); |
| 5192 | var dt = smo$('smo-disk-total'); if (dt) dt.textContent = smoBytes(total); |
| 5193 | var dp = smo$('smo-disk-path'); if (dp && d.path) dp.textContent = d.path; |
| 5194 | var bf = smo$('smo-disk-bar-fill'); |
| 5195 | if (bf) { bf.style.width = pct + '%'; bf.className = 'smo-disk-bar-fill' + (cls ? ' ' + cls : ''); } |
| 5196 | } |
| 5197 | |
| 5198 | function smoLoadDiskTree(path) { |
| 5199 | _tmPath = path; |
| 5200 | smoRenderTmBreadcrumb(); |
| 5201 | var tm = smo$('smo-treemap'); if (!tm) return; |
| 5202 | tm.innerHTML = '<div style="padding:40px;text-align:center;color:var(--tx3);font-size:11px">Loading tree…</div>'; |
| 5203 | fetch('/api/disk/tree?path=' + encodeURIComponent(path)) |
| 5204 | .then(function (r) { return r.ok ? r.json() : Promise.reject(r.status); }) |
| 5205 | .then(function (data) { |
| 5206 | _tmData = data; |
| 5207 | smoRenderTreemap(data, path); |
| 5208 | smoRenderTop10(data); |
| 5209 | }) |
| 5210 | .catch(function () { |
| 5211 | var tm2 = smo$('smo-treemap'); if (!tm2) return; |
| 5212 | tm2.innerHTML = '<div style="padding:40px;text-align:center;color:var(--tx3);font-size:11px">— Tree unavailable —</div>'; |
| 5213 | }); |
| 5214 | } |
| 5215 | |
| 5216 | function smoRenderTmBreadcrumb() { |
| 5217 | var bc = smo$('smo-tm-breadcrumb'); if (!bc) return; |
| 5218 | bc.innerHTML = ''; |
| 5219 | var crumb = document.createElement('span'); |
| 5220 | crumb.className = 'smo-crumb' + (_tmStack.length === 0 ? ' smo-crumb-act' : ''); |
| 5221 | crumb.textContent = '/'; |
| 5222 | crumb.onclick = function () { _tmStack = []; smoLoadDiskTree('/'); }; |
| 5223 | bc.appendChild(crumb); |
| 5224 | for (var i = 0; i < _tmStack.length; i++) { |
| 5225 | var sep = document.createElement('span'); sep.className = 'smo-crumb-sep'; sep.textContent = '/'; bc.appendChild(sep); |
| 5226 | var seg = document.createElement('span'); |
| 5227 | seg.className = 'smo-crumb' + (i === _tmStack.length - 1 ? ' smo-crumb-act' : ''); |
| 5228 | seg.textContent = _tmStack[i].name; |
| 5229 | (function (idx) { |
| 5230 | seg.onclick = function () { |
| 5231 | _tmStack = _tmStack.slice(0, idx + 1); |
| 5232 | smoLoadDiskTree(_tmStack.map(function (x) { return x.path }).join('')); |
| 5233 | }; |
| 5234 | }(i)); |
| 5235 | bc.appendChild(seg); |
| 5236 | } |
| 5237 | } |
| 5238 | |
| 5239 | var TM_COLORS = { |
| 5240 | dir: '#4da6ff', |
| 5241 | video: '#ff8a65', |
| 5242 | image: '#ce93d8', |
| 5243 | arch: '#ffb74d', |
| 5244 | code: '#80cbc4', |
| 5245 | doc: '#90caf9', |
| 5246 | other: '#546e7a' |
| 5247 | }; |
| 5248 | function smoFileColor(name) { |
| 5249 | if (!name) return TM_COLORS.other; |
| 5250 | var e = name.split('.').pop().toLowerCase(); |
| 5251 | if ({ mp4: 1, mkv: 1, avi: 1, mov: 1, webm: 1, flv: 1 }[e]) return TM_COLORS.video; |
| 5252 | if ({ png: 1, jpg: 1, jpeg: 1, gif: 1, svg: 1, webp: 1, bmp: 1 }[e]) return TM_COLORS.image; |
| 5253 | if ({ zip: 1, tar: 1, gz: 1, bz2: 1, xz: 1, rar: 1, '7z': 1 }[e]) return TM_COLORS.arch; |
| 5254 | if ({ js: 1, ts: 1, py: 1, c: 1, cpp: 1, go: 1, rs: 1, sh: 1, php: 1 }[e]) return TM_COLORS.code; |
| 5255 | if ({ md: 1, txt: 1, pdf: 1, doc: 1, docx: 1 }[e]) return TM_COLORS.doc; |
| 5256 | return TM_COLORS.other; |
| 5257 | } |
| 5258 | |
| 5259 | function smoRenderTreemap(data, rootPath) { |
| 5260 | var wrap = smo$('smo-treemap'); if (!wrap) return; |
| 5261 | wrap.innerHTML = ''; |
| 5262 | var W = wrap.clientWidth || 400, H = 220; |
| 5263 | if (!data || !data.children || !data.children.length) { |
| 5264 | wrap.innerHTML = '<div style="padding:40px;text-align:center;color:var(--tx3);font-size:11px">Empty directory</div>'; |
| 5265 | return; |
| 5266 | } |
| 5267 | |
| 5268 | /* Manual squarified treemap (no D3 required) */ |
| 5269 | var total = data.size || data.children.reduce(function (a, c) { return a + (c.size || 0); }, 0) || 1; |
| 5270 | var nodes = data.children.slice().sort(function (a, b) { return (b.size || 0) - (a.size || 0); }); |
| 5271 | var rects = smoSquarify(nodes, total, 0, 0, W, H); |
| 5272 | |
| 5273 | var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); |
| 5274 | svg.setAttribute('width', W); svg.setAttribute('height', H); |
| 5275 | svg.style.display = 'block'; |
| 5276 | |
| 5277 | var tip = smo$('smo-tm-tip'); |
| 5278 | |
| 5279 | rects.forEach(function (r) { |
| 5280 | var isDir = r.node.type === 'directory' || (r.node.children && r.node.children.length); |
| 5281 | var col = isDir ? TM_COLORS.dir : smoFileColor(r.node.name); |
| 5282 | var g = document.createElementNS('http://www.w3.org/2000/svg', 'g'); |
| 5283 | g.className.baseVal = 'smo-tm-node'; |
| 5284 | var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); |
| 5285 | rect.setAttribute('x', r.x + 1); rect.setAttribute('y', r.y + 1); |
| 5286 | rect.setAttribute('width', Math.max(0, r.w - 2)); rect.setAttribute('height', Math.max(0, r.h - 2)); |
| 5287 | rect.setAttribute('rx', 4); |
| 5288 | rect.setAttribute('fill', col); |
| 5289 | rect.setAttribute('fill-opacity', '0.85'); |
| 5290 | g.appendChild(rect); |
| 5291 | if (r.w > 40 && r.h > 22) { |
| 5292 | var txt = document.createElementNS('http://www.w3.org/2000/svg', 'text'); |
| 5293 | txt.setAttribute('x', r.x + r.w / 2); txt.setAttribute('y', r.y + r.h / 2 + 4); |
| 5294 | txt.setAttribute('text-anchor', 'middle'); txt.setAttribute('font-size', Math.min(11, r.w / 10 + 5)); |
| 5295 | txt.setAttribute('fill', 'rgba(255,255,255,.9)'); txt.setAttribute('pointer-events', 'none'); |
| 5296 | var label = r.node.name.length > 18 ? r.node.name.slice(0, 16) + '…' : r.node.name; |
| 5297 | txt.textContent = label; |
| 5298 | g.appendChild(txt); |
| 5299 | } |
| 5300 | /* Hover tooltip */ |
| 5301 | g.addEventListener('mouseenter', function (e) { |
| 5302 | if (!tip) return; |
| 5303 | var pct = Math.round((r.node.size || 0) / total * 100); |
| 5304 | smo$('smo-tm-tip-name').textContent = (isDir ? '[DIR] ' : '[FILE] ') + r.node.name; |
| 5305 | smo$('smo-tm-tip-size').textContent = smoBytes(r.node.size || 0); |
| 5306 | smo$('smo-tm-tip-pct').textContent = pct + '% of total'; |
| 5307 | var hint = smo$('smo-tm-tip-hint'); if (hint) hint.style.display = isDir ? '' : 'none'; |
| 5308 | tip.classList.add('visible'); |
| 5309 | }); |
| 5310 | g.addEventListener('mousemove', function (e) { |
| 5311 | if (!tip) return; |
| 5312 | tip.style.left = (e.clientX + 14) + 'px'; tip.style.top = (e.clientY - 10) + 'px'; |
| 5313 | }); |
| 5314 | g.addEventListener('mouseleave', function () { if (tip) tip.classList.remove('visible'); }); |
| 5315 | /* Click → drill down */ |
| 5316 | g.addEventListener('click', function () { |
| 5317 | if (!isDir) return; |
| 5318 | var newPath = rootPath === '/' ? '/' + r.node.name : rootPath + '/' + r.node.name; |
| 5319 | _tmStack.push({ name: r.node.name, path: newPath }); |
| 5320 | smoLoadDiskTree(newPath); |
| 5321 | }); |
| 5322 | svg.appendChild(g); |
| 5323 | }); |
| 5324 | wrap.appendChild(svg); |
| 5325 | } |
| 5326 | |
| 5327 | /* Simple slice-and-dice layout (no D3 dependency) */ |
| 5328 | function smoSquarify(nodes, total, x, y, w, h) { |
| 5329 | var results = []; |
| 5330 | var remaining = total; |
| 5331 | var cx = x, cy = y, cw = w, ch = h; |
| 5332 | nodes.forEach(function (n, i) { |
| 5333 | var sz = n.size || 0; |
| 5334 | var frac = sz / (remaining || 1); |
| 5335 | var horizontal = cw >= ch; |
| 5336 | var rw, rh; |
| 5337 | if (horizontal) { rw = Math.round(frac * cw); rh = ch; } |
| 5338 | else { rh = Math.round(frac * ch); rw = cw; } |
| 5339 | results.push({ node: n, x: cx, y: cy, w: rw, h: rh }); |
| 5340 | if (horizontal) { cx += rw; cw -= rw; } |
| 5341 | else { cy += rh; ch -= rh; } |
| 5342 | remaining -= sz; |
| 5343 | }); |
| 5344 | return results; |
| 5345 | } |
| 5346 | |
| 5347 | function smoRenderTop10(data) { |
| 5348 | var tbl = smo$('smo-top-list'); if (!tbl) return; |
| 5349 | var tbody = tbl.querySelector('tbody'); if (!tbody) return; |
| 5350 | tbody.innerHTML = ''; |
| 5351 | if (!data || !data.children) return; |
| 5352 | var items = data.children.slice().sort(function (a, b) { return (b.size || 0) - (a.size || 0); }).slice(0, 10); |
| 5353 | var maxSz = items.length ? (items[0].size || 1) : 1; |
| 5354 | items.forEach(function (item, i) { |
| 5355 | var pct = Math.round((item.size || 0) / maxSz * 100); |
| 5356 | var tr = document.createElement('tr'); |
| 5357 | tr.innerHTML = |
| 5358 | '<td class="smo-top-num">' + (i + 1) + '</td>' + |
| 5359 | '<td class="smo-top-name" title="' + item.name + '">' + item.name + '</td>' + |
| 5360 | '<td class="smo-top-size">' + smoBytes(item.size || 0) + '</td>' + |
| 5361 | '<td class="smo-top-bar"><div class="smo-top-bar-inner" style="width:' + pct + '%"></div></td>'; |
| 5362 | tbody.appendChild(tr); |
| 5363 | }); |
| 5364 | } |
| 5365 | |
| 5366 | /* ══ TAB 3: PROCESSES ═══════════════════════════════════════ */ |
| 5367 | function smoFetchProcs() { |
| 5368 | fetch('/api/processes') |
| 5369 | .then(function (r) { return r.ok ? r.json() : Promise.reject(r.status); }) |
| 5370 | .then(smoUpdateProcs) |
| 5371 | .catch(function () { }); |
| 5372 | } |
| 5373 | |
| 5374 | function smoUpdateProcs(arr) { |
| 5375 | if (!Array.isArray(arr)) return; |
| 5376 | _procs = arr; |
| 5377 | _procOffset = 0; |
| 5378 | smoRenderProcs(); |
| 5379 | } |
| 5380 | |
| 5381 | function smoRenderProcs() { |
| 5382 | var q = _procQuery.toLowerCase(); |
| 5383 | var filtered = _procs.filter(function (p) { |
| 5384 | return !q || (p.name || '').toLowerCase().indexOf(q) >= 0; |
| 5385 | }); |
| 5386 | |
| 5387 | /* Sort */ |
| 5388 | filtered.sort(function (a, b) { |
| 5389 | var av = a[_procSort], bv = b[_procSort]; |
| 5390 | if (typeof av === 'number' && typeof bv === 'number') { |
| 5391 | return _procSortAsc ? av - bv : bv - av; |
| 5392 | } |
| 5393 | av = String(av || ''); bv = String(bv || ''); |
| 5394 | return _procSortAsc ? av.localeCompare(bv) : bv.localeCompare(av); |
| 5395 | }); |
| 5396 | |
| 5397 | var total = smo$('smo-proc-count'); if (total) total.textContent = String(_procs.length); |
| 5398 | |
| 5399 | var tbody = smo$('smo-proc-tbody'); if (!tbody) return; |
| 5400 | tbody.innerHTML = ''; |
| 5401 | var slice = filtered.slice(0, _procOffset + 20); |
| 5402 | slice.forEach(function (p) { |
| 5403 | var hot = (p.cpu || 0) > 80 || (p.mem_mb || 0) > 500; |
| 5404 | var status = p.status || 'running'; |
| 5405 | var statusCls = status === 'zombie' ? 'smo-status-zombie' : status === 'sleep' ? 'smo-status-sleep' : 'smo-status-running'; |
| 5406 | var tr = document.createElement('tr'); |
| 5407 | if (hot) tr.className = 'smo-row-hot'; |
| 5408 | var cpuCls = (p.cpu || 0) > 80 ? ' hot' : ''; |
| 5409 | |
| 5410 | /* Action badge */ |
| 5411 | var actionHtml; |
| 5412 | if (status === 'zombie') { |
| 5413 | actionHtml = '<span class="smo-badge smo-badge-zmb">⚠ ZMB</span>'; |
| 5414 | } else if (p.killable) { |
| 5415 | actionHtml = '<button class="smo-badge smo-badge-kill" data-pid="' + p.pid + '" data-name="' + (p.name || '') |
| 5416 | + '" data-user="' + (p.user || '') + '">Kill ✕</button>'; |
| 5417 | } else { |
| 5418 | actionHtml = '<span class="smo-badge smo-badge-sys">🔒 SYS</span>'; |
| 5419 | } |
| 5420 | |
| 5421 | tr.innerHTML = |
| 5422 | '<td class="smo-pid">' + p.pid + '</td>' + |
| 5423 | '<td class="smo-name" title="' + (p.name || '') + '">' + ((p.name || '')) + '</td>' + |
| 5424 | '<td class="smo-user">' + (p.user || '—') + '</td>' + |
| 5425 | '<td class="smo-cpu' + cpuCls + '">' + (p.cpu != null ? p.cpu.toFixed(1) + '%' : '—') + '</td>' + |
| 5426 | '<td class="smo-mem">' + (p.mem_mb != null ? p.mem_mb + ' MB' : '—') + '</td>' + |
| 5427 | '<td class="smo-stat"><span class="' + statusCls + '">' + status + '</span></td>' + |
| 5428 | '<td class="smo-act">' + actionHtml + '</td>'; |
| 5429 | |
| 5430 | tbody.appendChild(tr); |
| 5431 | }); |
| 5432 | |
| 5433 | /* Wire kill buttons */ |
| 5434 | var btns = tbody.querySelectorAll('.smo-badge-kill'); |
| 5435 | for (var i = 0; i < btns.length; i++) { |
| 5436 | (function (btn) { |
| 5437 | btn.onclick = function (e) { |
| 5438 | e.stopPropagation(); |
| 5439 | smoShowKill({ pid: +btn.getAttribute('data-pid'), name: btn.getAttribute('data-name'), user: btn.getAttribute('data-user'), row: btn.closest('tr') }); |
| 5440 | }; |
| 5441 | }(btns[i])); |
| 5442 | } |
| 5443 | |
| 5444 | /* Load more button */ |
| 5445 | var more = smo$('smo-proc-more'); |
| 5446 | if (more) more.style.display = slice.length < filtered.length ? '' : 'none'; |
| 5447 | } |
| 5448 | |
| 5449 | /* ── Kill confirm ── */ |
| 5450 | function smoShowKill(target) { |
| 5451 | _killTarget = target; |
| 5452 | var kn = smo$('smo-kill-name'); if (kn) kn.textContent = target.name; |
| 5453 | var kp = smo$('smo-kill-pid'); if (kp) kp.textContent = target.pid; |
| 5454 | var ku = smo$('smo-kill-user'); if (ku) ku.textContent = target.user; |
| 5455 | var kov = smo$('smo-kill-overlay'); if (kov) kov.classList.add('on'); |
| 5456 | } |
| 5457 | function smoHideKill() { |
| 5458 | _killTarget = null; |
| 5459 | var kov = smo$('smo-kill-overlay'); if (kov) kov.classList.remove('on'); |
| 5460 | } |
| 5461 | function smoDoKill() { |
| 5462 | if (!_killTarget) return; |
| 5463 | var tgt = _killTarget; |
| 5464 | smoHideKill(); |
| 5465 | fetch('/api/process/kill', { |
| 5466 | method: 'POST', |
| 5467 | headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': (function () { var m = document.querySelector('meta[name="csrf-token"]'); return m ? m.content : ''; })() }, |
| 5468 | body: JSON.stringify({ pid: tgt.pid }) |
| 5469 | }) |
| 5470 | .then(function (r) { return r.json(); }) |
| 5471 | .then(function (d) { |
| 5472 | if (d && d.success) { |
| 5473 | smoToast('Process ' + tgt.name + ' (' + tgt.pid + ') terminated', 'ok'); |
| 5474 | /* Animate row removal */ |
| 5475 | if (tgt.row) { |
| 5476 | tgt.row.classList.add('smo-row-dying'); |
| 5477 | setTimeout(function () { if (tgt.row.parentNode) tgt.row.parentNode.removeChild(tgt.row); }, 320); |
| 5478 | } |
| 5479 | /* Remove from local list */ |
| 5480 | _procs = _procs.filter(function (p) { return p.pid !== tgt.pid; }); |
| 5481 | } else { |
| 5482 | smoToast('Error: ' + ((d && d.message) || 'permission denied') + ' for PID ' + tgt.pid, 'er'); |
| 5483 | } |
| 5484 | }) |
| 5485 | .catch(function (e) { |
| 5486 | smoToast('Kill failed: ' + e.message, 'er'); |
| 5487 | }); |
| 5488 | } |
| 5489 | |
| 5490 | /* ══ TAB 4: SYSTEM ══════════════════════════════════════════ */ |
| 5491 | function smoFetchSystem() { |
| 5492 | fetch('/api/stats/system') |
| 5493 | .then(function (r) { return r.ok ? r.json() : Promise.reject(r.status); }) |
| 5494 | .then(smoUpdateSystem) |
| 5495 | .catch(function () { }); |
| 5496 | } |
| 5497 | |
| 5498 | function smoUpdateSystem(d) { |
| 5499 | if (!d) return; |
| 5500 | |
| 5501 | /* Temperature */ |
| 5502 | if (typeof d.cpu_temp === 'number') { |
| 5503 | var t = d.cpu_temp; |
| 5504 | var tv = smo$('smo-temp-val'); |
| 5505 | if (tv) tv.textContent = t + '°C'; |
| 5506 | var tb = smo$('smo-temp-bar'); |
| 5507 | if (tb) { |
| 5508 | var tbpct = Math.min(100, t / 100 * 100); |
| 5509 | tb.style.width = tbpct + '%'; |
| 5510 | tb.className = 'smo-bar-fill' + (t >= 80 ? ' cr' : t >= 60 ? ' wn' : ' ok'); |
| 5511 | } |
| 5512 | var badge = smo$('smo-temp-badge'); |
| 5513 | if (badge) { |
| 5514 | badge.className = 'smo-temp-badge ' + (t >= 80 ? 'smo-temp-crit' : t >= 60 ? 'smo-temp-warn' : 'smo-temp-ok'); |
| 5515 | badge.textContent = '● ' + (t >= 80 ? 'CRIT' : t >= 60 ? 'WARN' : 'OK'); |
| 5516 | } |
| 5517 | _tempHist.push(t); |
| 5518 | if (_tempHist.length > _RAM_MAX) _tempHist.shift(); |
| 5519 | smoDrawSparkline('smo-temp-sparkline', _tempHist, t >= 80 ? 'var(--er)' : t >= 60 ? 'var(--wn)' : '#22c55e', 20, 100); |
| 5520 | } |
| 5521 | |
| 5522 | /* Uptime */ |
| 5523 | if (typeof d.uptime_seconds === 'number') { |
| 5524 | var uv = smo$('smo-uptime-val'); if (uv) uv.textContent = smoUptime(d.uptime_seconds); |
| 5525 | } |
| 5526 | if (typeof d.boot_epoch === 'number') { |
| 5527 | var bt = smo$('smo-boot-time'); if (bt) bt.textContent = smoFmt(d.boot_epoch); |
| 5528 | } |
| 5529 | |
| 5530 | /* Dir info */ |
| 5531 | if (d.dir_path) { var sp = smo$('smo-sys-path'); if (sp) sp.textContent = d.dir_path; } |
| 5532 | if (typeof d.dir_items === 'number') { var si = smo$('smo-sys-items'); if (si) si.textContent = d.dir_items + ' item(s)'; } |
| 5533 | |
| 5534 | /* Network (optional) */ |
| 5535 | if (typeof d.net_up_bps === 'number' && typeof d.net_down_bps === 'number') { |
| 5536 | var nc = smo$('smo-net-card'); if (nc) nc.style.display = ''; |
| 5537 | var nu = smo$('smo-net-up'); if (nu) nu.textContent = smoBps(d.net_up_bps); |
| 5538 | var nd = smo$('smo-net-down'); if (nd) nd.textContent = smoBps(d.net_down_bps); |
| 5539 | _netPeak = Math.max(_netPeak, d.net_up_bps, d.net_down_bps, 1); |
| 5540 | var nub = smo$('smo-net-up-bar'); if (nub) nub.style.width = Math.min(100, d.net_up_bps / _netPeak * 100) + '%'; |
| 5541 | var ndb = smo$('smo-net-down-bar'); if (ndb) ndb.style.width = Math.min(100, d.net_down_bps / _netPeak * 100) + '%'; |
| 5542 | if (d.net_iface) { var ni = smo$('smo-net-iface'); if (ni) ni.textContent = 'Interface: ' + d.net_iface + (d.net_ip ? ' — IP: ' + d.net_ip : ''); } |
| 5543 | } |
| 5544 | } |
| 5545 | |
| 5546 | /* ══ Sparkline (pure SVG, no D3) ════════════════════════════ */ |
| 5547 | function smoDrawSparkline(containerId, data, color, yMin, yMax) { |
| 5548 | var wrap = smo$(containerId); if (!wrap) return; |
| 5549 | var W = wrap.clientWidth || 300, H = wrap.clientHeight || 100; |
| 5550 | if (!W || !H) return; |
| 5551 | var min = typeof yMin === 'number' ? yMin : 0; |
| 5552 | var max = typeof yMax === 'number' ? yMax : 100; |
| 5553 | var range = (max - min) || 1; |
| 5554 | var N = data.length; |
| 5555 | if (!N) return; |
| 5556 | |
| 5557 | var pts = data.map(function (v, i) { |
| 5558 | var x = N < 2 ? W / 2 : i / (N - 1) * W; |
| 5559 | var y = H - (Math.min(max, Math.max(min, v)) - min) / range * H; |
| 5560 | return [x, y]; |
| 5561 | }); |
| 5562 | |
| 5563 | var polyline = pts.map(function (p) { return p[0] + ',' + p[1]; }).join(' '); |
| 5564 | /* area fill path */ |
| 5565 | var area = 'M' + pts[0][0] + ',' + H + ' L' + polyline + ' L' + pts[pts.length - 1][0] + ',' + H + ' Z'; |
| 5566 | |
| 5567 | var ns = 'http://www.w3.org/2000/svg'; |
| 5568 | var svg = document.createElementNS(ns, 'svg'); |
| 5569 | svg.setAttribute('width', W); svg.setAttribute('height', H); |
| 5570 | svg.setAttribute('viewBox', '0 0 ' + W + ' ' + H); |
| 5571 | svg.style.display = 'block'; |
| 5572 | |
| 5573 | /* Grid lines */ |
| 5574 | for (var g = 0; g <= 4; g++) { |
| 5575 | var gy = Math.round(H / 4 * g); |
| 5576 | var gl = document.createElementNS(ns, 'line'); |
| 5577 | gl.setAttribute('x1', 0); gl.setAttribute('y1', gy); |
| 5578 | gl.setAttribute('x2', W); gl.setAttribute('y2', gy); |
| 5579 | gl.setAttribute('stroke', 'var(--bd)'); gl.setAttribute('stroke-width', '1'); |
| 5580 | svg.appendChild(gl); |
| 5581 | } |
| 5582 | |
| 5583 | /* Area */ |
| 5584 | var pathEl = document.createElementNS(ns, 'path'); |
| 5585 | pathEl.setAttribute('d', area); |
| 5586 | pathEl.setAttribute('fill', color); |
| 5587 | pathEl.setAttribute('fill-opacity', '0.12'); |
| 5588 | svg.appendChild(pathEl); |
| 5589 | |
| 5590 | /* Line */ |
| 5591 | var lineEl = document.createElementNS(ns, 'polyline'); |
| 5592 | lineEl.setAttribute('points', polyline); |
| 5593 | lineEl.setAttribute('fill', 'none'); |
| 5594 | lineEl.setAttribute('stroke', color); |
| 5595 | lineEl.setAttribute('stroke-width', '2'); |
| 5596 | lineEl.setAttribute('stroke-linecap', 'round'); |
| 5597 | lineEl.setAttribute('stroke-linejoin', 'round'); |
| 5598 | svg.appendChild(lineEl); |
| 5599 | |
| 5600 | /* Current value dot */ |
| 5601 | if (pts.length) { |
| 5602 | var last = pts[pts.length - 1]; |
| 5603 | var dot = document.createElementNS(ns, 'circle'); |
| 5604 | dot.setAttribute('cx', last[0]); dot.setAttribute('cy', last[1]); dot.setAttribute('r', '3'); |
| 5605 | dot.setAttribute('fill', color); |
| 5606 | svg.appendChild(dot); |
| 5607 | } |
| 5608 | |
| 5609 | /* Y-axis labels */ |
| 5610 | [0, 50, 100].forEach(function (v) { |
| 5611 | var ly = H - (v - min) / range * H; |
| 5612 | var lbl = document.createElementNS(ns, 'text'); |
| 5613 | lbl.setAttribute('x', 3); lbl.setAttribute('y', ly - 2); |
| 5614 | lbl.setAttribute('font-size', '8'); lbl.setAttribute('fill', 'var(--tx3)'); |
| 5615 | lbl.textContent = v + '%'; |
| 5616 | svg.appendChild(lbl); |
| 5617 | }); |
| 5618 | |
| 5619 | wrap.innerHTML = ''; |
| 5620 | wrap.appendChild(svg); |
| 5621 | } |
| 5622 | |
| 5623 | /* ══ Init bindings ══════════════════════════════════════════ */ |
| 5624 | document.addEventListener('DOMContentLoaded', function () { |
| 5625 | /* Tabs */ |
| 5626 | var tabs = document.querySelectorAll('.smo-tab'); |
| 5627 | for (var i = 0; i < tabs.length; i++) { |
| 5628 | (function (tab) { |
| 5629 | tab.onclick = function () { smoSwitchTab(tab.getAttribute('data-tab')); }; |
| 5630 | }(tabs[i])); |
| 5631 | } |
| 5632 | |
| 5633 | /* Close */ |
| 5634 | var closeBtn = smo$('smo-close'); if (closeBtn) closeBtn.onclick = smoClose; |
| 5635 | |
| 5636 | /* Overlay click */ |
| 5637 | var ov = smo$('smo-overlay'); |
| 5638 | if (ov) ov.addEventListener('click', function (e) { if (e.target === ov) smoClose(); }); |
| 5639 | |
| 5640 | /* Popout */ |
| 5641 | var po = smo$('smo-popout'); |
| 5642 | if (po) po.onclick = function () { window.open(location.href + '#sysmon', '_blank', 'width=1100,height=700'); }; |
| 5643 | |
| 5644 | /* Refresh now */ |
| 5645 | var rb = smo$('smo-refresh-btn'); if (rb) rb.onclick = smoFetchAll; |
| 5646 | |
| 5647 | /* Process search */ |
| 5648 | var pq = smo$('smo-proc-q'); |
| 5649 | if (pq) pq.oninput = function () { _procQuery = this.value; _procOffset = 0; smoRenderProcs(); }; |
| 5650 | |
| 5651 | /* Process sort select */ |
| 5652 | var ps = smo$('smo-proc-sort'); |
| 5653 | if (ps) ps.onchange = function () { _procSort = this.value; _procSortAsc = this.value === 'name'; smoRenderProcs(); }; |
| 5654 | |
| 5655 | /* Load more */ |
| 5656 | var lm = smo$('smo-proc-more'); |
| 5657 | if (lm) lm.onclick = function () { _procOffset += 20; smoRenderProcs(); }; |
| 5658 | |
| 5659 | /* Process table header sort */ |
| 5660 | var ths = document.querySelectorAll('#smo-proc-table thead th[data-col]'); |
| 5661 | for (var j = 0; j < ths.length; j++) { |
| 5662 | (function (th) { |
| 5663 | th.onclick = function () { |
| 5664 | var col = th.getAttribute('data-col'); |
| 5665 | if (_procSort === col) { _procSortAsc = !_procSortAsc; } |
| 5666 | else { _procSort = col; _procSortAsc = col === 'name'; } |
| 5667 | /* update sort select */ |
| 5668 | var selEl = smo$('smo-proc-sort'); |
| 5669 | if (selEl && ['cpu', 'mem_mb', 'pid', 'name'].indexOf(col) >= 0) selEl.value = col; |
| 5670 | /* update header arrows */ |
| 5671 | var allThs = document.querySelectorAll('#smo-proc-table thead th'); |
| 5672 | for (var k = 0; k < allThs.length; k++) allThs[k].classList.remove('sort-active'); |
| 5673 | th.classList.add('sort-active'); |
| 5674 | th.innerHTML = th.textContent.replace(/[▲▼]/g, '').trim() |
| 5675 | + ' <span style="font-size:9px">' + (_procSortAsc ? '▲' : '▼') + '</span>'; |
| 5676 | smoRenderProcs(); |
| 5677 | }; |
| 5678 | }(ths[j])); |
| 5679 | } |
| 5680 | |
| 5681 | /* Kill confirm modal */ |
| 5682 | var kc = smo$('smo-kill-cancel'); if (kc) kc.onclick = smoHideKill; |
| 5683 | var kd = smo$('smo-kill-do'); if (kd) kd.onclick = smoDoKill; |
| 5684 | var kov = smo$('smo-kill-overlay'); |
| 5685 | if (kov) kov.addEventListener('click', function (e) { if (e.target === kov) smoHideKill(); }); |
| 5686 | }); |
| 5687 | |
| 5688 | }()); /* end IIFE */ |
| 5689 | </script> |
| 5690 | </body> |
| 5691 | |
| 5692 | </html> |