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
25 changes: 24 additions & 1 deletion assets/css/analytics.css
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,22 @@
color: var( --atfb-faint );
}

/* --- Wide content scrolls in place ----------------------------------------

A table and a histogram both have a real minimum width — a table never
shrinks below its content, and a histogram column never shrinks below its
count label. In a narrow window that minimum exceeds the panel, and without
this the bars paint straight through the panel border and off the window.
The wrapper is the whole fix: the panel keeps its edge, the content keeps
its size, and the strip between them scrolls. */

.atfa-scroll {
overflow-x: auto;
/* The mean bucket wears an outline just outside its own box; without this
the scroller clips it flat along the bottom. */
padding-block-end: 3px;
}

/* --- The cross-tab -------------------------------------------------------- */

.atfa-table {
Expand All @@ -387,7 +403,14 @@
.atfa-table thead th {
color: var( --atfb-muted );
font-weight: 500;
white-space: nowrap;
}

/* The metric columns are headed by whole questions. Nowrap headers gave the
table a minimum width of every question laid end to end; letting them wrap
over a fixed column width keeps six metrics readable before the scroll has
to take over. */
.atfa-table thead th:nth-child( n + 3 ) {
min-inline-size: 140px;
}

.atfa-table__label {
Expand Down
28 changes: 22 additions & 6 deletions assets/js/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -670,10 +670,15 @@ var allTerrainFormsAnalytics = function(exports) {
})
);
return this.panel(`Broken down by ${breakdown.label.toLowerCase()}`, "", [
el("table", {
class: "atfa-table",
children: [el("thead", { children: [head] }), el("tbody", { children: rows })]
})
// Six question columns do not fit a narrow window, and a table never
// shrinks below its content — it overflows. Wide content scrolls
// inside its own container; it must never bleed past the panel.
this.scrollable(
el("table", {
class: "atfa-table",
children: [el("thead", { children: [head] }), el("tbody", { children: rows })]
})
)
]);
}
/** One panel per question. */
Expand Down Expand Up @@ -753,7 +758,7 @@ var allTerrainFormsAnalytics = function(exports) {
}
const buckets = histogramBuckets(numbers);
const peak = buckets.reduce((most, bucket) => Math.max(most, bucket.count), 0);
return el("div", {
return this.scrollable(el("div", {
class: "atfa-hist",
children: buckets.map(
(bucket) => el("div", {
Expand All @@ -769,7 +774,18 @@ var allTerrainFormsAnalytics = function(exports) {
]
})
)
});
}));
}
/**
* Wraps something wider than the window in a sideways-scrolling strip.
*
* The one honest answer to content with a real minimum width: a table or a
* histogram that cannot shrink must scroll within its own panel, because
* the alternative — seen in the wild — is bars painting straight through
* the panel border and off the edge of the window.
*/
scrollable(child) {
return el("div", { class: "atfa-scroll", children: [child] });
}
/**
* The developer panel.
Expand Down
2 changes: 1 addition & 1 deletion assets/js/analytics.min.js

Large diffs are not rendered by default.

33 changes: 27 additions & 6 deletions src/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,15 @@ class AnalyticsWindow {
);

return this.panel( `Broken down by ${ breakdown.label.toLowerCase() }`, '', [
el( 'table', {
class: 'atfa-table',
children: [ el( 'thead', { children: [ head ] } ), el( 'tbody', { children: rows } ) ],
} ),
// Six question columns do not fit a narrow window, and a table never
// shrinks below its content — it overflows. Wide content scrolls
// inside its own container; it must never bleed past the panel.
this.scrollable(
el( 'table', {
class: 'atfa-table',
children: [ el( 'thead', { children: [ head ] } ), el( 'tbody', { children: rows } ) ],
} )
),
] );
}

Expand Down Expand Up @@ -617,7 +622,11 @@ class AnalyticsWindow {
const buckets = histogramBuckets( numbers );
const peak = buckets.reduce( ( most, bucket ) => Math.max( most, bucket.count ), 0 );

return el( 'div', {
// A wide-ranging answer — forty hour buckets — has more columns than a
// narrow window has pixels, and each column's count label sets a width
// it cannot shrink below. The histogram scrolls sideways rather than
// painting past the panel.
return this.scrollable( el( 'div', {
class: 'atfa-hist',
children: buckets.map( ( bucket ) =>
el( 'div', {
Expand All @@ -633,7 +642,19 @@ class AnalyticsWindow {
],
} )
),
} );
} ) );
}

/**
* Wraps something wider than the window in a sideways-scrolling strip.
*
* The one honest answer to content with a real minimum width: a table or a
* histogram that cannot shrink must scroll within its own panel, because
* the alternative — seen in the wild — is bars painting straight through
* the panel border and off the edge of the window.
*/
private scrollable( child: HTMLElement ): HTMLElement {
return el( 'div', { class: 'atfa-scroll', children: [ child ] } );
}

/**
Expand Down
Loading