Skip to main content

picoframe_core/
lib.rs

1//! Core types and the base frame plugin for picoframe Tauri apps.
2//!
3//! Every picoframe plugin command returns a [`CliResult`] — a small, uniform
4//! envelope the frontend's typed `defineCommand` bindings unwrap. This mirrors
5//! the engineer-assist `CliResult` pattern but trimmed to the essentials.
6
7use serde::Serialize;
8use serde_json::Value;
9use tauri::{
10    plugin::{Builder, TauriPlugin},
11    Runtime,
12};
13
14#[cfg(target_os = "macos")]
15mod mouse_nav;
16
17/// Uniform result envelope returned by picoframe plugin commands.
18#[derive(Debug, Clone, Serialize)]
19pub struct CliResult {
20    pub success: bool,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub data: Option<Value>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub error: Option<String>,
25}
26
27impl CliResult {
28    /// A successful result carrying a JSON payload.
29    pub fn ok(data: Value) -> Self {
30        Self { success: true, data: Some(data), error: None }
31    }
32
33    /// A failed result carrying an error message.
34    pub fn err(message: impl Into<String>) -> Self {
35        Self { success: false, data: None, error: Some(message.into()) }
36    }
37}
38
39/// The base frame plugin. Registered first in every picoframe app's builder.
40///
41/// On macOS its `setup` installs a native NSEvent monitor that emits `mouse-nav`
42/// for the X1/X2 mouse buttons (the frame's `useMouseNavigation` hook handles the
43/// DOM path on Windows/Linux). It registers no commands yet — window/theme
44/// commands land later — and anchors the generated `main.rs`
45/// `.plugin(picoframe_core::init())` call above the plugin markers.
46pub fn init<R: Runtime>() -> TauriPlugin<R> {
47    Builder::new("picoframe")
48        .setup(|_app, _api| {
49            #[cfg(target_os = "macos")]
50            mouse_nav::install(_app.clone());
51            Ok(())
52        })
53        .build()
54}