diff --git a/NeoDB/NeoDB.xcodeproj/project.pbxproj b/NeoDB/NeoDB.xcodeproj/project.pbxproj
index 7fe1246..e9742a6 100644
--- a/NeoDB/NeoDB.xcodeproj/project.pbxproj
+++ b/NeoDB/NeoDB.xcodeproj/project.pbxproj
@@ -7,8 +7,10 @@
objects = {
/* Begin PBXBuildFile section */
+ 2403E7662D2EF7CC00ED4CB5 /* HTML2Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = 2403E7652D2EF7CC00ED4CB5 /* HTML2Markdown */; };
242688402D2A9E0D00DFAAC1 /* InjectionNext in Frameworks */ = {isa = PBXBuildFile; productRef = 2426883F2D2A9E0D00DFAAC1 /* InjectionNext */; };
245FD2132D2A817A005B55B3 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 245FD2122D2A817A005B55B3 /* KeychainSwift */; };
+ 249B951D2D2EF5C800FE3D95 /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 249B951C2D2EF5C800FE3D95 /* MarkdownUI */; };
24D1BE412D2A9F340063B530 /* Inject in Frameworks */ = {isa = PBXBuildFile; productRef = 24D1BE402D2A9F340063B530 /* Inject */; };
/* End PBXBuildFile section */
@@ -73,7 +75,9 @@
files = (
245FD2132D2A817A005B55B3 /* KeychainSwift in Frameworks */,
242688402D2A9E0D00DFAAC1 /* InjectionNext in Frameworks */,
+ 2403E7662D2EF7CC00ED4CB5 /* HTML2Markdown in Frameworks */,
24D1BE412D2A9F340063B530 /* Inject in Frameworks */,
+ 249B951D2D2EF5C800FE3D95 /* MarkdownUI in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -145,6 +149,8 @@
245FD2122D2A817A005B55B3 /* KeychainSwift */,
2426883F2D2A9E0D00DFAAC1 /* InjectionNext */,
24D1BE402D2A9F340063B530 /* Inject */,
+ 249B951C2D2EF5C800FE3D95 /* MarkdownUI */,
+ 2403E7652D2EF7CC00ED4CB5 /* HTML2Markdown */,
);
productName = NeoDB;
productReference = 24CEACEF2D0DA6200083D4BA /* NeoDB.app */;
@@ -232,6 +238,8 @@
245FD2112D2A817A005B55B3 /* XCRemoteSwiftPackageReference "keychain-swift" */,
2415DF2F2D2A9DCC00DAC07F /* XCRemoteSwiftPackageReference "InjectionNext" */,
24AFFC8E2D2A9F040085A6D0 /* XCRemoteSwiftPackageReference "Inject" */,
+ 249B95192D2EF5B500FE3D95 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */,
+ 2403E7622D2EF7AE00ED4CB5 /* XCRemoteSwiftPackageReference "HTML2Markdown" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 24CEACF02D0DA6200083D4BA /* Products */;
@@ -631,6 +639,14 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
+ 2403E7622D2EF7AE00ED4CB5 /* XCRemoteSwiftPackageReference "HTML2Markdown" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/divadretlaw/HTML2Markdown";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 3.0.2;
+ };
+ };
2415DF2F2D2A9DCC00DAC07F /* XCRemoteSwiftPackageReference "InjectionNext" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/johnno1962/InjectionNext";
@@ -647,6 +663,14 @@
minimumVersion = 24.0.0;
};
};
+ 249B95192D2EF5B500FE3D95 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/gonzalezreal/swift-markdown-ui";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 2.4.1;
+ };
+ };
24AFFC8E2D2A9F040085A6D0 /* XCRemoteSwiftPackageReference "Inject" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/krzysztofzablocki/Inject.git";
@@ -658,6 +682,11 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
+ 2403E7652D2EF7CC00ED4CB5 /* HTML2Markdown */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 2403E7622D2EF7AE00ED4CB5 /* XCRemoteSwiftPackageReference "HTML2Markdown" */;
+ productName = HTML2Markdown;
+ };
2426883F2D2A9E0D00DFAAC1 /* InjectionNext */ = {
isa = XCSwiftPackageProductDependency;
package = 2415DF2F2D2A9DCC00DAC07F /* XCRemoteSwiftPackageReference "InjectionNext" */;
@@ -668,6 +697,11 @@
package = 245FD2112D2A817A005B55B3 /* XCRemoteSwiftPackageReference "keychain-swift" */;
productName = KeychainSwift;
};
+ 249B951C2D2EF5C800FE3D95 /* MarkdownUI */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 249B95192D2EF5B500FE3D95 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */;
+ productName = MarkdownUI;
+ };
24D1BE402D2A9F340063B530 /* Inject */ = {
isa = XCSwiftPackageProductDependency;
package = 24AFFC8E2D2A9F040085A6D0 /* XCRemoteSwiftPackageReference "Inject" */;
diff --git a/NeoDB/NeoDB.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NeoDB/NeoDB.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index de23583..2338c88 100644
--- a/NeoDB/NeoDB.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/NeoDB/NeoDB.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,6 +1,15 @@
{
- "originHash" : "657466b00a4cf16eda52a23bd963af27f6da71d69047ed11c12b2a367c93a6ba",
+ "originHash" : "3e7121260e0594c3a45cf5123fec5e95f05a024e1d9a426ddcda347f395a2ad2",
"pins" : [
+ {
+ "identity" : "html2markdown",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/divadretlaw/HTML2Markdown",
+ "state" : {
+ "revision" : "fe37711094b261d9fceeaf021143002ba37e563e",
+ "version" : "3.0.2"
+ }
+ },
{
"identity" : "inject",
"kind" : "remoteSourceControl",
@@ -27,6 +36,42 @@
"revision" : "5e1b02b6a9dac2a759a1d5dbc175c86bd192a608",
"version" : "24.0.0"
}
+ },
+ {
+ "identity" : "networkimage",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/gonzalezreal/NetworkImage",
+ "state" : {
+ "revision" : "2849f5323265386e200484b0d0f896e73c3411b9",
+ "version" : "6.0.1"
+ }
+ },
+ {
+ "identity" : "swift-cmark",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/swiftlang/swift-cmark",
+ "state" : {
+ "revision" : "3ccff77b2dc5b96b77db3da0d68d28068593fa53",
+ "version" : "0.5.0"
+ }
+ },
+ {
+ "identity" : "swift-markdown-ui",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/gonzalezreal/swift-markdown-ui",
+ "state" : {
+ "revision" : "5f613358148239d0292c0cef674a3c2314737f9e",
+ "version" : "2.4.1"
+ }
+ },
+ {
+ "identity" : "swiftsoup",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/scinfu/SwiftSoup.git",
+ "state" : {
+ "revision" : "0837db354faf9c9deb710dc597046edaadf5360f",
+ "version" : "2.7.6"
+ }
}
],
"version" : 3
diff --git a/NeoDB/NeoDB/References/Cursor/timeline_local.md b/NeoDB/NeoDB/References/Cursor/timeline_local.md
index a12c333..6ecdc5a 100644
--- a/NeoDB/NeoDB/References/Cursor/timeline_local.md
+++ b/NeoDB/NeoDB/References/Cursor/timeline_local.md
@@ -1,7 +1,7 @@
# Timeline Local-Only Implementation
## Overview
-Modified TimelineService to show only local statuses from the instance.
+Modified TimelineService to show only local statuses from the instance and properly render HTML content.
## API Reference
From Mastodon API documentation:
@@ -9,18 +9,46 @@ From Mastodon API documentation:
- Parameter: `local=true` to show only local statuses
- Default: Shows both local and remote statuses (local=false)
+## Content Rendering
+Status content comes in HTML format with the following features:
+- Links with href attributes
+- Mentions with rel attributes
+- Emoji ratings (π for filled stars)
+- Paragraphs with spacing
+
+### HTML Example
+```html
+
ηι η΅ε½±εη§° πππππ
+```
+
+### Implementation Details
+1. Added SwiftDown package for HTML parsing
+2. Created custom AttributedString converter
+3. Added link handling support
+4. Implemented emoji rating display
+
+## Dependencies
+Required SPM packages:
+- SwiftDown: HTML and Markdown parsing
+- SwiftSoup (optional): Advanced HTML manipulation
+
## Implementation Details
1. Added local parameter to URL query
2. Set local=true by default to show only local statuses
3. Improved error logging for better debugging
+4. Added HTML content parsing and rendering
+5. Implemented link handling and styling
## Design Rationale
- Local-only timeline provides more relevant content for NeoDB users
- Reduces noise from remote instances
- Improves performance by reducing data load
- Better content moderation as all content is from the same instance
+- Rich text rendering enhances readability and interaction
## Code Changes
- Modified getTimeline method in TimelineService
- Added local parameter to URLComponents
-- Updated documentation
\ No newline at end of file
+- Added HTML content rendering support
+- Updated documentation
+- Enhanced StatusView with rich text support
\ No newline at end of file
diff --git a/NeoDB/NeoDB/References/Packages/HTML2Markdown.md b/NeoDB/NeoDB/References/Packages/HTML2Markdown.md
new file mode 100644
index 0000000..d73afbb
--- /dev/null
+++ b/NeoDB/NeoDB/References/Packages/HTML2Markdown.md
@@ -0,0 +1,41 @@
+# HTML2Markdown
+
+## What is this?
+
+It's a Swift Package which attempts to convert HTML into Markdown.
+
+## How do I use it?
+
+```swift
+let html = "This is a terrible idea.
I must be daft.
"
+
+do {
+ let dom = try HTMLParser().parse(html: html)
+ let markdown = dom.markdownFormatted(options: .unorderedListBullets)
+ print(markdown)
+} catch {
+ // parsing error
+}
+```
+
+This generates the following markdown string:
+
+```
+This is a *terrible* idea.\nI must be daft.
+```
+
+## What is supported?
+
+* `` and `` for highlighting text
+* ordered and unordered lists (`` and ``)
+* paragraphs (``) and line breaks (`
`)
+* hyperlinks (``)
+
+All other HTML tags are removed.
+
+> Note:
+> `SwiftUI.Text` currently cannot render Markdown lists therefore use the `MarkdownGenerator.Options.unorderedListBullets` option to generate nicer-looking bullets: `β’` instead of `*`.
+
+## License
+
+See [LICENSE](LICSNE)
diff --git a/NeoDB/NeoDB/References/Packages/SwiftHTMLToMarkdown.md b/NeoDB/NeoDB/References/Packages/SwiftHTMLToMarkdown.md
new file mode 100644
index 0000000..3ce8738
--- /dev/null
+++ b/NeoDB/NeoDB/References/Packages/SwiftHTMLToMarkdown.md
@@ -0,0 +1,20 @@
+# Swift HTML -> Markdown
+This package allows you to quickly convert HTML code into Markdown. Normally you want to go from Markdown -> HTML and there are a thousand packages and parsers to do that. However, what if the service you are using (like Mastodon) provides everything in HTML but you want to parse it in Markdown? Well you need to convert it. This package allows you to do just that!
+
+## Supported Flavors of HTML
+| Flavor | Support |
+| -------------------- | --------------------------------------------------- |
+| Mastodon Status HTML (MastodonHTML) | β
|
+| Basic HTML (BasicHTML) | β οΈ (Almost fully supported, tables are not) |
+
+## How to use
+Using the library is pretty simple. The first step is to pick which HTML flavor you are going to be converting. If you are converting a Basic HTML document you can use the `BasicHTML` class. For Mastodon statuses you can use the `MastodonHTML` class.
+
+Once you have picked out the class you will be using, the following code is all you need!
+```swift
+var document = BasicHTML(rawHTML: raw)
+try document.parse()
+
+let markdown = try document.asMarkdown()
+print(markdwon)
+```
diff --git a/NeoDB/NeoDB/References/Packages/swift-markdown-ui/Articles/GettingStarted.md b/NeoDB/NeoDB/References/Packages/swift-markdown-ui/Articles/GettingStarted.md
new file mode 100755
index 0000000..d50a585
--- /dev/null
+++ b/NeoDB/NeoDB/References/Packages/swift-markdown-ui/Articles/GettingStarted.md
@@ -0,0 +1,197 @@
+# Getting started
+
+Learn how to display and style Markdown text in SwiftUI.
+
+## Creating a Markdown view
+
+A `Markdown` view displays rich structured text using the Markdown syntax. It can display images,
+headings, lists (including task lists), blockquotes, code blocks, tables, and thematic breaks,
+besides styled text and links.
+
+The simplest way of creating a `Markdown` view is to pass a Markdown string to the
+``Markdown/init(_:baseURL:imageBaseURL:)-63py1`` initializer.
+
+```swift
+let markdownString = """
+ ## Try MarkdownUI
+
+ **MarkdownUI** is a native Markdown renderer for SwiftUI
+ compatible with the
+ [GitHub Flavored Markdown Spec](https://github.github.com/gfm/).
+ """
+
+var body: some View {
+ Markdown(markdownString)
+}
+```
+
+![](MarkdownString)
+
+A more convenient way to create a `Markdown` view is by using the
+``Markdown/init(baseURL:imageBaseURL:content:)`` initializer, which takes a Markdown content
+builder in which you can compose the view content, either by providing Markdown strings or by
+using an expressive domain-specific language.
+
+```swift
+var body: some View {
+ Markdown {
+ """
+ ## Using a Markdown Content Builder
+ Use Markdown strings or an expressive domain-specific language
+ to build the content.
+ """
+ Heading(.level2) {
+ "Try MarkdownUI"
+ }
+ Paragraph {
+ Strong("MarkdownUI")
+ " is a native Markdown renderer for SwiftUI"
+ " compatible with the "
+ InlineLink(
+ "GitHub Flavored Markdown Spec",
+ destination: URL(string: "https://github.github.com/gfm/")!
+ )
+ "."
+ }
+ }
+}
+```
+
+![](MarkdownContentBuilder)
+
+You can also create a ``MarkdownContent`` value in your model layer and later create a `Markdown`
+view by passing the content value to the ``Markdown/init(_:baseURL:imageBaseURL:)-42bru``
+initializer. The ``MarkdownContent`` value pre-parses the Markdown string preventing the view from
+doing this step.
+
+```swift
+// Somewhere in the model layer
+let content = MarkdownContent("You can try **CommonMark** [here](https://spec.commonmark.org/dingus/).")
+
+// Later in the view layer
+var body: some View {
+ Markdown(self.model.content)
+}
+```
+
+## Styling Markdown
+
+Markdown views use a basic default theme to display the contents. For more information, read about
+the ``Theme/basic`` theme.
+
+```swift
+Markdown {
+ """
+ You can quote text with a `>`.
+
+ > Outside of a dog, a book is man's best friend. Inside of a
+ > dog it's too dark to read.
+
+ β Groucho Marx
+ """
+}
+```
+
+![](BlockquoteContent)
+
+You can customize the appearance of Markdown content by applying different themes using the
+`markdownTheme(_:)` modifier. For example, you can apply one of the built-in themes, like
+``Theme/gitHub``, to either a Markdown view or a view hierarchy that contains Markdown views.
+
+```swift
+Markdown {
+ """
+ You can quote text with a `>`.
+
+ > Outside of a dog, a book is man's best friend. Inside of a
+ > dog it's too dark to read.
+
+ β Groucho Marx
+ """
+}
+.markdownTheme(.gitHub)
+```
+
+![](GitHubBlockquote)
+
+To override a specific text style from the current theme, use the `markdownTextStyle(_:textStyle:)`
+modifier. The following example shows how to override the ``Theme/code`` text style.
+
+```swift
+Markdown {
+ """
+ Use `git status` to list all new or modified files
+ that haven't yet been committed.
+ """
+}
+.markdownTextStyle(\.code) {
+ FontFamilyVariant(.monospaced)
+ FontSize(.em(0.85))
+ ForegroundColor(.purple)
+ BackgroundColor(.purple.opacity(0.25))
+}
+```
+
+![](CustomInlineCode)
+
+You can also use the `markdownBlockStyle(_:body:)` modifier to override a specific block style. For
+example, you can override only the ``Theme/blockquote`` block style, leaving other block styles
+untouched.
+
+```swift
+Markdown {
+ """
+ You can quote text with a `>`.
+
+ > Outside of a dog, a book is man's best friend. Inside of a
+ > dog it's too dark to read.
+
+ β Groucho Marx
+ """
+}
+.markdownBlockStyle(\.blockquote) { configuration in
+ configuration.label
+ .padding()
+ .markdownTextStyle {
+ FontCapsVariant(.lowercaseSmallCaps)
+ FontWeight(.semibold)
+ BackgroundColor(nil)
+ }
+ .overlay(alignment: .leading) {
+ Rectangle()
+ .fill(Color.teal)
+ .frame(width: 4)
+ }
+ .background(Color.teal.opacity(0.5))
+}
+```
+
+![](CustomBlockquote)
+
+Another way to customize the appearance of Markdown content is to create your own theme. To create
+a theme, start by instantiating an empty ``Theme`` and chain together the different text and block
+styles in a single expression.
+
+```swift
+extension Theme {
+ static let fancy = Theme()
+ .code {
+ FontFamilyVariant(.monospaced)
+ FontSize(.em(0.85))
+ }
+ .link {
+ ForegroundColor(.purple)
+ }
+ // More text styles...
+ .paragraph { configuration in
+ configuration.label
+ .relativeLineSpacing(.em(0.25))
+ .markdownMargin(top: 0, bottom: 16)
+ }
+ .listItem { configuration in
+ configuration.label
+ .markdownMargin(top: .em(0.25))
+ }
+ // More block styles...
+}
+```
diff --git a/NeoDB/NeoDB/References/Packages/swift-markdown-ui/Articles/MigratingToVersion2.md b/NeoDB/NeoDB/References/Packages/swift-markdown-ui/Articles/MigratingToVersion2.md
new file mode 100755
index 0000000..393d150
--- /dev/null
+++ b/NeoDB/NeoDB/References/Packages/swift-markdown-ui/Articles/MigratingToVersion2.md
@@ -0,0 +1,80 @@
+# Migrating to MarkdownUI 2
+
+Learn how to migrate existing apps using MarkdownUI 1.x to the latest version of the library.
+
+## Overview
+
+MarkdownUI 2 has been rewritten from scratch and brings a ton of new features and improvements
+like:
+
+- [GitHub Flavored Markdown](https://github.github.com/gfm/) (tables, task lists,
+ strikethrough text, and autolinks)
+- Native SwiftUI rendering
+- Customization support via themes, text styles, and block styles.
+
+These new features come with the cost of a few breaking changes that this guide will help you to
+address.
+
+## Minimum requirements
+
+You can use MarkdownUI 2 on the following platforms:
+
+- macOS 12.0+
+- iOS 15.0+
+- tvOS 15.0+
+- watchOS 8.0+
+
+Some features, like displaying tables or multi-image paragraphs, require macOS 13.0+, iOS 16.0+,
+tvOS 16.0+, and watchOS 9.0+.
+
+## Creating Markdown content
+
+MarkdownUI 2 introduces a new domain-specific language to create Markdown content and no longer
+depends on [gonzalezreal/SwiftCommonMark](https://github.com/gonzalezreal/SwiftCommonMark).
+
+One significant difference when using MarkdownUI 2 is that ``MarkdownContent`` replaces `Document`
+by providing similar functionality.
+
+Another thing to be aware of is the different naming of some of the types you use to compose
+Markdown content:
+
+- Use ``Blockquote`` instead of `BlockQuote`.
+- Use ``NumberedList`` instead of `OrderedList`.
+- Use ``BulletedList`` instead of `BulletList`.
+- Use ``InlineImage`` instead of `Image`.
+- Use ``InlineLink`` instead of `Link`.
+- Use ``Code`` instead of `InlineCode`.
+
+## Loading asset images
+
+MarkdownUI 2 introduces the ``ImageProvider`` protocol and its conforming types
+``DefaultImageProvider`` and ``AssetImageProvider``. These types and the new
+`markdownImageProvider(_:)` modifier replace the `MarkdownImageHandler` type and
+the `setImageHandler(_:forURLScheme:)` modifier.
+
+The following example shows how to configure the asset image provider to load images from the
+main bundle.
+
+```swift
+Markdown {
+ "![A dog](dog)"
+ "β Photo by AndrΓ© Spieker"
+}
+.markdownImageProvider(.asset)
+```
+
+## Customizing link behavior
+
+The `onOpenMarkdownLink(perform:)` modifier in MarkdownUI 1.x was provided to enable link behavior
+customization in macOS 11.0, iOS 14.0, and tvOS 14.0. This modifier is no longer available in
+MarkdownUI 2 since it does not support those platforms. However, you can customize the link
+behavior by setting the `openURL` environment value with a custom `OpenURLAction`.
+
+## Styling Markdown
+
+MarkdownUI 1.x offered a few options to customize the content appearance. In contrast, MarkdownUI 2
+brings the new ``Theme``, ``TextStyle``, and ``BlockStyle`` types that let you apply a custom
+appearance to blocks and text inlines in a Markdown view.
+
+Consequently, the `MarkdownStyle` type, all of its subtypes, and the `markdownStyle(_:)` modifier
+are no longer available in MarkdownUI 2.
diff --git a/NeoDB/NeoDB/References/Packages/swift-markdown-ui/MarkdownUI.md b/NeoDB/NeoDB/References/Packages/swift-markdown-ui/MarkdownUI.md
new file mode 100755
index 0000000..385a3eb
--- /dev/null
+++ b/NeoDB/NeoDB/References/Packages/swift-markdown-ui/MarkdownUI.md
@@ -0,0 +1,85 @@
+# ``MarkdownUI``
+
+Display and customize Markdown text in SwiftUI.
+
+## Overview
+
+MarkdownUI is a powerful library for displaying and customizing Markdown text in SwiftUI. It is
+compatible with the [GitHub Flavored Markdown Spec](https://github.github.com/gfm/) and can
+display images, headings, lists (including task lists), blockquotes, code blocks, tables,
+and thematic breaks, besides styled text and links.
+
+MarkdownUI offers comprehensible theming features to customize how it displays Markdown text.
+You can use the built-in themes, create your own or override specific text and block styles.
+
+![A MarkdownUI view that displays a heading, paragraph, code block, and table using different themes](MarkdownUI)
+
+## Topics
+
+### Essentials
+
+-
+
+### Upgrade guides
+
+-
+
+### Displaying Markdown
+
+- ``Markdown``
+
+### Customizing Appearance
+
+- ``Theme``
+- ``TextStyle``
+- ``ForegroundColor``
+- ``BackgroundColor``
+- ``FontFamily``
+- ``FontSize``
+- ``FontStyle``
+- ``FontWeight``
+- ``FontWidth``
+- ``StrikethroughStyle``
+- ``UnderlineStyle``
+- ``FontFamilyVariant``
+- ``FontCapsVariant``
+- ``FontDigitVariant``
+- ``TextKerning``
+- ``TextTracking``
+- ``BlockStyle``
+- ``BlockConfiguration``
+- ``ListMarkerConfiguration``
+- ``TaskListMarkerConfiguration``
+- ``TableBackgroundStyle``
+- ``TableBorderStyle``
+- ``TableCellConfiguration``
+
+### Formatting content
+
+- ``MarkdownContent``
+- ``Paragraph``
+- ``Heading``
+- ``Blockquote``
+- ``CodeBlock``
+- ``BulletedList``
+- ``NumberedList``
+- ``ListItem``
+- ``TaskList``
+- ``TaskListItem``
+- ``TextTable``
+- ``ThematicBreak``
+- ``InlineContent``
+- ``Code``
+- ``Emphasis``
+- ``Strong``
+- ``Strikethrough``
+- ``InlineImage``
+- ``InlineLink``
+
+### Extensibility
+
+- ``ImageProvider``
+- ``DefaultImageProvider``
+- ``AssetImageProvider``
+- ``CodeSyntaxHighlighter``
+- ``PlainTextCodeSyntaxHighlighter``
diff --git a/NeoDB/NeoDB/Views/Home/HomeView.swift b/NeoDB/NeoDB/Views/Home/HomeView.swift
index adeab3d..acee98e 100644
--- a/NeoDB/NeoDB/Views/Home/HomeView.swift
+++ b/NeoDB/NeoDB/Views/Home/HomeView.swift
@@ -1,5 +1,7 @@
import SwiftUI
import OSLog
+import HTML2Markdown
+import MarkdownUI
@MainActor
class HomeViewModel: ObservableObject {
@@ -133,6 +135,7 @@ struct HomeView: View {
struct StatusView: View {
let status: Status
+ @Environment(\.openURL) private var openURL
var body: some View {
VStack(alignment: .leading, spacing: 12) {
@@ -176,8 +179,7 @@ struct StatusView: View {
}
// Content
- Text(status.content)
- .font(.body)
+ HTMLContentView(htmlContent: status.content)
.textSelection(.enabled)
// Media
@@ -213,7 +215,6 @@ struct StatusView: View {
}
.padding()
.background(Color(.systemBackground))
- .enableInjection()
}
#if DEBUG
@@ -254,4 +255,36 @@ struct StatusView: View {
}
}
}
+}
+
+struct HTMLContentView: View {
+ let htmlContent: String
+ @Environment(\.openURL) private var openURL
+
+ var body: some View {
+ if let markdown = convertHTMLToMarkdown(htmlContent) {
+ Markdown(markdown)
+ .textSelection(.enabled)
+ .padding(.vertical, 4)
+ } else {
+ Text(htmlContent)
+ .textSelection(.enabled)
+ }
+ }
+
+ private func convertHTMLToMarkdown(_ html: String) -> String? {
+ // Remove extra newlines and spaces
+ let cleanedHTML = html.replacingOccurrences(of: "\n", with: "")
+ .replacingOccurrences(of: "\\s+", with: " ", options: .regularExpression)
+
+ do {
+ let dom = try HTMLParser().parse(html: cleanedHTML)
+ // Use bullets for unordered lists for better SwiftUI Text compatibility
+ let markdown = dom.markdownFormatted(options: .unorderedListBullets)
+ return markdown
+ } catch {
+ print("Error parsing HTML: \(error)")
+ return nil
+ }
+ }
}
\ No newline at end of file