app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 485b9c675863af63036cc13b5dc32957a5412073
parent 8afc336aa88c8c910f1a2477abd45bb4e854dcc3
Author: triesap <tyson@radroots.org>
Date:   Fri, 20 Mar 2026 17:34:35 +0000

build: split bootstrap workspace into core desktop and web


Diffstat:
M.gitignore | 4++--
MAGENTS.md | 5+++--
MCONTRIBUTING.md | 6+++---
MCargo.lock | 13+++++++++++--
MCargo.toml | 5+++--
Dcrates/app-web/Cargo.toml | 28----------------------------
Dcrates/app-web/src/lib.rs | 44--------------------------------------------
Dcrates/app/Cargo.toml | 33---------------------------------
Dcrates/app/src/main.rs | 34----------------------------------
Acrates/core/Cargo.toml | 18++++++++++++++++++
Rcrates/app/src/lib.rs -> crates/core/src/lib.rs | 0
Acrates/desktop/Cargo.toml | 31+++++++++++++++++++++++++++++++
Acrates/desktop/src/main.rs | 30++++++++++++++++++++++++++++++
Acrates/web/Cargo.toml | 28++++++++++++++++++++++++++++
Rcrates/app-web/Trunk.toml -> crates/web/Trunk.toml | 0
Rcrates/app-web/index.html -> crates/web/index.html | 0
Acrates/web/src/lib.rs | 44++++++++++++++++++++++++++++++++++++++++++++
Rcrates/app-web/src/main.rs -> crates/web/src/main.rs | 0
18 files changed, 173 insertions(+), 150 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,7 +1,7 @@ /target/ /.trunk/ -/crates/app-web/.trunk/ -/crates/app-web/dist/ +/crates/web/.trunk/ +/crates/web/dist/ # Local environment files .env diff --git a/AGENTS.md b/AGENTS.md @@ -41,13 +41,14 @@ Before making substantial changes: - `cargo metadata --format-version 1 --no-deps` - `cargo check` - targeted `cargo test` - - targeted `cargo run -p radroots-app` + - targeted `cargo run -p radroots-app-desktop` - If validation cannot be run, report the blocker clearly. ## 6. Workspace structure - Keep the repository root as the workspace root. -- Keep the main application crate under `crates/app`. +- Keep shared application code under `crates/core`. +- Keep target launchers and bridge crates under `crates/`. - Add new crates only when they represent a durable architectural boundary. - Keep manifests, paths, and crate boundaries simple and intentional. - Do not reintroduce obsolete framework scaffolding unless the requested change explicitly requires it. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md @@ -69,7 +69,7 @@ cargo test Run the native application: ```bash -cargo run -p radroots-app +cargo run -p radroots-app-desktop ``` Check the wasm application: @@ -81,14 +81,14 @@ env -u NO_COLOR cargo check -p radroots-app-web --target wasm32-unknown-unknown Build the wasm application: ```bash -cd crates/app-web +cd crates/web env -u NO_COLOR trunk build ``` Run the wasm application: ```bash -cd crates/app-web +cd crates/web env -u NO_COLOR trunk serve --open ``` diff --git a/Cargo.lock b/Cargo.lock @@ -1984,12 +1984,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "radroots-app" +name = "radroots-app-core" +version = "0.1.0" +dependencies = [ + "eframe", + "egui", +] + +[[package]] +name = "radroots-app-desktop" version = "0.1.0" dependencies = [ "eframe", "egui", "objc2-foundation 0.3.2", + "radroots-app-core", "wgpu", ] @@ -1999,7 +2008,7 @@ version = "0.1.0" dependencies = [ "eframe", "log", - "radroots-app", + "radroots-app-core", "wasm-bindgen-futures", "web-sys", "wgpu", diff --git a/Cargo.toml b/Cargo.toml @@ -1,7 +1,8 @@ [workspace] members = [ - "crates/app", - "crates/app-web", + "crates/core", + "crates/desktop", + "crates/web", ] resolver = "2" diff --git a/crates/app-web/Cargo.toml b/crates/app-web/Cargo.toml @@ -1,28 +0,0 @@ -[package] -name = "radroots-app-web" -version.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true -authors.workspace = true -repository.workspace = true -homepage.workspace = true -description = "Rad Roots app wasm launcher" -publish = false - -[lib] -path = "src/lib.rs" -crate-type = ["cdylib", "rlib"] - -[dependencies] -eframe.workspace = true -log.workspace = true -radroots-app = { path = "../app" } -wasm-bindgen-futures.workspace = true -web-sys.workspace = true - -[target.'cfg(target_arch = "wasm32")'.dependencies] -wgpu = { workspace = true, features = ["std", "wgsl", "webgpu", "fragile-send-sync-non-atomic-wasm"] } - -[lints] -workspace = true diff --git a/crates/app-web/src/lib.rs b/crates/app-web/src/lib.rs @@ -1,44 +0,0 @@ -#![forbid(unsafe_code)] - -#[cfg(target_arch = "wasm32")] -use eframe::wasm_bindgen::JsCast as _; - -#[cfg(target_arch = "wasm32")] -pub fn launch() { - let log_level = if cfg!(debug_assertions) { - log::LevelFilter::Info - } else { - log::LevelFilter::Warn - }; - let _ = eframe::WebLogger::init(log_level); - - wasm_bindgen_futures::spawn_local(async { - let web_options = eframe::WebOptions::default(); - let window = web_sys::window().expect("window"); - let document = window.document().expect("document"); - let canvas = document - .get_element_by_id("radroots_app_canvas") - .expect("radroots_app_canvas") - .dyn_into::<web_sys::HtmlCanvasElement>() - .expect("canvas"); - - let result = eframe::WebRunner::new() - .start( - canvas, - web_options, - Box::new(|_cc| Ok(Box::new(radroots_app::RadrootsApp))), - ) - .await; - - if let Some(loading_text) = document.get_element_by_id("loading_text") { - if result.is_ok() { - loading_text.remove(); - } else { - loading_text.set_inner_html("<p>failed to start radroots app</p>"); - } - } - }); -} - -#[cfg(not(target_arch = "wasm32"))] -pub fn launch() {} diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml @@ -1,33 +0,0 @@ -[package] -name = "radroots-app" -authors.workspace = true -version.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true -repository.workspace = true -homepage.workspace = true -description = "Rad Roots app" -publish = false - -[lib] -path = "src/lib.rs" - -[lints] -workspace = true - -[dependencies] -eframe.workspace = true -egui.workspace = true - -[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] -wgpu = { workspace = true, features = ["metal", "wgsl"] } - -[target.'cfg(target_os = "macos")'.dependencies] -objc2-foundation = { workspace = true, features = ["NSProcessInfo", "NSString"] } - -[target.'cfg(target_os = "windows")'.dependencies] -wgpu = { workspace = true, features = ["dx12", "wgsl"] } - -[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] -wgpu = { workspace = true, features = ["vulkan", "gles", "wgsl"] } diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs @@ -1,34 +0,0 @@ -#![forbid(unsafe_code)] -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -use eframe::egui; -use radroots_app::{APP_NAME, RadrootsApp}; - -#[cfg(target_os = "macos")] -fn set_macos_app_name() { - use objc2_foundation::{NSProcessInfo, NSString}; - - let process_info = NSProcessInfo::processInfo(); - let process_name = NSString::from_str(APP_NAME); - process_info.setProcessName(&process_name); -} - -#[cfg(not(target_os = "macos"))] -fn set_macos_app_name() {} - -fn main() -> eframe::Result<()> { - set_macos_app_name(); - - let options = eframe::NativeOptions { - viewport: egui::ViewportBuilder::default() - .with_inner_size([1280.0, 820.0]) - .with_min_inner_size([480.0, 320.0]), - ..Default::default() - }; - - eframe::run_native( - APP_NAME, - options, - Box::new(|_cc| Ok(Box::new(RadrootsApp))), - ) -} diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "radroots-app-core" +authors.workspace = true +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true +homepage.workspace = true +description = "Rad Roots application core" +publish = false + +[lints] +workspace = true + +[dependencies] +eframe.workspace = true +egui.workspace = true diff --git a/crates/app/src/lib.rs b/crates/core/src/lib.rs diff --git a/crates/desktop/Cargo.toml b/crates/desktop/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "radroots-app-desktop" +authors.workspace = true +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true +homepage.workspace = true +description = "Rad Roots desktop launcher" +publish = false + +[lints] +workspace = true + +[dependencies] +eframe.workspace = true +egui.workspace = true +radroots-app-core = { path = "../core" } + +[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] +wgpu = { workspace = true, features = ["metal", "wgsl"] } + +[target.'cfg(target_os = "macos")'.dependencies] +objc2-foundation = { workspace = true, features = ["NSProcessInfo", "NSString"] } + +[target.'cfg(target_os = "windows")'.dependencies] +wgpu = { workspace = true, features = ["dx12", "wgsl"] } + +[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies] +wgpu = { workspace = true, features = ["vulkan", "gles", "wgsl"] } diff --git a/crates/desktop/src/main.rs b/crates/desktop/src/main.rs @@ -0,0 +1,30 @@ +#![forbid(unsafe_code)] +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +use eframe::egui; +use radroots_app_core::{APP_NAME, RadrootsApp}; + +#[cfg(target_os = "macos")] +fn set_macos_app_name() { + use objc2_foundation::{NSProcessInfo, NSString}; + + let process_info = NSProcessInfo::processInfo(); + let process_name = NSString::from_str(APP_NAME); + process_info.setProcessName(&process_name); +} + +#[cfg(not(target_os = "macos"))] +fn set_macos_app_name() {} + +fn main() -> eframe::Result<()> { + set_macos_app_name(); + + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default() + .with_inner_size([1280.0, 820.0]) + .with_min_inner_size([480.0, 320.0]), + ..Default::default() + }; + + eframe::run_native(APP_NAME, options, Box::new(|_cc| Ok(Box::new(RadrootsApp)))) +} diff --git a/crates/web/Cargo.toml b/crates/web/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "radroots-app-web" +version.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +authors.workspace = true +repository.workspace = true +homepage.workspace = true +description = "Rad Roots web launcher" +publish = false + +[lib] +path = "src/lib.rs" +crate-type = ["cdylib", "rlib"] + +[dependencies] +eframe.workspace = true +log.workspace = true +radroots-app-core = { path = "../core" } +wasm-bindgen-futures.workspace = true +web-sys.workspace = true + +[target.'cfg(target_arch = "wasm32")'.dependencies] +wgpu = { workspace = true, features = ["std", "wgsl", "webgpu", "fragile-send-sync-non-atomic-wasm"] } + +[lints] +workspace = true diff --git a/crates/app-web/Trunk.toml b/crates/web/Trunk.toml diff --git a/crates/app-web/index.html b/crates/web/index.html diff --git a/crates/web/src/lib.rs b/crates/web/src/lib.rs @@ -0,0 +1,44 @@ +#![forbid(unsafe_code)] + +#[cfg(target_arch = "wasm32")] +use eframe::wasm_bindgen::JsCast as _; + +#[cfg(target_arch = "wasm32")] +pub fn launch() { + let log_level = if cfg!(debug_assertions) { + log::LevelFilter::Info + } else { + log::LevelFilter::Warn + }; + let _ = eframe::WebLogger::init(log_level); + + wasm_bindgen_futures::spawn_local(async { + let web_options = eframe::WebOptions::default(); + let window = web_sys::window().expect("window"); + let document = window.document().expect("document"); + let canvas = document + .get_element_by_id("radroots_app_canvas") + .expect("radroots_app_canvas") + .dyn_into::<web_sys::HtmlCanvasElement>() + .expect("canvas"); + + let result = eframe::WebRunner::new() + .start( + canvas, + web_options, + Box::new(|_cc| Ok(Box::new(radroots_app_core::RadrootsApp))), + ) + .await; + + if let Some(loading_text) = document.get_element_by_id("loading_text") { + if result.is_ok() { + loading_text.remove(); + } else { + loading_text.set_inner_html("<p>failed to start radroots app</p>"); + } + } + }); +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn launch() {} diff --git a/crates/app-web/src/main.rs b/crates/web/src/main.rs