mirror of
https://github.com/seregonwar/zftpd.git
synced 2026-10-22 03:32:24 -05:00
Introduce an embedded Web File Explorer (zhttpd) and unified event loop implementation. Adds HTTP server headers and sources (http_api, http_parser, http_response, http_server, http_csrf, http_config), kqueue-based event loop (event_loop + event_loop_kqueue), embedded resource tooling and web UI (index.html, app.js, style.css, tools/generate_resources.py), API docs (docs/API.md), and tests (tests/test_http_query.c). Update Makefile to add ENABLE_ZHTTPD toggle (enabled by default on PS4/PS5), visibility flag for console targets, and test target for the new HTTP query test. Minor cleanup to include/ftp_config.h formatting and add ftpd.log to .gitignore.
37 lines
3.1 KiB
CSS
37 lines
3.1 KiB
CSS
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0f1216;color:#e7edf5;min-height:100vh}
|
|
.topbar{position:sticky;top:0;z-index:10;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;background:#171b21;border-bottom:2px solid #2b8cff}
|
|
.brand-title{font-weight:700;font-size:16px}
|
|
.brand-subtitle{margin-top:2px;font-size:12px;color:#9fb0c3;max-width:70vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
.status-pill{font-size:12px;padding:6px 10px;border-radius:999px;border:1px solid #2a3441;background:#1c222a}
|
|
.status-ok{color:#2ecc71}
|
|
.status-bad{color:#ff6b5f}
|
|
.toolbar{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#171b21;border-bottom:1px solid #2a3441}
|
|
.btn{border:1px solid #2a3441;background:#1c222a;color:#e7edf5;border-radius:10px;padding:8px 10px;font-size:13px;cursor:pointer}
|
|
.btn:active{transform:translateY(1px)}
|
|
.spacer{flex:1}
|
|
.search{width:60vw;max-width:340px;border:1px solid #2a3441;background:#0f1216;color:#e7edf5;border-radius:10px;padding:8px 10px;font-size:13px;outline:none}
|
|
.breadcrumb{display:flex;gap:6px;padding:10px 16px;overflow-x:auto;border-bottom:1px solid #2a3441}
|
|
.crumb{border:1px solid #2a3441;background:#171b21;color:#9fb0c3;border-radius:999px;padding:4px 8px;font-size:12px;cursor:pointer;white-space:nowrap}
|
|
.crumb:hover{color:#e7edf5;border-color:#2b8cff}
|
|
.content{padding:14px 16px}
|
|
.file-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
|
|
.card{display:flex;align-items:center;gap:10px;padding:12px;border:1px solid #2a3441;background:#171b21;border-radius:14px;cursor:pointer}
|
|
.card:hover{border-color:#2b8cff;background:#1c222a}
|
|
.icon{width:38px;height:38px;border-radius:12px;display:flex;align-items:center;justify-content:center;background:rgba(43,140,255,.15);border:1px solid rgba(43,140,255,.25);font-size:18px}
|
|
.meta{min-width:0;flex:1}
|
|
.name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
.sub{margin-top:4px;font-size:12px;color:#9fb0c3;display:flex;gap:8px;align-items:center}
|
|
.tag{border:1px solid #2a3441;border-radius:999px;padding:2px 8px;background:#0f1216}
|
|
.loading,.empty,.error{padding:12px;border-radius:14px;border:1px solid #2a3441;background:#171b21;color:#9fb0c3}
|
|
.error{border-color:rgba(196,43,28,.6);background:rgba(196,43,28,.12);color:#ffd6d1}
|
|
.drop{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(15,18,22,.65);backdrop-filter:blur(4px);z-index:50}
|
|
.drop.show{display:flex;animation:fadein .12s ease}
|
|
.drop-card{width:min(520px,92vw);border:1px dashed rgba(43,140,255,.7);border-radius:16px;padding:18px;background:rgba(23,27,33,.95)}
|
|
.drop-title{font-weight:700;font-size:16px}
|
|
.drop-sub{margin-top:6px;color:#9fb0c3;font-size:13px}
|
|
.drop-bar{margin-top:12px;height:10px;border-radius:999px;background:#0f1216;border:1px solid #2a3441;overflow:hidden}
|
|
.drop-bar-fill{height:100%;width:0%;background:linear-gradient(90deg,#2b8cff,#00c2ff);transition:width .12s ease}
|
|
@keyframes fadein{from{opacity:.6}to{opacity:1}}
|
|
@media(max-width:860px){.file-list{grid-template-columns:1fr}}
|