Skip to content

feat: show SVG icons from rel=icon links - #63

Draft
yharby wants to merge 1 commit into
mainfrom
feat/svg-icons
Draft

yharby wants to merge 1 commit into
mainfrom
feat/svg-icons

Conversation

@yharby

@yharby yharby commented Sep 24, 2026 •

Copy link
Copy Markdown

What changed

The browser now shows SVG icons from rel=icon links. The change applies to these places:

  • the page header icon
  • child catalog cards and list rows
  • the header logo, when the root carries the icon

Before this change, an icon with "type": "image/svg+xml" did not appear anywhere. PNG, JPEG, GIF and WebP icons behave as before.

Thumbnails, overviews and preview links do not change. They still accept only the stac-js raster types.

Why

The Portolan profile allows image/svg+xml icons (PORTO-CORE-075).

The Portolan pipeline now publishes SVG group icons. Each icon is a file under _assets/icons/. The pipeline change is https://github.com/CartoDB/portolan-pipeline/pull/110.

The stac-js release in use is 0.5.3. It leaves image/svg+xml out of browserImageTypes in src/mediatypes.js. STAC.getIcons() filters on canBrowserDisplayImage(), so it drops each SVG icon.

Verification

The fixture is a local static catalog at http://localhost:8111/catalog.json. It has one child catalog, roads/catalog.json, with this link:

{"rel":"icon","href":"../_assets/icons/x.svg","type":"image/svg+xml","title":"X"}

The SVG is a 24 x 24 cross with a fixed stroke colour, no script and no external reference. I served the fixture with CORS and ran npx vite --port 5199. Then I read the <img> elements in Playwright.

Root page, http://localhost:5199/#/external/http://localhost:8111/catalog.json, with this branch:

{ src: "http://localhost:8111/_assets/icons/x.svg", cls: "icon me-2", w: 24, title: "X", parent: "Roads" }

Child page, #/external/http://localhost:8111/roads/catalog.json, with this branch:

{ src: "http://localhost:8111/_assets/icons/x.svg", cls: "icon", complete: true, w: 24, title: "X" }

Root page with the change removed from src/utils.js and src/components/StacLink.vue:

[ "http://localhost:5199/portolan-logo.svg" ]

The card shows no icon in that case. A screenshot of the fixed root page shows the red cross beside "Roads".

Checks on this branch:

$ npx vitest run
 Test Files  14 passed (14)
      Tests  477 passed (477)
$ npx eslint src
(no output, exit 0)
$ npx vite build
✓ built in 11.98s
  • This change does not alter behavior (docs, chore, or CI only).
  • This pull request integrates changes already verified in their own pull
    requests (a release or integration branch). List them under "What
    changed".

Implementation notes

Utils.getIcons(data) in src/utils.js keeps an icon link in two cases:

  • stac-js canBrowserDisplayImage(true) accepts the link
  • Utils.isBrowserSvg() accepts the link

Utils.isBrowserSvg() repeats the stac-js protocol check. It accepts these links:

  • an http, https or relative href
  • the image/svg+xml type, or no type with a .svg extension

It rejects s3:// and other protocols. The missing-type rule matches the allowUndefined = true default of getIcons().

Utils.getIcon() and StacLink.vue now call Utils.getIcons(). They are the only callers of getIcons() in src/.

Safety: the browser renders each icon through <img :src>. It never puts SVG markup into the DOM. An SVG in <img> runs no scripts. It also loads no external resources.

The new unit tests in tests/unit/utils.spec.js cover these cases:

  • a relative SVG icon
  • an untyped .svg icon
  • a PNG icon and an SVG icon together
  • an s3:// SVG icon
  • a TIFF icon
  • input that is not STAC

A follow-up in stac-js upstream can add image/svg+xml to browserImageTypes. That change also affects thumbnails, so upstream must decide the scope. After an upstream release, Utils.isBrowserSvg() can go.

Related issues

https://github.com/CartoDB/portolan-pipeline/issues/154
https://github.com/CartoDB/portolan-pipeline/pull/110

stac-js 0.5.3 leaves image/svg+xml out of browserImageTypes. Its
getIcons() therefore drops every SVG icon. The Portolan profile allows
SVG icons (PORTO-CORE-075), and the Portolan pipeline publishes SVG
icons for browsing groups.

Utils.getIcons() now accepts an icon link when stac-js accepts it or
when the link is an SVG on http, https or a relative href. StacLink
and Utils.getIcon() use it. Thumbnails and previews do not change.

The browser renders icons only through <img>. An SVG in <img> runs no
scripts and loads no external resources.
@nlebovits

Copy link
Copy Markdown

@yharby is this still a draft?

@yharby

yharby commented Oct 6, 2026

Copy link
Copy Markdown
Author

I was waiting for moregeo-it/stac-js#26 and radiantearth#1021

CC @m-mohr

@m-mohr

m-mohr commented Oct 6, 2026 •

Copy link
Copy Markdown

Does someone have a voucher for the 48 hour day upgrade, please? 🙈😅 (currently at 12.5 hours at work)

@nlebovits

Copy link
Copy Markdown

@m-mohr I can lend you some claude credits ;)

@m-mohr

m-mohr commented Oct 6, 2026 •

Copy link
Copy Markdown

That's not how I work, at least for reviews 😐 I'll try my best to get to it soon.

This branch has not been deployed

No deployments
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.

3 participants