Stack the story and chapter lists on a phone instead of scrolling sideways

Each table had six columns, which squeezed down to unreadable widths on a
narrow screen and forced horizontal scrolling.

Below 600px, each row becomes a bordered card. The main value (the story
or chapter title) stays unlabelled at the top, and every other value gets
a small label in front of it, taken from its column heading.

The chapter table's "select all" checkbox lived in the table header,
which mobile now hides in favour of the per-row labels. It moves into
the sticky actions bar above the list instead, next to the buttons that
already act on the selection.
This commit is contained in:
tim
2026-09-27 23:38:28 +02:00
parent 407f67622b
commit 03ed1a69cb
4 changed files with 150 additions and 16 deletions
+21
View File
@@ -232,6 +232,27 @@ test('rule previews keep a valid chapter selection and skip empty lists', async
assert.equal(calls.length, 3);
});
test('the chapter table stacks on a narrow screen instead of scrolling sideways', async () => {
await mountStory();
const wrap = nodes(main).find((el) => el.className === 'table-wrap chapters-table');
assert.ok(wrap);
const headings = nodes(wrap).filter((el) => el.tagName === 'th').map((el) => el.textContent);
assert.deepEqual(headings, ['', '#', 'Title', 'State', 'Revisions', 'Added']);
const dataLabels = nodes(wrap).filter((el) => el.tagName === 'td').map((el) => el.attributes['data-label']);
const perRow = [undefined, '#', undefined, 'State', 'Revisions', 'Added'];
assert.deepEqual(dataLabels, [...perRow, ...perRow]);
// "Select all" moved above the table, so a hidden table header on mobile does not hide it.
assert.ok(nodes(main).find((el) => el.tagName === 'label' && el.textContent.trim() === 'Select all'));
});
test('story list stacks on a narrow screen instead of scrolling sideways', async () => {
await mountStories();
const wrap = nodes(main).find((el) => el.className === 'table-wrap stories-table');
assert.ok(wrap);
const dataLabels = nodes(wrap).filter((el) => el.tagName === 'td').map((el) => el.attributes['data-label']);
assert.deepEqual(dataLabels, [undefined, 'Author', 'Site', 'Chapters', 'Status', 'Last check']);
});
test('story download modes send selected chapters and clear forced fields after success', async () => {
await mountStory();
api.on('POST', 'stories/1/download', { mode_label: 'Queued' });