fix(planning): la grille remplit l'écran, une case ne grandit plus (#110) #113

Merged
kyuno merged 1 commit from fix/planning-grid-fluid-height into main 2026-09-08 02:08:55 +02:00
2 changed files with 75 additions and 0 deletions
Showing only changes of commit c4c2c2ae39 - Show all commits

View file

@ -182,6 +182,49 @@ describe("Planning grid", () => {
cy.contains("Semaine du 10 au 16 août 2026").should("be.visible"); cy.contains("Semaine du 10 au 16 août 2026").should("be.visible");
}); });
// Issue #110 — a slot with many recipes used to stretch its `<td>`, and
// with it the whole row and the table, past `.planning-grid-wrapper`
// into a vertical scroll (the other cells of that row just gaining dead
// space). The chip list now scrolls inside its own cell instead.
it("keeps a heavy slot's recipes scrolling inside the cell, not stretching the grid", () => {
cy.intercept("GET", /\/planning\?/, {
statusCode: 200,
body: {
id: 1,
startDate: "2026-08-17T00:00:00.000Z",
finishDate: "2026-08-23T00:00:00.000Z",
items: Array.from({ length: 14 }, (_, i) => ({
id: i + 1,
weekDay: "lundi",
meal: "dejeuner",
portions: 2,
recipe: { id: i + 1, name: `Recette ${i + 1}` },
})),
},
});
cy.visit("/");
cy.get(".recipe-chip").should("have.length", 14);
// The busy cell's own recipe list is now the scroller: it's capped and
// scrolls its own overflow instead of stretching the `<td>` (and with
// it the whole row, then the table past `.planning-grid-wrapper` into a
// tall vertical scroll).
cy.get(".meal-cell__recipes").should(($lists) => {
const list = [...$lists].find(
(el) => el.querySelectorAll(".recipe-chip").length === 14,
) as HTMLElement;
expect(list, "the 14-recipe cell's list").to.exist;
expect(getComputedStyle(list).overflowY).to.be.oneOf(["auto", "scroll"]);
expect(list.scrollHeight).to.be.greaterThan(list.clientHeight);
expect(list.clientHeight).to.be.lessThan(200);
});
cy.get(".planning-grid-wrapper").should(($w) => {
expect($w[0].scrollHeight).to.be.lessThan($w[0].clientHeight * 1.25);
});
});
it("jumps to an arbitrary week by picking a day in the calendar popover", () => { it("jumps to an arbitrary week by picking a day in the calendar popover", () => {
cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }).as("getPlanning"); cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: null }).as("getPlanning");

View file

@ -84,6 +84,18 @@ table.planning-grid {
border-collapse: collapse; border-collapse: collapse;
table-layout: fixed; table-layout: fixed;
// Share the wrapper's height evenly across the five meal rows instead of
// letting each row size to its own content. A `height` on a table row is
// a minimum the browser then stretches to absorb the table's leftover
// height; an equal tiny value on every row spreads that leftover evenly,
// so the grid genuinely fills the screen rather than being only as tall
// as its busiest column (with dead space under the short ones). The
// per-cell scroll below is what then keeps a heavy slot from pushing its
// row past that share.
tbody tr {
height: 1px;
}
th, th,
td { td {
border: 1px solid var(--color-border); border: 1px solid var(--color-border);
@ -178,12 +190,32 @@ table.planning-grid {
flex-direction: column; flex-direction: column;
gap: var(--space-xs); gap: var(--space-xs);
height: 100%; height: 100%;
// The content must not be what defines the row's height: a slot with
// several recipes would otherwise stretch its `<td>`, and with it the
// whole row (every other day's cell gaining the same dead height under
// `vertical-align: top`), then the table past the wrapper into a
// vertical scroll. `min-height: 0` lets this flex column shrink to its
// share of the row so `.meal-cell__recipes` below can take over the
// scrolling.
min-height: 0;
} }
.meal-cell__recipes { .meal-cell__recipes {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--space-xs); gap: var(--space-xs);
// A slot only ever holds a handful of recipes in real use; past that the
// list scrolls inside the cell instead of stretching the `<td>` (and
// with it the whole row, then the table past `.planning-grid-wrapper`
// into a vertical scroll — issue #110). A `rem` cap rather than a `%` of
// the cell: percentage heights against a `<td>` don't resolve
// consistently across engines. `flex: 1` still lets the list use the
// row's spare height up to that cap. `.add-recipe-btn` is a flex sibling
// (outside this box), so it stays pinned just below, always reachable.
flex: 1;
min-height: 0;
max-height: 8.5rem;
overflow-y: auto;
} }
.recipe-chip { .recipe-chip {