Skip to content
This repository was archived by the owner on Jul 2, 2025. It is now read-only.

DonaldoDes/SwiftDown

Β 
Β 

Repository files navigation

SwiftDown

πŸ“ Note: This is an enhanced fork of qeude/SwiftDown with extended wikilink functionality and AI-optimized documentation.

πŸ“– Description

SwiftDown is a markdown editor component for SwiftUI applications with built-in wikilink support.

πŸ†• What's New in This Fork

This enhanced version adds:

  • πŸ”— Complete Wikilink Implementation: Full [[Note Title]] syntax support with callbacks
  • 🎨 Wikilink Theming: Custom styling and theme integration
  • πŸ“± Platform-Specific Interactions: Touch (iOS) and hover (macOS) support
  • πŸ” Programmatic API: Extract and validate wikilinks in code
  • πŸ€– AI-Optimized Documentation: Copy-paste templates and integration guides
  • βœ… Comprehensive Testing: 73+ tests covering all wikilink functionality

✨ Key Features

  • πŸŽ‰ Live Preview: Real-time markdown rendering without web views
  • πŸ”— Wikilinks: Wikipedia-style [[Note Title]] linking with callbacks
  • ⚑️ Performance: Built on cmark for speed
  • πŸ—’ Standard Markdown: No proprietary formats
  • πŸ’»πŸ“± Cross-Platform: iOS and macOS support
  • 🎨 Themeable: Custom styling and built-in themes

πŸ› οΈ Installation

Swift Package Manager

Add to your Package.swift:

.package(url: "https://github.com/DonaldoDes/SwiftDown.git", from: "0.5.1")

Or in Xcode: File β†’ Add Package Dependencies β†’ https://github.com/DonaldoDes/SwiftDown.git

πŸš€ Quick Start

Step 1: Import SwiftDown

import SwiftDown
import SwiftUI

Step 2: Basic Markdown Editor

struct ContentView: View {
    @State private var text = "# Hello\nType **markdown** here!"

    var body: some View {
        SwiftDownEditor(text: $text)
            .theme(Theme.BuiltIn.defaultDark.theme())
            .insetsSize(20)
    }
}

Step 3: Add Wikilink Support

struct WikilinkEditor: View {
    @State private var text = "Welcome to [[My Notes]]!"

    var body: some View {
        SwiftDownEditor(text: $text)
            .onWikilinkTapped { title in
                print("Navigate to: \(title)")
                // Add your navigation logic here
            }
            .theme(Theme.BuiltIn.defaultLight.theme())
    }
}

πŸ”— Wikilinks

Wikilinks use [[Note Title]] syntax for note navigation. They are automatically detected, styled, and made interactive.

🎯 Implementation Patterns

Pattern 1: Basic Navigation

SwiftDownEditor(text: $text)
    .onWikilinkTapped { title in
        // REQUIRED: Handle navigation
        navigateToNote(title)
    }

func navigateToNote(_ title: String) {
    // Your implementation:
    // - Push new view
    // - Update navigation state  
    // - Load note content
    print("Navigate to: \(title)")
}

Pattern 2: With Validation

SwiftDownEditor(text: $text)
    .onWikilinkTapped { title in navigateToNote(title) }
    .wikilinkValidator { title in
        // REQUIRED: Return true if note exists
        return noteDatabase.contains(title)
    }

Pattern 3: Complete Integration

SwiftDownEditor(text: $text)
    .onWikilinkTapped { title in
        openNote(title)
    }
    .wikilinkValidator { title in
        noteManager.noteExists(title)
    }
    .wikilinkStyle(WikilinkStyle.defaultLight)
    .theme(Theme.BuiltIn.defaultLight.theme())

πŸ› οΈ Configuration API

Navigation (Required)

.onWikilinkTapped { title in
    // Called on tap/click - IMPLEMENT THIS
    handleNavigation(title)
}

Hover Support (macOS)

.onWikilinkHovered { title in
    if let title = title {
        showPreview(title)    // Hover started
    } else {
        hidePreview()         // Hover ended
    }
}

Validation (Optional)

.wikilinkValidator { title in
    // Return true if wikilink target exists
    return myNoteDatabase.hasNote(title)
}

Styling (Optional)

// Built-in styles
.wikilinkStyle(WikilinkStyle.defaultLight)  // Light theme
.wikilinkStyle(WikilinkStyle.defaultDark)   // Dark theme

// Custom style
.wikilinkStyle(WikilinkStyle(
    textColor: UniversalColor.blue,
    backgroundColor: UniversalColor.clear,
    underlineStyle: [],
    hoverUnderlineStyle: .patternDot
))

πŸ“Š Programmatic API

Extract and validate wikilinks in code:

// Create editor instance
let editor = SwiftDownEditor(text: $text)

// Get all wikilinks
let wikilinks = editor.getWikilinks()
for wikilink in wikilinks {
    print("Found: '\(wikilink.title)' at \(wikilink.range)")
}

// Validate with current validator
if let validation = editor.validateWikilinks() {
    for (title, isValid) in validation {
        print("'\(title)' is \(isValid ? "valid" : "invalid")")
    }
}

🎨 Theme Integration

// Method 1: Use built-in themes
SwiftDownEditor(text: $text)
    .theme(Theme.BuiltIn.defaultDark.theme())
    .wikilinkStyle(WikilinkStyle.defaultDark)

// Method 2: Custom theme file
SwiftDownEditor(text: $text)
    .theme(Theme(themePath: "path/to/theme.json"))
    .wikilinkStyle(customWikilinkStyle)

πŸ”„ Complete Implementation Template

Copy-Paste Template for AI Agents

import SwiftDown
import SwiftUI

struct MyMarkdownEditor: View {
    @State private var text = """
    # My Notes
    
    Welcome to [[Getting Started]]!
    Check out [[Project Ideas]] and [[References]].
    """
    
    var body: some View {
        SwiftDownEditor(text: $text)
            // STEP 1: Required - Handle wikilink navigation
            .onWikilinkTapped { title in
                handleWikilinkNavigation(title)
            }
            // STEP 2: Optional - Validate wikilinks
            .wikilinkValidator { title in
                return validateWikilink(title)
            }
            // STEP 3: Optional - macOS hover support
            .onWikilinkHovered { title in
                handleWikilinkHover(title)
            }
            // STEP 4: Optional - Custom styling
            .wikilinkStyle(WikilinkStyle.defaultLight)
            // STEP 5: Required - Set theme
            .theme(Theme.BuiltIn.defaultLight.theme())
            .insetsSize(20)
    }
    
    // IMPLEMENT: Navigation logic
    private func handleWikilinkNavigation(_ title: String) {
        print("Navigate to: \(title)")
        // TODO: Add your navigation implementation:
        // - navigationController.push(NoteView(title))
        // - Router.navigate(to: .note(title))
        // - selectedNote = title
    }
    
    // IMPLEMENT: Validation logic
    private func validateWikilink(_ title: String) -> Bool {
        // TODO: Check if note exists in your data store
        let existingNotes = ["Getting Started", "Project Ideas", "References"]
        return existingNotes.contains(title)
    }
    
    // IMPLEMENT: Hover logic (macOS only)
    private func handleWikilinkHover(_ title: String?) {
        if let title = title {
            print("Hovering: \(title)")
            // TODO: Show preview popup
        } else {
            print("Hover ended")
            // TODO: Hide preview popup
        }
    }
}

πŸ“‹ Quick Reference

Essential Methods

// REQUIRED: Navigation callback
.onWikilinkTapped { title in /* handle navigation */ }

// OPTIONAL: Validation  
.wikilinkValidator { title in /* return bool */ }

// OPTIONAL: Hover (macOS)
.onWikilinkHovered { title in /* handle hover */ }

// OPTIONAL: Styling
.wikilinkStyle(WikilinkStyle.defaultLight)

Built-in Themes

Theme.BuiltIn.defaultLight.theme()  // Light theme
Theme.BuiltIn.defaultDark.theme()   // Dark theme

Wikilink Styles

WikilinkStyle.defaultLight  // Blue text, no underline
WikilinkStyle.defaultDark   // Light blue text, no underline

Data Extraction

let wikilinks = editor.getWikilinks()           // Get all wikilinks
let validation = editor.validateWikilinks()     // Validate all

🎯 Integration Checklist for AI Agents

  • Import SwiftDown and SwiftUI
  • Create @State private var text with initial content
  • Add SwiftDownEditor(text: $text) to view
  • Implement .onWikilinkTapped { } callback (REQUIRED)
  • Add .theme() modifier (REQUIRED)
  • Test wikilink syntax: [[Note Title]]
  • Optional: Add .wikilinkValidator { } for validation
  • Optional: Add .wikilinkStyle() for custom styling
  • Optional: Add .onWikilinkHovered { } for macOS hover

Result: Functional markdown editor with clickable wikilinks

See SwiftDown-Wikilink-Specifications.md for technical details.

🎨 Themes

Built-in Themes

// Light theme
.theme(Theme.BuiltIn.defaultLight.theme())

// Dark theme  
.theme(Theme.BuiltIn.defaultDark.theme())
Default Light
Default Dark

Custom Themes

// From JSON file
let customTheme = Theme(themePath: "path/to/theme.json")
SwiftDownEditor(text: $text).theme(customTheme)

// Programmatic theme
let theme = Theme()
// Configure theme properties...
SwiftDownEditor(text: $text).theme(theme)

See theme JSON format: default-dark.json


πŸ“š Resources

πŸ‘¨πŸ»β€πŸ’» Authors

Original Author

Quentin Eude - GitHub β€’ LinkedIn

Fork Maintainer

DonaldoDes - GitHub

This enhanced fork adds comprehensive wikilink functionality, AI-optimized documentation, and additional features while maintaining compatibility with the original SwiftDown API.

About

πŸ“¦ A themable markdown editor component for your SwiftUI apps.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Swift 100.0%