Skip to content

hue notifier — Feature Requirements (interactive popups, all backends)

Status: planned (component: researched) · Date: 2026-07-23 · Scope: hue's notifier — interactive, collapsible floating popups available across all interactive backends (GUI, the TUI previewer, and HTML). Covers the shared component and the two concrete popups (startup info, file info).

NOTE

Everything here is forward-looking designnot started, with the component contract (NTF) marked researched (the design is captured; no popup code exists yet). Status legend and ID conventions: see the overview.

Design & rationale

The reference is folke/snacks.nvim's notifier: floating, titled panels that stack in a corner, can be dismissed or collapsed, and carry levels/icons/actions. hue adapts that into a cross-backend popup component — the same content model rendered in each backend's idiom:

  • a popup is a titled floating panel with a body, an optional close/collapse control, optional action buttons, and optional actionable/expandable items;
  • closing collapses it to a small floating icon (it is not destroyed); activating the icon expands it back to its prior place;
  • the same popup definition drives all three interactive backends — only the rendering/interaction primitive differs (raylib mouse, terminal keys, pure CSS).
  ┌─ popup (expanded) ──┐      ── close ▶──▶
  │ title     [buttons] │                      ● (floating icon)
  │ body / items ▸      │      ◀── activate ──
  └─────────────────────┘

This is a shared UI primitive, not a one-off: startup info and file info are its first two instances, and it composes with (but is distinct from) the overlay layer — overlays annotate the source; the notifier presents out-of-band panels about the session.

The notifier component (NTF)

IDRequirementStatusTraces to
NTF1A notifier must present interactive floating popups over the rendered content — a titled panel with a body, modeled on snacks.nvim's notifier. It is a shared component; concrete popups (NSI, NFI) supply content only.researched/not-startedproposed shared popup component
NTF2A popup's close control must collapse it to a small floating icon (corner-anchored), not destroy it; the icon persists so the popup can be recalled.not startedproposed collapse state
NTF3Activating the floating icon must re-expand the popup to its prior position/size (symmetric to NTF2).not startedproposed expand state
NTF4A popup body may contain actionable/expandable items rendered as actionable (underline, or a /> disclosure marker) that expand in place to reveal a detail list, and collapse back (e.g. languages: 42 ▸ → the full language list).not startedproposed disclosure item (drives NSI2)
NTF5A popup may include labeled action buttons; activating a button runs its action.not startedproposed button element
NTF6The component must render in every interactive backend — the "all backends" contract: GUI (raylib floating panel, mouse hit-test, sparkles:raylib-text drawBox border), TUI previewer (box-drawing panel over the viewport, key-driven), HTML (a positioned panel whose collapse/expand/disclosure is pure CSS, no JS — the <details>/:checked idiom the twoslash HTML backend already commits to).not startedgui.d; previewer.d; app.d HTML branch (all proposed)
NTF7Popups must anchor to a corner and stack without overlapping (snacks-style, default top-right); multiple popups (startup + file) must coexist.not startedproposed stack/layout
NTF8Each popup must be toggleable (a key in GUI/TUI; always-rendered, CSS-toggled in HTML); the startup popup is presented on launch and can be collapsed immediately.not startedproposed keybindings; HTML static render
NTF9The notifier must degrade gracefully: on the non-interactive ANSI path (piped/redirected, MOD3/MOD5) popups are omitted (never injected into piped output); in the TUI previewer the popup rendering must respect the previewer's @nogc nothrow render/output discipline (NFR1) or be explicitly carved out of it.not startedemitAnsiWholeFile (skip); previewer.d (NFR1)

Startup info popup (NSI)

Presented on launch; collapsible to an icon (NTF2).

IDRequirementStatusTraces to
NSI1Must show hue's version and short commit hash, and the active rendering mode (tui / gui / html); in GUI mode it must also show the GPU backend version (e.g. the raylib version).not startedproposed build stamp (none today); RAYLIB_VERSION; mode dispatch (MOD*)
NSI2Must show the counts of available/loaded tree-sitter languages and themes; languages: N and themes: N are actionable items (NTF4) that expand to the full lists.not startedGrammarRegistry (avail, ENG2) / TsConfigCache (loaded); names/themes (THM2)
NSI3The distinction between available (grammars in the $SPARKLES_TS_GRAMMAR_PATH bundle) and loaded (instantiated on demand) languages must be reflected in the count/list.not startedGrammarRegistry.fromEnvironment; TsConfigCache

File info popup (NFI)

Toggleable per NTF8; its theme field tracks live theme cycling.

IDRequirementStatusTraces to
NFI1Must show the file path, the detected language, the loaded tree-sitter grammar, and the current theme.not startedsourcePath (SRC1); canonicalLanguage (LNG1); TsConfigCache; theme name (THG1)
NFI2Must show file stats: byte count, line count, Unicode extended grapheme clusters (EGCs), and the number of tree-sitter highlight events.not startedsource.length (SRC1); lineCount; byGraphemeCluster (sparkles.base.text.grapheme); events[].length (ENG3)
NFI3The current theme field must update when the theme is cycled live (THG1); the byte/line/EGC/event stats are computed once at load.not startedapplyTheme (GUI); stats memoized at load

NOTE

The EGC count uses UAX #29 grapheme segmentation from sparkles.base.text.grapheme (byGraphemeCluster, @nogc) — this is grapheme counting, and is independent of the deferred grapheme/east-asian width table (DEF7 / gui.md FNT6); the popup reports a true EGC count even while the v1 grid still advances one cell per codepoint.

Diff & review adopters

The diff & PR view brings four future NTF consumers, each a thin adapter over the shared component (no new requirements here):

  • Destructive-op confirmations — discard (DST4) and conflict-resolution saves confirm through the popup, with touch-sized targets on Android (AND12).
  • Conflicts-remaining status — a collapse-to-icon count while resolving (CFV3).
  • Review submitted / failed — the draft-batch submission outcome (DCM6).
  • Forge degradation notices — rate limits and missing capabilities (DPR6/DPR7).

Module coverage (notifier)

Proposed layout — no code on any branch yet.

Source (proposed)Requirements
shared popup component (proposed)NTF1NTF5, NTF7, NTF8
apps/hue/src/gui.d (raylib popup layer, proposed)NTF6 (GUI), NSI*, NFI* (GUI paint)
apps/hue/src/previewer.d (TUI popup over viewport, proposed)NTF6 (TUI), NTF9 (@nogc discipline)
apps/hue/src/app.d HTML branch (CSS-only popup, proposed)NTF6 (HTML), NTF9 (ANSI skip)
build stamp (version + commit, proposed)NSI1
sparkles:base text/grapheme.d (byGraphemeCluster)NFI2 (EGC count)

Overlay requirements · GUI requirements · General requirements · Overview