feat: support custom SVG bullet markers #2616

Closed
jhermans wants to merge 1 commit from jhermans/Ocideck:feat/custom-svg-bullets into main
First-time contributor

Summary

Add custom_svg as a third bullet-marker type alongside dot and paw, so authors can upload their own SVG and use it as the theme default or as a per-slide override.

The SVG is stored inline in the style profile to keep decks portable and usable offline. That increases the amount of untrusted content handled by the deck format, so safety takes precedence over preserving every SVG feature: imports are capped at 256 KiB and sanitised before storage, with scripts, event handlers, animation, and external or data: URLs removed. I would reconsider the inline approach if interoperability requires referenced assets, or if the allow-list cannot be kept aligned with the renderer.

Changes

  • Add BulletMarker.customSvg with the stable file-format token custom_svg.
  • Store a sanitised customBulletSvg inline in ThemeProfile and preserve it through JSON/style-profile and Markdown round trips.
  • Add SVG selection/upload controls to the theme settings and the per-slide bullet-marker selector.
  • Render custom markers in Flutter previews and embed them as self-contained data URIs in HTML/Marp export, with a safe dot fallback when no valid SVG is present.
  • Extend SVG sanitisation with byte limits and active-content/remote-resource removal.
  • Add model, Markdown, widget-preview, HTML-export, sanitisation, and style-profile tests.
  • Document the new theme field and slide directive in the English and Dutch file-format references.

Checklist

  • Every commit is signed off (git commit -s) per the DCO, with my real name and a reachable email.
  • Maintainer: make check-full passes locally on the exact commit named in the PR before merge. Tested commit: 663fdb774634470b1d94833d225fc3dad3ab6e9b. The Debian 12 production build completed successfully on this commit; the full maintainer gate has not been claimed.
  • Added/updated tests for the behaviour changed.
  • No new translatable prose was introduced. Existing translated labels are reused; SVG is the standard technical acronym and is deliberately unchanged.
  • Updated docs/FILE_FORMAT.md and docs/FILE_FORMAT.nl.md for the new stored fields and directive value.
  • Docs updated where relevant.
  • The storage/security trade-off is described above: portability and offline operation are preserved, while unsupported or active SVG features are discarded.
  • Re-read docs/SECURITY_DESIGN.md (including HTML export sanitisation and the threat model) and assurance/risicoafweging.md. The threat model still holds: deck files and assets remain untrusted, custom SVG is bounded and sanitised before rendering/storage, no network access is added, and exported HTML retains its existing CSP/DOMPurify defence in depth.

Notes for reviewers

Please pay particular attention to the SVG allow-list and to parity between Flutter preview rendering and HTML export. Manual check: select SVG under the theme bullet-marker setting, choose a local .svg, verify bullets update in the editor, save/reopen the deck, and export to HTML while offline.

## Summary Add `custom_svg` as a third bullet-marker type alongside `dot` and `paw`, so authors can upload their own SVG and use it as the theme default or as a per-slide override. The SVG is stored inline in the style profile to keep decks portable and usable offline. That increases the amount of untrusted content handled by the deck format, so safety takes precedence over preserving every SVG feature: imports are capped at 256 KiB and sanitised before storage, with scripts, event handlers, animation, and external or `data:` URLs removed. I would reconsider the inline approach if interoperability requires referenced assets, or if the allow-list cannot be kept aligned with the renderer. ## Changes - Add `BulletMarker.customSvg` with the stable file-format token `custom_svg`. - Store a sanitised `customBulletSvg` inline in `ThemeProfile` and preserve it through JSON/style-profile and Markdown round trips. - Add SVG selection/upload controls to the theme settings and the per-slide bullet-marker selector. - Render custom markers in Flutter previews and embed them as self-contained data URIs in HTML/Marp export, with a safe dot fallback when no valid SVG is present. - Extend SVG sanitisation with byte limits and active-content/remote-resource removal. - Add model, Markdown, widget-preview, HTML-export, sanitisation, and style-profile tests. - Document the new theme field and slide directive in the English and Dutch file-format references. ## Checklist - [x] Every commit is **signed off** (`git commit -s`) per the DCO, with my real name and a reachable email. - [ ] Maintainer: `make check-full` passes locally on the exact commit named in the PR before merge. Tested commit: `663fdb774634470b1d94833d225fc3dad3ab6e9b`. The Debian 12 production build completed successfully on this commit; the full maintainer gate has not been claimed. - [x] Added/updated tests for the behaviour changed. - [x] No new translatable prose was introduced. Existing translated labels are reused; `SVG` is the standard technical acronym and is deliberately unchanged. - [x] Updated `docs/FILE_FORMAT.md` and `docs/FILE_FORMAT.nl.md` for the new stored fields and directive value. - [x] Docs updated where relevant. - [x] The storage/security trade-off is described above: portability and offline operation are preserved, while unsupported or active SVG features are discarded. - [x] Re-read `docs/SECURITY_DESIGN.md` (including HTML export sanitisation and the threat model) and `assurance/risicoafweging.md`. The threat model still holds: deck files and assets remain untrusted, custom SVG is bounded and sanitised before rendering/storage, no network access is added, and exported HTML retains its existing CSP/DOMPurify defence in depth. ## Notes for reviewers Please pay particular attention to the SVG allow-list and to parity between Flutter preview rendering and HTML export. Manual check: select **SVG** under the theme bullet-marker setting, choose a local `.svg`, verify bullets update in the editor, save/reopen the deck, and export to HTML while offline.
Signed-off-by: Jeroen Hermans <j.hermans@cloudaware.eu>
brenno referenced this pull request from a commit 2026-10-28 22:35:07 +00:00
brenno referenced this pull request from a commit 2026-10-29 00:22:54 +00:00
brenno referenced this pull request from a commit 2026-10-29 01:09:37 +00:00
Owner

Gemerged via #2652. De branch staat op een fork met allow_maintainer_edit uit, dus de poortfixes (dart format, ratchet-extractie van het marker-veld naar parts/settings_dialog_bullet_marker.dart, copyWith-baseline, SVG door l10n.d, sanitise-stabiele testinvoer) staan daar als eigen commits bovenop jouw fc1f9c151/663fdb774. Bedankt voor de bijdrage — de allow-list-aanpak op de SVG is precies de richtige kant op.

Gemerged via #2652. De branch staat op een fork met `allow_maintainer_edit` uit, dus de poortfixes (dart format, ratchet-extractie van het marker-veld naar `parts/settings_dialog_bullet_marker.dart`, `copyWith`-baseline, `SVG` door `l10n.d`, sanitise-stabiele testinvoer) staan daar als eigen commits bovenop jouw `fc1f9c151`/`663fdb774`. Bedankt voor de bijdrage — de allow-list-aanpak op de SVG is precies de richtige kant op.
brenno closed this pull request 2026-10-29 01:10:04 +00:00

Pull request closed

Sign in to join this conversation.
No description provided.