Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion web/src/app/community/u/[username]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ export default async function CommunityUserPage(props: RouteParams) {
</h1>
<p className={styles.profileMeta}>{stats.join(" · ")}</p>
</div>
<span className={styles.headerSpacer} />
{isSelf && (
<div className={styles.profileSelfActions}>
<Link href="/pattern-lab" className={styles.btnAccent}>
Expand Down
18 changes: 15 additions & 3 deletions web/src/components/community/Community.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3467,12 +3467,15 @@
}

/* Your own profile's right-hand side: the CTA, and on a phone the sign-out
that the header cannot fit. */
that the header cannot fit. The auto margin rather than a spacer span: at
390px the name and the CTA do not fit on one line, and a spacer stays on
the first line while the CTA wraps to the left edge of the second. */
.profileSelfActions {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 10px;
margin-left: auto;
}

/* Off by default — the header's copy is the one you see on a desktop. */
Expand Down Expand Up @@ -4141,6 +4144,12 @@
grid-column: span 2;
}

/* In the grid a spacer would take a cell of its own and push Empty deck
onto a third row. */
.actionRow > .headerSpacer {
display: none;
}

.actionRow button,
.actionRow a {
min-height: 44px;
Expand All @@ -4160,9 +4169,12 @@
padding: 14px 16px;
}

/* The section nav moves to the tab bar at the bottom of the screen. */
/* The section nav moves to the tab bar at the bottom of the screen, and the
gap that held it apart from the links goes with it. Only the header's own
gap: seven other rows use the same span to push a button right, and the
deck panel is drawn inside this <header>, hence the child combinator. */
.sectionNav,
.headerSpacer {
.pageHeader > .headerSpacer {
display: none;
}

Expand Down
48 changes: 48 additions & 0 deletions web/src/components/community/communityCss.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,54 @@ describe("the deck grid on a phone", () => {
});
});

/** Every rule inside each `@media <query>` block, its selector list split. */
function mediaRules(source: string, query: string) {
return source
.replace(/\/\*[\s\S]*?\*\//g, "")
.split(`\n@media ${query} {`)
.slice(1)
.flatMap((part) => [...part.slice(0, part.indexOf("\n}")).matchAll(/\n {2}([^{}]+) \{([^}]*)\}/g)])
.map(([, selectors, body]) => ({ selectors: selectors.split(",").map((s) => s.trim()), body }));
}

// On 26 October a bare `.headerSpacer { display: none }` in the phone block,
// meant for the page header's gap, took out the same span in eight other rows.
// At 390px the comment Post button sat at x 16 instead of 316, the deck
// panel's ↑ buttons wandered between x 115 and 213 with each title's length,
// and Make & publish on your own profile moved to the left edge.
describe("the header spacer on a phone", () => {
const community = css("Community.module.css");

it("hides only the page header's own spacer", () => {
const hidden = mediaRules(community, MOBILE_MEDIA_QUERY)
.flatMap(({ selectors }) => selectors)
.filter((selector) => selector.endsWith(".headerSpacer"));
expect(hidden).toEqual([".pageHeader > .headerSpacer"]);
});

// The deck panel opens from the header's deck chip and is drawn inside the
// <header>, so a descendant selector would still reach its rows.
it("reaches the header's spacer as a child, not the deck panel inside it", () => {
expect(community).not.toMatch(/\.pageHeader \.headerSpacer/);
});

// In the two-column action grid a spacer is a cell of its own, and Empty
// deck would drop to a third row.
it("still hides it in the action grid, wherever that grid is drawn", () => {
const grid = mediaRules(community, "(max-width: 900px)");
expect(grid.find(({ selectors }) => selectors.includes(".actionRow"))?.body).toContain("display: grid;");
const spacer = grid.find(({ selectors }) => selectors.includes(".actionRow > .headerSpacer"));
expect(spacer, ".actionRow > .headerSpacer is missing from @media (max-width: 900px)").toBeDefined();
expect(spacer!.body).toContain("display: none;");
});

// At 390px "@ada YOU" and its stats line take the first line, and the
// actions wrap to a second one where no spacer reaches.
it("keeps your profile's actions right when they wrap under the name", () => {
expect(declarations(rule(community, ".profileSelfActions"))).toContain("margin-left: auto");
});
});

// The community's text colours, against each ground they are drawn on. On 26
// October the faint ink was #6B6558, 3.18:1 on the well-2 and 3.40:1 on the
// page, and axe found 426 color-contrast failures over eleven community pages,
Expand Down
Loading