spb/zyquo-cloud Public MIT
Native macOS AI chat client for 12 cloud providers — your keys, every cloud model, one beautiful chat.
Swift 97.4%
Shell 1.7%
Makefile 1%
1//2// CodeBlockView.swift3// Zyquo Cloud4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// Fenced code block per the Phase 4 spec: surfaceSecondary card with medium9// radius, uppercased language label top-left, hover copy button top-right10// (with a brief checkmark confirmation), SF Mono content with syntax11// highlighting, horizontal scrolling for long lines, and text selection.12//1314import SwiftUI1516struct CodeBlockView: View {17 let code: String18 let language: String?19 let fontSize: Double2021 @State private var hovering = false22 @State private var copied = false23 @State private var copyGeneration = 02425 /// How long the copy confirmation checkmark stays visible.26 private static let copyConfirmationSeconds: Double = 1.22728 var body: some View {29 VStack(alignment: .leading, spacing: 0) {30 header31 ScrollView(.horizontal) {32 SwiftUI.Text(highlighted)33 .font(ZyquoFont.code(size: max(fontSize - 1, 1)))34 .textSelection(.enabled)35 .fixedSize(horizontal: false, vertical: true)36 .padding(.horizontal, ZyquoSpacing.sm)37 .padding(.top, ZyquoSpacing.xxs)38 .padding(.bottom, ZyquoSpacing.xs)39 }40 }41 .background(42 RoundedRectangle(cornerRadius: ZyquoRadius.medium, style: .continuous)43 .fill(ZyquoColor.surfaceSecondary)44 )45 .onHover { inside in46 withAnimation(ZyquoMotion.hover) { hovering = inside }47 }48 }4950 // MARK: Header5152 private var header: some View {53 HStack(spacing: ZyquoSpacing.xs) {54 if let language, !language.isEmpty {55 SwiftUI.Text(language.uppercased())56 .font(ZyquoFont.caption)57 .foregroundStyle(ZyquoColor.textSecondary)58 }59 Spacer(minLength: ZyquoSpacing.xs)60 copyButton61 .opacity(hovering || copied ? 1 : 0)62 }63 .padding(.horizontal, ZyquoSpacing.sm)64 .padding(.top, ZyquoSpacing.xs)65 }6667 private var copyButton: some View {68 Button(action: copy) {69 Image(systemName: copied ? "checkmark" : "doc.on.doc")70 .font(ZyquoFont.caption)71 .foregroundStyle(copied ? ZyquoColor.success : ZyquoColor.textSecondary)72 }73 .buttonStyle(PressableButtonStyle())74 .accessibilityLabel("Copy code")75 .help("Copy code")76 }7778 // MARK: Highlighting7980 private var highlighted: AttributedString {81 SyntaxHighlighter.highlight(code, language: language, baseColor: ZyquoColor.textPrimary)82 }8384 // MARK: Copy8586 private func copy() {87 let pasteboard = NSPasteboard.general88 pasteboard.clearContents()89 pasteboard.setString(code, forType: .string)9091 copyGeneration += 192 let generation = copyGeneration93 withAnimation(ZyquoMotion.hover) { copied = true }94 Task {95 try? await Task.sleep(for: .seconds(Self.copyConfirmationSeconds))96 if generation == copyGeneration {97 withAnimation(ZyquoMotion.hover) { copied = false }98 }99 }100 }101}102