Commit b0fa5a8

Ansari <ping@ansari.wtf>
2026-02-25 11:47:32
feat: Navigating between sections
1 parent 7057e85
internal/app/component.go
@@ -6,8 +6,13 @@ import (
 	"github.com/charmbracelet/lipgloss"
 )
 
-func RenderBoxWithTitle(title, content string, styles Styles, width int) string {
+func RenderBoxWithTitle(title, content string, styles Styles, width int, activeSession bool) string {
+	
 	borderColor := styles.SectionBorder.GetBorderTopForeground()
+	if activeSession{
+		borderColor = styles.SectionBorderActive.GetBorderTopForeground()
+		title  = title + " ●"
+	}
 
 	boxWidth := 0
 	if width != -1 {
@@ -16,7 +21,7 @@ func RenderBoxWithTitle(title, content string, styles Styles, width int) string
 
 	style := lipgloss.NewStyle().
 		Border(lipgloss.RoundedBorder()).
-		BorderForeground(styles.SectionBorder.GetBorderTopForeground()).
+		BorderForeground(borderColor).
 		Padding(1, 2)
 
 	if boxWidth > 0 {
internal/app/keys.go
@@ -3,11 +3,19 @@ package app
 import "github.com/charmbracelet/bubbles/key"
 
 type KeyMap struct {
-	Quit    key.Binding
-	Refresh key.Binding
+	Quit              key.Binding
+	Refresh           key.Binding
+	MoveToNextSection key.Binding
+	MoveToPrevSection key.Binding
 }
 
 var Keys = KeyMap{
+	MoveToPrevSection: key.NewBinding(
+		key.WithKeys("shift+tab", "left"),
+	),
+	MoveToNextSection: key.NewBinding(
+		key.WithKeys("tab", "right"),
+	),
 	Quit: key.NewBinding(
 		key.WithKeys("q", "ctrl+c", "esc"),
 		key.WithHelp("q/esc", "quit"),
internal/app/sections.go
@@ -8,6 +8,14 @@ import (
 	"github.com/charmbracelet/lipgloss"
 )
 
+const (
+	SectionStatus = iota
+	SectionPolicies
+	SectionRules
+
+// SectionDetails
+)
+
 func (m model) renderStatusSection() string {
 	var statusText string
 	var statusStyle lipgloss.Style
@@ -45,7 +53,7 @@ func (m model) renderStatusSection() string {
 		totalRulesLine,
 	)
 
-	return RenderBoxWithTitle("Firewall Stats", content, m.styles, -1)
+	return RenderBoxWithTitle("Firewall Stats", content, m.styles, -1, m.activeSection == SectionStatus)
 }
 
 func (m model) renderPoliciesSection() string {
@@ -78,15 +86,15 @@ func (m model) renderPoliciesSection() string {
 		outgoingLine,
 		routedLine,
 	)
-	return RenderBoxWithTitle("Default Policies", content, m.styles, -1)
+	return RenderBoxWithTitle("Default Policies", content, m.styles, -1, m.activeSection == SectionPolicies)
 }
 
 func (m model) renderRulesSection() string {
 	var rows []string
 
 	header := fmt.Sprintf(
-	"%-3s │ %-6s │ %-5s │ %-16s │ %-5s │ %-16s │ %-5s",
-		"#", "Action", "Proto", "Source", "sPort","Destination","dPort")
+		"%-3s │ %-6s │ %-5s │ %-16s │ %-5s │ %-16s │ %-5s",
+		"#", "Action", "Proto", "Source", "sPort", "Destination", "dPort")
 
 	headerContent := m.styles.Label.UnsetWidth().Render(header)
 	line := strings.Repeat("─", lipgloss.Width(headerContent))
@@ -110,7 +118,7 @@ func (m model) renderRulesSection() string {
 		lipgloss.Left,
 		table,
 	)
-	return RenderBoxWithTitle("Active Rules", content, m.styles, -1)
+	return RenderBoxWithTitle("Active Rules", content, m.styles, -1, m.activeSection == SectionRules)
 }
 
 func (m model) getPolicyStyle(policy string) lipgloss.Style {
@@ -127,12 +135,16 @@ func (m model) getPolicyStyle(policy string) lipgloss.Style {
 }
 
 func (m model) renderFooter(width int) string {
-	keys := []string{
-		m.styles.FooterKey.Render("r") + " refresh",
-		m.styles.FooterKey.Render("?") + " help",
-		m.styles.FooterKey.Render("q") + " quit",
+	var keys []string
+
+	switch m.activeSection {
+	case SectionRules:
+		keys = []string{"↑↓: navigate", "enter: details", "d: delete"}
+	default:
+		keys = []string{"tab: next section", "r: refresh"}
 	}
 
+	keys = append(keys, "q: quit")
 	footerText := strings.Join(keys, "  •  ")
 	return m.styles.Footer.Width(width).Render(footerText)
 }
internal/app/styles.go
@@ -16,8 +16,9 @@ type Styles struct {
 	StatusLabel    lipgloss.Style
 
 	// Sections
-	SectionBorder lipgloss.Style
-	SectionTitle  lipgloss.Style
+	SectionBorder       lipgloss.Style
+	SectionTitle        lipgloss.Style
+	SectionBorderActive lipgloss.Style
 
 	// Policies
 	AllowPolicy  lipgloss.Style
@@ -61,7 +62,7 @@ func NewStyles() Styles {
 		overlay2 = lipgloss.Color("#9399b2")
 		overlay1 = lipgloss.Color("#7f849c")
 		// overlay0  = lipgloss.Color("#6c7086")
-		// surface2  = lipgloss.Color("#585b70")
+		surface2  = lipgloss.Color("#585b70")
 		// surface1  = lipgloss.Color("#45475a")
 		// surface0  = lipgloss.Color("#313244")
 		// base      = lipgloss.Color("#1e1e2e")
@@ -94,8 +95,11 @@ func NewStyles() Styles {
 
 		SectionBorder: lipgloss.NewStyle().
 			Border(lipgloss.RoundedBorder()).
-			BorderForeground(mauve),
+			BorderForeground(surface2),
 
+		SectionBorderActive: lipgloss.NewStyle().
+			Border(lipgloss.RoundedBorder()).
+			BorderForeground(mauve),
 
 		SectionTitle: lipgloss.NewStyle().
 			Bold(true).
internal/app/update.go
@@ -15,6 +15,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	switch msg := msg.(type) {
 	case tea.KeyMsg:
 		switch {
+		case key.Matches(msg, Keys.MoveToNextSection): 
+			 m.activeSection = (m.activeSection + 1) % 3 
+		case key.Matches(msg, Keys.MoveToPrevSection):
+			 m.activeSection = (m.activeSection - 1 + 3) % 3 
 		case key.Matches(msg, Keys.Quit):
 			return m, tea.Quit
 		case key.Matches(msg, Keys.Refresh):