<feed xmlns='http://www.w3.org/2005/Atom'>
<title>sl0ppij.git/zellij-client/src/web_client/utils.rs, branch main</title>
<subtitle>a sl0p.foo repository</subtitle>
<id>https://git.sl0p.foo/sl0ppij.git/atom/zellij-client/src/web_client/utils.rs?h=main</id>
<link rel='self' href='https://git.sl0p.foo/sl0ppij.git/atom/zellij-client/src/web_client/utils.rs?h=main'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/sl0ppij.git/'/>
<updated>2026-06-01T13:35:39Z</updated>
<entry>
<title>feat: PWA support for the web client (#5184)</title>
<updated>2026-06-01T13:35:39Z</updated>
<author>
<name>Robert Jin</name>
<email>20613660+jzyrobert@users.noreply.github.com</email>
</author>
<published>2026-06-01T13:35:39Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/sl0ppij.git/commit/?id=e9173cba163506491becbeacad162315d6e8f726'/>
<id>urn:sha1:e9173cba163506491becbeacad162315d6e8f726</id>
<content type='text'>
* feat: PWA support for the web client

Adds Progressive Web App support so the Zellij web client can be
installed as a standalone app via Chromium/Firefox/Safari/iOS.

- New static asset `zellij-client/assets/manifest.webmanifest` with
  required W3C members (name, start_url, scope, display, icons). All
  path-bearing fields are relative to the manifest URL so a single
  static file works under any reverse-proxy base_url prefix without
  runtime templating.
- New icon set under `zellij-client/assets/`: icon.svg (vector),
  icon-192.png and icon-512.png (purpose "any"), and
  icon-maskable-512.png (purpose "maskable") rendered at 70% of
  canvas height on a #080317 backdrop so Android adaptive masks
  honour the W3C 80%-diameter safe zone.
- `scripts/render-pwa-icons.sh` pins the rendering toolchain
  (librsvg + ImageMagick) and the maskable safe-zone geometry so
  re-renders are reproducible.
- `.webmanifest` -&gt; `application/manifest+json` mapping added to
  `get_mime_type` in `zellij-client/src/web_client/utils.rs`.
- `index.html` gains &lt;link rel="manifest"&gt;, apple-touch-icon, and
  apple-mobile-web-app-* meta tags. Placed immediately after the
  existing favicon link and before any &lt;script&gt; tag so the manifest
  is in the browser's preload scanner early.
- 5 new tests cover Content-Type, required JSON members, the
  relative-URL contract, index.html references, icon reachability,
  and base_url invariance.

Closes #5094.

* update changelog with pull url

* feat(web): trim PWA icon set to PNGs only

Drops the duplicate `zellij-client/assets/icon.svg` (verbatim copy of
`assets/logo.svg`) and the maskable PNG variant from the manifest.
Net result is the minimal icon set most production PWAs ship:
icon-192.png and icon-512.png.

- `icon.svg` was redundant with the canonical `assets/logo.svg` at
  the repo root and offered no install-criterion benefit on top of
  the 192/512 PNGs.
- `icon-maskable-512.png` only benefits Android Chrome installs
  (desktop browsers and iOS ignore the maskable purpose). The
  Android win was small for the hexagonal Zellij glyph; a hand-tuned
  maskable can be added in a follow-up if Android installs need
  polish.

`scripts/render-pwa-icons.sh` now reads from `assets/logo.svg`
directly instead of the duplicate copy.

* feat(web): use existing assets/logo.png as the PWA icon

Removes the pre-rasterized 192/512 PNG variants and the render
script in favour of serving the canonical `assets/logo.png` via a
small dedicated handler. The repo's existing logo becomes the single
source of truth; the PWA picks up logo changes automatically with no
re-render step.

- `LOGO_PNG` static is loaded via `include_bytes!` from the repo
  root, mirroring how `WEB_CLIENT_PAGE` reaches `assets/index.html`.
- New `serve_logo_png` handler is registered at `/assets/logo.png`
  before the `get_static_asset` wildcard. axum's matchit router
  gives literal paths precedence, so the explicit route always wins.
- Manifest declares a single icon entry at the actual file dimensions
  (2269x2620). Browsers letterbox onto square launcher surfaces, the
  same way they do for the existing favicon.
- `apple-touch-icon` retargets to `assets/logo.png`.
- `test_pwa_icon_assets_reachable` collapses to a single case.
- `scripts/render-pwa-icons.sh` and the rendering toolchain
  (librsvg + ImageMagick) are no longer needed.

* feat(web): drop redundant apple-mobile-web-app meta tags

The three `apple-mobile-web-app-*` meta tags are backward-compat
scaffolding for iOS &lt; 16.4:

- `apple-mobile-web-app-capable: yes` — iOS 16.4+ reads
  `display: standalone` from the manifest.
- `apple-mobile-web-app-title: Zellij` — iOS 16.4+ reads `short_name`
  from the manifest.
- `apple-mobile-web-app-status-bar-style: default` — explicitly sets
  iOS's default status-bar behaviour, i.e. a no-op.

iOS 16.4 shipped in March 2023; the cohort still on iOS 15 is
essentially devices stuck on the iPhone 6s / 7 / SE 1st gen line
(2015-16 hardware), which is not the zellij audience.

`&lt;link rel="apple-touch-icon"&gt;` is kept because iOS still ignores
manifest `icons` entries and reads only that tag for the home-screen
icon on every iOS version.

* feat(web): restore square pre-rasterized PNG icon for installability

The earlier swap to serving `assets/logo.png` directly fails
Chromium's PWA installability gate: the logo is 2269x2620 (not
square), and Chromium specifically requires "an icon at least 144
pixels square" -- a non-square icon is rejected even though the
declared `sizes` covers the dimension threshold. DevTools'
Application -&gt; Manifest panel was misleading: it parsed and
displayed the icon, but installability is a separate stricter check.

This walks the swap back to a single committed 192x192 square PNG
(`icon-192.png`) rendered from `assets/logo.svg` with the logo
composited onto a transparent square canvas. The PNG is served by
the existing `get_static_asset` route via `include_dir!`. The
`LOGO_PNG` static, `serve_logo_png` handler, and dedicated
`/assets/logo.png` route are dropped.

apple-touch-icon retargets to icon-192.png (closer to iOS's
preferred 180px home-screen size).

Net effect on the diff: ~13KB committed PNG + a single icon entry
in the manifest, in exchange for actually meeting the
installability criterion.

* style: rustfmt

---------

Co-authored-by: Robert Jin &lt;robert.jin@gresearch.co.uk&gt;
Co-authored-by: Aram Drevekenin &lt;aram@poor.dev&gt;</content>
</entry>
<entry>
<title>fix(web_server): Handle extracting session_token from multiple cookies (#4271)</title>
<updated>2025-07-28T08:22:08Z</updated>
<author>
<name>DawidPietrykowski</name>
<email>53954695+DawidPietrykowski@users.noreply.github.com</email>
</author>
<published>2025-07-28T08:22:08Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/sl0ppij.git/commit/?id=f391a73731f3371d76f89477d7269cffed4bdf1c'/>
<id>urn:sha1:f391a73731f3371d76f89477d7269cffed4bdf1c</id>
<content type='text'>
Replaces `headers().get("cookie)` with `headers().get_all("cookie")`
because Axum splits a single `Cookie: a; b; c` into 3 separate headers
each with a single value</content>
</entry>
<entry>
<title>Feature: web-client/server to share your sessions in the browser (#4242)</title>
<updated>2025-06-23T17:19:37Z</updated>
<author>
<name>Aram Drevekenin</name>
<email>aram@poor.dev</email>
</author>
<published>2025-06-23T17:19:37Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/sl0ppij.git/commit/?id=c5ac7968809ddb1033b625562eae22019cccc2f4'/>
<id>urn:sha1:c5ac7968809ddb1033b625562eae22019cccc2f4</id>
<content type='text'>
* work

* moar work

* notes

* work

* separate to terminal and control channels

* stdin working

* serve html web client initial

* serve static assets loaded with include_dir

* merge

* enable_web_server config parameter

* compile time flag to disable web server capability

* rustfmt

* add license to all xterm.js assets

* mouse working except copy/paste

* helpful comment

* web client improvements

- move script to js file
- add favicon
- add nerd font
- change title

TODO: investigate if font license embedded in otf is sufficient

* get mouse to work properly

* kitty keyboard support initial

* fix wrong type in preload link

* wip axum websocket handlers

- upgrade axum to v0.8.1, enable ws feature
- begin setup of websocket handlers
- tidy up imports

* replace control listener

* handle terminal websocket with axum

* cleanup Cargo.toml

* kitty fixes and bracketed paste

* fix(mouse): pane not found crash

* initial session switching infra

* add `web_client_font` option

* session switching, creation and resurrection working through the session manager

* move session module to zellij-utils and share logic with web-client

* some cleanups

* require restart for enable-web-server

* use session name from router

* write config to disk and watch for config changes

* rename session name to ipc path

* add basic panic handler, make render_to_client exit on channel close

* use while let instead of loop

* handle websocket close

* add mouse motions

* make clipboard work

* add weblink handling and webgl rendering

* add todo

* fix: use session name instead of patch on session switch

* use "default" layout for new sessions

* ui indication for session being shared

* share this session ui

* plugin assets

* Fix process crash on mac with notify watcher.

Use poll watcher instead of recommended as a workaround.

* make url session switching and creation work

* start welcome screen on root url

* scaffold control messages, set font from config

* set dimensions on session start

* bring back session name from url

* send bytes on terminal websocket instead of json

- create web client os input and id before websocket connection

* draft ui

* work

* refactor ui

* remove otf font, remove margins to avoid scrollbar

* version query endpoint for server status

* web session info query endpoint

* refactor: move stuff around

* add web client info to session metadata

* make tests pass

* populate real data in session list

* remove unnecessary endpoint

* add web_client node to config, add font option

* remove web_client_font

* allow disabling the web session through the config - WIP

* formalize sharing/not-sharing configuration

* fix tests

* allow shutting down web server

* display error when web clients are forbidden to attach

* only show sessions that allow web clients if this is a web client

* style(fmt): rustfmt

* fix: query web server from Zellij rather than from each plugin

* remove log spam

* handle some error paths better in the web client

* allow controlling the web server through the cli

* allow configuring the web server's ip/port

* fix tests and format code

* use direct WebServerStatus event instead of piggy-backing on SessionInfo

* plugin revamp initial

* make plugin responsive

* adjust plugin title

* refactor: share plugin

* refactor: share plugin

* add cors middleware

* some fixes for running without a compiled web server capability

* display error when starting the share plugin without web server support

* clarify config

* add pipelines to compile zellij without web support

* display error when unable to start web server

* only query web server when share plugin is running

* refactor(web-client): connection table

* give zellij_server_listener access to the control channel

* fixes and clarifications

* refactor: consolidate generate_unique_session_name

* give proper error when trying to attach to a forbidden session

* change browser URL when switching sessions

* add keyboard shortcut

* enforce https when bound to non-loopback ip

* initial authentication token implementation

* background color from theme

* initial web client theme config

* basic token generation ui

* refactor set config message creation

* also set body background

* allow editing scrollback for plugins too

* set scrollback to 0

* properly parse colors in config

* generate token from plugin

* nice login modals

* initial token management screen

* implement token authentication

* refactor(share): token management screen

* style(fmt): rustfmt

* fix(plugin): some minor bugs

* refactor(share): main screen

* refactor(share): token screen

* refactor(share): main

* refactor(share): ui components

* fix(responsiveness): properly send usage_width to the render function

* fix cli commands and add some verbosity

* add support for settings ansi and selection colors

* add cursor and cursor accent

* basic web client tests

* fix tests

* refactor: web client

* use session tokens for authentication

* improve modals

* move shutdown to ipc

* refactor: ipc logic

* serialize theme config for web client

* update tests

* refactor: move some stuff around to prepare for config hot reload

* config live reloading for the web clients

* change remember-me UI wording

* improve xterm.js link handling

* make sure terminal is focused on mousemove

* remove deprecated sharing indication from compact-bar

* gate deps and functionality behind the web_server_compatibility feature

* feat(build): add --no-web flag in all the places

* fix some other build flows

* add new assets

* update CI for no-web (untested)

* make more dependencies optional

* update axum-extra

* add web client configuration options

* gracefully close connections on server exit

* tests for graceful connection closing

* handle client-side reconnect when server is down

* fix: make sure ipc bus folder exists before starting

* add commands to manage login tokens from the cli

* style(fmt): rustfmt

* some cleanups

* fix(ux): allow alt-right-click on the web client without opening the context menu

* fix: prevent attaching to welcome screen

* fix: reload config issues

* fix long socket path on macos

* normalize config conversion and fix color gap in browser

* revoke session_token cookie if it is not valid

* fix: visual bug with multiple clients in extremely small screen sizes

* fix: only include rusqlite for the web server capability builds

* update e2e snapshots

* refactor(web): client side js

* some cleanups

* moar cleanups

* fix(tests): wait for server instead of using a fixed timeout

* debug CI

* fix(tests): use spawn_blocking for running the test web server

* fix(tests): wait for http rather than tcp port

* fix(tests): properly pass config path - hopefully this is the issue...

* success! bring back the rest of the tests

* attempt to fix the macos CI issue

* docs(changelog): add PR

---------

Co-authored-by: Thomas Linford &lt;linford.t@gmail.com&gt;</content>
</entry>
</feed>
