|
7 | 7 |
|
8 | 8 |
|
9 | 9 | import SwiftUI |
| 10 | +import MarkdownUI |
10 | 11 |
|
11 | 12 | public struct UserChatBubble: View { |
12 | 13 | var text: String |
@@ -43,11 +44,28 @@ public struct BotChatBubble: View { |
43 | 44 | if isGenerating && text.isEmpty { |
44 | 45 | TypingIndicator() |
45 | 46 | } else { |
46 | | - Text(text) |
| 47 | + Markdown(text) |
47 | 48 | .padding(.top, -2) |
48 | 49 | .background(Color("BackgroundColor")) |
49 | 50 | .frame(maxWidth: maxWidth * 0.75, alignment: .leading) |
50 | 51 | .font(.body()) |
| 52 | + .markdownTextStyle(\.code) { |
| 53 | + FontFamilyVariant(.monospaced) |
| 54 | + FontSize(.em(0.85)) |
| 55 | + BackgroundColor(Color("Surface").opacity(0.35)) |
| 56 | + } |
| 57 | + .markdownBlockStyle(\.codeBlock) { configuration in |
| 58 | + configuration.label |
| 59 | + .frame(maxWidth: .infinity, alignment: .leading) |
| 60 | + .padding(.horizontal, 12) |
| 61 | + .padding(.vertical, 6) |
| 62 | + .background(Color("Surface").opacity(0.35)) |
| 63 | + .markdownTextStyle { |
| 64 | + FontFamilyVariant(.monospaced) |
| 65 | + FontSize(.em(0.85)) |
| 66 | + } |
| 67 | + .markdownMargin(top: 8, bottom: 8) |
| 68 | + } |
51 | 69 | } |
52 | 70 | Spacer() |
53 | 71 | } |
@@ -296,6 +314,106 @@ public struct ChatView: View { |
296 | 314 | } |
297 | 315 | } |
298 | 316 |
|
| 317 | +#Preview("Markdown Features") { |
| 318 | + let exampleHistory: [Chat] = [ |
| 319 | + Chat(role: .user, content: "Show me what markdown features you support"), |
| 320 | + Chat(role: .bot, content: """ |
| 321 | + # Markdown Showcase |
| 322 | + Let me demonstrate the various markdown features I support: |
| 323 | +
|
| 324 | + ## Text Formatting |
| 325 | + You can use **bold**, *italic*, or ***both***. You can also ~~strikethrough~~ text. |
| 326 | +
|
| 327 | + ## Code Examples |
| 328 | + Here's a code sample: |
| 329 | + ```swift |
| 330 | + struct Example { |
| 331 | + let value: String |
| 332 | + func process() -> String { |
| 333 | + return "Processed: \\(value)" |
| 334 | + } |
| 335 | + } |
| 336 | + ``` |
| 337 | + You can also use `inline code` or ``nested `backticks` ``. |
| 338 | +
|
| 339 | + ## Lists and Tasks |
| 340 | + Here's what I can do: |
| 341 | + 1. Ordered lists |
| 342 | + * Nested bullets |
| 343 | + * Deep nesting |
| 344 | +
|
| 345 | + And task lists: |
| 346 | + - [x] Completed task |
| 347 | + - [ ] Pending task |
| 348 | + - [x] Nested task |
| 349 | + """), |
| 350 | + |
| 351 | + Chat(role: .user, content: "That's cool! What about tables and quotes?"), |
| 352 | + Chat(role: .bot, content: """ |
| 353 | + ## Tables |
| 354 | + | Feature | Support | Notes | |
| 355 | + |---------|:-------:|-------| |
| 356 | + | Tables | ✅ | With alignment | |
| 357 | + | Lists | ✅ | Nested too | |
| 358 | +
|
| 359 | + ## Blockquotes |
| 360 | + > Single quote |
| 361 | + >> Nested quote |
| 362 | + >>> Triple nested with **bold** and *italic* |
| 363 | +
|
| 364 | + ## Links and References |
| 365 | + [External Link](https://example.com) |
| 366 | + <https://auto-link.com> |
| 367 | +
|
| 368 | + Reference-style [link][ref] and footnotes[^1] |
| 369 | +
|
| 370 | + [^1]: This is a footnote |
| 371 | + [ref]: https://example.com |
| 372 | + """), |
| 373 | + |
| 374 | + Chat(role: .user, content: "Any special features?"), |
| 375 | + Chat(role: .bot, content: """ |
| 376 | + ## Special Elements |
| 377 | + <details> |
| 378 | + <summary>Expandable Section</summary> |
| 379 | +
|
| 380 | + * Hidden content |
| 381 | + * More items |
| 382 | + </details> |
| 383 | +
|
| 384 | + ## Math and Diagrams |
| 385 | + Math: $E = mc^2$ |
| 386 | +
|
| 387 | + ```mermaid |
| 388 | + graph TD; |
| 389 | + A-->B; |
| 390 | + B-->C; |
| 391 | + C-->D; |
| 392 | + ``` |
| 393 | +
|
| 394 | + ## Definition Lists |
| 395 | + Term 1 |
| 396 | + : First definition |
| 397 | + : Another definition |
| 398 | +
|
| 399 | + Term 2 |
| 400 | + : With nested list |
| 401 | + * Item 1 |
| 402 | + * Item 2 |
| 403 | + """) |
| 404 | + ] |
| 405 | + |
| 406 | + ChatView( |
| 407 | + history: exampleHistory, |
| 408 | + output: "", |
| 409 | + isGenerating: .constant(false), |
| 410 | + isScrolledToBottom: .constant(true), |
| 411 | + stopSubmitted: .constant(false) |
| 412 | + ) |
| 413 | + .padding(12) |
| 414 | + .background(Color("BackgroundColor")) |
| 415 | +} |
| 416 | + |
299 | 417 | #Preview("Replying") { |
300 | 418 | let exampleOutput = "This is a bot response that spans multiple lines to better test spacing and alignment in the chat view during development previews in Xcode. This is a bot response that spans multiple lines to better test spacing and alignment in the chat view during development previews in Xcode." |
301 | 419 | let exampleHistory: [Chat] = [ |
|
0 commit comments