- Updated Komponent

- Updated Kotlin version
This commit is contained in:
2019-11-15 19:07:13 +01:00
parent 575e3ae39a
commit b84278334d
14 changed files with 96 additions and 195 deletions

2
.idea/gradle.xml generated
View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
@@ -11,6 +12,7 @@
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useAutoImport" value="true" />
</GradleProjectSettings>
</option>
</component>

View File

@@ -1,10 +0,0 @@
<component name="libraryTable">
<library name="Gradle: nl.astraeus:komp:0.1.0-SNAPSHOT" type="kotlin.js">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/nl.astraeus/komp/0.1.0-SNAPSHOT/95ba39cc4f8ee0e4e733beb0b8186ef4258aaa1f/komp-0.1.0-SNAPSHOT.jar!/" />
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/nl.astraeus/komp/0.1.0-SNAPSHOT/9a3c2ce9cd6d19d64a2554c9dc630b2a9faf279f/komp-0.1.0-SNAPSHOT.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -1,11 +0,0 @@
<component name="libraryTable">
<library name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.51" type="kotlin.common">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.2.51/e4a9d4b13ab19ed1e6531fce6df98e8cfa7f7301/kotlin-stdlib-common-1.2.51.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.2.51/e8c91083a5863d94fdc2836459e7e7a555774be9/kotlin-stdlib-common-1.2.51-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,11 +0,0 @@
<component name="libraryTable">
<library name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.2.51" type="kotlin.js">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.2.51/ac00507005af8df9e3a0957f9169f47cca7cdb72/kotlin-stdlib-js-1.2.51.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-js/1.2.51/c00799bfcbee73a3cd1f0d78031de126a0e7c200/kotlin-stdlib-js-1.2.51-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,11 +0,0 @@
<component name="libraryTable">
<library name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.6.4" type="kotlin.common">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.6.4/4ebf5aad41e363f63d196c4bbbee3662840288ca/kotlinx-html-common-0.6.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-common/0.6.4/ea347822bde2249e8e6fd8361c9596f36d69f7f1/kotlinx-html-common-0.6.4-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -1,11 +0,0 @@
<component name="libraryTable">
<library name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.6.4" type="kotlin.js">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.6.4/a5a4863f2c5fd25f8bb9a1ddb55bb7def89ea5ed/kotlinx-html-js-0.6.4.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-html-js/0.6.4/5286978d3b689a42a353237f05161288f0e426ac/kotlinx-html-js-0.6.4-sources.jar!/" />
</SOURCES>
</library>
</component>

2
.idea/modules.xml generated
View File

@@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/komp-todo.iml" filepath="$PROJECT_DIR$/komp-todo.iml" />
<module fileurl="file://$PROJECT_DIR$/komp-todo.iml" filepath="$PROJECT_DIR$/komp-todo.iml" group="komp-todo" />
</modules>
</component>
</project>

View File

@@ -1,7 +1,5 @@
import com.eriwen.gradle.js.tasks.CombineJsTask
buildscript {
ext.kotlin_version = '1.2.51'
ext.kotlin_version = '1.3.50'
repositories {
maven {
@@ -14,16 +12,10 @@ buildscript {
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.eriwen:gradle-js-plugin:1.12.1"
}
}
plugins {
id "com.eriwen.gradle.js" version "2.14.1"
}
apply plugin: 'kotlin2js'
apply plugin: 'kotlin-platform-js'
apply plugin: 'kotlin-dce-js'
group 'nl.astraeus'
@@ -31,7 +23,7 @@ version '0.0.1-SNAPSHOT'
allprojects {
ext {
kotlin_version = '1.2.51'
kotlin_version = '1.3.50'
}
}
@@ -44,7 +36,7 @@ repositories {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
compile "nl.astraeus:komp:0.1.1-SNAPSHOT"
compile "nl.astraeus:komp:0.1.7"
}
compileKotlin2Js {
@@ -63,24 +55,3 @@ runDceKotlinJs.doLast {
into("web/js/generated")
}
}
// Create new CombineJsTasks if you have multiple sets of JS files
task combineKotlinJs(type: CombineJsTask) {
dependsOn runDceKotlinJs
source = [
"${projectDir}/web/js/generated/kotlin.js",
"${projectDir}/web/js/generated/min/kotlinx-html-js.js",
"${projectDir}/web/js/generated/min/komp.js",
"${projectDir}/web/js/generated/min/komp-todo.js"
]
dest = file("${projectDir}/web/js/generated/todo.all.js")
}
minifyJs {
source = combineKotlinJs
dest = file("${projectDir}/web/js/generated/todo.all.min.js")
closure {
warningLevel = 'QUIET'
compilerOptions.languageIn = "ECMASCRIPT5"
}
}

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-all.zip

View File

@@ -2,36 +2,39 @@
<module external.linked.project.id="komp-todo" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="nl.astraeus" external.system.module.version="0.0.1-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JavaScript " useProjectSettings="false">
<testOutputPath>$MODULE_DIR$/build/classes/test/komp-todo_test.js</testOutputPath>
<configuration version="3" platform="JavaScript " allPlatforms="JS []" useProjectSettings="false" pureKotlinSourceFolders="$MODULE_DIR$/src/test/kotlin;/home/rnentjes/Development/komp/komp-todo/src/main/kotlin">
<testOutputPath>$MODULE_DIR$/build/classes/kotlin/test/komp-todo_test.js</testOutputPath>
<compilerSettings>
<option name="additionalArguments" value="-verbose" />
</compilerSettings>
<compilerArguments>
<option name="outputFile" value="$MODULE_DIR$/build/classes/main/komp-todo.js" />
<option name="outputFile" value="$MODULE_DIR$/build/classes/kotlin/main/komp-todo.js" />
<option name="noStdlib" value="true" />
<option name="sourceMap" value="true" />
<option name="sourceMapEmbedSources" value="always" />
<option name="metaInfo" value="true" />
<option name="target" value="v5" />
<option name="main" value="call" />
<option name="languageVersion" value="1.2" />
<option name="apiVersion" value="1.2" />
<option name="languageVersion" value="1.3" />
<option name="apiVersion" value="1.3" />
<option name="pluginOptions">
<array />
</option>
<option name="pluginClasspaths">
<array />
</option>
<option name="coroutinesState" value="warn" />
<option name="multiPlatform" value="true" />
<option name="errors">
<ArgumentParseErrors />
</option>
<option name="suppressWarnings" value="true" />
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/out/production/classes" />
<output-test url="file://$MODULE_DIR$/out/test/classes" />
<output url="file://$MODULE_DIR$/build/classes/java/main" />
<output-test url="file://$MODULE_DIR$/build/classes/java/test" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" type="kotlin-source" />
@@ -41,20 +44,20 @@
</content>
<orderEntry type="jdk" jdkName="Kotlin SDK" jdkType="KotlinSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.2.51" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: nl.astraeus:komp:0.1.0-SNAPSHOT" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.51" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.6.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.6.4" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.2.51" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: nl.astraeus:komp:0.1.0-SNAPSHOT" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.51" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.6.4" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.6.4" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.2.51" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: nl.astraeus:komp:0.1.0-SNAPSHOT" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.51" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.6.4" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.6.4" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: nl.astraeus:komp:0.1.7" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.6.10" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.3.50" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.6.10" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: nl.astraeus:komp:0.1.7" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.6.10" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.3.50" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.6.10" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: nl.astraeus:komp:0.1.7" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-js:0.6.10" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:1.3.50" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlinx:kotlinx-html-common:0.6.10" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50" level="project" />
</component>
</module>

View File

@@ -1,6 +1,8 @@
package nl.astraeus.komp.todo
import kotlinx.html.HtmlBlockTag
import kotlinx.html.InputType
import kotlinx.html.TagConsumer
import kotlinx.html.a
import kotlinx.html.button
import kotlinx.html.classes
@@ -19,10 +21,10 @@ import kotlinx.html.section
import kotlinx.html.span
import kotlinx.html.strong
import kotlinx.html.ul
import nl.astraeus.komp.KompConsumer
import kotlinx.html.video
import nl.astraeus.komp.Komponent
import nl.astraeus.komp.UpdateStrategy
import nl.astraeus.komp.include
import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.events.Event
import org.w3c.dom.events.KeyboardEvent
@@ -46,17 +48,23 @@ enum class Selection(val title: String) {
COMPLETED("Completed")
}
fun HtmlBlockTag.todo(app: TodoApp, todo: Todo) {
this.include(TodoKomponent(app, todo))
}
class TodoKomponent(
val app: TodoApp,
val todo: Todo
): Komponent() {
override fun render(consumer: KompConsumer) = consumer.li {
) : Komponent() {
override fun render(consumer: TagConsumer<HTMLElement>) = consumer.li {
if (todo.editing) {
classes += "editing"
input(classes = "edit") {
value = todo.title
onKeyPressFunction = { e ->
if (e is KeyboardEvent && e.keyCode == 13) {
val target = e.target
if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) {
app.editTodo(e, todo)
}
}
@@ -174,7 +182,7 @@ class TodoApp : Komponent() {
}
}
override fun render(consumer: KompConsumer) = consumer.section(classes = "todoapp") {
override fun render(consumer: TagConsumer<HTMLElement>) = consumer.section(classes = "todoapp") {
header(classes = "header") {
h1 { +"todos" }
input(classes = "new-todo") {
@@ -182,15 +190,12 @@ class TodoApp : Komponent() {
placeholder = "What needs to be done?"
autoFocus = true
onKeyPressFunction = { e ->
if (e is KeyboardEvent && e.keyCode == 13) {
val target = e.target
if (target is HTMLInputElement && e is KeyboardEvent && e.keyCode == 13 && target.value.isNotBlank()) {
addTodo(e)
val target = e.target
if (target is HTMLInputElement) {
target.value = ""
target.defaultValue = ""
}
target.value = ""
target.defaultValue = ""
}
}
}
@@ -201,7 +206,7 @@ class TodoApp : Komponent() {
type = InputType.checkBox
}
label {
for_ = "toggle-all"
htmlFor = "toggle-all"
+"Mark all as complete"
}
ul(classes = "todo-list") {
@@ -209,7 +214,7 @@ class TodoApp : Komponent() {
if (selected == Selection.ALL ||
(todo.completed && selected == Selection.COMPLETED) ||
(!todo.completed && selected == Selection.ACTIVE)) {
include(TodoKomponent(this@TodoApp, todo))
todo(this@TodoApp, todo)
}
}
}
@@ -247,13 +252,6 @@ class TodoApp : Komponent() {
}
fun main(args: Array<String>) {
/*
Komponent.logReplaceEvent = true
Komponent.logEquals = true
Komponent.logRenderEvent = true
*/
Komponent.updateStrategy = UpdateStrategy.REPLACE
fun main() {
Komponent.create(document.body!!, TodoApp(), true)
}

View File

@@ -17,8 +17,7 @@ button {
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
@@ -30,14 +29,12 @@ body {
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
}
button,
input[type="checkbox"] {
outline: none;
:focus {
outline: 0;
}
.hidden {
@@ -93,15 +90,13 @@ input[type="checkbox"] {
font-weight: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
@@ -117,28 +112,32 @@ input[type="checkbox"] {
border-top: 1px solid #e6e6e6;
}
label[for='toggle-all'] {
display: none;
}
.toggle-all {
position: absolute;
top: -55px;
left: -12px;
width: 60px;
height: 34px;
text-align: center;
border: none; /* Mobile Safari */
opacity: 0;
position: absolute;
}
.toggle-all:before {
.toggle-all + label {
width: 60px;
height: 34px;
font-size: 0;
position: absolute;
top: -52px;
left: -13px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.toggle-all + label:before {
content: '';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked:before {
.toggle-all:checked + label:before {
color: #737373;
}
@@ -166,7 +165,7 @@ label[for='toggle-all'] {
.todo-list li.editing .edit {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
padding: 12px 16px;
margin: 0 0 0 43px;
}
@@ -188,19 +187,27 @@ label[for='toggle-all'] {
appearance: none;
}
.todo-list li .toggle:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
.todo-list li .toggle {
opacity: 0;
}
.todo-list li .toggle:checked:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
.todo-list li .toggle + label {
/*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
background-repeat: no-repeat;
background-position: center left;
}
.todo-list li .toggle:checked + label {
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}
.todo-list li label {
white-space: pre-line;
word-break: break-all;
padding: 15px 60px 15px 15px;
margin-left: 45px;
padding: 15px 15px 15px 60px;
display: block;
line-height: 1.2;
transition: color 0.4s;
@@ -300,7 +307,6 @@ label[for='toggle-all'] {
border-radius: 3px;
}
.filters li a.selected,
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
@@ -316,7 +322,6 @@ html .clear-completed:active {
line-height: 20px;
text-decoration: none;
cursor: pointer;
position: relative;
}
.clear-completed:hover {
@@ -358,13 +363,6 @@ html .clear-completed:active {
.todo-list li .toggle {
height: 40px;
}
.toggle-all {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
@media (max-width: 430px) {

View File

@@ -12,6 +12,9 @@
<p>Compare other javascript MVC* frameworks with <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<script src="js/generated/todo.all.min.js" ></script>
<script src="js/generated/kotlin.js" ></script>
<script src="js/generated/kotlinx-html-js.js" ></script>
<script src="js/generated/komp.js" ></script>
<script src="js/generated/komp-todo.js" ></script>
</body>
</html>
</html>

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Komp-Todo</title>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<footer class="info">
<p>Double-click to edit a todo</p>
<p>Compare other javascript MVC* frameworks with <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<script src="js/generated/kotlin.js" ></script>
<script src="js/generated/kotlinx-html-js.js" ></script>
<script src="js/generated/komp.js" ></script>
<script src="js/generated/komp-todo.js" ></script>
</body>
</html>