// // CodeBlockView.swift // Zyquo Cloud // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // // Fenced code block per the Phase 4 spec: surfaceSecondary card with medium // radius, uppercased language label top-left, hover copy button top-right // (with a brief checkmark confirmation), SF Mono content with syntax // highlighting, horizontal scrolling for long lines, and text selection. // import SwiftUI struct CodeBlockView: View { let code: String let language: String? let fontSize: Double @State private var hovering = false @State private var copied = false @State private var copyGeneration = 0 /// How long the copy confirmation checkmark stays visible. private static let copyConfirmationSeconds: Double = 1.2 var body: some View { VStack(alignment: .leading, spacing: 0) { header ScrollView(.horizontal) { SwiftUI.Text(highlighted) .font(ZyquoFont.code(size: max(fontSize - 1, 1))) .textSelection(.enabled) .fixedSize(horizontal: false, vertical: true) .padding(.horizontal, ZyquoSpacing.sm) .padding(.top, ZyquoSpacing.xxs) .padding(.bottom, ZyquoSpacing.xs) } } .background( RoundedRectangle(cornerRadius: ZyquoRadius.medium, style: .continuous) .fill(ZyquoColor.surfaceSecondary) ) .onHover { inside in withAnimation(ZyquoMotion.hover) { hovering = inside } } } // MARK: Header private var header: some View { HStack(spacing: ZyquoSpacing.xs) { if let language, !language.isEmpty { SwiftUI.Text(language.uppercased()) .font(ZyquoFont.caption) .foregroundStyle(ZyquoColor.textSecondary) } Spacer(minLength: ZyquoSpacing.xs) copyButton .opacity(hovering || copied ? 1 : 0) } .padding(.horizontal, ZyquoSpacing.sm) .padding(.top, ZyquoSpacing.xs) } private var copyButton: some View { Button(action: copy) { Image(systemName: copied ? "checkmark" : "doc.on.doc") .font(ZyquoFont.caption) .foregroundStyle(copied ? ZyquoColor.success : ZyquoColor.textSecondary) } .buttonStyle(PressableButtonStyle()) .accessibilityLabel("Copy code") .help("Copy code") } // MARK: Highlighting private var highlighted: AttributedString { SyntaxHighlighter.highlight(code, language: language, baseColor: ZyquoColor.textPrimary) } // MARK: Copy private func copy() { let pasteboard = NSPasteboard.general pasteboard.clearContents() pasteboard.setString(code, forType: .string) copyGeneration += 1 let generation = copyGeneration withAnimation(ZyquoMotion.hover) { copied = true } Task { try? await Task.sleep(for: .seconds(Self.copyConfirmationSeconds)) if generation == copyGeneration { withAnimation(ZyquoMotion.hover) { copied = false } } } } }