Files

5.7 KiB

UI patterns

Reusable patterns used across the operator console.

Three-layer view identification

See ADR-0009 for the full rationale.

Layer Function Element
1 Navigation (where am I in the product?) Active pill in left rail
2 Mode (what domain is this view in?) Title strip in topbar (color shifts per domain)
3 Operational context (what's happening here right now?) .ctx-strip with badge + dynamic data

The panel-level <h2> "▸ NAME" is gone. Don't reintroduce it.

For multi-zone views (e.g. forensics), inner <h3> headers are kept because zones coexist on screen.

Compact context strip

Used at the top of every panel. Pattern:

<div class="pane">
  <div class="ctx-strip">
    <span class="ctx-badge">DYNAMIC INFO HERE</span>
    <span class="ctx-sub">optional info-bearing sub-line, no descriptive prose</span>
  </div>
  <!-- panel body -->
</div>

The badge contains dynamic info (states, counts, target endpoints, branch/sha). The sub-line is optional and only when it adds info. Never used for descriptive prose explaining what the view does — that's redundant with the rail.

Full-screen wizard mode

Used for first-boot wizard and camera onboarding. The console chrome (rail, topbar, status strip) is hidden when in wizard mode.

<body class="wizard-on">
  <div class="wizard-mode">
    <!-- wizard chrome: header, stepper, body, footer -->
  </div>
</body>

Activation via body.classList.add('wizard-on'). Deactivation reverts to normal console.

For demos, both wizards have a floating toggle button at the bottom right. In production these don't exist — the wizard appears automatically on first boot, and disappears once provisioning is complete.

SCADA-style live diagram (SYNOPSIS)

The landing view is a hand-tuned SVG diagram of the site's hardware and services. Conventions:

  • Components as rectangles with rounded corners (rx="14" for major devices, rx="6" for small chips).
  • VLANs as dashed colored halos around groups of components.
  • Service chips as small rounded rectangles inside their host device, with a status pulse dot on the right edge.
  • Flows as stroke-dasharray lines with flow-line animation. Direction arrows via SVG marker-end.
  • Gauges at the bottom: half-circle SVG paths with the value as text below.

Hand-tuned coordinates for now. If the diagram grows beyond ~10 components, consider migrating to a layout library (e.g., Cytoscape.js) but accept the loss of brand polish.

Chat with ghost-text autocomplete

Forensic and transcript queries use the same pattern:

<div class="input-shell">
  <div class="input-line">
    <span class="typed">user typed text</span>
    <span class="cursor"></span>
    <span class="ghost"> suggested completion</span>
  </div>
</div>
<div class="input-meta">
  <span><span class="key">TAB</span> ACCEPT</span>
  <span><span class="key"></span> RUN</span>
  <span><span class="key">⌘K</span> COMMANDS</span>
</div>

Suggestions come from the agent backend, contextual to known cameras / speakers / topics / time ranges.

Agent pipeline visualization

When a query is decomposed into sub-queries, render the pipeline as:

<div class="agent-pipeline">
  <div class="agent-step done">
    <span></span>
    <span>nlp.search(topic="contrato Acme")</span>
    <span class="timing">94ms</span>
  </div>
  <!-- ... more steps ... -->
</div>

States: done (green check), run (running, animated), pending (dimmed circle), fail (red).

Communicates "the system is doing work, here's what" and demonstrates the multi-AI fusion.

Timeline with markers

Used for forensics and transcript playback.

  • X-axis: time, with sparse axis labels (5-10 ticks).
  • Markers: vertical lines at hit positions, color-coded by type.
  • Playhead: distinct color (cyan or warn-cyan), fixed during playback.
  • Swimlanes (when multiple sources): horizontal bands per source, one row each.

Click on marker → jump player to that timestamp + scroll transcript/event list to corresponding entry.

Player shell

For both video clips (Blocao) and audio segments (transcript):

[ play | pause ]  [ scrubber with progress overlay ]   [ time MM:SS / TOTAL ]
[ controls row: ±5s, prev/next turn, speed, follow playhead, secondary actions ]
[ live caption / metadata bar ]

The shell is shared; what differs is the visualization above the scrubber (frame for video, waveform for audio).

Health test items with expandable detail

<div class="test-item warn">
  <span class="icon">!</span>
  <div class="name">FPS per camera<div class="sub">expected 15.0 ±10%</div></div>
  <div class="value">3/4 IN RANGE</div>
  <div class="test-detail">
    <div class="err-label">⚠ WARNING · cam-04 below threshold</div>
    Body explaining the issue.
    <div class="fix-suggestion">
      <strong>Likely cause:</strong> ...
    </div>
    <div class="quick-actions">
      <button class="primary">PRIMARY ACTION</button>
      <button>SECONDARY</button>
    </div>
  </div>
</div>

OK items don't expand (no info to show). Warn/err items expand with detail + suggested actions.

When to break a pattern

Patterns are starting points, not handcuffs. Break a pattern when:

  • The data shape genuinely doesn't fit (e.g., a 1000-row table doesn't belong in a card).
  • The user's primary question can't be answered with the standard layout.
  • A custom visualization is more memorable for a key moment (SYNOPSIS itself is a "broken pattern" relative to the rest of the console).

Document any pattern break with an inline code comment and, if it sticks, promote it to a new pattern in this file.