Lab pictures are now uploadable by the owner — pick an image in
the CollaborationPanel (NSOpenPanel on Mac, GtkFileDialog shim
on GTK) and it becomes the lab's avatar on every client and on
the browser /l/<id> page. PNG, JPEG, WebP, and GIF are accepted;
the server enforces a 512 KiB cap. When no picture is set we
fall through to the owner's GitHub avatar, so a lab that nobody
bothers customizing still shows a real face. Clients get
pictures inline in the .join snapshot (bytes appended after the
notebook blob) and live updates via +update on
/labs/<id>/picture; CollaborationSession gains setLabPicture /
removeLabPicture RPCs.
Two other fixes in the same pass:
- Relative timestamps now refresh. Mac wraps each label in a
TimelineView(.periodic(..., by: 60)); GTK runs a single 60 s
Task that rewrites the string on every registered Label. So
"1 min ago" actually advances to "2 min ago" without a
rebuild.
- Closing a document window now stops collaboration. Previously
the session stayed joined until the whole app quit — Mac via
.onDisappear on MainWindowView, GTK via the existing
closeHandler calling engine.collaboration.stop() before
persisting state.