Open multiple documents per markdown file
This commit is contained in:
@@ -1,77 +1,34 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UniformTypeIdentifiers
|
|
||||||
import AppKit
|
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@State private var selectedFileURL: URL?
|
|
||||||
@State private var markdownContent: String = ""
|
|
||||||
|
|
||||||
var body: some View {
|
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 {
|
VStack {
|
||||||
Image(systemName: "doc.text")
|
Image(systemName: "doc.text")
|
||||||
.font(.system(size: 60))
|
.font(.system(size: 80))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
Text("Select a markdown file to preview")
|
Text("Markdown Viewer")
|
||||||
|
.font(.largeTitle)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
Text("Open markdown files from the File menu")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.padding()
|
.padding(.top, 8)
|
||||||
|
Text("⌘O")
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.font(.caption)
|
||||||
|
.padding(.top, 4)
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle("Markdown Viewer")
|
|
||||||
}
|
|
||||||
|
|
||||||
private func openFile() {
|
struct MarkdownDocumentView: View {
|
||||||
let panel = NSOpenPanel()
|
let content: String
|
||||||
panel.allowsMultipleSelection = false
|
let fileName: String
|
||||||
panel.canChooseDirectories = false
|
|
||||||
panel.canChooseFiles = true
|
|
||||||
panel.allowedContentTypes = [UTType.plainText, UTType(filenameExtension: "md")!]
|
|
||||||
|
|
||||||
if panel.runModal() == .OK {
|
var body: some View {
|
||||||
if let url = panel.url {
|
MarkdownRenderer(content: content)
|
||||||
selectedFileURL = url
|
.navigationTitle(fileName)
|
||||||
loadMarkdownFile(from: url)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,84 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import UniformTypeIdentifiers
|
||||||
|
import AppKit
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct MarkdownViewerApp: App {
|
struct MarkdownViewerApp: App {
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
Settings {
|
||||||
ContentView()
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user