import SwiftUI private struct DetailListItem: View where Content: View { private let alignment: VerticalAlignment private let spacing: CGFloat? private let content: Content init(alignment: VerticalAlignment = .center, spacing: CGFloat? = nil, @ViewBuilder content: () -> Content) { self.alignment = alignment self.spacing = spacing self.content = content() } var body: some View { HStack(alignment: alignment, spacing: spacing) { content } .padding(.horizontal) .padding(.vertical) .background(Color(NSColor.windowBackgroundColor)) .cornerRadius(8) } } struct PostDetailView: View { @Environment(\.language) private var language @ObservedObject private var post: Post @State private var newId: String @State private var showLinkedPagePicker = false init(post: Post) { self.post = post self.newId = post.id } private let allowedCharactersInPostId = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-")).inverted private var idExists: Bool { post.content.posts.contains { $0.id == newId } } private var containsInvalidCharacters: Bool { newId.rangeOfCharacter(from: allowedCharactersInPostId) != nil } var body: some View { ScrollView { VStack(alignment: .leading) { Text("ID") .font(.headline) HStack { TextField("", text: $newId) .textFieldStyle(.roundedBorder) Button("Update", action: setNewId) .disabled(newId.isEmpty || containsInvalidCharacters || idExists) } .padding(.bottom) HStack { Text("Draft") .font(.headline) Spacer() Toggle("", isOn: $post.isDraft) .toggleStyle(.switch) } .padding(.bottom) HStack { Text("Start") .font(.headline) Spacer() DatePicker("", selection: $post.startDate, displayedComponents: .date) .datePickerStyle(.compact) .padding(.bottom) } HStack(alignment: .firstTextBaseline) { Text("Has end date") .font(.headline) Spacer() Toggle("", isOn: $post.hasEndDate) .toggleStyle(.switch) .padding(.bottom) } if post.hasEndDate { HStack(alignment: .firstTextBaseline) { Text("End date") .font(.headline) Spacer() DatePicker("", selection: $post.endDate, displayedComponents: .date) .datePickerStyle(.compact) .padding(.bottom) } } HStack { Text("Linked page") .font(.headline) IconButton(symbol: .squareAndPencilCircleFill, size: 22, color: .blue) { showLinkedPagePicker = true } Spacer() } Text(post.linkedPage?.localized(in: language).title ?? "No page linked") LocalizedPostDetailView(post: post.localized(in: language)) } .padding() } .sheet(isPresented: $showLinkedPagePicker) { PagePickerView( showPagePicker: $showLinkedPagePicker, selectedPage: $post.linkedPage) } } private func setNewId() { guard post.update(id: newId) else { newId = post.id return } post.id = newId } } extension PostDetailView: MainContentView { init(item: Post) { self.init(post: item) } static let itemDescription = "a post" } #Preview(traits: .fixedLayout(width: 270, height: 500)) { PostDetailView(post: .fullMock) }