rail

package
v0.0.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package rail draws the TUI 2.0 right-hand context rail: what is pinned in the open chat, who is in it, and what has been shared there.

It replaces the modal group-info overlay. The point of the change is that context stops being something you leave the conversation to look at — the overlay covered the chat list, so checking who was in a group meant losing sight of the group.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Model

type Model struct {
	// contains filtered or unexported fields
}

Model is the rail.

func New

func New(roles theme.Roles) Model

New builds a rail with a default palette, so a Model that never has SetRoles called still renders.

func (*Model) Close

func (m *Model) Close()

Close forgets which chat the rail is pointing at, without dropping the cache: reopening it on the same chat is instant.

func (*Model) Invalidate

func (m *Model) Invalidate()

Invalidate drops everything and bumps the generation, so results already in flight are discarded when they land. Called when the account's data changes underneath the rail.

func (*Model) Open

func (m *Model) Open(chatID int64) tea.Cmd

Open points the rail at a chat and starts fetching what that chat's sections need (decision 6).

Nothing is fetched until this is called, and this is only called when the rail is opened. Opening a chat costs no rail request at all: the primary history paint never competes with rail work, and a user who keeps the rail closed never pays for it.

A chat whose data is already cached for this generation is not refetched — toggling the rail off and on is free.

func (Model) Sections

func (m Model) Sections() []Section

Sections builds what View draws, from whatever is known right now.

Every section is present whatever its state: a section that vanished while loading and reappeared when it finished would make the rail jump under the reader, and a section that vanished on failure would leave them thinking the chat has no files rather than that the request failed.

func (*Model) SetDataForTest

func (m *Model) SetDataForTest(chatID int64, pinned, files []*telegram.Message,
	members []*telegram.ChatMember, memberCount int)

SetDataForTest installs a chat's rail sections directly, as though every fetch had already answered.

The three sections arrive from three commands this component starts itself, against a client a test does not have. Without a seam a rail in a test says "unavailable" in every section, which is the one state the goldens do not draw. Same reason and same shape as chatlist.MarkLoadedForTest.

func (*Model) SetRoles

func (m *Model) SetRoles(r theme.Roles)

SetRoles supplies the TUI 2.0 semantic palette.

func (*Model) SetSize

func (m *Model) SetSize(width, height int)

SetSize sets the rail's dimensions.

func (*Model) SetStore

func (m *Model) SetStore(s *store.Store, tg *telegram.Client)

SetStore wires the data sources. A rail without them still renders its chrome and says every section is unavailable, which is what a test model and a disconnected client should both see.

func (Model) Update

func (m Model) Update(msg tea.Msg) (Model, tea.Cmd)

Update folds results in, dropping anything stale.

func (Model) View

func (m Model) View() string

View renders the rail as height rows, each exactly width cells.

type Row

type Row struct {
	Kind RowKind
	// Text is the row's main content, elided when it does not fit.
	Text string
	// Right is the trailing field: a role, a last-seen, a size. Empty for
	// rows that have none.
	Right string
	// ID is the identity a colour is hashed from, for member rows. Zero
	// elsewhere.
	ID int64
}

Row is one line of a section.

type RowKind

type RowKind int

RowKind selects a row's glyph and colour, so the palette stays inside this package rather than being decided by whoever assembled the data.

const (
	// RowPinned is a pinned message: amber bullet, muted text, ghost author.
	RowPinned RowKind = iota
	// RowMemberOnline and RowMemberOffline are people, filled or hollow.
	RowMemberOnline
	RowMemberOffline
	// RowFile is a shared document.
	RowFile
	// RowFileImage is a shared file that is a picture. It gets the mark
	// the media card gives a photo, so the same file is the same glyph
	// wherever it is drawn.
	RowFileImage
	// RowLink is a shared link.
	RowLink
	// RowMore is the "+N more" remainder under a capped list.
	RowMore
	// RowNote is an honest state line: loading, empty, or unavailable.
	RowNote
)

type Section

type Section struct {
	// Title is the heading, drawn upper case.
	Title string
	// Count is shown after the title as "· N" when non-zero. It is the
	// TOTAL, which is often larger than len(Rows) — that difference is the
	// whole reason to show it.
	Count int
	Rows  []Row
}

Section is one titled group of rows.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL