I needed to patch SwiftyMarkdown into existing code. Styles needed to be compatible, strongly typed, consistent and readable. Here's my example of usage. Hope it helps someone.
Detail:
init() takes a list of markdown styles such as body and applies StyleProperty to them.
func applyStyles copies the custom properties to the styles.
enum StyleProperty provides the custom properties structure.
Code:
import AppKit
import SwiftUI
import SwiftyMarkdown
class MarkdownHelper {
static var shared: MarkdownHelper = MarkdownHelper()
static let customFontName = "Bitstream Vera Sans Mono"
var md : SwiftyMarkdown
private init() {
let md : SwiftyMarkdown = SwiftyMarkdown(string: "")
self.md = md
let size = 14
applyStyles(stylesMapping: [
md.body: [ // the default style
.fontName(customFontName),
.fontStyle(.normal),
.fontSize(size),
.color(PhosphorColors.white)
],
md.code: [ // the code style
.fontName(customFontName),
.fontStyle(.normal),
.fontSize(size),
.color(PhosphorColors.white),
],
md.h1: [
.fontName(customFontName),
.fontStyle(.bold),
.fontSize(size),
.color(PhosphorColors.brightWhite)
],
md.h2: [
.fontName(customFontName),
.fontStyle(.bold),
.fontSize(size),
.color(PhosphorColors.brightAmber)
],
md.h3: [
.fontName(customFontName),
.fontStyle(.bold),
.fontSize(size),
.color(PhosphorColors.brightCyan)
],
md.italic: [
.fontName(customFontName),
.fontStyle(.italic),
.fontSize(size),
.color(PhosphorColors.green)
],
md.bold: [
.fontName(customFontName),
.fontStyle(.bold),
.fontSize(size),
.color(PhosphorColors.overBrightGreen)
]
])
}
enum StyleProperty {
case fontName(String)
case color(NSColor)
case fontSize(CGFloat)
case fontStyle(FontStyle)
case alignment(NSTextAlignment)
case lineSpacing(CGFloat)
case paragraphSpacing(CGFloat)
case underlineStyle(NSUnderlineStyle)
case underlineColor(NSColor)
}
func applyStyles(stylesMapping: [NSObject: [StyleProperty]]) {
// Applying styles
for (instance, properties) in stylesMapping {
for property in properties {
switch property {
case .fontName(let value):
(instance as? BasicStyles)?.fontName = value
(instance as? LineStyles)?.fontName = value
case .color(let value):
(instance as? BasicStyles)?.color = value
(instance as? LineStyles)?.color = value
case .fontSize(let value):
(instance as? BasicStyles)?.fontSize = value
(instance as? LineStyles)?.fontSize = value
case .fontStyle(let value):
(instance as? BasicStyles)?.fontStyle = value
(instance as? LineStyles)?.fontStyle = value
case .alignment(let value):
(instance as? LineStyles)?.alignment = value
case .lineSpacing(let value):
(instance as? LineStyles)?.lineSpacing = value
case .paragraphSpacing(let value):
(instance as? LineStyles)?.paragraphSpacing = value
case .underlineStyle(let value):
(instance as? LinkStyles)?.underlineStyle = value
case .underlineColor(let value):
(instance as? LinkStyles)?.underlineColor = value
}
}
}
}
func parse(markdown: String) -> NSAttributedString {
md.string = markdown.replacingOccurrences(of: "\r\n", with: "\n") // the presumption is that styles do not change, otherwise we'd reinitialise all styles each time.
return md.attributedString()
}
struct PhosphorColors {
static let white : NSColor = NSColor(Color(#colorLiteral(red: 0.9159484512, green: 0.9159484512, blue: 0.9463420244, alpha: 1)))
static let amber : NSColor = NSColor(Color(#colorLiteral(red: 0.990, green: 0.857, blue: 0.205, alpha: 1)))
static let darkAmber : NSColor = NSColor(Color(#colorLiteral(red: 0.937, green: 0.622, blue: 0.227, alpha: 1)))
static let mediumBrightBlue : NSColor = NSColor(Color(#colorLiteral(red: 0.699, green: 0.834, blue: 0.929, alpha: 1)))
static let blue : NSColor = NSColor(Color(#colorLiteral(red: 0.623, green: 0.826, blue: 0.973, alpha: 1)))
static let darkBlue : NSColor = NSColor(Color(#colorLiteral(red: 0.343, green: 0.559, blue: 0.731, alpha: 1)))
static let overBrightGreen : NSColor = NSColor(Color(#colorLiteral(red: 0.596, green: 0.991, blue: 0.988, alpha: 1)))
static let darkGreen : NSColor = NSColor(Color(#colorLiteral(red: 0.400, green: 0.704, blue: 0.386, alpha: 1)))
static let green : NSColor = NSColor(Color(#colorLiteral(red: 0.231, green: 0.925, blue: 0.349, alpha: 1)))
static let noSignal : NSColor = NSColor(Color(#colorLiteral(red: 0.017, green: 0.198, blue: 1.000, alpha: 1)))
static let red : NSColor = NSColor(Color(#colorLiteral(red: 0.940, green: 0.300, blue: 0.280, alpha: 1)))
static let magenta : NSColor = NSColor(Color(#colorLiteral(red: 0.780, green: 0.360, blue: 0.780, alpha: 1)))
static let cyan : NSColor = NSColor(Color(#colorLiteral(red: 0.420, green: 0.840, blue: 0.780, alpha: 1)))
static let yellow : NSColor = NSColor(Color(#colorLiteral(red: 0.980, green: 0.880, blue: 0.240, alpha: 1)))
// Bright colors based on your existing colors
static let brightWhite : NSColor = NSColor(Color(#colorLiteral(red: 1.000, green: 1.000, blue: 1.000, alpha: 1)))
static let brightAmber : NSColor = NSColor(Color(#colorLiteral(red: 1.000, green: 0.922, blue: 0.531, alpha: 1)))
static let brightBrightBlue : NSColor = NSColor(Color(#colorLiteral(red: 0.792, green: 0.937, blue: 1.000, alpha: 1)))
static let brightBlue : NSColor = NSColor(Color(#colorLiteral(red: 0.792, green: 0.923, blue: 1.000, alpha: 1)))
static let brightDarkBlue : NSColor = NSColor(Color(#colorLiteral(red: 0.517, green: 0.735, blue: 1.000, alpha: 1)))
static let brightOverBrightGreen : NSColor = NSColor(Color(#colorLiteral(red: 0.800, green: 1.000, blue: 1.000, alpha: 1)))
static let brightDarkGreen : NSColor = NSColor(Color(#colorLiteral(red: 0.543, green: 0.893, blue: 0.756, alpha: 1)))
static let brightGreen : NSColor = NSColor(Color(#colorLiteral(red: 0.447, green: 1.000, blue: 0.752, alpha: 1)))
static let brightNoSignal : NSColor = NSColor(Color(#colorLiteral(red: 0.042, green: 0.556, blue: 1.000, alpha: 1)))
static let brightRed : NSColor = NSColor(Color(#colorLiteral(red: 1.000, green: 0.440, blue: 0.420, alpha: 1)))
static let brightMagenta : NSColor = NSColor(Color(#colorLiteral(red: 0.896, green: 0.501, blue: 0.896, alpha: 1)))
static let brightCyan : NSColor = NSColor(Color(#colorLiteral(red: 0.504, green: 0.954, blue: 0.934, alpha: 1)))
static let brightYellow : NSColor = NSColor(Color(#colorLiteral(red: 1.000, green: 0.930, blue: 0.300, alpha: 1)))
}
}
extension Color {
init(_ nsColor: NSColor) {
self.init(
red: Double(nsColor.redComponent),
green: Double(nsColor.greenComponent),
blue: Double(nsColor.blueComponent),
opacity: Double(nsColor.alphaComponent)
)
}
}
extension NSColor {
var asColor: Color {
let r = Double(redComponent)
let g = Double(greenComponent)
let b = Double(blueComponent)
let a = Double(alphaComponent)
return Color(.sRGB, red: r, green: g, blue: b, opacity: a)
}
}
Caveat: original code works fine but I've removed various code unneeded for the example.
I needed to patch SwiftyMarkdown into existing code. Styles needed to be compatible, strongly typed, consistent and readable. Here's my example of usage. Hope it helps someone.
Detail:
init()
takes a list of markdown styles such asbody
and appliesStyleProperty
to them.func applyStyles
copies the custom properties to the styles.enum StyleProperty
provides the custom properties structure.Code:
Caveat: original code works fine but I've removed various code unneeded for the example.