From eb849651dab500531c4441a9b6a3f82d11644803 Mon Sep 17 00:00:00 2001 From: Lukas Hirt Date: Thu, 17 Sep 2026 15:06:45 +0200 Subject: [PATCH 1/3] feat: re-add mediumzoom as a tracked npm dependency The previous vendored copy of medium-zoom.min.js was reverted (#131) for missing dependency management. Install medium-zoom via npm so it is tracked in package.json/package-lock.json (and covered by Dependabot), and copy its prebuilt browser bundle into ui/supplemental/js/vendor/ via a preantora/preantora-local script, since the site has no client-side bundler of its own. Signed-off-by: Lukas Hirt --- .gitignore | 4 ++++ package-lock.json | 9 ++++++++- package.json | 5 ++++- scripts/sync-vendor-assets.js | 19 +++++++++++++++++++ ui/supplemental/css/medium-zoom.css | 10 ++++++++++ ui/supplemental/js/medium-zoom-init.js | 19 +++++++++++++++++++ ui/supplemental/partials/footer-scripts.hbs | 5 +++++ ui/supplemental/partials/head-styles.hbs | 1 + 8 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 scripts/sync-vendor-assets.js create mode 100644 ui/supplemental/css/medium-zoom.css create mode 100644 ui/supplemental/js/medium-zoom-init.js diff --git a/.gitignore b/.gitignore index 444527a..e934dac 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,10 @@ public/ _import/ docs/superpowers/ +# synced from node_modules/medium-zoom by scripts/sync-vendor-assets.js +# (see the preantora/preantora-local npm scripts) +ui/supplemental/js/vendor/ + # macOS and IDEs .DS_Store .vscode/ diff --git a/package-lock.json b/package-lock.json index 00e7083..cc6b920 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "antora": "^3.2.0", "asciidoctor": "^4.0.11", "asciidoctor-kroki": "^1.0.1", - "js-yaml": "^5.4.1" + "js-yaml": "^5.4.1", + "medium-zoom": "^1.1.0" }, "devDependencies": { "@sntke/antora-mermaid-extension": "^0.0.13", @@ -1476,6 +1477,12 @@ "node": ">= 0.4" } }, + "node_modules/medium-zoom": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.1.0.tgz", + "integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", diff --git a/package.json b/package.json index 213a16b..881d5ea 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "homepage": "https://github.com/owncloud/docs.owncloud.com#readme", "license": "AGPL-3.0-or-later", "scripts": { + "preantora": "node scripts/sync-vendor-assets.js", "antora": "antora --stacktrace site.yml", + "preantora-local": "node scripts/sync-vendor-assets.js", "antora-local": "antora --stacktrace --url http://localhost:8080 site.yml", "pagefind": "pagefind --site public", "build": "npm run antora && npm run pagefind", @@ -15,7 +17,8 @@ "antora": "^3.2.0", "asciidoctor": "^4.0.11", "asciidoctor-kroki": "^1.0.1", - "js-yaml": "^5.4.1" + "js-yaml": "^5.4.1", + "medium-zoom": "^1.1.0" }, "devDependencies": { "@sntke/antora-mermaid-extension": "^0.0.13", diff --git a/scripts/sync-vendor-assets.js b/scripts/sync-vendor-assets.js new file mode 100644 index 0000000..c59fff8 --- /dev/null +++ b/scripts/sync-vendor-assets.js @@ -0,0 +1,19 @@ +'use strict' + +// Copies the medium-zoom browser bundle out of node_modules into the Antora UI +// supplemental tree. ui/supplemental is layered onto the stock UI bundle as +// plain files (site.yml ui.supplemental_files) -- there is no bundler step of +// our own -- so a real npm dependency (tracked in package.json/package-lock.json, +// and by Dependabot) still needs its browser build placed on disk before Antora +// runs. Wired up as `preantora`/`preantora-local` in package.json. + +const fs = require('node:fs') +const path = require('node:path') + +const ROOT = path.join(__dirname, '..') +const PKG_DIR = path.join(ROOT, 'node_modules/medium-zoom') +const VENDOR_DIR = path.join(ROOT, 'ui/supplemental/js/vendor') + +fs.mkdirSync(VENDOR_DIR, { recursive: true }) +fs.copyFileSync(path.join(PKG_DIR, 'dist/medium-zoom.min.js'), path.join(VENDOR_DIR, 'medium-zoom.min.js')) +fs.copyFileSync(path.join(PKG_DIR, 'LICENSE'), path.join(VENDOR_DIR, 'LICENSE-medium-zoom.txt')) diff --git a/ui/supplemental/css/medium-zoom.css b/ui/supplemental/css/medium-zoom.css new file mode 100644 index 0000000..b7c36d6 --- /dev/null +++ b/ui/supplemental/css/medium-zoom.css @@ -0,0 +1,10 @@ +/* + * medium-zoom (js/vendor/medium-zoom.min.js) injects its own stylesheet for the + * overlay and the zoom transition, but that stylesheet sets no stacking order. + * The stock Antora default UI goes up to z-index 4 (navbar, toolbar), so without + * this the navbar would sit on top of the zoomed image and its backdrop. + */ +.medium-zoom-overlay, +img.medium-zoom-image { + z-index: 1000; +} diff --git a/ui/supplemental/js/medium-zoom-init.js b/ui/supplemental/js/medium-zoom-init.js new file mode 100644 index 0000000..11c5349 --- /dev/null +++ b/ui/supplemental/js/medium-zoom-init.js @@ -0,0 +1,19 @@ +/* + * Click-to-zoom for images, restoring the behavior the retired custom UI + * (docs-ui) provided via its webpack-bundled `js/vendor/medium-zoom.js`. + * + * Binds medium-zoom to every image Asciidoctor emits: + * span.image img -- inline images (`image:file[]`) + * div.imageblock img -- block images (`image::file[]`), including svg + * With that, no `role` or attribute is needed in the page source: all images + * are zoomable. + * + * Loaded with `defer` after js/vendor/medium-zoom.min.js so the global is in + * place -- deferred external scripts execute in document order. + */ +;(function () { + 'use strict' + + if (typeof window.mediumZoom !== 'function') return + window.mediumZoom('span.image img, div.imageblock img', { background: '#fff', margin: 10 }) +})() diff --git a/ui/supplemental/partials/footer-scripts.hbs b/ui/supplemental/partials/footer-scripts.hbs index a394ab1..a26ba3d 100644 --- a/ui/supplemental/partials/footer-scripts.hbs +++ b/ui/supplemental/partials/footer-scripts.hbs @@ -6,3 +6,8 @@ {{!-- Companion behavior for the AsciiDoc tabs extension (asciidoc-extensions/tabs.js): removes the is-loading fallback and wires tab switching. --}} +{{!-- Click-to-zoom for images. `defer` on both (not `async`) because the init + script needs the global the vendored library defines, and deferred external + scripts run in document order. --}} + + diff --git a/ui/supplemental/partials/head-styles.hbs b/ui/supplemental/partials/head-styles.hbs index 81a5081..36d97e8 100644 --- a/ui/supplemental/partials/head-styles.hbs +++ b/ui/supplemental/partials/head-styles.hbs @@ -2,3 +2,4 @@ + From b44557da69758574502a59d865dbc1c2e4984c50 Mon Sep 17 00:00:00 2001 From: Lukas Hirt Date: Thu, 17 Sep 2026 15:09:18 +0200 Subject: [PATCH 2/3] refactor: make sync-vendor-assets.js data-driven Replace the two hardcoded copyFileSync calls with a VENDOR_FILES list, so vendoring another package's browser build later means adding an entry instead of writing a new script. Signed-off-by: Lukas Hirt --- scripts/sync-vendor-assets.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/scripts/sync-vendor-assets.js b/scripts/sync-vendor-assets.js index c59fff8..7d6de42 100644 --- a/scripts/sync-vendor-assets.js +++ b/scripts/sync-vendor-assets.js @@ -1,19 +1,27 @@ 'use strict' -// Copies the medium-zoom browser bundle out of node_modules into the Antora UI +// Copies prebuilt browser bundles out of node_modules into the Antora UI // supplemental tree. ui/supplemental is layered onto the stock UI bundle as // plain files (site.yml ui.supplemental_files) -- there is no bundler step of -// our own -- so a real npm dependency (tracked in package.json/package-lock.json, -// and by Dependabot) still needs its browser build placed on disk before Antora -// runs. Wired up as `preantora`/`preantora-local` in package.json. +// our own -- so real npm dependencies (tracked in package.json/package-lock.json, +// and by Dependabot) still need their browser build placed on disk before +// Antora runs. Wired up as `preantora`/`preantora-local` in package.json. +// +// To vendor another package's browser build the same way, add an entry below +// rather than writing a new script. +const VENDOR_FILES = [ + { package: 'medium-zoom', src: 'dist/medium-zoom.min.js', dest: 'js/vendor/medium-zoom.min.js' }, + { package: 'medium-zoom', src: 'LICENSE', dest: 'js/vendor/LICENSE-medium-zoom.txt' }, +] const fs = require('node:fs') const path = require('node:path') const ROOT = path.join(__dirname, '..') -const PKG_DIR = path.join(ROOT, 'node_modules/medium-zoom') -const VENDOR_DIR = path.join(ROOT, 'ui/supplemental/js/vendor') -fs.mkdirSync(VENDOR_DIR, { recursive: true }) -fs.copyFileSync(path.join(PKG_DIR, 'dist/medium-zoom.min.js'), path.join(VENDOR_DIR, 'medium-zoom.min.js')) -fs.copyFileSync(path.join(PKG_DIR, 'LICENSE'), path.join(VENDOR_DIR, 'LICENSE-medium-zoom.txt')) +for (const { package: pkg, src, dest } of VENDOR_FILES) { + const from = path.join(ROOT, 'node_modules', pkg, src) + const to = path.join(ROOT, 'ui/supplemental', dest) + fs.mkdirSync(path.dirname(to), { recursive: true }) + fs.copyFileSync(from, to) +} From 182103c16896f2a07c1e03353b9c13e5491c1aa3 Mon Sep 17 00:00:00 2001 From: Lukas Hirt Date: Thu, 17 Sep 2026 19:51:15 +0200 Subject: [PATCH 3/3] fix: address review on the medium-zoom vendoring approach - Add a build-output guard (extension-tests/static-files.test.js) that fails loudly if ui/supplemental/js/vendor/ wasn't repopulated before the build (e.g. npx antora run directly, bypassing the preantora hook): today it publishes green with a 404'ing