Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions App/ResourcesPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,22 @@ import ShepherdrCore
struct ResourcesPanel: View {
let workspace: SessionWorkspace
let checks: ChecksMonitor
/// Hides the panel; the toolbar toggle is still there to bring it back.
let close: () -> Void
private static let shown = 10
@ViewState private var expanded = Set<SessionResource.Kind>()

var body: some View {
VStack(alignment: .leading, spacing: 0) {
ConsoleHeader(title: "Resources", trailing: "\(workspace.visibleResources.count)")
.padding(.horizontal, 12).padding(.top, 10).padding(.bottom, 6)
HStack(spacing: 8) {
ConsoleHeader(title: "Resources", trailing: "\(workspace.visibleResources.count)")
Button(action: close) {
Text("✕").font(Theme.mono(10.5, .semibold)).foregroundStyle(Theme.dim)
}
.buttonStyle(.plain)
.help("Close Resources panel — the ≡ button in the header brings it back")
}
.padding(.horizontal, 12).padding(.top, 10).padding(.bottom, 6)
ScrollView {
VStack(alignment: .leading, spacing: 0) {
ForEach(SessionResource.Kind.allCases, id: \.self) { kind in
Expand Down
51 changes: 27 additions & 24 deletions App/SessionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ struct SessionView: View {
workArea
if showsResources && !workspace.visibleResources.isEmpty {
Rectangle().fill(Theme.line).frame(width: 1)
ResourcesPanel(workspace: workspace, checks: model.checksMonitor).frame(width: 230)
ResourcesPanel(workspace: workspace, checks: model.checksMonitor) { showsResources = false }
.frame(width: 230)
}
}
}
Expand Down Expand Up @@ -125,10 +126,14 @@ struct SessionView: View {
Spacer(minLength: 8)
if let agent = context.agent { StateTag(state: agent.agent.state, stale: agent.isStale) }
lockButton
Button { terminal.open() } label: { Text("↻") }
.buttonStyle(ConsoleButtonStyle(tint: Theme.dim))
.disabled(terminal.status == .connecting || !context.canConnect)
.help("Reconnect to this terminal")
HStack(spacing: 4) {
Button { terminal.open() } label: { Text("↻").frame(width: 16, height: 14) }
.buttonStyle(ConsoleButtonStyle(tint: Theme.dim))
.disabled(terminal.status == .connecting || !context.canConnect)
.help("Reconnect to this terminal")
resourcesButton
browserButton
}
Button { showDetails.toggle() } label: { Text("i") }
.buttonStyle(ConsoleButtonStyle(tint: Theme.dim))
.help("Session details")
Expand Down Expand Up @@ -163,6 +168,23 @@ struct SessionView: View {
.accessibilityLabel(locked ? "Unlock session" : "Lock session")
}

private var resourcesButton: some View {
let links = workspace.visibleResources.count
return Button { showsResources.toggle() } label: { Text("≡").frame(width: 16, height: 14) }
.buttonStyle(ConsoleButtonStyle(tint: showsResources && links > 0 ? Theme.phosphor : Theme.dim))
.disabled(links == 0)
.help(links > 0 ? "Pull requests, issues and Claude artifacts this session linked to"
: "Pull requests, issues and Claude artifacts this session links to gather here")
}

private var browserButton: some View {
Button { model.toggleBrowser() } label: {
Image(systemName: "globe").font(.system(size: 11, weight: .semibold)).frame(width: 16, height: 14)
}
.buttonStyle(ConsoleButtonStyle(tint: workspace.browser.isVisible ? Theme.phosphor : Theme.dim))
.help("This session's browser (⌘B). Its tabs stay open while you work elsewhere.")
}

// MARK: Banners and states

private func banner(_ message: String, dismiss: (() -> Void)? = nil, action: (String, () -> Void)? = nil) -> some View {
Expand Down Expand Up @@ -278,25 +300,6 @@ struct SessionView: View {
key("↓", .down, help: "Down arrow")
key("⏎", .enter, help: "Return")
Spacer(minLength: 8)
if !compact {
Text(isLive ? "⇧⏎ new line · click a link to browse · ⌘-click opens your browser" : "locked · read-only · ⌘E to unlock")
.font(Theme.mono(9.5)).foregroundStyle(Theme.faint).lineLimit(1).truncationMode(.head)
.layoutPriority(-1)
}
let links = workspace.visibleResources.count
barToggle(compact ? (links > 0 ? "≡ \(links)" : "≡") : (links > 0 ? "≡ RESOURCES \(links)" : "≡ RESOURCES"),
active: showsResources && links > 0,
help: links > 0 ? "Pull requests, issues and Claude artifacts this session linked to"
: "Pull requests, issues and Claude artifacts this session links to gather here") {
showsResources.toggle()
}
.disabled(links == 0)
let tabs = workspace.browser.tabs.count
barToggle(compact ? (tabs > 0 ? "◫ \(tabs)" : "◫") : (tabs > 0 ? "◫ BROWSER \(tabs)" : "◫ BROWSER"),
active: workspace.browser.isVisible,
help: "This session's browser (⌘B). Its tabs stay open while you work elsewhere.") {
model.toggleBrowser()
}
}
}

Expand Down
Loading