Files
nostr_terminal/docs/tui_style.md
T

3.8 KiB

TUI Style Guide — Nostr Terminal

Library

The TUI is built on tui_ncurses (vendored at resources/tui_ncurses/), which provides:

  • Pinned header/footer panes with a scrollable body window
  • Library-owned menu loops (tuin_menu_run)
  • Library-owned table loops (tuin_table_run)
  • Library-owned pager (tuin_pager_run)
  • Modal dialogs (tuin_prompt, tuin_confirm, tuin_notice)
  • Automatic KEY_RESIZE handling

Adapter Layer (src/nt_tui_adapter.c)

App-specific helpers wrapping the library:

Function Purpose
nt_frame(breadcrumb) Build a TuiFrame with current app title + user
nt_status() Build a TuiStatus with latest log line
nt_set_app_info(name, version) Set app name/version for header
nt_set_user(user) Set user label for header (empty hides it)
nt_set_window_title(title) OSC 2 terminal title
nt_print(fmt, ...) Write to body window (in-screen composition)
nt_print_reset() Clear body window + reset cursor
nt_run_external_editor(spawn, user) Bracket editor with cleanup/init
nt_log(fmt, ...) Append to footer-log (informational stream)
nt_log_show() Open full log in scrollable pager
nt_log_clear() Clear log buffer
nt_pager_show_text(breadcrumb, text) Show text in full-screen pager

Three-Tier Output Model

Every "show something to the user" call fits one of three tiers:

  • When: Passive informational stream — publishes, network events, action completions.
  • Behavior: Latest line shown in footer status area. Full history via "View log" main menu entry.
  • Example: nt_log("Tweet published to 3/5 relays.");

Tier 2: Modal Dialog (tuin_notice / tuin_confirm)

  • When: Must-acknowledge errors or destructive confirmations.
  • Behavior: Centered popup, blocks until user responds.
  • Example: tuin_notice("Failed to connect to relay.");
  • Example: if (tuin_confirm("Delete this relay?") == 1) { ... }

Tier 3: Full-Screen Pager (nt_pager_show_text)

  • When: Intentional content viewing — DM threads, event JSON, AI responses, blog posts, NIP-11 info.
  • Behavior: Full-screen scrollable view with Up/Down/PgUp/PgDn/Home/End. Esc returns.
  • Example: nt_pager_show_text("> Relays > NIP-11", nip11_text);

In-Screen Composition (nt_print)

  • When: Building custom body content inside streaming/live loops.
  • Not for: Post-action results (use nt_log) or content viewing (use pager).

Header Format

================ NOSTR TERMINAL - v0.0.13 - alice ================
> Main Menu > Relays
  • Pre-login: NOSTR TERMINAL - v0.0.13
  • Logged in: NOSTR TERMINAL - v0.0.13 - <username>

Menu Pattern

static const TuiMenuItem ITEMS[] = {
    {NT_HK("A","dd relay"),    'a'},
    {NT_HK("D","elete relay"), 'd'},
    {"E" NT_HK("x","it"),      'x'},
};
TuiMenuState state = {0};
TuiFrame frame = nt_frame("> Main Menu > Relays");
TuiMenu menu = {ITEMS, 3};
TuiStatus status = nt_status();

int idx = tuin_menu_run(&frame, &menu, &status, &state);

Hotkey Convention

Use NT_HK("X", "rest") macro which expands to "\033[4mX\033[0mrest" (underlined first letter).

Breadcrumb Convention

Format: "> Main Menu > SubMenu > Action"

  • Root: "> Main Menu"
  • Sub: "> Main Menu > Relays"
  • Deep: "> Main Menu > Relays > NIP-11"

Main Menu Entries

Write, Tweet, Profile, Relays, Follows, Kind/event dump, Notifications, Blogs/posts, Live feeds, Message, Todo, Journal, Ai, Ecash, View log, Quit.

Key Bindings (library-provided)

  • Menus: Up/Down + Enter, or shortcut key. Esc/q/x to cancel.
  • Tables: Up/Down/PgUp/PgDn/Home/End + Enter to select. Esc/q/x to cancel.
  • Pager: Up/Down/j/k, PgUp/PgDn, Home/End/g/G. Esc/q/x/Enter to return.
  • Prompts: Type + Enter to submit. Esc to cancel.
  • Confirm: y/n keys.