Add support for Highlight (kind:9802)

This commit is contained in:
dtonon
2025-04-02 00:44:53 +02:00
parent bb8a1a84af
commit 1ca10e12fb
7 changed files with 168 additions and 0 deletions

View File

@@ -110,6 +110,12 @@ func generateClientList(
amethyst,
snort, coracle, nostrudel,
}
case 9802:
clients = []ClientReference{
highlighter,
coracle,
nostrudel,
}
case 30311:
clients = []ClientReference{
native,

55
data.go
View File

@@ -3,7 +3,9 @@ package main
import (
"context"
"fmt"
"html"
"html/template"
"strconv"
"strings"
"time"
@@ -37,6 +39,7 @@ type Data struct {
kind30311Metadata *Kind30311Metadata
kind31922Or31923Metadata *Kind31922Or31923Metadata
Kind30818Metadata Kind30818Metadata
Kind9802Metadata Kind9802Metadata
}
func grabData(ctx context.Context, code string, withRelays bool) (Data, error) {
@@ -129,6 +132,58 @@ func grabData(ctx context.Context, code string, withRelays bool) (Data, error) {
return ""
}()
data.content = event.Content
case 9802:
data.templateId = Highlight
data.content = event.Content
if author := event.Tags.Find("p"); author != nil {
ctx, cancel := context.WithTimeout(ctx, time.Second*3)
defer cancel()
data.Kind9802Metadata.Author = sys.FetchProfileMetadata(ctx, author[1])
}
if sourceEvent := event.Tags.Find("e"); sourceEvent != nil {
data.Kind9802Metadata.SourceEvent = sourceEvent[1]
data.Kind9802Metadata.SourceName = "#" + shortenString(sourceEvent[1], 8, 4)
} else if sourceEvent := event.Tags.Find("a"); sourceEvent != nil {
spl := strings.Split(sourceEvent[1], ":")
kind, _ := strconv.Atoi(spl[0])
var relayHints []string
if len(sourceEvent) > 2 {
relayHints = []string{sourceEvent[2]}
}
naddr, _ := nip19.EncodeEntity(spl[1], kind, spl[2], relayHints)
data.Kind9802Metadata.SourceEvent = naddr
sourceEvent, _, _ := getEvent(ctx, naddr, withRelays)
if title := sourceEvent.Tags.Find("title"); title != nil {
data.Kind9802Metadata.SourceName = title[1]
} else {
data.Kind9802Metadata.SourceName = "#" + shortenString(naddr, 8, 4)
}
} else if sourceUrl := event.Tags.Find("r"); sourceUrl != nil {
data.Kind9802Metadata.SourceURL = sourceUrl[1]
data.Kind9802Metadata.SourceName = sourceUrl[1]
}
if context := event.Tags.Find("context"); context != nil {
data.Kind9802Metadata.Context = context[1]
escapedContext := html.EscapeString(context[1])
escapedCitation := html.EscapeString(data.content)
// Some clients mistakenly put the highlight in the context
if escapedContext != escapedCitation {
// Replace the citation with the marked version
data.Kind9802Metadata.MarkedContext = strings.Replace(
escapedContext,
escapedCitation,
fmt.Sprintf("<span class=\"bg-amber-100 dark:bg-amber-700\">%s</span>", escapedCitation),
-1, // Replace all occurrences
)
}
}
if comment := event.Tags.Find("comment"); comment != nil {
data.Kind9802Metadata.Comment = basicFormatting(comment[1], false, false, false)
}
default:
data.templateId = Other
}

69
highlight.templ Normal file
View File

@@ -0,0 +1,69 @@
package main
import "html/template"
type HighlightPageParams struct {
BaseEventPageParams
OpenGraphParams
HeadParams
Details DetailsParams
Content template.HTML
HighlightEvent Kind9802Metadata
Clients []ClientReference
}
templ highlightInnerBlock(params HighlightPageParams) {
<h1 class="text-2xl" itemprop="headline">Highlight</h1>
<div itemprop="articleBody">
if params.HighlightEvent.Comment != "" {
<div dir="auto" class="leading-6">
@templ.Raw(params.HighlightEvent.Comment)
</div>
}
<blockquote dir="auto" class="text-xl leading-7">
if params.HighlightEvent.MarkedContext != "" {
@templ.Raw(params.HighlightEvent.MarkedContext)
} else {
@templ.Raw(params.Content)
}
<footer class="text-base mt-4">
if params.HighlightEvent.Author.Name != "" {
{ params.HighlightEvent.Author.Name + "," }
}
<cite>
if params.HighlightEvent.SourceURL != "" {
<a href={ templ.SafeURL(params.HighlightEvent.SourceURL) }>{ params.HighlightEvent.SourceName }</a>
}
if params.HighlightEvent.SourceEvent != "" {
<a href={ templ.SafeURL("/" + params.HighlightEvent.SourceEvent) }>{ params.HighlightEvent.SourceName }</a>
}
</cite>
</footer>
</blockquote>
</div>
}
templ highlightTemplate(params HighlightPageParams, isEmbed bool) {
<!DOCTYPE html>
if isEmbed {
@embeddedPageTemplate(
params.Event,
params.NeventNaked,
) {
@highlightInnerBlock(params)
}
} else {
@eventPageTemplate(
"Highlight",
params.OpenGraphParams,
params.HeadParams,
params.Clients,
params.Details,
params.Event,
) {
@highlightInnerBlock(params)
}
}
}

View File

@@ -24,6 +24,7 @@ const (
LiveEventMessage
CalendarEvent
WikiEvent
Highlight
Other
)

View File

@@ -564,6 +564,25 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
component = wikiEventTemplate(params, isEmbed)
case Highlight:
content := data.content
params := HighlightPageParams{
BaseEventPageParams: baseEventPageParams,
OpenGraphParams: opengraph,
HeadParams: HeadParams{
IsProfile: false,
NaddrNaked: data.naddrNaked,
NeventNaked: data.neventNaked,
},
Content: template.HTML(content),
HighlightEvent: data.Kind9802Metadata,
Details: detailsData,
Clients: generateClientList(data.event.Kind, data.nevent),
}
component = highlightTemplate(params, isEmbed)
case Other:
detailsData.HideDetails = false // always open this since we know nothing else about the event

View File

@@ -35,3 +35,13 @@ type Kind30818Metadata struct {
Summary string
PublishedAt time.Time
}
type Kind9802Metadata struct {
Author sdk.ProfileMetadata
SourceEvent string
SourceURL string
SourceName string
Context string
MarkedContext string
Comment string
}

View File

@@ -67,6 +67,7 @@ var kindNames = map[int]string{
1984: "Reporting",
9734: "Zap Request",
9735: "Zap",
9802: "Highlight",
10000: "Mute List",
10001: "Pin List",
10002: "Relay List Metadata",
@@ -107,6 +108,7 @@ var kindNIPs = map[int]string{
1984: "56",
9734: "57",
9735: "57",
9802: "84",
10000: "51",
10001: "51",
10002: "65",
@@ -254,6 +256,12 @@ func shortenNostrURLs(input string) string {
})
}
func shortenString(input string, before int, after int) string {
firstChars := input[:before]
lastChars := input[len(input)-after:]
return firstChars + "…" + lastChars
}
func getNameFromNip19(ctx context.Context, nip19code string) (string, bool) {
metadata, _ := sys.FetchProfileFromInput(ctx, nip19code)
if metadata.Name == "" {