mirror of
https://github.com/simonw/datasette.git
synced 2026-07-13 02:54:44 +02:00
Sticky headers for tables prototype
I'm not convinced by this, it feels a bit flickery.
This commit is contained in:
parent
db82123108
commit
7a848d34fa
3 changed files with 69 additions and 0 deletions
|
|
@ -497,7 +497,10 @@ table.rows-and-columns td em {
|
|||
color: #aaa;
|
||||
}
|
||||
table.rows-and-columns th {
|
||||
background: #F8FAFB;
|
||||
padding-right: 1em;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
table.rows-and-columns a:link {
|
||||
text-decoration: none;
|
||||
|
|
|
|||
|
|
@ -506,6 +506,45 @@ function renderActionLink(itemConfig) {
|
|||
return newLink;
|
||||
}
|
||||
|
||||
function initializeStickyTableHeader(tableWrapper) {
|
||||
var table = tableWrapper.querySelector("table.rows-and-columns");
|
||||
var tableHead = table && table.querySelector("thead");
|
||||
if (!tableHead || !window.requestAnimationFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
var animationFrame = null;
|
||||
function updatePosition() {
|
||||
animationFrame = null;
|
||||
if (window.matchMedia("(max-width: 576px)").matches) {
|
||||
tableHead.style.transform = "";
|
||||
return;
|
||||
}
|
||||
// overflow-x: auto makes tableWrapper the sticky scroll container, even
|
||||
// though the page handles vertical scrolling. Counter the page scroll so
|
||||
// the real header stays aligned with both the viewport and the table.
|
||||
var wrapperTop = tableWrapper.getBoundingClientRect().top;
|
||||
var maximumOffset = Math.max(
|
||||
0,
|
||||
table.offsetHeight - tableHead.offsetHeight,
|
||||
);
|
||||
var offset = Math.min(Math.max(-wrapperTop, 0), maximumOffset);
|
||||
tableHead.style.transform = offset
|
||||
? `translateY(${offset}px)`
|
||||
: "";
|
||||
}
|
||||
|
||||
function queuePositionUpdate() {
|
||||
if (animationFrame === null) {
|
||||
animationFrame = window.requestAnimationFrame(updatePosition);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("scroll", queuePositionUpdate, { passive: true });
|
||||
window.addEventListener("resize", queuePositionUpdate);
|
||||
queuePositionUpdate();
|
||||
}
|
||||
|
||||
/** Main initialization function for Datasette Table interactions */
|
||||
const initDatasetteTable = function (manager) {
|
||||
// Feature detection
|
||||
|
|
@ -521,6 +560,7 @@ const initDatasetteTable = function (manager) {
|
|||
if (tableWrapper) {
|
||||
tableWrapper.addEventListener("scroll", closeMenu);
|
||||
}
|
||||
window.addEventListener("scroll", closeMenu, { passive: true });
|
||||
document.body.addEventListener("click", (ev) => {
|
||||
/* was this click outside the menu? */
|
||||
var target = ev.target;
|
||||
|
|
@ -631,6 +671,9 @@ const initDatasetteTable = function (manager) {
|
|||
icon.addEventListener("click", onTableHeaderClick);
|
||||
th.appendChild(icon);
|
||||
});
|
||||
if (tableWrapper) {
|
||||
initializeStickyTableHeader(tableWrapper);
|
||||
}
|
||||
};
|
||||
|
||||
function filterRowSelector(manager) {
|
||||
|
|
|
|||
|
|
@ -410,6 +410,29 @@ def test_datasette_homepage_contains_datasette(page, datasette_server):
|
|||
assert "Datasette" in page.locator("body").inner_text()
|
||||
|
||||
|
||||
@pytest.mark.playwright
|
||||
def test_table_header_stays_visible_while_scrolling(page, datasette_server):
|
||||
page.set_viewport_size({"width": 600, "height": 400})
|
||||
page.goto(f"{datasette_server}fixtures/sortable?_size=100")
|
||||
|
||||
wrapper = page.locator(".table-wrapper")
|
||||
header = wrapper.locator("table.rows-and-columns th").first
|
||||
assert wrapper.evaluate("node => node.scrollWidth > node.clientWidth")
|
||||
|
||||
wrapper.evaluate("""node => window.scrollTo(
|
||||
0,
|
||||
node.getBoundingClientRect().top + window.scrollY + 100
|
||||
)""")
|
||||
page.wait_for_function("""() => Math.abs(document.querySelector(
|
||||
'table.rows-and-columns th'
|
||||
).getBoundingClientRect().top) < 1""")
|
||||
assert abs(header.bounding_box()["y"]) < 1
|
||||
|
||||
wrapper.evaluate("node => node.scrollLeft = 100")
|
||||
assert wrapper.evaluate("node => node.scrollLeft") == 100
|
||||
assert abs(header.bounding_box()["y"]) < 1
|
||||
|
||||
|
||||
@pytest.mark.playwright
|
||||
def test_create_table_flow(page, datasette_server):
|
||||
page.goto(f"{datasette_server}data")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue