diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte
index b9fe32e..22b7a6c 100644
--- a/frontend/src/routes/+page.svelte
+++ b/frontend/src/routes/+page.svelte
@@ -1,5 +1,6 @@
diff --git a/src/src/lib.rs b/src/src/lib.rs
index a10efe4..f6a7be3 100644
--- a/src/src/lib.rs
+++ b/src/src/lib.rs
@@ -12,7 +12,7 @@ pub fn run() {
.setup(move |app| {
commands::theme::watch_and_emit(app.handle());
if let Some(req) = screenshot_req {
- screenshot::dispatch(req);
+ screenshot::dispatch(req, app.handle().clone());
}
Ok(())
})
diff --git a/src/src/screenshot.rs b/src/src/screenshot.rs
index 9c32abd..bb432a6 100644
--- a/src/src/screenshot.rs
+++ b/src/src/screenshot.rs
@@ -1,35 +1,69 @@
-//! `--screenshot` CLI mode: capture the settings window via
-//! `bread-screenshots`, then exit — driven by `bread-ecosystem`'s
-//! `bread-capture` orchestrator, or run standalone for one-off captures.
+//! `--screenshot` CLI mode: switch the Svelte SPA to the named sidebar
+//! section, capture it via `bread-screenshots`, then exit — driven by
+//! `bread-ecosystem`'s `bread-capture` orchestrator, or run standalone for
+//! one-off captures.
//!
-//! First pass at a Tauri (webview, not raw GTK4) target: there's no
-//! `connect_map`/`glib` signal to hook here the way every other bread-
-//! ecosystem app's screenshot mode does, since the window is owned by
-//! tao/wry, not gtk4-rs directly. Instead this just waits a fixed
-//! [`SETTLE_DELAY`] on Tauri's own async runtime after `setup()` runs —
-//! longer than the native apps' settle delays, since a webview's first
-//! paint means a full page load (JS bundle parse + Svelte mount), not just
-//! GTK widget layout. The window itself is a plain, non-layer-shell
-//! toplevel (per `tauri.conf.json`'s fixed 960x640 size), so — same
-//! reasoning as breadman/breadhelp — a full known-size canvas capture is
-//! enough; no geometry to track.
+//! There's no `connect_map`/`glib` signal to hook here the way every other
+//! bread-ecosystem app's screenshot mode does, since the window is owned by
+//! tao/wry (Tauri's Linux backend), not gtk4-rs directly. Instead this
+//! waits a fixed [`INITIAL_SETTLE_DELAY`] on Tauri's own async runtime after
+//! `setup()` runs for the page's first paint (JS bundle parse + Svelte
+//! mount) — longer than the native apps' settle delays, since a webview's
+//! first paint is a full page load, not just GTK widget layout — then emits
+//! a `screenshot-set-view` event the frontend listens for
+//! (`+page.svelte`'s `onMount`) to switch `activePage` exactly like a real
+//! sidebar click would, then waits [`VIEW_SETTLE_DELAY`] more for that
+//! view's own data to load (each section fetches its own state over Tauri
+//! commands on mount) before capturing. The window itself is a plain,
+//! non-layer-shell toplevel (per `tauri.conf.json`'s fixed 960x640 size),
+//! so — same reasoning as breadman/breadhelp — a full known-size canvas
+//! capture is enough; no geometry to track.
//!
-//! Only one view ("default", the settings window's initial landing
-//! section) is wired up so far. The frontend is a Svelte SPA with its own
-//! sidebar routing for each settings section (Appearance, Network,
-//! Bluetooth, ...) — capturing one of those specifically would mean
-//! passing a route via a URL/hash on window creation and is real, separate
-//! frontend work, deferred past this first pass (which exists to prove the
-//! isolated-headless-Sway pipeline works against a Tauri/webview window at
-//! all, not to reach full view parity with the native GTK4 apps).
+//! View names match `frontend/src/lib/sidebar.ts`'s item ids exactly (see
+//! `KNOWN_VIEWS`) — every one of them has a real registered component (see
+//! `frontend/src/lib/views/registry.ts`), no Placeholder fallbacks to skip.
use std::path::PathBuf;
use std::time::Duration;
+use tauri::Emitter;
-const SETTLE_DELAY: Duration = Duration::from_millis(2000);
-const KNOWN_VIEWS: &[&str] = &["default"];
+const INITIAL_SETTLE_DELAY: Duration = Duration::from_millis(2000);
+/// Applied after switching views — shorter than the initial load (no full
+/// page/JS reload, just a component swap + that view's own Tauri-command
+/// data fetch), but the About page alone needed 2s for its fetch to land
+/// (see the initial-pass commit), so this stays generous rather than
+/// re-guessing per view.
+const VIEW_SETTLE_DELAY: Duration = Duration::from_millis(2000);
+
+const KNOWN_VIEWS: &[&str] = &[
+ "network",
+ "breadcrumbs",
+ "bluetooth",
+ "firewall",
+ "sound",
+ "power",
+ "datetime",
+ "hyprland",
+ "keybinds",
+ "autostart",
+ "users",
+ "appearance",
+ "breadpaper",
+ "breadbar",
+ "breadbox",
+ "breadclip",
+ "breadpad",
+ "breadsearch",
+ "bread",
+ "packages",
+ "aur",
+ "firmware",
+ "snapshots",
+ "about",
+];
pub struct ScreenshotRequest {
+ pub view: String,
pub output: PathBuf,
pub width: u32,
pub height: u32,
@@ -73,13 +107,20 @@ pub fn parse(args: &[String]) -> Option {
eprintln!("bos-settings: --screenshot requires --output");
std::process::exit(1);
};
- Some(ScreenshotRequest { output: output.into(), width, height })
+ Some(ScreenshotRequest { view, output: output.into(), width, height })
}
-/// Schedule the capture-then-exit sequence. Called once from `setup()`.
-pub fn dispatch(req: ScreenshotRequest) {
+/// Schedule the switch-view-then-capture-then-exit sequence. Called once
+/// from `setup()`, which is also where `app` (needed to emit the
+/// `screenshot-set-view` event) comes from.
+pub fn dispatch(req: ScreenshotRequest, app: tauri::AppHandle) {
tauri::async_runtime::spawn(async move {
- tokio::time::sleep(SETTLE_DELAY).await;
+ tokio::time::sleep(INITIAL_SETTLE_DELAY).await;
+ if let Err(e) = app.emit("screenshot-set-view", &req.view) {
+ eprintln!("bos-settings: failed to emit screenshot-set-view: {e}");
+ std::process::exit(1);
+ }
+ tokio::time::sleep(VIEW_SETTLE_DELAY).await;
finish(bread_screenshots::capture_region(
0,
0,