@@ -1,8 +1,18 @@
11package chat
22
3−import tea "github.com/charmbracelet/bubbletea"
3+import (
4+ "fmt"
45
5−type sidebarCmp struct{}
6+ tea "github.com/charmbracelet/bubbletea"
7+ "github.com/charmbracelet/lipgloss"
8+ "github.com/kujtimiihoxha/termai/internal/config"
9+ "github.com/kujtimiihoxha/termai/internal/tui/styles"
10+ "github.com/kujtimiihoxha/termai/internal/version"
11+)
12+
13+type sidebarCmp struct {
14+ width, height int
15+}
616
717func (m *sidebarCmp) Init() tea.Cmd {
818 return nil
@@ -13,7 +23,174 @@ func (m *sidebarCmp) Update(tea.Msg) (tea.Model, tea.Cmd) {
1323}
1424
1525func (m *sidebarCmp) View() string {
16− return "Sidebar"
26+ return styles.BaseStyle.Width(m.width).Render(
27+ lipgloss.JoinVertical(
28+ lipgloss.Top,
29+ m.header(),
30+ " ",
31+ m.session(),
32+ " ",
33+ m.modifiedFiles(),
34+ " ",
35+ m.lspsConfigured(),
36+ ),
37+ )
38+}
39+
40+func (m *sidebarCmp) session() string {
41+ sessionKey := styles.BaseStyle.Foreground(styles.PrimaryColor).Render("Session")
42+ sessionValue := styles.BaseStyle.
43+ Foreground(styles.Forground).
44+ Width(m.width - lipgloss.Width(sessionKey)).
45+ Render(": New Session")
46+ return lipgloss.JoinHorizontal(
47+ lipgloss.Left,
48+ sessionKey,
49+ sessionValue,
50+ )
51+}
52+
53+func (m *sidebarCmp) modifiedFile(filePath string, additions, removals int) string {
54+ stats := ""
55+ if additions > 0 && removals > 0 {
56+ stats = styles.BaseStyle.Foreground(styles.ForgroundDim).Render(fmt.Sprintf("%d additions and %d removals", additions, removals))
57+ } else if additions > 0 {
58+ stats = styles.BaseStyle.Foreground(styles.ForgroundDim).Render(fmt.Sprintf("%d additions", additions))
59+ } else if removals > 0 {
60+ stats = styles.BaseStyle.Foreground(styles.ForgroundDim).Render(fmt.Sprintf("%d removals", removals))
61+ }
62+ filePathStr := styles.BaseStyle.Foreground(styles.Forground).Render(filePath)
63+
64+ return styles.BaseStyle.
65+ Width(m.width).
66+ Render(
67+ lipgloss.JoinHorizontal(
68+ lipgloss.Left,
69+ filePathStr,
70+ " ",
71+ stats,
72+ ),
73+ )
74+}
75+
76+func (m *sidebarCmp) lspsConfigured() string {
77+ lsps := styles.BaseStyle.Width(m.width).Foreground(styles.PrimaryColor).Render("LSP Configuration:")
78+ lspsConfigured := []struct {
79+ name string
80+ path string
81+ }{
82+ {"golsp", "path/to/lsp1"},
83+ {"vtsls", "path/to/lsp2"},
84+ }
85+
86+ var lspViews []string
87+ for _, lsp := range lspsConfigured {
88+ lspName := styles.BaseStyle.Foreground(styles.Forground).Render(
89+ fmt.Sprintf("• %s", lsp.name),
90+ )
91+ lspPath := styles.BaseStyle.Foreground(styles.ForgroundDim).Render(
92+ fmt.Sprintf("(%s)", lsp.path),
93+ )
94+ lspViews = append(lspViews,
95+ styles.BaseStyle.
96+ Width(m.width).
97+ Render(
98+ lipgloss.JoinHorizontal(
99+ lipgloss.Left,
100+ lspName,
101+ " ",
102+ lspPath,
103+ ),
104+ ),
105+ )
106+
107+ }
108+ return styles.BaseStyle.
109+ Width(m.width).
110+ Render(
111+ lipgloss.JoinVertical(
112+ lipgloss.Left,
113+ lsps,
114+ lipgloss.JoinVertical(
115+ lipgloss.Left,
116+ lspViews...,
117+ ),
118+ ),
119+ )
120+}
121+
122+func (m *sidebarCmp) modifiedFiles() string {
123+ modifiedFiles := styles.BaseStyle.Width(m.width).Foreground(styles.PrimaryColor).Render("Modified Files:")
124+ files := []struct {
125+ path string
126+ additions int
127+ removals int
128+ }{
129+ {"file1.txt", 10, 5},
130+ {"file2.txt", 20, 0},
131+ {"file3.txt", 0, 15},
132+ }
133+ var fileViews []string
134+ for _, file := range files {
135+ fileViews = append(fileViews, m.modifiedFile(file.path, file.additions, file.removals))
136+ }
137+
138+ return styles.BaseStyle.
139+ Width(m.width).
140+ Render(
141+ lipgloss.JoinVertical(
142+ lipgloss.Top,
143+ modifiedFiles,
144+ lipgloss.JoinVertical(
145+ lipgloss.Left,
146+ fileViews...,
147+ ),
148+ ),
149+ )
150+}
151+
152+func (m *sidebarCmp) logo() string {
153+ logo := fmt.Sprintf("%s %s", styles.OpenCodeIcon, "OpenCode")
154+
155+ version := styles.BaseStyle.Foreground(styles.ForgroundDim).Render(version.Version)
156+
157+ return styles.BaseStyle.
158+ Bold(true).
159+ Width(m.width).
160+ Render(
161+ lipgloss.JoinHorizontal(
162+ lipgloss.Left,
163+ logo,
164+ " ",
165+ version,
166+ ),
167+ )
168+}
169+
170+func (m *sidebarCmp) header() string {
171+ header := lipgloss.JoinVertical(
172+ lipgloss.Top,
173+ m.logo(),
174+ m.cwd(),
175+ )
176+ return header
177+}
178+
179+func (m *sidebarCmp) cwd() string {
180+ cwd := fmt.Sprintf("cwd: %s", config.WorkingDirectory())
181+ return styles.BaseStyle.
182+ Foreground(styles.ForgroundDim).
183+ Width(m.width).
184+ Render(cwd)
185+}
186+
187+func (m *sidebarCmp) SetSize(width, height int) {
188+ m.width = width
189+ m.height = height
190+}
191+
192+func (m *sidebarCmp) GetSize() (int, int) {
193+ return m.width, m.height
17194}
18195
19196func NewSidebarCmp() tea.Model {