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
This commit is contained in:
1 parent
3b274ed853
commit
6fb594ed28
16 files changed
+904
-463
No files matched your search
@@ -17,8 +17,16 @@ use rust_decimal::Decimal;
|
||||
|
||||
fn kv(ui: &mut Ui, k: &str, v: &str) {
|
||||
let p = pal(ui.ctx());
|
||||
// Narrow, the label goes above its value.
|
||||
if ui.available_width() < 360.0 {
|
||||
ui.label(RichText::new(k).font(theme::regular(12.0)).color(p.muted));
|
||||
ui.add(egui::Label::new(RichText::new(v).font(theme::regular(13.0))).wrap());
|
||||
ui.add_space(4.0);
|
||||
return;
|
||||
}
|
||||
ui.horizontal(|ui| {
|
||||
let (r, _) = ui.allocate_exact_size(vec2(180.0, 20.0), Sense::hover());
|
||||
let kw = (ui.available_width() * 0.4).min(180.0);
|
||||
let (r, _) = ui.allocate_exact_size(vec2(kw, 20.0), Sense::hover());
|
||||
ui.painter().text(
|
||||
r.left_center(),
|
||||
egui::Align2::LEFT_CENTER,
|
||||
@@ -79,7 +87,7 @@ pub fn show(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
|
||||
.all()
|
||||
.filter(|a| a.account_type == ledger_core::AccountType::Equity)
|
||||
{
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(
|
||||
RichText::new(format!("{} {}", a.code, a.name))
|
||||
.font(theme::regular(13.0)),
|
||||
@@ -101,7 +109,7 @@ pub fn show(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
|
||||
for m in &c.members {
|
||||
let cap = b.ledger.chart().find_by_code(&m.capital_account);
|
||||
let bal = cap.map(|a| b.balance_on(a.id, b.today)).unwrap_or_default();
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(RichText::new(&m.name).font(theme::semibold(13.5)));
|
||||
widgets::pill(
|
||||
ui,
|
||||
@@ -141,7 +149,7 @@ pub fn show(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
|
||||
ui.label(RichText::new("No periods yet. Closing a period locks it and moves its earnings into equity.").color(p.muted));
|
||||
}
|
||||
for per in periods {
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
let (g, color) = match per.status {
|
||||
PeriodStatus::Closed => (icon::LOCK, p.muted),
|
||||
PeriodStatus::Open => (icon::LOCK_OPEN, p.warning),
|
||||
@@ -217,7 +225,7 @@ fn assets(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
|
||||
} else {
|
||||
(acc / dep).try_into().unwrap_or(0.0)
|
||||
};
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
if widgets::link(
|
||||
ui,
|
||||
RichText::new(&a.description).font(theme::semibold(13.5)),
|
||||
@@ -303,7 +311,7 @@ fn schedules(ui: &mut Ui, b: &Books) {
|
||||
((total - remaining) / total).try_into().unwrap_or(0.0)
|
||||
};
|
||||
let due = s.due(b.today);
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(RichText::new(&s.description).font(theme::semibold(13.5)));
|
||||
ui.label(
|
||||
RichText::new(format!(
|
||||
@@ -361,7 +369,7 @@ fn recurring(ui: &mut Ui, b: &Books) {
|
||||
.filter(|d| r.end.is_none_or(|e| *d <= e))
|
||||
})
|
||||
.find(|d| !r.generated.contains(d));
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(RichText::new(&r.description).font(theme::semibold(13.5)));
|
||||
ui.label(
|
||||
RichText::new(format!(
|
||||
@@ -424,7 +432,7 @@ fn parties(ui: &mut Ui, b: &Books) {
|
||||
.find(|x| x.vendor_id == v.id)
|
||||
.map(|x| x.paid)
|
||||
.unwrap_or_default();
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(RichText::new(&v.name).font(theme::semibold(13.0)));
|
||||
if let Some(f) = v.form_1099 {
|
||||
widgets::pill(ui, f.label(), p.accent, p.accent_soft);
|
||||
@@ -470,7 +478,7 @@ fn parties(ui: &mut Ui, b: &Books) {
|
||||
.filter(|i| i.customer_id == c.id)
|
||||
.map(|i| i.balance())
|
||||
.sum();
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.label(RichText::new(&c.name).font(theme::semibold(13.0)));
|
||||
ui.with_layout(
|
||||
egui::Layout::right_to_left(egui::Align::Center),
|
||||
|
||||
Reference in new issue
Block a user