UnENVerse 0.42.6
Local-first desktop secrets manager — TypeScript frontend
Loading...
Searching...
No Matches
icons.ts File Reference
import showToast;

Functions

function iconImgURL (slug:string)
 A data: URI for a bundled provider icon, or ‘’'` when the slug is unknown.
 
function renderIconGrid (query:string)
 Renders the icon selection grid filtered by query.
 
function selectIcon (slug:string)
 Marks a slug as selected, re-renders the grid, and applies the icon to the current picker target immediately so the user sees a live preview.
 
function applyIconToTarget (slug:string|null)
 Writes the chosen slug (or clears it) to the bound form field and preview element.
 
function export openIconPicker (fieldEl?:HTMLInputElement, previewEl?:HTMLElement, onClose?:(slug:string|null)=> void,)
 Opens the icon-picker overlay and binds it to the supplied DOM elements.
 
function export closeIconPicker ()
 Closes the icon-picker overlay, fires the onClose callback with the final selection, and resets all picker state.
 

Variables

const SI_REGISTRY
 Master registry of supported Simple Icons entries.
 
const string
 
const SI_AUTO
 Normalised name-to-slug lookup built from SI_REGISTRY plus manual aliases.
 
function export getIconSlug(provider:string, customIcon?:string|null) const ICON_MIME_RE
 Resolves a Simple Icons slug for a given provider name or custom icon override.
 
 base64
 
function export isEmbeddedIcon(value?:string|null) const iconUrlCache = new Map<string, string>()
 Whether custom_icon holds an embedded image rather than a Simple Icons slug.
 

Function Documentation

◆ iconImgURL()

function iconImgURL (   slug:string)

A data: URI for a bundled provider icon, or ‘’'` when the slug is unknown.

This used to be https://cdn.simpleicons.org/<slug>/e4e4e4. Every card render therefore asked a third party for /stripe, /github, /aws, /openai — so that third party, and anyone on the path, learned the exact set of services the user holds credentials for, the entry count per service, their IP, and when they opened their vault. That is the most sensitive metadata this application holds, and it left the machine by default, from a product whose README opens with "runs on your machine and talks to nothing else … no telemetry". (review-01 §3.3.)

The paths are now bundled by scripts/gen-icons.mjs and https://cdn.simpleicons.org is gone from the CSP, so the leak cannot come back by accident: a stray remote icon URL is now blocked rather than fetched.

An unknown slug returns ‘’'` and the caller falls back to a letter avatar — the same thing that happened before when the CDN answered 404, which it had been doing for 55 registry entries nobody had noticed. Returns an <img> tag for a known provider icon, or a letter-initial fallback <span>.

The <img> uses loading="lazy" to avoid blocking the initial render. If the CDN request fails at runtime, a global error handler in initIconPicker replaces the broken image with the letter fallback.

Parameters
provider- Provider name used both for alt text and slug resolution.
customIcon- Optional explicit slug override.
Returns
Escaped markup (a SafeHtml). Shared mutable state for the icon-picker overlay.

Using a plain exported object rather than re-assignable variables avoids ESM live-binding issues when the object is imported across modules.

Callbacks and DOM references for the currently active picker session.

The Simple Icons slug that is currently highlighted in the picker grid.

◆ renderIconGrid()

function renderIconGrid (   query:string)

Renders the icon selection grid filtered by query.

Matches against both the slug and the display name (case-insensitive). Highlights the currently iconPicker.selected item.

Parameters
query- Search string; empty string shows all icons.

◆ selectIcon()

function selectIcon (   slug:string)

Marks a slug as selected, re-renders the grid, and applies the icon to the current picker target immediately so the user sees a live preview.

Parameters
slug- Simple Icons slug to select.

◆ applyIconToTarget()

function applyIconToTarget ( slug:string|  null)

Writes the chosen slug (or clears it) to the bound form field and preview element.

Parameters
slug- Slug to apply, or null / empty string to clear the icon.

◆ openIconPicker()

function export openIconPicker (   fieldEl?:HTMLInputElement,
  previewEl?:HTMLElement,
onClose?  :slug:string|null,
  void 
)

Opens the icon-picker overlay and binds it to the supplied DOM elements.

Parameters
fieldEl- Hidden <input> that receives the chosen slug value.
previewEl- Element that displays a live preview of the selected icon.
onClose- Callback fired with the final slug (or null) when the picker closes.

◆ closeIconPicker()

function export closeIconPicker ( )

Closes the icon-picker overlay, fires the onClose callback with the final selection, and resets all picker state.

Variable Documentation

◆ SI_REGISTRY

const SI_REGISTRY

Master registry of supported Simple Icons entries.

Each tuple is [slug, displayName, category] where slug is the Simple Icons identifier — now a key into the bundled ICON_PATHS rather than a CDN URL — and displayName is what the picker shows.

category is not currently rendered: the picker grid is flat and filters by substring. It stayed as a grouping hint, and because it was never read, 29 providers were listed twice under two different categories and appeared twice in the picker. Slugs are unique now and tests/icon-bundle.test.ts keeps them that way.

See also
https://simpleicons.org for slug reference.

◆ string

const string

◆ SI_AUTO

const SI_AUTO

Normalised name-to-slug lookup built from SI_REGISTRY plus manual aliases.

Keys are lower-cased and stripped of non-alphanumeric characters so that fuzzy provider-name matching works without exact casing. Manual aliases handle common abbreviations (e.g. "aws", "gcp", "x" → "twitter").

◆ ICON_MIME_RE

function export getIconSlug (provider: string, customIcon?: string | null) const ICON_MIME_RE
Initial value:
=
/^data:image\/(png|jpeg|gif|webp|bmp|x-icon|vnd\.microsoft\.icon)

Resolves a Simple Icons slug for a given provider name or custom icon override.

Resolution order:

  1. If customIcon is a non-empty string, return it as-is (explicit override).
  2. Strip non-alphanumeric characters from provider and look up in SI_AUTO.
  3. Fall back to a trimmed lower-case lookup against the raw provider name.
  4. Return null if no slug is found (UI will render an initial-letter fallback).
Parameters
provider- Provider display name (e.g. "GitHub", "AWS").
customIcon- Explicit slug override from the entry's custom_icon field.
Returns
A Simple Icons slug string, or null if unresolved. Constructs a Simple Icons CDN URL for a given slug.

Icons are fetched as light-coloured (e4e4e4) SVGs to match dark-theme cards.

Parameters
slug- A valid Simple Icons identifier (e.g. "github").
Returns
Absolute CDN URL string. Largest embedded icon accepted, as data-URI characters.

The vault is a single JSON blob that is decrypted, parsed and re-serialised on every save, so an icon is not free: a handful of 1 MB PNGs would show up as lag on every write. 96 KB of base64 is roughly a 70 KB file — comfortably more than any favicon, and small enough that a hundred of them do not matter. Raster image types accepted as an embedded icon.

◆ base64

base64

◆ iconUrlCache

function export isEmbeddedIcon (value?: string | null) const iconUrlCache = new Map<string, string>()

Whether custom_icon holds an embedded image rather than a Simple Icons slug.

Both live in the same field on purpose: everything that already renders, stores, copies or exports custom_icon keeps working, and an entry cannot end up with a slug and a file disagreeing about which icon it has. Validate an embedded icon, returning an error message or null.

A vault is untrusted input (invariant 4) — it may come from a remote server or an imported backup — so this runs on read, not only when the user picks a file. SVG is deliberately excluded: it is a script-bearing format, and the one thing worth avoiding is a stored image that is also a program. Colour the bundled monochrome paths are filled with. Matches the value the CDN URL used to request, so nothing changes visually. Built data URIs, memoised — the picker grid renders ~370 of these per keystroke.