import Environment import SwiftUI @MainActor final class SuggestionPanelViewModel: ObservableObject { @Published var startLineIndex: Int @Published var suggestion: [String] @Published var isPanelDisplayed: Bool @Published var suggestionCount: Int @Published var currentSuggestionIndex: Int public init( startLineIndex: Int = 0, suggestion: [String] = [], isPanelDisplayed: Bool = false, suggestionCount: Int = 0, currentSuggestionIndex: Int = 0 ) { self.startLineIndex = startLineIndex self.suggestion = suggestion self.isPanelDisplayed = isPanelDisplayed self.suggestionCount = suggestionCount self.currentSuggestionIndex = currentSuggestionIndex } } struct SuggestionPanelView: View { @ObservedObject var viewModel: SuggestionPanelViewModel @State var isHovering: Bool = false @State var codeHeight: Double = 0 var body: some View { VStack { ZStack(alignment: .topLeading) { VStack(spacing: 0) { ScrollView { CodeBlock(viewModel: viewModel) } ToolBar(viewModel: viewModel) } } .frame(maxWidth: .infinity, maxHeight: Style.panelHeight) .fixedSize(horizontal: false, vertical: true) .background(Color(red: 31 / 255, green: 31 / 255, blue: 36 / 255)) .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous)) .onHover { yes in withAnimation(.easeInOut(duration: 0.2)) { isHovering = yes } } .allowsHitTesting(viewModel.isPanelDisplayed && !viewModel.suggestion.isEmpty) Spacer() .frame(minHeight: 0, maxHeight: .infinity) .allowsHitTesting(false) } .overlay( RoundedRectangle(cornerRadius: 8, style: .continuous) .stroke(Color.black.opacity(0.3), style: .init(lineWidth: 1)) ) .opacity({ guard viewModel.isPanelDisplayed else { return 0 } guard !viewModel.suggestion.isEmpty else { return 0 } return 1 }()) } } struct CodeBlock: View { struct SizePreferenceKey: PreferenceKey { public static var defaultValue: CGSize = .zero public static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = value.width + value.height > nextValue().width + nextValue() .height ? value : nextValue() } } @ObservedObject var viewModel: SuggestionPanelViewModel var body: some View { LazyVGrid(columns: [ GridItem(.fixed(30), alignment: .top), GridItem(.flexible()), ], spacing: 4) { ForEach(0.. some View { configuration.label .padding(.vertical, 4) .padding(.horizontal, 8) .foregroundColor(.white) .background( RoundedRectangle(cornerRadius: 4, style: .continuous) .fill(color.opacity(configuration.isPressed ? 0.8 : 1)) .animation(.easeOut(duration: 0.1), value: configuration.isPressed) ) .overlay { RoundedRectangle(cornerRadius: 4, style: .continuous) .stroke(Color.white.opacity(0.2), style: .init(lineWidth: 1)) } } } struct SuggestionPanelView_Preview: PreviewProvider { static var previews: some View { SuggestionPanelView(viewModel: .init( startLineIndex: 8, suggestion: """ LazyVGrid(columns: [GridItem(.fixed(30)), GridItem(.flexible())]) { ForEach(0..