mirror of
https://github.com/aljazceru/njump.git
synced 2026-01-31 11:44:34 +01:00
tmpl migration: note.html
This commit is contained in:
4
data.go
4
data.go
@@ -146,11 +146,11 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
return nil, err
|
||||
}
|
||||
case 1, 7, 30023, 30024:
|
||||
typ = "note"
|
||||
templateId = Note
|
||||
content = event.Content
|
||||
parentNevent = getParentNevent(event)
|
||||
case 6:
|
||||
typ = "note"
|
||||
templateId = Note
|
||||
if reposted := event.Tags.GetFirst([]string{"e", ""}); reposted != nil {
|
||||
original_nevent, _ := nip19.EncodeEvent((*reposted)[1], []string{}, "")
|
||||
content = "Repost of nostr:" + original_nevent
|
||||
|
||||
1
main.go
1
main.go
@@ -73,7 +73,6 @@ func main() {
|
||||
"homepage": "homepage.html",
|
||||
"profile": "profile.html",
|
||||
"profile_sitemap": "sitemap.xml",
|
||||
"note": "note.html",
|
||||
"relay": "relay.html",
|
||||
"relay_sitemap": "sitemap.xml",
|
||||
"archive": "archive.html",
|
||||
|
||||
57
pages.go
57
pages.go
@@ -54,7 +54,7 @@ var (
|
||||
DetailsTemplate = tmpl.MustCompile(&DetailsPartial{})
|
||||
)
|
||||
|
||||
//tmpl:bind footer.html
|
||||
//tmpl:bind details.html
|
||||
type DetailsPartial struct {
|
||||
HideDetails bool
|
||||
CreatedAt string
|
||||
@@ -69,6 +69,21 @@ func (*DetailsPartial) TemplateText() string {
|
||||
return tmplDetails
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed templates/clients.html
|
||||
tmplClients string
|
||||
ClientsTemplate = tmpl.MustCompile(&ClientsPartial{})
|
||||
)
|
||||
|
||||
//tmpl:bind clients.html
|
||||
type ClientsPartial struct {
|
||||
Clients []ClientReference
|
||||
}
|
||||
|
||||
func (*ClientsPartial) TemplateText() string {
|
||||
return tmplClients
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed templates/footer.html
|
||||
tmplFooter string
|
||||
@@ -151,3 +166,43 @@ type OtherPage struct {
|
||||
func (*OtherPage) TemplateText() string {
|
||||
return tmplOther
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed templates/note.html
|
||||
tmplNote string
|
||||
NoteTemplate = tmpl.MustCompile(&NotePage{})
|
||||
)
|
||||
|
||||
type NotePage struct {
|
||||
HeadCommonPartial `tmpl:"head_common"`
|
||||
TopPartial `tmpl:"top"`
|
||||
DetailsPartial `tmpl:"details"`
|
||||
ClientsPartial `tmpl:"clients"`
|
||||
FooterPartial `tmpl:"footer"`
|
||||
|
||||
AuthorLong string
|
||||
Content template.HTML
|
||||
CreatedAt string
|
||||
Description string
|
||||
Image string
|
||||
Metadata nostr.ProfileMetadata
|
||||
Nevent string
|
||||
Npub string
|
||||
NpubShort string
|
||||
Oembed string
|
||||
ParentLink template.HTML
|
||||
Proxy string
|
||||
SeenOn []string
|
||||
Style string
|
||||
Subject string
|
||||
TextImageURL string
|
||||
Title string
|
||||
TitleizedContent string
|
||||
TwitterTitle string
|
||||
Video string
|
||||
VideoType string
|
||||
}
|
||||
|
||||
func (*NotePage) TemplateText() string {
|
||||
return tmplNote
|
||||
}
|
||||
|
||||
43
render.go
43
render.go
@@ -218,7 +218,7 @@ func render(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// oembed discovery
|
||||
oembed := ""
|
||||
if data.typ == "note" {
|
||||
if data.templateId == Note {
|
||||
oembed = (&url.URL{
|
||||
Scheme: "https",
|
||||
Host: host,
|
||||
@@ -289,11 +289,50 @@ func render(w http.ResponseWriter, r *http.Request) {
|
||||
AuthorLong: data.authorLong,
|
||||
CreatedAt: data.createdAt,
|
||||
})
|
||||
case Note:
|
||||
err = NoteTemplate.Render(w, &NotePage{
|
||||
HeadCommonPartial: HeadCommonPartial{IsProfile: false},
|
||||
DetailsPartial: DetailsPartial{
|
||||
HideDetails: true,
|
||||
CreatedAt: data.createdAt,
|
||||
KindDescription: data.kindDescription,
|
||||
KindNIP: data.kindNIP,
|
||||
EventJSON: string(eventJSON),
|
||||
Kind: data.event.Kind,
|
||||
},
|
||||
ClientsPartial: ClientsPartial{
|
||||
Clients: generateClientList(code, data.event),
|
||||
},
|
||||
|
||||
AuthorLong: data.authorLong,
|
||||
Content: template.HTML(data.content),
|
||||
CreatedAt: data.createdAt,
|
||||
Description: description,
|
||||
Image: data.image,
|
||||
Metadata: data.metadata,
|
||||
Nevent: data.nevent,
|
||||
Npub: data.npub,
|
||||
NpubShort: data.npubShort,
|
||||
Oembed: oembed,
|
||||
ParentLink: template.HTML(
|
||||
replaceNostrURLsWithTags(nostrNoteNeventMatcher, "nostr:"+data.parentNevent),
|
||||
),
|
||||
Proxy: "https://" + host + "/njump/proxy?src=",
|
||||
SeenOn: data.relays,
|
||||
Style: style,
|
||||
Subject: subject,
|
||||
TextImageURL: textImageURL,
|
||||
Title: title,
|
||||
TitleizedContent: titleizedContent,
|
||||
TwitterTitle: twitterTitle,
|
||||
Video: data.video,
|
||||
VideoType: data.videoType,
|
||||
})
|
||||
case Other:
|
||||
err = OtherTemplate.Render(w, &OtherPage{
|
||||
HeadCommonPartial: HeadCommonPartial{IsProfile: false},
|
||||
DetailsPartial: DetailsPartial{
|
||||
HideDetails: false,
|
||||
HideDetails: true,
|
||||
CreatedAt: data.createdAt,
|
||||
KindDescription: data.kindDescription,
|
||||
KindNIP: data.kindNIP,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<aside class="column column_clients">
|
||||
<div class="title open-list">
|
||||
<span class="text">Open {{.type}} in</span>
|
||||
<span class="text">Open in</span>
|
||||
<span class="open">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -33,10 +33,10 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="clients_wrapper">
|
||||
{{range .clients}}
|
||||
{{range .Clients}}
|
||||
<div class="btn">
|
||||
<a class="client" data-client="{{.Name}}" href="{{.URL}}"
|
||||
><span>Open {{$.type}} in</span> {{.Name}}</a
|
||||
><span>Open in</span> {{.Name}}</a
|
||||
>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,122 +1,112 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html class="theme--default">
|
||||
<meta charset="UTF-8" />
|
||||
<head>
|
||||
<title>{{.titleizedContent}}</title>
|
||||
<title>
|
||||
{{.nevent | escapeString}} by {{.metadata.Name | escapeString}} is this
|
||||
note nostr ”nevent"
|
||||
</title>
|
||||
<title>{{.TitleizedContent}}</title>
|
||||
<title>{{.Nevent}} by {{.Metadata.Name}} is this note nostr ”nevent"</title>
|
||||
|
||||
<meta property="og:title" content="{{.title | escapeString}}" />
|
||||
{{ if eq .style "twitter" }}
|
||||
<meta name="twitter:title" content="{{.twitterTitle | escapeString}}" />
|
||||
<meta property="og:title" content="{{.Title}}" />
|
||||
{{ if eq .Style "twitter" }}
|
||||
<meta name="twitter:title" content="{{.TwitterTitle}}" />
|
||||
{{ end }}
|
||||
|
||||
<meta property="og:site_name" content="{{.authorLong | escapeString}}" />
|
||||
{{ if .textImageURL }}
|
||||
<meta property="og:site_name" content="{{.AuthorLong}}" />
|
||||
{{ if not (eq "" .TextImageURL) }}
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content="@nostrprotocol" />
|
||||
<meta property="og:image" content="{{.textImageURL | escapeString}}" />
|
||||
<meta name="twitter:image" content="{{.textImageURL | escapeString}}" />
|
||||
<meta property="og:image" content="{{.TextImageURL}}" />
|
||||
<meta name="twitter:image" content="{{.TextImageURL}}" />
|
||||
{{ else }}
|
||||
<!---->
|
||||
<meta property="twitter:card" content="summary" />
|
||||
{{ if .image }}
|
||||
<meta property="og:image" content="{{.image | escapeString}}" />
|
||||
<meta name="twitter:image" content="{{.proxy}}{{.image | escapeString}}" />
|
||||
{{ end }} {{ if .video }}
|
||||
<meta property="og:video" content="{{.video | escapeString}}" />
|
||||
<meta property="og:video:secure_url" content="{{.video | escapeString}}" />
|
||||
<meta
|
||||
property="og:video:type"
|
||||
content="video/{{.videoType | escapeString}}"
|
||||
/>
|
||||
{{ if not (eq "" .Image) }}
|
||||
<meta property="og:image" content="{{.Image}}" />
|
||||
<meta name="twitter:image" content="{{.Proxy}}{{.Image}}" />
|
||||
{{ end }} {{ if not (eq "" .Video) }}
|
||||
<meta property="og:video" content="{{.Video}}" />
|
||||
<meta property="og:video:secure_url" content="{{.Video}}" />
|
||||
<meta property="og:video:type" content="video/{{.VideoType}}" />
|
||||
{{ end }} {{ end }}
|
||||
<!---->
|
||||
{{ if .description }}
|
||||
<meta property="og:description" content="{{.description | escapeString}}" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="{{.description | escapeString}}"
|
||||
/>
|
||||
{{ if not (eq "" .Description) }}
|
||||
<meta property="og:description" content="{{.Description}}" />
|
||||
<meta name="twitter:description" content="{{.Description}}" />
|
||||
{{ end }}
|
||||
|
||||
<link
|
||||
rel="canonical"
|
||||
href="https://{{s.CanonicalHost}}/{{.nevent | escapeString }}"
|
||||
/>
|
||||
<link rel="canonical" href="https://njump.me/{{.Nevent }}" />
|
||||
<!---->
|
||||
{{ if .oembed }}
|
||||
{{ if not (eq "" .Oembed) }}
|
||||
<link
|
||||
rel="alternate"
|
||||
type="application/json+oembed"
|
||||
href="{{.oembed}}&format=json"
|
||||
href="{{.Oembed}}&format=json"
|
||||
/>
|
||||
<link
|
||||
rel="alternate"
|
||||
type="text/xml+oembed"
|
||||
href="{{.oembed}}&format=xml"
|
||||
href="{{.Oembed}}&format=xml"
|
||||
/>
|
||||
{{ end }} {{template "head_common.html" .}}
|
||||
{{ end }}
|
||||
|
||||
<!---->
|
||||
{{template "head_common" .}}
|
||||
</head>
|
||||
|
||||
<body class="note">
|
||||
{{template "top.html" .}}
|
||||
{{template "top" .}}
|
||||
|
||||
<div class="container_wrapper">
|
||||
<div class="container">
|
||||
<div class="column column_content">
|
||||
<header class="profile_intro">
|
||||
<a href="/{{.npub | escapeString}}">
|
||||
<a href="/{{.Npub}}">
|
||||
<div class="pic-wrapper">
|
||||
<img class="pic" src="{{.metadata.Picture | escapeString}}" />
|
||||
<img class="pic" src="{{.Metadata.Picture}}" />
|
||||
</div>
|
||||
<div class="info-wrapper">
|
||||
<div class="name">
|
||||
{{.metadata.Name | escapeString}} {{if not (eq .metadata.Name
|
||||
.metadata.DisplayName)}}
|
||||
<span class="display"
|
||||
>{{.metadata.DisplayName | escapeString}}</span
|
||||
>
|
||||
{{.Metadata.Name}}
|
||||
<!---->
|
||||
{{if not (eq .Metadata.Name .Metadata.DisplayName)}}
|
||||
<span class="display">{{.Metadata.DisplayName}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="npub">{{.npubShort | escapeString}}</div>
|
||||
<div class="npub">{{.NpubShort}}</div>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
<div class="published_at">{{.createdAt | escapeString}}</div>
|
||||
<div class="published_at">{{.CreatedAt}}</div>
|
||||
|
||||
<div class="reply_of">
|
||||
{{ if .parentNevent }} In reply to {{ printf "%s%s" "nostr:"
|
||||
.parentNevent | escapeString | basicFormatting }} {{ end }}
|
||||
{{ if not (eq "" .ParentLink) }} In reply to {{ .ParentLink }} {{
|
||||
end }}
|
||||
</div>
|
||||
|
||||
<div class="field separator"></div>
|
||||
|
||||
<article class="field content">
|
||||
{{ if (not (eq .subject ""))}}
|
||||
<h1>{{.subject | escapeString}}</h1>
|
||||
{{ if (not (eq "" .Subject))}}
|
||||
<h1>{{.Subject}}</h1>
|
||||
{{ else }}
|
||||
<h1 class="h">
|
||||
{{.metadata.Name | escapeString}} on Nostr: {{.titleizedContent}}
|
||||
{{.Metadata.Name}} on Nostr: {{.TitleizedContent}}
|
||||
</h1>
|
||||
{{ end }}
|
||||
<!-- main content -->
|
||||
{{ .content }}
|
||||
{{ .Content }}
|
||||
</article>
|
||||
|
||||
<div class="field separator"></div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">Author Public key</div>
|
||||
{{.npub | escapeString}}
|
||||
{{.Npub}}
|
||||
</div>
|
||||
|
||||
{{ if .seenOn }}
|
||||
{{ if not (eq 0 (len .SeenOn)) }}
|
||||
<div class="field">
|
||||
<div class="label">Seen on</div>
|
||||
{{ range .seenOn }}<a href="/r/{{.}}">{{.}}</a>
|
||||
{{ range .SeenOn }}<a href="/r/{{.}}">{{.}}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -131,19 +121,17 @@
|
||||
<label for="advanced-switch">Show more details</label>
|
||||
</div>
|
||||
|
||||
{{template "details.html" .}}
|
||||
{{template "details" .}}
|
||||
|
||||
<div class="field separator"></div>
|
||||
</div>
|
||||
|
||||
{{template "column_clients.html" .}}
|
||||
{{template "clients" .ClientsPartial}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "footer.html"}}
|
||||
{{template "footer" .}}
|
||||
|
||||
<script>
|
||||
{{template "scripts.js"}}
|
||||
</script>
|
||||
<script src="/njump/static/scripts.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
48
utils.go
48
utils.go
@@ -226,45 +226,35 @@ func replaceURLsWithTags(input string, imageReplacementTemplate, videoReplacemen
|
||||
})
|
||||
}
|
||||
|
||||
func replaceNostrURLs(matcher *regexp.Regexp, input string, style string) string {
|
||||
// Match and replace npup1, nprofile1, note1, nevent1, etc
|
||||
input = matcher.ReplaceAllStringFunc(input, func(match string) string {
|
||||
func replaceNostrURLsWithTags(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:"):]
|
||||
first_chars := nip19[:8]
|
||||
last_chars := nip19[len(nip19)-4:]
|
||||
replacement := ""
|
||||
if strings.HasPrefix(nip19, "npub1") || strings.HasPrefix(nip19, "nprofile1") {
|
||||
if style == "tags" {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*4)
|
||||
defer cancel()
|
||||
name := getNameFromNip19(ctx, nip19)
|
||||
replacement = fmt.Sprintf(`<a href="/%s" class="nostr" ><strong>%s</strong> (<i>%s</i>)</a>`, nip19, name, first_chars+"…"+last_chars)
|
||||
} else if style == "short" {
|
||||
replacement = "@" + first_chars + "…" + last_chars
|
||||
} else {
|
||||
replacement = nip19
|
||||
}
|
||||
return replacement
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*4)
|
||||
defer cancel()
|
||||
name := getNameFromNip19(ctx, nip19)
|
||||
return fmt.Sprintf(`<a href="/%s" class="nostr" ><strong>%s</strong> (<i>%s</i>)</a>`, nip19, name, first_chars+"…"+last_chars)
|
||||
} else {
|
||||
if style == "tags" {
|
||||
replacement = fmt.Sprintf(`<a href="/%s" class="nostr">%s</a>`, nip19, first_chars+"…"+last_chars)
|
||||
} else if style == "short" {
|
||||
replacement = "#" + first_chars + "…" + last_chars
|
||||
} else {
|
||||
replacement = nip19
|
||||
}
|
||||
return replacement
|
||||
return fmt.Sprintf(`<a href="/%s" class="nostr">%s</a>`, nip19, first_chars+"…"+last_chars)
|
||||
}
|
||||
})
|
||||
return input
|
||||
}
|
||||
|
||||
func replaceNostrURLsWithTags(matcher *regexp.Regexp, input string) string {
|
||||
return replaceNostrURLs(matcher, input, "tags")
|
||||
}
|
||||
|
||||
func shortenNostrURLs(input string) string {
|
||||
return replaceNostrURLs(nostrEveryMatcher, input, "short")
|
||||
// match and replace npup1, nprofile1, note1, nevent1, etc
|
||||
return nostrEveryMatcher.ReplaceAllStringFunc(input, func(match string) string {
|
||||
nip19 := match[len("nostr:"):]
|
||||
first_chars := nip19[:8]
|
||||
last_chars := nip19[len(nip19)-4:]
|
||||
if strings.HasPrefix(nip19, "npub1") || strings.HasPrefix(nip19, "nprofile1") {
|
||||
return "@" + first_chars + "…" + last_chars
|
||||
} else {
|
||||
return "#" + first_chars + "…" + last_chars
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getNameFromNip19(ctx context.Context, nip19 string) string {
|
||||
|
||||
Reference in New Issue
Block a user