basically the same functionality as the old nak.

This commit is contained in:
fiatjaf 2023-03-23 22:36:00 -03:00
parent 570ee55359
commit 88dd984095
No known key found for this signature in database
GPG Key ID: BAD43C4BE5C1A3A1
3 changed files with 88 additions and 23 deletions

View File

@ -3,7 +3,12 @@ enablePlugins(ScalaJSPlugin, EsbuildPlugin)
name := "nostr-army-knife" name := "nostr-army-knife"
scalaVersion := "3.2.2" scalaVersion := "3.2.2"
scalaJSUseMainModuleInitializer := true lazy val root = (project in file("."))
.settings(
libraryDependencies += "com.armanbilge" %%% "calico" % "0.2.0-RC2" libraryDependencies ++= Seq(
libraryDependencies += "com.fiatjaf" %%% "snow" % "0.0.1-SNAPSHOT" "com.armanbilge" %%% "calico" % "0.2.0-RC2",
"com.fiatjaf" %%% "snow" % "0.0.1-SNAPSHOT"
),
scalaJSUseMainModuleInitializer := true,
scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) }
)

View File

@ -5,10 +5,12 @@ import cats.syntax.all.*
import fs2.concurrent.* import fs2.concurrent.*
import fs2.dom.{Event => _, *} import fs2.dom.{Event => _, *}
import io.circe.parser.* import io.circe.parser.*
import io.circe.syntax.*
import calico.* import calico.*
import calico.html.io.{*, given} import calico.html.io.{*, given}
import calico.syntax.* import calico.syntax.*
import snow.* import snow.*
import scoin.*
object Store { object Store {
def apply(window: Window[IO]): Resource[IO, Store] = { def apply(window: Window[IO]): Resource[IO, Store] = {
@ -49,25 +51,42 @@ object Main extends IOWebApp {
store => store =>
div( div(
cls := "flex w-full h-full flex-col items-center justify-center", cls := "flex w-full h-full flex-col items-center justify-center",
h1(cls := "px-1 py-2 text-lg", "nostr army knife"),
div( div(
cls := "flex justify-center my-3" cls := "w-4/5",
// button(cls := buttonCls, "generate event", onClick --> (_.foreach(_ => ))), h1(cls := "px-1 py-2 text-center text-xl", "nostr army knife"),
), div(
input(store), cls := "flex justify-center my-3",
result(store) input(store),
button(
cls :=
"shrink bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 mx-2 px-4 rounded ",
"generate event",
onClick --> (_.foreach(_ =>
store.input.set(
Event(
kind = 1,
content = "hello world"
).sign(PrivateKey(randomBytes32()))
.asJson
.printWith(Utils.jsonPrinter)
)
))
)
),
result(store)
)
) )
} }
def input(store: Store): Resource[IO, HtmlDivElement[IO]] = def input(store: Store): Resource[IO, HtmlDivElement[IO]] =
div( div(
cls := "w-full", cls := "w-full grow",
div( div(
cls := "w-full flex justify-center", cls := "w-full flex justify-center",
textArea.withSelf { self => textArea.withSelf { self =>
( (
cls := "w-2/3 max-h-96 p-3", cls := "w-full max-h-96 p-3 rounded",
styleAttr := "min-height: 200px", styleAttr := "min-height: 400px",
placeholder := "paste something nostric", placeholder := "paste something nostric",
onInput --> (_.foreach(_ => onInput --> (_.foreach(_ =>
self.value.get.flatMap(store.input.set) self.value.get.flatMap(store.input.set)
@ -80,23 +99,46 @@ object Main extends IOWebApp {
def result(store: Store): Resource[IO, HtmlDivElement[IO]] = def result(store: Store): Resource[IO, HtmlDivElement[IO]] =
div( div(
cls := "w-full flex justify-center", cls := "w-full flex my-5",
store.input.map { input => store.input.map { input =>
if input.trim() == "" then "" if input.trim() == "" then div("")
else else
decode[Event](input) match { decode[Event](input) match {
case Right(event) => event.toString case Left(err: io.circe.ParsingFailure) =>
div("not valid JSON")
case Left(err: io.circe.DecodingFailure) => case Left(err: io.circe.DecodingFailure) =>
err.pathToRootString match { err.pathToRootString match {
case Some(path) => s"field $path is missing or wrong" case None => div(s"decoding ${err.pathToRootString}")
case None => s"decoding ${err.pathToRootString}" case Some(path) => div(s"field $path is missing or wrong")
} }
case Left(err: io.circe.ParsingFailure) => case Right(event) =>
"not valid JSON" div(
cls := "text-md",
styleAttr := "font-family: monospace",
div(
span(cls := "font-bold", "serialized event "),
event.serialized
),
div(
span(cls := "font-bold", "implied event id "),
event.hash.toHex
),
div(
span(
cls := "font-bold",
"does the implied event id match the given event id? "
),
event.id == event.hash.toHex match {
case true => "yes"; case false => "no"
}
),
div(
span(cls := "font-bold", "is signature valid? "),
event.isValid match { case true => "yes"; case false => "no" }
)
)
} }
} }
) )
val buttonCls =
"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 mx-2 px-4 rounded"
} }

View File

@ -0,0 +1,18 @@
import io.circe.Printer
object Utils {
val jsonPrinter = Printer(
dropNullValues = false,
indent = " ",
lbraceRight = "\n",
rbraceLeft = "\n",
lbracketRight = "\n",
rbracketLeft = "\n",
lrbracketsEmpty = "",
arrayCommaRight = "\n",
objectCommaRight = "\n",
colonLeft = "",
colonRight = " ",
sortKeys = true
)
}