One card, in full: its title, what is known about it, and its description.
Opened with ^I over the list and centred on the terminal. Everything in it
was fetched with the board, so it opens instantly and keeps working with the
network gone — including the card it moves to next.
↑ ↓ j k ^P ^N the next or previous card ⏎ ^O open in a browser
PgUp PgDn ^D ^U scroll a long description ESC q close
Home back to the topMoving without closing
j and k walk the list with the popup still open, which is what reading
through a column is: open the first card, keep pressing j. The popup does
not hold the list — it asks Gitpro.Views.Issues to move its selection and is
handed back whatever is now selected. So the selection behind the popup moves
with it, the search and the switches still decide what "next" means, and
closing the popup leaves the cursor on the card you stopped at rather than the
one you started from.
Drawing someone else's text
An issue body is text from the internet being drawn into a terminal in raw
mode, which is the one place where that is dangerous: an escape sequence in it
would move the cursor, repaint colours the view never asked for, or set the
window title. Atui.Text.sanitize/1 takes those out, and Atui.Text.wrap/2
breaks what is left to the popup's width. Markdown is left as it was written —
a terminal that renders it is a different program, and the source of a list is
still a readable list.
Lines, then a window onto them
lines/2 turns the card into the rows to draw, and the view keeps a scroll
offset into that list. It is a pure function of the card and a width, so what
a long body looks like at forty columns is a test rather than a screenshot.
Summary
Functions
The card as the rows to draw, each with the style to draw it in.
The popup's own title: the card's number, or what it is instead.
Functions
@spec lines(Gitpro.Item.t(), integer()) :: [{String.t(), Atui.Style.t() | nil}]
The card as the rows to draw, each with the style to draw it in.
The metadata comes first and only for the fields the card actually has — an empty "Milestone:" is a row that says nothing — then a rule, then the body.
@spec title(Gitpro.Item.t()) :: String.t()
The popup's own title: the card's number, or what it is instead.