3.0 KiB
type, id, title, status, date
| type | id | title | status | date |
|---|---|---|---|---|
| ADR | 0049 | Per-note icon property (_icon on individual notes) | active | 2026-04-08 |
Context
Laputa already supports type-level icons via the _icon system property on type documents (ADR 0008). Every note of a given type inherits the type's icon. Users needed a way to give individual notes a distinct visual identity without changing the type — e.g., marking a specific project with a rocket emoji, or a key person with a star icon — without creating a new type just for one note.
Decision
The _icon system property (already used by type documents) is now also supported on regular notes. When a note has an _icon value, it overrides the inherited type icon in all UI surfaces. The value may be an emoji, a Phosphor icon name, or an HTTP(S) image URL.
Resolution logic
resolveNoteIcon(icon) in utils/noteIcon.ts returns a discriminated union:
| Kind | Condition |
|---|---|
none |
Value is empty/null |
emoji |
Value passes isEmoji() |
image |
Value is an HTTP(S) URL |
phosphor |
Value matches a registered Phosphor icon name |
The NoteTitleIcon component renders the correct element for each kind (span, <img>, or Phosphor SVG component).
UI surfaces updated
- Editor breadcrumb bar (clicking the icon opens the
_iconproperty editor) - Note list items (
NoteItem) - Search panel results
- Relationship chips (shows icons on wikilink chips)
- Sidebar type sections
- Backlinks / ReferencedBy panels
- Inspector pinned area
Editing
A custom event (laputa:focus-note-icon-property) is dispatched from the breadcrumb bar click to focus the _icon field in the Properties panel without scrolling. The field uses the existing property editor UI.
Options considered
- Option A — Separate
_note_iconproperty: Avoids ambiguity with the type-level_icon. Downside: two names for the same concept depending on context; complicates the resolver. - Option B — Reuse
_iconon notes (chosen): Consistent with existing convention (ADR 0008); type docs and note docs follow the same schema. The distinction between type-level and note-level is determined byis_a: Typein the frontmatter, not by a different property name. - Option C — Inline emoji in note title: Zero-friction. Downside: title is also the filename (ADR 0044); emojis in filenames cause filesystem/git pain.
Consequences
_iconon a note overrides the type icon everywhere. A note with no_iconcontinues to inherit the type icon (no behavior change for existing vaults).- The icon resolver (
resolveNoteIcon) is shared between note icons and type icons; future changes to icon resolution affect both. iconRegistry.tsgrows with any new Phosphor icon additions — currently loaded eagerly. If the icon set grows large, lazy loading or a build-time icon map should be considered.- Re-evaluation trigger: if users request per-note color (the
_colorsystem property currently only applies to types), the same resolution pattern can be extended.