# cbd-web — the browser client A [Leptos](https://leptos.dev) client-side WASM app with the same functionality as `cbd-tui`, served by `crabidy-server` itself. See `architecture/web-client.md` for the design. ## How it works - **Transport**: gRPC-web (`tonic-web-wasm-client`) over the *same* generated client and proto types the TUI uses (`crabidy-core`). No second API surface — feature parity is structural. The server wraps its existing gRPC service in `tonic-web`, so the browser and the TUI hit identical `/crabidy.v1.CrabidyService/…` paths, and the role auth layer (`architecture/roles-auth.md`) gates both. - **Serving**: the built bundle (`cbd-web/dist`) is embedded into `crabidy-server` at compile time behind the default-on `web-ui` feature and served as the fallback route on port 50051. gRPC and static assets share one origin, so there is no CORS story. - **Local-first**: pure client-side rendering, every asset in the bundle (no CDN, no external fonts), library listings cached in memory like the TUI, credentials and theme in `localStorage`, and the update stream reconnects with backoff when the server disappears. There is no CRDT layer — this is a remote control for one live server state, not an offline-editing app (a deliberate departure from the `web_client_example_workspace` template that informed the toolchain). ## Functionality Everything the TUI does: browse the library (`j`/`k`/`h`/`l`, click), marks, create/rename/delete nodes (`%`/`e`/`d`, with the capture-delete `y/N` confirmation), bookmark and capture (`w`/`W`, with live progress lines and skipped-track marking), the full queue and playback controls, volume, shuffle/repeat, and a `?` help overlay listing the keys. Keys mirror the TUI; every key also has a clickable control. A light/dark theme follows the OS and can be toggled (persisted). The accent color is the crab orange-red. When the server requires credentials, a login form collects the role (`owner` / `queue-owner` / `queue-appender`) and password; they are stored in `localStorage` and sent as the gRPC-web `authorization` header on every request. ## Building The WASM toolchain (trunk, wasm-bindgen, the `wasm32-unknown-unknown` target) is provided by devenv. From the repo root: ```sh devenv shell -- build-web # release bundle → cbd-web/dist cargo build -p crabidy-server # embeds cbd-web/dist ``` `build-web` clears `RUSTFLAGS` first: the native toolchain sets the mold linker, which `rust-lld` (the wasm linker) cannot parse. Building `crabidy-server` without a `cbd-web/dist` present is fine — it embeds a placeholder page telling you to run `build-web`. Build the server `--no-default-features` to drop the web client (and the `tonic-web` layer) entirely. ## Dev loop Run a server, then a live-reloading trunk server that proxies gRPC-web to it: ```sh cargo run -p crabidy-server # or `cbd` devenv shell -- serve-web # trunk serve on http://127.0.0.1:8080 ``` `Trunk.toml` proxies `/crabidy.v1.CrabidyService` to `127.0.0.1:50051`, so the app behaves as if served from the server. ## Tests The DOM-free logic (pane/selection state machines, the keymap, capture progress formatting) lives in `src/state.rs` and `src/keymap.rs` and is unit-tested on the native target: ```sh cargo test -p cbd-web ``` Components in `src/app.rs` stay thin over that logic. The server-side serving and the gRPC-web + auth routing are tested in `crabidy-server` (`src/web.rs`, `tests/web_server.rs`).