Skip to content

Fix logo paths for documents in project subdirectories - #15002

Open
cderv wants to merge 8 commits into
quarto-dev:mainfrom
cderv:fix/issue-14946
Open

cderv wants to merge 8 commits into
quarto-dev:mainfrom
cderv:fix/issue-14946

Conversation

@cderv

@cderv cderv commented Oct 6, 2026

Copy link
Copy Markdown
Member

When a revealjs or dashboard document is in a project subdirectory, an active brand can cause non-brand logo paths to be treated as project-relative. Extension logos then point outside _site and are not copied to site_libs; document logos can also break. Brand logos in default projects are affected too.

The shared leading-slash rewrite assumes all logos are project-relative, but only brand logos use that base. Extension, front matter, project metadata, and _metadata.yml logos are already document-relative.

Resolve brand paths relative to the input document before merging them with the document logo. For websites, retain a deprecated fallback for project-relative document logos that do not resolve relative to the document, and emit a warning. Regression cases cover encoded paths, query and fragment suffixes, dark-only brands, path collisions, and filenames that cannot be stat'ed. Smoke fixtures also ignore generated files.

Fixes #14946

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes
  • updated the appropriate changelog in the PR
  • ensured the present test suite passes
  • added new tests
  • created a separate documentation PR in Quarto's website repo and linked it to this PR
AI-assisted PR

cderv added 8 commits October 6, 2026 16:19
Fixes quarto-dev#14946.

Since v1.8.22 (quarto-dev#13279 for quarto-dev#11982), revealjs and dashboard prefixed every
logo path with `/` whenever a brand was active and the document sat in a
project subdirectory. That assumed all logo paths were project-relative,
but only brand logos are: front matter, `_quarto.yml`, `metadata-files`,
`_metadata.yml` and extension format logos all arrive already relative to
the document. Turning `../_extensions/x/logo.png` into
`/../_extensions/x/logo.png` broke extension logos in websites (never
copied to `site_libs`), and every other non-brand source broke too. In
default projects even brand logos rendered as an unresolvable `/img/...`.

Brand logo paths are now rebased onto the document directory before they
are merged with the document logo, the same split quarto-dev#14075 made for Typst,
so every source ends up document-relative in any project type. The `/`
helper stays for the website navbar and sidebar, which have no single
input document.

Since v1.8.22, a project-relative front-matter or `_metadata.yml` logo in a
subdirectory worked by accident, only in a website with a brand. Public
projects rely on it, so it still resolves there with a deprecation
warning. In default projects it never worked, so no fallback is added.
…ded paths

The deprecated fallback that still resolves a project-relative logo in a
website subdirectory missed two cases the previous leading-slash behavior
handled. A brand configured with only `dark:` has no `light` variant, so the
project directory was never found. A URL-encoded path such as
`img/my%20logo.png` was checked as a literal filename; the leading-slash
path worked because HTML resource processing decodes attributes before
resolving them. The existence checks now decode the path the same way,
while the emitted path stays as written.
Both decode a path with decodeURI and keep the raw value on a malformed
escape. Only the HTML attribute reader warns: the logo path ends up in an
HTML attribute too, so warning in the fallback would report it twice.
The deprecated project-relative logo fallback checked `img/logo.png?v=1`
or `img/logo.svg#id` as literal file names. On Windows `?` is not a valid
file name character, so the existence check threw and the render failed,
where 1.10 rendered `../img/logo.png?v=1`. Elsewhere the check simply
missed and left a broken path. The file checks now use only the path part,
and the query and fragment are appended back to the rebased path.
A document logo path that exists both next to the document and at the
project root now resolves to the document's file, silently. Versions 1.8 to
1.10 picked the project-root file in branded projects, only because every
logo path got a leading '/'. Document-relative wins in 1.7 and in any
project without a brand, so this keeps the documented rule instead of the
accidental one; the project-relative fallback only applies when the
document-relative file is missing.
The reported failure includes the logo never being copied, which the HTML
src regex alone does not check. Rendered alone on main, both subdirectory
documents leave site_libs/quarto-contrib/.../logo.png missing.
On Windows, stat throws (os error 123) for a path containing a character
that is invalid in a filename, such as '*', so a branded website document
in a subdirectory with such a logo path failed to render. The check only
serves the deprecated project-relative fallback; treating an unstat-able
path as missing leaves it as written, as 1.10 did.
@posit-snyk-bot

posit-snyk-bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

revealjs format extension logo: resolves to a broken path in subfolder documents when the project has a _brand.yml

2 participants