Skip to content

ADR 0010 — Icons for section controls: one folder, embedded, sanitized ​

  • Status: Accepted
  • Date: 2026-10-04
  • Context repos: cratly.io site (this repo), scavold, editor

Problem ​

A site offers styling choices on its sections — text flowing around the first block on the left or on the right, a frame or none. As a select or a checkbox, such a choice is a word the author has to translate into a picture. A button showing the picture is quicker to read, so a property and the choices of an enum should be able to name an icon.

The editor's own icons cannot serve: they are Font Awesome icons, and its build copies exactly those its source code names. A name coming from a site's configuration is not known at that time. The icons have to come from the site.

Decision ​

  1. One fixed folder. A site keeps its icons as .cratly/icons/<name>.svg; a property or choice names one by icon: <name>. The folder is the registry, so an icon used in several places is one file. There is no path and no URL to give: a name that could point anywhere in the repository — or outside it — is a name that has to be checked, and an icon fetched from elsewhere is one that changes without a commit, depends on another host's CORS, and tells it who is editing.

    An adapter may bring icons of its own for the section kinds it builds in, so a variant it offers looks the same on every site using it. They travel with the adapter's release, not from elsewhere at runtime, and a site's icon of the same name replaces one, so a site whose design differs is not stuck with it.

  2. Embedded in the manifest. The adapter embeds the icons the manifest refers to under its icons key. The editor reads them with the manifest, through the same GitLab API call, and the adapter is where a reference to a missing icon is noticed and reported.

  3. Sanitized by the editor. The markup is repository content, and the editor acts with its author's access to that repository. An SVG inserted as it is runs whatever script or handler it carries in that context. Rendering it as an image would be safe but could not take the colour of the button it sits on, which is how a pressed or disabled state shows. So the editor keeps a fixed subset — plain shapes and their painting attributes — and drops everything else. The subset is part of the section-type contract, not only of the editor's code, so every editor applies the same one.

Consequences ​

  • An icon set exported as plain paths works; one relying on gradients, embedded styles or references loses its look. That is accepted: these are control icons, not artwork.
  • An enum names an icon for choosing no value as well, on the property itself: a group of buttons whose one text button says "none" reads worse than one more picture.
  • Icons stay optional. A choice without an icon, or an enum where only some choices have one, keeps the select — a group mixing pictures and words reads as neither.
  • The label stays required in practice: an icon carries no text, and the label is what a screen reader announces and a tooltip shows.