From d9b9b1723da11459e3a05c848c8daae8d1863042 Mon Sep 17 00:00:00 2001 From: Lanius Trolling Date: Fri, 8 Mar 2024 08:20:37 -0500 Subject: [PATCH] Improve formatting of raw factbooks --- .../info/mechyrdia/lore/article_listing.kt | 2 +- .../kotlin/info/mechyrdia/lore/http_utils.kt | 2 +- .../kotlin/info/mechyrdia/lore/parser_raw.kt | 76 +++++++++++++++---- .../kotlin/info/mechyrdia/lore/parser_tags.kt | 50 ++++++------ .../kotlin/info/mechyrdia/lore/view_tpl.kt | 2 + .../info/mechyrdia/lore/views_robots.kt | 4 +- src/jvmMain/resources/static/raw.css | 71 +++++++++++++++++ 7 files changed, 163 insertions(+), 44 deletions(-) create mode 100644 src/jvmMain/resources/static/raw.css diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/article_listing.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/article_listing.kt index 14643cc..5ae6e26 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/lore/article_listing.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/lore/article_listing.kt @@ -32,7 +32,7 @@ val File.isViewable: Boolean get() = name.isViewable fun List.renderInto(list: UL, base: String? = null, suffix: String = "") { - val prefix by lazy(LazyThreadSafetyMode.NONE) { base?.let { "$it/" } ?: "" } + val prefix by lazy(LazyThreadSafetyMode.NONE) { base?.let { "$it/" }.orEmpty() } for (node in this) { if (node.isViewable) list.li { diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/http_utils.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/http_utils.kt index 923c971..11d5998 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/lore/http_utils.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/lore/http_utils.kt @@ -8,7 +8,7 @@ fun redirect(url: String, permanent: Boolean = false): Nothing = throw HttpRedir fun redirectWithError(url: String, error: String, hash: String? = null): Nothing { val parameters = parametersOf("error", error).formUrlEncode() - val markedHash = hash?.let { "#$it" } ?: "" + val markedHash = hash?.let { "#$it" }.orEmpty() val urlWithError = "$url?$parameters$markedHash" redirect(urlWithError, false) } diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/parser_raw.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/parser_raw.kt index 1cc340b..7f7bfde 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/lore/parser_raw.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/lore/parser_raw.kt @@ -7,24 +7,52 @@ import java.io.File fun String.toRawLink() = substringBeforeLast('#') + ".raw" enum class TextParserRawPageTag(val type: TextParserTagType) { + B( + TextParserTagType.Direct( + false, + { _, _ -> "" }, + { _ -> "" }, + ) + ), + I( + TextParserTagType.Direct( + false, + { _, _ -> "" }, + { _ -> "" }, + ) + ), + U( + TextParserTagType.Direct( + false, + { _, _ -> "" }, + { _ -> "" }, + ) + ), + S( + TextParserTagType.Direct( + false, + { _, _ -> "" }, + { _ -> "" }, + ) + ), IPA( TextParserTagType.Direct( false, - { _, _ -> "" }, - { _ -> "" }, + { _, _ -> "" }, + { _ -> "" }, ) ), CODE( TextParserTagType.Direct( false, - { _, _ -> "" }, + { _, _ -> "" }, { _ -> "" }, ) ), CODE_BLOCK( TextParserTagType.Direct( false, - { _, _ -> "
" },
+			{ _, _ -> "
" },
 			{ _ -> "
" }, ) ), @@ -70,13 +98,25 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { { _ -> "" } ) ), + ALIGN( + TextParserTagType.Direct( + true, + { tagParam, _ -> + val alignments = setOf("left", "center", "right", "justify") + val alignment = tagParam?.takeIf { it in alignments } + val styleAttr = alignment?.let { " data-align=\"$it\"" }.orEmpty() + "" + }, + { _ -> "
" }, + ) + ), ASIDE( TextParserTagType.Direct( true, { tagParam, _ -> val floats = setOf("left", "right") val float = tagParam?.takeIf { it in floats } ?: "right" - "
" + "
" }, { _ -> "
" }, ) @@ -91,9 +131,9 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { File(Configuration.CurrentConfiguration.assetDir, "images") .combineSafe(imageUrl) .readText() - .replace("" + "" } ), MODEL( @@ -109,7 +149,7 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { TABLE( TextParserTagType.Direct( true, - { _, _ -> "" }, + { _, _ -> "
" }, { _ -> "
" }, ) ), @@ -120,7 +160,7 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { val (width, height) = getSizeParam(tagParam) val sizeAttrs = getTableSizeAttributes(width, height) - "" + "" }, { _ -> "" }, ) @@ -132,7 +172,7 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { val (width, height) = getSizeParam(tagParam) val sizeAttrs = getTableSizeAttributes(width, height) - "" + "" }, { _ -> "" }, ) @@ -143,7 +183,7 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { { tagParam, _ -> val param = tagParam?.let { TextParserState.censorText(it) } val url = param?.let { if (it.startsWith('/')) "/lore$it" else "./$it" } - val attr = url?.let { " href=\"${it.toRawLink()}\"" } ?: "" + val attr = url?.let { " href=\"${it.toRawLink()}\"" }.orEmpty() "" }, @@ -155,13 +195,16 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { val target = TextParserState.censorText(content) val url = if (target.startsWith('/')) "/lore$target" else "./$target" - "Click here for a manual redirect" + "Click here for a manual redirect" } ), LANG( TextParserTagType.Direct( false, - { _, _ -> "" }, + { param, _ -> + val lang = param?.let { sanitizeLang(it) } ?: "foreign" + "" + }, { _ -> "" } ) ), @@ -184,5 +227,8 @@ enum class TextParserRawPageTag(val type: TextParserTagType) { } } -fun getRawImageSizeStyleValue(width: Int?, height: Int?) = (width?.let { "width: ${it * 0.25}px;" } ?: "") + (height?.let { "height: ${it * 0.25}px;" } ?: "") -fun getRawImageSizeAttributes(width: Int?, height: Int?) = " style=\"${getRawImageSizeStyleValue(width, height)}\"" +fun getRawImageSizeStyleValue(width: Int?, height: Int?) = width?.let { "width:${it * 0.25}px;" }.orEmpty() + height?.let { "height:${it * 0.25}px;" }.orEmpty() +fun getRawImageSizeAttributes(width: Int?, height: Int?) = width?.let { " data-width=\"$it\"" }.orEmpty() + height?.let { " data-height=\"$it\"" }.orEmpty() + " style=\"${getRawImageSizeStyleValue(width, height)}\"" + +val NON_LANG_CHAR = Regex("[^a-z0-9\\-]") +fun sanitizeLang(attr: String) = attr.replace(NON_LANG_CHAR, "") diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/parser_tags.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/parser_tags.kt index 7fa4183..aec52ae 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/lore/parser_tags.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/lore/parser_tags.kt @@ -52,28 +52,28 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { B( TextParserTagType.Direct( false, - { _, _ -> "" }, + { _, _ -> "" }, { _ -> "" }, ) ), I( TextParserTagType.Direct( false, - { _, _ -> "" }, + { _, _ -> "" }, { _ -> "" }, ) ), U( TextParserTagType.Direct( false, - { _, _ -> "" }, + { _, _ -> "" }, { _ -> "" }, ) ), S( TextParserTagType.Direct( false, - { _, _ -> "" }, + { _, _ -> "" }, { _ -> "" }, ) ), @@ -96,7 +96,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { false, { tagParam, _ -> val color = tagParam?.toIntOrNull(16)?.toString(16)?.padStart(6, '0') - val style = color?.let { " style=\"color: #$it\"" } ?: "" + val style = color?.let { " style=\"color:#$it\"" }.orEmpty() "" }, { _ -> "" }, @@ -105,57 +105,57 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { IPA( TextParserTagType.Direct( false, - { _, _ -> "" }, + { _, _ -> "" }, { _ -> "" }, ) ), CODE( TextParserTagType.Direct( false, - { _, _ -> "" }, + { _, _ -> "" }, { _ -> "" }, ) ), CODE_BLOCK( TextParserTagType.Direct( true, - { _, _ -> "
" },
+			{ _, _ -> "
" },
 			{ _ -> "
" }, ) ), H1( TextParserTagType.Indirect(true) { _, content, _ -> - "

$content

" + "

$content

" } ), H2( TextParserTagType.Indirect(true) { _, content, _ -> val anchor = headerContentToAnchor(content) - "

$content

" + "

$content

" } ), H3( TextParserTagType.Indirect(true) { _, content, _ -> val anchor = headerContentToAnchor(content) - "

$content

" + "

$content

" } ), H4( TextParserTagType.Indirect(true) { _, content, _ -> val anchor = headerContentToAnchor(content) - "

$content

" + "

$content

" } ), H5( TextParserTagType.Indirect(true) { _, content, _ -> val anchor = headerContentToAnchor(content) - "
$content
" + "
$content
" } ), H6( TextParserTagType.Indirect(true) { _, content, _ -> val anchor = headerContentToAnchor(content) - "
$content
" + "
$content
" } ), ALIGN( @@ -164,7 +164,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { { tagParam, _ -> val alignments = setOf("left", "center", "right", "justify") val alignment = tagParam?.takeIf { it in alignments } - val styleAttr = alignment?.let { " style=\"text-align: $it\"" } ?: "" + val styleAttr = alignment?.let { " style=\"text-align:$it\"" }.orEmpty() "" }, { _ -> "
" }, @@ -176,7 +176,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { { tagParam, _ -> val floats = setOf("left", "right") val float = tagParam?.takeIf { it in floats } ?: "right" - "
" + "
" }, { _ -> "
" }, ) @@ -212,9 +212,9 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { File(Configuration.CurrentConfiguration.assetDir, "images") .combineSafe(imageUrl) .readText() - .replace("window.appendImageThumb('/assets/images/$imageUrl', '${getImageSizeStyleValue(width, height)}');" + "" } ), MODEL( @@ -315,7 +315,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { { tagParam, _ -> val param = tagParam?.let { TextParserState.censorText(it) } val url = param?.let { if (it.startsWith('/')) "/lore$it" else "./$it" } - val attr = url?.let { " href=\"$it\"" } ?: "" + val attr = url?.let { " href=\"$it\"" }.orEmpty() "" }, @@ -327,7 +327,7 @@ enum class TextParserFormattingTag(val type: TextParserTagType) { false, { tagParam, _ -> val url = tagParam?.let { TextParserState.censorText(it) } - val attr = url?.let { " href=\"$it\"" } ?: "" + val attr = url?.let { " href=\"$it\"" }.orEmpty() "" }, @@ -472,7 +472,7 @@ enum class TextParserCommentTags(val type: TextParserTagType) { false, { tagParam, _ -> val url = tagParam?.let { TextParserState.censorText(it) } - val attr = url?.let { " href=\"$it\" rel=\"ugc nofollow\"" } ?: "" + val attr = url?.let { " href=\"$it\" rel=\"ugc nofollow\"" }.orEmpty() "" }, @@ -487,7 +487,7 @@ enum class TextParserCommentTags(val type: TextParserTagType) { val imageUrl = sanitizeExtLink(content) val (width, height) = getSizeParam(tagParam) - "" + "" } ), IMGBB( @@ -495,7 +495,7 @@ enum class TextParserCommentTags(val type: TextParserTagType) { val imageUrl = sanitizeExtLink(content) val (width, height) = getSizeParam(tagParam) - "" + "" } ), @@ -538,8 +538,8 @@ fun getSizeParam(tagParam: String?): Pair = tagParam?.let { resoluti parts.getOrNull(0)?.toIntOrNull() to parts.getOrNull(1)?.toIntOrNull() } ?: (null to null) -fun getTableSizeAttributes(width: Int?, height: Int?) = (width?.let { " colspan=\"$it\"" } ?: "") + (height?.let { " rowspan=\"$it\"" } ?: "") -fun getImageSizeStyleValue(width: Int?, height: Int?) = (width?.let { "width: calc(var(--media-size-unit) * $it);" } ?: "") + (height?.let { "height: calc(var(--media-size-unit) * $it);" } ?: "") +fun getTableSizeAttributes(width: Int?, height: Int?) = width?.let { " colspan=\"$it\"" }.orEmpty() + height?.let { " rowspan=\"$it\"" }.orEmpty() +fun getImageSizeStyleValue(width: Int?, height: Int?) = width?.let { "width: calc(var(--media-size-unit) * $it);" }.orEmpty() + height?.let { "height: calc(var(--media-size-unit) * $it);" }.orEmpty() fun getImageSizeAttributes(width: Int?, height: Int?) = " style=\"${getImageSizeStyleValue(width, height)}\"" val NON_ANCHOR_CHAR = Regex("[^a-zA-Z\\d\\-]") diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/view_tpl.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/view_tpl.kt index 64bb487..6d718e3 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/lore/view_tpl.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/lore/view_tpl.kt @@ -186,6 +186,8 @@ fun ApplicationCall.rawPage(pageTitle: String, ogData: OpenGraphData? = null, co link(rel = "icon", type = "image/svg+xml", href = "/static/images/icon.png") + link(rel = "stylesheet", type = "text/css", href = "/static/raw.css") + title { +pageTitle } diff --git a/src/jvmMain/kotlin/info/mechyrdia/lore/views_robots.kt b/src/jvmMain/kotlin/info/mechyrdia/lore/views_robots.kt index 60bac01..0d2e7e1 100644 --- a/src/jvmMain/kotlin/info/mechyrdia/lore/views_robots.kt +++ b/src/jvmMain/kotlin/info/mechyrdia/lore/views_robots.kt @@ -26,7 +26,7 @@ private val File.lastContentModified: Instant context(Appendable) private fun List.renderIntoSitemap(base: String? = null) { - val prefix by lazy(LazyThreadSafetyMode.NONE) { base?.let { "$it/" } ?: "" } + val prefix by lazy(LazyThreadSafetyMode.NONE) { base?.let { "$it/" }.orEmpty() } for (node in this) { if (Configuration.CurrentConfiguration.isDevMode || !(node.name.endsWith(".wip") || node.name.endsWith(".old"))) { val path = "$prefix${node.name}" @@ -76,7 +76,7 @@ private fun Appendable.renderIntroSitemap() { } fun Appendable.generateSitemap() { - appendLine("") + appendLine("") appendLine("") renderIntroSitemap() renderLoreSitemap() diff --git a/src/jvmMain/resources/static/raw.css b/src/jvmMain/resources/static/raw.css new file mode 100644 index 0000000..b769432 --- /dev/null +++ b/src/jvmMain/resources/static/raw.css @@ -0,0 +1,71 @@ +img { + filter: drop-shadow(0 0 0.5rem rgba(0, 0, 0, 50%)); + padding: 0.75rem; +} + +table { + width: 100%; + table-layout: fixed; +} + +td { + margin: 0.25rem; + background-color: #ddd; +} + +th { + margin: 0.25rem; + background-color: #333; + color: #eee; +} + +[data-format=b] { + font-weight: bold; +} + +[data-format=i] { + font-style: italic; +} + +[data-format=u] { + text-decoration: underline; +} + +[data-format=s] { + text-decoration: line-through; +} + +[data-format=code] { + font-family: monospace; +} + +[data-format|=lang-] { + font-style: italic; +} + +[data-align=left] { + text-align: left; +} + +[data-align=center] { + text-align: center; +} + +[data-align=right] { + text-align: right; +} + +[data-align=justify] { + text-align: justify; + text-align-last: left; +} + +[data-aside=left] { + float: left; + max-width: 50vw; +} + +[data-aside=right] { + float: right; + max-width: 50vw; +} -- 2.25.1