#421 · The header stays at the top of every page, phones get a side menu, and pull-to-refresh works on timelines
- timeline-app
- pull request
## The header is sticky everywhere On timeline pages the header stayed in view only because the editor's page doesn't scroll: the page is exactly one screen tall, and the editor scrolls inside its frame. Every other page scrolled the header away. The header is now `position: sticky` on every page. - A new `--header-height` variable (72px, and 60px on phones) sets `scroll-padding-top`, so jumping to an anchor doesn't land under the header. - The sticky contents lists on the help and API pages now sit below the header. ## A side menu on phones (650px and narrower) - **One row:** the header is the menu button, the brand and the account. Before, the links wrapped onto a second row; on the timeline page that row took about a sixth of the screen. - **The panel:** - the menu button slides the links in from the left over a dimmed page, and they slide back out; - the panel is hidden only once it has finished sliding out, so closing animates too. - **Closing:** the panel closes on: - a link; - its close button; - a tap outside; - Escape, which returns the focus to the menu button; - the focus leaving the panel; - the screen widening. While it's open, the page behind doesn't scroll. - **Smoothness:** sliding is only switched on a frame after the page loads, so loading never animates the panel. Reduced motion turns the sliding off. - **Without JavaScript:** the links stay in the header as before. The code is in `platform/components/site-menu.jsx`, a client component wrapping the existing links in `layout.jsx`. ## Pull-to-refresh on a timeline's page Mobile browsers' pull-to-refresh didn't work on timeline pages, while it did on others. - **Cause:** the page set `overflow: hidden` so that rounding couldn't show a second scrollbar next to the editor's. A clipped page turns pull-to-refresh off. - **Fix:** the page is one screen tall and doesn't scroll either way, so it is now clipped only with a mouse (`(hover: hover) and (pointer: fine)`). On touch screens, pulling down past the top of the editor reaches the browser. - **Still no refresh:** a drag that starts on the timeline itself pans the timeline, so it doesn't refresh the page. ## Tests `test/site-menu-live-postgres.mjs` (new, and added to CI) runs in a live browser. - **Wide screens:** the links are inline, there's no menu button, and the header stays at the top after scrolling. - **Phones:** - one row, with the menu button before the brand; - the panel is hidden from the first frame and slides with a transform transition; - it opens with the focus inside and the page locked; - each way of closing works, and a link navigates. - **Without JavaScript:** the links show in the header. - **A timeline's page:** it fits the screen, and it isn't clipped on a touch screen; with a mouse it is clipped. It passes in Chromium, WebKit and Firefox. The unit tests pass, apart from the README contents check, which fails locally only because of a `node_modules` symlink. I checked screenshots of the open panel and of a scrolled page on a phone.