feat(layout): stick the title row too, and chain the sticky offsets
"All items · N items" scrolled away like the pager did. It now sticks at the scrollport top (padding-top/negative margin cancel .content's padding so nothing shows through the gap), and the three things below it offset by --hdr-h: batch bar, pagination, and the table header (--hdr-h + --pag-h). Both vars are measured on .content in renderEntries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+13
-4
@@ -800,7 +800,15 @@ input[type="range"]::-webkit-slider-thumb {
|
|||||||
.dropdown-item svg { color: var(--text-dim); }
|
.dropdown-item svg { color: var(--text-dim); }
|
||||||
|
|
||||||
.content { flex: 1; padding: 24px 32px; overflow-y: auto; }
|
.content { flex: 1; padding: 24px 32px; overflow-y: auto; }
|
||||||
.content-header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 20px; }
|
/* Sticky title row. The negative top margin cancels .content's padding-top so
|
||||||
|
nothing scrolls through the gap above it. Everything else that sticks
|
||||||
|
(batch bar, pagination, table header) offsets by --hdr-h. */
|
||||||
|
.content-header {
|
||||||
|
display: flex; align-items: baseline; gap: 12px; margin-bottom: 20px;
|
||||||
|
position: sticky; top: 0; z-index: 12;
|
||||||
|
background: var(--bg);
|
||||||
|
padding-top: 24px; margin-top: -24px;
|
||||||
|
}
|
||||||
.content-header h2 { font-size: 22px; font-weight: 600; margin: 0; }
|
.content-header h2 { font-size: 22px; font-weight: 600; margin: 0; }
|
||||||
.content-meta { color: var(--text-faint); font-size: 12px; }
|
.content-meta { color: var(--text-faint); font-size: 12px; }
|
||||||
|
|
||||||
@@ -1000,7 +1008,7 @@ input[type="range"]::-webkit-slider-thumb {
|
|||||||
/* Batch action bar (appears when selection is non-empty) */
|
/* Batch action bar (appears when selection is non-empty) */
|
||||||
.batch-bar {
|
.batch-bar {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: -1px;
|
top: var(--hdr-h, 0px);
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
padding: 10px 14px;
|
padding: 10px 14px;
|
||||||
@@ -2581,6 +2589,7 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before {
|
|||||||
.nav-item { justify-content: center; padding: 8px; }
|
.nav-item { justify-content: center; padding: 8px; }
|
||||||
.topbar { padding: 12px 16px; }
|
.topbar { padding: 12px 16px; }
|
||||||
.content { padding: 16px; }
|
.content { padding: 16px; }
|
||||||
|
.content-header { padding-top: 16px; margin-top: -16px; }
|
||||||
.slideover { width: 100%; }
|
.slideover { width: 100%; }
|
||||||
/* On a narrow viewport the slideover fills the screen — no point
|
/* On a narrow viewport the slideover fills the screen — no point
|
||||||
pushing the shell, the table isn't visible anyway. */
|
pushing the shell, the table isn't visible anyway. */
|
||||||
@@ -2676,7 +2685,7 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before {
|
|||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
background: var(--bg-elev);
|
background: var(--bg-elev);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: sticky; top: var(--pag-h, 0px);
|
position: sticky; top: calc(var(--hdr-h, 0px) + var(--pag-h, 0px));
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.entry-table th.is-sortable { cursor: pointer; }
|
.entry-table th.is-sortable { cursor: pointer; }
|
||||||
@@ -2968,7 +2977,7 @@ input[type="password"]::-ms-clear {
|
|||||||
is pushed down by --pag-h (measured in renderEntries). */
|
is pushed down by --pag-h (measured in renderEntries). */
|
||||||
.pagination {
|
.pagination {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: var(--hdr-h, 0px);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
display: flex; align-items: center; gap: 6px;
|
display: flex; align-items: center; gap: 6px;
|
||||||
|
|||||||
@@ -2296,13 +2296,16 @@ function renderGrid() {
|
|||||||
const start = (state.currentPage - 1) * state.pageSize;
|
const start = (state.currentPage - 1) * state.pageSize;
|
||||||
const pageList = list.slice(start, start + state.pageSize);
|
const pageList = list.slice(start, start + state.pageSize);
|
||||||
|
|
||||||
|
// Sticky offsets: the pagination bar parks under the title row, and the
|
||||||
|
// table header under both. Measured, so a wrapped pager still lines up.
|
||||||
|
const content = $('.content');
|
||||||
|
content.style.setProperty('--hdr-h', $('.content-header').offsetHeight + 'px');
|
||||||
if (total > 10) {
|
if (total > 10) {
|
||||||
const pag = renderPagination(total, totalPages);
|
const pag = renderPagination(total, totalPages);
|
||||||
grid.appendChild(pag);
|
grid.appendChild(pag);
|
||||||
// The table header sticks below the sticky pagination bar, not under it.
|
content.style.setProperty('--pag-h', pag.offsetHeight + 'px');
|
||||||
grid.style.setProperty('--pag-h', pag.offsetHeight + 'px');
|
|
||||||
} else {
|
} else {
|
||||||
grid.style.setProperty('--pag-h', '0px');
|
content.style.setProperty('--pag-h', '0px');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.viewMode === 'table') {
|
if (state.viewMode === 'table') {
|
||||||
|
|||||||
Reference in New Issue
Block a user