feat: copy buttons for the install commands, icons on the file bar buttons; the path title back on the left, the upload figures sliding, dialogs focused without a ring
This commit is contained in:
1 parent
55c37a0097
commit
89d5bfd3ab
2 files changed
+66
-18
No files matched your search
@@ -13,6 +13,8 @@
|
||||
display:inline-flex; align-items:center; justify-content:center;
|
||||
vertical-align:middle; height:34px; line-height:1; margin:0; box-sizing:border-box;
|
||||
}
|
||||
/* A button with an icon before its text. */
|
||||
.fm-bar .btn.ico { gap:6px; }
|
||||
input.fm-path { font-family:ui-monospace,Menlo,monospace; font-size:13px; color:var(--muted);
|
||||
background:#0c0f13; border:1px solid var(--border); border-radius:8px; padding:8px 12px;
|
||||
flex:1; min-width:200px; height:34px; box-sizing:border-box; }
|
||||
@@ -27,14 +29,16 @@
|
||||
@keyframes spin { to { transform:rotate(360deg); } }
|
||||
/* Busy indicator; while files upload it also shows how far they got, and a
|
||||
click on it lists them. It takes room only while it shows. */
|
||||
#uppct:empty { display:none; }
|
||||
#uppct { display:inline-block; max-width:0; margin-left:0; overflow:hidden; white-space:nowrap;
|
||||
transition:max-width .3s ease, margin-left .3s ease; }
|
||||
#uppct.on { max-width:110px; margin-left:8px; }
|
||||
.busy { flex:none; display:none; align-items:center; gap:8px; background:none; border:0; padding:0 2px;
|
||||
height:34px; color:var(--muted); font-size:13px; font-variant-numeric:tabular-nums; cursor:default; }
|
||||
/* Folded to nothing when idle (the negative margin takes back the bar's
|
||||
gap), it opens smoothly, and only for work that lasts a moment. */
|
||||
.fm-bar .busy { display:inline-flex; box-sizing:border-box; max-width:0; padding:0; margin-left:-8px; opacity:0;
|
||||
.fm-bar .busy { display:inline-flex; gap:0; box-sizing:border-box; max-width:0; padding:0; margin-left:-8px; opacity:0;
|
||||
overflow:hidden; white-space:nowrap; transition:max-width .3s ease, margin-left .3s ease, opacity .25s ease; }
|
||||
.fm-bar .busy.on { max-width:120px; margin-left:0; opacity:1; transition-delay:.15s; }
|
||||
.fm-bar .busy.on { max-width:140px; margin-left:0; opacity:1; transition-delay:.15s; }
|
||||
.busy:hover { background:none; }
|
||||
.busy.up { cursor:pointer; color:var(--text); }
|
||||
.busy.up:hover { color:var(--accent); }
|
||||
@@ -75,6 +79,9 @@
|
||||
dialog { background:var(--panel); color:var(--text); border:1px solid var(--border);
|
||||
border-radius:12px; padding:0; max-width:900px; width:92vw; }
|
||||
dialog::backdrop { background:rgba(0,0,0,.6); }
|
||||
/* A dialog takes the focus itself when it opens, rather than its first
|
||||
button, which would light up as if tabbed to. */
|
||||
dialog:focus { outline:none; }
|
||||
.dlg-h { padding:14px 18px; border-bottom:1px solid var(--border); display:flex; align-items:center; gap:10px; }
|
||||
.dlg-b { padding:16px 18px; }
|
||||
#save { display:inline-flex; align-items:center; gap:8px; }
|
||||
@@ -107,7 +114,9 @@
|
||||
/* File viewer: the code editor, a picture / video / sound, or the hex editor. */
|
||||
#viewer { max-width:1100px; }
|
||||
#viewer .dlg-h { flex-wrap:wrap; }
|
||||
.vpath { flex:1; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;
|
||||
/* Right to left so a long path is cut at its start, keeping the name in
|
||||
sight; still set to the left like any title. */
|
||||
.vpath { flex:1; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; text-align:left;
|
||||
font-family:ui-monospace,Menlo,monospace; font-size:13px; font-weight:600; }
|
||||
.vmsg { width:100%; order:9; font-size:12px; }
|
||||
.vbody { padding:0; }
|
||||
@@ -225,7 +234,7 @@
|
||||
</header>
|
||||
<div class="wrap" style="max-width:1100px">
|
||||
<div class="fm-bar">
|
||||
<button class="btn ghost small" id="up">↑ Вверх</button>
|
||||
<button class="btn ghost small ico" id="up"><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="M12 19V5M5 12l7-7 7 7"/></svg>Вверх</button>
|
||||
<div class="fm-pathbox">
|
||||
<input class="fm-path" id="path" value="/" spellcheck="false" autocapitalize="off" autocomplete="off">
|
||||
<button class="btn ghost small icon sq" id="dirprops" title="Свойства папки" aria-label="Свойства папки"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M21 4h-7M10 4H3M21 12h-9M8 12H3M21 20h-5M12 20H3M14 2v4M8 10v4M16 18v4"/></svg></button>
|
||||
@@ -234,9 +243,9 @@
|
||||
<button class="btn ghost small" id="refresh">Обновить</button>
|
||||
</div>
|
||||
<div class="fm-bar">
|
||||
<button class="btn small" id="mkdir">+ Папка</button>
|
||||
<button class="btn small" id="newfile">+ Файл</button>
|
||||
<label class="btn small" style="cursor:pointer">+ Загрузить<input type="file" id="upl" multiple hidden></label>
|
||||
<button class="btn small ico" id="mkdir"><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 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"/><path d="M12 11v6M9 14h6"/></svg>Папка</button>
|
||||
<button class="btn small ico" id="newfile"><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="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M12 12v6M9 15h6"/></svg>Файл</button>
|
||||
<label class="btn small ico" style="cursor:pointer"><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="M12 3v12M6 10l6 6 6-6M5 21h14"/></svg>Загрузить<input type="file" id="upl" multiple hidden></label>
|
||||
<span class="spacer" style="flex:1"></span>
|
||||
<span id="selinfo" class="muted" style="font-size:13px"></span>
|
||||
<button class="btn ghost small" id="zipsel" disabled>В zip</button>
|
||||
@@ -256,7 +265,7 @@
|
||||
<p class="muted" id="hint" style="font-size:13px">Перетащите файлы сюда для загрузки. Клик по файлу - просмотр и правка.</p>
|
||||
</div>
|
||||
|
||||
<dialog id="viewer">
|
||||
<dialog id="viewer" tabindex="-1">
|
||||
<div class="dlg-h">
|
||||
<strong class="vpath" dir="rtl"><bdi id="vname"></bdi></strong>
|
||||
<button class="btn ghost small" id="vtext" hidden>Редактировать</button>
|
||||
@@ -295,7 +304,7 @@
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog id="updlg">
|
||||
<dialog id="updlg" tabindex="-1">
|
||||
<div class="dlg-h">
|
||||
<strong style="flex:1">Загрузка файлов</strong>
|
||||
<button class="btn ghost small icon close x" id="updlg-close" title="Закрыть" aria-label="Закрыть"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
|
||||
@@ -303,7 +312,7 @@
|
||||
<div class="dlg-b" id="updlg-list"></div>
|
||||
</dialog>
|
||||
|
||||
<dialog id="propdlg">
|
||||
<dialog id="propdlg" tabindex="-1">
|
||||
<div class="dlg-h">
|
||||
<strong style="flex:1">Свойства</strong>
|
||||
<button class="btn ghost small icon close x" id="propdlg-close" title="Закрыть" aria-label="Закрыть"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
|
||||
@@ -369,6 +378,8 @@
|
||||
// An open dialog sits in the page's top layer, above any z-index: the toast
|
||||
// goes inside it then, so "сохранено" or an error shows over the editor.
|
||||
let toastTimer = null;
|
||||
// Opens a dialog with the focus on the dialog itself, not its first button.
|
||||
const openModal = d => { d.showModal(); d.focus(); };
|
||||
const toast = (msg, err) => {
|
||||
const t = $('toast'), host = [...document.querySelectorAll('dialog[open]')].pop() || document.body;
|
||||
if (t.parentNode !== host) host.appendChild(t);
|
||||
@@ -607,7 +618,7 @@
|
||||
V.path = path; V.dirty = false;
|
||||
$('vname').textContent = path;
|
||||
$('vname').parentElement.title = path;
|
||||
if (!$('viewer').open) $('viewer').showModal();
|
||||
if (!$('viewer').open) openModal($('viewer'));
|
||||
}
|
||||
|
||||
async function view(e) {
|
||||
@@ -1036,7 +1047,7 @@
|
||||
showMode(d.mode);
|
||||
$('pp-rec').hidden = !d.is_dir;
|
||||
$('pp-recursive').checked = false; $('pp-only').value = ''; $('pp-only').disabled = true;
|
||||
if (!$('propdlg').open) $('propdlg').showModal();
|
||||
if (!$('propdlg').open) openModal($('propdlg'));
|
||||
}
|
||||
$('pp-apply').onclick = async () => {
|
||||
const o = P.orig, mode = readMode();
|
||||
@@ -1137,7 +1148,10 @@
|
||||
const busy = $('busy');
|
||||
busy.classList.toggle('up', uploads.length > 0);
|
||||
busy.title = uploads.length ? 'Показать загружаемые файлы' : '';
|
||||
$('uppct').textContent = pend.length ? Math.floor(100 * sent / total) + '%' + (counted.length > 1 ? ' · ' + (counted.length - pend.length) + '/' + counted.length : '') : '';
|
||||
// The figures slide in while files go and slide out after, keeping the
|
||||
// last text as they go.
|
||||
if (pend.length) $('uppct').textContent = Math.floor(100 * sent / total) + '%' + (counted.length > 1 ? ' · ' + (counted.length - pend.length) + '/' + counted.length : '');
|
||||
$('uppct').classList.toggle('on', pend.length > 0);
|
||||
const list = $('updlg-list');
|
||||
if (!$('updlg').open) return;
|
||||
list.innerHTML = uploads.length ? '' : '<p class="muted">Сейчас ничего не загружается.</p>';
|
||||
@@ -1156,7 +1170,7 @@
|
||||
list.appendChild(el);
|
||||
}
|
||||
}
|
||||
$('busy').onclick = () => { if (!uploads.length) return; $('updlg').showModal(); renderUploads(); };
|
||||
$('busy').onclick = () => { if (!uploads.length) return; openModal($('updlg')); renderUploads(); };
|
||||
$('updlg-close').onclick = () => $('updlg').close();
|
||||
|
||||
// The pieces go on to the client as they come, so the bar follows the
|
||||
|
||||
Reference in new issue
Block a user