diff --git a/README.md b/README.md
index ae53219b..17fa8669 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ turn your phone or raspi into a portable file server with resumable uploads/down
* *resumable* uploads need `firefox 34+` / `chrome 41+` / `safari 7+` for full speed
* code standard: `black`
-📷 screenshots: [browser](#the-browser) // [upload](#uploading) // [md-viewer](#markdown-viewer) // [search](#searching) // [fsearch](#file-search) // [zip-DL](#zip-downloads) // [ie4](#browser-support)
+📷 **screenshots:** [browser](#the-browser) // [upload](#uploading) // [thumbnails](#thumbnails) // [md-viewer](#markdown-viewer) // [search](#searching) // [fsearch](#file-search) // [zip-DL](#zip-downloads) // [ie4](#browser-support)
## readme toc
@@ -29,6 +29,7 @@ turn your phone or raspi into a portable file server with resumable uploads/down
* [tabs](#tabs)
* [hotkeys](#hotkeys)
* [tree-mode](#tree-mode)
+ * [thumbnails](#thumbnails)
* [zip downloads](#zip-downloads)
* [uploading](#uploading)
* [file-search](#file-search)
@@ -43,6 +44,8 @@ turn your phone or raspi into a portable file server with resumable uploads/down
* [client examples](#client-examples)
* [up2k](#up2k)
* [dependencies](#dependencies)
+ * [optional dependencies](#optional-dependencies)
+ * [install recommended deps](#install-recommended-deps)
* [optional gpl stuff](#optional-gpl-stuff)
* [sfx](#sfx)
* [sfx repack](#sfx-repack)
@@ -148,11 +151,16 @@ summary: it works!
the browser has the following hotkeys
* `I/K` prev/next folder
* `P` parent folder
+* `G` toggle list / grid view
+* `T` toggle thumbnails / icons
* when playing audio:
* `0..9` jump to 10%..90%
* `U/O` skip 10sec back/forward
* `J/L` prev/next song
* `J` also starts playing the folder
+* in the grid view:
+ * `S` toggle multiselect
+ * `A/D` zoom
## tree-mode
@@ -162,6 +170,13 @@ by default there's a breadcrumbs path; you can replace this with a tree-browser
click `[-]` and `[+]` to adjust the size, and the `[a]` toggles if the tree should widen dynamically as you go deeper or stay fixed-size
+## thumbnails
+
+
+
+it does static images with Pillow and uses FFmpeg for video files, so you may want to `--no-thumb` or maybe just `--no-vthumb` depending on how destructive your users are
+
+
## zip downloads
the `zip` link next to folders can produce various types of zip/tar files using these alternatives in the browser settings tab:
@@ -421,7 +436,7 @@ enable reading HEIF pictures:
* `pyheif-pillow-opener` (requires Linux or a C compiler)
-## install recommended dependencies
+## install recommended deps
```
python -m pip install --user -U jinja2 mutagen Pillow
```
diff --git a/copyparty/ico.py b/copyparty/ico.py
index eb03c7c2..450d9f23 100644
--- a/copyparty/ico.py
+++ b/copyparty/ico.py
@@ -25,7 +25,8 @@ class Ico(object):
"""
svg = svg.format(c[:6], c[6:], ext).encode("utf-8")
diff --git a/copyparty/web/browser.css b/copyparty/web/browser.css
index cb58e71c..c2bc271d 100644
--- a/copyparty/web/browser.css
+++ b/copyparty/web/browser.css
@@ -67,6 +67,11 @@ a, #files tbody div a:last-child {
background: #161616;
text-decoration: underline;
}
+#files thead {
+ background: #333;
+ position: sticky;
+ top: 0;
+}
#files thead a {
color: #999;
font-weight: normal;
@@ -183,11 +188,21 @@ a, #files tbody div a:last-child {
color: #840;
text-shadow: 0 0 .3em #b80;
}
-#files tbody tr.sel td {
+#files tbody tr.sel td,
+#ggrid a.sel {
color: #fff;
background: #925;
border-color: #c37;
}
+#files tbody tr.sel:hover td,
+#ggrid a.sel:hover {
+ color: #fff;
+ background: #a36;
+ border-color: #d48;
+}
+#ggrid a.sel {
+ box-shadow: 0 .1em .7em #b36;
+}
#files tr.sel a {
color: #fff;
}
@@ -719,7 +734,9 @@ input[type="checkbox"]:checked+label {
border: 1px solid #444;
border-radius: .3em;
padding: .5em;
- margin: 0 1.5em 0 .4em;
+ margin: 0 1.5em 1em .4em;
+ position: sticky;
+ top: 0;
}
#ghead .btn {
position: relative;
diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js
index 6f6b37b6..e06d71c0 100644
--- a/copyparty/web/browser.js
+++ b/copyparty/web/browser.js
@@ -745,7 +745,7 @@ var thegrid = (function () {
}
};
- var click = function (e) {
+ var btnclick = function (e) {
ev(e);
var s = this.getAttribute('s'),
z = this.getAttribute('z');
@@ -765,12 +765,13 @@ var thegrid = (function () {
var links = QSA('#ghead>a');
for (var a = 0; a < links.length; a++)
- links[a].onclick = click;
+ links[a].onclick = btnclick;
ebi('gridsel').onclick = function (e) {
ev(e);
r.sel = !r.sel;
bcfg_set('gridsel', r.sel);
+ r.loadsel();
};
r.setvis = function (vis) {
@@ -793,15 +794,34 @@ var thegrid = (function () {
}
setsz();
+ function seltgl(e) {
+ ev(e);
+ var oth = ebi(this.getAttribute('ref')),
+ td = oth.parentNode.nextSibling,
+ tr = td.parentNode;
+
+ td.click();
+ this.setAttribute('class', tr.getAttribute('class'));
+ }
+
+ r.loadsel = function () {
+ var ths = QSA('#ggrid>a');
+ for (var a = 0, aa = ths.length; a < aa; a++) {
+ ths[a].onclick = r.sel ? seltgl : null;
+ ths[a].setAttribute('class', ebi(ths[a].getAttribute('ref')).parentNode.parentNode.getAttribute('class'));
+ }
+ }
+
function loadgrid() {
if (!r.dirty)
- return;
+ return r.loadsel();
var html = [];
var tr = lfiles.tBodies[0].rows;
for (var a = 0; a < tr.length; a++) {
var ao = tr[a].cells[1].firstChild,
href = esc(ao.getAttribute('href')),
+ ref = ao.getAttribute('id'),
isdir = href.split('?')[0].slice(-1)[0] == '/',
ihref = href;
@@ -830,13 +850,13 @@ var thegrid = (function () {
ihref = '/.cpr/ico/' + ihref.slice(0, -1);
}
- html.push('
' +
- ao.innerHTML + '');
+ html.push('
' + ao.innerHTML + '');
}
lfiles.style.display = 'none';
gfiles.style.display = 'block';
ebi('ggrid').innerHTML = html.join('\n');
+ r.loadsel();
}
if (r.en) {
@@ -920,6 +940,19 @@ document.onkeydown = function (e) {
if (k == 'KeyT')
return ebi('thumbs').click();
+
+ if (window['thegrid'] && thegrid.en) {
+ if (k == 'KeyS')
+ return ebi('gridsel').click();
+
+ if (k == 'KeyA')
+ return QSA('#ghead>a[z]')[0].click();
+
+ if (k == 'KeyD')
+ return QSA('#ghead>a[z]')[1].click();
+ }
+
+
};
@@ -1943,6 +1976,8 @@ var msel = (function () {
}
function selui() {
clmod(ebi('wtoggle'), 'sel', getsel().length);
+ if (window['thegrid'])
+ thegrid.loadsel();
}
function seltgl(e) {
ev(e);