From a921131ea7faa3facbadd4e70618599aad4d9db8 Mon Sep 17 00:00:00 2001 From: 0x8664b2 <0x8664b2@pm.me> Date: Fri, 20 Jun 2025 09:58:53 -0700 Subject: [PATCH] Open multiple documents per markdown file --- MarkdownViewer/ContentView.swift | 95 +++++++------------------- MarkdownViewer/MarkdownViewerApp.swift | 78 ++++++++++++++++++++- 2 files changed, 102 insertions(+), 71 deletions(-) diff --git a/MarkdownViewer/ContentView.swift b/MarkdownViewer/ContentView.swift index 15d8da0..503de45 100644 --- a/MarkdownViewer/ContentView.swift +++ b/MarkdownViewer/ContentView.swift @@ -1,77 +1,34 @@ import SwiftUI -import UniformTypeIdentifiers -import AppKit struct ContentView: View { - @State private var selectedFileURL: URL? - @State private var markdownContent: String = "" + var body: some View { + VStack { + Image(systemName: "doc.text") + .font(.system(size: 80)) + .foregroundColor(.secondary) + Text("Markdown Viewer") + .font(.largeTitle) + .fontWeight(.medium) + Text("Open markdown files from the File menu") + .foregroundColor(.secondary) + .padding(.top, 8) + Text("⌘O") + .foregroundColor(.secondary) + .font(.caption) + .padding(.top, 4) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct MarkdownDocumentView: View { + let content: String + let fileName: String var body: some View { - NavigationSplitView { - VStack { - Button("Open Markdown File") { - openFile() - } - .padding() - - if let url = selectedFileURL { - Text("File: \(url.lastPathComponent)") - .foregroundColor(.secondary) - .font(.caption) - .truncationMode(.middle) - .padding(.horizontal) - } - - Spacer() - } - .frame(minWidth: 200) - .navigationSplitViewColumnWidth(min: 200, ideal: 250) - } detail: { - if !markdownContent.isEmpty { - MarkdownRenderer(content: markdownContent) - .onAppear { - print("MarkdownRenderer appeared with content length: \(markdownContent.count)") - } - } else { - VStack { - Image(systemName: "doc.text") - .font(.system(size: 60)) - .foregroundColor(.secondary) - Text("Select a markdown file to preview") - .foregroundColor(.secondary) - .padding() - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - } - } - .navigationTitle("Markdown Viewer") - } - - private func openFile() { - let panel = NSOpenPanel() - panel.allowsMultipleSelection = false - panel.canChooseDirectories = false - panel.canChooseFiles = true - panel.allowedContentTypes = [UTType.plainText, UTType(filenameExtension: "md")!] - - if panel.runModal() == .OK { - if let url = panel.url { - selectedFileURL = url - loadMarkdownFile(from: url) - } - } - } - - private func loadMarkdownFile(from url: URL) { - do { - let content = try String(contentsOf: url, encoding: .utf8) - print("File loaded successfully, content length: \(content.count)") - print("First 100 characters: \(String(content.prefix(100)))") - markdownContent = content - } catch { - print("Error reading file: \(error)") - markdownContent = "Error loading file: \(error.localizedDescription)" - } + MarkdownRenderer(content: content) + .navigationTitle(fileName) + .frame(maxWidth: .infinity, maxHeight: .infinity) } } diff --git a/MarkdownViewer/MarkdownViewerApp.swift b/MarkdownViewer/MarkdownViewerApp.swift index 781b894..82540f6 100644 --- a/MarkdownViewer/MarkdownViewerApp.swift +++ b/MarkdownViewer/MarkdownViewerApp.swift @@ -1,10 +1,84 @@ import SwiftUI +import UniformTypeIdentifiers +import AppKit @main struct MarkdownViewerApp: App { var body: some Scene { - WindowGroup { - ContentView() + Settings { + EmptyView() + } + .commands { + CommandGroup(replacing: .newItem) { + Button("Open Markdown File...") { + openMarkdownFile() + } + .keyboardShortcut("o", modifiers: .command) + } + } + } + + private func openMarkdownFile() { + let panel = NSOpenPanel() + panel.allowsMultipleSelection = true + panel.canChooseDirectories = false + panel.canChooseFiles = true + panel.allowedContentTypes = [UTType.plainText, UTType(filenameExtension: "md")!] + + if panel.runModal() == .OK { + for url in panel.urls { + openNewWindow(for: url) + } + } + } + + private func openNewWindow(for url: URL) { + do { + let content = try String(contentsOf: url, encoding: .utf8) + let newWindow = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), + styleMask: [.titled, .closable, .resizable, .miniaturizable], + backing: .buffered, + defer: false + ) + + newWindow.title = url.lastPathComponent + newWindow.contentView = NSHostingView( + rootView: MarkdownDocumentView( + content: content, + fileName: url.lastPathComponent + ) + ) + newWindow.center() + newWindow.makeKeyAndOrderFront(nil) + + } catch { + print("Error reading file: \(error)") + // Show error in a new window + let newWindow = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 400, height: 200), + styleMask: [.titled, .closable], + backing: .buffered, + defer: false + ) + + newWindow.title = "Error" + newWindow.contentView = NSHostingView( + rootView: VStack { + Image(systemName: "exclamationmark.triangle") + .font(.system(size: 40)) + .foregroundColor(.red) + Text("Error loading file") + .font(.headline) + Text(error.localizedDescription) + .font(.caption) + .foregroundColor(.secondary) + .multilineTextAlignment(.center) + } + .padding() + ) + newWindow.center() + newWindow.makeKeyAndOrderFront(nil) } } } \ No newline at end of file