massive template refactoring and cleanup.

This commit is contained in:
fiatjaf
2024-01-10 14:18:42 -03:00
parent 6b19f5103c
commit 8403f6e129
21 changed files with 478 additions and 561 deletions

27
calendar_event.templ Normal file
View File

@@ -0,0 +1,27 @@
package main
templ calendarEventTemplate(params CalendarPageParams) {
<!DOCTYPE html>
@eventPageTemplate(
"Calendar Event: " + params.CalendarEvent.Title,
params.OpenGraphParams,
params.HeadParams,
params.Metadata,
params.Clients,
params.Details,
params.Event,
) {
<h1 class="text-2xl">
<span class="mr-2">{ params.CalendarEvent.Title }</span>
</h1>
<div class="mb-4"></div>
<!-- main content -->
<div class="mb-4">
for _, v := range params.CalendarEvent.Hashtags {
<span class="mr-2 whitespace-nowrap rounded bg-neutral-200 px-2 dark:bg-neutral-700 dark:text-white">
{ v }
</span>
}
</div>
}
}

View File

@@ -28,6 +28,7 @@ var (
zapStream = ClientReference{ID: "zap.stream", Name: "zap.stream", Base: "https://zap.stream/{code}", Platform: "web"} zapStream = ClientReference{ID: "zap.stream", Name: "zap.stream", Base: "https://zap.stream/{code}", Platform: "web"}
nostrrr = ClientReference{ID: "nostrrr", Name: "Nostrrr", Base: "https://nostrrr.com/relay/{code}", Platform: "web"} nostrrr = ClientReference{ID: "nostrrr", Name: "Nostrrr", Base: "https://nostrrr.com/relay/{code}", Platform: "web"}
flockstr = ClientReference{ID: "flockstr", Name: "Flockstr", Base: "https://www.flockstr.com/event/{code}", Platform: "web"}
yakihonne = ClientReference{ID: "yakihonne", Name: "YakiHonne", Base: "https://yakihonne.com/article/{code}", Platform: "web"} yakihonne = ClientReference{ID: "yakihonne", Name: "YakiHonne", Base: "https://yakihonne.com/article/{code}", Platform: "web"}
habla = ClientReference{ID: "habla", Name: "Habla", Base: "https://habla.news/a/{code}", Platform: "web"} habla = ClientReference{ID: "habla", Name: "Habla", Base: "https://habla.news/a/{code}", Platform: "web"}
@@ -90,6 +91,12 @@ func generateClientList(kind int, code string, withModifiers ...func(string) str
zapStream, nostrudel, zapStream, nostrudel,
amethyst, amethyst,
} }
case 31922, 31923:
clients = []ClientReference{
native,
flockstr, nostrudel,
amethyst,
}
default: default:
clients = []ClientReference{ clients = []ClientReference{
native, native,

View File

@@ -1,5 +1,38 @@
package main package main
templ headCommonTemplate(params HeadParams) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
if params.Oembed != "" {
<link rel="alternate" type="application/json+oembed" href={ params.Oembed + "&format=json" }/>
<link rel="alternate" type="text/xml+oembed" href={ params.Oembed + "&format=xml" }/>
}
if params.IsProfile {
<link rel="apple-touch-icon" sizes="180x180" href="/njump/static/favicon/profile/apple-touch-icon.png?v=2"/>
<link rel="icon" type="image/png" sizes="32x32" href="/njump/static/favicon/profile/favicon-32x32.png?v=2"/>
<link rel="icon" type="image/png" sizes="16x16" href="/njump/static/favicon/profile/favicon-16x16.png?v=2"/>
} else {
<link rel="apple-touch-icon" sizes="180x180" href="/njump/static/favicon/event/apple-touch-icon.png?v=2"/>
<link rel="icon" type="image/png" sizes="32x32" href="/njump/static/favicon/event/favicon-32x32.png?v=2"/>
<link rel="icon" type="image/png" sizes="16x16" href="/njump/static/favicon/event/favicon-16x16.png?v=2"/>
}
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
if tailwindDebugStuff != "" {
@templ.Raw(tailwindDebugStuff)
} else {
<link rel="stylesheet" type="text/css" href="/njump/static/tailwind-bundle.min.css"/>
}
<style> @media print { @page { margin: 2cm 3cm; } } </style>
<meta name="theme-color" content="#e42a6d"/>
if params.NaddrNaked != "" {
<link rel="canonical" href={ "https://njump.me/" + params.NaddrNaked }/>
} else {
<link rel="canonical" href={ "https://njump.me/" + params.NeventNaked }/>
}
<script type="text/hyperscript">
on load get [navigator.userAgent.includes('Safari'), navigator.userAgent.includes('Chrome')] then if it[0] is true and it[1] is false add .safari to <body /> end
</script>
}
templ authorHeaderTemplate(metadata Metadata) { templ authorHeaderTemplate(metadata Metadata) {
<header class="mb-4 max-w-full"> <header class="mb-4 max-w-full">
<a class="flex flex-wrap items-center" href={ templ.URL("/" + metadata.Npub()) }> <a class="flex flex-wrap items-center" href={ templ.URL("/" + metadata.Npub()) }>
@@ -9,7 +42,6 @@ templ authorHeaderTemplate(metadata Metadata) {
<div class="block print:text-base sm:grow"> <div class="block print:text-base sm:grow">
<div class="leading-4 sm:text-2xl"> <div class="leading-4 sm:text-2xl">
{ metadata.Name } { metadata.Name }
<!---->
if metadata.Name != metadata.DisplayName { if metadata.Name != metadata.DisplayName {
<span class="text-stone-400 sm:text-xl">/ { metadata.DisplayName } </span> <span class="text-stone-400 sm:text-xl">/ { metadata.DisplayName } </span>
} }
@@ -24,29 +56,18 @@ templ authorHeaderTemplate(metadata Metadata) {
templ lastNotesTemplate(lastNotes []EnhancedEvent) { templ lastNotesTemplate(lastNotes []EnhancedEvent) {
<aside> <aside>
<div <div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"
></div>
<nav class="mb-6 leading-5"> <nav class="mb-6 leading-5">
<h2 class="text-2xl text-strongpink">Last Notes</h2> <h2 class="text-2xl text-strongpink">Last Notes</h2>
for _, ee := range lastNotes { for _, ee := range lastNotes {
<a <a class="my-8 block no-underline hover:-ml-6 hover:border-l-05rem hover:border-solid hover:border-l-gray-100 hover:pl-4 dark:hover:border-l-zinc-700" href={ templ.URL("/" + ee.Nevent()) }>
class="my-8 block no-underline hover:-ml-6 hover:border-l-05rem hover:border-solid hover:border-l-gray-100 hover:pl-4 dark:hover:border-l-zinc-700" <div class="-ml-2.5 mb-1.5 flex flex-row flex-wrap border-b-4 border-solid border-b-gray-100 pb-1 pl-2.5 dark:border-b-neutral-800">
href={ templ.URL("/" + ee.Nevent()) }
>
<div
class="-ml-2.5 mb-1.5 flex flex-row flex-wrap border-b-4 border-solid border-b-gray-100 pb-1 pl-2.5 dark:border-b-neutral-800"
>
<div class="text-sm text-strongpink">{ ee.CreatedAtStr() }</div> <div class="text-sm text-strongpink">{ ee.CreatedAtStr() }</div>
if ee.IsReply() { if ee.isReply() {
<div class="ml-2 text-sm text-gray-300 dark:text-gray-400">- reply</div> <div class="ml-2 text-sm text-gray-300 dark:text-gray-400">- reply</div>
} }
</div> </div>
<div <div class="mt-0.5 max-h-40 basis-full overflow-hidden hover:text-strongpink" _="on load if my scrollHeight > my offsetHeight add .gradient" dir="auto">
class="mt-0.5 max-h-40 basis-full overflow-hidden hover:text-strongpink"
_="on load if my scrollHeight > my offsetHeight add .gradient"
dir="auto"
>
@templ.Raw(ee.Preview()) @templ.Raw(ee.Preview())
</div> </div>
</a> </a>

14
data.go
View File

@@ -4,12 +4,12 @@ import (
"context" "context"
"fmt" "fmt"
"html/template" "html/template"
"strconv"
"strings" "strings"
"time" "time"
"github.com/nbd-wtf/go-nostr/nip19" "github.com/nbd-wtf/go-nostr/nip19"
"github.com/nbd-wtf/go-nostr/nip31" "github.com/nbd-wtf/go-nostr/nip31"
"github.com/nbd-wtf/go-nostr/nip52"
"github.com/nbd-wtf/go-nostr/nip53" "github.com/nbd-wtf/go-nostr/nip53"
"github.com/nbd-wtf/go-nostr/nip94" "github.com/nbd-wtf/go-nostr/nip94"
sdk "github.com/nbd-wtf/nostr-sdk" sdk "github.com/nbd-wtf/nostr-sdk"
@@ -122,9 +122,6 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
case 1, 7, 30023, 30024: case 1, 7, 30023, 30024:
data.templateId = Note data.templateId = Note
data.content = event.Content data.content = event.Content
if parentNevent := getParentNevent(event); parentNevent != "" {
data.parentLink = template.HTML(replaceNostrURLsWithTags(nostrNoteNeventMatcher, "nostr:"+parentNevent))
}
case 6: case 6:
data.templateId = Note data.templateId = Note
if reposted := event.Tags.GetFirst([]string{"e", ""}); reposted != nil { if reposted := event.Tags.GetFirst([]string{"e", ""}); reposted != nil {
@@ -145,12 +142,9 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
case 1311: case 1311:
data.templateId = LiveEventMessage data.templateId = LiveEventMessage
data.content = event.Content data.content = event.Content
if atag := event.Tags.GetFirst([]string{"a", ""}); atag != nil { case 31922, 31923:
parts := strings.Split((*atag)[1], ":") data.templateId = CalendarEvent
kind, _ := strconv.Atoi(parts[0]) data.kind31922Or31923Metadata = &Kind31922Or31923Metadata{CalendarEvent: nip52.ParseCalendarEvent(*event)}
parentNevent, _ := nip19.EncodeEntity(parts[1], kind, parts[2], data.event.relays)
data.parentLink = template.HTML(replaceNostrURLsWithTags(nostrEveryMatcher, "nostr:"+parentNevent))
}
default: default:
data.templateId = Other data.templateId = Other
} }

View File

@@ -4,44 +4,22 @@ import (
"strconv" "strconv"
) )
templ detailsTemplate(params DetailsParams) { templ detailsTemplate(details DetailsParams) {
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div> <div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
if params.Metadata.Npub() != "" { if details.Metadata.Npub() != "" {
<div class="mb-6 break-all leading-5"> <div class="mb-6 break-all leading-5">
<div class="text-sm text-strongpink">Author Public Key</div> <div class="text-sm text-strongpink">Author Public Key</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.Metadata.Npub() }</span> <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ details.Metadata.Npub() }</span>
</div> </div>
} }
if params.FileMetadata != nil { if details.Extra != nil {
if params.FileMetadata.Summary != "" { @details.Extra
<div class="mb-6 leading-5">
<div class="text-sm text-strongpink">Summary</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Summary }</span>
</div>
}
if params.FileMetadata.Dim != "" {
<div class="mb-6 leading-5">
<div class="text-sm text-strongpink">Dimension</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Dim }</span>
</div>
}
if params.FileMetadata.Size != "" {
<div class="mb-6 leading-5">
<div class="text-sm text-strongpink">Size</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Size } bytes</span>
</div>
}
if params.FileMetadata.Magnet != "" {
<div class="mb-6 leading-5">
<div class="text-sm text-strongpink">Magnet URL</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Magnet }</span>
</div>
}
} }
if len(params.SeenOn) != 0 { <span></span>
if len(details.SeenOn) != 0 {
<div class="mb-6 leading-5 text-neutral-500 dark:text-neutral-300 text-[16px]"> <div class="mb-6 leading-5 text-neutral-500 dark:text-neutral-300 text-[16px]">
<div class="text-sm text-strongpink">Seen on</div> <div class="text-sm text-strongpink">Seen on</div>
for _, v := range params.SeenOn { for _, v := range details.SeenOn {
<a <a
href={ templ.URL("/r/" + v) } href={ templ.URL("/r/" + v) }
class="underline-none pr-2 decoration-neutral-200 decoration-1 underline-offset-[6px] hover:underline" class="underline-none pr-2 decoration-neutral-200 decoration-1 underline-offset-[6px] hover:underline"
@@ -50,7 +28,7 @@ templ detailsTemplate(params DetailsParams) {
</div> </div>
} }
<!-- details hidden behind a toggle --> <!-- details hidden behind a toggle -->
if params.HideDetails { if details.HideDetails {
<div class="mb-6 flex items-center print:hidden"> <div class="mb-6 flex items-center print:hidden">
<input <input
type="checkbox" type="checkbox"
@@ -81,25 +59,25 @@ templ detailsTemplate(params DetailsParams) {
>Show more details</label> >Show more details</label>
</div> </div>
} }
<div id="hidden-fields" class={ templ.KV("hidden", params.HideDetails) }> <div id="hidden-fields" class={ templ.KV("hidden", details.HideDetails) }>
<div class="mb-6 leading-5"> <div class="mb-6 leading-5">
<div class="text-sm text-strongpink">Published at</div> <div class="text-sm text-strongpink">Published at</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.CreatedAt }</span> <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ details.CreatedAt }</span>
</div> </div>
<div class="mb-6 leading-5"> <div class="mb-6 leading-5">
<div class="text-sm text-strongpink">Kind type</div> <div class="text-sm text-strongpink">Kind type</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ strconv.Itoa(params.Kind) }</span> <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ strconv.Itoa(details.Kind) }</span>
if params.KindNIP != "" { if details.KindNIP != "" {
<a <a
href={ templ.URL("https://github.com/nostr-protocol/nips/blob/master/" + params.KindNIP + ".md") } href={ templ.URL("https://github.com/nostr-protocol/nips/blob/master/" + details.KindNIP + ".md") }
class="underline decoration-neutral-200 dark:decoration-neutral-500 decoration-1 underline-offset-[6px] text-neutral-500 dark:text-neutral-300 text-[16px]" class="underline decoration-neutral-200 dark:decoration-neutral-500 decoration-1 underline-offset-[6px] text-neutral-500 dark:text-neutral-300 text-[16px]"
>{ params.KindDescription }</a> >{ details.KindDescription }</a>
} }
</div> </div>
if params.Nevent != "" { if details.Nevent != "" {
<div class="mb-6 leading-5"> <div class="mb-6 leading-5">
<div class="text-sm text-strongpink">Address Code</div> <div class="text-sm text-strongpink">Address Code</div>
<span class="text-[16px] text-neutral-500 dark:text-neutral-300">{ params.Nevent }</span> <span class="text-[16px] text-neutral-500 dark:text-neutral-300">{ details.Nevent }</span>
</div> </div>
} }
<div class="-mx-4 my-8 bg-neutral-100 px-4 pb-4 leading-5 dark:bg-neutral-700"> <div class="-mx-4 my-8 bg-neutral-100 px-4 pb-4 leading-5 dark:bg-neutral-700">
@@ -109,13 +87,13 @@ templ detailsTemplate(params DetailsParams) {
Event JSON Event JSON
</div> </div>
<div class="mt-4 whitespace-pre-wrap break-all font-mono text-sm"> <div class="mt-4 whitespace-pre-wrap break-all font-mono text-sm">
@templ.Raw(params.EventJSON) @templ.Raw(details.EventJSON)
</div> </div>
</div> </div>
if params.Nprofile != "" { if details.Nprofile != "" {
<div class="mb-6 break-all leading-5"> <div class="mb-6 break-all leading-5">
<div class="text-sm text-strongpink">Author Profile Code</div> <div class="text-sm text-strongpink">Author Profile Code</div>
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.Nprofile }</span> <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ details.Nprofile }</span>
</div> </div>
} }
</div> </div>

49
event_page.templ Normal file
View File

@@ -0,0 +1,49 @@
package main
templ eventPageTemplate(
title string,
og OpenGraphParams,
head HeadParams,
author Metadata,
clients []ClientReference,
details DetailsParams,
event EnhancedEvent,
) {
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
<meta charset="UTF-8"/>
<head>
<title>{ title }</title>
@openGraphTemplate(og)
@headCommonTemplate(head)
</head>
<body class="mb-16 bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black">
@topTemplate()
<div class="mx-auto px-4 sm:flex sm:items-center sm:justify-center sm:px-0">
<div class="w-full max-w-screen-2xl justify-between gap-10 overflow-visible print:w-full sm:flex sm:w-11/12 sm:px-4 md:w-10/12 lg:w-9/12 lg:gap-48vw">
<div class="w-full break-words print:w-full sm:w-3/4">
@authorHeaderTemplate(author)
<div class="w-full text-right text-sm text-stone-400">
{ event.CreatedAtStr() }
</div>
<div class="w-full text-right text-sm text-stone-400">
if nevent := event.getParentNevent(); nevent != "" {
in reply to
<span class="text-strongpink">
@templ.Raw(replaceNostrURLsWithHTMLTags(nostrNoteNeventMatcher, "nostr:" + nevent))
</span>
}
</div>
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
<article class="prose-cite:text-sm prose mb-6 leading-5 dark:prose-invert prose-headings:font-light prose-p:m-0 prose-p:mb-2 prose-blockquote:mx-0 prose-blockquote:my-8 prose-blockquote:border-l-05rem prose-blockquote:border-solid prose-blockquote:border-l-gray-100 prose-blockquote:py-2 prose-blockquote:pl-4 prose-blockquote:pr-0 prose-ol:m-0 prose-ol:p-0 prose-ol:pl-4 prose-ul:m-0 prose-ul:p-0 prose-ul:pl-4 prose-li:mb-2 dark:prose-blockquote:border-l-zinc-800 sm:prose-a:text-justify">
{ children... }
</article>
@detailsTemplate(details)
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
</div>
@clientsTemplate(clients)
</div>
</div>
@footerTemplate()
</body>
</html>
}

View File

@@ -2,72 +2,59 @@ package main
templ fileMetadataTemplate(params FileMetadataPageParams) { templ fileMetadataTemplate(params FileMetadataPageParams) {
<!DOCTYPE html> <!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl"> @eventPageTemplate(
<meta charset="UTF-8"/> "File Metadata",
<head> params.OpenGraphParams,
<title>File Metadata</title> params.HeadParams,
@openGraphTemplate(params.OpenGraphParams) params.Metadata,
@headCommonTemplate(params.HeadParams) params.Clients,
</head> params.Details,
<body params.Event,
class="mb-16 bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black" ) {
> if params.FileMetadata.Image != "" {
@topTemplate() <img src={ params.FileMetadata.Image } alt={ params.Alt }/>
<div class="mx-auto px-4 sm:flex sm:items-center sm:justify-center sm:px-0"> } else if params.IsImage {
<div <img src={ params.FileMetadata.URL } alt={ params.Alt }/>
class="w-full max-w-screen-2xl justify-between gap-10 overflow-visible print:w-full sm:flex sm:w-11/12 sm:px-4 md:w-10/12 lg:w-9/12 lg:gap-48vw" } else if params.IsVideo {
> <video
<div class="w-full break-words print:w-full sm:w-3/4"> controls
@authorHeaderTemplate(params.Metadata) width="100%%"
<div class="w-full text-right text-sm text-stone-400"> class="max-h-[90vh] bg-neutral-300 dark:bg-zinc-700"
{ params.CreatedAt } >
</div> <source src={ params.FileMetadata.URL } alt={ params.Alt }/>
<div class="w-full text-right text-sm text-stone-400"> </video>
if params.ParentLink != "" { }
in reply to <a
<span class="text-strongpink"> href={ templ.URL(params.FileMetadata.URL) }
@templ.Raw(params.ParentLink) target="_new"
</span> class="not-prose mx-auto mb-3 block w-4/5 basis-full rounded-lg border-0 bg-strongpink px-4 py-2 text-center text-[17px] font-light text-white no-underline sm:w-2/6"
} >Download file</a>
</div> }
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div> }
<article
class="prose-cite:text-sm prose mb-6 leading-5 dark:prose-invert prose-headings:font-light prose-p:m-0 prose-p:mb-2 prose-blockquote:mx-0 prose-blockquote:my-8 prose-blockquote:border-l-05rem prose-blockquote:border-solid prose-blockquote:border-l-gray-100 prose-blockquote:py-2 prose-blockquote:pl-4 prose-blockquote:pr-0 prose-ol:m-0 prose-ol:p-0 prose-ol:pl-4 prose-ul:m-0 prose-ul:p-0 prose-ul:pl-4 prose-li:mb-2 dark:prose-blockquote:border-l-zinc-800 sm:prose-a:text-justify" templ fileMetadataDetails(params FileMetadataPageParams) {
> if params.FileMetadata.Summary != "" {
if params.Subject != "" { <div class="mb-6 leading-5">
<h1 class="text-2xl">{ params.Subject }</h1> <div class="text-sm text-strongpink">Summary</div>
} else { <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Summary }</span>
<h1 class="hidden"> </div>
{ params.Metadata.ShortName() } on Nostr: { params.TitleizedContent } }
</h1> if params.FileMetadata.Dim != "" {
} <div class="mb-6 leading-5">
<!-- main content --> <div class="text-sm text-strongpink">Dimension</div>
if params.FileMetadata.Image != "" { <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Dim }</span>
<img src={ params.FileMetadata.Image } alt={ params.Alt }/> </div>
} else if params.IsImage { }
<img src={ params.FileMetadata.URL } alt={ params.Alt }/> if params.FileMetadata.Size != "" {
} else if params.IsVideo { <div class="mb-6 leading-5">
<video <div class="text-sm text-strongpink">Size</div>
controls <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Size } bytes</span>
width="100%%" </div>
class="max-h-[90vh] bg-neutral-300 dark:bg-zinc-700" }
> if params.FileMetadata.Magnet != "" {
<source src={ params.FileMetadata.URL } alt={ params.Alt }/> <div class="mb-6 leading-5">
</video> <div class="text-sm text-strongpink">Magnet URL</div>
} <span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ params.FileMetadata.Magnet }</span>
<a </div>
href={ templ.URL(params.FileMetadata.URL) } }
target="_new"
class="not-prose mx-auto mb-3 block w-4/5 basis-full rounded-lg border-0 bg-strongpink px-4 py-2 text-center text-[17px] font-light text-white no-underline sm:w-2/6"
>Download file</a>
</article>
@detailsTemplate(params.DetailsParams)
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
</div>
@clientsTemplate(params.Clients)
</div>
</div>
@footerTemplate()
</body>
</html>
} }

View File

@@ -1,70 +0,0 @@
package main
templ headCommonTemplate(params HeadParams) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
if params.Oembed != "" {
<link
rel="alternate"
type="application/json+oembed"
href={ params.Oembed + "&format=json" }
/>
<link rel="alternate" type="text/xml+oembed" href={ params.Oembed + "&format=xml" }/>
}
if params.IsProfile {
<link
rel="apple-touch-icon"
sizes="180x180"
href="/njump/static/favicon/profile/apple-touch-icon.png?v=2"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/njump/static/favicon/profile/favicon-32x32.png?v=2"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/njump/static/favicon/profile/favicon-16x16.png?v=2"
/>
} else {
<link
rel="apple-touch-icon"
sizes="180x180"
href="/njump/static/favicon/event/apple-touch-icon.png?v=2"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/njump/static/favicon/event/favicon-32x32.png?v=2"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/njump/static/favicon/event/favicon-16x16.png?v=2"
/>
}
<script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
if tailwindDebugStuff != "" {
@templ.Raw(tailwindDebugStuff)
} else {
<link
rel="stylesheet"
type="text/css"
href="/njump/static/tailwind-bundle.min.css"
/>
}
<style> @media print { @page { margin: 2cm 3cm; } } </style>
<meta name="theme-color" content="#e42a6d"/>
if params.NaddrNaked != "" {
<link rel="canonical" href={ "https://njump.me/" + params.NaddrNaked }/>
} else {
<link rel="canonical" href={ "https://njump.me/" + params.NeventNaked }/>
}
<script type="text/hyperscript">
on load get [navigator.userAgent.includes('Safari'), navigator.userAgent.includes('Chrome')] then if it[0] is true and it[1] is false add .safari to <body /> end
</script>
}

View File

@@ -2,75 +2,49 @@ package main
templ liveEventTemplate(params LiveEventPageParams) { templ liveEventTemplate(params LiveEventPageParams) {
<!DOCTYPE html> <!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl"> @eventPageTemplate(
<meta charset="UTF-8"/> params.LiveEvent.title(),
<head> params.OpenGraphParams,
<title>Stream: { params.LiveEvent.Title } by { params.LiveEvent.Host.Name }</title> params.HeadParams,
@openGraphTemplate(params.OpenGraphParams) params.Metadata,
@headCommonTemplate(params.HeadParams) params.Clients,
</head> params.Details,
<body class="mb-16 bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black"> params.Event,
@topTemplate() ) {
<div class="mx-auto px-4 sm:flex sm:items-center sm:justify-center sm:px-0"> <h1 class="text-2xl">
<div class="w-full max-w-screen-2xl justify-between gap-10 overflow-visible print:w-full sm:flex sm:w-11/12 sm:px-4 md:w-10/12 lg:w-9/12 lg:gap-48vw"> <span class="mr-2">{ params.LiveEvent.Title }</span>
<div class="w-full break-words print:w-full sm:w-3/4"> switch params.LiveEvent.Status {
@authorHeaderTemplate(params.Metadata) case "ended":
<div class="w-full text-right text-sm text-stone-400"> <span class="whitespace-nowrap rounded bg-neutral-400 px-4 py-1 align-text-top text-base text-white dark:bg-neutral-700">Ended</span>
{ params.CreatedAt } case "live":
</div> <span class="whitespace-nowrap rounded bg-strongpink px-4 py-1 align-text-top text-base text-white">Live now!</span>
<div class="w-full text-right text-sm text-stone-400"> }
if params.ParentLink != "" { </h1>
in reply to <div class="mb-4">
<span class="text-strongpink"> if params.LiveEvent.Host != nil {
@templ.Raw(params.ParentLink) Streaming hosted by
</span> <a href={ templ.URL("/" + params.LiveEvent.Host.Npub()) }>
} { params.LiveEvent.Host.Name }
</div> </a>
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div> }
<article class="prose-cite:text-sm prose mb-6 max-w-full leading-5 dark:prose-invert prose-headings:font-light prose-p:m-0 prose-p:mb-2 prose-blockquote:mx-0 prose-blockquote:my-8 prose-blockquote:border-l-05rem prose-blockquote:border-solid prose-blockquote:border-l-gray-100 prose-blockquote:py-2 prose-blockquote:pl-4 prose-blockquote:pr-0 prose-ol:m-0 prose-ol:p-0 prose-ol:pl-4 prose-ul:m-0 prose-ul:p-0 prose-ul:pl-4 prose-li:mb-2 dark:prose-blockquote:border-l-zinc-800 sm:prose-a:text-justify"> </div>
<h1 class="text-2xl"> <!-- main content -->
<span class="mr-2">{ params.LiveEvent.Title }</span> <div class="mb-4">
switch params.LiveEvent.Status { for _, v := range params.LiveEvent.Hashtags {
case "ended": <span class="mr-2 whitespace-nowrap rounded bg-neutral-200 px-2 dark:bg-neutral-700 dark:text-white">
<span class="whitespace-nowrap rounded bg-neutral-400 px-4 py-1 align-text-top text-base text-white dark:bg-neutral-700">Ended</span> { v }
case "live": </span>
<span class="whitespace-nowrap rounded bg-strongpink px-4 py-1 align-text-top text-base text-white">Live now!</span> }
} </div>
</h1> if params.LiveEvent.Summary != "" {
<div class="mb-4"> <div>{ params.LiveEvent.Summary }</div>
if params.LiveEvent.Host != nil { }
Streaming hosted by if params.LiveEvent.Image != "" {
<a href={ templ.URL("/" + params.LiveEvent.Host.Npub()) }> <img
{ params.LiveEvent.Host.Name } src={ params.LiveEvent.Image }
</a> alt={ params.Alt }
} _="on load repeat set @src to @src wait 5s end"
</div> />
<!-- main content --> }
<div class="mb-4"> }
for _, v := range params.LiveEvent.Hashtags {
<span class="mr-2 whitespace-nowrap rounded bg-neutral-200 px-2 dark:bg-neutral-700 dark:text-white">
{ v }
</span>
}
</div>
if params.LiveEvent.Summary != "" {
<div>{ params.LiveEvent.Summary }</div>
}
if params.LiveEvent.Image != "" {
<img
src={ params.LiveEvent.Image }
alt={ params.Alt }
_="on load repeat set @src to @src wait 5s end"
/>
}
</article>
@detailsTemplate(params.DetailsParams)
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
</div>
@clientsTemplate(params.Clients)
</div>
</div>
@footerTemplate()
</body>
</html>
} }

View File

@@ -2,51 +2,15 @@ package main
templ liveEventMessageTemplate(params LiveEventMessagePageParams) { templ liveEventMessageTemplate(params LiveEventMessagePageParams) {
<!DOCTYPE html> <!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl"> @eventPageTemplate(
<meta charset="UTF-8"/> params.TitleizedContent,
<head> params.OpenGraphParams,
<title>{ params.TitleizedContent }</title> params.HeadParams,
@openGraphTemplate(params.OpenGraphParams) params.Metadata,
@headCommonTemplate(params.HeadParams) params.Clients,
</head> params.Details,
<body class="mb-16 bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black"> params.Event,
@topTemplate() ) {
<div class="mx-auto px-4 sm:flex sm:items-center sm:justify-center sm:px-0"> @templ.Raw(params.Content)
<div class="w-full max-w-screen-2xl justify-between gap-10 overflow-visible print:w-full sm:flex sm:w-11/12 sm:px-4 md:w-10/12 lg:w-9/12 lg:gap-48vw"> }
<div class="w-full break-words print:w-full sm:w-3/4">
@authorHeaderTemplate(params.Metadata)
<div class="w-full text-right text-sm text-stone-400">
{ params.CreatedAt }
</div>
<div class="w-full text-right text-sm text-stone-400">
if params.ParentLink != "" {
messaging during the live event
<span class="text-strongpink">
@templ.Raw(params.ParentLink)
</span>
}
</div>
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
<article
class="prose-cite:text-sm prose mb-6 leading-5 dark:prose-invert prose-headings:font-light prose-p:m-0 prose-p:mb-2 prose-blockquote:mx-0 prose-blockquote:my-8 prose-blockquote:border-l-05rem prose-blockquote:border-solid prose-blockquote:border-l-gray-100 prose-blockquote:py-2 prose-blockquote:pl-4 prose-blockquote:pr-0 prose-ol:m-0 prose-ol:p-0 prose-ol:pl-4 prose-ul:m-0 prose-ul:p-0 prose-ul:pl-4 prose-li:mb-2 dark:prose-blockquote:border-l-zinc-800 sm:prose-a:text-justify"
>
if params.Subject != "" {
<h1 class="text-2xl">{ params.Subject }</h1>
} else {
<h1 class="hidden">
{ params.Metadata.ShortName() } on Nostr: { params.TitleizedContent }
</h1>
}
<!-- main content -->
@templ.Raw(params.Content)
</article>
@detailsTemplate(params.DetailsParams)
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
</div>
@clientsTemplate(params.Clients)
</div>
</div>
@footerTemplate()
</body>
</html>
} }

View File

@@ -52,7 +52,7 @@ var tgivmdrenderer = html.NewRenderer(html.RendererOptions{
func mdToHTML(md string, usingTelegramInstantView bool, skipLinks bool) string { func mdToHTML(md string, usingTelegramInstantView bool, skipLinks bool) string {
md = strings.ReplaceAll(md, "\u00A0", " ") md = strings.ReplaceAll(md, "\u00A0", " ")
md = replaceNostrURLsWithTags(nostrEveryMatcher, md) md = replaceNostrURLsWithHTMLTags(nostrEveryMatcher, md)
// create markdown parser with extensions // create markdown parser with extensions
// this parser is stateful so it must be reinitialized every time // this parser is stateful so it must be reinitialized every time

View File

@@ -2,51 +2,25 @@ package main
templ noteTemplate(params NotePageParams) { templ noteTemplate(params NotePageParams) {
<!DOCTYPE html> <!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl"> @eventPageTemplate(
<meta charset="UTF-8"/> params.TitleizedContent,
<head> params.OpenGraphParams,
<title>{ params.TitleizedContent }</title> params.HeadParams,
@openGraphTemplate(params.OpenGraphParams) params.Metadata,
@headCommonTemplate(params.HeadParams) params.Clients,
</head> params.Details,
<body class="mb-16 bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black"> params.Event,
@topTemplate() ) {
<div class="mx-auto px-4 sm:flex sm:items-center sm:justify-center sm:px-0"> if params.Subject != "" {
<div class="w-full max-w-screen-2xl justify-between gap-10 overflow-visible print:w-full sm:flex sm:w-11/12 sm:px-4 md:w-10/12 lg:w-9/12 lg:gap-48vw"> <h1 class="text-2xl">{ params.Subject }</h1>
<div class="w-full break-words print:w-full sm:w-3/4"> } else {
@authorHeaderTemplate(params.Metadata) <h1 class="hidden">
<div class="w-full text-right text-sm text-stone-400"> { params.Metadata.ShortName() } on Nostr: { params.TitleizedContent }
{ params.CreatedAt } </h1>
</div> }
<div class="w-full text-right text-sm text-stone-400"> <!-- main content -->
if params.ParentLink != "" { <div dir="auto">
in reply to @templ.Raw(params.Content)
<span class="text-strongpink"> </div>
@templ.Raw(params.ParentLink) }
</span>
}
</div>
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
<article class="prose-cite:text-sm prose mb-6 leading-5 dark:prose-invert prose-headings:font-light prose-p:m-0 prose-p:mb-2 prose-blockquote:mx-0 prose-blockquote:my-8 prose-blockquote:mb-2 prose-blockquote:mt-2 prose-blockquote:border-l-05rem prose-blockquote:border-solid prose-blockquote:border-l-neutral-200 prose-blockquote:py-2 prose-blockquote:pl-4 prose-blockquote:pr-0 prose-blockquote:pt-0 prose-blockquote:font-light prose-blockquote:not-italic prose-ol:m-0 prose-ol:p-0 prose-ol:pl-4 prose-ul:m-0 prose-ul:p-0 prose-ul:pl-4 prose-li:mb-2 dark:prose-blockquote:border-l-neutral-700 sm:prose-a:text-justify">
if params.Subject != "" {
<h1 class="text-2xl">{ params.Subject }</h1>
} else {
<h1 class="hidden">
{ params.Metadata.ShortName() } on Nostr: { params.TitleizedContent }
</h1>
}
<!-- main content -->
<div dir="auto">
@templ.Raw(params.Content)
</div>
</article>
@detailsTemplate(params.DetailsParams)
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
</div>
@clientsTemplate(params.Clients)
</div>
</div>
@footerTemplate()
</body>
</html>
} }

View File

@@ -26,7 +26,7 @@ templ otherTemplate(params OtherPageParams) {
{ params.Alt } { params.Alt }
</article> </article>
} }
@detailsTemplate(params .DetailsParams) @detailsTemplate(params.Details)
<div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div> <div class="-ml-4 mb-6 h-1.5 w-1/3 bg-zinc-100 dark:bg-zinc-700 sm:-ml-2.5"></div>
</div> </div>
</div> </div>

196
pages.go
View File

@@ -7,6 +7,7 @@ import (
"html/template" "html/template"
"strings" "strings"
"github.com/a-h/templ"
"github.com/nbd-wtf/go-nostr/nip11" "github.com/nbd-wtf/go-nostr/nip11"
) )
@@ -20,6 +21,7 @@ const (
FileMetadata FileMetadata
LiveEvent LiveEvent
LiveEventMessage LiveEventMessage
CalendarEvent
Other Other
) )
@@ -51,10 +53,7 @@ type DetailsParams struct {
Kind int Kind int
KindNIP string KindNIP string
KindDescription string KindDescription string
Extra templ.Component
// kind-specific stuff
FileMetadata *Kind1063Metadata
LiveEvent *Kind30311Metadata
} }
type HeadParams struct { type HeadParams struct {
@@ -65,17 +64,17 @@ type HeadParams struct {
} }
type TelegramInstantViewParams struct { type TelegramInstantViewParams struct {
Video string Video string
VideoType string VideoType string
Image string Image string
Summary template.HTML Summary template.HTML
Content template.HTML Content template.HTML
Description string Description string
Subject string Subject string
Metadata Metadata Metadata Metadata
AuthorLong string AuthorLong string
CreatedAt string CreatedAt string
ParentLink template.HTML ParentNevent string
} }
type HomePageParams struct { type HomePageParams struct {
@@ -97,30 +96,6 @@ type ArchivePageParams struct {
PrevPage int PrevPage int
} }
type OtherPageParams struct {
HeadParams
DetailsParams
Kind int
KindDescription string
Alt string
}
type NotePageParams struct {
OpenGraphParams
HeadParams
DetailsParams
Content template.HTML
CreatedAt string
Metadata Metadata
ParentLink template.HTML
SeenOn []string
Subject string
TitleizedContent string
Clients []ClientReference
}
type EmbeddedNoteParams struct { type EmbeddedNoteParams struct {
Content template.HTML Content template.HTML
CreatedAt string CreatedAt string
@@ -132,8 +107,8 @@ type EmbeddedNoteParams struct {
type ProfilePageParams struct { type ProfilePageParams struct {
HeadParams HeadParams
DetailsParams
Details DetailsParams
AuthorRelays []string AuthorRelays []string
Content string Content string
CreatedAt string CreatedAt string
@@ -144,7 +119,6 @@ type ProfilePageParams struct {
RenderedAuthorAboutText template.HTML RenderedAuthorAboutText template.HTML
Nevent string Nevent string
Nprofile string Nprofile string
IsReply string
Proxy string Proxy string
Title string Title string
Clients []ClientReference Clients []ClientReference
@@ -164,66 +138,6 @@ type EmbeddedProfileParams struct {
Title string Title string
} }
type FileMetadataPageParams struct {
OpenGraphParams
HeadParams
DetailsParams
Content template.HTML
CreatedAt string
Metadata Metadata
ParentLink template.HTML
SeenOn []string
Style Style
Subject string
TitleizedContent string
Alt string
FileMetadata Kind1063Metadata
IsImage bool
IsVideo bool
Clients []ClientReference
}
type LiveEventPageParams struct {
OpenGraphParams
HeadParams
DetailsParams
Content template.HTML
CreatedAt string
Metadata Metadata
ParentLink template.HTML
SeenOn []string
Style Style
Subject string
TitleizedContent string
Alt string
LiveEvent Kind30311Metadata
Clients []ClientReference
}
type LiveEventMessagePageParams struct {
OpenGraphParams
HeadParams
DetailsParams
Content template.HTML
CreatedAt string
Metadata Metadata
ParentLink template.HTML
SeenOn []string
Style Style
Subject string
TitleizedContent string
Alt string
Clients []ClientReference
}
type RelayPageParams struct { type RelayPageParams struct {
HeadParams HeadParams
@@ -259,3 +173,83 @@ func (e *ErrorPageParams) MessageHTML() template.HTML {
return "I can't give any suggestions to solve the problem.<br> Please tag <a href='/dtonon.com'>daniele</a> and <a href='/fiatjaf.com'>fiatjaf</a> and complain!" return "I can't give any suggestions to solve the problem.<br> Please tag <a href='/dtonon.com'>daniele</a> and <a href='/fiatjaf.com'>fiatjaf</a> and complain!"
} }
} }
type BaseEventPageParams struct {
Event EnhancedEvent
Metadata Metadata
Style Style
Alt string
}
type NotePageParams struct {
BaseEventPageParams
OpenGraphParams
HeadParams
Details DetailsParams
Content template.HTML
Subject string
TitleizedContent string
Clients []ClientReference
}
type FileMetadataPageParams struct {
BaseEventPageParams
OpenGraphParams
HeadParams
Details DetailsParams
Content template.HTML
FileMetadata Kind1063Metadata
IsImage bool
IsVideo bool
Clients []ClientReference
}
type LiveEventPageParams struct {
BaseEventPageParams
OpenGraphParams
HeadParams
Details DetailsParams
Content template.HTML
LiveEvent Kind30311Metadata
Clients []ClientReference
}
type LiveEventMessagePageParams struct {
BaseEventPageParams
OpenGraphParams
HeadParams
Details DetailsParams
Content template.HTML
TitleizedContent string
Clients []ClientReference
}
type CalendarPageParams struct {
BaseEventPageParams
OpenGraphParams
HeadParams
Details DetailsParams
Content template.HTML
CalendarEvent Kind31922Or31923Metadata
Clients []ClientReference
}
type OtherPageParams struct {
BaseEventPageParams
HeadParams
Details DetailsParams
Kind int
KindDescription string
}

View File

@@ -127,7 +127,7 @@ templ profileTemplate(params ProfilePageParams) {
} }
</div> </div>
} }
@detailsTemplate(params.DetailsParams) @detailsTemplate(params.Details)
<div <div
_={ "init fetch '?just-last-notes=true' then put the result into me end" } _={ "init fetch '?just-last-notes=true' then put the result into me end" }
> >

View File

@@ -114,7 +114,7 @@ templ relayTemplate(params RelayPageParams) {
{ ee.CreatedAtStr() } { ee.CreatedAtStr() }
</div> </div>
<br/> <br/>
if ee.IsReply() { if ee.isReply() {
<div class="ml-2 text-xs text-gray-300 dark:text-gray-400"> <div class="ml-2 text-xs text-gray-300 dark:text-gray-400">
- reply - reply
</div> </div>

View File

@@ -160,7 +160,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
subscript += " (" + subject + ")" subscript += " (" + subject + ")"
} }
subscript += " by " + data.metadata.ShortName() subscript += " by " + data.metadata.ShortName()
if data.event.IsReply() { if data.event.isReply() {
subscript += " (reply)" subscript += " (reply)"
} }
@@ -290,10 +290,6 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
Kind: data.event.Kind, Kind: data.event.Kind,
SeenOn: data.event.relays, SeenOn: data.event.relays,
Metadata: data.metadata, Metadata: data.metadata,
// kind-specific stuff
FileMetadata: data.kind1063Metadata,
LiveEvent: data.kind30311Metadata,
} }
opengraph := OpenGraphParams{ opengraph := OpenGraphParams{
@@ -309,21 +305,27 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
} }
var component templ.Component var component templ.Component
baseEventPageParams := BaseEventPageParams{
Event: data.event,
Metadata: data.metadata,
Style: style,
Alt: data.alt,
}
switch data.templateId { switch data.templateId {
case TelegramInstantView: case TelegramInstantView:
component = telegramInstantViewTemplate(TelegramInstantViewParams{ component = telegramInstantViewTemplate(TelegramInstantViewParams{
Video: data.video, Video: data.video,
VideoType: data.videoType, VideoType: data.videoType,
Image: data.image, Image: data.image,
Summary: template.HTML(summary), Summary: template.HTML(summary),
Content: template.HTML(data.content), Content: template.HTML(data.content),
Description: description, Description: description,
Subject: subject, Subject: subject,
Metadata: data.metadata, Metadata: data.metadata,
AuthorLong: data.authorLong, AuthorLong: data.authorLong,
CreatedAt: data.createdAt, CreatedAt: data.createdAt,
ParentLink: data.parentLink, ParentNevent: data.event.getParentNevent(),
}) })
case Note: case Note:
if style == StyleTwitter { if style == StyleTwitter {
@@ -346,64 +348,55 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
} }
component = noteTemplate(NotePageParams{ component = noteTemplate(NotePageParams{
OpenGraphParams: opengraph, BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{ HeadParams: HeadParams{
IsProfile: false, IsProfile: false,
Oembed: oembed, Oembed: oembed,
NaddrNaked: data.naddrNaked, NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked, NeventNaked: data.neventNaked,
}, },
DetailsParams: detailsData,
Clients: generateClientList(data.event.Kind, enhancedCode),
Details: detailsData,
Content: template.HTML(data.content), Content: template.HTML(data.content),
CreatedAt: data.createdAt,
Metadata: data.metadata,
ParentLink: data.parentLink,
Subject: subject, Subject: subject,
TitleizedContent: titleizedContent, TitleizedContent: titleizedContent,
Clients: generateClientList(data.event.Kind, enhancedCode),
}) })
case FileMetadata: case FileMetadata:
opengraph.Image = data.kind1063Metadata.DisplayImage() opengraph.Image = data.kind1063Metadata.DisplayImage()
params := FileMetadataPageParams{
component = fileMetadataTemplate(FileMetadataPageParams{ BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph, OpenGraphParams: opengraph,
HeadParams: HeadParams{ HeadParams: HeadParams{
IsProfile: false, IsProfile: false,
NaddrNaked: data.naddrNaked, NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked, NeventNaked: data.neventNaked,
}, },
DetailsParams: detailsData,
CreatedAt: data.createdAt, Details: detailsData,
Metadata: data.metadata, Clients: generateClientList(data.event.Kind, data.nevent),
Style: style,
Subject: subject,
TitleizedContent: titleizedContent,
Alt: data.alt,
Clients: generateClientList(data.event.Kind, data.nevent),
FileMetadata: *data.kind1063Metadata, FileMetadata: *data.kind1063Metadata,
IsImage: data.kind1063Metadata.IsImage(), IsImage: data.kind1063Metadata.IsImage(),
IsVideo: data.kind1063Metadata.IsVideo(), IsVideo: data.kind1063Metadata.IsVideo(),
}) }
params.Details.Extra = fileMetadataDetails(params)
component = fileMetadataTemplate(params)
case LiveEvent: case LiveEvent:
opengraph.Image = data.kind30311Metadata.Image opengraph.Image = data.kind30311Metadata.Image
component = liveEventTemplate(LiveEventPageParams{ component = liveEventTemplate(LiveEventPageParams{
OpenGraphParams: opengraph, BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{ HeadParams: HeadParams{
IsProfile: false, IsProfile: false,
NaddrNaked: data.naddrNaked, NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked, NeventNaked: data.neventNaked,
}, },
DetailsParams: detailsData,
CreatedAt: data.createdAt, Details: detailsData,
Metadata: data.metadata, LiveEvent: *data.kind30311Metadata,
Style: style,
Subject: subject,
TitleizedContent: titleizedContent,
Alt: data.alt,
Clients: generateClientList(data.event.Kind, data.naddr, Clients: generateClientList(data.event.Kind, data.naddr,
func(s string) string { func(s string) string {
if strings.Contains(s, "nostrudel") { if strings.Contains(s, "nostrudel") {
@@ -412,42 +405,51 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
return s return s
}, },
), ),
LiveEvent: *data.kind30311Metadata,
}) })
case LiveEventMessage: case LiveEventMessage:
// opengraph.Image = data.kind1311Metadata.Image
component = liveEventMessageTemplate(LiveEventMessagePageParams{ component = liveEventMessageTemplate(LiveEventMessagePageParams{
OpenGraphParams: opengraph, BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{ HeadParams: HeadParams{
IsProfile: false, IsProfile: false,
NaddrNaked: data.naddrNaked, NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked, NeventNaked: data.neventNaked,
}, },
DetailsParams: detailsData,
Details: detailsData,
Content: template.HTML(data.content), Content: template.HTML(data.content),
CreatedAt: data.createdAt,
Metadata: data.metadata,
ParentLink: data.parentLink,
Style: style,
Subject: subject,
TitleizedContent: titleizedContent, TitleizedContent: titleizedContent,
Alt: data.alt,
Clients: generateClientList(data.event.Kind, data.naddr), Clients: generateClientList(data.event.Kind, data.naddr),
}) })
case CalendarEvent:
if data.kind31922Or31923Metadata.Image != "" {
opengraph.Image = data.kind31922Or31923Metadata.Image
}
component = calendarEventTemplate(CalendarPageParams{
BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{
IsProfile: false,
NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked,
},
Details: detailsData,
Content: template.HTML(data.content),
Clients: generateClientList(data.event.Kind, data.naddr),
})
case Other: case Other:
detailsData.HideDetails = false // always open this since we know nothing else about the event detailsData.HideDetails = false // always open this since we know nothing else about the event
component = otherTemplate(OtherPageParams{ component = otherTemplate(OtherPageParams{
BaseEventPageParams: baseEventPageParams,
HeadParams: HeadParams{ HeadParams: HeadParams{
IsProfile: false, IsProfile: false,
NaddrNaked: data.naddrNaked, NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked, NeventNaked: data.neventNaked,
}, },
DetailsParams: detailsData,
Alt: data.alt, Details: detailsData,
Kind: data.event.Kind, Kind: data.event.Kind,
KindDescription: data.kindDescription, KindDescription: data.kindDescription,
}) })

View File

@@ -66,7 +66,7 @@ func renderProfile(w http.ResponseWriter, r *http.Request, code string) {
w.Header().Set("Cache-Control", "max-age=86400") w.Header().Set("Cache-Control", "max-age=86400")
err = profileTemplate(ProfilePageParams{ err = profileTemplate(ProfilePageParams{
HeadParams: HeadParams{IsProfile: true}, HeadParams: HeadParams{IsProfile: true},
DetailsParams: DetailsParams{ Details: DetailsParams{
HideDetails: true, HideDetails: true,
CreatedAt: data.createdAt, CreatedAt: data.createdAt,
KindDescription: data.kindDescription, KindDescription: data.kindDescription,

View File

@@ -33,16 +33,16 @@ templ telegramInstantViewTemplate(params TelegramInstantViewParams) {
<a href={ templ.URL("/" + params.Metadata.Npub()) }> <a href={ templ.URL("/" + params.Metadata.Npub()) }>
{ params.Metadata.ShortName() } { params.Metadata.ShortName() }
</a> on Nostr </a> on Nostr
if params.ParentLink != "" { if params.ParentNevent != "" {
(reply) (reply)
} }
: :
} }
</h1> </h1>
if params.ParentLink != "" { if params.ParentNevent != "" {
<aside> <aside>
in reply to{ " " } in reply to{ " " }
@templ.Raw(params.ParentLink) @templ.Raw(replaceNostrURLsWithHTMLTags(nostrNoteNeventMatcher, "nostr:" + params.ParentNevent))
</aside> </aside>
} }
<!----> <!---->

View File

@@ -7,6 +7,7 @@ import (
"html" "html"
"html/template" "html/template"
"regexp" "regexp"
"strconv"
"strings" "strings"
"time" "time"
@@ -39,12 +40,36 @@ type EnhancedEvent struct {
relays []string relays []string
} }
func (ee EnhancedEvent) IsReply() bool { func (ee EnhancedEvent) getParentNevent() string {
return nip10.GetImmediateReply(ee.Event.Tags) != nil parentNevent := ""
switch ee.Kind {
case 1, 1063:
replyTag := nip10.GetImmediateReply(ee.Tags)
if replyTag != nil {
var relays []string
if (len(*replyTag) > 2) && ((*replyTag)[2] != "") {
relays = []string{(*replyTag)[2]}
}
parentNevent, _ = nip19.EncodeEvent((*replyTag)[1], relays, "")
}
case 1311:
if atag := ee.Tags.GetFirst([]string{"a", ""}); atag != nil {
parts := strings.Split((*atag)[1], ":")
kind, _ := strconv.Atoi(parts[0])
var relays []string
if (len(*atag) > 2) && ((*atag)[2] != "") {
relays = []string{(*atag)[2]}
}
parentNevent, _ = nip19.EncodeEntity(parts[1], kind, parts[2], relays)
}
}
return parentNevent
} }
func (ee EnhancedEvent) Reply() *nostr.Tag { func (ee EnhancedEvent) isReply() bool {
return nip10.GetImmediateReply(ee.Event.Tags) return nip10.GetImmediateReply(ee.Event.Tags) != nil
} }
func (ee EnhancedEvent) Preview() template.HTML { func (ee EnhancedEvent) Preview() template.HTML {
@@ -96,8 +121,7 @@ func (ee EnhancedEvent) RssContent() string {
content := ee.Event.Content content := ee.Event.Content
content = basicFormatting(html.EscapeString(content), true, false, false) content = basicFormatting(html.EscapeString(content), true, false, false)
content = renderQuotesAsHTML(context.Background(), content, false) content = renderQuotesAsHTML(context.Background(), content, false)
if ee.IsReply() { if nevent := ee.getParentNevent(); nevent != "" {
nevent, _ := nip19.EncodeEvent(ee.Reply().Value(), ee.relays, ee.Event.PubKey)
neventShort := nevent[:8] + "…" + nevent[len(nevent)-4:] neventShort := nevent[:8] + "…" + nevent[len(nevent)-4:]
content = "In reply to <a href='/" + nevent + "'>" + neventShort + "</a><br/>_________________________<br/><br/>" + content content = "In reply to <a href='/" + nevent + "'>" + neventShort + "</a><br/>_________________________<br/><br/>" + content
} }
@@ -189,6 +213,13 @@ type Kind30311Metadata struct {
Host *sdk.ProfileMetadata Host *sdk.ProfileMetadata
} }
func (le Kind30311Metadata) title() string {
if le.Host != nil {
return le.Title + " by " + le.Host.Name
}
return le.Title
}
type Kind31922Or31923Metadata struct { type Kind31922Or31923Metadata struct {
nip52.CalendarEvent nip52.CalendarEvent
} }

View File

@@ -15,8 +15,6 @@ import (
"mvdan.cc/xurls/v2" "mvdan.cc/xurls/v2"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip10"
"github.com/nbd-wtf/go-nostr/nip19"
sdk "github.com/nbd-wtf/nostr-sdk" sdk "github.com/nbd-wtf/nostr-sdk"
) )
@@ -172,19 +170,6 @@ func getPreviewStyle(r *http.Request) Style {
} }
} }
func getParentNevent(event *nostr.Event) string {
parentNevent := ""
replyTag := nip10.GetImmediateReply(event.Tags)
if replyTag != nil {
var relays []string
if (len(*replyTag) > 2) && ((*replyTag)[2] != "") {
relays = []string{(*replyTag)[2]}
}
parentNevent, _ = nip19.EncodeEvent((*replyTag)[1], relays, "")
}
return parentNevent
}
func attachRelaysToEvent(eventId string, relays ...string) []string { func attachRelaysToEvent(eventId string, relays ...string) []string {
key := "rls:" + eventId key := "rls:" + eventId
existingRelays := make([]string, 0, 10) existingRelays := make([]string, 0, 10)
@@ -250,7 +235,7 @@ func replaceURLsWithTags(input string, imageReplacementTemplate, videoReplacemen
}) })
} }
func replaceNostrURLsWithTags(matcher *regexp.Regexp, input string) string { func replaceNostrURLsWithHTMLTags(matcher *regexp.Regexp, input string) string {
// match and replace npup1, nprofile1, note1, nevent1, etc // match and replace npup1, nprofile1, note1, nevent1, etc
return matcher.ReplaceAllStringFunc(input, func(match string) string { return matcher.ReplaceAllStringFunc(input, func(match string) string {
nip19 := match[len("nostr:"):] nip19 := match[len("nostr:"):]
@@ -377,7 +362,7 @@ func basicFormatting(input string, skipNostrEventLinks bool, usingTelegramInstan
lines := strings.Split(input, "\n") lines := strings.Split(input, "\n")
for i, line := range lines { for i, line := range lines {
line = replaceURLsWithTags(line, imageReplacementTemplate, videoReplacementTemplate, skipLinks) line = replaceURLsWithTags(line, imageReplacementTemplate, videoReplacementTemplate, skipLinks)
line = replaceNostrURLsWithTags(nostrMatcher, line) line = replaceNostrURLsWithHTMLTags(nostrMatcher, line)
lines[i] = line lines[i] = line
} }
return strings.Join(lines, "<br/>") return strings.Join(lines, "<br/>")