compact calendar now

This commit is contained in:
Priec
2026-05-16 17:06:18 +02:00
parent a2c851a853
commit 7220ec87bc
2 changed files with 58 additions and 1 deletions

View File

@@ -64,6 +64,9 @@ pub struct Cell {
pub struct Row {
pub hour_label: String,
pub cells: Vec<Cell>,
/// Public view only: `true` when this row collapses a run of fully-free
/// hours into one compact strip. The admin grid never sets it.
pub free_group: bool,
}
#[derive(Debug, Serialize)]
@@ -107,6 +110,46 @@ fn week_monday(week: Option<&str>) -> NaiveDate {
monday_of(base)
}
/// Collapses runs of fully-free hour rows into one compact strip so a court
/// that isn't booked solid doesn't waste vertical space. Rows holding at
/// least one booking are kept full-size so bookings stay easy to read.
/// Public calendar only — the admin grid always shows every hour.
fn group_free_rows(rows: Vec<Row>) -> Vec<Row> {
let mut out: Vec<Row> = Vec::new();
let mut run: Vec<Row> = Vec::new();
for row in rows {
if row.cells.iter().all(|c| !c.booked) {
run.push(row);
} else {
flush_free_run(&mut run, &mut out);
out.push(row);
}
}
flush_free_run(&mut run, &mut out);
out
}
/// Drains a pending run of free rows into `out` as a single collapsed row.
fn flush_free_run(run: &mut Vec<Row>, out: &mut Vec<Row>) {
if run.is_empty() {
return;
}
let hour_of = |r: &Row| r.cells.first().map_or(FIRST_HOUR, |c| c.hour);
let first = run.first().map_or(FIRST_HOUR, hour_of);
let last = run.last().map_or(first, hour_of);
let hour_label = if run.len() > 1 {
format!("{first:02}:00 {:02}:00", last + 1)
} else {
format!("{first:02}:00")
};
out.push(Row {
hour_label,
cells: Vec::new(),
free_group: true,
});
run.clear();
}
/// Builds the calendar grid for the selected court and week.
pub async fn build_calendar(
ctx: &AppContext,
@@ -201,10 +244,15 @@ pub async fn build_calendar(
Row {
hour_label: format!("{hour:02}:00"),
cells,
free_group: false,
}
})
.collect();
// The public calendar collapses empty stretches to stay compact; the admin
// grid always shows every hour so each slot stays individually editable.
let rows = if is_admin { rows } else { group_free_rows(rows) };
Ok(CalendarPage {
lang: lang.to_string(),
is_admin,