Give every archival PDF a page to be read on - #29
Merged
Conversation
A DOI click lands a reader on the repository's item page, which is a file browser: it shows a PDF and a zip and asks which one you wanted. We cannot restyle that page -- it is the repository's -- but we can stop sending readers a file when what they wanted was to look at the document. `/<slug>/read/` shows the archival PDF embedded, under the note's title, authors, date and DOI, with three buttons: Download PDF, Markdown source, and Read on the site. The site's own PDF links now go there rather than at the file, and the theme's Downloads menu is retargeted at it in the browser -- the same after-hydration trick the comments use, since React owns the document and undoes anything changed before it hydrates. Only anchors into the theme's `/build/` export path are touched, so a PDF linked from an article's prose is left alone. The markdown source is staged beside the PDF at `/<slug>/<slug>.md` to give that second button something to point at. It is what someone reusing a figure, a table or an equation actually wants, and it was already in the repository. Embedding our own copy rather than the repository's widget is not only a styling choice: `ndownloader.figshare.com` answers with `content-disposition: attachment` and `x-frame-options: SAMEORIGIN`, so the archived file cannot be framed from this origin at all. Ours is served as `application/pdf` with no disposition, so it renders inline, needs no third-party script, and works in a preview build. Tests cover the ordering that is easy to lose -- the reader page is only written where the PDF is already staged, so `stage_downloads.py` must run first, in the build task and in the preview path alike -- and that the page carries both downloads, the way back, and a noindex (the article remains canonical). Underworld development team with AI support from Claude Code
Contributor
|
Preview: https://underworld-technical-notes.github.io/underworldcode.org-preview/c468a06e88/ No article changed on this branch. Built from |
Every href and the embed source were absolute (/<slug>/<slug>.pdf). The preview site serves the whole site from a hashed subdirectory, so an absolute path walks out of it to the domain root and the buttons 404 on exactly the build where they would be reviewed. They are now ../<slug>.pdf and ../, which work in both. The Downloads retarget had the same fault -- it built "/" + slug + "/read/" -- and now derives the href from the current path, prefix and all. The test asserts the outcome rather than the strings: no absolute article path appears on the page. Underworld development team with AI support from Claude Code
…n race it Louis asked where the button is. It was inside the theme's Downloads menu, behind an icon in the frontmatter row -- which is not an answer. A visible "PDF" link now sits in that row beside the licence badge, styled with the site's own tokens, and goes to /<slug>/read/. The menu entry is handled differently too. The theme renders those entries from its hydration payload only when the menu OPENS, so there is no anchor in the page to rewrite beforehand, and the MutationObserver rewrite this replaces was racing the reader's second click by its own 120 ms debounce. A capture-phase click listener has no race: it sees the click on any anchor into /build/*.pdf and sends it to the reader page instead. Tests assert the visible link, the capture-phase interception, and that the href is still built from the current path so the preview subdirectory survives. The first draft of that last test asserted the ABSENCE of an absolute form and matched the comment explaining why we do not use one; it asserts the positive. Underworld development team with AI support from Claude Code
With a visible PDF link going to /<slug>/read/, where the PDF and the markdown source are both a button away, the theme's Downloads menu is a quieter second route to the same two files. It is gone. Removed at both ends. The menu is rendered from the `exports` array in the page's hydration payload, so that is emptied -- 82 pages. The button MyST had already rendered into the static HTML is deleted with it -- 80 pages: React would reconcile it away once hydration ran, but not before it had been on screen, and never at all for a reader without Javascript. The button is found by its own accessible label rather than by a class. The theme's classes are utility soup and its element ids are generated per render, but `<span class="sr-only">Downloads</span>` is there because a screen reader needs it to be. The capture-phase click interception stays as belt and braces: if a theme upgrade renders an export link from somewhere this does not reach, it still leads to the reader page rather than to a bare file. Verified on a full build: no Downloads label, no populated exports, no /build/ PDF references, the licence badge untouched and the visible PDF link in place. Underworld development team with AI support from Claude Code
#28 landed the absolute-path guard on the same file this branch appends its reader-page tests to. Both are new tests and neither replaces the other, so the resolution keeps both. 136 pass. Underworld development team with AI support from Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A DOI click lands a reader on figshare's item page, which is a file browser: it
shows a PDF and a zip and asks which one you wanted. We cannot restyle that page.
What we can do is stop our links handing over a file when the reader wanted to
look at the document.
/<slug>/read/shows the archival PDF embedded, under the note's title,authors, date and DOI, with three buttons: Download PDF, Markdown source,
and Read on the site.
instead of at the file.
after-hydration approach as the comments — React owns the document and undoes
anything changed before it hydrates. Only anchors into the theme's
/build/export path are touched, so a PDF linked from an article's prose is untouched.
/<slug>/<slug>.mdto give that buttonsomething to point at.
Why our own copy rather than figshare's widget
Measured, not assumed:
ndownloader.figshare.com/files/<id>content-disposition: attachment,x-frame-options: SAMEORIGIN— cannot be framed here, only downloaded/<slug>/<slug>.pdf(ours)application/pdf, no disposition — renders inline, frames from our origin, no third-party script, works in a preview buildTests
The ordering is the part that is easy to lose in a one-line build task: the
reader page is only written where the PDF is already staged, so
stage_downloads.pymust run first — asserted for the build task and for thepreview path. Plus the page carrying both downloads, the way back, and a
noindex(the article stays canonical). 133 pass.Preview:
/<any-slug>/read/, e.g./running-underworld-in-a-browser/read/.Underworld development team with AI support from Claude Code