Skip to content

fix: animate the page rather than the window, and let the browser fetch the bundles - #2235

Merged
karlitschek merged 3 commits into
masterfrom
fix/page-transition-scope
Sep 18, 2026
Merged

karlitschek merged 3 commits into
masterfrom
fix/page-transition-scope

Conversation

@karlitschek

Copy link
Copy Markdown
Member

Two fixes found by running the app rather than by testing it. They are independent — the commits split cleanly if you would rather have them separately.

The page transition slid the whole window

Clicking an entry in the sidebar slid the entire interface sideways: the sidebar itself, the top bar, the search box, the logo — not only the page being opened. Reported by a reader as "the view moves a bit from left to right".

::view-transition-old(root) and new(root) are the browser's name for a picture of the whole window. Animating those animates everything in it, so the parts of the app that had not changed were carried across with the part that had. Naming the page gives the browser something smaller to animate and lifts it out of that picture; the rest of the window is then identical before and after, and is told to hold still rather than cross-fade the same image against itself.

It is invisible in the DOM, which is why it survived the tests that shipped it: a view transition animates snapshots that sit outside the layout, so measuring element positions during a navigation shows nothing moving at all. What proves it is a frame caught mid-transition, with the animation slowed down — every sidebar entry doubled over itself. The same frame afterwards shows the sidebar sharp and still with only the page moving.

The new test pins the scoping, so this cannot quietly go back to root.

The app's own JavaScript was denied to the browser

js/.htaccess holds Deny from all, and js/ is exactly the directory a browser must fetch — every bundle this app ships is under it.

It has been harmless only where Apache runs with AllowOverride None, which means the file is never read. On an instance configured the way Nextcloud's own documentation recommendsAllowOverride All, so that the server's .htaccess works — every request for a bundle is answered 403, Apache falls through to index.php, and the app renders an empty page. Nothing in the log points at a file checked in years ago; it took LogLevel warn and Apache's AH01797 client denied by server configuration to find it.

The other three copies stay. Nothing fetches src/, appinfo/ or context/ over HTTP, so denying those costs nothing and is a sensible default.

Testing

  • npx vitest run — 2530 tests, all passing, including the two new ones for the transition scope.
  • npm run lint and npm run typecheck clean. Bundle rebuilt for 0.26.16 and reproducible on a second build.
  • Both fixes were verified on a live instance, which is how they were found. The transition was checked by slowing it to three seconds and photographing a frame mid-flight, before and after; the packaging fix by watching every bundle go from 404 to 200 and the app from a blank page to a working one.

AI disclosure

Written with Claude Code (Claude Opus 5). Reviewed before submitting.

Frank Karlitschek and others added 3 commits September 18, 2026 17:03
Clicking an entry in the sidebar slid the entire interface sideways -- the
sidebar itself, the header, the search box -- rather than only the page being
opened.

`::view-transition-old(root)` and `new(root)` are what the browser calls a
picture of the *whole window*. Animating those animates everything in it, so
the parts of the app that had not changed at all were carried across with the
part that had. It is invisible in the DOM, because a view transition animates
snapshots that sit outside the layout, which is why it survived the tests: a
frame caught mid-transition shows every sidebar entry doubled over itself.

Naming the page gives the browser something smaller to animate and lifts it
out of that picture; the rest of the window is then the same before and after,
and is told to stay still rather than cross-fade an identical image.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Frank Karlitschek <frank.karlitschek@nextcloud.com>
`js/.htaccess` holds `Deny from all`, and `js/` is exactly the directory a
browser has to fetch: every bundle this app ships is under it.

It has been harmless only where Apache is configured with `AllowOverride
None`, which means the file is never read. On an instance set up the way
Nextcloud's own documentation recommends -- `AllowOverride All`, so that the
server's `.htaccess` works -- every request for a bundle is answered 403,
Apache falls through to `index.php`, and the app renders an empty page with
no error anybody would connect to a file checked in years ago.

The other three copies stay: nothing fetches `src/`, `appinfo/` or `context/`
over HTTP, so denying those costs nothing and is a sensible default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Frank Karlitschek <frank.karlitschek@nextcloud.com>
The app version reaches the webpack build, so the committed bundle has to be
rebuilt with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Frank Karlitschek <frank.karlitschek@nextcloud.com>
@karlitschek
karlitschek merged commit 9856760 into master Sep 18, 2026
48 of 52 checks passed
@karlitschek
karlitschek deleted the fix/page-transition-scope branch September 18, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant