Skip to content

Instantly share code, notes, and snippets.

@nguyenyou
Created February 22, 2025 15:24
Show Gist options
  • Save nguyenyou/156f29598d51a3b550335e3124a67e0d to your computer and use it in GitHub Desktop.
Save nguyenyou/156f29598d51a3b550335e3124a67e0d to your computer and use it in GitHub Desktop.
Laminar + SAPUI5 TodoApp
//> using scala 3.6.3
//> using platform scala-js
//> using dep "org.scala-js::scalajs-dom::2.8.0"
//> using dep "com.raquo::laminar::17.2.0"
//> using dep "be.doeraene::web-components-ui5::2.1.0"
//> using jsModuleKind es
//> using jsModuleSplitStyleStr fewestmodules
package myapp
import org.scalajs.dom
import com.raquo.laminar.api.L.*
import be.doeraene.webcomponents.ui5.*
import be.doeraene.webcomponents.ui5.configkeys.*
case class Todo(id: Int, text: String, completed: Boolean)
@main
def main(): Unit = {
val container = dom.document.getElementById("app")
// State management
val todosVar = Var(Vector.empty[Todo])
val inputVar = Var("")
def addTodo(text: String): Unit =
if text.trim.nonEmpty then
val newTodo = Todo(
id = System.currentTimeMillis().toInt,
text = text.trim,
completed = false
)
todosVar.update(_ :+ newTodo)
inputVar.set("")
def toggleTodo(id: Int): Unit =
todosVar.update(_.map { todo =>
if todo.id == id then todo.copy(completed = !todo.completed)
else todo
})
def deleteTodo(id: Int): Unit =
todosVar.update(_.filterNot(_.id == id))
render(
container,
div(
className := "max-w-md mx-auto mt-8 p-4",
// Input form
form(
className := "flex items-center gap-2 mb-4",
onSubmit.preventDefault --> { _ => addTodo(inputVar.now()) },
Input(
_.placeholder := "Add a new todo...",
_.value <-- inputVar,
_.events.onInput.mapToValue --> inputVar.writer
),
Button(
_.design := ButtonDesign.Emphasized,
_.tpe := ButtonType.Submit,
"Add"
)
),
// Todo list
div(
className := "space-y-2",
children <-- todosVar.signal.map { todos =>
todos.map { todo =>
div(
className := "flex items-center gap-2 p-2 border rounded",
input(
typ := "checkbox",
checked := todo.completed,
className := "h-5 w-5",
onClick --> { _ => toggleTodo(todo.id) }
),
span(
className := (if todo.completed then "line-through text-gray-500" else ""),
todo.text
),
button(
className := "ml-auto px-2 py-1 text-red-500 hover:bg-red-100 rounded",
onClick --> { _ => deleteTodo(todo.id) },
"×"
)
)
}
}
)
)
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment