Files
wanderbooks/crates/ledger-gui/src/main.rs
T
swaitsandClaude Opus 5.5 6fb594ed28 gui: every screen lays itself out to fit, down to a 360-point tiling slot
Narrow windows overlapped and clipped: the top bar's crumb, date, and
search ran into each other; big numbers wrapped mid-figure; tables
painted columns over each other; the entry and document panes squeezed
their lists to slivers; anything too wide widened the whole page.

- Below 1000 points the sidebar becomes an icon rail (names, attention,
  and integrity checks in tooltips).
- The top bar lays out right to left: search shrinks to its icon, the
  date drops, the crumb truncates.
- Pages are pinned to the window width with narrower margins when tight,
  so one wide thing can't push everything off screen.
- Tiles (KPIs, cash accounts, documents) fit as many columns as the
  width allows, balanced across rows; KPI figures shrink rather than wrap.
- Painted tables shrink their amount columns, clip labels with an
  ellipsis, then scroll sideways rather than overlap.
- List/detail splits show only the detail when both won't fit.
- Reports: the side list becomes a picker; controls wrap by known width.
- Smaller fixes: chart labels thin out, company facts stack, journal
  timestamps yield, transaction filters become a dropdown.
- Min window size drops to 360x400; the screenshot test covers every
  report, a register, a document, and a journal event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
2026-10-12 20:02:48 -06:00

75 lines
2.7 KiB
Rust

//! `ledger-gui [--data-dir PATH] [--books-toml PATH] [--today YYYY-MM-DD] [--demo]`
//!
//! Opens the books read-only and follows them live. With no flags it looks
//! for `books-data/` and `wanderbooks.toml` in the current directory.
//! `--demo` builds a demo company in a temp directory and opens that.
use ledger_gui::{App, Source};
use std::path::PathBuf;
fn main() -> eframe::Result<()> {
let mut data_dir: Option<PathBuf> = None;
let mut books_toml: Option<PathBuf> = None;
let mut today = None;
let mut demo = false;
let mut args = std::env::args().skip(1);
while let Some(a) = args.next() {
match a.as_str() {
"--data-dir" => data_dir = args.next().map(PathBuf::from),
"--books-toml" => books_toml = args.next().map(PathBuf::from),
"--today" => today = args.next().and_then(|d| d.parse().ok()),
"--demo" => demo = true,
"-h" | "--help" => {
println!(
"usage: ledger-gui [--data-dir PATH] [--books-toml PATH] [--today YYYY-MM-DD] [--demo]"
);
return Ok(());
}
other => {
eprintln!("unknown argument {other}");
std::process::exit(2);
}
}
}
if demo {
let d = today.unwrap_or_else(|| chrono::Local::now().date_naive());
let dir = std::env::temp_dir().join(format!("wanderbooks-demo-{d}"));
let _ = std::fs::remove_dir_all(&dir);
if let Err(e) = ledger_gui::demo::build(&dir, d) {
eprintln!("building the demo books failed: {e}");
std::process::exit(1);
}
eprintln!("demo books: {}", dir.display());
data_dir = Some(dir.join("books-data"));
books_toml = Some(dir.join("wanderbooks.toml"));
}
let data_dir = data_dir.unwrap_or_else(|| PathBuf::from("books-data"));
let books_toml = books_toml.or_else(|| {
let guess = data_dir
.parent()
.unwrap_or(&data_dir)
.join("wanderbooks.toml");
guess.exists().then_some(guess)
});
let source = Source {
data_dir,
books_toml,
today,
};
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_title("wanderbooks")
.with_app_id("wanderbooks")
.with_inner_size([1440.0, 920.0])
// Small on purpose: tiling window managers hand out small slots
// regardless, and every screen lays itself out to fit.
.with_min_inner_size([360.0, 400.0]),
..Default::default()
};
eframe::run_native(
"wanderbooks",
options,
Box::new(move |cc| Ok(Box::new(App::new(cc, source)))),
)
}