24966 Commits

Author SHA1 Message Date
claude 2385166213 Dashboard footer fix, larger version text, rewrite README
Build and Deploy Verso / deploy (push) Successful in 9m47s
- Fix the projects dashboard footer needing a scroll to reach: the main area
  used min-height: 100% which always pushed the footer a full screen down.
  Lay the content out as a flex column with main growing (flex: 1 0 auto), so
  the footer sticks to the bottom of the viewport when the list is short.
- Bump the instance-name/version text to ~33px ('7.5', between font-size-07
  and -08).
- Rewrite README to match the current triple-compiler product (Quarto + LaTeX
  + Typst), the editor language support, format badge, publishing flow and
  Python venv option; drop the stale 'Quarto-only / TeX Live removed' notes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 10:31:49 +00:00
claude fddb141d19 Polish: smaller version text, bigger loader logo, keep RevealJS slide on recompile
Build and Deploy Verso / deploy (push) Successful in 9m35s
- Reduce the dashboard instance-name/version font size (07 -> 06).
- Enlarge the Verso logo in the loading animation (160px -> 240px).
- Preserve the current RevealJS slide across recompiles: capture the deck's
  URL hash (same-origin) and re-append it to the iframe src so the new build
  reopens on the same slide instead of jumping to the start.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 09:10:33 +00:00
claude 8272d6de88 Editor/dashboard polish: PDF publish, Typst outline, bigger branding
Build and Deploy Verso / deploy (push) Successful in 9m29s
- Hide the Present button when the current output is a PDF (it only makes
  sense for HTML/RevealJS decks).
- Publish now supports PDF projects: snapshot output.pdf and serve it inline
  via a small index.html wrapper at /p/:token, so link holders can view the
  PDF straight from the published version.
- Add a Typst document outline (scans '=' headings) wired into the file
  outline panel.
- Dashboard branding: enlarge the instance-name/version text and let the
  sidebar Verso wordmark span the full column width.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 08:33:56 +00:00
claude 4fc86ebd3d Editor: qmd/typst autocomplete, format column, compiler gating, Verso loader
Build and Deploy Verso / deploy (push) Successful in 9m48s
- Add a Typst language (stream highlighting + completions) for .typ, and
  Quarto completions (code chunks, callouts, cross-refs) for .qmd/markdown.
- Project dashboard: new Format column (Quarto/Typst/LaTeX) from the cheap
  project compiler field, surfaced through the projects list API.
- Compiler dropdown: grey out engines that don't match the root file's
  extension (.qmd->Quarto, .typ->Typst, .tex->LaTeX engines).
- Replace the Overleaf fill loader with an animated Verso logo: the four
  quadrant circles drift on their own orbits while colour warms up with load
  progress; reused on the token-access screen too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 07:47:31 +00:00
claude 12cabd1d1b Branding: build-number version, EB Garamond title, blue filters, Present button
Build and Deploy Verso / deploy (push) Successful in 9m21s
- Instance name: stamp the nav title with the build number at deploy time
  ("Verso V0.<run> alpha") via a sed placeholder fed by GITHUB_RUN_NUMBER,
  instead of the static "Verso V1.0 Alpha".

- Title typeface: self-host the EB Garamond latin subset (same one embedded in
  the logo SVGs) and apply it to .navbar-title so the instance name matches the
  Verso wordmark.

- Sidebar wordmark: let the logo fill the full sidebar column width (drop the
  160px cap).

- Project filters: switch the ds-nav active state (filter selection + theme
  toggle) from the green tokens to the blue scale, matching the rail.

- Present button: rename the presentation toolbar action from "Preview" to
  "Present" / "Présenter" and add a tooltip explaining it publishes the
  presentation and opens it in a new tab. New keys present /
  present_publishes_and_opens_in_new_tab in en, fr and extracted-translations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:32:07 +00:00
claude 676663ffcc Branding polish: blue rail accent, drop fork link, bigger login logo, dashboard logo placement
Build and Deploy Verso / deploy (push) Successful in 9m41s
- Editor rail: the active item used the Overleaf green accent. Switch
  --ide-rail-link-active-color/background to the blue scale (--blue-10/70,
  --bg-info-03) to match the Verso palette.

- Footers: remove the default "Fork on GitHub!" right_footer item (redundant
  with the "Built on Overleaf" link); right_footer now defaults to [].

- Login: move the hero wordmark into a full-width centered block and bump it to
  max-width 480px so it's no longer constrained by the form column.

- Projects dashboard: restore the instance name in the top-left navbar (set
  OVERLEAF_NAV_TITLE="Verso V1.0 Alpha") instead of the wordmark logo, and move
  the full Verso wordmark to the sidebar's lower section (where the old
  "Digital Science" mark sat). Revert HeaderLogoOrTitle to its title-first
  behaviour now that the dashboard no longer passes a logo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 21:28:50 +00:00
claude 7d5deebfce Fix Python-packages toolbar icon: add deployed_code to unfilled font subset
Build and Deploy Verso / deploy (push) Successful in 9m35s
The file-tree "Python packages" button rendered the literal text
"deployed_code" in the icon font because that glyph was missing from the
outlined/unfilled Material Symbols subset (MaterialSymbolsRoundedUnfilledPartialSlice.woff2),
so the ligature never resolved. The toolbar buttons all use the unfilled
variant, so switching this one to the full filled font would look inconsistent.

Add 'deployed_code' to unfilled-symbols.mjs and regenerate the subset woff2
(same Google Fonts request build-unfilled.mjs makes) so the box/package icon
renders, matching the other outlined toolbar icons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 21:06:55 +00:00
claude 7a50f42e02 Restore dashboard footer; show navbar logo over title; enlarge login logo
Build and Deploy Verso / deploy (push) Successful in 9m46s
Three follow-ups after the visual-identity deploy:

- Footer: restore the React <Footer> on the projects dashboard (both
  ProjectListDsNav and the legacy DefaultNavbarAndFooter). Removing it earlier
  was an overcorrection — it now renders the Verso/AGPL thin footer rather than
  the old "Powered by Overleaf" line. Other pages already kept the pug footer.

- Navbar brand: HeaderLogoOrTitle previously hid the logo whenever a nav title
  was set, so on the dashboard only the "Verso" instance-name text showed and
  the wired-up Verso logo never appeared. Make a configured logo (custom logo
  or the Verso brand logo) take precedence over the title text; fall back to the
  title only when no logo is provided (unchanged for other navbars).

- Login: enlarge the hero wordmark (max-width 260px -> 380px, full column width).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 20:41:18 +00:00
claude 2eccfe7f75 Add Verso visual identity (logos + favicon)
Build and Deploy Verso / deploy (push) Has been cancelled
Introduce the Verso brand marks as self-contained SVGs with the EB Garamond
latin subset embedded as a base64 @font-face, so they render identically in
every context (favicon, CSS background, <img>, inline) with no runtime Google
Fonts dependency — important for the self-hosted alpha. Falls back to Georgia
serif if a browser ignores SVG-embedded fonts.

Assets:
- verso-square.svg  — rounded "V" tile (200×200); used as favicon.svg and the
  editor top-left toolbar logo.
- verso-logo.svg / verso-logo-dark.svg — wide "verso · ONLINE EDITOR" wordmark
  (760×200), light + dark wordmark variants.

Wiring:
- favicon: public/favicon.svg replaced with the square mark.
- editor toolbar: --redesign-toolbar-logo-url (light + dark) -> verso-square.svg.
- projects dashboard navbar: ProjectListDsNav logo -> verso-logo(.dark), with
  --navbar-brand-width widened to 200px to fit the wide wordmark.
- login page: centered Verso wordmark above the form; suppress the top navbar
  so the hero logo stands alone (no competing Overleaf mark).

PNG favicons / apple-touch-icon are left as-is (no raster tooling available);
modern browsers use the SVG favicon.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 19:43:36 +00:00
claude 7670982f60 Dashboard: drop footer + Digital Science branding; Verso-ify React thin footer
Build and Deploy Verso / deploy (push) Successful in 9m47s
The project dashboard ("main menu") rendered the React <Footer> (ThinFooter)
at the bottom of the page, which forced a page-level scrollbar just to reach a
stale "© 2025 Powered by Overleaf" line. Remove <Footer> from both dashboard
variants (ProjectListDsNav and the legacy DefaultNavbarAndFooter) so the main
menu has no footer and no useless scroll. The login/auth pages keep the Verso
attribution footer (thin-footer.pug), which already satisfies the AGPL source
link requirement.

Also remove the hardcoded "Digital Science" marking from the dashboard sidebar
lower section, and update the React ThinFooter (used by other React pages such
as settings/subscription) to match the pug footer: © <year> Aloïs Coquillard ·
Built on Overleaf, with AGPL licence + source-code links on the right, instead
of "Powered by Overleaf".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 19:13:19 +00:00
claude f50d6cb053 Footer: put Verso/AGPL attribution in the rendered thin-footer
Build and Deploy Verso / deploy (push) Successful in 9m41s
The login (and other CE) pages render layout/thin-footer, not
fat-footer-website-redesign, because showThinFooter = !hasFeature('saas')
is true in Community Edition. The earlier footer edit therefore never
showed. Replace the static "© 2025 Built on Overleaf" line with the
Verso attribution (© <year> Aloïs Coquillard · Built on Overleaf) and
add an AGPL licence + source-code link group on the right, keeping the
language picker and custom nav items intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 17:42:06 +00:00
claude 2e657e51d6 Replace marketing footer with Verso attribution/AGPL footer
Swap the Overleaf marketing footer (careers, pricing, 'for universities', …)
shown on the login and other auth pages for a clean Verso footer: copyright
(Aloïs Coquillard -> alocoq.fr), 'Built on Overleaf' (-> Overleaf repo), and on
the right the AGPL licence (-> repo LICENSE) and Source code (-> the Gitea
repo). This also satisfies the AGPL source-offer on the public domain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 15:06:27 +00:00
claude 4c13d139f6 Share modal: 'Add collaborators' heading; fix French 404 title
Build and Deploy Verso / deploy (push) Has been cancelled
Add an 'Add collaborators' heading above the email-invite section in the share
modal so it's visually distinct from the presentation-sharing section.

Add the missing French 'not_found' key so the 404 page shows 'Introuvable'
instead of the raw 'not_found' (the 404 pug template translates server-side;
the key existed in en.json but not fr.json).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 14:36:33 +00:00
claude 405c1d27c9 Bundle Python requirements into a dedicated editor; hide requirements.vrf
Add a 'Python packages' button to the file-tree toolbar that opens a modal to
edit the project's requirements.vrf (one package per line, pip syntax), backed
by GET/POST /project/:id/python-requirements (read via ProjectEntityHandler,
write via EditorController.upsertDocWithPath, write-gated). The .vrf file is now
hidden from the file tree, so it is managed only through this editor rather than
appearing as a loose file. Adds python_packages / python_packages_help i18n.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 14:26:03 +00:00
claude c9727a26e4 Python deps: smart missing-package hint + switch to .vrf requirements file
Build and Deploy Verso / deploy (push) Successful in 9m46s
Option A: when a {python} cell fails with ModuleNotFoundError/ImportError, the
log now suggests the exact PyPI package to add (with a module->package map, e.g.
cv2 -> opencv-python, sklearn -> scikit-learn), names the Verso requirements
file, and notes it could instead be a local module — so the langmuirthermalstudy
case isn't mistaken for a PyPI package.

Switch the per-project requirements file from requirements.txt to a Verso-
specific requirements.vrf (so it won't be confused with arbitrary .txt files);
QuartoRunner now looks for requirements.vrf, and 'vrf' is registered as an
editable text extension. The dedicated in-UI editor (and hiding it from the
file tree) follows in a separate change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 14:19:01 +00:00
claude 8530c5ebe0 Run Quarto Python kernel inside the project venv, not base python
Build and Deploy Verso / deploy (push) Successful in 9m33s
The global python3 kernelspec hardcodes /usr/bin/python3, so even with
QUARTO_PYTHON pointing at the project venv, Quarto launched the kernel in the
base interpreter — packages installed into the venv (e.g. openpyxl) were not
importable. Register a python3 kernelspec inside the venv via
'ipykernel install --sys-prefix' (kernel.json argv -> the venv's python); since
Quarto runs kernel discovery through QUARTO_PYTHON, the venv's kernelspec is
found ahead of the global one and the kernel runs in the venv.

Bump the completion marker (.verso-complete -> .verso-ready) so venvs built
before this change are rebuilt with the kernelspec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 13:50:01 +00:00
claude 83b6b323c3 Add cv2/tqdm to base; implement per-project Python venvs (Design B, Phase 1)
Build and Deploy Verso / deploy (push) Successful in 17m0s
Base image: add opencv-python-headless (cv2) and tqdm to the bundled
scientific stack, and python3-venv (needed to build per-project venvs).

Per-project dependencies: a project's requirements.txt is now installed into a
venv cached by its sha256 (python3 -m venv --system-site-packages, so the
bundled stack stays visible and only extra packages are installed); QuartoRunner
points Quarto at it via QUARTO_PYTHON. A per-hash flock serialises concurrent
builds; pip output is merged into output.log; on failure the render falls back
to the base interpreter. Venvs live under PYTHON_VENVS_DIR
(default /var/lib/overleaf/data/python-venvs).

Gating: PythonVenvGate.userCanInstallPython restricts installs to the project
owner + invited collaborators (ignorePublicAccess excludes anonymous/link
users), threaded to CLSI as allowPythonInstall on the editor compile,
presentation export, and publish paths. Behind OVERLEAF_ENABLE_PROJECT_PYTHON_VENV
(enabled in the deployment). Design doc updated; Phase 2 (egress policy) and
Phase 3 (venv eviction) remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 13:14:47 +00:00
claude 96fc1a90a1 Surface missing-Python-package errors clearly in the Quarto log
Build and Deploy Verso / deploy (push) Successful in 14m45s
When a {python} cell fails with ModuleNotFoundError/ImportError, the Quarto
log parser now emits an actionable error ('Python package "X" is not
installed on the server') noting which scientific packages are pre-installed,
instead of leaking an opaque traceback line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:32:08 +00:00
claude f2abd42969 Presentation export: progress modal + inline failure log
Build and Deploy Verso / deploy (push) Has been cancelled
The HTML/PDF export links were plain downloads that left the browser
silently spinning during the server-side render and, on failure, saved an
error page as pdf.txt/pdf.htm. Replace them with fetch-based downloads that
show a modal: a spinner with a 'this can take up to a minute' message while
compiling, and the actual compile log inline if the export fails. The user
can dismiss at any time; a stale request that finishes after dismissal no
longer reopens the modal. Adds the three i18n keys (en/fr + extracted).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:57:25 +00:00
claude 7e1c2ce53a Fix standalone-HTML export: inject embed-resources into the deck frontmatter
Build and Deploy Verso / deploy (push) Has been cancelled
embed-resources cannot be enabled from the CLI: Quarto only honours it when
nested under the format, and a document's own format block fully overrides
project/CLI metadata (confirmed in Quarto docs). So --metadata embed-resources
was silently ignored and the 'standalone' HTML was the ordinary non-embedded
deck referencing a sibling _files/ dir — unstyled, no math, no images once
downloaded on its own.

For the html-standalone export, render a temporary copy of the root .qmd with
embed-resources/self-contained-math enabled and chalkboard disabled inside its
revealjs block (replacing an existing chalkboard key rather than duplicating
it), then clean the temp file up. Falls back to the original file if the deck
isn't an editable nested-revealjs document, so the export is never worse than
before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:51:52 +00:00
claude 67b27c2684 Fix PDF export Chromium launch + HTML export caching
Build and Deploy Verso / deploy (push) Successful in 7m54s
The slide-PDF export failed because the CLSI runtime user has no writable
HOME, so Chromium's crashpad couldn't create its database and the browser
died on launch ('chrome_crashpad_handler: --database is required'). Give
decktape's Chromium a fresh writable temp dir via HOME/XDG_*/--user-data-dir
(plus --disable-gpu).

The standalone-HTML export kept returning the old non-embedded file partly
because the GET response had no cache headers, so the browser served its
cached copy; add Cache-Control: no-store to both export responses. Also
switch the embed-resources flags to the long '--metadata KEY:VALUE' form
(the documented Quarto syntax) to remove any ambiguity vs the '-M' alias.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:27:44 +00:00
claude 4d9adb2723 Fix presentation export: Quarto -M uses colon syntax, harden decktape
Build and Deploy Verso / deploy (push) Successful in 8m13s
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>
2026-06-02 07:11:51 +00:00
claude c38e2b8b49 Presentation download menu: standalone HTML + faithful slide PDF (decktape)
Build and Deploy Verso / deploy (push) Failing after 24m2s
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>
2026-06-01 21:00:50 +00:00
claude 899879472e Default the instance to French and translate the Verso-specific strings
Build and Deploy Verso / deploy (push) Successful in 7m35s
- 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>
2026-06-01 20:04:42 +00:00
claude 28a578ec85 Fix untranslated UI keys (raw "snake_case" labels) + anonymous edit links
Build and Deploy Verso / deploy (push) Successful in 7m46s
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>
2026-06-01 19:40:47 +00:00
claude 4766071e69 Published presentations: three access tiers + per-link reset
Build and Deploy Verso / deploy (push) Successful in 7m57s
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>
2026-06-01 18:19:15 +00:00
claude 4d3ac2b9ea Published presentations: two fixed links (public + private) instead of a toggle
Build and Deploy Verso / deploy (push) Successful in 7m30s
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>
2026-06-01 16:07:37 +00:00
claude 2cb81bd246 Serve published decks from a trailing-slash URL so assets load
Build and Deploy Verso / deploy (push) Successful in 7m29s
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>
2026-06-01 15:49:21 +00:00
claude cb0d9ac9fa Fix publish-presentation failing right after an editor compile
Build and Deploy Verso / deploy (push) Successful in 7m49s
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>
2026-06-01 15:30:46 +00:00
claude 59055aa67e Publish presentations: share-modal section + Preview button (UI)
Build and Deploy Verso / deploy (push) Successful in 7m53s
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>
2026-06-01 14:39:39 +00:00
claude 18f9220e73 Publish presentations as standalone shareable links (backend)
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>
2026-06-01 14:34:06 +00:00
claude 9b01fab383 Serve referenced media for HTML/RevealJS output
Build and Deploy Verso / deploy (push) Successful in 7m39s
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>
2026-06-01 14:01:58 +00:00
claude 7c2b903e4d Warn about missing images/videos in Quarto HTML output
Build and Deploy Verso / deploy (push) Successful in 7m49s
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>
2026-06-01 13:24:56 +00:00
claude 2d4ca6f13a Fix LaTeX projects failing to compile (HTTP 500, no logs)
Build and Deploy Verso / deploy (push) Successful in 7m44s
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>
2026-06-01 13:08:57 +00:00
claude d67bc77b0e Add a Typst compiler alongside Quarto and LaTeX
Build and Deploy Verso / deploy (push) Successful in 7m37s
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>
2026-06-01 12:56:30 +00:00
claude 2a9c4cfe81 New-project menu: split into Quarto and LaTeX blank/example options
Build and Deploy Verso / deploy (push) Successful in 7m44s
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>
2026-06-01 12:30:07 +00:00
claude 3e10d1c4ee Recolour remaining green brand-accent surfaces to the accent token
Build and Deploy Verso / deploy (push) Successful in 7m50s
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>
2026-06-01 11:49:12 +00:00
claude aa3fb56458 Parse Quarto logs and make the accent colour a single knob
Build and Deploy Verso / deploy (push) Successful in 11m55s
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>
2026-06-01 10:57:06 +00:00
claude e87bbfe5b0 HTML preview: drop embed-resources and clear stale deck on failure
Build and Deploy Verso / deploy (push) Successful in 12m5s
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>
2026-06-01 08:40:18 +00:00
claude 56d66b109e Outline: ignore YAML frontmatter and strip Quarto attribute blocks
Build and Deploy Verso / deploy (push) Successful in 12m25s
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>
2026-06-01 08:30:15 +00:00
claude b6c1a2d5ce Fix empty titles in Markdown/Quarto file outline
Build and Deploy Verso / deploy (push) Successful in 12m13s
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>
2026-06-01 08:04:42 +00:00
claude 2ae860a1a8 Raise upload limit from 50 MB to 500 MB
Build and Deploy Verso / deploy (push) Has been cancelled
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>
2026-05-31 19:38:21 +00:00
claude 422ac30e6c Support LaTeX and Quarto compilation in parallel
Build and Deploy Verso / deploy (push) Has been cancelled
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>
2026-05-31 19:27:39 +00:00
claude a241e2c201 Pre-install popular Quarto extensions in the Docker image
Build and Deploy Verso / deploy (push) Successful in 11m22s
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>
2026-05-31 16:54:56 +00:00
claude 24cd4bf13d Fix HTML compile success check: size is undefined for non-PDF outputs
Build and Deploy Verso / deploy (push) Has been cancelled
collectOutputPdfSize() only calls stat() and sets .size on output.pdf.
All other output files (including output.html) keep size: undefined.
The previous check required file.size > 0 for both PDF and HTML, so
undefined > 0 always evaluated false for output.html, making every
RevealJS compile report 'failure' even when the file was produced.

Fix: require size > 0 only for output.pdf; accept output.html
regardless of size (it is always non-empty if Quarto succeeded).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:27:02 +00:00
claude 090018c191 Fix QuartoRunner mv: use relative paths to avoid $COMPILE_DIR replacement bug
Build and Deploy Verso / deploy (push) Successful in 11m1s
LocalCommandRunner.replace() uses String.replace() which only substitutes
the FIRST occurrence of '$COMPILE_DIR' in the shell script string. The mv
commands had two more occurrences that stayed as literal '$COMPILE_DIR',
which the shell expanded to '', making 'mv /main.pdf /output.pdf' fail
silently. The file was produced (Quarto logged 'Output created: main.pdf')
but never renamed to output.pdf, so the pipeline reported failure.

Fix: mv uses relative filenames since the shell CWD is already the compile
directory (set by LocalCommandRunner via the spawnCwd option).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:51:01 +00:00
claude 48fd24a6b2 Add HTML/RevealJS preview alongside existing PDF preview
Build and Deploy Verso / deploy (push) Successful in 11m0s
clsi-nginx.conf: the types{} block was overriding all nginx defaults,
  leaving HTML/CSS/JS/fonts as application/octet-stream. Add the full
  set of web MIME types so RevealJS assets are served correctly. Also
  needed for X-Content-Type-Options: nosniff to pass.

CompileController.js: success was hardcoded to require output.pdf.
  Also accept output.html so a RevealJS compile is reported as
  'success' rather than 'failure'.

QuartoRunner.js: remove hardcoded --to typst --output output.pdf.
  Instead run `quarto render` without --to/--output so the YAML
  frontmatter decides the format (typst → PDF, revealjs → HTML, etc.).
  Pass --embed-resources so HTML output is self-contained (flag is
  silently ignored by the typst backend). After render, rename
  main.pdf → output.pdf or main.html → output.html so the pipeline
  finds the standard canonical filename.

output-files.ts: handleOutputFiles now falls back to output.html when
  output.pdf is absent. Download URL uses outputFile.path instead of
  the hardcoded 'output.pdf' string.

pdf-viewer.tsx: when pdfUrl contains output.html, bypass PDF.js
  entirely and render a sandboxed iframe (allow-scripts for RevealJS
  interactivity, allow-presentation for fullscreen).

Usage: set `format: revealjs` in the .qmd YAML frontmatter to get
  an HTML presentation preview; set `format: typst` for PDF.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:32:00 +00:00
claude 141cf95f9e Apply Verso brand identity: Quarto palette, logo, UI text
Build and Deploy Verso / deploy (push) Successful in 10m58s
Color palette: introduce Quarto's five brand colours ($verso-blue
  #447099, $verso-blue-dark #1B3B6F, $verso-blue-light #75AADB,
  $verso-green #72994E, $verso-orange #EE6331) as CSS custom
  properties alongside the existing layout vars.

Logo: replace all Overleaf SVG assets (icon, wordmarks, favicons,
  horizontal logos) with the Verso mark — a circle split into four
  Quarto-coloured quadrants (Quarto DNA) with a bold white V
  letterform (Verso identity). Filenames kept so imports stay intact.
  Status favicons keep their layout; brand green #046530#447099.

UI text:
  - appName / nav.title default → 'Verso'
  - Footer copyright → '© Verso'; remove Overleaf social links;
    thin-footer attribution → 'Built on Overleaf' (with OSS link)
  - mask-icon colour → #447099
  - interstitial logo alt → 'Verso'
  - Key locale strings (welcome, agree terms, go-to) → Verso;
    SaaS-specific strings (subscriptions, AI Assist) left as-is
    since CE users never see them

Env var names (OVERLEAF_*) intentionally untouched to avoid breaking
  the build. Code comments citing Overleaf origin preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:06:36 +00:00
claude 1e5ce6c068 Add document outline support for Markdown/Quarto files
Build and Deploy Verso / deploy (push) Successful in 10m47s
outline.ts: export NestingLevel so it can be used outside the file.

markdown/document-outline.ts: new enterMarkdownNode function that walks
  the Lezer Markdown syntax tree and extracts ATXHeading1-6 and
  SetextHeading1-2 nodes, mapping them to the same NestingLevel enum
  used by the LaTeX outline (Section→SubSection→SubSubSection…).
  Wrapped in makeProjectionStateField for incremental updates.

markdown/index.ts: register markdownDocumentOutline as a CodeMirror
  extension in the Markdown LanguageSupport so the StateField is active
  whenever a .qmd file is open.

codemirror-outline.tsx: fall back to markdownDocumentOutline when the
  LaTeX documentOutline StateField is not present in the editor state
  (i.e. when the active language is Markdown, not LaTeX).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:35:01 +00:00
claude ce0572e01e Revert QuartoRunner: restore --output output.pdf
Build and Deploy Verso / deploy (push) Successful in 11m9s
The previous compile logs confirm Quarto handles --to typst --output
output.pdf correctly: pandoc produces main.typ, typst compiles it to
main.pdf, then Quarto renames to output.pdf. The mv-based approach was
unnecessary and incorrect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:11:03 +00:00