<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/src/meshbay_hub/static/icon.js, branch 0.18</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.18</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.18'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-10-05T10:23:18Z</updated>
<entry>
<title>feat: copy a file's or folder's #/name@owner link from Files, Music, Photos and Search</title>
<updated>2026-10-05T10:23:18Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-05T10:23:18Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=1d94a92936abb3d37a8f9bfb36c8850246fee15d'/>
<id>urn:sha1:1d94a92936abb3d37a8f9bfb36c8850246fee15d</id>
<content type='text'>
"Copy link" puts the address group-link.js resolves on the clipboard, on the
hub's origin rather than the page's, so a link copied in the desktop
application is not app://meshbay. Files offers it for one row, from the
right-click menu or the toolbar with one row ticked (a phone's way in);
Music on one track's menu, whose dots a phone has; Photos on a right-clicked
tile and in the lightbox's bar. The video player and the file preview carry
a link button next to Download.

Applications get a `linkFor(entry | folderPath)` prop (MESHBAY_DESIGN.md
§9.2) and offer the action only when it names a link. The group page builds
it from the hub's row; Search from each result's own group and its path
before the merged views prefixed it, and names no link for a folder of the
merged tree, which a group name alone does not identify.

harness/copy_link_probe.py mounts the three applications in Chrome and reads
what reached the clipboard.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Player: redesigned cast remote</title>
<updated>2026-10-03T12:24:55Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-03T12:12:39Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=3a9f18aaa55df75e0ad91c4b3e2f2eb47369feda'/>
<id>urn:sha1:3a9f18aaa55df75e0ad91c4b3e2f2eb47369feda</id>
<content type='text'>
Skip buttons with circular arrows, filled scrubber, large play/pause,
device header; the remote is its own component.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): reveal button in the sign-in and registration passphrase fields</title>
<updated>2026-09-20T14:35:55Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-20T14:35:46Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=be50f1442148c21cabf039abdcae5fe20bc690e8'/>
<id>urn:sha1:be50f1442148c21cabf039abdcae5fe20bc690e8</id>
<content type='text'>
One PasswordInput for all three fields, with an eye toggle inside the box.
Out of the tab order, type="button" so a click cannot submit the form.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: embedded subtitles in the video player (MNP 3.3)</title>
<updated>2026-09-17T11:39:23Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-17T11:39:23Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=ad4ca3229002997934ccb5b2eaeb553c13b8888f'/>
<id>urn:sha1:ad4ca3229002997934ccb5b2eaeb553c13b8888f</id>
<content type='text'>
MSE decodes no in-band text track, so a subtitle cannot ride inside the
fragmented MP4 the player is fed. The node extracts one track whole, converts
it to WebVTT and caches it under its own hash; the client pulls that blob
through the ordinary file_req/chunk path and hangs a &lt;track&gt; on the video
element — the same indirection as a TMDB poster or an audio transcode, which
is what makes a film's subtitles extracted once in the life of the file rather
than once per viewing. Whole-file also makes the cues absolute, so a seek and
an audio-language change both leave the track untouched.

**The ordinal counts every subtitle stream, including the ones never listed.**
Only text codecs are offered: a bitmap track (PGS, VOBSUB — about a fifth of a
real library) has no path to WebVTT without OCR, and one extracted anyway
yields a header with no cues, which is a menu entry that shows nothing and
reports no error. Numbering the survivors of that filter would give a
PGS/SRT/SRT file the ordinals 0 and 1 for its text tracks and `-map 0:s:0`
would then extract the PGS — the same trap `AudioTrack.ordinal` exists for,
one level deeper. A fixture whose first subtitle stream cannot be decoded pins
it, and the handler checks membership of the probed list, never a range.

Additive and MINOR: the selector is drawn from `subtitle_tracks` in the node's
own `stream_init` and from no version number, so `subtitle_req` is never sent
to a peer that would not answer it. The floor stays at 3.0.

Also here: a failed extraction never touches playback, a superseded reply
cannot install its blob over a newer choice, and `_languageName` is shared
with the audio labels — lifted by both label harnesses, since a lift that
names one function stops covering the rule the moment logic moves out of it.

Tests: 9 node (tracks told apart by the words in the extracted cues, not by
tags), 10 client. Full suite green: 1545 node/common, 1252 hub.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01UGY17EPph5LsLzePPXhUVc
</content>
</entry>
<entry>
<title>feat(hub): give the audio-language button a glyph of its own</title>
<updated>2026-09-17T10:56:13Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-17T10:56:13Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=3e6d514663a5df1be3b2f0286c5f67f669d9c1d6'/>
<id>urn:sha1:3e6d514663a5df1be3b2f0286c5f67f669d9c1d6</id>
<content type='text'>
The audio-track selector was drawn with `volume` — the same glyph the music
player uses for its level control, and the same one the browser draws a few
dozen pixels below it, since the video player mounts `&lt;video controls&gt;` and
gets the native volume speaker with it. One drawing, two meanings, in one
window.

`speech-pair` is two offset bubbles: the same line, said twice, which is what
the button chooses. Nothing crosses anything — the set is stroked with no
fill, and two overlapping outlines read as a tangle at 20 px — and it leaves
the conventional subtitle glyph free for the button planned beside it.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01UGY17EPph5LsLzePPXhUVc
</content>
</entry>
<entry>
<title>music: play, play next, add to queue</title>
<updated>2026-09-16T09:01:02Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-16T09:01:02Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=20706fb9a4ec646816b44a10842aa8f58ea0fd75'/>
<id>urn:sha1:20706fb9a4ec646816b44a10842aa8f58ea0fd75</id>
<content type='text'>
The player's queue could only be replaced: every onPlayQueue reset
tracks/order/pos together. It becomes one reducer (queue-ops.js) with
an `op`, because two appends batched into one tick cannot both read the
track count out of separate useStates.

A shared pop-up menu (menu.js) carries the three verbs, on right-click
and on a dots button. A track row is now a div holding two buttons: a
button cannot contain a button.

Found by the browser probe: both music wrappers took two arguments and
forwarded two, so every "add to queue" arrived as a plain play.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): Videos and Music list their cards a page at a time</title>
<updated>2026-09-15T15:01:06Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-15T15:01:06Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=459fc93e98f23e326c2fa77fe86ba74c2bae77f0'/>
<id>urn:sha1:459fc93e98f23e326c2fa77fe86ba74c2bae77f0</id>
<content type='text'>
Previous/next arrows in the pinned toolbar, on group pages and in Search.
Page size is an account preference (Settings → Defaults), 50 by default,
10 to 200 in steps of 10.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(client): tray menu starts and stops the node, and a clearer icon</title>
<updated>2026-09-05T11:32:26Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-04T22:15:55Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=b3362e6b25bc77dfe94f4c088a865e6fd2be2601'/>
<id>urn:sha1:b3362e6b25bc77dfe94f4c088a865e6fd2be2601</id>
<content type='text'>
The first icon was an arrow dropping into a receptacle, which is the download
glyph -- a vertical stem above a container reads that way whatever the context.
Replaced with a window folding a chevron into itself: no stem, and the frame
says which object is being minimised. Applied to both the nav button and the
panel indicator, which carried the same wrong shape.

The menu now offers Start or Stop for the node daemon, chosen from its actual
state and shown only when there is a daemon to act on: `supported &amp;&amp; installed`,
so a machine with no node installed gets no entry rather than a control that
fails when used. `restart` is the start verb -- systemd's restart starts a
stopped unit, and there is no separate one to call.

The three service handlers become named functions so the tray drives exactly
what the Node page drives, instead of a second copy of the systemctl and Task
Scheduler branches. A read of the state that throws is treated as no control
at all.

The menu is rebuilt on a 5s timer while an indicator exists, and again straight
after an action. libappindicator has no "menu is about to open" event, so a menu
built once would show a stale Start/Stop for the life of the process; `systemctl
--user show` costs a few milliseconds.

Locales: tray.start_node / tray.stop_node in all ten.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01DtfG7z6wHWj8RKHCvxQtY1
</content>
</entry>
<entry>
<title>feat(client): minimise to a system tray indicator (GNOME)</title>
<updated>2026-09-05T11:32:26Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-04T16:10:39Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=89ed51e9b7ea38bd4475ce3a234f8c783b3d9b09'/>
<id>urn:sha1:89ed51e9b7ea38bd4475ce3a234f8c783b3d9b09</id>
<content type='text'>
A dedicated monochrome button in the nav, immediately left of the notification
bell, hides the window to a tray indicator. Linux only for now; Windows is
being done on that OS, and the capability is declared per platform so the
button never appears where the desktop shows no indicator -- there it would
hide the window for good.

Hides, never closes: `window-all-closed` quits the app, so closing here would
make "minimise" mean "exit" and drop the session, the transfers and the node
connection. `second-instance` now calls the same restore path, since focusing
a hidden window does nothing visible.

The context menu is not decoration. Under libappindicator -- how GNOME shows a
tray at all, via the AppIndicator extension -- `tray.on('click')` never fires;
the indicator only opens its menu. A tray whose sole affordance was a click
would be inert on the one desktop this targets. The click handler is kept for
desktops that do send it.

Menu labels come from the renderer with the IPC call: the locale files are the
interface's, the main process has no i18n, and a second string table is how two
of them start disagreeing. English fallbacks if none arrive.

The icon lives in src/, not build/: package.json `files` packages only `src/**`
and `ui/**`, so an icon under build/ is present in a dev run and missing from
every installed one. Monochrome, stroked, matching the nav glyph.

Verified on this host: Ubuntu GNOME with ubuntu-appindicators@ubuntu.com and
libayatana-appindicator3 present, so the indicator has somewhere to appear.
Not yet run end to end.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01DtfG7z6wHWj8RKHCvxQtY1
</content>
</entry>
<entry>
<title>feat(hub): drop the Search page title, add a Files refresh button</title>
<updated>2026-08-29T15:35:20Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-29T15:35:20Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=a36661b4c2a24199922d60be1bcb6ed597b433a5'/>
<id>urn:sha1:a36661b4c2a24199922d60be1bcb6ed597b433a5</id>
<content type='text'>
1. The "Search Files" &lt;h2&gt; is removed from the search page — it duplicated
   the nav and cost a line of vertical space on mobile. `search.title` is
   dropped from all ten locales (its only use).

2. A monochrome refresh button sits left of the Files breadcrumb home
   icon. It calls `onRefreshIndex` (re-fetch the group index from the
   node — the file list is a view over a cached copy with no other way to
   pull a fresh one), spins while in flight, and only renders where an
   `onRefreshIndex` is wired (the real group view, not the cross-group
   search results). New `refresh` icon; `group.refresh_index` in all ten
   locales.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_018BMLQjqFGCize2KtNBT79v
</content>
</entry>
</feed>
