From 1f4f39b1e4ff6dfb05128d45496a96f5f9e54d8e Mon Sep 17 00:00:00 2001 From: Daniele Tonon Date: Sun, 3 Sep 2023 02:04:22 +0200 Subject: [PATCH] Render mentions inline --- image.go | 2 +- main.go | 13 +++++++------ static/styles.css | 14 ++++++++++++++ static/styles.scss | 11 +++++++++++ templates/head_common.html | 2 +- templates/note.html | 2 +- text.go | 20 ++++++++++++++++++- utils.go | 39 +++++++++++++++++++++++++++++++++----- 8 files changed, 88 insertions(+), 15 deletions(-) diff --git a/image.go b/image.go index a77535e..560f66c 100644 --- a/image.go +++ b/image.go @@ -21,7 +21,7 @@ func generate(w http.ResponseWriter, r *http.Request) { return } - lines := normalizeText(event.Content) + lines := normalizeText(renderInlineMentions(event.Content)) img, err := drawImage(lines, getPreviewStyle(r)) if err != nil { diff --git a/main.go b/main.go index 81f22df..4177914 100644 --- a/main.go +++ b/main.go @@ -71,12 +71,13 @@ func main() { templateMapping["relay_sitemap"] = "sitemap.xml" funcMap := template.FuncMap{ - "basicFormatting": basicFormatting, - "mdToHTML": mdToHTML, - "escapeString": html.EscapeString, - "sanitizeXSS": sanitizeXSS, - "trimProtocol": trimProtocol, - "titleize": titleize, + "basicFormatting": basicFormatting, + "renderInlineMentions": renderInlineMentions, + "mdToHTML": mdToHTML, + "escapeString": html.EscapeString, + "sanitizeXSS": sanitizeXSS, + "trimProtocol": trimProtocol, + "titleize": titleize, } tmpl = template.Must( diff --git a/static/styles.css b/static/styles.css index 6b3aae7..5a40c0f 100644 --- a/static/styles.css +++ b/static/styles.css @@ -465,6 +465,20 @@ iframe { .theme--dark .container .column_content .field blockquote { border-left: 0.5rem solid #2d2d2d; } +.container .column_content .field blockquote.mention { + border-left: 0.5rem solid #e32a6d; + padding: 0rem 0 0.5rem 1rem; +} +.theme--default .container .column_content .field blockquote.mention div { + padding: 0.5rem 0.5rem 0.5rem 1rem; + margin: 0 0 1rem -1rem; + background-color: #f3f3f3; +} +.theme--dark .container .column_content .field blockquote.mention div { + padding: 0.5rem 0.5rem 0.5rem 1rem; + margin: 0 0 1rem -1rem; + background-color: #2d2d2d; +} .container .column_content .field blockquote p { margin: 0 0 0.5rem 0; } diff --git a/static/styles.scss b/static/styles.scss index 4a9f8f3..2bcc817 100644 --- a/static/styles.scss +++ b/static/styles.scss @@ -455,6 +455,17 @@ iframe { padding: 0.5rem 0 0.5rem 1rem; margin: 2rem 0; font-style: italic; + &.mention { + border-left: 0.5rem solid $color-accent1; + padding: 0rem 0 0.5rem 1rem; + div { + @include themed() { + padding: 0.5rem 0.5rem 0.5rem 1rem; + margin: 0 0 1rem -1rem; + background-color: t($over-bg); + } + } + } p { margin: 0 0 0.5rem 0; } diff --git a/templates/head_common.html b/templates/head_common.html index 3a148d6..43acf04 100644 --- a/templates/head_common.html +++ b/templates/head_common.html @@ -1,2 +1,2 @@ - + diff --git a/templates/note.html b/templates/note.html index 3b57bf0..ff997a7 100644 --- a/templates/note.html +++ b/templates/note.html @@ -77,7 +77,7 @@ {{ if (or (eq .kindID 30023) (eq .kindID 30024))}} {{.content | mdToHTML }} {{ else }} - {{.content | escapeString | basicFormatting }} + {{.content | renderInlineMentions | escapeString | basicFormatting}} {{ end }} diff --git a/text.go b/text.go index b4e2d37..f5e59e1 100644 --- a/text.go +++ b/text.go @@ -3,6 +3,7 @@ package main import ( "image" "image/draw" + "regexp" "strings" "github.com/apatters/go-wordwrap" @@ -17,10 +18,27 @@ const ( ) func normalizeText(t string) []string { + re := regexp.MustCompile(`{div}.*?{/div}`) + t = re.ReplaceAllString(t, "") lines := make([]string, 0, MAX_LINES) + mention := false + maxChars := MAX_CHARS_PER_LINE for _, line := range strings.Split(t, "\n") { - line = wordwrap.Wrap(MAX_CHARS_PER_LINE, line) + line = wordwrap.Wrap(maxChars, line) for _, subline := range strings.Split(line, "\n") { + if strings.HasPrefix(subline, "{blockquote}") { + mention = true + subline = strings.ReplaceAll(subline, "{blockquote}", "") + subline = strings.ReplaceAll(subline, "{/blockquote}", "") + maxChars = MAX_CHARS_PER_LINE - 1 + } else if strings.HasSuffix(subline, "{/blockquote}") { + mention = false + subline = strings.ReplaceAll(subline, "{/blockquote}", "") + maxChars = MAX_CHARS_PER_LINE + } + if mention { + subline = "> " + subline + } lines = append(lines, subline) } } diff --git a/utils.go b/utils.go index 07bdf00..1ee224d 100644 --- a/utils.go +++ b/utils.go @@ -10,7 +10,7 @@ import ( "time" "github.com/gomarkdown/markdown" - "github.com/gomarkdown/markdown/html" + mdhtml "github.com/gomarkdown/markdown/html" "github.com/gomarkdown/markdown/parser" "github.com/microcosm-cc/bluemonday" @@ -258,6 +258,32 @@ func replaceNostrURLsWithTags(input string) string { return input } +func renderInlineMentions(input string) string { + lines := strings.Split(input, "\n") + + var processedLines []string + for _, line := range lines { + nostrRegexPattern := `\S*(nostr:)?((note|nevent)1[a-z0-9]+)\b` + nostrRegex := regexp.MustCompile(nostrRegexPattern) + input = nostrRegex.ReplaceAllStringFunc(line, func(match string) string { + submatch := nostrRegex.FindStringSubmatch(match) + if len(submatch) < 2 || strings.Contains(submatch[0], "/") { + return match + } + capturedGroup := submatch[2] + replacement := "" + ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + event, _ := getEvent(ctx, capturedGroup) + cancel() + replacement = fmt.Sprintf(`{blockquote} {div}From: %s {/div} %s {/blockquote}`, capturedGroup, event.Content) + return replacement + }) + processedLines = append(processedLines, input) + } + + return strings.Join(processedLines, "\n") +} + func replaceURLsWithTags(line string) string { var rline string @@ -293,8 +319,11 @@ func sanitizeXSS(html string) string { } func basicFormatting(input string) string { + input = strings.ReplaceAll(input, "{blockquote}", "
") + input = strings.ReplaceAll(input, "{/blockquote}", "
") + input = strings.ReplaceAll(input, "{div}", "
") + input = strings.ReplaceAll(input, "{/div}", "
") lines := strings.Split(input, "\n") - var processedLines []string for _, line := range lines { processedLine := replaceURLsWithTags(line) @@ -316,9 +345,9 @@ func mdToHTML(md string) string { doc := p.Parse([]byte(md)) // create HTML renderer with extensions - htmlFlags := html.CommonFlags | html.HrefTargetBlank - opts := html.RendererOptions{Flags: htmlFlags} - renderer := html.NewRenderer(opts) + htmlFlags := mdhtml.CommonFlags | mdhtml.HrefTargetBlank + opts := mdhtml.RendererOptions{Flags: htmlFlags} + renderer := mdhtml.NewRenderer(opts) output := string(markdown.Render(doc, renderer)) // Sanitize content