mirror of
https://github.com/github-tijlxyz/khatru-pyramid.git
synced 2025-06-06 01:02:07 +00:00
convert templates to .templ
This commit is contained in:
parent
be73687eaf
commit
a64a12e03d
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ users.json
|
|||||||
khatru-pyramid
|
khatru-pyramid
|
||||||
.env
|
.env
|
||||||
db
|
db
|
||||||
|
*_templ.go
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
sdk "github.com/nbd-wtf/go-nostr/sdk"
|
|
||||||
. "github.com/theplant/htmlgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func inviteTreeComponent(ctx context.Context, inviter string, loggedUser string) HTMLComponent {
|
|
||||||
children := make([]HTMLComponent, 0, len(whitelist)/2)
|
|
||||||
for pubkey, invitedBy := range whitelist {
|
|
||||||
if invitedBy == inviter {
|
|
||||||
profile := sys.FetchProfileMetadata(ctx, pubkey)
|
|
||||||
children = append(children, userRowComponent(ctx, profile, loggedUser))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ul(children...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func userRowComponent(ctx context.Context, profile sdk.ProfileMetadata, loggedUser string) HTMLComponent {
|
|
||||||
button := Span("")
|
|
||||||
if isAncestorOf(loggedUser, profile.PubKey) && loggedUser != "" {
|
|
||||||
button = Button("remove").
|
|
||||||
Class(buttonClass+" px-2 bg-red-100 hover:bg-red-300").
|
|
||||||
Attr(
|
|
||||||
"hx-post", "/remove-from-whitelist",
|
|
||||||
"hx-trigger", "click",
|
|
||||||
"hx-target", "#tree",
|
|
||||||
"hx-vals", `{"pubkey": "`+profile.PubKey+`"}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Li(
|
|
||||||
userNameComponent(profile),
|
|
||||||
button,
|
|
||||||
inviteTreeComponent(ctx, profile.PubKey, loggedUser),
|
|
||||||
).Class("ml-6")
|
|
||||||
}
|
|
||||||
|
|
||||||
func userNameComponent(profile sdk.ProfileMetadata) HTMLComponent {
|
|
||||||
return A().Href("https://nosta.me/" + profile.Npub()).Target("_blank").Children(
|
|
||||||
Span(profile.ShortName()).Attr("title", profile.Npub()),
|
|
||||||
).Class("font-mono py-1")
|
|
||||||
}
|
|
18
handler.go
18
handler.go
@ -6,15 +6,11 @@ import (
|
|||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"github.com/nbd-wtf/go-nostr"
|
||||||
"github.com/nbd-wtf/go-nostr/nip19"
|
"github.com/nbd-wtf/go-nostr/nip19"
|
||||||
"github.com/theplant/htmlgo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func inviteTreeHandler(w http.ResponseWriter, r *http.Request) {
|
func inviteTreeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
loggedUser := getLoggedUser(r)
|
loggedUser := getLoggedUser(r)
|
||||||
content := inviteTreePageHTML(r.Context(), InviteTreePageParams{
|
inviteTreePage(loggedUser).Render(r.Context(), w)
|
||||||
loggedUser: loggedUser,
|
|
||||||
})
|
|
||||||
htmlgo.Fprint(w, baseHTML(content, loggedUser), r.Context())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -35,8 +31,7 @@ func addToWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := inviteTreeComponent(r.Context(), "", loggedUser)
|
inviteTreeComponent("", loggedUser).Render(r.Context(), w)
|
||||||
htmlgo.Fprint(w, content, r.Context())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeFromWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
func removeFromWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -46,8 +41,7 @@ func removeFromWhitelistHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, "failed to remove from whitelist: "+err.Error(), 500)
|
http.Error(w, "failed to remove from whitelist: "+err.Error(), 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content := inviteTreeComponent(r.Context(), "", loggedUser)
|
inviteTreeComponent("", loggedUser).Render(r.Context(), w)
|
||||||
htmlgo.Fprint(w, content, r.Context())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this deletes all events from users not in the relay anymore
|
// this deletes all events from users not in the relay anymore
|
||||||
@ -95,11 +89,7 @@ func reportsViewerHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := reportsPageHTML(r.Context(), ReportsPageParams{
|
reportsPage(events, getLoggedUser(r)).Render(r.Context(), w)
|
||||||
reports: events,
|
|
||||||
loggedUser: getLoggedUser(r),
|
|
||||||
})
|
|
||||||
htmlgo.Fprint(w, content, r.Context())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func joubleHandler(w http.ResponseWriter, r *http.Request) {
|
func joubleHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
69
invite_tree.templ
Normal file
69
invite_tree.templ
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nbd-wtf/go-nostr/sdk"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ inviteTreePage(loggedUser string) {
|
||||||
|
@layout(loggedUser) {
|
||||||
|
<div>
|
||||||
|
if loggedUser != "" && (loggedUser == s.RelayPubkey || !hasInvitedAtLeast(loggedUser, s.MaxInvitesPerPerson)) {
|
||||||
|
<form
|
||||||
|
hx-post="/add-to-whitelist"
|
||||||
|
hx-trigger="submit"
|
||||||
|
hx-target="#tree"
|
||||||
|
_="on htmx:afterRequest(elt, successful) if successful and elt is I call I.reset()"
|
||||||
|
class="flex justify-center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="pubkey"
|
||||||
|
placeholder="npub1..."
|
||||||
|
class="w-96 rounded-md border-0 p-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="rounded-md text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 ml-2 p-2 bg-white hover:bg-gray-50"
|
||||||
|
>
|
||||||
|
invite
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
<div id="tree" class="mt-3 flex justify-center">
|
||||||
|
@inviteTreeComponent("", loggedUser)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templ inviteTreeComponent(inviter string, loggedUser string) {
|
||||||
|
<ul>
|
||||||
|
for pubkey, invitedBy := range whitelist {
|
||||||
|
if invitedBy == inviter {
|
||||||
|
<li class="ml-6">
|
||||||
|
@userNameComponent(sys.FetchProfileMetadata(ctx, pubkey))
|
||||||
|
if isAncestorOf(loggedUser, pubkey) && loggedUser != "" {
|
||||||
|
<button
|
||||||
|
class="rounded-md text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 px-2 ml-2 bg-red-100 hover:bg-red-300"
|
||||||
|
hx-post="/remove-from-whitelist"
|
||||||
|
hx-trigger="click"
|
||||||
|
hx-target="#tree"
|
||||||
|
hx-vals={ fmt.Sprintf(`{"pubkey": "%s"}`, pubkey) }
|
||||||
|
>
|
||||||
|
remove
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
@inviteTreeComponent(pubkey, loggedUser)
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ userNameComponent(profile sdk.ProfileMetadata) {
|
||||||
|
<a href={ templ.URL("https://nosta.me/" + profile.Npub()) } target="_blank" class="font-mono py-1">
|
||||||
|
<span title={ profile.Npub() }>{ profile.ShortName() }</span>
|
||||||
|
</a>
|
||||||
|
}
|
7
justfile
7
justfile
@ -1,9 +1,12 @@
|
|||||||
dev:
|
dev:
|
||||||
ag -l --go | entr -r godotenv go run .
|
fd 'go|templ' | entr -r bash -c 'just templ && godotenv go run .'
|
||||||
|
|
||||||
build:
|
build: templ
|
||||||
CC=musl-gcc go build -ldflags='-linkmode external -extldflags "-static"' -o ./khatru-pyramid
|
CC=musl-gcc go build -ldflags='-linkmode external -extldflags "-static"' -o ./khatru-pyramid
|
||||||
|
|
||||||
|
templ:
|
||||||
|
templ generate
|
||||||
|
|
||||||
deploy target: build
|
deploy target: build
|
||||||
ssh root@{{target}} 'systemctl stop pyramid';
|
ssh root@{{target}} 'systemctl stop pyramid';
|
||||||
scp khatru-pyramid {{target}}:pyramid/khatru-invite
|
scp khatru-pyramid {{target}}:pyramid/khatru-invite
|
||||||
|
59
layout.templ
Normal file
59
layout.templ
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
templ layout(loggedUser string) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<title>{ s.RelayName }</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
|
||||||
|
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
|
||||||
|
</head>
|
||||||
|
<body class="max-w-screen-lg px-3 mx-auto">
|
||||||
|
<div class="mx-auto my-6 text-center">
|
||||||
|
<h1 class="font-bold text-2xl">{ s.RelayName }</h1>
|
||||||
|
if s.RelayDescription != "" {
|
||||||
|
<p class="text-lg">{ s.RelayDescription }</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<nav class="flex flex-1 items-center justify-center">
|
||||||
|
<a href="/" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium" hx-boost="true" hx-target="main" hx-select="main">invite tree</a>
|
||||||
|
<a href="/browse" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium">browse</a>
|
||||||
|
<a href="/reports" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium" hx-boost="true" hx-target="main" hx-select="main">reports</a>
|
||||||
|
if loggedUser == s.RelayPubkey {
|
||||||
|
<a href="/cleanup" class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium">clear stuff</a>
|
||||||
|
}
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium"
|
||||||
|
_="
|
||||||
|
on click if my innerText is equal to 'login'
|
||||||
|
get window.nostr.signEvent({created_at: Math.round(Date.now()/1000), kind: 27235, tags: [['domain', '{ s.Domain }']], content: ''})
|
||||||
|
then get JSON.stringify(it)
|
||||||
|
then set cookies['nip98'] to it
|
||||||
|
otherwise
|
||||||
|
call cookies.clear('nip98')
|
||||||
|
end
|
||||||
|
then call location.reload()
|
||||||
|
|
||||||
|
on load
|
||||||
|
get cookies['nip98']
|
||||||
|
then if it is undefined
|
||||||
|
set my innerText to 'login'
|
||||||
|
otherwise
|
||||||
|
set my innerText to 'logout'
|
||||||
|
"
|
||||||
|
></a>
|
||||||
|
</nav>
|
||||||
|
<main class="m-4">
|
||||||
|
{ children... }
|
||||||
|
</main>
|
||||||
|
<p class="text-end my-4 text-sm">
|
||||||
|
powered by
|
||||||
|
<a href="https://github.com/github-tijlxyz/khatru-pyramid" class="hover:underline cursor-pointer text-blue-500">khatru-pyramid</a>
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
148
pages.go
148
pages.go
@ -1,148 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
|
||||||
. "github.com/theplant/htmlgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
const buttonClass = "rounded-md text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300"
|
|
||||||
|
|
||||||
func baseHTML(inside HTMLComponent, loggedUser string) HTMLComponent {
|
|
||||||
navItemClass := "text-gray-600 hover:bg-gray-200 rounded-md px-3 py-2 font-medium"
|
|
||||||
|
|
||||||
cleanupButton := Span("")
|
|
||||||
if loggedUser == s.RelayPubkey {
|
|
||||||
cleanupButton = A().Text("clear stuff").Href("/cleanup").Class(navItemClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
return HTML(
|
|
||||||
Head(
|
|
||||||
Meta().Charset("utf-8"),
|
|
||||||
Meta().Name("viewport").Content("width=device-width, initial-scale=1"),
|
|
||||||
Title(s.RelayName),
|
|
||||||
Script("").Src("https://cdn.tailwindcss.com"),
|
|
||||||
Script("").Src("https://unpkg.com/htmx.org@1.9.6"),
|
|
||||||
Script("").Src("https://unpkg.com/hyperscript.org@0.9.12"),
|
|
||||||
),
|
|
||||||
Body(
|
|
||||||
Div(
|
|
||||||
H1(s.RelayName).Class("font-bold text-2xl"),
|
|
||||||
P().Text(s.RelayDescription).Class("text-lg"),
|
|
||||||
).Class("mx-auto my-6 text-center"),
|
|
||||||
Nav(
|
|
||||||
A().Text("invite tree").Href("/").Class(navItemClass).Attr("hx-boost", "true", "hx-target", "main", "hx-select", "main"),
|
|
||||||
A().Text("browse").Href("/browse").Class(navItemClass),
|
|
||||||
A().Text("reports").Href("/reports").Class(navItemClass).Attr("hx-boost", "true", "hx-target", "main", "hx-select", "main"),
|
|
||||||
cleanupButton,
|
|
||||||
A().Text("").Href("#").Class(navItemClass).
|
|
||||||
Attr("_", `
|
|
||||||
on click if my innerText is equal to "login" get window.nostr.signEvent({created_at: Math.round(Date.now()/1000), kind: 27235, tags: [['domain', "`+s.Domain+`"]], content: ''}) then get JSON.stringify(it) then set cookies['nip98'] to it otherwise call cookies.clear('nip98') end then call location.reload()
|
|
||||||
|
|
||||||
on load get cookies['nip98'] then if it is undefined set my innerText to "login" otherwise set my innerText to "logout"`),
|
|
||||||
).Class("flex flex-1 items-center justify-center"),
|
|
||||||
Main(inside).Class("m-4"),
|
|
||||||
P(
|
|
||||||
Text("powered by "),
|
|
||||||
A().Href("https://github.com/github-tijlxyz/khatru-pyramid").Text("khatru-pyramid").Class("hover:underline cursor-pointer text-blue-500"),
|
|
||||||
).Class("text-end my-4 text-sm"),
|
|
||||||
).Class("my-6 mx-auto max-w-min min-w-96"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InviteTreePageParams struct {
|
|
||||||
loggedUser string
|
|
||||||
}
|
|
||||||
|
|
||||||
func inviteTreePageHTML(ctx context.Context, params InviteTreePageParams) HTMLComponent {
|
|
||||||
inviteForm := Div()
|
|
||||||
|
|
||||||
if params.loggedUser != "" && (params.loggedUser == s.RelayPubkey || !hasInvitedAtLeast(params.loggedUser, s.MaxInvitesPerPerson)) {
|
|
||||||
inviteForm = Form(
|
|
||||||
Input("pubkey").Type("text").Placeholder("npub1...").Class("w-96 rounded-md border-0 p-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600"),
|
|
||||||
Button("invite").Class(buttonClass+" ml-2 p-2 bg-white hover:bg-gray-50"),
|
|
||||||
).Attr(
|
|
||||||
"hx-post", "/add-to-whitelist",
|
|
||||||
"hx-trigger", "submit",
|
|
||||||
"hx-target", "#tree",
|
|
||||||
"_", "on htmx:afterRequest(elt, successful) if successful and elt is I call I.reset()",
|
|
||||||
).Class("flex")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Div(
|
|
||||||
inviteForm,
|
|
||||||
Div(
|
|
||||||
inviteTreeComponent(ctx, "", params.loggedUser),
|
|
||||||
).Id("tree").Class("mt-3"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReportsPageParams struct {
|
|
||||||
reports chan *nostr.Event
|
|
||||||
loggedUser string
|
|
||||||
}
|
|
||||||
|
|
||||||
func reportsPageHTML(ctx context.Context, params ReportsPageParams) HTMLComponent {
|
|
||||||
items := make([]HTMLComponent, 0, 52)
|
|
||||||
for report := range params.reports {
|
|
||||||
var primaryType string
|
|
||||||
var secondaryType string
|
|
||||||
var relatedContent HTMLComponent
|
|
||||||
|
|
||||||
if e := report.Tags.GetFirst([]string{"e", ""}); e != nil {
|
|
||||||
// event report
|
|
||||||
res, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{IDs: []string{(*e)[1]}})
|
|
||||||
if len(res) == 0 {
|
|
||||||
sys.Store.DeleteEvent(ctx, report)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(*e) >= 3 {
|
|
||||||
primaryType = (*e)[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
relatedEvent := res[0]
|
|
||||||
relatedContent = Div(
|
|
||||||
Text("event reported: "),
|
|
||||||
Div().Text(relatedEvent.String()).Class("text-mono"),
|
|
||||||
)
|
|
||||||
} else if p := report.Tags.GetFirst([]string{"p", ""}); p != nil {
|
|
||||||
// pubkey report
|
|
||||||
if !isPublicKeyInWhitelist((*p)[1]) {
|
|
||||||
sys.Store.DeleteEvent(ctx, report)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(*p) >= 3 {
|
|
||||||
primaryType = (*p)[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
relatedProfile := sys.FetchProfileMetadata(ctx, (*p)[1])
|
|
||||||
relatedContent = Div(
|
|
||||||
Text("profile reported: "),
|
|
||||||
userNameComponent(relatedProfile),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
reporter := sys.FetchProfileMetadata(ctx, report.PubKey)
|
|
||||||
report := Div(
|
|
||||||
Div(Span(primaryType).Class("font-semibold"), Text(" report")).Class("font-lg"),
|
|
||||||
Div().Text(secondaryType),
|
|
||||||
Div(Text("by "), userNameComponent(reporter)),
|
|
||||||
Div().Text(report.Content).Class("p-3"),
|
|
||||||
relatedContent,
|
|
||||||
)
|
|
||||||
|
|
||||||
items = append(items, report)
|
|
||||||
}
|
|
||||||
return baseHTML(
|
|
||||||
Div(
|
|
||||||
H1("reports received").Class("text-xl p-4"),
|
|
||||||
Div(items...),
|
|
||||||
),
|
|
||||||
params.loggedUser,
|
|
||||||
)
|
|
||||||
}
|
|
64
reports.templ
Normal file
64
reports.templ
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/nbd-wtf/go-nostr"
|
||||||
|
|
||||||
|
templ reportsPage(reports chan *nostr.Event, loggedUser string) {
|
||||||
|
@layout(loggedUser) {
|
||||||
|
<div>
|
||||||
|
<h1 class="text-xl p-4">reports received</h1>
|
||||||
|
<div>
|
||||||
|
for report := range reports {
|
||||||
|
<div>
|
||||||
|
if e := report.Tags.GetFirst([]string{"e", ""}); e != nil {
|
||||||
|
@eventReportComponent(e, report)
|
||||||
|
} else if p := report.Tags.GetFirst([]string{"p", ""}); p != nil {
|
||||||
|
@profileReportComponent(p, report)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templ eventReportComponent(e *nostr.Tag, report *nostr.Event) {
|
||||||
|
if res, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{IDs: []string{(*e)[1]}}); len(res) > 0 {
|
||||||
|
<div>
|
||||||
|
<div class="font-lg">
|
||||||
|
<span class="font-semibold">
|
||||||
|
if len(*e) >= 3 {
|
||||||
|
{ (*e)[2] }
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
{ " report" }
|
||||||
|
</div>
|
||||||
|
<div>by @userNameComponent(sys.FetchProfileMetadata(ctx, report.PubKey))</div>
|
||||||
|
<div class="p-3">{ report.Content }</div>
|
||||||
|
<div>
|
||||||
|
event reported:
|
||||||
|
<div class="text-mono">{ res[0].String() }</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templ profileReportComponent(p *nostr.Tag, report *nostr.Event) {
|
||||||
|
if isPublicKeyInWhitelist((*p)[1]) {
|
||||||
|
<div>
|
||||||
|
<div class="font-lg">
|
||||||
|
<span class="font-semibold">
|
||||||
|
if len(*p) >= 3 {
|
||||||
|
{ (*p)[2] }
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
{ " report" }
|
||||||
|
</div>
|
||||||
|
<div>by @userNameComponent(sys.FetchProfileMetadata(ctx, report.PubKey))</div>
|
||||||
|
<div class="p-3">{ report.Content }</div>
|
||||||
|
<div>
|
||||||
|
profile reported:
|
||||||
|
@userNameComponent(sys.FetchProfileMetadata(ctx, (*p)[1]))
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user