Adds previews to test markdown rendering

This commit is contained in:
Vitor Pamplona
2024-08-12 15:55:01 -04:00
parent ac5f550ff3
commit 2e144ebdf8

View File

@@ -20,22 +20,41 @@
*/
package com.vitorpamplona.amethyst.ui.components.markdown
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.tooling.preview.Preview
import com.halilibo.richtext.commonmark.CommonmarkAstNodeParser
import com.halilibo.richtext.commonmark.MarkdownParseOptions
import com.halilibo.richtext.markdown.BasicMarkdown
import com.halilibo.richtext.ui.material3.RichText
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
import com.vitorpamplona.amethyst.service.previews.UrlInfoItem
import com.vitorpamplona.amethyst.ui.components.UrlPreviewState
import com.vitorpamplona.amethyst.ui.components.mockAccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.MarkdownTextStyle
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow
import com.vitorpamplona.amethyst.ui.theme.markdownStyle
import com.vitorpamplona.amethyst.ui.uriToRoute
import com.vitorpamplona.quartz.events.EmptyTagList
import com.vitorpamplona.quartz.events.ImmutableListOfLists
import com.vitorpamplona.quartz.events.LongTextNoteEvent
import com.vitorpamplona.quartz.events.MetadataEvent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
@Composable
fun RenderContentAsMarkdown(
@@ -91,3 +110,348 @@ fun RenderContentAsMarkdown(
}
}
}
@Preview
@Composable
fun RenderContentAsMarkdownPreview() {
val accountViewModel = mockAccountViewModel()
val nav: (String) -> Unit = {}
ThemeComparisonRow {
val background = MaterialTheme.colorScheme.background
RenderContentAsMarkdown(
"# Hello 1\n" +
"## Hello 2\n" +
"### Hello 3\n" +
"#### Hello 4\n" +
"##### Hello 5\n" +
"###### Hello 6\n" +
"This is regular text\n" +
"\n" +
"**This is bold text**\n" +
"\n" +
"__This is bold text__\n" +
"\n" +
"*This is italic text*\n" +
"\n" +
"_This is italic text_\n" +
"\n" +
"~~Strikethrough~~\n" +
"\n" +
"\n" +
"## Blockquotes\n" +
"\n" +
"\n" +
"> Blockquotes can also be nested...\n" +
">> ...by using additional greater-than signs right next to each other...\n" +
"> > > ...or with spaces between arrows.\n" +
"\n" +
"\n" +
"## End\n",
tags = EmptyTagList,
canPreview = true,
quotesLeft = 2,
backgroundColor =
remember {
mutableStateOf(background)
},
callbackUri = "nostr:something",
accountViewModel = accountViewModel,
nav = nav,
)
}
}
@Preview
@Composable
fun RenderContentAsMarkdownListsPreview() {
val accountViewModel = mockAccountViewModel()
val nav: (String) -> Unit = {}
ThemeComparisonRow {
val background = MaterialTheme.colorScheme.background
RenderContentAsMarkdown(
"## Lists\n" +
"\n" +
"Unordered\n" +
"\n" +
"+ Create a list by starting a line with `+`, `-`, or `*`\n" +
"+ Sub-lists 2 spaces:\n" +
" - Character change forces new list:\n" +
" * Ac tristique libero volutpat at\n" +
" + Facilisis in pretium nisl aliquet\n" +
" - Nulla volutpat aliquam velit\n" +
"+ Very easy!\n" +
"\n" +
"Ordered\n" +
"\n" +
"1. Lorem ipsum dolor sit amet\n" +
"2. Consectetur adipiscing elit\n" +
"3. Integer molestie lorem at massa\n" +
"\n" +
"\n" +
"1. You can use sequential numbers...\n" +
"1. ...or keep all the numbers as `1.`\n" +
"\n" +
"Start number with offset:\n" +
"\n" +
"57. foo\n" +
"1. bar\n",
tags = EmptyTagList,
canPreview = true,
quotesLeft = 2,
backgroundColor =
remember {
mutableStateOf(background)
},
callbackUri = "nostr:something",
accountViewModel = accountViewModel,
nav = nav,
)
}
}
@Preview
@Composable
fun RenderContentAsMarkdownCodePreview() {
val accountViewModel = mockAccountViewModel()
val nav: (String) -> Unit = {}
ThemeComparisonRow {
val background = MaterialTheme.colorScheme.background
RenderContentAsMarkdown(
"## Code\n" +
"\n" +
"Inline `code`\n" +
"\n" +
"Indented code\n" +
"\n" +
" // Some comments\n" +
" line 1 of code\n" +
" line 2 of code\n" +
" line 3 of code\n" +
"\n" +
"\n" +
"Block code \"fences\"\n" +
"\n" +
"```\n" +
"Sample text here...\n" +
"```\n" +
"\n" +
"Syntax highlighting\n" +
"\n" +
"``` js\n" +
"var foo = function (bar) {\n" +
" return bar++;\n" +
"};\n" +
"var veryVeryVeryLongVariableNameWithALongValueAsWell = 123456789012345678901234567890;\n" +
"console.log(foo(5));\n" +
"```\n" +
"\n" +
"\n" +
"### End\n",
tags = EmptyTagList,
canPreview = true,
quotesLeft = 2,
backgroundColor =
remember {
mutableStateOf(background)
},
callbackUri = "nostr:something",
accountViewModel = accountViewModel,
nav = nav,
)
}
}
@Preview
@Composable
fun RenderContentAsMarkdownTablesPreview() {
val accountViewModel = mockAccountViewModel()
val nav: (String) -> Unit = {}
ThemeComparisonRow {
val background = MaterialTheme.colorScheme.background
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
RenderContentAsMarkdown(
"## Tables\n" +
"\n" +
"| Option | Description |\n" +
"| ------ | ----------- |\n" +
"| data | path to data files to supply the data that will be passed into templates. |\n" +
"| engine | engine to be used for processing templates. Handlebars is the default. |\n" +
"| ext | extension to be used for dest files. |\n" +
"\n" +
"Right aligned columns\n" +
"\n" +
"| Option | Description |\n" +
"| ------:| -----------:|\n" +
"| data | path to data files to supply the data that will be passed into templates. |\n" +
"| engine | engine to be used for processing templates. Handlebars is the default. |\n" +
"| ext | extension to be used for dest files. |\n",
tags = EmptyTagList,
canPreview = true,
quotesLeft = 2,
backgroundColor =
remember {
mutableStateOf(background)
},
callbackUri = "nostr:something",
accountViewModel = accountViewModel,
nav = nav,
)
}
}
}
@Preview
@Composable
fun RenderContentAsMarkdownFootNotesPreview() {
val accountViewModel = mockAccountViewModel()
val nav: (String) -> Unit = {}
ThemeComparisonRow {
val background = MaterialTheme.colorScheme.background
RenderContentAsMarkdown(
"### [Footnotes]\n" +
"\n" +
"Footnote 1 link[^first].\n" +
"\n" +
"Footnote 2 link[^second].\n" +
"\n" +
"Duplicated footnote reference[^second].\n" +
"\n" +
"[^first]: Footnote **can have markup**\n" +
"\n" +
" and multiple paragraphs.\n" +
"\n" +
"[^second]: Footnote text.\n",
tags = EmptyTagList,
canPreview = true,
quotesLeft = 2,
backgroundColor =
remember {
mutableStateOf(background)
},
callbackUri = "nostr:something",
accountViewModel = accountViewModel,
nav = nav,
)
}
}
@Preview
@Composable
fun RenderContentAsMarkdownUserPreview() {
val accountViewModel = mockAccountViewModel()
val nav: (String) -> Unit = {}
runBlocking {
withContext(Dispatchers.IO) {
val qa =
MetadataEvent(
id = "4d5e1c614e18b915e6899fff93b5345253a5e2a8d0cbdb9ca98758da1612e05b",
pubKey = "88cc134b1a65f54ef48acc1df3665063d3ea45f04eab8af4646e561c5ae99079",
createdAt = 1722306330,
tags = emptyArray(),
content = "{\"lud16\":\"qa@primal.net\",\"website\":\"https:\\/\\/primal.net\",\"lud06\":\"\",\"name\":\"qauser\",\"banner\":\"https:\\/\\/m.primal.net\\/HQTd.jpg\",\"display_name\":\"qa\",\"nip05\":\"qa@primal.net\",\"picture\":\"https:\\/\\/m.primal.net\\/JidC.jpg\",\"about\":\"If you are following this account for quality content, you are going to have a bad time. #qa #primal \"}",
sig = "2a5fbd16e8fd67873cee1e60fc7b1b09d8a3cb5d503528507fa47d29669b259153ba710acce725d1f1bec867d7f86cc72820e496604e9183e5f58d0f2fb98f58",
)
UrlCachedPreviewer.cache.put(
"https://duckduckgo.com/",
UrlPreviewState.Loaded(
UrlInfoItem(
url = "https://duckduckgo.com/",
image = "https://duckduckgo.com/assets/logo_social-media.png",
title = "DuckDuckGo — Privacy, simplified.",
description = "The Internet privacy company that empowers you to seamlessly take control of your personal information online, without any tradeoffs.",
mimeType = "text/html".toMediaType(),
),
),
)
LocalCache.justConsume(qa, null)
}
}
ThemeComparisonRow {
val background = MaterialTheme.colorScheme.background
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
RenderContentAsMarkdown(
"This is a test by nostr:npub13rxpxjc6vh65aay2eswlxejsv0f7530sf64c4arydetpckhfjpustsjeaf that tests multiple lines of markdown\n" +
"\n" +
"nostr:npub13rxpxjc6vh65aay2eswlxejsv0f7530sf64c4arydetpckhfjpustsjeaf\n" +
"\n" +
"here is a [link to somewhere in text](https://duckduckgo.com/) so as to see how it would render and here it is bare-bone https://duckduckgo.com/ as preview just to make sure it is nicely parsed.\n" +
"\n ## END \n",
tags = EmptyTagList,
canPreview = true,
quotesLeft = 2,
backgroundColor =
remember {
mutableStateOf(background)
},
callbackUri = "nostr:something",
accountViewModel = accountViewModel,
nav = nav,
)
}
}
}
@Preview
@Composable
fun RenderContentAsMarkdownNotePreview() {
val accountViewModel = mockAccountViewModel()
val nav: (String) -> Unit = {}
runBlocking {
withContext(Dispatchers.IO) {
val blogPost =
LongTextNoteEvent(
id = "e69fa72a221d0b7362f8e63fd6ab84cc6b5e7b505fe49cefe6823a47a6a4b583",
pubKey = "88cc134b1a65f54ef48acc1df3665063d3ea45f04eab8af4646e561c5ae99079",
createdAt = 1718785725,
tags = arrayOf(arrayOf("d", "1718785686085"), arrayOf("title", "Test again"), arrayOf("summary", "Testing...."), arrayOf("t", "test"), arrayOf("t", "testing"), arrayOf("published_at", "1718785712"), arrayOf("alt", "This is a long form article, you can read it in https://habla.news/a/naddr1qvzqqqr4gupzpzxvzd935e04fm6g4nqa7dn9qc7nafzlqn4t3t6xgmjkr3dwnyreqqxnzde38qmnsdfk8qmrqwp405km0k"), arrayOf("p", "88cc134b1a65f54ef48acc1df3665063d3ea45f04eab8af4646e561c5ae99079"), arrayOf("e", "ab002ebdf49a06f9d94959d955c419964403339fde473ebd144321574a105811", "", "mention"), arrayOf("e", "466e2c6e5a59042b44799899885edd112074141e49cc50f9e2ead06f43bfc424", "", "mention"), arrayOf("e", "d6236a9108896ccf7882ce52cd8c53466d2c1018e7e85190f28310aa3dd5b554", "", "mention"), arrayOf("e", "c1896afdf528e2a62ab0fc15b8e0320ef58f10685363a9c6b2d549b79102f446", "", "mention")),
content = "lets try this out nostr:note14vqza005ngr0nk2ft8v4t3qejezqxvulmerna0g5gvs4wjsstqgsmeupgy and nostr:note1gehzcmj6tyzzk3renzvcshkazys8g9q7f8x9p70zatgx7salcsjqax60pz or nostr:note16c3k4ygg39kv77yzeefvmrzngekjcyqcul59ry8jsvg250w4k42qk9d4dw or nostr:note1cxyk4l049r32v24sls2m3cpjpm6c7yrg2d36n34j64ym0ygz73rqzplrn7 and some users nostr:npub13rxpxjc6vh65aay2eswlxejsv0f7530sf64c4arydetpckhfjpustsjeaf and nostr:npub13rxpxjc6vh65aay2eswlxejsv0f7530sf64c4arydetpckhfjpustsjeaf",
sig = "4c85e0eb0c46c5e3023431ad4ed8efa0abd66447ff757d246154e2349ac01ae0f88f213d02efa0a77f307f305d4a608c785ae1ca080c01cd3a9e7b8dffea6f9c",
)
LocalCache.justConsume(blogPost, null)
}
}
ThemeComparisonRow {
val background = MaterialTheme.colorScheme.background
RenderContentAsMarkdown(
"here is a mention of another article nostr:naddr1qvzqqqr4gupzpzxvzd935e04fm6g4nqa7dn9qc7nafzlqn4t3t6xgmjkr3dwnyreqqxnzde38qmnsdfk8qmrqwp405km0k\n" +
"\n" +
"## Images\n" +
"\n" +
"![landscape](https://primal.b-cdn.net/media-cache?s=o&a=1&u=https%3A%2F%2Fm.primal.net%2FHUmC.jpg)\n" +
"\n" +
"and here is one in the middle of the text ![rose](https://primal.b-cdn.net/media-cache?s=o&a=1&u=https%3A%2F%2Fm.primal.net%2FHUmM.jpg) that continues right after. Just to see how this will render\n" +
"\n",
tags = EmptyTagList,
canPreview = true,
quotesLeft = 2,
backgroundColor =
remember {
mutableStateOf(background)
},
callbackUri = "nostr:something",
accountViewModel = accountViewModel,
nav = nav,
)
}
}