import io.ktor.server.application.*
import kotlinx.html.*
import kotlinx.serialization.Serializable
+import kotlinx.serialization.serializer
@Serializable(PageThemeSerializer::class)
enum class PageTheme(val attributeValue: String?) {
else -> April1stMode.DEFAULT
}
+class JoinToHtmlConsumer<E>(val iterator: Iterator<E>) {
+ inline fun <T : Tag> T.invokeReceiver(separator: T.() -> Unit, body: T.(E) -> Unit) {
+ var isFirst = true
+ for (item in iterator) {
+ if (isFirst)
+ isFirst = false
+ else
+ separator()
+ body(item)
+ }
+ }
+
+ context(T)
+ inline operator fun <T : Tag> invoke(separator: T.() -> Unit, body: T.(E) -> Unit) {
+ invokeReceiver(separator, body)
+ }
+}
+
+val <E> Iterable<E>.joinToHtml: JoinToHtmlConsumer<E>
+ get() = JoinToHtmlConsumer(iterator())
+
+inline fun <reified E : Enum<E>> FlowOrInteractiveOrPhrasingContent.preference(inputName: String, current: E, crossinline localize: (E) -> String) {
+ val serializer = serializer<E>() as? KeyedEnumSerializer<E> ?: throw UnsupportedOperationException("Serializer for ${E::class.simpleName} has not been declared as KeyedEnumSerializer")
+ val entries = serializer.entries
+
+ entries.joinToHtml(Tag::br) { option ->
+ label {
+ radioInput(name = inputName) {
+ value = serializer.getKey(option) ?: "null"
+ required = true
+ checked = current == option
+ }
+ +Entities.nbsp
+ +localize(option)
+ }
+ }
+}
+
suspend fun ApplicationCall.clientSettingsPage(): HTML.() -> Unit {
attributes.put(PageDoNotCacheAttributeKey, true)
}
section {
h2 { +"Page Theme" }
- label {
- radioInput(name = "theme") {
- value = "null"
- required = true
- checked = theme == PageTheme.SYSTEM
- }
- +Entities.nbsp
- +"System Choice"
- }
- br
- label {
- radioInput(name = "theme") {
- value = "light"
- required = true
- checked = theme == PageTheme.LIGHT
- }
- +Entities.nbsp
- +"Light Theme"
- }
- br
- label {
- radioInput(name = "theme") {
- value = "dark"
- required = true
- checked = theme == PageTheme.DARK
+ preference<PageTheme>("theme", theme) {
+ when (it) {
+ PageTheme.SYSTEM -> "Chosen by Browser/System"
+ PageTheme.LIGHT -> "Light Theme"
+ PageTheme.DARK -> "Dark Theme"
}
- +Entities.nbsp
- +"Dark Theme"
}
}
section {
h2 { +"April Fools' Day Mode" }
- label {
- radioInput(name = "april1st") {
- value = "default"
- required = true
- checked = april1st == April1stMode.DEFAULT
- }
- +Entities.nbsp
- +"Only on April 1st"
- }
- br
- label {
- radioInput(name = "april1st") {
- value = "always"
- required = true
- checked = april1st == April1stMode.ALWAYS
- }
- +Entities.nbsp
- +"Always"
- }
- br
- label {
- radioInput(name = "april1st") {
- value = "never"
- required = true
- checked = april1st == April1stMode.NEVER
+ preference<April1stMode>("april1st", april1st) {
+ when (it) {
+ April1stMode.DEFAULT -> "Only on April 1st"
+ April1stMode.ALWAYS -> "Always"
+ April1stMode.NEVER -> "Never"
}
- +Entities.nbsp
- +"Never"
}
}
}