// // GitSyncManualFixSheet.swift // Confab // // Manual-fix instructions for Git Sync's "untracked working tree files" pull failure — // shown in-app instead of deep-linking to the Help Book (NSWorkspace.shared.open() drops // #fragment anchors on file:// URLs, so an anchored help link always landed on the index). // // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 // Copyright (C) 2026 Rune Olsen // // This file is part of Confab. // // Confab is licensed under the PolyForm Noncommercial License 1.0.0. // You may use, study, modify, and share it for any noncommercial // purpose. Commercial use — including selling Confab or any part of // it, standalone or bundled into another product or service — // requires a separate commercial license from the copyright holder. // // See the LICENSE file or // for // the full license text. For commercial licensing, contact Rune // Olsen via . import SwiftUI struct GitSyncManualFixSheet: View { let files: [String] let syncPath: String let onDone: () -> Void var body: some View { VStack(alignment: .leading, spacing: 20) { HStack(spacing: 12) { Image(systemName: "wrench.and.screwdriver") .font(.title2) .foregroundStyle(.secondary) VStack(alignment: .leading, spacing: 2) { Text("Fix It Yourself") .font(.system(size: 17, weight: .semibold)) Text("Four steps, then Confab takes over again") .font(.system(size: 13)) .foregroundStyle(.secondary) } Spacer() } VStack(alignment: .leading, spacing: 14) { step(1, "Open your sync folder:") Text(syncPath) .font(.system(size: 13, design: .monospaced)) .textSelection(.enabled) .padding(10) .frame(maxWidth: .infinity, alignment: .leading) .background(Color.secondary.opacity(0.08)) .clipShape(RoundedRectangle(cornerRadius: 8)) step(2, "Delete the file\(files.count == 1 ? "" : "s") named in the error:") VStack(alignment: .leading, spacing: 4) { ForEach(files, id: \.self) { file in Text(file) .font(.system(size: 13, design: .monospaced)) } } .textSelection(.enabled) .padding(10) .frame(maxWidth: .infinity, alignment: .leading) .background(Color.secondary.opacity(0.08)) .clipShape(RoundedRectangle(cornerRadius: 8)) step(3, "Open Terminal, cd into that folder, and run this once:") Text("git pull --ff-only") .font(.system(size: 13, design: .monospaced)) .textSelection(.enabled) .padding(10) .frame(maxWidth: .infinity, alignment: .leading) .background(Color.secondary.opacity(0.08)) .clipShape(RoundedRectangle(cornerRadius: 8)) step(4, "That's it — Confab will regenerate the file correctly on its next sync.") } HStack { Spacer() Button("Done") { onDone() } .buttonStyle(.borderedProminent) .keyboardShortcut(.return, modifiers: []) } } .padding(24) .frame(width: 480) } @ViewBuilder private func step(_ number: Int, _ text: String) -> some View { HStack(alignment: .firstTextBaseline, spacing: 8) { Text("\(number).") .font(.system(size: 13, weight: .semibold)) .foregroundStyle(.secondary) Text(text) .font(.system(size: 13)) .fixedSize(horizontal: false, vertical: true) } } }