Files
work-app/src-tauri/src/lib.rs
T
Vincent e1ac3d7509 Size the rail to the traffic lights instead of guessing
The collapsed rail was a fixed 72px, which left the cluster with more
room on its left than its right. The width now comes from the buttons
themselves - the close button's own inset plus the zoom button's right
edge - so the margin matches on both sides. That inset is macOS's to
choose and has changed between releases, so it is asked for rather than
assumed.

Measured at startup rather than on demand. The answer arrives on the main
thread, and a command waiting for it there deadlocks until the timeout
and silently returns the fallback - which is what the first attempt did.
2026-09-02 10:07:32 +02:00

143 lines
5.5 KiB
Rust

pub mod commands;
pub mod config;
pub mod routing;
pub mod webviews;
use tauri::menu::{AboutMetadata, Menu, MenuItem, PredefinedMenuItem, Submenu};
use tauri::Manager;
/// The macOS menu bar. Edit has no entry of its own, but its items live under
/// the app menu because they are what make ⌘X/⌘C/⌘V work in a text field.
fn build_menu(app: &tauri::AppHandle) -> tauri::Result<Menu<tauri::Wry>> {
let app_menu = Submenu::with_items(
app,
"Work",
true,
&[
&PredefinedMenuItem::about(app, None, Some(AboutMetadata::default()))?,
&PredefinedMenuItem::separator(app)?,
&PredefinedMenuItem::hide(app, None)?,
&PredefinedMenuItem::hide_others(app, None)?,
&PredefinedMenuItem::show_all(app, None)?,
&PredefinedMenuItem::separator(app)?,
&PredefinedMenuItem::cut(app, None)?,
&PredefinedMenuItem::copy(app, None)?,
&PredefinedMenuItem::paste(app, None)?,
&PredefinedMenuItem::select_all(app, None)?,
&PredefinedMenuItem::separator(app)?,
&PredefinedMenuItem::quit(app, None)?,
],
)?;
let window_menu = Submenu::with_items(
app,
"Window",
true,
&[
&PredefinedMenuItem::minimize(app, None)?,
&PredefinedMenuItem::maximize(app, None)?,
&PredefinedMenuItem::fullscreen(app, None)?,
&PredefinedMenuItem::separator(app)?,
&PredefinedMenuItem::close_window(app, None)?,
],
)?;
// Zoom lives in the menu bar rather than a key listener, because the
// keystroke has to work while an app's own webview has focus — and that
// webview is a remote page this app deliberately cannot script for input.
let view_menu = Submenu::with_items(
app,
"View",
true,
&[
&MenuItem::with_id(app, "zoom-in", "Zoom In", true, Some("CmdOrCtrl+="))?,
&MenuItem::with_id(app, "zoom-out", "Zoom Out", true, Some("CmdOrCtrl+-"))?,
&MenuItem::with_id(app, "zoom-reset", "Actual Size", true, Some("CmdOrCtrl+0"))?,
&PredefinedMenuItem::separator(app)?,
&MenuItem::with_id(app, "reload", "Reload", true, Some("CmdOrCtrl+R"))?,
],
)?;
Menu::with_items(app, &[&app_menu, &view_menu, &window_menu])
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.menu(build_menu)
.on_menu_event(|app, event| match event.id().as_ref() {
"zoom-in" => commands::adjust_zoom(app, Some(1)),
"zoom-out" => commands::adjust_zoom(app, Some(-1)),
"zoom-reset" => commands::adjust_zoom(app, None),
"reload" => commands::reload_active(app),
_ => {}
})
// Remembers where the window was and how big, across launches.
.plugin(tauri_plugin_window_state::Builder::default().build())
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_notification::init())
.setup(|app| {
let state = commands::build_state(&app.handle().clone())?;
app.manage(state);
// Asked for at startup rather than at the first notification, so
// the prompt does not arrive attached to someone else's message.
commands::ensure_notification_permission(&app.handle().clone());
// Measured once: every app is positioned against the window frame
// while the shell measures from inside the content view, and the
// two are a title bar apart.
let handle = app.handle().clone();
let chrome = webviews::measure_chrome(&handle);
*handle.state::<commands::AppState>().chrome.lock().unwrap() = chrome;
let rail = commands::measure_rail(&handle);
*handle.state::<commands::AppState>().rail.lock().unwrap() = rail;
let theme = app.state::<commands::AppState>().cfg().settings.theme;
commands::apply_window_theme(&app.handle().clone(), &theme);
Ok(())
})
.invoke_handler(tauri::generate_handler![
commands::get_config,
commands::bootstrap,
commands::set_stage,
commands::set_active,
commands::hide_stage,
commands::stage_snapshot,
commands::show_stage,
commands::navigate_app,
commands::history_go,
commands::current_url,
commands::open_external,
commands::add_app,
commands::update_app,
commands::delete_app,
commands::reorder_apps,
commands::add_group,
commands::update_group,
commands::delete_group,
commands::set_nav_collapsed,
commands::set_theme,
commands::set_count_notifications,
commands::reset_config,
commands::set_window_chrome,
commands::chrome_height,
commands::rail_width,
commands::unread_counts,
commands::focus_window,
commands::save_password,
commands::fill_password,
commands::discard_password,
commands::notification_click,
commands::set_zoom,
commands::set_hidden,
commands::test_notification,
commands::notification_status,
commands::probe_apps,
commands::app_reports,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}