From 47f8f7366442afda47fd271789263f6618abb643 Mon Sep 17 00:00:00 2001 From: Ilyas Hallak Date: Sun, 19 Oct 2025 20:41:04 +0200 Subject: [PATCH] fix: Improve markdown formatting in release notes view Add custom AttributedString extension to properly format markdown with correct spacing and header styles. This fixes the compressed appearance of release notes by adding proper line breaks between sections and applying appropriate font sizes to headers. --- readeck/UI/Settings/ReleaseNotesView.swift | 46 ++++++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) 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