img(src = nationData.flag, alt = "Flag of ${nationData.name}", classes = "flag-icon")
p {
style = "text-align:center"
- +nationData.name
+ a(href = "https://www.nationstates.net/nation=${nationData.id}") {
+ +nationData.name
+ }
+ }
+ }
+}
+
+data class QuoteOriginSidebar(val author: String, val portrait: String, val link: String) : Sidebar() {
+ override fun TagConsumer<*>.display() {
+ img(src = "/assets/images/$portrait", alt = "Portrait of $author")
+ p {
+ style = "text-align:center"
+ a(href = "/lore/$link") {
+ +author
+ }
}
}
}
--- /dev/null
+package info.mechyrdia.lore
+
+import info.mechyrdia.Configuration
+import info.mechyrdia.JsonFileCodec
+import io.ktor.server.application.*
+import io.ktor.util.*
+import kotlinx.html.*
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.builtins.ListSerializer
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.put
+import java.io.File
+
+@Serializable
+data class Quote(
+ val quote: String,
+ val author: String,
+ val portrait: String,
+ val link: String
+) {
+ val fullPortrait: String
+ get() = if (portrait.startsWith("http://") || portrait.startsWith("https://"))
+ portrait
+ else
+ "https://mechyrdia.info/assets/images/$portrait"
+
+ val fullLink: String
+ get() = if (link.startsWith("http://") || link.startsWith("https://"))
+ link
+ else
+ "https://mechyrdia.info/lore/$link"
+}
+
+fun loadQuotes(): List<Quote> {
+ val quotesJsonFile = File(Configuration.CurrentConfiguration.rootDir).combineSafe("quotes.json")
+ return JsonFileCodec.decodeFromString(ListSerializer(Quote.serializer()), quotesJsonFile.readText())
+}
+
+fun randomQuote(): Quote = loadQuotes().random()
+
+fun Quote.toXml(standalone: Boolean = true): String {
+ return buildString {
+ if (standalone)
+ appendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
+ appendLine("<quote>")
+ append("<text>").append(quote.escapeHTML()).appendLine("</text>")
+ append("<author>").append(author.escapeHTML()).appendLine("</author>")
+ append("<portrait href=\"").append(fullPortrait.escapeHTML()).appendLine("\" />")
+ append("<link href=\"").append(fullLink.escapeHTML()).appendLine("\" />")
+ appendLine("</quote>")
+ }
+}
+
+fun Quote.toJson(): String {
+ return buildJsonObject {
+ put("text", quote)
+ put("author", author)
+ put("portrait", fullPortrait)
+ put("link", fullLink)
+ }.toString()
+}
+
+context(ApplicationCall)
+suspend fun Quote.toHtml(title: String): HTML.() -> Unit {
+ return page(title, standardNavBar(), QuoteOriginSidebar(author, portrait, link)) {
+ section {
+ a { id = "page-top" }
+ h1 { +title }
+ blockQuote {
+ +quote
+ }
+ p {
+ style = "align:right"
+ unsafe { raw("―") }
+ +Entities.nbsp
+ a(href = "/lore/$link") { +author }
+ }
+ }
+ }
+}
--- /dev/null
+import json
+import re
+
+quote_pattern = re.compile(r"^\"(.*)\" \- (.*?)\|(.*?)\@(.*?)$")
+
+quote_list = []
+
+with open("../test/quotes.json", mode="r", encoding="utf-8") as quotes_json_file:
+ quote_list.extend(json.load(quotes_json_file))
+
+with open("../test/quotes.txt", mode="r", encoding="utf-8") as quotes_file:
+ for quote in quotes_file:
+ quote = quote.rstrip()
+ match = quote_pattern.fullmatch(quote)
+
+ text, author, portrait, link = match.groups()
+ quote_dict = {
+ "quote": text,
+ "author": author,
+ "portrait": "portrait-" + portrait.lower().replace(" ", "-").replace("'", ""),
+ "link": link.removeprefix("https://mechyrdia.info/lore/")
+ }
+ quote_list.append(quote_dict)
+
+with open("../test/quotes.json", mode="w", encoding="utf-8") as quotes_json_file:
+ json.dump(quote_list, quotes_json_file, indent="\t")