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
75 lines
2.7 KiB
Rust
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)))),
|
|
)
|
|
}
|