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"}
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"}
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,
amethyst,
}
case 31922, 31923:
clients = []ClientReference{
native,
flockstr, nostrudel,
amethyst,
}
default:
clients = []ClientReference{
native,

View File

@@ -1,5 +1,38 @@
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) {
<header class="mb-4 max-w-full">
<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="leading-4 sm:text-2xl">
{ metadata.Name }
<!---->
if metadata.Name != metadata.DisplayName {
<span class="text-stone-400 sm:text-xl">/ { metadata.DisplayName } </span>
}
@@ -24,29 +56,18 @@ templ authorHeaderTemplate(metadata Metadata) {
templ lastNotesTemplate(lastNotes []EnhancedEvent) {
<aside>
<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>
<nav class="mb-6 leading-5">
<h2 class="text-2xl text-strongpink">Last Notes</h2>
for _, ee := range lastNotes {
<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()) }
>
<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"
>
<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()) }>
<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>
if ee.IsReply() {
if ee.isReply() {
<div class="ml-2 text-sm text-gray-300 dark:text-gray-400">- reply</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"
>
<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">
@templ.Raw(ee.Preview())
</div>
</a>

14
data.go
View File

@@ -4,12 +4,12 @@ import (
"context"
"fmt"
"html/template"
"strconv"
"strings"
"time"
"github.com/nbd-wtf/go-nostr/nip19"
"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/nip94"
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:
data.templateId = Note
data.content = event.Content
if parentNevent := getParentNevent(event); parentNevent != "" {
data.parentLink = template.HTML(replaceNostrURLsWithTags(nostrNoteNeventMatcher, "nostr:"+parentNevent))
}
case 6:
data.templateId = Note
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:
data.templateId = LiveEventMessage
data.content = event.Content
if atag := event.Tags.GetFirst([]string{"a", ""}); atag != nil {
parts := strings.Split((*atag)[1], ":")
kind, _ := strconv.Atoi(parts[0])
parentNevent, _ := nip19.EncodeEntity(parts[1], kind, parts[2], data.event.relays)
data.parentLink = template.HTML(replaceNostrURLsWithTags(nostrEveryMatcher, "nostr:"+parentNevent))
}
case 31922, 31923:
data.templateId = CalendarEvent
data.kind31922Or31923Metadata = &Kind31922Or31923Metadata{CalendarEvent: nip52.ParseCalendarEvent(*event)}
default:
data.templateId = Other
}

View File

@@ -4,44 +4,22 @@ import (
"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>
if params.Metadata.Npub() != "" {
if details.Metadata.Npub() != "" {
<div class="mb-6 break-all leading-5">
<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>
}
if params.FileMetadata != nil {
if params.FileMetadata.Summary != "" {
<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 details.Extra != nil {
@details.Extra
}
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="text-sm text-strongpink">Seen on</div>
for _, v := range params.SeenOn {
for _, v := range details.SeenOn {
<a
href={ templ.URL("/r/" + v) }
class="underline-none pr-2 decoration-neutral-200 decoration-1 underline-offset-[6px] hover:underline"
@@ -50,7 +28,7 @@ templ detailsTemplate(params DetailsParams) {
</div>
}
<!-- details hidden behind a toggle -->
if params.HideDetails {
if details.HideDetails {
<div class="mb-6 flex items-center print:hidden">
<input
type="checkbox"
@@ -81,25 +59,25 @@ templ detailsTemplate(params DetailsParams) {
>Show more details</label>
</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="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 class="mb-6 leading-5">
<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>
if params.KindNIP != "" {
<span class="text-neutral-500 dark:text-neutral-300 text-[16px]">{ strconv.Itoa(details.Kind) }</span>
if details.KindNIP != "" {
<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]"
>{ params.KindDescription }</a>
>{ details.KindDescription }</a>
}
</div>
if params.Nevent != "" {
if details.Nevent != "" {
<div class="mb-6 leading-5">
<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 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
</div>
<div class="mt-4 whitespace-pre-wrap break-all font-mono text-sm">
@templ.Raw(params.EventJSON)
@templ.Raw(details.EventJSON)
</div>
</div>
if params.Nprofile != "" {
if details.Nprofile != "" {
<div class="mb-6 break-all leading-5">
<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>

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,46 +2,15 @@ package main
templ fileMetadataTemplate(params FileMetadataPageParams) {
<!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
<meta charset="UTF-8"/>
<head>
<title>File Metadata</title>
@openGraphTemplate(params.OpenGraphParams)
@headCommonTemplate(params.HeadParams)
</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(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 != "" {
in reply to
<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 -->
@eventPageTemplate(
"File Metadata",
params.OpenGraphParams,
params.HeadParams,
params.Metadata,
params.Clients,
params.Details,
params.Event,
) {
if params.FileMetadata.Image != "" {
<img src={ params.FileMetadata.Image } alt={ params.Alt }/>
} else if params.IsImage {
@@ -60,14 +29,32 @@ templ fileMetadataTemplate(params FileMetadataPageParams) {
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>
}
}
templ fileMetadataDetails(params FileMetadataPageParams) {
if params.FileMetadata.Summary != "" {
<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>
}
}

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,32 +2,15 @@ package main
templ liveEventTemplate(params LiveEventPageParams) {
<!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
<meta charset="UTF-8"/>
<head>
<title>Stream: { params.LiveEvent.Title } by { params.LiveEvent.Host.Name }</title>
@openGraphTemplate(params.OpenGraphParams)
@headCommonTemplate(params.HeadParams)
</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(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 != "" {
in reply to
<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 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">
@eventPageTemplate(
params.LiveEvent.title(),
params.OpenGraphParams,
params.HeadParams,
params.Metadata,
params.Clients,
params.Details,
params.Event,
) {
<h1 class="text-2xl">
<span class="mr-2">{ params.LiveEvent.Title }</span>
switch params.LiveEvent.Status {
@@ -63,14 +46,5 @@ templ liveEventTemplate(params LiveEventPageParams) {
_="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) {
<!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
<meta charset="UTF-8"/>
<head>
<title>{ params.TitleizedContent }</title>
@openGraphTemplate(params.OpenGraphParams)
@headCommonTemplate(params.HeadParams)
</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(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 -->
@eventPageTemplate(
params.TitleizedContent,
params.OpenGraphParams,
params.HeadParams,
params.Metadata,
params.Clients,
params.Details,
params.Event,
) {
@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 {
md = strings.ReplaceAll(md, "\u00A0", " ")
md = replaceNostrURLsWithTags(nostrEveryMatcher, md)
md = replaceNostrURLsWithHTMLTags(nostrEveryMatcher, md)
// create markdown parser with extensions
// this parser is stateful so it must be reinitialized every time

View File

@@ -2,32 +2,15 @@ package main
templ noteTemplate(params NotePageParams) {
<!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
<meta charset="UTF-8"/>
<head>
<title>{ params.TitleizedContent }</title>
@openGraphTemplate(params.OpenGraphParams)
@headCommonTemplate(params.HeadParams)
</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(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 != "" {
in reply to
<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: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">
@eventPageTemplate(
params.TitleizedContent,
params.OpenGraphParams,
params.HeadParams,
params.Metadata,
params.Clients,
params.Details,
params.Event,
) {
if params.Subject != "" {
<h1 class="text-2xl">{ params.Subject }</h1>
} else {
@@ -39,14 +22,5 @@ templ noteTemplate(params NotePageParams) {
<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 }
</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>
</div>

176
pages.go
View File

@@ -7,6 +7,7 @@ import (
"html/template"
"strings"
"github.com/a-h/templ"
"github.com/nbd-wtf/go-nostr/nip11"
)
@@ -20,6 +21,7 @@ const (
FileMetadata
LiveEvent
LiveEventMessage
CalendarEvent
Other
)
@@ -51,10 +53,7 @@ type DetailsParams struct {
Kind int
KindNIP string
KindDescription string
// kind-specific stuff
FileMetadata *Kind1063Metadata
LiveEvent *Kind30311Metadata
Extra templ.Component
}
type HeadParams struct {
@@ -75,7 +74,7 @@ type TelegramInstantViewParams struct {
Metadata Metadata
AuthorLong string
CreatedAt string
ParentLink template.HTML
ParentNevent string
}
type HomePageParams struct {
@@ -97,30 +96,6 @@ type ArchivePageParams struct {
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 {
Content template.HTML
CreatedAt string
@@ -132,8 +107,8 @@ type EmbeddedNoteParams struct {
type ProfilePageParams struct {
HeadParams
DetailsParams
Details DetailsParams
AuthorRelays []string
Content string
CreatedAt string
@@ -144,7 +119,6 @@ type ProfilePageParams struct {
RenderedAuthorAboutText template.HTML
Nevent string
Nprofile string
IsReply string
Proxy string
Title string
Clients []ClientReference
@@ -164,66 +138,6 @@ type EmbeddedProfileParams struct {
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 {
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!"
}
}
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>
}
@detailsTemplate(params.DetailsParams)
@detailsTemplate(params.Details)
<div
_={ "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() }
</div>
<br/>
if ee.IsReply() {
if ee.isReply() {
<div class="ml-2 text-xs text-gray-300 dark:text-gray-400">
- reply
</div>

View File

@@ -160,7 +160,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
subscript += " (" + subject + ")"
}
subscript += " by " + data.metadata.ShortName()
if data.event.IsReply() {
if data.event.isReply() {
subscript += " (reply)"
}
@@ -290,10 +290,6 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
Kind: data.event.Kind,
SeenOn: data.event.relays,
Metadata: data.metadata,
// kind-specific stuff
FileMetadata: data.kind1063Metadata,
LiveEvent: data.kind30311Metadata,
}
opengraph := OpenGraphParams{
@@ -309,6 +305,12 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
}
var component templ.Component
baseEventPageParams := BaseEventPageParams{
Event: data.event,
Metadata: data.metadata,
Style: style,
Alt: data.alt,
}
switch data.templateId {
case TelegramInstantView:
@@ -323,7 +325,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
Metadata: data.metadata,
AuthorLong: data.authorLong,
CreatedAt: data.createdAt,
ParentLink: data.parentLink,
ParentNevent: data.event.getParentNevent(),
})
case Note:
if style == StyleTwitter {
@@ -346,6 +348,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
}
component = noteTemplate(NotePageParams{
BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{
IsProfile: false,
@@ -353,57 +356,47 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked,
},
DetailsParams: detailsData,
Clients: generateClientList(data.event.Kind, enhancedCode),
Details: detailsData,
Content: template.HTML(data.content),
CreatedAt: data.createdAt,
Metadata: data.metadata,
ParentLink: data.parentLink,
Subject: subject,
TitleizedContent: titleizedContent,
Clients: generateClientList(data.event.Kind, enhancedCode),
})
case FileMetadata:
opengraph.Image = data.kind1063Metadata.DisplayImage()
component = fileMetadataTemplate(FileMetadataPageParams{
params := FileMetadataPageParams{
BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{
IsProfile: false,
NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked,
},
DetailsParams: detailsData,
CreatedAt: data.createdAt,
Metadata: data.metadata,
Style: style,
Subject: subject,
TitleizedContent: titleizedContent,
Alt: data.alt,
Details: detailsData,
Clients: generateClientList(data.event.Kind, data.nevent),
FileMetadata: *data.kind1063Metadata,
IsImage: data.kind1063Metadata.IsImage(),
IsVideo: data.kind1063Metadata.IsVideo(),
})
}
params.Details.Extra = fileMetadataDetails(params)
component = fileMetadataTemplate(params)
case LiveEvent:
opengraph.Image = data.kind30311Metadata.Image
component = liveEventTemplate(LiveEventPageParams{
BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{
IsProfile: false,
NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked,
},
DetailsParams: detailsData,
CreatedAt: data.createdAt,
Metadata: data.metadata,
Style: style,
Subject: subject,
TitleizedContent: titleizedContent,
Alt: data.alt,
Details: detailsData,
LiveEvent: *data.kind30311Metadata,
Clients: generateClientList(data.event.Kind, data.naddr,
func(s string) string {
if strings.Contains(s, "nostrudel") {
@@ -412,42 +405,51 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
return s
},
),
LiveEvent: *data.kind30311Metadata,
})
case LiveEventMessage:
// opengraph.Image = data.kind1311Metadata.Image
component = liveEventMessageTemplate(LiveEventMessagePageParams{
BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{
IsProfile: false,
NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked,
},
DetailsParams: detailsData,
Details: detailsData,
Content: template.HTML(data.content),
CreatedAt: data.createdAt,
Metadata: data.metadata,
ParentLink: data.parentLink,
Style: style,
Subject: subject,
TitleizedContent: titleizedContent,
Alt: data.alt,
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:
detailsData.HideDetails = false // always open this since we know nothing else about the event
component = otherTemplate(OtherPageParams{
BaseEventPageParams: baseEventPageParams,
HeadParams: HeadParams{
IsProfile: false,
NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked,
},
DetailsParams: detailsData,
Alt: data.alt,
Details: detailsData,
Kind: data.event.Kind,
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")
err = profileTemplate(ProfilePageParams{
HeadParams: HeadParams{IsProfile: true},
DetailsParams: DetailsParams{
Details: DetailsParams{
HideDetails: true,
CreatedAt: data.createdAt,
KindDescription: data.kindDescription,

View File

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

View File

@@ -7,6 +7,7 @@ import (
"html"
"html/template"
"regexp"
"strconv"
"strings"
"time"
@@ -39,12 +40,36 @@ type EnhancedEvent struct {
relays []string
}
func (ee EnhancedEvent) IsReply() bool {
return nip10.GetImmediateReply(ee.Event.Tags) != nil
func (ee EnhancedEvent) getParentNevent() string {
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)
}
}
func (ee EnhancedEvent) Reply() *nostr.Tag {
return nip10.GetImmediateReply(ee.Event.Tags)
return parentNevent
}
func (ee EnhancedEvent) isReply() bool {
return nip10.GetImmediateReply(ee.Event.Tags) != nil
}
func (ee EnhancedEvent) Preview() template.HTML {
@@ -96,8 +121,7 @@ func (ee EnhancedEvent) RssContent() string {
content := ee.Event.Content
content = basicFormatting(html.EscapeString(content), true, false, false)
content = renderQuotesAsHTML(context.Background(), content, false)
if ee.IsReply() {
nevent, _ := nip19.EncodeEvent(ee.Reply().Value(), ee.relays, ee.Event.PubKey)
if nevent := ee.getParentNevent(); nevent != "" {
neventShort := nevent[:8] + "…" + nevent[len(nevent)-4:]
content = "In reply to <a href='/" + nevent + "'>" + neventShort + "</a><br/>_________________________<br/><br/>" + content
}
@@ -189,6 +213,13 @@ type Kind30311Metadata struct {
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 {
nip52.CalendarEvent
}

View File

@@ -15,8 +15,6 @@ import (
"mvdan.cc/xurls/v2"
"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"
)
@@ -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 {
key := "rls:" + eventId
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
return matcher.ReplaceAllStringFunc(input, func(match string) string {
nip19 := match[len("nostr:"):]
@@ -377,7 +362,7 @@ func basicFormatting(input string, skipNostrEventLinks bool, usingTelegramInstan
lines := strings.Split(input, "\n")
for i, line := range lines {
line = replaceURLsWithTags(line, imageReplacementTemplate, videoReplacementTemplate, skipLinks)
line = replaceNostrURLsWithTags(nostrMatcher, line)
line = replaceNostrURLsWithHTMLTags(nostrMatcher, line)
lines[i] = line
}
return strings.Join(lines, "<br/>")