Domain Entities: Unit 5 — Export & Polish

ExportFormat

Enumerates the supported export target formats.

enum ExportFormat: String, CaseIterable, Identifiable {
    case html                                   // Standalone HTML file
    case pdf                                    // PDF document via WKWebView snapshot

    var id: String { rawValue }

    var fileExtension: String {
        switch self {
        case .html: return "html"
        case .pdf:  return "pdf"
        }
    }

    var utType: UTType {
        switch self {
        case .html: return .html
        case .pdf:  return .pdf
        }
    }
}

ExportResult

Outcome of an export operation, carrying either generated data or an error.

struct ExportResult {
    var format: ExportFormat
    var data: Data                              // Generated file bytes (HTML UTF-8 or PDF)
    var suggestedFileName: String               // e.g., "My Document.html"
    var sourceDocumentURL: URL?                 // Original .md file URL, if saved
}

ExportError

Typed errors for the export pipeline.

enum ExportError: LocalizedError {
    case emptySource                            // Source text is empty
    case htmlGenerationFailed(underlying: Error)
    case pdfRenderingFailed(underlying: Error)
    case pdfRenderingTimedOut                   // WKWebView snapshot exceeded timeout
    case fileWriteFailed(url: URL, underlying: Error)

    var errorDescription: String? {
        switch self {
        case .emptySource:
            return "Cannot export an empty document."
        case .htmlGenerationFailed(let e):
            return "HTML generation failed: \(e.localizedDescription)"
        case .pdfRenderingFailed(let e):
            return "PDF rendering failed: \(e.localizedDescription)"
        case .pdfRenderingTimedOut:
            return "PDF rendering timed out."
        case .fileWriteFailed(let url, let e):
            return "Failed to write \(url.lastPathComponent): \(e.localizedDescription)"
        }
    }
}

HTMLTemplate

Encapsulates the HTML document structure used for both HTML export and PDF rendering input.

struct HTMLTemplate {
    var title: String                           // <title> and <h1> if desired
    var cssStyles: String                       // Embedded CSS (light/dark aware)
    var bodyHTML: String                         // Rendered Markdown content as HTML
    var baseURL: URL?                           // For resolving relative image paths

    func assembleFullDocument() -> String {
        // Returns complete <!DOCTYPE html>...<html>...</html>
    }
}

Default CSS Rules

Element Style Rationale
body font-family: -apple-system; max-width: 720px; margin: auto Clean reading width, system font
h1-h6 Scaled sizes matching editor rendering Visual consistency with WYSIWYG
code font-family: SF Mono; background: #f5f5f5 Matches editor code block styling
blockquote border-left: 3px solid #ccc; padding-left: 1em Standard blockquote convention
table border-collapse: collapse; border: 1px solid #ddd Readable table presentation
img max-width: 100% Prevent overflow

PDFConfiguration

Settings for PDF generation via WKWebView snapshot.

struct PDFConfiguration {
    var paperSize: CGSize                       // Default: A4 (595.28 x 841.89 points)
    var margins: NSEdgeInsets                   // Default: 72pt (1 inch) all sides
    var timeoutInterval: TimeInterval           // Default: 30 seconds
    var includeBackgroundGraphics: Bool         // Default: true
}

Paper Size Presets

Preset Width (pt) Height (pt)
A4 595.28 841.89
US Letter 612 792

SidebarItem

Represents a single entry displayed in the recent files sidebar.

struct SidebarItem: Identifiable, Equatable {
    let id: UUID
    var displayName: String                     // File name without .md extension
    var url: URL                                // File URL for opening
    var lastOpened: Date                        // For sorting (most recent first)
    var isCurrentDocument: Bool                 // Highlighted if this is the active document
}

SidebarState

Tracks sidebar visibility and selection state.

@Observable
class SidebarState {
    var isVisible: Bool                         // Toggle via toolbar button or Cmd+Shift+L
    var selectedItemID: SidebarItem.ID?         // Currently selected (highlighted) item
    var items: [SidebarItem]                    // Recent files list, sorted by lastOpened descending

    init() {
        self.isVisible = true                   // Visible by default
        self.selectedItemID = nil
        self.items = []
    }
}

AppearanceMode (defined in Unit 2)

Referenced from EditorSettings.appearanceOverride. Governs light/dark mode behavior across the entire app.

// Defined in Unit 2 — EditorSettings
enum AppearanceMode: String, CaseIterable, Codable {
    case system                                 // Follow macOS System Preferences
    case light                                  // Force light appearance
    case dark                                   // Force dark appearance
}

NSAppearance Mapping

AppearanceMode NSAppearance.Name Behavior
.system nil (inherit) Follows macOS system setting; updates automatically on system toggle
.light .aqua Forces light mode regardless of system setting
.dark .darkAqua Forces dark mode regardless of system setting

AppearanceColors

Semantic color set for theming. All colors resolve dynamically based on current effective appearance.

struct AppearanceColors {
    // Editor
    var editorBackground: NSColor               // Light: .white, Dark: #1E1E1E
    var editorText: NSColor                     // Light: .black, Dark: #D4D4D4
    var editorCursor: NSColor                   // Follows system accent color

    // Sidebar
    var sidebarBackground: NSColor              // Light: .windowBackgroundColor, Dark: .windowBackgroundColor
    var sidebarItemText: NSColor                // Light: .labelColor, Dark: .labelColor
    var sidebarItemSelected: NSColor            // System accent with alpha
    var sidebarSeparator: NSColor               // .separatorColor (auto light/dark)

    // Toolbar
    var toolbarBackground: NSColor              // .windowBackgroundColor (auto)

    // Syntax highlighting (active block)
    var syntaxDelimiter: NSColor                // .secondaryLabelColor (auto)
    var syntaxLink: NSColor                     // .linkColor (auto)
    var syntaxCodeFence: NSColor                // .systemOrange (auto)
    var syntaxBlockquoteMarker: NSColor         // .systemGreen (auto)

    static func resolved(for appearance: NSAppearance) -> AppearanceColors
}

Factory Defaults

Setting Default Value Rationale
ExportFormat .html Most common export target
PDFConfiguration.paperSize A4 International standard
PDFConfiguration.margins 72pt all sides Standard 1-inch margins
PDFConfiguration.timeoutInterval 30s Generous for complex documents
SidebarState.isVisible true Sidebar visible by default for discoverability
AppearanceMode .system Respect user’s macOS setting