11import SwiftUI
22
3- struct VPNMenu < Conn : CoderVPN > : View {
4- @ObservedObject var vpnService : Conn
3+ struct VPNMenu < VPN : CoderVPN > : View {
4+ @ObservedObject var vpnService : VPN
55
66 var body : some View {
77 // Main stack
@@ -45,24 +45,24 @@ struct VPNMenu<Conn: CoderVPN>: View {
4545 // Trailing stack
4646 VStack ( alignment: . leading, spacing: 3 ) {
4747 Divider ( ) . padding ( [ . horizontal] , 10 ) . padding ( . vertical, 4 )
48- RowButtonView {
48+ ButtonRowView {
4949 Text ( " Create workspace " )
5050 EmptyView ( )
5151 } action: {
5252 // TODO
5353 }
5454 Divider ( ) . padding ( [ . horizontal] , 10 ) . padding ( . vertical, 4 )
55- RowButtonView {
55+ ButtonRowView {
5656 Text ( " About " )
5757 } action: {
5858 // TODO
5959 }
60- RowButtonView {
60+ ButtonRowView {
6161 Text ( " Preferences " )
6262 } action: {
6363 // TODO
6464 }
65- RowButtonView {
65+ ButtonRowView {
6666 Text ( " Sign out " )
6767 } action: {
6868 // TODO
@@ -72,94 +72,6 @@ struct VPNMenu<Conn: CoderVPN>: View {
7272 }
7373}
7474
75- struct AgentRow : Identifiable {
76- let id : UUID
77- let name : String
78- let status : Color
79- let copyableDNS : String
80- }
81-
82- struct AgentRowView : View {
83- let workspace : AgentRow
84- @State private var nameIsSelected : Bool = false
85- @State private var copyIsSelected : Bool = false
86-
87- private var fmtWsName : AttributedString {
88- var formattedName = AttributedString ( workspace. name)
89- formattedName. foregroundColor = . primary
90- var coderPart = AttributedString ( " .coder " )
91- coderPart. foregroundColor = . gray
92- formattedName. append ( coderPart)
93- return formattedName
94- }
95-
96- var body : some View {
97- HStack ( spacing: 0 ) {
98- Button {
99- // TODO: Action
100- } label: {
101- HStack ( spacing: 10 ) {
102- ZStack {
103- Circle ( )
104- . fill ( workspace. status. opacity ( 0.4 ) )
105- . frame ( width: 12 , height: 12 )
106- Circle ( )
107- . fill ( workspace. status. opacity ( 1.0 ) )
108- . frame ( width: 7 , height: 7 )
109- }
110- Text ( fmtWsName) . lineLimit ( 1 ) . truncationMode ( . tail)
111- Spacer ( )
112- } . padding ( . horizontal, 10 )
113- . frame ( minHeight: 22 )
114- . frame ( maxWidth: . infinity, alignment: . leading)
115- . foregroundStyle ( nameIsSelected ? Color . white : . primary)
116- . background ( nameIsSelected ? Color . accentColor. opacity ( 0.8 ) : . clear)
117- . clipShape ( . rect( cornerRadius: 4 ) )
118- . onHover { hovering in nameIsSelected = hovering }
119- Spacer ( )
120- } . buttonStyle ( . plain)
121- Button {
122- // TODO: Proper clipboard abstraction
123- NSPasteboard . general. setString ( workspace. copyableDNS, forType: . string)
124- } label: {
125- Image ( systemName: " doc.on.doc " )
126- . symbolVariant ( . fill)
127- . padding ( 3 )
128- } . foregroundStyle ( copyIsSelected ? Color . white : . primary)
129- . imageScale ( . small)
130- . background ( copyIsSelected ? Color . accentColor. opacity ( 0.8 ) : . clear)
131- . clipShape ( . rect( cornerRadius: 4 ) )
132- . onHover { hovering in copyIsSelected = hovering }
133- . buttonStyle ( . plain)
134- . padding ( . trailing, 5 )
135- }
136- }
137- }
138-
139- struct RowButtonView < Label: View > : View {
140- @State private var isSelected : Bool = false
141- @ViewBuilder var label : ( ) -> Label
142- var action : ( ) -> Void
143-
144- var body : some View {
145- Button {
146- action ( )
147- } label: {
148- HStack ( spacing: 0 ) {
149- label ( )
150- Spacer ( )
151- }
152- . padding ( . horizontal, 10 )
153- . frame ( minHeight: 22 )
154- . frame ( maxWidth: . infinity, alignment: . leading)
155- . foregroundStyle ( isSelected ? Color . white : . primary)
156- . background ( isSelected ? Color . accentColor. opacity ( 0.8 ) : . clear)
157- . clipShape ( . rect( cornerRadius: 4 ) )
158- . onHover { hovering in isSelected = hovering }
159- } . buttonStyle ( . plain)
160- }
161- }
162-
16375#Preview {
16476 VPNMenu ( vpnService: PreviewVPN ( ) ) . frame ( width: 256 )
16577}
0 commit comments