mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
added mac-like traffic lights to the top of tabshellview
This commit is contained in:
@@ -185,8 +185,8 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setTitle(_ newTitle: String) {
|
func setTitle(_ newTitle: String) {
|
||||||
DispatchQueue.main.async {
|
Task { @MainActor in
|
||||||
self.title = newTitle
|
withAnimation { self.title = newTitle }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,56 +16,85 @@ struct ShellTabView: View {
|
|||||||
|
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geo in
|
GeometryReader { geo in
|
||||||
VStack {
|
VStack {
|
||||||
let oneTabWidth = max(60, geo.size.width/CGFloat(container.sessionIDs.count))
|
HStack(alignment: .center, spacing: 10) {
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
Button() {
|
||||||
HStack(spacing: 0) {
|
for session in container.sessions.values {
|
||||||
ForEach(container.sessionIDs, id: \.self) { id in
|
session.handler.disconnect()
|
||||||
let selected = selectedID == id
|
}
|
||||||
let foreground = hostsManager.selectedTheme.foreground.suiColor
|
} label: {
|
||||||
let ansi7 = hostsManager.selectedTheme.ansi[6].suiColor.opacity(0.7)
|
Image(systemName: "xmark.circle.fill")
|
||||||
let background = hostsManager.selectedTheme.background.suiColor
|
.resizable().scaledToFit()
|
||||||
ZStack {
|
.symbolRenderingMode(.palette)
|
||||||
Rectangle()
|
.foregroundStyle(
|
||||||
.fill(selected ? ansi7 : background)
|
ColorCodable(red: 0.5411764706, green: 0, blue: 0).stColor.suiColor,
|
||||||
HStack {
|
.red
|
||||||
if selected {
|
)
|
||||||
Button() {
|
}
|
||||||
container.sessions[id]?.handler.disconnect()
|
Button() {
|
||||||
} label: {
|
dismiss()
|
||||||
Image(systemName: "xmark.app.fill")
|
} label: {
|
||||||
.resizable().scaledToFit()
|
Image(systemName: "minus.circle.fill")
|
||||||
|
.resizable().scaledToFit()
|
||||||
|
.symbolRenderingMode(.palette)
|
||||||
|
.foregroundStyle(
|
||||||
|
ColorCodable(red: 0.5764705882, green: 0.5333333333, blue: 0.2784313725).stColor.suiColor,
|
||||||
|
.yellow
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
Text(container.sessions[selectedID ?? UUID()]?.handler.title ?? "title")
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.frame(height: 30)
|
||||||
|
.padding(10)
|
||||||
|
|
||||||
|
let oneTabWidth = max(60, (geo.size.width-35)/CGFloat(container.sessionIDs.count))
|
||||||
|
HStack(alignment: .center, spacing: 0) {
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
ForEach(container.sessionIDs, id: \.self) { id in
|
||||||
|
let selected = selectedID == id
|
||||||
|
let foreground = hostsManager.selectedTheme.foreground.suiColor
|
||||||
|
let ansi7 = hostsManager.selectedTheme.ansi[6].suiColor.opacity(0.7)
|
||||||
|
let background = hostsManager.selectedTheme.background.suiColor
|
||||||
|
ZStack {
|
||||||
|
Rectangle()
|
||||||
|
.fill(selected ? ansi7 : background)
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
VStack {
|
||||||
|
Text(container.sessions[id]!.handler.title)
|
||||||
|
.monospaced()
|
||||||
|
.foregroundStyle(foreground)
|
||||||
|
.bold(selected)
|
||||||
|
Text(container.sessions[id]!.handler.host.description)
|
||||||
|
.foregroundStyle(foreground.opacity(0.7))
|
||||||
|
.monospaced()
|
||||||
|
.font(.caption)
|
||||||
}
|
}
|
||||||
.padding()
|
Spacer()
|
||||||
}
|
}
|
||||||
Spacer()
|
}
|
||||||
VStack {
|
.frame(width: oneTabWidth)
|
||||||
Text(container.sessions[id]!.handler.title)
|
.ignoresSafeArea(.all)
|
||||||
.monospaced()
|
.onTapGesture {
|
||||||
.foregroundStyle(foreground)
|
withAnimation { selectedID = id }
|
||||||
.bold(selected)
|
|
||||||
Text(container.sessions[id]!.handler.host.description)
|
|
||||||
.foregroundStyle(foreground.opacity(0.7))
|
|
||||||
.monospaced()
|
|
||||||
.font(.caption)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(width: oneTabWidth)
|
|
||||||
.ignoresSafeArea(.all)
|
|
||||||
.onTapGesture {
|
|
||||||
withAnimation { selectedID = id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Button() {
|
|
||||||
dismiss()
|
|
||||||
} label: {
|
|
||||||
Image(systemName: "arrow.down.right.and.arrow.up.left")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Button() {
|
||||||
|
dismiss()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "arrow.down.right.and.arrow.up.left")
|
||||||
|
.resizable().scaledToFit()
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.frame(width: 30)
|
||||||
|
.padding(.horizontal, 2.5)
|
||||||
}
|
}
|
||||||
.frame(height: 30)
|
.frame(height: 30)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
@@ -104,7 +133,7 @@ struct ShellTabView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
|||||||
Reference in New Issue
Block a user