mirror of
https://github.com/aljazceru/njump.git
synced 2026-02-09 16:14:23 +01:00
syntax-highlight event JSON on the server.
This commit is contained in:
2
pages.go
2
pages.go
@@ -58,7 +58,7 @@ var (
|
||||
type DetailsPartial struct {
|
||||
HideDetails bool
|
||||
CreatedAt string
|
||||
EventJSON string
|
||||
EventJSON template.HTML
|
||||
Nevent string
|
||||
Kind int
|
||||
KindNIP string
|
||||
|
||||
@@ -196,9 +196,6 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Cache-Control", "max-age=60")
|
||||
}
|
||||
|
||||
// pretty JSON
|
||||
eventJSON, _ := json.MarshalIndent(data.event, "", " ")
|
||||
|
||||
// oembed discovery
|
||||
oembed := ""
|
||||
if data.templateId == Note {
|
||||
@@ -237,7 +234,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
CreatedAt: data.createdAt,
|
||||
KindDescription: data.kindDescription,
|
||||
KindNIP: data.kindNIP,
|
||||
EventJSON: string(eventJSON),
|
||||
EventJSON: eventToHTML(data.event),
|
||||
Kind: data.event.Kind,
|
||||
},
|
||||
ClientsPartial: ClientsPartial{
|
||||
@@ -274,7 +271,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
CreatedAt: data.createdAt,
|
||||
KindDescription: data.kindDescription,
|
||||
KindNIP: data.kindNIP,
|
||||
EventJSON: string(eventJSON),
|
||||
EventJSON: eventToHTML(data.event),
|
||||
Kind: data.event.Kind,
|
||||
},
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
@@ -30,9 +29,6 @@ func renderProfile(w http.ResponseWriter, r *http.Request, code string) {
|
||||
w.Header().Set("Cache-Control", "max-age=3600")
|
||||
}
|
||||
|
||||
// pretty JSON
|
||||
eventJSON, _ := json.MarshalIndent(data.event, "", " ")
|
||||
|
||||
if !isSitemap {
|
||||
err = ProfileTemplate.Render(w, &ProfilePage{
|
||||
HeadCommonPartial: HeadCommonPartial{IsProfile: true},
|
||||
@@ -41,7 +37,7 @@ func renderProfile(w http.ResponseWriter, r *http.Request, code string) {
|
||||
CreatedAt: data.createdAt,
|
||||
KindDescription: data.kindDescription,
|
||||
KindNIP: data.kindNIP,
|
||||
EventJSON: string(eventJSON),
|
||||
EventJSON: eventToHTML(data.event),
|
||||
Kind: data.event.Kind,
|
||||
},
|
||||
ClientsPartial: ClientsPartial{
|
||||
|
||||
@@ -165,37 +165,12 @@ body {
|
||||
margin-top: 0rem;
|
||||
}
|
||||
}
|
||||
.columnA .last_update {
|
||||
font-size: 0.8em;
|
||||
margin-top: 0.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
.theme--default .columnA .last_update {
|
||||
color: #c9c9c9;
|
||||
}
|
||||
.theme--dark .columnA .last_update {
|
||||
color: #969696;
|
||||
}
|
||||
@media (max-width: 580px) {
|
||||
.columnA .last_update {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.column_content {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.column_content a.nostr {
|
||||
border-bottom: none;
|
||||
}
|
||||
.theme--default .column_content a.nostr {
|
||||
background-color: #fdf0f5;
|
||||
}
|
||||
.theme--dark .column_content a.nostr {
|
||||
background-color: #42091e;
|
||||
}
|
||||
.column_content a.button {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
@@ -211,15 +186,6 @@ body {
|
||||
background-color: #e32a6d;
|
||||
border: 1px solid #e32a6d;
|
||||
}
|
||||
.column_content .label {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.theme--default .column_content .label {
|
||||
color: #e32a6d;
|
||||
}
|
||||
.theme--dark .column_content .label {
|
||||
color: #e32a6d;
|
||||
}
|
||||
.column_content blockquote {
|
||||
padding: 0.5rem 0 0.5rem 1rem;
|
||||
margin: 2rem 0;
|
||||
@@ -285,43 +251,6 @@ body {
|
||||
.theme--dark .column_content .footnotes {
|
||||
border-top: 6px solid #2d2d2d;
|
||||
}
|
||||
.column_content .json {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 0.9rem;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.column_content .json .key {
|
||||
display: inline-block;
|
||||
}
|
||||
.theme--default .column_content .json .key {
|
||||
color: #e32a6d;
|
||||
}
|
||||
.theme--dark .column_content .json .key {
|
||||
color: #e32a6d;
|
||||
}
|
||||
.theme--default .column_content .json .string {
|
||||
color: #373737;
|
||||
}
|
||||
.theme--dark .column_content .json .string {
|
||||
color: #fafafa;
|
||||
}
|
||||
.column_content .json .number {
|
||||
color: darkorange;
|
||||
}
|
||||
.theme--default .column_content .json .boolean {
|
||||
color: #373737;
|
||||
}
|
||||
.theme--dark .column_content .json .boolean {
|
||||
color: #fafafa;
|
||||
}
|
||||
.theme--default .column_content .json .null {
|
||||
color: #373737;
|
||||
}
|
||||
.theme--dark .column_content .json .null {
|
||||
color: #fafafa;
|
||||
}
|
||||
|
||||
.column_clients {
|
||||
position: -webkit-sticky;
|
||||
|
||||
@@ -300,37 +300,6 @@ body {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
.json {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 0.9rem;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
margin-top: 1rem;
|
||||
.key {
|
||||
display: inline-block;
|
||||
@include themed() {
|
||||
color: t($accent1);
|
||||
}
|
||||
}
|
||||
.string {
|
||||
@include themed() {
|
||||
color: t($base7);
|
||||
}
|
||||
}
|
||||
.number {
|
||||
color: darkorange;
|
||||
}
|
||||
.boolean {
|
||||
@include themed() {
|
||||
color: t($base7);
|
||||
}
|
||||
}
|
||||
.null {
|
||||
@include themed() {
|
||||
color: t($base7);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.column_clients {
|
||||
|
||||
@@ -61,39 +61,6 @@
|
||||
>
|
||||
Event JSON
|
||||
</div>
|
||||
<div class="json" _="on load call syntaxHighlight(me)">
|
||||
{{- .EventJSON}}
|
||||
</div>
|
||||
<div>{{- .EventJSON}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function syntaxHighlight(elt) {
|
||||
elt.innerHTML = elt.innerHTML
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(
|
||||
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
|
||||
function (match, p1) {
|
||||
var cls = 'number'
|
||||
if (/^"/.test(match)) {
|
||||
if (/:$/.test(match)) {
|
||||
cls = 'key'
|
||||
} else {
|
||||
if (p1.length < 100) {
|
||||
cls = 'string'
|
||||
} else {
|
||||
cls = 'string content'
|
||||
}
|
||||
}
|
||||
} else if (/true|false/.test(match)) {
|
||||
cls = 'boolean'
|
||||
} else if (/null/.test(match)) {
|
||||
cls = 'null'
|
||||
}
|
||||
return '<span class="' + cls + '">' + match + '</span>'
|
||||
}
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
49
utils.go
49
utils.go
@@ -2,7 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
html "html"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
@@ -11,7 +14,6 @@ import (
|
||||
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/ast"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
mdhtml "github.com/gomarkdown/markdown/html"
|
||||
"github.com/gomarkdown/markdown/parser"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
@@ -380,7 +382,7 @@ func mdToHTML(md string, usingTelegramInstantView bool) string {
|
||||
parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock | parser.Footnotes)
|
||||
doc := p.Parse([]byte(md))
|
||||
|
||||
var customNodeHook html.RenderNodeFunc = nil
|
||||
var customNodeHook mdhtml.RenderNodeFunc = nil
|
||||
if usingTelegramInstantView {
|
||||
// telegram instant view really doesn't like when there is an image inside a paragraph (like <p><img></p>)
|
||||
// so we use this custom thing to stop all paragraphs before the images, print the images then start a new
|
||||
@@ -390,12 +392,12 @@ func mdToHTML(md string, usingTelegramInstantView bool) string {
|
||||
if entering {
|
||||
src := img.Destination
|
||||
w.Write([]byte(`</p><img src="`))
|
||||
html.EscLink(w, src)
|
||||
mdhtml.EscLink(w, src)
|
||||
w.Write([]byte(`" alt="`))
|
||||
} else {
|
||||
if img.Title != nil {
|
||||
w.Write([]byte(`" title="`))
|
||||
html.EscapeHTML(w, img.Title)
|
||||
mdhtml.EscapeHTML(w, img.Title)
|
||||
}
|
||||
w.Write([]byte(`" /><p>`))
|
||||
}
|
||||
@@ -492,3 +494,42 @@ func loadRelaysArchive(ctx context.Context) {
|
||||
cache.SetWithTTL("ra:"+relay, nil, time.Hour*24*7)
|
||||
}
|
||||
}
|
||||
|
||||
func eventToHTML(evt *nostr.Event) template.HTML {
|
||||
tagsHTML := "["
|
||||
for t, tag := range evt.Tags {
|
||||
tagsHTML += "\n ["
|
||||
for i, item := range tag {
|
||||
cls := `"text-zinc-500 dark:text-zinc-50"`
|
||||
if i == 0 {
|
||||
cls = `"text-amber-500 dark:text-amber-200"`
|
||||
}
|
||||
itemJSON, _ := json.Marshal(item)
|
||||
tagsHTML += "\n <span class=" + cls + ">" + html.EscapeString(string(itemJSON))
|
||||
if i < len(tag)-1 {
|
||||
tagsHTML += ","
|
||||
}
|
||||
}
|
||||
tagsHTML += "\n ]"
|
||||
if t < len(evt.Tags)-1 {
|
||||
tagsHTML += ","
|
||||
}
|
||||
}
|
||||
tagsHTML += "\n ]"
|
||||
|
||||
contentJSON, _ := json.Marshal(evt.Content)
|
||||
|
||||
keyCls := "text-purple-700 dark:text-purple-300"
|
||||
|
||||
return template.HTML(fmt.Sprintf(
|
||||
`{
|
||||
<span class="`+keyCls+`">"id":</span> <span class="text-zinc-500 dark:text-zinc-50">"%s"</span>,
|
||||
<span class="`+keyCls+`">"pubkey":</span> <span class="text-zinc-500 dark:text-zinc-50">"%s"</span>,
|
||||
<span class="`+keyCls+`">"created_at":</span> <span class="text-green-600">%d</span>,
|
||||
<span class="`+keyCls+`">"kind":</span> <span class="text-amber-500 dark:text-amber-200">%d</span>,
|
||||
<span class="`+keyCls+`">"tags":</span> %s,
|
||||
<span class="`+keyCls+`">"content":</span> <span class="text-zinc-500 dark:text-zinc-50">%s</span>,
|
||||
<span class="`+keyCls+`">"sig":</span> <span class="text-zinc-500 dark:text-zinc-50 content">"%s"</span>
|
||||
}`, evt.ID, evt.PubKey, evt.CreatedAt, evt.Kind, tagsHTML, html.EscapeString(string(contentJSON)), evt.Sig),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user