diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-06 23:42:59 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-06 23:42:59 +0200 |
| commit | 920284009d634cb568f95b3e93b93012c4b803bb (patch) | |
| tree | 5f86205d3e659075b532b043005152ad57e7ca3a /packages/meshbay-hub/src | |
| parent | 13ccc4a16c604f46ed10b6c5dbfbc8fdd7d008c0 (diff) | |
| download | meshbay-920284009d634cb568f95b3e93b93012c4b803bb.tar.gz | |
feat(client): bring back New folder, icon-only — and close the hole it opened
The control was hidden and its `canCreateDir` left computed and unused. It is
back in the Files toolbar as an icon: the toolbar already carries one labelled
primary action, and a second beside it competes for the width the breadcrumb
trail needs. The name is in `title` *and* `aria-label` — a title is invisible
to a screen reader on a button with no text, so an icon-only control without
both is simply unnamed for anyone not reading with their eyes.
Its gate changes. It required `isNodeAdmin`, which contradicted the node's own
rule — "making a directory is not a privileged act; a member who can add a file
can organise where it goes" — and hid the control from everyone who could have
used it. It now follows the Upload button: a writable root, and not at the top
of a group, where the level is the set of roots rather than a directory on
anyone's disk.
Restoring it surfaced a real gap. `_do_dir_create` never learned about RO/RW:
`_do_file_upload` gained the `writable` check with the model and this one did
not, so a member refused a file in a published library could still leave empty
directories all through it, and could write to a drive mid-eject. Read-only has
to mean read-only for every way of writing, not just for files.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011pvMdvLBG92jyhvD5pD6us
Diffstat (limited to 'packages/meshbay-hub/src')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/files-app.js | 19 | ||||
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/style.css | 4 |
2 files changed, 22 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js index 9ca3aae..fb57a0f 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/files-app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/files-app.js @@ -234,7 +234,13 @@ function FilesPanel({ // set of roots, which is the operator's configuration and not a directory on // anyone's disk. The node refuses it, so offering it would only produce an // error nobody can act on. - const canCreateDir = Boolean(currentPath) && isNodeAdmin; + // + // Otherwise the rule is the same as the Upload button's, and for the same + // reason the node gives: "making a directory is not a privileged act — a + // member who can add a file can organise where it goes". It used to require + // `isNodeAdmin`, which contradicted the node and hid the control from + // everyone who could actually use it. + const canCreateDir = Boolean(currentPath) && currentRootWritable && !readOnly; const breadcrumbs = currentPath ? currentPath.split('/') : []; @@ -363,6 +369,17 @@ function FilesPanel({ onChange=${uploadFile} /> </label> `} + ${/* Icon only: the toolbar already carries a labelled primary + action, and a second one beside it competes with it for the + width a breadcrumb trail needs. The name lives in the tooltip + and in aria-label, so it is not lost to anyone reading with + something other than their eyes. */''} + ${canCreateDir && html` + <button class="tb-btn tb-btn-icon" onClick=${makeDirectory} + title=${t('group.mkdir')} aria-label=${t('group.mkdir')}> + <${Icon} name="folder-plus" /> + </button> + `} </div> <div class="breadcrumbs"> diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css index 0441e14..4647209 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/style.css +++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css @@ -833,6 +833,10 @@ button:disabled { opacity: 0.5; cursor: not-allowed; } .tb-btn:disabled { opacity: 0.45; cursor: not-allowed; } .tb-btn:disabled:hover { border-color: var(--border); color: var(--text); } .tb-btn .icon { width: 15px; height: 15px; } +/* Square, for a toolbar button whose name is in its tooltip rather than + beside it. The horizontal padding goes; the height does not, so it lines up + with the labelled buttons next to it. */ +.tb-btn-icon { padding: 0; width: 32px; justify-content: center; gap: 0; } .tb-btn.primary { background: var(--accent); border-color: var(--accent); |