refactor so embedded note and profile are rendered similarly to their non-embedded versions.

This commit is contained in:
fiatjaf
2024-08-03 14:26:57 -03:00
parent 0dd8c38a95
commit 4011528058
7 changed files with 46 additions and 105 deletions

View File

@@ -1,6 +1,6 @@
package main package main
templ embeddedNoteTemplate(params EmbeddedNoteParams) { templ embeddedNoteTemplate(params NotePageParams) {
<!DOCTYPE html> <!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl"> <html class="theme--default text-lg font-light print:text-base sm:text-xl">
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
@@ -15,9 +15,9 @@ templ embeddedNoteTemplate(params EmbeddedNoteParams) {
<body class="relative bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black sm:items-center sm:justify-center"> <body class="relative bg-white text-gray-600 dark:bg-neutral-900 dark:text-neutral-50 print:text-black sm:items-center sm:justify-center">
<style> ::-webkit-scrollbar { display: none; } </style> <style> ::-webkit-scrollbar { display: none; } </style>
<div class="mx-auto w-full max-w-screen-2xl justify-between gap-10 overflow-visible px-4 pb-4 pt-4 print:w-full sm:w-11/12 md:w-10/12 lg:w-9/12"> <div class="mx-auto w-full max-w-screen-2xl justify-between gap-10 overflow-visible px-4 pb-4 pt-4 print:w-full sm:w-11/12 md:w-10/12 lg:w-9/12">
<a href={ templ.URL("/" + params.Url) } target="_new" class="no-underline"> <a href={ templ.URL("/" + params.NeventNaked) } target="_blank" class="no-underline">
<div class="w-full break-words"> <div class="w-full break-words">
@authorHeaderTemplate(params.Metadata) @authorHeaderTemplate(params.Event.author)
<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>
<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"> <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 != "" { if params.Subject != "" {
@@ -28,7 +28,7 @@ templ embeddedNoteTemplate(params EmbeddedNoteParams) {
@templ.Raw(params.Content) @templ.Raw(params.Content)
</div> </div>
<div class="mt-2 w-full text-right text-sm text-stone-400"> <div class="mt-2 w-full text-right text-sm text-stone-400">
{ params.CreatedAt } { params.Event.CreatedAtStr() }
</div> </div>
</article> </article>
<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>

View File

@@ -1,6 +1,6 @@
package main package main
templ embeddedProfileTemplate(params EmbeddedProfileParams) { templ embeddedProfileTemplate(params ProfilePageParams) {
<!DOCTYPE html> <!DOCTYPE html>
<html class="theme--default text-lg font-light print:text-base sm:text-xl"> <html class="theme--default text-lg font-light print:text-base sm:text-xl">
<meta charset="UTF-8"/> <meta charset="UTF-8"/>

View File

@@ -140,8 +140,10 @@ func main() {
mux.HandleFunc("/e/", redirectFromESlash) mux.HandleFunc("/e/", redirectFromESlash)
mux.HandleFunc("/p/", redirectFromPSlash) mux.HandleFunc("/p/", redirectFromPSlash)
mux.HandleFunc("/favicon.ico", redirectToFavicon) mux.HandleFunc("/favicon.ico", redirectToFavicon)
mux.HandleFunc("/embed/", renderEmbedjs) mux.HandleFunc("/embed/{code}", renderEmbedjs)
mux.HandleFunc("/", renderEvent) mux.HandleFunc("/about", renderAbout)
mux.HandleFunc("/{code}", renderEvent)
mux.HandleFunc("/{$}", renderHomepage)
corsHandler := cors.Default().Handler(relay) corsHandler := cors.Default().Handler(relay)

View File

@@ -1,11 +1,7 @@
package main package main
import ( import (
"html"
"html/template"
"net/http" "net/http"
"github.com/a-h/templ"
) )
func renderEmbedjs(w http.ResponseWriter, r *http.Request) { func renderEmbedjs(w http.ResponseWriter, r *http.Request) {
@@ -13,61 +9,3 @@ func renderEmbedjs(w http.ResponseWriter, r *http.Request) {
fileContent, _ := static.ReadFile("static/embed.js") fileContent, _ := static.ReadFile("static/embed.js")
w.Write(fileContent) w.Write(fileContent)
} }
func renderEmbedded(w http.ResponseWriter, r *http.Request, code string) {
ctx := r.Context()
data, err := grabData(ctx, code)
if err != nil {
w.Header().Set("Cache-Control", "max-age=60")
w.WriteHeader(http.StatusNotFound)
errorTemplate(ErrorPageParams{Errors: err.Error()}).Render(ctx, w)
return
}
var subject string
for _, tag := range data.event.Tags {
if tag[0] == "subject" || tag[0] == "title" {
subject = tag[1]
}
}
if data.event.Kind == 30023 || data.event.Kind == 30024 {
data.content = mdToHTML(data.content, data.templateId == TelegramInstantView, true)
} else {
// first we run basicFormatting, which turns URLs into their appropriate HTML tags
data.content = basicFormatting(html.EscapeString(data.content), true, false, false)
// then we render quotes as HTML, which will also apply basicFormatting to all the internal quotes
data.content = renderQuotesAsHTML(ctx, data.content, data.templateId == TelegramInstantView)
// we must do this because inside <blockquotes> we must treat <img>s differently when telegram_instant_view
}
var component templ.Component
switch data.templateId {
case Note:
component = embeddedNoteTemplate(EmbeddedNoteParams{
Content: template.HTML(data.content),
CreatedAt: data.createdAt,
Metadata: data.event.author,
Subject: subject,
Url: code,
})
case Profile:
component = embeddedProfileTemplate(EmbeddedProfileParams{
Metadata: data.event.author,
NormalizedAuthorWebsiteURL: normalizeWebsiteURL(data.event.author.Website),
RenderedAuthorAboutText: template.HTML(basicFormatting(html.EscapeString(data.event.author.About), false, false, true)),
AuthorRelays: relaysPretty(ctx, data.event.author.PubKey),
})
default:
log.Error().Int("templateId", int(data.templateId)).Msg("no way to render")
http.Error(w, "tried to render an unsupported template at render_event.go", 500)
return
}
if err := component.Render(ctx, w); err != nil {
log.Warn().Err(err).Msg("error rendering tmpl")
}
return
}

View File

@@ -19,29 +19,11 @@ import (
"github.com/pelletier/go-toml" "github.com/pelletier/go-toml"
) )
func isValidShortcode(s string) bool {
for _, r := range s {
if !('a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || r == '_') {
return false
}
}
return true
}
func renderEvent(w http.ResponseWriter, r *http.Request) { func renderEvent(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
code := r.URL.Path[1:] // hopefully a nip19 code code := r.PathValue("code")
// it's the homepage isEmbed := r.URL.Query().Get("embed") != ""
if code == "" {
renderHomepage(w, r)
return
}
if code == "about" {
renderAbout(w, r)
return
}
if strings.HasPrefix(code, "nostr:") { if strings.HasPrefix(code, "nostr:") {
// remove the "nostr:" prefix // remove the "nostr:" prefix
@@ -61,7 +43,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
// it may be a NIP-05 // it may be a NIP-05
if nip05.IsValidIdentifier(code) { if nip05.IsValidIdentifier(code) {
renderProfile(ctx, w, code) renderProfile(ctx, r, w, code)
return return
} }
@@ -72,17 +54,10 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
return return
} }
// Check if the embed parameter is set to "yes"
embedParam := r.URL.Query().Get("embed")
if embedParam == "yes" {
renderEmbedded(w, r, code)
return
}
// render npub and nprofile using a separate function // render npub and nprofile using a separate function
if prefix == "npub" || prefix == "nprofile" { if prefix == "npub" || prefix == "nprofile" {
// it's a profile // it's a profile
renderProfile(ctx, w, code) renderProfile(ctx, r, w, code)
return return
} }
@@ -370,7 +345,8 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
} }
} }
} }
component = noteTemplate(NotePageParams{
params := NotePageParams{
BaseEventPageParams: baseEventPageParams, BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph, OpenGraphParams: opengraph,
HeadParams: HeadParams{ HeadParams: HeadParams{
@@ -384,7 +360,13 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
Content: template.HTML(content), Content: template.HTML(content),
Cover: data.cover, Cover: data.cover,
TitleizedContent: titleizedContent, TitleizedContent: titleizedContent,
}) }
if isEmbed {
component = embeddedNoteTemplate(params)
} else {
component = noteTemplate(params)
}
case FileMetadata: case FileMetadata:
opengraph.Image = data.kind1063Metadata.DisplayImage() opengraph.Image = data.kind1063Metadata.DisplayImage()
params := FileMetadataPageParams{ params := FileMetadataPageParams{

View File

@@ -8,7 +8,9 @@ import (
"strings" "strings"
) )
func renderProfile(ctx context.Context, w http.ResponseWriter, code string) { func renderProfile(ctx context.Context, r *http.Request, w http.ResponseWriter, code string) {
isEmbed := r.URL.Query().Get("embed") != ""
isSitemap := false isSitemap := false
if strings.HasSuffix(code, ".xml") { if strings.HasSuffix(code, ".xml") {
code = code[:len(code)-4] code = code[:len(code)-4]
@@ -37,7 +39,10 @@ func renderProfile(ctx context.Context, w http.ResponseWriter, code string) {
createdAt := profile.Event.CreatedAt.Time().Format("2006-01-02T15:04:05Z07:00") createdAt := profile.Event.CreatedAt.Time().Format("2006-01-02T15:04:05Z07:00")
modifiedAt := profile.Event.CreatedAt.Time().Format("2006-01-02T15:04:05Z07:00") modifiedAt := profile.Event.CreatedAt.Time().Format("2006-01-02T15:04:05Z07:00")
lastNotes := authorLastNotes(ctx, profile.PubKey, isSitemap) var lastNotes []EnhancedEvent
if !isEmbed {
lastNotes = authorLastNotes(ctx, profile.PubKey, isSitemap)
}
if isSitemap { if isSitemap {
w.Header().Add("content-type", "text/xml") w.Header().Add("content-type", "text/xml")
@@ -63,8 +68,7 @@ func renderProfile(ctx context.Context, w http.ResponseWriter, code string) {
w.Header().Set("Cache-Control", "max-age=86400") w.Header().Set("Cache-Control", "max-age=86400")
nprofile := profile.Nprofile(ctx, sys, 2) nprofile := profile.Nprofile(ctx, sys, 2)
params := ProfilePageParams{
err = profileTemplate(ProfilePageParams{
HeadParams: HeadParams{IsProfile: true}, HeadParams: HeadParams{IsProfile: true},
Details: DetailsParams{ Details: DetailsParams{
HideDetails: true, HideDetails: true,
@@ -94,7 +98,13 @@ func renderProfile(ctx context.Context, w http.ResponseWriter, code string) {
return s return s
}, },
), ),
}).Render(ctx, w) }
if isEmbed {
err = embeddedProfileTemplate(params).Render(ctx, w)
} else {
err = profileTemplate(params).Render(ctx, w)
}
} }
if err != nil { if err != nil {

View File

@@ -550,3 +550,12 @@ func toJSONHTML(evt *nostr.Event) template.HTML {
}`, evt.ID, evt.PubKey, evt.CreatedAt, evt.Kind, tagsHTML, html.EscapeString(string(contentJSON)), evt.Sig), }`, evt.ID, evt.PubKey, evt.CreatedAt, evt.Kind, tagsHTML, html.EscapeString(string(contentJSON)), evt.Sig),
) )
} }
func isValidShortcode(s string) bool {
for _, r := range s {
if !('a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || '0' <= r && r <= '9' || r == '_') {
return false
}
}
return true
}