* Add tests on plurals
* Update `collabs_per_proj` and its pluralisations
* Update `n_user` and its pluralisations
* Update `showing_x_results` and its pluralisations
* Update `show_x_more_projects` and its pluralisations
* `bin/run web npm run extract-translations`
* Populate `_plural` keys in non-en locales
For 2-form languages (da, de, es, fi, fr, it, nl, no, pt, sv, tr), copy
the existing bare-key value into the new `_plural` sibling to prevent
i18next from falling back to English for count!=1.
Also remove orphan singular keys (`collabs_per_proj_single`,
`showing_1_result*`) left over from the previous commits.
Bare-key values remain in their original plural form pending translator
review — count=1 will still render the plural form in non-en until
translators flip those to singular. Multi-form (cs, pl, ru) and
single-form (ja, ko, zh-CN, zh-TW) locales are unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Flip non-en bare-key values to singular form
Per review, the i18next v3 plural convention uses the bare key for count=1
(singular) and `_plural` for count!=1. The non-en bare-key values were
left as the original plural form by the previous commit so the `_plural`
siblings could be copied from them; this commit flips the bare values to
the singular form per language.
Languages where singular and plural noun forms coincide (Finnish, Swedish,
Turkish) are unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Apply suggestions from code review
Co-authored-by: Olzhas Askar <olzhas.askar@gmail.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Olzhas Askar <olzhas.askar@gmail.com>
GitOrigin-RevId: 628513ca792c2dcce023247e52b7320e2741cc54
* move Review Toggle into the toolbar
* cleaning up and adding a comment
* adding the cursor styling
* adding isolation on writefull toolbar to adjust z-index of writefull toolbar
* fixing the dark mode colours for review dropdown trigger
* Fix review mode switcher dark mode styles
GitOrigin-RevId: 36847e0debdc4dce5f96492261d25e7cc46b2e96
The standalone-HTML export produced a non-self-contained file (no slide
CSS/JS, math or images when opened away from the server) because Quarto's
--metadata/-M flag uses KEY:VALUE (colon), not KEY=VALUE. '-M
embed-resources=true' silently registered a bogus key and left
embed-resources unset. Switch to colon syntax and also embed MathJax
(self-contained-math:true) so equations render offline.
For the slide PDF, add --disable-dev-shm-usage (the usual cause of
Chromium crashing inside a container with a small /dev/shm), and have the
export controller return the compile log as text/plain on failure so a
failed PDF export shows the real decktape/Chromium error instead of an
HTML page the browser saves as 'pdf.htm'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In RevealJS mode the download button becomes a 2-choice menu:
- Standalone HTML: a one-off compile with embed-resources (chalkboard and other
runtime-only plugins are dropped, since they don't survive self-containment),
yielding a single portable .html.
- Slide PDF: render the deck, then print it with decktape (headless Chromium)
to a faithful one-slide-per-page PDF.
Implementation:
- Dockerfile-base: install decktape + headless Chromium (open-source; deps via
playwright install-deps for Ubuntu-Noble correctness). Base-only change.
- QuartoRunner honours options.exportMode ('html-standalone' | 'pdf-slides');
exportMode is threaded web ClsiManager -> CLSI RequestParser -> CompileManager
-> runner.
- New GET /project/:id/presentation-export/:format compiles in the matching
export mode and streams the result as a download (PresentationExportController,
reusing ClsiManager.getOutputFileStream).
- pdf-hybrid-download-button shows the dropdown when the output is output.html;
PDF/LaTeX projects keep the single download button.
- i18n: download_as_standalone_html / download_as_pdf_slides (en + fr +
extracted-translations.json).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Deployment: set OVERLEAF_SITE_LANGUAGE=fr so the UI defaults to French.
- fr.json: add French translations for the Verso strings — blank_/example_
{quarto,latex,typst}_project, share_compiled_presentation(_info),
presentation_link_{members,private,public}, reset_link, and preview (which
was missing from fr.json). Other untranslated keys keep falling back to
English via the translations-loader.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The frontend bundles only the locale keys listed in
frontend/extracted-translations.json (a custom webpack translations-loader
filters en.json to that set, normally regenerated by i18next-scanner). Every
key added by hand to en.json without also adding it here renders as its raw
key — which is why "blank_quarto_project", "share_compiled_presentation", etc.
showed up literally in the New-project menu and Share dialog.
Add all introduced keys to extracted-translations.json: blank_/example_
{quarto,latex,typst}_project, share_compiled_presentation(_info),
presentation_link_{members,private,public}, reset_link.
Also enable anonymous read-AND-write share links (edit without an account) via
OVERLEAF_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING; read-only links already worked
through OVERLEAF_ALLOW_PUBLIC_ACCESS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a project-members-only link tier and independent link rotation.
- Three tokens per project instead of two: publicToken (anyone), loginToken
(any logged-in user), memberToken (only users who can read the project).
serve() resolves the token to its tier and enforces accordingly — 'member'
requires AuthorizationManager.canUserReadProject.
- New POST /project/:id/publish-presentation/regenerate { tier } rotates a
single tier's token (invalidating only that old link), leaving the snapshot
and the other links intact.
- Share dialog now shows three links (members / logged-in / anyone), each with
its own Copy and Reset buttons; Publish refreshes, Unpublish removes all.
Preview button opens the logged-in-users link.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The web service installs a site-wide login gate (router.mjs: webRouter.all('*',
requireGlobalLogin)) whenever Settings.allowPublicAccess is false — which it was,
since OVERLEAF_ALLOW_PUBLIC_ACCESS wasn't set. That gate bounced every anonymous
request to /login, breaking both Overleaf's own link-sharing and the public
presentation links (the dynamic token routes can't be in the exact-match
global whitelist, so there's no per-path exemption — allowPublicAccess is the
intended knob).
Set OVERLEAF_ALLOW_PUBLIC_ACCESS=true on the verso Deployment. Per-project and
per-route authorization still applies, and private presentation links still
require a login (enforced in the serve handler), so only genuinely public
content is reachable anonymously.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the single token + visibility toggle with two stable tokens per project
pointing at the same snapshot:
- publicToken → anyone with the link
- privateToken → any logged-in Verso user
This fixes both reported issues: changing visibility no longer mutates a link
(there's no toggle — both links always exist), and a public link can never
become private by accident. It also fixes public links redirecting to login:
access is now decided purely by which token was used (public token = open),
not a per-record flag.
- Model: storageId (snapshot dir) + publicToken + privateToken; drop token/
visibility.
- Manager.publish: mints both tokens once and reuses them on re-publish; serve
resolves a token to its record and treats the public token as open.
- Controller: returns { publicUrl, privateUrl }.
- Share dialog: shows the private and public links side by side, each with its
own copy button; Publish refreshes, Unpublish removes. Preview button opens
the private link.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A deck served at /p/:token (no trailing slash) made the browser resolve its
relative asset references (main_files/... CSS+JS) against /p/, 404ing them —
so the deck rendered as unstyled HTML with no reveal.js. Publish links now end
in a slash, and the bare /p/:token URL 301-redirects to /p/:token/, so relative
assets resolve under /p/:token/ and load correctly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The default published-presentations folder resolved to the app dir
(/overleaf/services/web/data/published), which isn't writable by the runtime
user → EACCES on publish. Point it at the Overleaf data volume in the
production config (Path.join(DATA_DIR, 'published') = /var/lib/overleaf/data/
published), alongside compiles/output, where the app user can write (and which
persists when a volume is mounted). Overridable via PUBLISHED_PRESENTATIONS_PATH.
CompileManager.compile debounces compiles via a Redis key set on every compile
(_checkIfRecentlyCompiled), returning {status:'too-recently-compiled',
outputFiles:[]} when the editor has just auto-compiled. Publishing called
compile() and then required output.html, so it threw "did not produce an HTML
presentation" — which is why Preview/Publish errored whenever the deck was
freshly compiled.
- CompileManager.compile: honour options.bypassRecentCompileCheck to skip the
debounce (still runs the normal autocompile-limit guards).
- PublishedPresentationManager: publish with bypassRecentCompileCheck, and put
the compile status in the error message for diagnosis.
- Controller: catch publish errors, log them, and return the message so the
Share dialog can show what went wrong instead of a generic error.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wires the two entry points to the publishing backend:
- Share dialog: a "Share compiled presentation" section (owner only) with a
public / logged-in-users-only choice, Publish/Unpublish, and a copyable link.
- Top-right toolbar: a "Preview" button that publishes a private (logged-in-
users-only) link in one click and opens the standalone deck in a new tab
(opened synchronously to dodge popup blockers).
Both talk to /project/:id/publish-presentation. Reuses existing i18n
(publish/unpublish/copy/preview); adds share_compiled_presentation(_info) and
presentation_link_public/private.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the engine + API for publishing a project's compiled HTML/RevealJS deck as
a stable, standalone snapshot served at /p/:token, independent of the editor.
- PublishedPresentation model: one per project { token, visibility, buildId },
re-publishing keeps the same token so shared links stay stable.
- Manager.publish: compiles the project, then copies the HTML deck + its _files
assets + referenced media (now included thanks to the OutputFileFinder fix)
into a persistent snapshot dir (Settings.path.publishedPresentationsFolder,
override with PUBLISHED_PRESENTATIONS_PATH). Logs/aux are excluded.
- Routes: GET/POST/DELETE /project/:id/publish-presentation (owner/reader) for
status/publish/unpublish; public GET /p/:token(/*) serves the deck full-page.
Visibility is enforced in the handler: 'public' = anonymous, 'private' = any
logged-in Verso user. CSP is dropped on these responses so reveal.js renders.
Frontend entry points (share-modal section + top-right Preview button) follow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OutputFileFinder excluded all incoming project resources from the output set,
and OutputCacheManager only copies outputs into the served build dir. For PDF
that's fine (media is embedded), but for HTML/RevealJS the browser fetches
images/videos/fonts from the output path at runtime — so a deck's referenced
image (a project input file) was never served and rendered broken in the
preview.
When the compile produced output.html, keep media inputs (img/video/audio/font
extensions) in the output set so they're served alongside the deck. PDF/LaTeX
compiles are unaffected. This also makes referenced media land in output.zip,
which the upcoming presentation-publishing feature relies on.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Since we dropped --embed-resources (so RevealJS plugins like chalkboard work),
pandoc no longer tries to fetch referenced media for HTML output, so a missing
image or video produces no compile-time warning — it only renders broken in the
browser. PDF/Typst output is unaffected because Typst hard-errors on a missing
image.
After an HTML render, QuartoRunner now scans output.html for local media
references (img/video/audio/iframe src, poster, RevealJS data-background-*) and
appends a `[WARNING] Missing resource: …` line to output.log for any that don't
exist on disk. External URLs, data URIs, anchors and Quarto's own generated
<basename>_files assets are ignored. The [WARNING] prefix is recognised by the
Quarto/Typst log parser, so these show up in the Warnings tab.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Project.compiler defaults to settings.defaultLatexCompiler ('quarto' in this
fork), so every .tex project carried compiler='quarto'. Since the CLSI runner
is chosen by file extension, a .tex root still goes to LatexRunner, whose
_buildLatexCommand threw `unknown compiler: quarto` — surfacing as an opaque
HTTP 500 with no compile log.
- LatexRunner: fall back to pdfLaTeX when the compiler isn't a known TeX engine
instead of throwing. Universal safety net (covers existing projects, uploads
and GitHub imports already saved with compiler='quarto').
- ProjectCreationHandler: store a sensible compiler per flavour at creation via
a shared _flavourConfig helper — blank/example LaTeX → 'pdflatex',
Typst → 'typst', Quarto → 'quarto' — so the compiler dropdown reflects the
engine and LatexRunner receives a valid one directly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A project whose root file is a .typ file now compiles straight to PDF with
Typst, as a third engine beside Quarto (.qmd) and latexmk (.tex). Dispatch
stays purely extension-based.
CLSI:
- New TypstRunner.js: runs `quarto typst compile <main>.typ output.pdf` (reuses
the Typst bundled in Quarto, so no extra binary / Docker change). stderr is
merged into output.log.
- CompileManager: _isTypstFile + a TypstRunner branch in _getRunner, and
TypstRunner added to the isRunning check and stopCompile kill list.
- RequestParser: 'typst' added to VALID_COMPILERS.
web:
- settings.defaults: 'typ' added to validRootDocExtensions and the text
extensions (so .typ opens in the editor); 'typst' added to safeCompilers.
- output-files: the Quarto/Typst log parser (which already understands Typst
`error:`/`warning:` + `┌─ file:line:col` diagnostics) now also handles .typ
compiles, so their errors/warnings populate the log tabs.
Polish:
- New-project menu: "Blank Typst project" + "Example Typst project" in both the
main and welcome dropdowns, backed by createBasicProject/createExampleProject
flavour 'typst', a new mainbasic.typ template and an example-project-typst
presentation (math, an image, a table, lists).
- Compiler dropdown gains a "Typst" option (cosmetic; dispatch is by extension).
README updated: three compilers side by side, with a Writing-a-Typst-document
section.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the generic "Blank project" / "Example project" entries with four
flavour-specific ones in both the New-project dropdown and the welcome-screen
dropdown:
- Blank Quarto project -> empty main.qmd (format: typst)
- Blank LaTeX project -> empty main.tex
- Example Quarto project -> a Reveal.js presentation showcasing images, math,
a table, code and incremental lists (new template
project_files/example-project-quarto/)
- Example LaTeX project -> the existing LaTeX example
Backend: ProjectController.newProject now dispatches the `template` value
(blank_quarto/blank_latex/example_quarto/example_latex, plus the legacy
'example'/'none') to createBasicProject(flavour) / createExampleProject(flavour).
_createRootDoc takes a root-doc name so each flavour gets the right extension —
this also fixes the LaTeX example, whose root doc was wrongly created as
main.qmd, back to main.tex (matching the acceptance test). Signatures stay
backward compatible (flavour defaults: blank=quarto, example=latex).
Also refresh the README: Verso now runs Quarto and LaTeX side by side
(engine chosen by root-file extension), not Quarto instead of LaTeX.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The $accent knob caught primary buttons, but several places still
referenced the green ramp directly as a brand-accent colour (rather than
genuine success semantics). Repoint those at the --bg-accent-* tokens so
they too follow the single $accent knob:
- navbar Sign in / Register ("primary" + subdued/link hover) buttons
- file-tree selected-item highlight and drag background (IDE redesign,
light and dark)
- document-outline highlighted item (IDE redesign, light and dark)
- the Visual/Code editor-switcher button mixin
- web/content hyperlinks (--link-web*), e.g. on the project dashboard;
dark-theme variants point at the blue ramp to stay readable on dark
Genuine success/positive greens (notification success icon,
$content-positive, beta badges, etc.) are deliberately left green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two build-speed changes to the Gitea Actions deploy workflow.
(#1) Build the base image only when it changes. The base layers' only
repo input is server-ce/Dockerfile-base, so the prepare step hashes that
file and the base is tagged verso-base:base-<hash>; the app builds FROM
that exact tag. If a base with the current hash already exists in the
registry, the heavy base build (apt ~111s, TeX Live ~51s, Quarto, plus
its ~49s export/push) is skipped entirely — which is every commit that
doesn't touch Dockerfile-base.
(#2) Import/export a registry-backed layer cache (verso-cache:base and
verso-cache:app, mode=max) on both builds. Unchanged layers are reused
instead of rebuilt: yarn install is skipped when package.json is
unchanged, and only the web compile re-runs on a frontend source change.
No new cluster resources — the cache lives as extra tags in the same
in-cluster registry.
First run after this is still a full build (populates the caches and the
hash-tagged base); subsequent commits should be substantially faster.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quarto compiles (.qmd/.md/.Rmd, dispatched to QuartoRunner) write
Typst/Pandoc/Quarto diagnostics to output.log that the LaTeX log parser
does not understand, so the Errors/Warnings tabs stayed empty. Add a
dedicated quarto-log-parser that recognises Typst `error:`/`warning:`
(+ `┌─ file:line:col`), Pandoc `[WARNING]`/`[ERROR]`, Quarto CLI/Deno
`ERROR:`/`WARNING:`, and knitr `Quitting from lines`. handleLogFiles now
routes to it when the root file is a Quarto file (mirrors CLSI dispatch),
otherwise the LaTeX path is unchanged.
Also decouple the UI accent from the green ramp. The framework already
funnels every primary/accent surface (primary buttons, Bootstrap
$primary/$success, --btn-primary-background) through the --bg-accent-*
tokens; those just happened to point at Overleaf green. Introduce a
single $accent knob in foundations/colors.scss (with auto-derived
hover/tint shades) and repoint the accent tokens at it, defaulting to
the Verso/Quarto blue. Re-skinning the whole UI is now a one-line edit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two HTML/RevealJS preview fixes:
1. Stop passing --embed-resources to quarto render. A self-contained
single-file HTML breaks reveal.js plugins that load/store resources at
runtime (chalkboard, multiplex) and is slow to transfer. Quarto now
emits the HTML plus a sibling "<basename>_files/" asset dir referenced
by relative paths; both are served from the same .../output/ path
(nginx output/(.+) and web :file(.*) both capture slashes), so the
relative links resolve. The renamed output.html still points at the
unchanged "<basename>_files" dir. This also fixes the slow-load issue,
since assets now load on demand instead of one giant inlined file.
2. On a failed compile that follows a successful one, the previous deck
stayed in the iframe, making the failure look like a success. We now
clear pdfFile when a non-success status carries a stale output.html.
The last-good-PDF-beside-the-error behaviour is preserved for PDF
output (only output.html is dropped).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two fixes to the Markdown/Quarto file outline:
1. The last frontmatter line (e.g. `format: typst`) appeared as a
heading. The Lezer Markdown grammar has no frontmatter support, so it
reads the closing `---` of the YAML block as a Setext underline and
promotes the line above it to a heading. Detect the leading
`---`...`---`/`...` block and skip any heading inside it.
2. Pandoc/Quarto attribute blocks were shown in titles, e.g.
`## Slide {.smaller auto-animate="true"}`. Strip a trailing `{...}`
from the extracted title.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The outline entries showed up at the right lines and jumped correctly,
but their titles were blank. The text-extraction walked the heading
node's children and collected non-HeaderMark child text — but in the
Lezer Markdown grammar a heading has NO child node for its text; the
only children are the HeaderMark nodes. The title text lives in the
gaps between marks, so the walk collected nothing.
Slice the whole heading's source instead and strip the markers:
leading/trailing '#'s for ATX headings and the '==='/'---' underline
for Setext headings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reverts the heavy multi-collection texlive install back toward the
original upstream-Overleaf approach: install-tl with scheme-basic
(~300 MB) plus latexmk and texcount via tlmgr, no docfiles/srcfiles.
This restores the fast, small base image we had before LaTeX support
was added in full.
Tradeoff: documents needing tikz/beamer/siunitx/extra fonts won't
compile out of the box for now — those should stay in Quarto/Typst
until the project is mature enough to justify a full TeX Live.
Made deliberately easy to reverse: a header comment documents that
switching scheme-basic -> scheme-full (one line) restores the complete
toolchain, or individual packages can be appended to the tlmgr list.
Uses TEXDIR=/usr/local/texlive (unversioned) so PATH stays stable
across TeX Live releases.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous install expanded texlive-full (minus -doc/-lang-), pulling in
essentially every CTAN package plus inkscape's large GTK GUI tree — ~20 min
and several GB. Replace it with a curated set of meta-packages that covers
the vast majority of documents: latex base/recommended/extra, recommended
fonts, plain-generic, science (math/physics), xetex, luatex, bibtex-extra,
extra-utils (texcount), plus latexmk/biber/chktex/pygments.
Smaller and faster to build. Documents needing an omitted package can have
the relevant texlive-* collection added back. Drops inkscape (only used for
auto SVG->PDF conversion) to avoid its heavy GUI dependency chain.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The cluster nodes' containerd can only pull from registry.alocoq.fr, not
the in-cluster service name. Keep pushing via the in-cluster address (to
bypass the Traefik upload-timeout), but reference registry.alocoq.fr/verso
in the test Deployment and the rolling update. Both addresses front the
same registry storage, so the pushed image resolves at the public name.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous approach created a verso-buildkitd-config ConfigMap, but the
workflow's RBAC does not permit creating new cluster resources. Write the
buildkitd.toml (marking the in-cluster registry as http/insecure) directly
inside the buildkit container at runtime via printf, and drop the configMap
volume/mount. No new k8s resources are created.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The TeX Live layer (~3.5 GB) failed to push to registry.alocoq.fr:
Traefik severed the upload mid-stream ("client disconnected during blob
PUT ... unexpected EOF"), buildkit retried at the wrong offset, and the
registry returned "blob upload invalid".
Push to the in-cluster registry Service (registry.git.svc.cluster.local:5000)
instead, so the upload never traverses Traefik. Changes:
- buildctl outputs use registry.insecure=true (registry is plain HTTP)
- add a verso-buildkitd-config ConfigMap with buildkitd.toml marking the
registry http/insecure, so the second build can pull the base image back
- the verso Deployment and rolling update reference the in-cluster image
NOTE: the cluster nodes' containerd must also treat
registry.git.svc.cluster.local:5000 as an insecure registry, otherwise
the kubelet image pull for the test deployment will fail. That is node-
level config outside this repo.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The base image build failed with "E: Unable to locate package texcount".
texcount ships inside texlive-extra-utils, not as its own apt package.
Replace the bogus texcount entry with texlive-extra-utils (which provides
both texcount and latexmk). latexmk is kept explicit for clarity.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both limits that gate uploads are bumped in tandem so they don't conflict:
- settings.defaults.js maxUploadSize: 50 MB → 500 MB (app-level check)
- nginx.conf.template client_max_body_size: 50m → 500m (proxy body limit)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verso now compiles both .tex (latexmk) and .qmd (Quarto) projects,
dispatching by the root file's extension rather than replacing one with
the other. LaTeX and Quarto projects can coexist on the same server.
CompileManager: re-import LatexRunner and add a _getRunner() dispatcher
that returns a uniform {run, isRunning, kill} interface. .qmd/.md/.Rmd
→ QuartoRunner; everything else (.tex/.ltx/.Rtex/.Rnw) → LatexRunner.
stopCompile now checks/kills both runners since it has no root path.
compiler-setting.tsx: restore the LaTeX engine choices (pdfLaTeX, LaTeX,
XeLaTeX, LuaLaTeX) alongside Quarto. The dropdown still controls which
TeX engine latexmk uses; actual engine dispatch is by file extension.
Dockerfile-base: reinstall TeX Live alongside Quarto (texlive-full minus
-doc/-lang- packages, plus xetex/luatex/biber/latexmk/texcount/chktex/
synctex). Restore TEXMFVAR for a writable LuaTeX cache. This brings back
a large image, which is the accepted cost of full LaTeX+Quarto support.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RevealJS presentations are served as (currently embed-resources) HTML that
went over the wire uncompressed, because gzip_types only listed text/plain.
This made the HTML preview slow to load for heavy decks.
Add text/html, text/css, application/javascript, application/json and
image/svg+xml to gzip_types so the text-based portion of the output is
compressed. Already-compressed formats (pdf, png/jpeg/webp, woff/woff2)
are intentionally excluded to avoid wasting CPU. Also set gzip_min_length
1024 so tiny responses aren't compressed needlessly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dockerfile-base: after Quarto is installed, run 'quarto add --no-prompt'
for a curated set of extensions into /opt/quarto-extensions/. Quarto
writes _extensions/<author>/<name>/ in the working dir, giving us a
clean shared store. Extensions included:
- igorlima/charged-ieee — IEEE paper format (Typst)
- quarto-ext/fontawesome — Font Awesome icons
- quarto-ext/attribution — attribution footer on RevealJS slides
- quarto-ext/pointer — laser pointer for presentations
- quarto-ext/drop — drop-down overlay for RevealJS
Adding more: one extra '&& quarto add --no-prompt <author>/<repo>' line.
QuartoRunner: before quarto render, merge /opt/quarto-extensions/_extensions/
into the compile dir's _extensions/ with 'cp -rn' (no-clobber). This
makes all pre-installed extensions available to every project without
any user action. Project-uploaded _extensions/ files take precedence
since cp -n never overwrites existing files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>