tui

package
v0.0.0-...-9f3510a Latest Latest
Warning

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

Go to latest
Published: Jan 15, 2026 License: BSD-3-Clause Imports: 22 Imported by: 0

Documentation

Overview

Package tui provides the terminal user interface for glem.

Index

Constants

View Source
const DefaultSplitRatio = 40

DefaultSplitRatio is the default left pane width percentage (40/60 split).

View Source
const DividerChar = "┋"

DividerChar is the character used for the draggable divider handle.

View Source
const DividerHandleHeight = 4

DividerHandleHeight is the number of lines the divider handle spans.

View Source
const DoubleClickThreshold = 400 * time.Millisecond

DoubleClickThreshold is the maximum time between clicks to count as double-click.

View Source
const MaxPaneWidthPercent = 80

MaxPaneWidthPercent is the maximum width for the left pane as a percentage.

View Source
const MinCommentsHeight = 3

MinCommentsHeight is the minimum height for the comments pane in lines.

View Source
const MinHeight = 15

MinHeight is the minimum terminal height.

View Source
const MinPaneWidthPercent = 20

MinPaneWidthPercent is the minimum width for either pane as a percentage.

View Source
const MinPostHeight = 4

MinPostHeight is the minimum height for the post pane in lines.

View Source
const MinWidth = 60

MinWidth is the minimum terminal width.

Variables

View Source
var (
	// ErrNotLoggedIn indicates an operation that requires login.
	ErrNotLoggedIn = errors.New("login required for this action")
	// ErrNotOwnComment indicates an attempt to edit/delete a comment not owned by the user.
	ErrNotOwnComment = errors.New("you can only edit/delete your own comments")
	// ErrCommentDeleted indicates an attempt to edit/delete an already deleted comment.
	ErrCommentDeleted = errors.New("this comment has already been deleted")
	// ErrNotOwnPost indicates an attempt to edit/delete a post not owned by the user.
	ErrNotOwnPost = errors.New("you can only edit/delete your own posts")
	// ErrPostDeleted indicates an attempt to edit/delete an already deleted post.
	ErrPostDeleted = errors.New("this post has already been deleted")
)

Sentinel errors for comment edit/delete operations.

View Source
var (
	// BaseStyle is the default text style
	BaseStyle = lipgloss.NewStyle().
				Foreground(fgMain)

	// HeaderStyle for the header bar
	HeaderStyle = lipgloss.NewStyle().
				Foreground(fgBright).
				Bold(true).
				Padding(0, 1)

	// FooterStyle for the footer bar
	FooterStyle = lipgloss.NewStyle().
				Foreground(fgDim).
				Padding(0, 1)

	// FooterErrorStyle for error messages in footer
	FooterErrorStyle = lipgloss.NewStyle().
						Foreground(red).
						Padding(0, 1)

	// TitleStyle for the app title
	TitleStyle = lipgloss.NewStyle().
				Foreground(orange).
				Bold(true)

	// SubtitleStyle for secondary header elements
	SubtitleStyle = lipgloss.NewStyle().
					Foreground(fgMuted)

	// SeparatorStyle for the header separator character
	SeparatorStyle = lipgloss.NewStyle().
					Foreground(bgMuted)

	// Header element styles (icons coloured, values bright)
	HeaderTitleStyle = lipgloss.NewStyle().
						Foreground(orange).
						Bold(true)

	HeaderInstanceIconStyle = lipgloss.NewStyle().
							Foreground(cyan)

	HeaderSortIconStyle = lipgloss.NewStyle().
						Foreground(green)

	HeaderFeedIconStyle = lipgloss.NewStyle().
						Foreground(blue)

	HeaderPageIconStyle = lipgloss.NewStyle().
						Foreground(yellow)

	HeaderViewIconStyle = lipgloss.NewStyle().
						Foreground(purple)

	HeaderValueStyle = lipgloss.NewStyle().
						Foreground(fgBright)

	HeaderHelpStyle = lipgloss.NewStyle().
					Foreground(fgMuted)
)

Base styles

View Source
var (
	// FocusedPaneStyle for the currently focused pane
	FocusedPaneStyle = lipgloss.NewStyle().
						Border(lipgloss.RoundedBorder()).
						BorderForeground(yellow)

	// UnfocusedPaneStyle for inactive panes
	UnfocusedPaneStyle = lipgloss.NewStyle().
						Border(lipgloss.RoundedBorder()).
						BorderForeground(bgMuted)

	// NoBorderPaneStyle for panes without borders
	NoBorderPaneStyle = lipgloss.NewStyle()
)

Pane styles

View Source
var (
	// PostTitleStyle for post titles
	PostTitleStyle = lipgloss.NewStyle().
					Foreground(fgMain)

	// PostTitleSelectedStyle for selected post title
	PostTitleSelectedStyle = lipgloss.NewStyle().
							Foreground(fgBright).
							Bold(true)

	// CommunityStyle for community names
	CommunityStyle = lipgloss.NewStyle().
					Foreground(cyan)

	// AuthorStyle for author/user names
	AuthorStyle = lipgloss.NewStyle().
				Foreground(blue)

	// URLStyle for post URLs
	URLStyle = lipgloss.NewStyle().
				Foreground(blue).
				Underline(true)

	// MetaStyle for metadata text
	MetaStyle = lipgloss.NewStyle().
				Foreground(fgMuted)

	// SelectedRowStyle for highlighted rows
	SelectedRowStyle = lipgloss.NewStyle().
						Background(bgSelect)

	// CursorStyle for the selection cursor
	CursorStyle = lipgloss.NewStyle().
				Foreground(yellow).
				Bold(true)

	// PostDateStyle for post age/date display
	PostDateStyle = lipgloss.NewStyle().
					Foreground(purple)

	// NSFWBadgeStyle for NSFW content warning badge
	NSFWBadgeStyle = lipgloss.NewStyle().
					Foreground(fgBright).
					Background(red).
					Bold(true).
					Padding(0, 1)
)

Post styles

View Source
var (
	// PositiveScoreStyle for positive scores
	PositiveScoreStyle = lipgloss.NewStyle().
						Foreground(green)

	// NegativeScoreStyle for negative scores
	NegativeScoreStyle = lipgloss.NewStyle().
						Foreground(red)

	// ZeroScoreStyle for zero scores
	ZeroScoreStyle = lipgloss.NewStyle().
					Foreground(fgSubtle)
)

Score styles

View Source
var (
	// UpvotedScoreStyle for scores where the user has upvoted (bright cyan/teal).
	UpvotedScoreStyle = lipgloss.NewStyle().
						Foreground(lipgloss.Color("#00d7d7")).
						Bold(true)

	// DownvotedScoreStyle for scores where the user has downvoted (orange/amber).
	DownvotedScoreStyle = lipgloss.NewStyle().
						Foreground(lipgloss.Color("#ff8c00")).
						Bold(true)
)

Vote state score styles (distinct from score-based colours)

View Source
var (
	// CommentHeaderStyle for comment author/meta line
	CommentHeaderStyle = lipgloss.NewStyle().
						Foreground(fgDim)

	// CommentBodyStyle for comment content
	CommentBodyStyle = lipgloss.NewStyle().
						Foreground(fgBright)

	// TreeBranchStyle for tree-style comment connectors
	TreeBranchStyle = lipgloss.NewStyle().
					Foreground(bgMuted)
)

Comment styles

View Source
var (
	// SectionHeaderStyle for section headers like "COMMENTS"
	SectionHeaderStyle = lipgloss.NewStyle().
						Foreground(orange).
						Bold(true)

	// DividerStyle for horizontal dividers
	DividerStyle = lipgloss.NewStyle().
					Foreground(bgSubtle)
)

Section styles

View Source
var (
	// LoginTitleStyle for the login screen title
	LoginTitleStyle = lipgloss.NewStyle().
					Foreground(orange).
					Bold(true).
					MarginBottom(1)

	// LoginSubtitleStyle for the login screen subtitle
	LoginSubtitleStyle = lipgloss.NewStyle().
						Foreground(fgMuted).
						MarginBottom(2)

	// InputLabelStyle for input field labels
	InputLabelStyle = lipgloss.NewStyle().
					Foreground(fgDim).
					Width(15)

	// InputHintStyle for optional field hints
	InputHintStyle = lipgloss.NewStyle().
					Foreground(fgSubtle).
					Italic(true)

	// ButtonStyle for action buttons
	ButtonStyle = lipgloss.NewStyle().
				Foreground(bgMain).
				Background(yellow).
				Padding(0, 2).
				Bold(true)
)

Login screen styles

View Source
var (
	// HelpBoxStyle for the help overlay container
	HelpBoxStyle = lipgloss.NewStyle().
					Border(lipgloss.DoubleBorder()).
					BorderForeground(yellow).
					Padding(1, 2)

	// HelpTitleStyle for the help overlay title
	HelpTitleStyle = lipgloss.NewStyle().
					Foreground(orange).
					Bold(true).
					Align(lipgloss.Center)

	// HelpSectionStyle for help section headers
	HelpSectionStyle = lipgloss.NewStyle().
						Foreground(yellow).
						Bold(true).
						MarginTop(1)

	// HelpKeyStyle for key descriptions
	HelpKeyStyle = lipgloss.NewStyle().
					Foreground(cyan).
					Width(16)

	// HelpDescStyle for key action descriptions
	HelpDescStyle = lipgloss.NewStyle().
					Foreground(fgDim)
)

Help overlay styles

View Source
var (
	// LoadingStyle for loading indicators
	LoadingStyle = lipgloss.NewStyle().
					Foreground(yellow)

	// ErrorStyle for error messages
	ErrorStyle = lipgloss.NewStyle().
				Foreground(red)

	// SuccessStyle for success messages
	SuccessStyle = lipgloss.NewStyle().
					Foreground(green)

	// WarningStyle for warning messages
	WarningStyle = lipgloss.NewStyle().
					Foreground(yellow).
					Bold(true)
)

Loading and status styles

View Source
var (
	// PaneTitleActiveStyle for active pane title header
	PaneTitleActiveStyle = lipgloss.NewStyle().
							Foreground(yellow).
							Bold(true)

	// PaneTitleInactiveStyle for inactive pane title header
	PaneTitleInactiveStyle = lipgloss.NewStyle().
							Foreground(fgSubtle)

	// ActivePaneBackgroundStyle for subtle background tint on active pane
	ActivePaneBackgroundStyle = lipgloss.NewStyle().
								Background(lipgloss.Color("#2a2a2a")) // Slightly lighter than bgMain (#242424)
)

Pane indicator styles

View Source
var (
	// SearchBoxStyle for the search overlay container
	SearchBoxStyle = lipgloss.NewStyle().
					Border(lipgloss.RoundedBorder()).
					BorderForeground(yellow).
					Padding(1, 2)

	// SearchTitleStyle for the search overlay title
	SearchTitleStyle = lipgloss.NewStyle().
						Foreground(orange).
						Bold(true).
						Align(lipgloss.Center)

	// SearchInputStyle for the search input field
	SearchInputStyle = lipgloss.NewStyle().
						Foreground(fgBright).
						Background(bgLight).
						Padding(0, 1)

	// SearchLabelStyle for labels in the search overlay
	SearchLabelStyle = lipgloss.NewStyle().
						Foreground(fgDim)

	// SearchTypeActiveStyle for the active search type
	SearchTypeActiveStyle = lipgloss.NewStyle().
							Foreground(bgMain).
							Background(yellow).
							Bold(true).
							Padding(0, 1)

	// SearchTypeInactiveStyle for inactive search types
	SearchTypeInactiveStyle = lipgloss.NewStyle().
							Foreground(fgMuted).
							Padding(0, 1)

	// SearchHintStyle for hints in the search overlay
	SearchHintStyle = lipgloss.NewStyle().
					Foreground(fgSubtle).
					Italic(true)
)

Search overlay styles

View Source
var (
	// CommentSelectionCursor is the cursor character for selected comments.
	CommentSelectionCursor = "▶"

	// CommentSelectionCursorStyle for the cursor indicator.
	CommentSelectionCursorStyle = lipgloss.NewStyle().
								Foreground(yellow).
								Bold(true)

	// CommentSelectionHighlightStyle for background highlight on selected comments.
	CommentSelectionHighlightStyle = lipgloss.NewStyle().
									Background(bgSelect)

	// CommentSelectionBorderStyle for border box around selected comments.
	CommentSelectionBorderStyle = lipgloss.NewStyle().
								Border(lipgloss.RoundedBorder()).
								BorderForeground(yellow)
)

Comment selection styles

View Source
var (
	// CertWarningIcon is the icon shown for informational certificate warnings (self-signed).
	CertWarningIcon = "⚠"

	// CertUrgentIcon is the icon shown for urgent certificate warnings (expiring soon).
	CertUrgentIcon = "󰌾"

	// CertWarningIconStyle for the warning icon next to server name (orange, informational)
	CertWarningIconStyle = lipgloss.NewStyle().
							Foreground(orange).
							Bold(true)

	// CertUrgentIconStyle for the warning icon when certificate is expiring soon (yellow, urgent)
	CertUrgentIconStyle = lipgloss.NewStyle().
						Foreground(yellow).
						Bold(true)

	// CertWarningTextStyle for the warning text on the right side (orange)
	CertWarningTextStyle = lipgloss.NewStyle().
							Foreground(orange)

	// CertUrgentTextStyle for urgent warning text (yellow, bold)
	CertUrgentTextStyle = lipgloss.NewStyle().
						Foreground(yellow).
						Bold(true)
)

Certificate warning styles

View Source
var (
	// ComposerBoxStyle for the composer overlay container
	ComposerBoxStyle = lipgloss.NewStyle().
						Border(lipgloss.RoundedBorder()).
						BorderForeground(yellow).
						Padding(1, 2)

	// ComposerTitleStyle for the composer overlay title
	ComposerTitleStyle = lipgloss.NewStyle().
						Foreground(orange).
						Bold(true).
						Align(lipgloss.Center)

	// ComposerQuoteStyle for quoted parent content
	ComposerQuoteStyle = lipgloss.NewStyle().
						Foreground(fgMuted).
						Italic(true).
						PaddingLeft(2).
						BorderLeft(true).
						BorderStyle(lipgloss.NormalBorder()).
						BorderForeground(fgSubtle)

	// ComposerHelpStyle for help text in the composer
	ComposerHelpStyle = lipgloss.NewStyle().
						Foreground(fgSubtle).
						Align(lipgloss.Center)
)

Comment composer styles

View Source
var (
	// ConfirmBoxStyle for the confirmation dialog container
	ConfirmBoxStyle = lipgloss.NewStyle().
					Border(lipgloss.RoundedBorder()).
					BorderForeground(yellow).
					Padding(1, 2)

	// ConfirmTitleStyle for the confirmation dialog title
	ConfirmTitleStyle = lipgloss.NewStyle().
						Foreground(orange).
						Bold(true).
						Align(lipgloss.Center)

	// ConfirmMessageStyle for the confirmation dialog message
	ConfirmMessageStyle = lipgloss.NewStyle().
						Foreground(fgMain).
						Align(lipgloss.Center)

	// ConfirmHelpStyle for help text in the confirmation dialog
	ConfirmHelpStyle = lipgloss.NewStyle().
						Foreground(fgSubtle).
						Align(lipgloss.Center)
)

Confirmation dialog styles

View Source
var (
	// HorizontalDividerHandle is the character sequence for the draggable handle.
	HorizontalDividerHandle = "┉┉┉┉┉"

	// HorizontalDividerHandleWidth is the width of the handle in characters.
	HorizontalDividerHandleWidth = 5

	// HorizontalDividerStyle for the horizontal divider line.
	HorizontalDividerStyle = lipgloss.NewStyle().
							Foreground(fgSubtle)

	// HorizontalDividerHandleStyle for the draggable handle portion.
	HorizontalDividerHandleStyle = lipgloss.NewStyle().
									Foreground(fgMuted)

	// HorizontalDividerHandleActiveStyle for the handle when being dragged.
	HorizontalDividerHandleActiveStyle = lipgloss.NewStyle().
										Foreground(yellow)
)

Horizontal divider styles for Post/Comments split

View Source
var (
	// VoteUpIcon is the upvote arrow indicator.
	VoteUpIcon = "▲"

	// VoteDownIcon is the downvote arrow indicator.
	VoteDownIcon = "▼"

	// VoteNeutralIcon is the neutral (no vote) indicator.
	VoteNeutralIcon = "•"

	// VoteUpStyle for upvoted items (orange).
	VoteUpStyle = lipgloss.NewStyle().
				Foreground(orange).
				Bold(true)

	// VoteDownStyle for downvoted items (blue).
	VoteDownStyle = lipgloss.NewStyle().
					Foreground(blue).
					Bold(true)

	// VoteNeutralStyle for items with no vote.
	VoteNeutralStyle = lipgloss.NewStyle().
						Foreground(fgSubtle)
)

Vote indicator styles

View Source
var (
	// MetaSeparatorDot is the styled dot separator used between metadata items.
	MetaSeparatorDot = MetaStyle.Render(" · ")

	// MetaSeparatorPipe is the styled pipe separator used between metadata items.
	MetaSeparatorPipe = MetaStyle.Render(" | ")
)

Separator styles

View Source
var (
	// OPBadgeStyle for the [op] badge (original poster).
	OPBadgeStyle = lipgloss.NewStyle().
					Foreground(blue).
					Bold(true)

	// AdminBadgeStyle for the [admin] badge.
	AdminBadgeStyle = lipgloss.NewStyle().
					Foreground(orange).
					Bold(true)

	// BotBadgeStyle for the [bot] badge.
	BotBadgeStyle = lipgloss.NewStyle().
					Foreground(fgMuted)

	// PinnedBadgeStyle for the [pinned] badge (distinguished comments).
	PinnedBadgeStyle = lipgloss.NewStyle().
						Foreground(cyan).
						Bold(true)

	// EditedStyle for the (edited) indicator.
	EditedStyle = lipgloss.NewStyle().
				Foreground(fgSubtle).
				Italic(true)

	// DeletedContentStyle for [deleted] placeholder text.
	DeletedContentStyle = lipgloss.NewStyle().
						Foreground(fgMuted).
						Italic(true)

	// RemovedContentStyle for [removed] placeholder text.
	RemovedContentStyle = lipgloss.NewStyle().
						Foreground(fgMuted).
						Italic(true)

	// ReplyCountStyle for the reply count indicator when collapsed.
	ReplyCountStyle = lipgloss.NewStyle().
					Foreground(fgSubtle)
)

Comment badge styles

View Source
var (
	// LinkBadgeStyle for the [link] or [L] badge.
	LinkBadgeStyle = lipgloss.NewStyle().
					Foreground(blue)

	// ImageBadgeStyle for the [image] or [I] badge.
	ImageBadgeStyle = lipgloss.NewStyle().
					Foreground(green)

	// TextBadgeStyle for the [text] or [T] badge.
	TextBadgeStyle = lipgloss.NewStyle().
					Foreground(fgSubtle)
)

Post type badge styles

View Source
var (
	// PinnedPostBadgeStyle for the [pinned] or [P] badge on posts.
	PinnedPostBadgeStyle = lipgloss.NewStyle().
							Foreground(cyan).
							Bold(true)

	// LockedBadgeStyle for the [locked] or [X] badge.
	LockedBadgeStyle = lipgloss.NewStyle().
						Foreground(orange)

	// DeletedPostBadgeStyle for the [deleted] or [D] badge on posts.
	DeletedPostBadgeStyle = lipgloss.NewStyle().
							Foreground(fgMuted).
							Italic(true)
)

Post status badge styles

View Source
var (
	// DotsSeparatorStyle for dotted line separators.
	DotsSeparatorStyle = lipgloss.NewStyle().
						Foreground(fgMuted)

	// CenteredSeparatorStyle for short centered line separators.
	CenteredSeparatorStyle = lipgloss.NewStyle().
							Foreground(fgMuted)

	// ThinSeparatorStyle for indented thin line separators.
	ThinSeparatorStyle = lipgloss.NewStyle().
						Foreground(fgMuted)
)

Separator styles for feed posts

View Source
var (
	// UpvoteCountStyle for upvote count in breakdown.
	UpvoteCountStyle = lipgloss.NewStyle().
						Foreground(green)

	// DownvoteCountStyle for downvote count in breakdown.
	DownvoteCountStyle = lipgloss.NewStyle().
						Foreground(blue)
)

Vote breakdown styles

View Source
var (
	// DetailBodyStyle for post body text in the detail pane
	DetailBodyStyle = lipgloss.NewStyle().
		Foreground(fgBright)
)

Detail pane styles

View Source
var EmptyStateStyle = lipgloss.NewStyle().
	Foreground(fgMuted).
	Align(lipgloss.Center)

EmptyStateStyle for empty state messages

View Source
var (
	// ModBadgeStyle for the [mod] or [M] badge.
	ModBadgeStyle = lipgloss.NewStyle().
		Foreground(green).
		Bold(true)
)

Author badge styles for posts

View Source
var (
	// ScrollPercentStyle for scroll percentage indicator
	ScrollPercentStyle = lipgloss.NewStyle().
		Foreground(fgSubtle)
)

Scrollbar styles

Functions

func GetDepthColor

func GetDepthColor(depth int) lipgloss.Color

GetDepthColor returns a colour for the given comment depth.

func GetMetaSeparator

func GetMetaSeparator(style string) string

GetMetaSeparator returns the appropriate styled separator based on the style setting. Valid styles are "dot" and "pipe". Defaults to dot if invalid.

func GetScoreStyle

func GetScoreStyle(score int) lipgloss.Style

GetScoreStyle returns the appropriate style for a score value.

func GetVotedScoreStyle

func GetVotedScoreStyle(score int, myVote *int) lipgloss.Style

GetVotedScoreStyle returns the appropriate style for a score value, taking into account the user's vote state. If myVote is nil or 0, falls back to score-based colouring. If myVote is 1 (upvoted), returns bright cyan style. If myVote is -1 (downvoted), returns orange/amber style.

func RenderMarkdown

func RenderMarkdown(content string, width int) string

RenderMarkdown is a convenience function for one-off markdown rendering.

Types

type App

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

App is the main application model.

func NewApp

func NewApp(cfg config.Config) *App

NewApp creates a new application model.

func NewDemoApp

func NewDemoApp(cfg config.Config, posts []api.PostView, comments []api.CommentView) *App

NewDemoApp creates an application model pre-populated with mock data. This skips the login screen and displays the main view immediately, allowing rapid UI testing without a live Lemmy connection.

func (*App) GetDemoCommentVote

func (a *App) GetDemoCommentVote(commentID int) *int

GetDemoCommentVote returns the simulated vote for a comment in demo mode.

func (*App) GetDemoPostVote

func (a *App) GetDemoPostVote(postID int) *int

GetDemoPostVote returns the simulated vote for a post in demo mode.

func (*App) GetEnableDownvotes

func (a *App) GetEnableDownvotes() bool

GetEnableDownvotes returns whether downvotes are enabled on this instance.

func (*App) Init

func (a *App) Init() tea.Cmd

Init initializes the application.

func (*App) SetBorderless

func (a *App) SetBorderless(borderless bool)

SetBorderless enables or disables the outer border rendering.

func (*App) SetCertStatus

func (a *App) SetCertStatus(status *api.CertStatus)

SetCertStatus sets the TLS certificate status for security indicators.

func (*App) Update

func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles messages for the application.

func (*App) View

func (a *App) View() string

View renders the application.

type CancelComposeMsg

type CancelComposeMsg struct{}

CancelComposeMsg signals that the user cancelled comment composition.

type CancelCreatePostMsg

type CancelCreatePostMsg struct{}

CancelCreatePostMsg signals that the user cancelled post creation.

type CertCheckMsg

type CertCheckMsg struct {
	Status   *api.CertStatus // Certificate status information
	Hostname string          // Hostname of the server
	Err      error           // Error if connection check failed
}

CertCheckMsg carries the result of a TLS certificate check.

type CertTrustDecisionMsg

type CertTrustDecisionMsg struct {
	Decision    TrustDecision
	Hostname    string // Hostname of the server
	Fingerprint string // Certificate fingerprint (SHA-256)
}

CertTrustDecisionMsg carries the user's trust decision for a certificate.

type ClearCommunityFilterMsg

type ClearCommunityFilterMsg struct{}

ClearCommunityFilterMsg signals that the community filter should be cleared.

type CloseCommunityBrowserMsg

type CloseCommunityBrowserMsg struct{}

CloseCommunityBrowserMsg signals that the community browser should be closed.

type CommentStyle

type CommentStyle int

CommentStyle represents the display style for comments.

const (
	// CommentStyleTree shows tree-style connectors (default).
	CommentStyleTree CommentStyle = iota
	// CommentStyleIndent shows space indentation.
	CommentStyleIndent
	// CommentStyleColored shows colored depth borders.
	CommentStyleColored
)

type CommentSubmitErrorMsg

type CommentSubmitErrorMsg struct {
	Err error
}

CommentSubmitErrorMsg indicates a comment submission failed.

type CommentSubmittedMsg

type CommentSubmittedMsg struct {
	Comment api.CommentView // The newly created comment
}

CommentSubmittedMsg indicates a comment was successfully submitted.

type CommentVoteResultMsg

type CommentVoteResultMsg struct {
	CommentView api.CommentView
	Err         error
}

CommentVoteResultMsg carries the result of a comment vote action.

type CommentsLoadedMsg

type CommentsLoadedMsg struct {
	Comments []api.CommentView
}

CommentsLoadedMsg carries comments for a post.

type CommentsModel

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

CommentsModel handles the comments pane state and rendering. It displays comments for the currently selected post with support for three visual styles (indent, tree, coloured) and provides navigation with automatic selection when scrolling.

func NewCommentsModel

func NewCommentsModel(defaultStyle string, autoSelectOnFocus, openURLEnabled bool, metaSeparatorStyle string) CommentsModel

NewCommentsModel creates a new comments pane model.

func (*CommentsModel) CancelDeleteConfirm

func (m *CommentsModel) CancelDeleteConfirm()

CancelDeleteConfirm cancels any pending delete confirmation.

func (*CommentsModel) ClearSelection

func (m *CommentsModel) ClearSelection()

ClearSelection deselects any selected comment.

func (*CommentsModel) GetCommentCount

func (m *CommentsModel) GetCommentCount() int

GetCommentCount returns the number of comments.

func (*CommentsModel) GetComments

func (m *CommentsModel) GetComments() []api.CommentView

GetComments returns a copy of the current comments slice.

func (*CommentsModel) GetCurrentUserID

func (m *CommentsModel) GetCurrentUserID() int

GetCurrentUserID returns the current user's ID.

func (*CommentsModel) GetDeleteConfirmCommentID

func (m *CommentsModel) GetDeleteConfirmCommentID() int

GetDeleteConfirmCommentID returns the ID of the comment pending delete confirmation.

func (*CommentsModel) GetPostCreatorID

func (m *CommentsModel) GetPostCreatorID() int

GetPostCreatorID returns the post creator ID.

func (*CommentsModel) GetSelectedComment

func (m *CommentsModel) GetSelectedComment() *api.CommentView

GetSelectedComment returns the currently selected comment, or nil if none.

func (*CommentsModel) GetSelectedCommentIdx

func (m *CommentsModel) GetSelectedCommentIdx() int

GetSelectedCommentIdx returns the currently selected comment index. Returns -1 if no comment is selected.

func (CommentsModel) Init

func (m CommentsModel) Init() tea.Cmd

Init initialises the comments model.

func (*CommentsModel) IsDeleteConfirmPending

func (m *CommentsModel) IsDeleteConfirmPending() bool

IsDeleteConfirmPending returns whether a delete confirmation is pending.

func (*CommentsModel) IsFocused

func (m *CommentsModel) IsFocused() bool

IsFocused returns whether this pane is focused.

func (*CommentsModel) IsLoading

func (m *CommentsModel) IsLoading() bool

IsLoading returns whether the comments pane is loading.

func (*CommentsModel) IsSelectedOwnedByUser

func (m *CommentsModel) IsSelectedOwnedByUser(userID int) bool

IsSelectedOwnedByUser returns true if the currently selected comment is owned by the given user ID.

func (*CommentsModel) ScrollPercent

func (m *CommentsModel) ScrollPercent() float64

ScrollPercent returns the current scroll percentage.

func (*CommentsModel) SetComments

func (m *CommentsModel) SetComments(comments []api.CommentView)

SetComments sets the comments to display. Comments are sorted by path for proper threading and descendant counts are pre-computed.

func (*CommentsModel) SetCurrentUserID

func (m *CommentsModel) SetCurrentUserID(userID int)

SetCurrentUserID sets the current user's ID for ownership checks.

func (*CommentsModel) SetFocused

func (m *CommentsModel) SetFocused(focused bool)

SetFocused sets whether this pane is focused. When focused with autoSelectOnFocus enabled, auto-selects the first comment.

func (*CommentsModel) SetLoading

func (m *CommentsModel) SetLoading(loading bool)

SetLoading sets the loading state.

func (*CommentsModel) SetPostCreatorID

func (m *CommentsModel) SetPostCreatorID(creatorID int)

SetPostCreatorID sets the post creator ID for [op] badge detection.

func (*CommentsModel) SetPostID

func (m *CommentsModel) SetPostID(postID int)

SetPostID sets the post ID for compose/reply actions.

func (*CommentsModel) SetShowHeader

func (m *CommentsModel) SetShowHeader(show bool)

SetShowHeader sets whether the internal pane header should be rendered. Set to false in three-column mode where headers are rendered externally.

func (*CommentsModel) SetSize

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

SetSize updates the dimensions of the comments pane.

func (*CommentsModel) SetSpinnerFrame

func (m *CommentsModel) SetSpinnerFrame(frame string)

SetSpinnerFrame sets the current spinner animation frame.

func (CommentsModel) Update

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

Update handles messages for the comments pane.

func (CommentsModel) View

func (m CommentsModel) View() string

View renders the comments pane.

type CommunitiesLoadedMsg

type CommunitiesLoadedMsg struct {
	Communities []api.CommunityView
}

CommunitiesLoadedMsg carries loaded communities from the API.

type CommunityBrowserModel

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

CommunityBrowserModel handles the community browser overlay. This overlay allows users to browse and select communities for filtering.

func NewCommunityBrowserModel

func NewCommunityBrowserModel() CommunityBrowserModel

NewCommunityBrowserModel creates a new community browser model.

func (*CommunityBrowserModel) GetListingType

func (m *CommunityBrowserModel) GetListingType() api.ListingType

GetListingType returns the current listing type filter.

func (*CommunityBrowserModel) GetSelectedCommunity

func (m *CommunityBrowserModel) GetSelectedCommunity() (api.CommunityView, bool)

GetSelectedCommunity returns the currently selected community, if any.

func (*CommunityBrowserModel) Hide

func (m *CommunityBrowserModel) Hide()

Hide hides the browser overlay.

func (CommunityBrowserModel) Init

func (m CommunityBrowserModel) Init() tea.Cmd

Init initialises the community browser model.

func (*CommunityBrowserModel) IsVisible

func (m *CommunityBrowserModel) IsVisible() bool

IsVisible returns whether the browser overlay is visible.

func (*CommunityBrowserModel) SetCommunities

func (m *CommunityBrowserModel) SetCommunities(communities []api.CommunityView)

SetCommunities updates the list of communities.

func (*CommunityBrowserModel) SetLoading

func (m *CommunityBrowserModel) SetLoading(loading bool)

SetLoading sets the loading state.

func (*CommunityBrowserModel) SetSize

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

SetSize updates the dimensions of the browser overlay.

func (*CommunityBrowserModel) Show

func (m *CommunityBrowserModel) Show()

Show makes the browser visible.

func (CommunityBrowserModel) Update

Update handles messages for the community browser overlay.

func (*CommunityBrowserModel) UpdateCommunity

func (m *CommunityBrowserModel) UpdateCommunity(updated api.CommunityView)

UpdateCommunity updates a specific community in the list (e.g., after follow/unfollow).

func (CommunityBrowserModel) View

func (m CommunityBrowserModel) View() string

View renders the community browser overlay.

type CommunityLoadedMsg

type CommunityLoadedMsg struct {
	Community api.CommunityView
}

CommunityLoadedMsg carries a single community's details.

type ComposeMode

type ComposeMode int

ComposeMode represents whether composing a new comment or a reply.

const (
	// ComposeModeNewComment is for creating a new top-level comment.
	ComposeModeNewComment ComposeMode = iota
	// ComposeModeReply is for replying to an existing comment.
	ComposeModeReply
	// ComposeModeEdit is for editing an existing comment.
	ComposeModeEdit
)

type ComposerModel

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

ComposerModel handles the comment composition overlay.

func NewComposerModel

func NewComposerModel() ComposerModel

NewComposerModel creates a new comment composer model.

func (*ComposerModel) FocusTextarea

func (m *ComposerModel) FocusTextarea() tea.Cmd

FocusTextarea returns a blink command to start cursor blinking. Note: We don't return textarea.Focus() as it causes terminal query delays.

func (*ComposerModel) ForceHide

func (m *ComposerModel) ForceHide()

ForceHide hides the composer without checking for unsaved changes. Used after user confirms discard.

func (*ComposerModel) GetContent

func (m *ComposerModel) GetContent() string

GetContent returns the current content of the textarea.

func (*ComposerModel) GetEditCommentID

func (m *ComposerModel) GetEditCommentID() int

GetEditCommentID returns the comment ID being edited (only valid in edit mode).

func (*ComposerModel) GetMode

func (m *ComposerModel) GetMode() ComposeMode

GetMode returns the current compose mode.

func (*ComposerModel) GetOriginalContent

func (m *ComposerModel) GetOriginalContent() string

GetOriginalContent returns the original content before editing (only valid in edit mode).

func (*ComposerModel) GetParentCommentID

func (m *ComposerModel) GetParentCommentID() int

GetParentCommentID returns the parent comment ID (0 for top-level).

func (*ComposerModel) GetPostID

func (m *ComposerModel) GetPostID() int

GetPostID returns the post ID being commented on.

func (*ComposerModel) HasUnsavedChanges

func (m *ComposerModel) HasUnsavedChanges() bool

HasUnsavedChanges returns true if the current content differs from the original.

func (*ComposerModel) Hide

func (m *ComposerModel) Hide()

Hide hides the composer overlay.

func (ComposerModel) Init

func (m ComposerModel) Init() tea.Cmd

Init initialises the composer model.

func (*ComposerModel) IsVisible

func (m *ComposerModel) IsVisible() bool

IsVisible returns whether the composer overlay is visible.

func (*ComposerModel) SetSize

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

SetSize updates the dimensions of the composer overlay.

func (*ComposerModel) Show

func (m *ComposerModel) Show(postID, parentCommentID int, parentAuthor, parentContent string)

Show makes the composer visible and sets up the composition context.

func (*ComposerModel) ShowEdit

func (m *ComposerModel) ShowEdit(commentID int, content string)

ShowEdit makes the composer visible in edit mode with pre-populated content.

func (ComposerModel) Update

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

Update handles messages for the composer overlay.

func (ComposerModel) View

func (m ComposerModel) View() string

View renders the composer overlay.

type ConfirmDiscardMsg

type ConfirmDiscardMsg struct {
	Confirmed bool // true if user confirmed discard, false if cancelled
}

ConfirmDiscardMsg signals the user's response to the discard confirmation.

type ConfirmModel

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

ConfirmModel handles simple yes/no confirmation dialogs.

func NewConfirmModel

func NewConfirmModel() ConfirmModel

NewConfirmModel creates a new confirmation dialog model.

func (*ConfirmModel) GetConfirmType

func (m *ConfirmModel) GetConfirmType() ConfirmType

GetConfirmType returns the type of confirmation being shown.

func (*ConfirmModel) Hide

func (m *ConfirmModel) Hide()

Hide hides the confirmation dialog.

func (ConfirmModel) Init

func (m ConfirmModel) Init() tea.Cmd

Init initialises the confirm model.

func (*ConfirmModel) IsVisible

func (m *ConfirmModel) IsVisible() bool

IsVisible returns whether the confirmation dialog is visible.

func (*ConfirmModel) SetSize

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

SetSize updates the dimensions of the confirmation dialog.

func (*ConfirmModel) ShowDelete

func (m *ConfirmModel) ShowDelete(itemType string)

ShowDelete shows the delete confirmation dialog.

func (*ConfirmModel) ShowDiscard

func (m *ConfirmModel) ShowDiscard()

ShowDiscard shows the discard changes confirmation dialog.

func (ConfirmModel) Update

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

Update handles messages for the confirmation dialog.

func (ConfirmModel) View

func (m ConfirmModel) View() string

View renders the confirmation dialog.

type ConfirmType

type ConfirmType int

ConfirmType represents the type of confirmation dialog.

const (
	// ConfirmTypeDiscard is for discarding unsaved changes.
	ConfirmTypeDiscard ConfirmType = iota
	// ConfirmTypeDelete is for confirming deletion.
	ConfirmTypeDelete
)

type DeleteCommentErrorMsg

type DeleteCommentErrorMsg struct {
	Err error // The validation error (e.g., not own comment, already deleted)
}

DeleteCommentErrorMsg indicates a local validation error for delete operation.

type DeleteCommentRequestMsg

type DeleteCommentRequestMsg struct {
	CommentID int // ID of the comment to delete
}

DeleteCommentRequestMsg signals that the user wants to delete a comment.

type DeleteCommentResultMsg

type DeleteCommentResultMsg struct {
	CommentView api.CommentView // The updated comment view (with Deleted=true)
	Err         error           // Error if the delete failed
}

DeleteCommentResultMsg carries the result of a delete operation.

type DeleteConfirmPromptMsg

type DeleteConfirmPromptMsg struct {
	CommentID int // ID of the comment pending deletion
}

DeleteConfirmPromptMsg signals that the delete confirmation prompt should be shown.

type DeletePostConfirmPromptMsg

type DeletePostConfirmPromptMsg struct {
	PostID int // ID of the post pending deletion
}

DeletePostConfirmPromptMsg signals that the delete confirmation prompt should be shown.

type DeletePostErrorMsg

type DeletePostErrorMsg struct {
	Err error // The validation error (e.g., not own post, already deleted)
}

DeletePostErrorMsg indicates a local validation error for delete operation.

type DeletePostRequestMsg

type DeletePostRequestMsg struct {
	PostID int // ID of the post to delete
}

DeletePostRequestMsg signals that the user wants to delete a post.

type DeletePostResultMsg

type DeletePostResultMsg struct {
	Post api.PostView // The updated post view (with Deleted=true)
	Err  error        // Error if the delete failed
}

DeletePostResultMsg carries the result of a delete operation.

type DemoLoadingCompleteMsg

type DemoLoadingCompleteMsg struct {
	Target string // "posts" or "detail"
}

DemoLoadingCompleteMsg signals that simulated loading has finished.

type EditCommentErrorMsg

type EditCommentErrorMsg struct {
	Err error // The validation error (e.g., not own comment, already deleted)
}

EditCommentErrorMsg indicates a local validation error for edit operation.

type EditCommentResultMsg

type EditCommentResultMsg struct {
	CommentView api.CommentView // The updated comment view
	Err         error           // Error if the edit failed
}

EditCommentResultMsg carries the result of an edit operation.

type EditCommentSubmitMsg

type EditCommentSubmitMsg struct {
	CommentID int    // ID of the comment being edited
	Content   string // The updated comment content
}

EditCommentSubmitMsg carries the edited comment to be submitted.

type EditPostErrorMsg

type EditPostErrorMsg struct {
	Err error // The validation error (e.g., not own post, already deleted)
}

EditPostErrorMsg indicates a local validation error for edit operation.

type EditPostResultMsg

type EditPostResultMsg struct {
	Post api.PostView // The updated post view
	Err  error        // Error if the edit failed
}

EditPostResultMsg carries the result of an edit operation.

type EditPostSubmitMsg

type EditPostSubmitMsg struct {
	PostID int    // ID of the post being edited
	Title  string // Updated title
	URL    string // Updated URL
	Body   string // Updated body
	NSFW   bool   // Updated NSFW flag
}

EditPostSubmitMsg carries the edited post data to be submitted.

type ErrorMsg

type ErrorMsg struct {
	Err error
}

ErrorMsg carries an error from an async operation.

type FeedConfig

type FeedConfig struct {
	DefaultSort          string
	DefaultFeed          string
	FeedStyle            string
	TextPostPreview      bool
	Separator            string
	TruncateNameInstance string
	ShowPostBadges       string
	MetaSeparatorStyle   string
}

FeedConfig holds configuration options for the feed display.

type FeedModel

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

FeedModel handles the feed pane state and rendering.

func NewFeedModel

func NewFeedModel(cfg FeedConfig) FeedModel

NewFeedModel creates a new feed model with the given configuration.

func (*FeedModel) ClearCommunityFilter

func (m *FeedModel) ClearCommunityFilter()

ClearCommunityFilter removes the community filter.

func (*FeedModel) GetCommunityFilter

func (m *FeedModel) GetCommunityFilter() (int, string)

GetCommunityFilter returns the current community filter (ID and name). Returns (0, "") if no filter is active.

func (*FeedModel) GetCommunityName

func (m *FeedModel) GetCommunityName() string

GetCommunityName returns the name of the community filter, or empty string if none.

func (*FeedModel) GetCursor

func (m *FeedModel) GetCursor() int

GetCursor returns the current cursor position.

func (*FeedModel) GetListType

func (m *FeedModel) GetListType() api.ListingType

GetListType returns the current listing type.

func (*FeedModel) GetPage

func (m *FeedModel) GetPage() int

GetPage returns the current page number.

func (*FeedModel) GetPostCount

func (m *FeedModel) GetPostCount() int

GetPostCount returns the total number of posts.

func (*FeedModel) GetPosts

func (m *FeedModel) GetPosts() []api.PostView

GetPosts returns a copy of the current posts slice.

func (*FeedModel) GetSelectedPost

func (m *FeedModel) GetSelectedPost() *api.PostView

GetSelectedPost returns the currently selected post, or nil if none.

func (*FeedModel) GetSortType

func (m *FeedModel) GetSortType() api.SortType

GetSortType returns the current sort type.

func (*FeedModel) GetStyle

func (m *FeedModel) GetStyle() PostListStyle

GetStyle returns the current post list style.

func (*FeedModel) GetStyleIcon

func (m *FeedModel) GetStyleIcon() string

GetStyleIcon returns the icon for the current post list style.

func (*FeedModel) GetStyleLetter

func (m *FeedModel) GetStyleLetter() string

GetStyleLetter returns the lowercase letter for the current post list style.

func (*FeedModel) HasCommunityFilter

func (m *FeedModel) HasCommunityFilter() bool

HasCommunityFilter returns true if a community filter is active.

func (FeedModel) Init

func (m FeedModel) Init() tea.Cmd

Init initializes the posts model.

func (*FeedModel) IsFocused

func (m *FeedModel) IsFocused() bool

IsFocused returns whether this pane is focused.

func (*FeedModel) IsLoading

func (m *FeedModel) IsLoading() bool

IsLoading returns whether the posts list is loading.

func (*FeedModel) SetCommunityFilter

func (m *FeedModel) SetCommunityFilter(id int, name string)

SetCommunityFilter sets the community filter. Pass 0, "" to clear the filter.

func (*FeedModel) SetFocused

func (m *FeedModel) SetFocused(focused bool)

SetFocused sets whether this pane is focused.

func (*FeedModel) SetLoading

func (m *FeedModel) SetLoading(loading bool)

SetLoading sets the loading state.

func (*FeedModel) SetPosts

func (m *FeedModel) SetPosts(posts []api.PostView)

SetPosts updates the posts list.

func (*FeedModel) SetSize

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

SetSize updates the dimensions of the posts list.

func (*FeedModel) SetSpinnerFrame

func (m *FeedModel) SetSpinnerFrame(frame string)

SetSpinnerFrame sets the current spinner animation frame.

func (FeedModel) Update

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

Update handles messages for the posts list.

func (FeedModel) View

func (m FeedModel) View() string

View renders the posts list. This method is used by the two-column layout. For three-column layout, use buildHeader() and buildContent() separately to control header visibility.

type FollowCommunityResultMsg

type FollowCommunityResultMsg struct {
	Community api.CommunityView
	Err       error
}

FollowCommunityResultMsg carries the result of a follow/unfollow operation.

type HelpModel

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

HelpModel handles the help overlay state and rendering.

func NewHelpModel

func NewHelpModel() HelpModel

NewHelpModel creates a new help overlay model.

func (*HelpModel) Hide

func (m *HelpModel) Hide()

Hide hides the help overlay.

func (HelpModel) Init

func (m HelpModel) Init() tea.Cmd

Init initialises the help model.

func (*HelpModel) IsVisible

func (m *HelpModel) IsVisible() bool

IsVisible returns whether the help overlay is visible.

func (*HelpModel) NeedsScroll

func (m *HelpModel) NeedsScroll() bool

NeedsScroll returns whether the help content needs scrolling.

func (*HelpModel) ScrollPercent

func (m *HelpModel) ScrollPercent() float64

ScrollPercent returns the current scroll position as a percentage.

func (*HelpModel) SetSize

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

SetSize updates the dimensions of the help overlay.

func (*HelpModel) Show

func (m *HelpModel) Show()

Show makes the help overlay visible.

func (*HelpModel) Toggle

func (m *HelpModel) Toggle()

Toggle toggles the visibility of the help overlay.

func (HelpModel) Update

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

Update handles messages for the help overlay.

func (HelpModel) View

func (m HelpModel) View() string

View renders the help overlay.

type LoadingMsg

type LoadingMsg struct {
	Loading bool
}

LoadingMsg indicates a loading state change.

type LoginModel

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

LoginModel handles the login screen state and rendering.

func NewLoginModel

func NewLoginModel(defaultInstance string) LoginModel

NewLoginModel creates a new login screen model.

func (*LoginModel) GetInstance

func (m *LoginModel) GetInstance() string

GetInstance returns the entered instance URL.

func (*LoginModel) GetPassword

func (m *LoginModel) GetPassword() string

GetPassword returns the entered password.

func (*LoginModel) GetTOFUFingerprint

func (m *LoginModel) GetTOFUFingerprint() string

GetTOFUFingerprint returns the fingerprint for the current TOFU prompt.

func (*LoginModel) GetTOFUHostname

func (m *LoginModel) GetTOFUHostname() string

GetTOFUHostname returns the hostname for the current TOFU prompt.

func (*LoginModel) GetUsername

func (m *LoginModel) GetUsername() string

GetUsername returns the entered username.

func (*LoginModel) HideTOFUPrompt

func (m *LoginModel) HideTOFUPrompt()

HideTOFUPrompt hides the TOFU certificate trust prompt.

func (LoginModel) Init

func (m LoginModel) Init() tea.Cmd

Init initializes the login model.

func (*LoginModel) IsConnecting

func (m *LoginModel) IsConnecting() bool

IsConnecting returns whether a connection is in progress.

func (*LoginModel) IsShowingTOFUPrompt

func (m *LoginModel) IsShowingTOFUPrompt() bool

IsShowingTOFUPrompt returns whether the TOFU prompt is being displayed.

func (*LoginModel) SetConnecting

func (m *LoginModel) SetConnecting(connecting bool)

SetConnecting sets the connecting state.

func (*LoginModel) SetError

func (m *LoginModel) SetError(err error)

SetError sets an error to display on the login screen.

func (*LoginModel) SetSize

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

SetSize updates the dimensions of the login screen.

func (*LoginModel) ShowTOFUPrompt

func (m *LoginModel) ShowTOFUPrompt(hostname, fingerprint string, fpChanged bool, prevFP string)

ShowTOFUPrompt displays the TOFU certificate trust prompt.

func (LoginModel) Update

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

Update handles messages for the login screen.

func (LoginModel) View

func (m LoginModel) View() string

View renders the login screen.

type LoginSuccessMsg

type LoginSuccessMsg struct{}

LoginSuccessMsg indicates successful connection (login or anonymous).

type MarkdownRenderer

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

MarkdownRenderer handles rendering of markdown content for the TUI.

func NewMarkdownRenderer

func NewMarkdownRenderer(width int) (*MarkdownRenderer, error)

NewMarkdownRenderer creates a new markdown renderer with the specified width.

func (*MarkdownRenderer) Render

func (r *MarkdownRenderer) Render(content string) (string, error)

Render renders markdown content to a styled string.

func (*MarkdownRenderer) SetWidth

func (r *MarkdownRenderer) SetWidth(width int) error

SetWidth updates the word wrap width and recreates the renderer.

type OpenCommunityBrowserMsg

type OpenCommunityBrowserMsg struct{}

OpenCommunityBrowserMsg signals that the community browser should be opened.

type Pane

type Pane int

Pane represents which pane is focused.

const (
	// PaneFeed is the left pane with the post feed.
	PaneFeed Pane = iota
	// PanePost is the right pane with post detail (top of right side).
	PanePost
	// PaneComments is the comments pane (bottom of right side).
	PaneComments
)

type PaneIndicatorStyle

type PaneIndicatorStyle string

PaneIndicatorStyle represents how the active pane is indicated.

const (
	// PaneIndicatorTitle shows coloured pane title headers (default).
	PaneIndicatorTitle PaneIndicatorStyle = "title"
	// PaneIndicatorBackground applies a subtle background tint to the active pane.
	PaneIndicatorBackground PaneIndicatorStyle = "background"
	// PaneIndicatorBoth applies both title and background indicators simultaneously.
	PaneIndicatorBoth PaneIndicatorStyle = "both"
)

type PostComposeMode

type PostComposeMode int

PostComposeMode represents whether creating a new post or editing.

const (
	// PostComposeModeCreate is for creating a new post.
	PostComposeModeCreate PostComposeMode = iota
	// PostComposeModeEdit is for editing an existing post.
	PostComposeModeEdit
)

type PostComposerField

type PostComposerField int

PostComposerField represents which field is currently focused.

const (
	// PostFieldCommunity focuses the community selector.
	PostFieldCommunity PostComposerField = iota
	// PostFieldTitle focuses the title input.
	PostFieldTitle
	// PostFieldURL focuses the URL input.
	PostFieldURL
	// PostFieldBody focuses the body textarea.
	PostFieldBody
	// PostFieldNSFW focuses the NSFW toggle.
	PostFieldNSFW
)

type PostComposerModel

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

PostComposerModel handles the post composition overlay.

func NewPostComposerModel

func NewPostComposerModel() PostComposerModel

NewPostComposerModel creates a new post composer model.

func (*PostComposerModel) ForceHide

func (m *PostComposerModel) ForceHide()

ForceHide hides the composer without checking for unsaved changes.

func (*PostComposerModel) GetMode

func (m *PostComposerModel) GetMode() PostComposeMode

GetMode returns the current compose mode.

func (*PostComposerModel) Hide

func (m *PostComposerModel) Hide()

Hide hides the composer overlay.

func (PostComposerModel) Init

func (m PostComposerModel) Init() tea.Cmd

Init initialises the post composer model.

func (*PostComposerModel) IsVisible

func (m *PostComposerModel) IsVisible() bool

IsVisible returns whether the composer overlay is visible.

func (*PostComposerModel) SetCommunities

func (m *PostComposerModel) SetCommunities(communities []api.CommunityView)

SetCommunities updates the available communities for selection.

func (*PostComposerModel) SetSize

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

SetSize updates the dimensions of the composer overlay.

func (*PostComposerModel) Show

func (m *PostComposerModel) Show(communityID int, communityName string, communities []api.CommunityView)

Show makes the composer visible for creating a new post.

func (*PostComposerModel) ShowEdit

func (m *PostComposerModel) ShowEdit(postID int, title, url, body string, nsfw bool)

ShowEdit makes the composer visible for editing an existing post.

func (PostComposerModel) Update

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

Update handles messages for the post composer overlay.

func (PostComposerModel) View

func (m PostComposerModel) View() string

View renders the post composer overlay.

type PostConfig

type PostConfig struct {
	ShowBadges            bool   // Show status and author badges
	BadgesDedicatedLine   bool   // All badges on dedicated line vs split
	DeletedContentDisplay string // "show", "placeholder", or "dimmed"
	URLExpandKey          string // "u" or "ctrl+u"
	MetaSeparatorStyle    string // "dot" or "pipe"
}

PostConfig holds configuration options for the post detail pane.

type PostCreateErrorMsg

type PostCreateErrorMsg struct {
	Err error
}

PostCreateErrorMsg indicates post creation failed.

type PostCreatedMsg

type PostCreatedMsg struct {
	Post api.PostView
}

PostCreatedMsg indicates a post was successfully created.

type PostDetailLoadedMsg

type PostDetailLoadedMsg struct {
	Post     api.PostView
	Comments []api.CommentView
}

PostDetailLoadedMsg carries a post with its comments.

type PostListStyle

type PostListStyle int

PostListStyle represents the display style for the posts list.

const (
	// PostListMinimal shows 1 line per post (most compact).
	PostListMinimal PostListStyle = iota
	// PostListCompact shows 2 lines per post plus separator.
	PostListCompact
	// PostListDetailed shows 3 lines per post plus separator.
	PostListDetailed
	// PostListFull shows 4 lines per post plus separator (most detailed).
	PostListFull
)

type PostModel

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

PostModel handles the post detail pane state and rendering.

func NewPostModel

func NewPostModel(cfg PostConfig) PostModel

NewPostModel creates a new post detail model with the given configuration.

func (*PostModel) ClearDeleteConfirm

func (m *PostModel) ClearDeleteConfirm()

ClearDeleteConfirm clears any pending delete confirmation.

func (*PostModel) GetComments

func (m *PostModel) GetComments() []api.CommentView

GetComments returns an empty slice since comments are now handled by CommentsModel. This method is retained for backward compatibility with app.go.

func (*PostModel) GetPost

func (m *PostModel) GetPost() *api.PostView

GetPost returns the currently displayed post.

func (PostModel) Init

func (m PostModel) Init() tea.Cmd

Init initializes the post detail model.

func (*PostModel) IsDeleteConfirmPending

func (m *PostModel) IsDeleteConfirmPending() bool

IsDeleteConfirmPending returns whether a delete confirmation is pending.

func (*PostModel) IsFocused

func (m *PostModel) IsFocused() bool

IsFocused returns whether this pane is focused.

func (*PostModel) IsLoading

func (m *PostModel) IsLoading() bool

IsLoading returns whether the detail pane is loading.

func (*PostModel) IsOwnedByUser

func (m *PostModel) IsOwnedByUser(userID int) bool

IsOwnedByUser returns true if the current post is owned by the given user ID.

func (*PostModel) ScrollPercent

func (m *PostModel) ScrollPercent() float64

ScrollPercent returns the current scroll percentage.

func (*PostModel) SetComments

func (m *PostModel) SetComments(comments []api.CommentView)

SetComments sets the comments for the current post. This method is retained for backward compatibility with app.go, but does nothing since comments are now handled by CommentsModel.

func (*PostModel) SetConfig

func (m *PostModel) SetConfig(cfg PostConfig)

SetConfig sets the post configuration options.

func (*PostModel) SetCurrentUserID

func (m *PostModel) SetCurrentUserID(userID int)

SetCurrentUserID sets the current user's ID for ownership checks.

func (*PostModel) SetFocused

func (m *PostModel) SetFocused(focused bool)

SetFocused sets whether this pane is focused.

func (*PostModel) SetLoading

func (m *PostModel) SetLoading(loading bool)

SetLoading sets the loading state.

func (*PostModel) SetLocalInstance

func (m *PostModel) SetLocalInstance(instance string)

SetLocalInstance sets the local instance hostname for community display.

func (*PostModel) SetPost

func (m *PostModel) SetPost(post *api.PostView)

SetPost sets the post to display.

func (*PostModel) SetShowHeader

func (m *PostModel) SetShowHeader(show bool)

SetShowHeader sets whether the internal pane header should be rendered. Set to false in three-column mode where headers are rendered externally.

func (*PostModel) SetSize

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

SetSize updates the dimensions of the post detail pane.

func (*PostModel) SetSpinnerFrame

func (m *PostModel) SetSpinnerFrame(frame string)

SetSpinnerFrame sets the current spinner animation frame.

func (*PostModel) ToggleURLExpanded

func (m *PostModel) ToggleURLExpanded()

ToggleURLExpanded toggles the URL expansion state.

func (PostModel) Update

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

Update handles messages for the post detail pane.

func (PostModel) View

func (m PostModel) View() string

View renders the post detail pane.

type PostType

type PostType string

PostType represents the type of post content.

const (
	// PostTypeLink is a post with an external URL.
	PostTypeLink PostType = "link"
	// PostTypeImage is a post with an image.
	PostTypeImage PostType = "image"
	// PostTypeText is a text-only post.
	PostTypeText PostType = "text"
)

type PostVoteResultMsg

type PostVoteResultMsg struct {
	PostView api.PostView
	Err      error
}

PostVoteResultMsg carries the result of a post vote action.

type PostsLoadedMsg

type PostsLoadedMsg struct {
	Posts []api.PostView
}

PostsLoadedMsg carries loaded posts from API.

type RefetchCommunitiesMsg

type RefetchCommunitiesMsg struct{}

RefetchCommunitiesMsg signals that the community list should be refetched.

type Screen

type Screen int

Screen represents the current screen state.

const (
	// ScreenLogin is the login/connection screen.
	ScreenLogin Screen = iota
	// ScreenMain is the main split-pane view.
	ScreenMain
)

type SearchModel

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

SearchModel handles the search overlay state and rendering.

func NewSearchModel

func NewSearchModel() SearchModel

NewSearchModel creates a new search overlay model.

func (*SearchModel) FocusInput

func (m *SearchModel) FocusInput() tea.Cmd

FocusInput returns a command to focus the text input.

func (*SearchModel) GetQuery

func (m *SearchModel) GetQuery() string

GetQuery returns the current search query.

func (*SearchModel) GetSearchType

func (m *SearchModel) GetSearchType() api.SearchType

GetSearchType returns the currently selected search type.

func (*SearchModel) Hide

func (m *SearchModel) Hide()

Hide hides the search overlay.

func (SearchModel) Init

func (m SearchModel) Init() tea.Cmd

Init initialises the search model.

func (*SearchModel) IsLoading

func (m *SearchModel) IsLoading() bool

IsLoading returns whether the search is in progress.

func (*SearchModel) IsVisible

func (m *SearchModel) IsVisible() bool

IsVisible returns whether the search overlay is visible.

func (*SearchModel) SetLoading

func (m *SearchModel) SetLoading(loading bool)

SetLoading sets the loading state.

func (*SearchModel) SetSize

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

SetSize updates the dimensions of the search overlay.

func (*SearchModel) SetSpinnerFrame

func (m *SearchModel) SetSpinnerFrame(frame string)

SetSpinnerFrame sets the current spinner animation frame.

func (*SearchModel) Show

func (m *SearchModel) Show()

Show makes the search overlay visible and focuses the input.

func (SearchModel) Update

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

Update handles messages for the search overlay.

func (SearchModel) View

func (m SearchModel) View() string

View renders the search overlay.

type SearchResultsMsg

type SearchResultsMsg struct {
	Query       string
	Type        api.SearchType
	Posts       []api.PostView
	Comments    []api.CommentView
	Communities []api.Community
	Users       []api.Person
}

SearchResultsMsg carries search results from the API.

type SearchSubmitMsg

type SearchSubmitMsg struct {
	Query string
	Type  api.SearchType
}

SearchSubmitMsg carries a search query to be executed.

type SelectCommunityMsg

type SelectCommunityMsg struct {
	CommunityID   int
	CommunityName string
}

SelectCommunityMsg signals that a community was selected for filtering.

type SelectionStyle

type SelectionStyle int

SelectionStyle represents the visual style for selected comments.

const (
	// SelectionStyleCursor shows a cursor prefix indicator.
	SelectionStyleCursor SelectionStyle = iota
	// SelectionStyleHighlight shows a background highlight.
	SelectionStyleHighlight
	// SelectionStyleBorder shows a border box around the comment.
	SelectionStyleBorder
)

type SessionState

type SessionState struct {
	TwoColumn struct {
		LeftPaneWidth     int // Left pane width percentage (feed pane)
		PostCommentsSplit int // Post/Comments split percentage
	}
	ThreeColumn struct {
		FeedPaneWidth     int // Feed column width percentage
		PostPaneWidth     int // Post column width percentage
		CommentsPaneWidth int // Comments column width percentage
	}
}

SessionState stores layout-specific divider positions that persist during the session. When switching between layouts, each layout's divider positions are preserved independently.

type ShowDiscardConfirmMsg

type ShowDiscardConfirmMsg struct{}

ShowDiscardConfirmMsg signals that the discard confirmation dialog should be shown. This is sent when the user tries to cancel editing with unsaved changes.

type SiteConfigLoadedMsg

type SiteConfigLoadedMsg struct {
	EnableDownvotes bool
	CurrentUserID   int // Person ID of the current user, 0 if not authenticated
	Err             error
}

SiteConfigLoadedMsg carries the site configuration after login.

type StartComposeMsg

type StartComposeMsg struct {
	PostID          int    // The post to comment on
	ParentCommentID int    // 0 for top-level comment, or parent comment ID for reply
	ParentAuthor    string // Author name of the parent comment (for display)
	ParentContent   string // Content snippet of the parent comment (for context)
}

StartComposeMsg signals that the user wants to compose a new comment.

type StartCreatePostMsg

type StartCreatePostMsg struct {
	CommunityID   int    // Pre-selected community ID (0 if none)
	CommunityName string // Pre-selected community name (for display)
}

StartCreatePostMsg signals that the user wants to create a new post.

type StartEditCommentMsg

type StartEditCommentMsg struct {
	CommentID      int    // ID of the comment to edit
	CurrentContent string // Current content to pre-populate the editor
}

StartEditCommentMsg signals that the user wants to edit a comment.

type StartEditPostMsg

type StartEditPostMsg struct {
	PostID       int    // ID of the post to edit
	CurrentTitle string // Current title to pre-populate
	CurrentURL   string // Current URL to pre-populate
	CurrentBody  string // Current body to pre-populate
	CurrentNSFW  bool   // Current NSFW flag
}

StartEditPostMsg signals that the user wants to edit a post.

type SubmitCommentMsg

type SubmitCommentMsg struct {
	PostID          int    // The post to comment on
	ParentCommentID int    // 0 for top-level comment, or parent comment ID for reply
	Content         string // The comment content
}

SubmitCommentMsg carries the composed comment to be submitted.

type SubmitPostMsg

type SubmitPostMsg struct {
	CommunityID int    // Target community
	Title       string // Post title
	URL         string // Optional URL (for link posts)
	Body        string // Optional body content
	NSFW        bool   // Whether the post is NSFW
}

SubmitPostMsg carries the post data to be created.

type TrustDecision

type TrustDecision int

TrustDecision represents the user's trust decision for a certificate.

const (
	// TrustDecisionNone means no decision has been made.
	TrustDecisionNone TrustDecision = iota
	// TrustDecisionOnce trusts the certificate for this session only.
	TrustDecisionOnce
	// TrustDecisionAlways trusts the certificate permanently (save fingerprint).
	TrustDecisionAlways
	// TrustDecisionReject rejects the certificate and cancels connection.
	TrustDecisionReject
)

type VoteDebounceExpiredMsg

type VoteDebounceExpiredMsg struct {
	ItemKey string // "post:123" or "comment:456"
}

VoteDebounceExpiredMsg signals that a vote debounce period has expired.

type VoteRequestMsg

type VoteRequestMsg struct {
	PostID    int          // Non-zero for post votes
	CommentID int          // Non-zero for comment votes
	VoteType  api.VoteType // The desired vote action
}

VoteRequestMsg requests a vote action on a post or comment.

Jump to

Keyboard shortcuts

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