@@ -18,7 +18,9 @@ import (
18 "github.com/charmbracelet/crush/internal/tui/components/core/layout"
18 "github.com/charmbracelet/crush/internal/tui/components/core/layout"
19 "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands"
19 "github.com/charmbracelet/crush/internal/tui/components/dialogs/commands"
20 "github.com/charmbracelet/crush/internal/tui/page"
20 "github.com/charmbracelet/crush/internal/tui/page"
21+ "github.com/charmbracelet/crush/internal/tui/styles"
21 "github.com/charmbracelet/crush/internal/tui/util"
22 "github.com/charmbracelet/crush/internal/tui/util"
23+ "github.com/charmbracelet/lipgloss/v2"
24var ChatPageID page.PageID = "chat"
26var ChatPageID page.PageID = "chat"
@@ -51,7 +53,9 @@ type chatPage struct {
52 compactMode bool
54 compactMode bool
53 forceCompactMode bool // Force compact mode regardless of window size
55 forceCompactMode bool // Force compact mode regardless of window size
56+ showDetails bool // Show details in the header
54 header header.Header
57 header header.Header
58+ compactSidebar layout.Container
57func (p *chatPage) Init() tea.Cmd {
61func (p *chatPage) Init() tea.Cmd {
@@ -69,6 +73,9 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
69 h, cmd := p.header.Update(msg)
73 h, cmd := p.header.Update(msg)
70 cmds = append(cmds, cmd)
74 cmds = append(cmds, cmd)
71 p.header = h.(header.Header)
75 p.header = h.(header.Header)
76+ if p.compactMode && p.showDetails {
77+ cmds = append(cmds, p.compactSidebar.SetSize(msg.Width-4, 0))
72 // the mode is only relevant when there is a session
79 // the mode is only relevant when there is a session
73 if p.session.ID != "" {
80 if p.session.ID != "" {
74 // Only auto-switch to compact mode if not forced
81 // Only auto-switch to compact mode if not forced
@@ -178,15 +185,34 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
178 p.app.CoderAgent.Cancel(p.session.ID)
185 p.app.CoderAgent.Cancel(p.session.ID)
179 return p, nil
186 return p, nil
188+ case key.Matches(msg, p.keyMap.Details):
189+ if p.session.ID == "" || !p.compactMode {
190+ return p, nil // No session to show details for
192+ p.showDetails = !p.showDetails
193+ p.header.SetDetailsOpen(p.showDetails)
195+ p.compactSidebar = sidebarCmp(p.app, true)
196+ c, cmd := p.compactSidebar.Update(chat.SessionSelectedMsg(p.session))
197+ p.compactSidebar = c.(layout.Container)
198+ return p, tea.Batch(
200+ p.compactSidebar.SetSize(p.wWidth-4, 0),
183 u, cmd := p.layout.Update(msg)
207 u, cmd := p.layout.Update(msg)
184 cmds = append(cmds, cmd)
208 cmds = append(cmds, cmd)
185 p.layout = u.(layout.SplitPaneLayout)
209 p.layout = u.(layout.SplitPaneLayout)
211+ if p.compactMode && p.showDetails {
187− h, cmd := p.header.Update(msg)
212+ s, cmd := p.compactSidebar.Update(msg)
213+ p.compactSidebar = s.(layout.Container)
188− cmds = append(cmds, cmd)
214+ cmds = append(cmds, cmd)
189− p.header = h.(header.Header)
215+ }
190 return p, tea.Batch(cmds...)
216 return p, tea.Batch(cmds...)
@@ -199,7 +225,7 @@ func (p *chatPage) setMessages() tea.Cmd {
201func (p *chatPage) setSidebar() tea.Cmd {
227func (p *chatPage) setSidebar() tea.Cmd {
202− sidebarContainer := sidebarCmp(p.app)
228+ sidebarContainer := sidebarCmp(p.app, false)
203 sidebarContainer.Init()
229 sidebarContainer.Init()
204 return p.layout.SetRightPanel(sidebarContainer)
230 return p.layout.SetRightPanel(sidebarContainer)
@@ -267,16 +293,29 @@ func (p *chatPage) View() tea.View {
267 return p.layout.View()
293 return p.layout.View()
269 layoutView := p.layout.View()
295 layoutView := p.layout.View()
270− chatView := tea.NewView(
271− strings.Join(
296+ chatView := strings.Join(
272− []string{
297+ []string{
273− p.header.View().String(),
298+ p.header.View().String(),
274− layoutView.String(),
299+ layoutView.String(),
275− }, "\n",
300+ }, "\n",
302+ layers := []*lipgloss.Layer{
303+ lipgloss.NewLayer(chatView).X(0).Y(0),
306+ t := styles.CurrentTheme()
307+ style := t.S().Base.
308+ Border(lipgloss.RoundedBorder()).
309+ BorderForeground(t.BorderFocus)
310+ details := style.Render(p.compactSidebar.View().String())
311+ layers = append(layers, lipgloss.NewLayer(details).X(1).Y(1))
313+ canvas := lipgloss.NewCanvas(
316+ view := tea.NewView(canvas.Render())
278− chatView.SetCursor(layoutView.Cursor())
317+ view.SetCursor(layoutView.Cursor())
279− return chatView
318+ return view
282func (p *chatPage) Bindings() []key.Binding {
321func (p *chatPage) Bindings() []key.Binding {
@@ -308,10 +347,14 @@ func (p *chatPage) Bindings() []key.Binding {
308 return bindings
347 return bindings
311−func sidebarCmp(app *app.App) layout.Container {
350+func sidebarCmp(app *app.App, compact bool) layout.Container {
351+ padding := layout.WithPadding(1, 1, 1, 1)
353+ padding = layout.WithPadding(0, 1, 1, 1)
312 return layout.NewContainer(
355 return layout.NewContainer(
313− sidebar.NewSidebarCmp(app.History, app.LSPClients),
356+ sidebar.NewSidebarCmp(app.History, app.LSPClients, compact),
314− layout.WithPadding(1, 1, 1, 1),
357+ padding,
@@ -322,7 +365,7 @@ func NewChatPage(app *app.App) ChatPage {
322 return &chatPage{
365 return &chatPage{
323 app: app,
366 app: app,
324 layout: layout.NewSplitPane(
367 layout: layout.NewSplitPane(
325− layout.WithRightPanel(sidebarCmp(app)),
368+ layout.WithRightPanel(sidebarCmp(app, false)),
326 layout.WithBottomPanel(editorContainer),
369 layout.WithBottomPanel(editorContainer),
327 layout.WithFixedBottomHeight(5),
370 layout.WithFixedBottomHeight(5),
328 layout.WithFixedRightWidth(31),
371 layout.WithFixedRightWidth(31),