diff --git a/readeck/UI/Settings/ReleaseNotesView.swift b/readeck/UI/Settings/ReleaseNotesView.swift index a717155..76724af 100644 --- a/readeck/UI/Settings/ReleaseNotesView.swift +++ b/readeck/UI/Settings/ReleaseNotesView.swift @@ -1,5 +1,46 @@ import SwiftUI +extension AttributedString { + init(styledMarkdown markdownString: String) throws { + var output = try AttributedString( + markdown: markdownString, + options: .init( + allowsExtendedAttributes: true, + interpretedSyntax: .full, + failurePolicy: .returnPartiallyParsedIfPossible + ), + baseURL: nil + ) + + for (intentBlock, intentRange) in output.runs[AttributeScopes.FoundationAttributes.PresentationIntentAttribute.self].reversed() { + guard let intentBlock = intentBlock else { continue } + for intent in intentBlock.components { + switch intent.kind { + case .header(level: let level): + switch level { + case 1: + output[intentRange].font = .system(.title).bold() + case 2: + output[intentRange].font = .system(.title2).bold() + case 3: + output[intentRange].font = .system(.title3).bold() + default: + break + } + default: + break + } + } + + if intentRange.lowerBound != output.startIndex { + output.characters.insert(contentsOf: "\n\n", at: intentRange.lowerBound) + } + } + + self = output + } +} + struct ReleaseNotesView: View { @Environment(\.dismiss) private var dismiss @@ -33,10 +74,7 @@ struct ReleaseNotesView: View { private func loadReleaseNotes() -> AttributedString? { guard let url = Bundle.main.url(forResource: "RELEASE_NOTES", withExtension: "md"), let markdownContent = try? String(contentsOf: url), - let attributedString = try? AttributedString( - markdown: markdownContent, - options: .init(interpretedSyntax: .full) - ) else { + let attributedString = try? AttributedString(styledMarkdown: markdownContent) else { return nil } return attributedString