clicking on edit button to fill in the input.

This commit is contained in:
fiatjaf 2023-06-20 14:49:56 -03:00
parent 7890466783
commit 76ca99a73b
No known key found for this signature in database
GPG Key ID: BAD43C4BE5C1A3A1
4 changed files with 111 additions and 20 deletions

7
edit.svg Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" ?>
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M20,16v4a2,2,0,0,1-2,2H4a2,2,0,0,1-2-2V6A2,2,0,0,1,4,4H8" fill="none" stroke="#f9cc9d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<polygon fill="none" points="12.5 15.8 22 6.2 17.8 2 8.3 11.5 8 16 12.5 15.8" stroke="#f9cc9d" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 463 B

View File

@ -1 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17 13.5v6H5v-12h6m3-3h6v6m0-6-9 9" class="icon_svg-stroke" stroke="#666" stroke-width="1.5" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg> <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17 13.5v6H5v-12h6m3-3h6v6m0-6-9 9" class="icon_svg-stroke" stroke="#3b82f6" stroke-width="1.5" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg>

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 281 B

View File

@ -16,7 +16,10 @@ import snow.*
import Utils.* import Utils.*
object Components { object Components {
def render32Bytes(bytes32: ByteVector32): Resource[IO, HtmlDivElement[IO]] = def render32Bytes(
store: Store,
bytes32: ByteVector32
): Resource[IO, HtmlDivElement[IO]] =
div( div(
cls := "text-md", cls := "text-md",
entry("canonical hex", bytes32.toHex), entry("canonical hex", bytes32.toHex),
@ -25,9 +28,16 @@ object Components {
cls := "mt-2 pl-2 mb-2", cls := "mt-2 pl-2 mb-2",
entry( entry(
"npub", "npub",
NIP19.encode(XOnlyPublicKey(bytes32)),
Some(
editable(
store,
NIP19.encode(XOnlyPublicKey(bytes32)) NIP19.encode(XOnlyPublicKey(bytes32))
)
)
), ),
nip19_21( nip19_21(
store,
"nprofile", "nprofile",
NIP19.encode(ProfilePointer(XOnlyPublicKey(bytes32))) NIP19.encode(ProfilePointer(XOnlyPublicKey(bytes32)))
) )
@ -37,13 +47,26 @@ object Components {
cls := "pl-2 mb-2", cls := "pl-2 mb-2",
entry( entry(
"nsec", "nsec",
NIP19.encode(PrivateKey(bytes32)),
Some(
editable(
store,
NIP19.encode(PrivateKey(bytes32)) NIP19.encode(PrivateKey(bytes32))
)
)
), ),
entry( entry(
"npub", "npub",
NIP19.encode(PrivateKey(bytes32).publicKey.xonly),
Some(
editable(
store,
NIP19.encode(PrivateKey(bytes32).publicKey.xonly) NIP19.encode(PrivateKey(bytes32).publicKey.xonly)
)
)
), ),
nip19_21( nip19_21(
store,
"nprofile", "nprofile",
NIP19.encode(ProfilePointer(PrivateKey(bytes32).publicKey.xonly)) NIP19.encode(ProfilePointer(PrivateKey(bytes32).publicKey.xonly))
) )
@ -52,6 +75,7 @@ object Components {
div( div(
cls := "pl-2 mb-2", cls := "pl-2 mb-2",
nip19_21( nip19_21(
store,
"nevent", "nevent",
NIP19.encode(EventPointer(bytes32.toHex)) NIP19.encode(EventPointer(bytes32.toHex))
) )
@ -60,10 +84,16 @@ object Components {
cls := "pl-2 mb-2", cls := "pl-2 mb-2",
entry( entry(
"note", "note",
NIP19.encode(bytes32),
Some(
editable(
store,
NIP19.encode(bytes32) NIP19.encode(bytes32)
) )
) )
) )
)
)
def renderEventPointer( def renderEventPointer(
store: Store, store: Store,
@ -71,13 +101,21 @@ object Components {
): Resource[IO, HtmlDivElement[IO]] = ): Resource[IO, HtmlDivElement[IO]] =
div( div(
cls := "text-md", cls := "text-md",
entry("event id (hex)", evp.id), entry(
"event id (hex)",
evp.id,
Some(editable(store, evp.id))
),
relayHints(store, evp.relays), relayHints(store, evp.relays),
evp.author.map { pk => evp.author.map { pk =>
entry("author hint (pubkey hex)", pk.value.toHex) entry("author hint (pubkey hex)", pk.value.toHex)
}, },
nip19_21("nevent", NIP19.encode(evp)), nip19_21(store, "nevent", NIP19.encode(evp)),
entry("note", NIP19.encode(ByteVector32.fromValidHex(evp.id))) entry(
"note",
NIP19.encode(ByteVector32.fromValidHex(evp.id)),
Some(editable(store, NIP19.encode(ByteVector32.fromValidHex(evp.id))))
)
) )
def renderProfilePointer( def renderProfilePointer(
@ -87,16 +125,36 @@ object Components {
): Resource[IO, HtmlDivElement[IO]] = ): Resource[IO, HtmlDivElement[IO]] =
div( div(
cls := "text-md", cls := "text-md",
sk.map { k => entry("private key (hex)", k.value.toHex) }, sk.map { k =>
sk.map { k => entry("nsec", NIP19.encode(k)) }, entry(
entry("public key (hex)", pp.pubkey.value.toHex), "private key (hex)",
k.value.toHex,
Some(editable(store, k.value.toHex))
)
},
sk.map { k =>
entry(
"nsec",
NIP19.encode(k),
Some(editable(store, NIP19.encode(k)))
)
},
entry(
"public key (hex)",
pp.pubkey.value.toHex,
Some(editable(store, pp.pubkey.value.toHex))
),
relayHints( relayHints(
store, store,
pp.relays, pp.relays,
dynamic = if sk.isDefined then false else true dynamic = if sk.isDefined then false else true
), ),
entry("npub", NIP19.encode(pp.pubkey)), entry(
nip19_21("nprofile", NIP19.encode(pp)) "npub",
NIP19.encode(pp.pubkey),
Some(editable(store, NIP19.encode(pp.pubkey)))
),
nip19_21(store, "nprofile", NIP19.encode(pp))
) )
def renderAddressPointer( def renderAddressPointer(
@ -109,7 +167,7 @@ object Components {
entry("identifier", addr.d), entry("identifier", addr.d),
entry("kind", addr.kind.toString), entry("kind", addr.kind.toString),
relayHints(store, addr.relays), relayHints(store, addr.relays),
nip19_21("naddr", NIP19.encode(addr)) nip19_21(store, "naddr", NIP19.encode(addr))
) )
def renderEvent( def renderEvent(
@ -205,6 +263,7 @@ object Components {
), ),
event.id.map(id => event.id.map(id =>
nip19_21( nip19_21(
store,
"nevent", "nevent",
NIP19.encode(EventPointer(id, author = event.pubkey)) NIP19.encode(EventPointer(id, author = event.pubkey))
) )
@ -212,28 +271,33 @@ object Components {
event.id.map(id => event.id.map(id =>
entry( entry(
"note", "note",
NIP19.encode(ByteVector32.fromValidHex(id)) NIP19.encode(ByteVector32.fromValidHex(id)),
Some(editable(store, NIP19.encode(ByteVector32.fromValidHex(id))))
) )
) )
) )
private def entry( private def entry(
key: String, key: String,
value: String value: String,
editLink: Option[Resource[IO, HtmlSpanElement[IO]]] = None
): Resource[IO, HtmlDivElement[IO]] = ): Resource[IO, HtmlDivElement[IO]] =
div( div(
cls := "flex items-center space-x-3", cls := "flex items-center space-x-3",
span(cls := "font-bold", key + " "), span(cls := "font-bold", key + " "),
span(Styles.mono, cls := "max-w-xl", value) span(Styles.mono, cls := "max-w-xl", value),
editLink
) )
private def nip19_21( private def nip19_21(
store: Store,
key: String, key: String,
code: String code: String
): Resource[IO, HtmlDivElement[IO]] = ): Resource[IO, HtmlDivElement[IO]] =
div( div(
span(cls := "font-bold", key + " "), span(cls := "font-bold", key + " "),
span(Styles.mono, cls := "break-all", code), span(Styles.mono, cls := "break-all", code),
editable(store, code),
a( a(
href := "nostr:" + code, href := "nostr:" + code,
external external
@ -364,5 +428,25 @@ object Components {
) )
} }
private def editable(
store: Store,
code: String
): Resource[IO, HtmlSpanElement[IO]] =
span(
store.input.map(current =>
if current == code then a("")
else
a(
href := "#/" + code,
onClick --> (_.foreach(evt =>
evt.preventDefault >>
store.input.set(code)
)),
edit
)
)
)
private val edit = img(cls := "inline w-4 ml-2", src := "edit.svg")
private val external = img(cls := "inline w-4 ml-2", src := "ext.svg") private val external = img(cls := "inline w-4 ml-2", src := "ext.svg")
} }

View File

@ -18,7 +18,7 @@ object Main extends IOWebApp {
def render: Resource[IO, HtmlDivElement[IO]] = Store(window).flatMap { def render: Resource[IO, HtmlDivElement[IO]] = Store(window).flatMap {
store => store =>
div( div(
cls := "flex w-full h-full flex-col items-center justify-center", cls := "flex w-full flex-col items-center justify-center",
div( div(
cls := "w-4/5", cls := "w-4/5",
h1( h1(
@ -131,7 +131,7 @@ object Main extends IOWebApp {
cls := "w-full flex my-5", cls := "w-full flex my-5",
store.result.map { store.result.map {
case Left(msg) => div(msg) case Left(msg) => div(msg)
case Right(bytes: ByteVector32) => render32Bytes(bytes) case Right(bytes: ByteVector32) => render32Bytes(store, bytes)
case Right(event: Event) => renderEvent(store, event) case Right(event: Event) => renderEvent(store, event)
case Right(pp: ProfilePointer) => renderProfilePointer(store, pp) case Right(pp: ProfilePointer) => renderProfilePointer(store, pp)
case Right(evp: EventPointer) => renderEventPointer(store, evp) case Right(evp: EventPointer) => renderEventPointer(store, evp)