diff --git a/.gitignore b/.gitignore
index 3e56dee..3b235c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,5 @@
njump
+.air.toml
+tmp/
+node_modules/
+.sass-cache/
\ No newline at end of file
diff --git a/go.mod b/go.mod
index cf0ba51..8c7b211 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
github.com/die-net/lrucache v0.0.0-20220628165024-20a71bc65bf1
github.com/lukevers/freetype-go v0.0.0-20150513150840-77e276735410
github.com/mailru/easyjson v0.7.7
- github.com/nbd-wtf/go-nostr v0.18.1-0.20230509030905-52a493fd9666
+ github.com/nbd-wtf/go-nostr v0.18.4
github.com/pelletier/go-toml v1.9.5
golang.org/x/image v0.0.0-20190802002840-cff245a6509b
)
@@ -23,6 +23,9 @@ require (
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
+ github.com/tidwall/gjson v1.14.4 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.0 // indirect
golang.org/x/exp v0.0.0-20221106115401-f9659909a136 // indirect
golang.org/x/sys v0.6.0 // indirect
)
diff --git a/go.sum b/go.sum
index 65fea02..7800b26 100644
--- a/go.sum
+++ b/go.sum
@@ -69,8 +69,12 @@ github.com/lukevers/freetype-go v0.0.0-20150513150840-77e276735410 h1:ED5jVfC//X
github.com/lukevers/freetype-go v0.0.0-20150513150840-77e276735410/go.mod h1:cnsFc3HOpydgckvXF3xq4fvlLFOAuTh4VyJ118x8LQc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/nbd-wtf/go-nostr v0.18.1-0.20230509030905-52a493fd9666 h1:dWnwxgOl+dnVsKQLoNo5TaYJB7opG3LUIZ0YPl63iQI=
-github.com/nbd-wtf/go-nostr v0.18.1-0.20230509030905-52a493fd9666/go.mod h1:fN8trCzHEtsf2954h8neqNERM/OXnCYI71nA4wWCobI=
+github.com/nbd-wtf/go-nostr v0.18.4-0.20230514132335-123d3a6a9ab1 h1:rfkAcjBBR7j9aHRYIn+VjCO12lt8Bero5/cYPmO6Q6Q=
+github.com/nbd-wtf/go-nostr v0.18.4-0.20230514132335-123d3a6a9ab1/go.mod h1:GPJOOK8US38kz+bfb9nWe873Xu0e6bXlThejOs1LTkc=
+github.com/nbd-wtf/go-nostr v0.18.4-0.20230525112312-5c0f8bff83ea h1:L4eHtPd5bgj7Cl9j+TA5fZaQGVPt8SunZhqNtMbqzWo=
+github.com/nbd-wtf/go-nostr v0.18.4-0.20230525112312-5c0f8bff83ea/go.mod h1:GPJOOK8US38kz+bfb9nWe873Xu0e6bXlThejOs1LTkc=
+github.com/nbd-wtf/go-nostr v0.18.4 h1:P5qHEvvwS6DMaDMD82fP66M3kFBJnNQATczGH93rC0s=
+github.com/nbd-wtf/go-nostr v0.18.4/go.mod h1:GPJOOK8US38kz+bfb9nWe873Xu0e6bXlThejOs1LTkc=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -92,6 +96,12 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
+github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
+github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
diff --git a/justfile b/justfile
index 414a988..2716fa3 100644
--- a/justfile
+++ b/justfile
@@ -6,3 +6,7 @@ deploy: build
rsync njump turgot:njump/njump-new
ssh turgot 'mv njump/njump-new njump/njump'
ssh root@turgot 'systemctl start njump'
+
+refresh_build:
+ sass static/styles.scss static/styles.css
+ go build -o ./tmp/main .
\ No newline at end of file
diff --git a/main.go b/main.go
index f28cec2..fd2997f 100644
--- a/main.go
+++ b/main.go
@@ -7,6 +7,9 @@ import (
)
func main() {
+
+ http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
+
http.HandleFunc("/image/", generate)
http.HandleFunc("/proxy/", proxy)
http.HandleFunc("/", render)
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..38ebbae
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,212 @@
+{
+ "name": "njump",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "sass": "^1.62.1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/immutable": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
+ "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg=="
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/sass": {
+ "version": "1.62.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
+ "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..1e435dc
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "sass": "^1.62.1"
+ }
+}
diff --git a/render.go b/render.go
index e2990f6..b159643 100644
--- a/render.go
+++ b/render.go
@@ -4,19 +4,24 @@ import (
_ "embed"
"encoding/json"
"fmt"
+ "html"
"net/http"
"regexp"
"strings"
"text/template"
-
+ "time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
)
-//go:embed event.html
-var eventHTML string
+//go:embed static/raw.html
+var rawHTML string
-var tmpl = template.Must(template.New("event").Parse(eventHTML))
+//go:embed static/profile.html
+var profileHTML string
+
+//go:embed static/note.html
+var noteHTML string
func render(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.URL.Path, ":~", r.Header.Get("user-agent"))
@@ -48,10 +53,11 @@ func render(w http.ResponseWriter, r *http.Request) {
npub, _ := nip19.EncodePublicKey(event.PubKey)
nevent, _ := nip19.EncodeEvent(event.ID, []string{}, event.PubKey)
naddr := ""
+ createdAt := time.Unix(int64(event.CreatedAt), 0).Format("2006-01-02 15:04:05")
author := event
if event.Kind != 0 {
- typ = "event"
+ typ = "note"
author, _ = getEvent(r.Context(), npub)
if event.Kind >= 30000 && event.Kind < 40000 {
@@ -154,19 +160,24 @@ func render(w http.ResponseWriter, r *http.Request) {
description = prettyJsonOrRaw(event.Content)
}
+ content := prettyJsonOrRaw(event.Content)
+
eventJSON, _ := json.MarshalIndent(event, "", " ")
params := map[string]any{
+ "createdAt": createdAt,
"clients": generateClientList(code, event),
"type": typ,
"title": title,
"twitterTitle": twitterTitle,
"npub": npub,
+ "npubShort": npubShort,
"nevent": nevent,
"naddr": naddr,
"metadata": metadata,
"authorLong": authorLong,
"description": description,
+ "content": content,
"textImageURL": textImageURL,
"videoType": videoType,
"image": image,
@@ -174,6 +185,25 @@ func render(w http.ResponseWriter, r *http.Request) {
"proxy": "https://" + hostname + "/proxy?src=",
"eventJSON": string(eventJSON),
}
+
+ templates := make(map[string]string)
+ templates["profile"] = profileHTML
+ templates["note"] = noteHTML
+ templates["address"] = rawHTML
+
+ var funcMap = template.FuncMap{
+ "BasicFormatting": BasicFormatting,
+ "SanitizeString": html.EscapeString,
+ }
+
+ tmpl, err := template.Must(template.New("event").
+ Funcs(funcMap).
+ Parse(templates[typ])).
+ ParseFiles("static/head.html", "static/top.html", "static/column_clients.html", "static/footer.html", "static/scripts.js")
+ if err != nil {
+ // Handle error
+ }
+
if err := tmpl.ExecuteTemplate(w, "event", params); err != nil {
http.Error(w, "error rendering: "+err.Error(), 500)
return
diff --git a/static/column_clients.html b/static/column_clients.html
new file mode 100644
index 0000000..a5bc312
--- /dev/null
+++ b/static/column_clients.html
@@ -0,0 +1,22 @@
+
+
+
Open {{.type}} in
+
+
+
+
+
+
+
+
+ {{range .clients}}
+
+ {{end}}
+
+
\ No newline at end of file
diff --git a/static/footer.html b/static/footer.html
new file mode 100644
index 0000000..f10d5c7
--- /dev/null
+++ b/static/footer.html
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/static/head.html b/static/head.html
new file mode 100644
index 0000000..e8172b4
--- /dev/null
+++ b/static/head.html
@@ -0,0 +1,51 @@
+
+ {{if eq .type "profile"}}
+ Nostr Public Key {{.npub}}
+
+
+ {{ if .metadata.Picture }}
+
+
+ {{end}} {{ if .metadata.About }}
+
+ {{end}}
+
+ {{end}}
+
+ {{ if eq .type "event" }}
+ Nostr Event {{.nevent}}
+
+
+
+
+ {{ if .textImageURL }}
+
+
+
+
+ {{ else }}
+
+
+ {{ if .image }}
+
+
+ {{end}} {{ if .video }}
+
+
+
+ {{end}}
+
+ {{end}}
+
+
+ {{end}}
+
+ {{ if eq .type "address" }}
+ Nostr Address {{.naddr | SanitizeString }}
+ {{end}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/static/note.html b/static/note.html
new file mode 100644
index 0000000..1c1e783
--- /dev/null
+++ b/static/note.html
@@ -0,0 +1,81 @@
+
+
+
+ {{template "head.html" .}}
+
+
+
+ {{template "top.html" .}}
+
+
+
+
+
+
+
+
+
+
+
+ {{.content | SanitizeString | BasicFormatting }}
+
+
+
+
+
+
Author Public key
+ {{.npub}}
+
+
+
+ Last update:
+ {{.createdAt | SanitizeString}}
+
+
+
+
+
+
+
+
+
+
Nevent
+
{{.nevent | SanitizeString}}
+
+
+
+
Event JSON
+
{{.eventJSON | SanitizeString}}
+
+
+
+
+ {{template "column_clients.html" .}}
+
+
+
+
+ {{template "footer.html"}}
+
+
+
+
+
+
diff --git a/static/profile.html b/static/profile.html
new file mode 100644
index 0000000..96b2721
--- /dev/null
+++ b/static/profile.html
@@ -0,0 +1,89 @@
+
+
+
+ {{template "head.html" .}}
+
+
+
+ {{template "top.html" .}}
+
+
+
+
+
+
+ {{.metadata.Name | SanitizeString}} {{.metadata.DisplayName | SanitizeString}}
+
+
+

+
+
+ Last update:
+ {{.createdAt | SanitizeString}}
+
+
+
+
+
+
+ {{.metadata.Name | SanitizeString}} {{.metadata.DisplayName | SanitizeString}}
+
+
+
+
+
+ {{.metadata.About | SanitizeString}}
+
+
+
+
Public key
+ {{.npub | SanitizeString}}
+
+
+
NIP-05
+ {{.metadata.NIP05 | SanitizeString}}
+
+
+
LN Address
+ {{.metadata.LUD16 | SanitizeString}}
+
+
+
+ Last update:
+ {{.createdAt | SanitizeString}}
+
+
+
+
+
+
+
+
+
+
Metadata Event
+
{{.nevent | SanitizeString}}
+
+
+
+
Event JSON
+
{{.eventJSON}}
+
+
+
+
+ {{template "column_clients.html" .}}
+
+
+
+
+ {{template "footer.html"}}
+
+
+
+
+
+
diff --git a/event.html b/static/raw.html
similarity index 100%
rename from event.html
rename to static/raw.html
diff --git a/static/scripts.js b/static/scripts.js
new file mode 100644
index 0000000..5496306
--- /dev/null
+++ b/static/scripts.js
@@ -0,0 +1,97 @@
+const type = '{{.type}}'
+let counts = []
+let clients = document.querySelectorAll('.client')
+for (let i = 0; i < clients.length; i++) {
+ let name = clients[i].innerText
+ let url = clients[i].href
+ let key = 'nj:' + type + ':' + name
+ let count = parseInt(localStorage.getItem(key) || 0)
+ clients[i].parentNode.setAttribute('count', count)
+ clients[i].parentNode.setAttribute('title', 'Used ' + count + ' times')
+ clients[i].addEventListener('click', () => {
+ localStorage.setItem(key, count + 1)
+ })
+ counts.push([count, name, url])
+}
+
+// Reorder clients following the counter
+let clients_wrapper = document.querySelector('.clients_wrapper')
+const elements = Array.from(clients_wrapper.getElementsByClassName('btn'))
+elements.sort((a, b) => {
+ const rankA = parseInt(a.getAttribute('count'))
+ const rankB = parseInt(b.getAttribute('count'))
+ return rankB - rankA
+})
+elements.forEach(element => clients_wrapper.appendChild(element))
+
+counts.sort((a, b) => b[0] - a[0])
+let tailsum = counts.slice(1).reduce((acc, c) => acc + c[0], 0)
+
+if (location.hash !== '#noredirect') {
+ if (counts[0][0] - tailsum > 10) {
+ location.href = counts[0][2]
+ }
+}
+
+let jsons = document.querySelectorAll('.json')
+for (let i = 0; i < jsons.length; i++) {
+ console.log(jsons[i].innerHTML)
+ jsons[i].innerHTML = syntaxHighlight(jsons[i].innerHTML)
+}
+
+const shareButton = document.querySelector('.open-list')
+const clients_list = document.querySelector('.column_clients')
+shareButton.addEventListener('click', function () {
+ clients_list.classList.toggle('up')
+ if (clients_list.classList.contains('up')) {
+ document.body.classList.add('lock')
+ } else {
+ document.body.classList.remove('lock')
+ }
+})
+
+function updateAdvanceSwitch() {
+ advanced_list.forEach(element => {
+ if (advanceSwitch.checked) {
+ element.classList.add('visible')
+ } else {
+ element.classList.remove('visible')
+ }
+ })
+}
+
+const advanceSwitch = document.querySelector('.advanced-switch')
+const advanced_list = document.querySelectorAll('.advanced')
+advanceSwitch.addEventListener('change', function () {
+ updateAdvanceSwitch()
+})
+
+updateAdvanceSwitch() // Check at the page load, some browsers keep the state in cache
+
+var url = new URL(window.location.href)
+var searchParams = new URLSearchParams(url.search)
+if (searchParams.has('details') && searchParams.get('details') == 'yes') {
+ advanceSwitch.click()
+}
+
+function syntaxHighlight(json) {
+ json = json.replace(/&/g, '&').replace(//g, '>')
+ return json.replace(
+ /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
+ function (match) {
+ var cls = 'number'
+ if (/^"/.test(match)) {
+ if (/:$/.test(match)) {
+ cls = 'key'
+ } else {
+ cls = 'string'
+ }
+ } else if (/true|false/.test(match)) {
+ cls = 'boolean'
+ } else if (/null/.test(match)) {
+ cls = 'null'
+ }
+ return '' + match + ''
+ }
+ )
+}
\ No newline at end of file
diff --git a/static/styles.css b/static/styles.css
new file mode 100644
index 0000000..21c833c
--- /dev/null
+++ b/static/styles.css
@@ -0,0 +1,657 @@
+
+html {
+ font-family: Helvetica, sans-serif;
+ font-size: 19px;
+ font-weight: 300;
+}
+@media (max-width: 580px) {
+ html {
+ font-size: 18px;
+ }
+}
+
+body {
+ margin: 0;
+ margin-bottom: 4rem;
+}
+.theme--default body {
+ color: #373737;
+}
+.theme--dark body {
+ color: #FAFAFA;
+}
+@media (max-width: 580px) {
+ body.lock {
+ overflow: hidden;
+ }
+}
+
+.theme--default a {
+ color: #373737;
+}
+.theme--dark a {
+ color: #FAFAFA;
+}
+
+.background {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ overflow: hidden;
+ z-index: -1;
+}
+.theme--default .background {
+ background: #FFFFFF;
+}
+.theme--dark .background {
+ background: #1e1e1e;
+}
+.background::after {
+ content: "";
+ position: absolute;
+ width: 140%;
+ height: 100%;
+ transform: rotate(-20deg);
+ transform-origin: bottom;
+ bottom: -40%;
+}
+.theme--default .background::after {
+ background: #FFFFFF;
+}
+.theme--dark .background::after {
+ background: #181818;
+}
+@media (max-width: 580px) {
+ .background::after {
+ width: 200%;
+ bottom: -40%;
+ }
+}
+
+.theme-toggle {
+ position: fixed;
+ top: 1rem;
+ right: 1rem;
+ width: 1rem;
+ height: 1rem;
+ border-radius: 50%;
+ cursor: pointer;
+}
+.theme--default .theme-toggle {
+ color: #F3F3F3;
+}
+.theme--dark .theme-toggle {
+ color: #9a9a9a;
+}
+@media (max-width: 580px) {
+ .theme-toggle {
+ position: relative;
+ float: right;
+ top: 0;
+ right: 0;
+ }
+}
+
+.sun {
+ display: none;
+}
+
+.moon {
+ display: block;
+}
+
+.theme--dark .sun {
+ display: block;
+}
+.theme--dark .moon {
+ display: none;
+}
+
+.top {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 1rem 0;
+ justify-content: left;
+}
+@media (max-width: 580px) {
+ .top {
+ display: block;
+ width: 90%;
+ margin: 1rem auto 1rem auto;
+ font-size: 0.8rem;
+ }
+}
+.theme--default .top span {
+ color: #E32A6D;
+}
+.theme--dark .top span {
+ color: #E32A6D;
+}
+
+.pic-wrapper {
+ max-width: 100%;
+ overflow: hidden;
+}
+@media (max-width: 580px) {
+ .pic-wrapper {
+ flex-basis: 40%;
+ }
+}
+.pic-wrapper img.pic {
+ max-width: 100%;
+ width: 100%;
+ height: auto;
+ -webkit-clip-path: url(#svg-shape);
+ -moz-clip-path: url(#svg-shape);
+ -o-clip-path: url(#svg-shape);
+ -ms-clip-path: url(#svg-shape);
+ clip-path: url(#svg-shape);
+}
+
+.container_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+@media (max-width: 580px) {
+ .container_wrapper {
+ display: block;
+ padding: 0 1rem;
+ margin: 0 auto;
+ }
+}
+
+.nostr_link {
+ flex-basis: 15%;
+ text-align: right;
+ text-decoration: none;
+}
+
+.container {
+ display: flex;
+ width: 70%;
+ justify-content: space-between;
+ gap: 4.8vw;
+}
+@media (max-width: 580px) {
+ .container {
+ display: block;
+ width: 100%;
+ }
+}
+.container .columnA {
+ flex-basis: 25%;
+ margin-top: 2rem;
+}
+@media (max-width: 580px) {
+ .container .columnA {
+ display: flex;
+ align-items: center;
+ margin-top: 0rem;
+ }
+}
+.container .columnA .info-wrapper {
+ display: none;
+}
+@media (max-width: 580px) {
+ .container .columnA .info-wrapper {
+ display: block;
+ flex-basis: 64%;
+ max-width: 64%;
+ overflow: hidden;
+ font-size: 1.6rem;
+ }
+ .container .columnA .info-wrapper .display {
+ display: block;
+ font-size: 1.2rem;
+ }
+ .theme--default .container .columnA .info-wrapper .display {
+ color: #C9C9C9;
+ }
+ .theme--dark .container .columnA .info-wrapper .display {
+ color: #C9C9C9;
+ }
+}
+.container .columnA .last_update {
+ font-size: 0.8em;
+ margin-top: 0.5rem;
+ text-align: center;
+}
+.theme--default .container .columnA .last_update {
+ color: #C9C9C9;
+}
+.theme--dark .container .columnA .last_update {
+ color: #C9C9C9;
+}
+@media (max-width: 580px) {
+ .container .columnA .last_update {
+ display: none;
+ }
+}
+.container .column_content {
+ flex-grow: 0;
+ flex-shrink: 0;
+ word-wrap: break-word;
+ margin-right: 1vw;
+}
+.container .column_content .info-wrapper {
+ font-size: 1.6rem;
+}
+.theme--default .container .column_content .info-wrapper .display {
+ color: #C9C9C9;
+}
+.theme--dark .container .column_content .info-wrapper .display {
+ color: #C9C9C9;
+}
+.container .column_content .info-wrapper .npub {
+ font-size: 1rem;
+}
+.theme--default .container .column_content .info-wrapper .npub {
+ color: #C9C9C9;
+}
+.theme--dark .container .column_content .info-wrapper .npub {
+ color: #C9C9C9;
+}
+@media (max-width: 580px) {
+ .container .column_content .info-wrapper {
+ display: none;
+ }
+}
+.container .column_content .separator {
+ height: 6px;
+ width: 30%;
+ margin-left: -0.6rem;
+}
+.theme--default .container .column_content .separator {
+ background: #F3F3F3;
+}
+.theme--dark .container .column_content .separator {
+ background: #232323;
+}
+.container .column_content .separator.long {
+ width: 50%;
+}
+@media (max-width: 580px) {
+ .container .column_content .separator {
+ margin-left: -1rem;
+ }
+}
+.container .column_content .field {
+ margin-bottom: 1.5rem;
+}
+.container .column_content .field .label {
+ font-size: 0.8rem;
+}
+.theme--default .container .column_content .field .label {
+ color: #E32A6D;
+}
+.theme--dark .container .column_content .field .label {
+ color: #E32A6D;
+}
+.container .column_content .field.advanced {
+ display: none;
+}
+.container .column_content .field.advanced.visible {
+ display: block;
+}
+.container .column_content .field.advanced.boxed {
+ padding: 0 1rem 1rem;
+ margin-left: -1rem;
+ margin-right: -1rem;
+}
+.theme--default .container .column_content .field.advanced.boxed {
+ background: #F3F3F3;
+}
+.theme--dark .container .column_content .field.advanced.boxed {
+ background: #131313;
+}
+.container .column_content .field.advanced.boxed .label {
+ padding: 0.2rem 1rem;
+ margin: 0 -1rem;
+}
+.theme--default .container .column_content .field.advanced.boxed .label {
+ color: #373737;
+}
+.theme--dark .container .column_content .field.advanced.boxed .label {
+ color: #9a9a9a;
+}
+.theme--default .container .column_content .field.advanced.boxed .label {
+ background: #C9C9C9;
+}
+.theme--dark .container .column_content .field.advanced.boxed .label {
+ background: #191919;
+}
+.container .column_content .field.advanced-switch-wrapper {
+ display: flex;
+ align-items: center;
+}
+.container .column_content .field.advanced-switch-wrapper input[type=checkbox] {
+ height: 0;
+ width: 0;
+ visibility: hidden;
+ display: none;
+}
+.container .column_content .field.advanced-switch-wrapper label:first-of-type {
+ cursor: pointer;
+ text-indent: -9999px;
+ width: 2.6rem;
+ height: 1.2rem;
+ background: #3d3d3d;
+ display: inline-block;
+ border-radius: 100px;
+ position: relative;
+ margin-right: 0.5rem;
+}
+@media (max-width: 580px) {
+ .container .column_content .field.advanced-switch-wrapper label:first-of-type {
+ width: 3rem;
+ height: 1.4rem;
+ }
+}
+.container .column_content .field.advanced-switch-wrapper label:first-of-type:after {
+ content: "";
+ position: absolute;
+ top: 2px;
+ left: 2px;
+ width: 1rem;
+ height: 1rem;
+ background: #fff;
+ border-radius: 1rem;
+ transition: 0.2s;
+}
+@media (max-width: 580px) {
+ .container .column_content .field.advanced-switch-wrapper label:first-of-type:after {
+ width: 1.2rem;
+ height: 1.2rem;
+ }
+}
+.theme--default .container .column_content .field.advanced-switch-wrapper input:checked + label {
+ background: #E32A6D;
+}
+.theme--dark .container .column_content .field.advanced-switch-wrapper input:checked + label {
+ background: #E32A6D;
+}
+.container .column_content .field.advanced-switch-wrapper input:checked + label:first-of-type:after {
+ left: calc(100% - 2px);
+ transform: translateX(-100%);
+}
+.container .column_content .field.advanced-switch-wrapper label:first-of-type:active:after {
+ width: 2rem;
+}
+.container .column_content .field.content {
+ line-height: 1.4rem;
+}
+.container .column_content .field.content img {
+ max-width: 100%;
+ margin: 1rem 0;
+}
+.container .column_content .field .json, .container .column_content .field .data {
+ white-space: pre-wrap;
+ word-break: break-all;
+ margin-top: 1rem;
+}
+.container .column_content .field .json .key, .container .column_content .field .data .key {
+ display: inline-block;
+ margin-top: 0.5rem;
+}
+.theme--default .container .column_content .field .json .key, .theme--default .container .column_content .field .data .key {
+ color: #E32A6D;
+}
+.theme--dark .container .column_content .field .json .key, .theme--dark .container .column_content .field .data .key {
+ color: #E32A6D;
+}
+.theme--default .container .column_content .field .json .string, .theme--default .container .column_content .field .data .string {
+ color: #373737;
+}
+.theme--dark .container .column_content .field .json .string, .theme--dark .container .column_content .field .data .string {
+ color: #FAFAFA;
+}
+.container .column_content .field .json .number, .container .column_content .field .data .number {
+ color: darkorange;
+}
+.theme--default .container .column_content .field .json .boolean, .theme--default .container .column_content .field .data .boolean {
+ color: #373737;
+}
+.theme--dark .container .column_content .field .json .boolean, .theme--dark .container .column_content .field .data .boolean {
+ color: #FAFAFA;
+}
+.theme--default .container .column_content .field .json .null, .theme--default .container .column_content .field .data .null {
+ color: #373737;
+}
+.theme--dark .container .column_content .field .json .null, .theme--dark .container .column_content .field .data .null {
+ color: #FAFAFA;
+}
+.container .column_content .field.last_update {
+ display: none;
+}
+@media (max-width: 580px) {
+ .container .column_content .field.last_update {
+ display: block;
+ font-size: 0.8em;
+ }
+ .theme--default .container .column_content .field.last_update {
+ color: #C9C9C9;
+ }
+ .theme--dark .container .column_content .field.last_update {
+ color: #C9C9C9;
+ }
+}
+.container .column_clients {
+ flex-basis: 25%;
+ margin-top: 2rem;
+}
+@media (max-width: 580px) {
+ .container .column_clients {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ transition: all 500ms ease-in-out;
+ }
+ .container .column_clients.up .btn {
+ display: block;
+ }
+ .container .column_clients.up .title span.open {
+ display: none;
+ }
+}
+.container .column_clients .title {
+ font-size: 0.8rem;
+ margin-bottom: 1rem;
+ text-align: center;
+}
+.container .column_clients .title span.open, .container .column_clients .title span.close {
+ display: none;
+}
+@media (max-width: 580px) {
+ .container .column_clients .title {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 2.6rem;
+ height: 2.6rem;
+ border-left: 1px solid #bc1150;
+ }
+ .container .column_clients .title span.text {
+ display: none;
+ }
+ .container .column_clients .title span.open, .container .column_clients .title span.close {
+ display: inline;
+ }
+ .container .column_clients .title span.open svg, .container .column_clients .title span.close svg {
+ width: 50%;
+ height: 50%;
+ margin: 28% auto auto auto;
+ display: block;
+ }
+}
+.container .column_clients .btn {
+ display: flex;
+ align-items: center;
+ margin-bottom: 0.8rem;
+}
+@media (max-width: 580px) {
+ .container .column_clients .btn {
+ display: none;
+ margin-bottom: 0;
+ }
+}
+.container .column_clients .btn a {
+ flex-basis: 100%;
+ padding: 0.4rem;
+ text-align: center;
+ font-size: 0.9rem;
+ color: #FFFFFF;
+ background-color: #3d3d3d;
+ border-bottom: 1px solid #131313;
+ text-decoration: none;
+ border-radius: 8px;
+}
+@media (max-width: 580px) {
+ .container .column_clients .btn a {
+ display: block;
+ padding: 0.8rem;
+ border-radius: 0px;
+ font-weight: 400;
+ text-align: left;
+ }
+}
+.container .column_clients .btn a span {
+ display: none;
+}
+@media (max-width: 580px) {
+ .container .column_clients .btn a span {
+ display: inline;
+ color: #FFFFFF;
+ }
+}
+.container .column_clients .btn a:hover {
+ background: #373737;
+}
+@media (max-width: 580px) {
+ .container .column_clients .btn:first-of-type {
+ display: block;
+ }
+}
+.container .column_clients .btn:first-of-type a {
+ border-bottom: none;
+}
+.theme--default .container .column_clients .btn:first-of-type a {
+ background: #E32A6D;
+}
+.theme--dark .container .column_clients .btn:first-of-type a {
+ background: #E32A6D;
+}
+@media (max-width: 580px) {
+ .container .column_clients .btn:first-of-type a {
+ border-radius: 8px 8px 0 0;
+ }
+}
+.theme--default .container .column_clients .btn:first-of-type a:hover {
+ background: #bc1150;
+}
+.theme--dark .container .column_clients .btn:first-of-type a:hover {
+ background: #bc1150;
+}
+.container .column_clients .btn span {
+ flex-basis: 20%;
+ margin-left: 0.4rem;
+ color: #FFFFFF;
+}
+@media (max-width: 580px) {
+ .container .column_clients .btn span {
+ display: none;
+ }
+}
+
+body.profile .column_content {
+ flex-basis: 50%;
+ max-width: 50%;
+}
+@media (max-width: 580px) {
+ body.profile .column_content {
+ flex-basis: 100%;
+ max-width: 100%;
+ margin-right: 0;
+ }
+}
+
+body.note .column_content {
+ flex-basis: 70%;
+ max-width: 70%;
+}
+@media (max-width: 580px) {
+ body.note .column_content {
+ flex-basis: 100%;
+ max-width: 100%;
+ margin-right: 0;
+ }
+}
+body.note .column_content .profile_intro {
+ display: flex;
+ max-width: 100%;
+ align-items: center;
+}
+body.note .column_content .profile_intro a {
+ display: inherit;
+ align-items: inherit;
+ margin: 1rem 0 1rem 0;
+ text-decoration: none;
+ flex-wrap: wrap;
+}
+@media (max-width: 580px) {
+ body.note .column_content .profile_intro a {
+ margin-top: 0rem;
+ margin-bottom: -0.5rem;
+ }
+}
+body.note .column_content .profile_intro .info-wrapper {
+ flex-basis: 80%;
+}
+@media (max-width: 580px) {
+ body.note .column_content .profile_intro .info-wrapper {
+ display: block;
+ }
+}
+@media (max-width: 580px) {
+ body.note .column_content .profile_intro .info-wrapper .name, body.note .column_content .profile_intro .info-wrapper .npub {
+ display: block-inline;
+ font-size: 0.9rem;
+ }
+}
+body.note .column_content .profile_intro .pic-wrapper {
+ flex-basis: 16%;
+ margin-right: 1rem;
+}
+@media (max-width: 580px) {
+ body.note .column_content .profile_intro .pic-wrapper {
+ margin-right: 0.5rem;
+ }
+}
+body.note .column_content .profile_intro .published_at {
+ flex-grow: 1;
+ text-align: right;
+ align-self: end;
+ font-size: 0.8rem;
+}
+.theme--default body.note .column_content .profile_intro .published_at {
+ color: #9a9a9a;
+}
+.theme--dark body.note .column_content .profile_intro .published_at {
+ color: #F3F3F3;
+}
+@media (max-width: 580px) {
+ body.note .column_content .profile_intro .published_at {
+ padding-top: 0.5rem;
+ }
+}
+
+.footer {
+ font-size: 0.8rem;
+ text-align: center;
+}
+
+/*# sourceMappingURL=styles.css.map */
diff --git a/static/styles.css.map b/static/styles.css.map
new file mode 100644
index 0000000..2b34ac3
--- /dev/null
+++ b/static/styles.css.map
@@ -0,0 +1 @@
+{"version":3,"sourceRoot":"","sources":["styles.scss"],"names":[],"mappings":";AAoFA;EACC;EACA;EACA;;AACA;EAJD;IAKE;;;;AAGF;EAIC;EACA;;AA9BG;EA2BA;;AA3BA;EA2BA;;AAKF;EADD;IAEE;;;;AAjCC;EAuCA;;AAvCA;EAuCA;;;AAGJ;EACC;EACA;EACA;EACA;EACA;EAIA;EACA;;AApDG;EAiDF;;AAjDE;EAiDF;;AAID;EACC;EACA;EAIA;EACA;EACA;EACA;EACA;;AA/DE;EAyDD;;AAzDC;EAyDD;;AAOD;EAXD;IAYE;IACA;;;;AAKH;EACC;EACA;EACA;EACA;EACA;EAKA;EACA;;AAlFG;EA8EF;;AA9EE;EA8EF;;AAKD;EAZD;IAaE;IACE;IACA;IACA;;;;AAIJ;EACC;;;AAED;EACC;;;AAIA;EACC;;AAED;EACC;;;AAIF;EACC;EACA;EACA;EACA;EACA;;AACA;EAND;IAOE;IACA;IACA;IACA;;;AArHE;EAyHD;;AAzHC;EAyHD;;;AAKH;EACC;EACA;;AACA;EAHD;IAIE;;;AAED;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACC;EACA;EACA;;AACC;EAJF;IAKE;IACE;IACF;;;;AAGF;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;;AAEC;EANF;IAOE;IACE;;;AAGH;EACC;EACA;;AACA;EAHD;IAIE;IACA;IACA;;;AAED;EACC;;AACA;EAFD;IAGE;IACA;IACA;IACA;IACA;;EACA;IACC;IACA;;EA7LD;IA+LE;;EA/LF;IA+LE;;;AAKJ;EACC;EACA;EACA;;AAvMC;EAyMA;;AAzMA;EAyMA;;AAED;EAPD;IAQE;;;AAIH;EAEC;EACA;EACA;EACA;;AAEA;EACC;;AAxNC;EA2NC;;AA3ND;EA2NC;;AAGF;EACC;;AA/NA;EAiOC;;AAjOD;EAiOC;;AAGF;EAbD;IAcE;;;AAGF;EACC;EACA;EACA;;AA3OC;EA6OA;;AA7OA;EA6OA;;AAED;EACC;;AAED;EAVD;IAWE;;;AAGF;EACC;;AACA;EACC;;AAzPA;EA2PC;;AA3PD;EA2PC;;AAGF;EACC;;AACA;EACC;;AAED;EACC;EACA;EACA;;AAtQD;EAwQE;;AAxQF;EAwQE;;AAED;EACC;EACA;;AA5QF;EA8QG;;AA9QH;EA8QG;;AA9QH;EAiRG;;AAjRH;EAiRG;;AAKJ;EACC;EACA;;AAEA;EACC;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA,YAnWS;EAoWT;EACA;EACA;EACA;;AACA;EAVD;IAWE;IACA;;;AAIF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EAVD;IAWE;IACA;;;AA7TF;EAmUE;;AAnUF;EAmUE;;AAIF;EACC;EACA;;AAGD;EACC;;AAIF;EACC;;AACA;EACC;EACA;;AAGF;EACC;EACA;EACA;;AACA;EACC;EACA;;AA9VD;EAgWE;;AAhWF;EAgWE;;AAhWF;EAqWI;;AArWJ;EAqWI;;AAGJ;EAAU;;AAxWV;EA2WI;;AA3WJ;EA2WI;;AA3WJ;EAgXI;;AAhXJ;EAgXI;;AAIL;EACC;;AACA;EAFD;IAGE;IACA;;EAxXD;IA0XE;;EA1XF;IA0XE;;;AAQL;EACC;EACA;;AACA;EAHD;IAIE;IAEA;IACA;IACA;IACA;;EAEC;IACC;;EAED;IACC;;;AAIH;EACC;EACA;EACA;;AACA;EACC;;AAED;EAPD;IAQE;IACA;IACA;IACA;IACA;IACA;;EACA;IACC;;EAED;IACC;;EACA;IACC;IACA;IACA;IACA;;;AAKJ;EACC;EACA;EACA;;AACA;EAJD;IAKE;IACA;;;AAED;EACC;EACA;EACA;EACA;EACA,OAhgBU;EAigBV,kBA5fU;EA6fV;EACA;EACA;;AACA;EAVD;IAWE;IACA;IACA;IACA;IACA;;;AAED;EACC;;AACA;EAFD;IAGE;IACA,OAhhBQ;;;AAmhBV;EACC,YA9gBS;;AAkhBV;EADD;IAEE;;;AAED;EAIC;;AA7dD;EA2dG;;AA3dH;EA2dG;;AAGF;EALD;IAME;;;AA/dF;EAmeG;;AAneH;EAmeG;;AAKJ;EACC;EACA;EACA,OA7iBU;;AA8iBV;EAJD;IAKE;;;;AASJ;EACC;EACA;;AACA;EAHD;IAIE;IACA;IACA;;;;AAMF;EACC;EACA;;AACA;EAHD;IAIE;IACA;IACA;;;AAED;EACC;EACA;EACA;;AACA;EACC;EACA;EACA;EACA;EACA;;AACA;EAND;IAOE;IACA;;;AAGF;EACC;;AACA;EAFD;IAGE;;;AAGA;EADD;IAEE;IACA;;;AAIH;EACC;EACA;;AACA;EAHD;IAIE;;;AAGF;EACC;EACA;EACA;EACA;;AAhjBA;EAkjBC;;AAljBD;EAkjBC;;AAED;EARD;IASE;;;;AAOL;EACC;EACA","file":"styles.css"}
\ No newline at end of file
diff --git a/static/styles.scss b/static/styles.scss
new file mode 100644
index 0000000..51b966f
--- /dev/null
+++ b/static/styles.scss
@@ -0,0 +1,643 @@
+
+$color-base1: #FFFFFF;
+$color-base2: #FAFAFA;
+$color-base3: #F3F3F3;
+$color-base4: #C9C9C9;
+$color-base5: #9a9a9a;
+$color-base6: #3d3d3d;
+$color-base7: #373737;
+$color-accent1: #E32A6D;
+$color-accent2: #bc1150;
+
+$themes: (
+ default: (
+ base1: $color-base1,
+ base2: $color-base2,
+ base3: $color-base3,
+ base4: $color-base4,
+ base5: $color-base5,
+ base6: $color-base6,
+ base7: $color-base7,
+ accent1: $color-accent1,
+ accent2: $color-accent2,
+ bg-up: $color-base1,
+ bg-down: $color-base1,
+ boxed-title: $color-base7,
+ boxed-bg-title: $color-base4,
+ boxed-bg: $color-base3,
+ separator: $color-base3,
+ ),
+ dark: (
+ base1: $color-base7,
+ base2: $color-base6,
+ base3: $color-base5,
+ base4: $color-base4,
+ base5: $color-base3,
+ base6: $color-base2,
+ base7: $color-base2,
+ accent1: $color-accent1,
+ accent2: $color-accent2,
+ bg-up: darken($color-base6, 12%),
+ bg-down: darken($color-base7, 12%),
+ boxed-title: $color-base5,
+ boxed-bg-title: darken($color-base6, 14%),
+ boxed-bg: darken($color-base7, 14%),
+ separator: darken($color-base7, 8%),
+ ),
+);
+
+$base1: 'base1';
+$base2: 'base2';
+$base3: 'base3';
+$base4: 'base4';
+$base5: 'base5';
+$base6: 'base6';
+$base7: 'base7';
+$accent1: 'accent1';
+$accent2: 'accent2';
+$bg-up: 'bg-up';
+$bg-down: 'bg-down';
+$boxed-title: 'boxed-title';
+$boxed-bg-title: 'boxed-bg-title';
+$boxed-bg: 'boxed-bg';
+$separator: 'separator';
+
+$theme-map: null;
+@mixin themed() {
+ @each $theme, $map in $themes {
+ .theme--#{$theme} & {
+ $theme-map: () !global;
+ @each $key, $submap in $map {
+ $value: map-get(map-get($themes, $theme), '#{$key}');
+ $theme-map: map-merge($theme-map, ($key: $value)) !global;
+ }
+ @content;
+ $theme-map: null !global;
+ }
+ }
+}
+
+@function t($key) {
+ @return map-get($theme-map, $key);
+}
+
+/*# sourceMappingURL=styles.css.map */
+html {
+ font-family: Helvetica, sans-serif;
+ font-size: 19px;
+ font-weight: 300;
+ @media (max-width: 580px) {
+ font-size: 18px;
+ }
+}
+body {
+ @include themed() {
+ color: t($base7);
+ }
+ margin: 0;
+ margin-bottom: 4rem;
+ &.lock {
+ @media (max-width: 580px) {
+ overflow: hidden;
+ }
+ }
+}
+a {
+ @include themed() {
+ color: t($base7);
+ }
+}
+.background {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ @include themed() {
+ background: t($bg-up);
+ }
+ overflow: hidden;
+ z-index: -1;
+ &::after {
+ content: "";
+ position: absolute;
+ @include themed() {
+ background: t($bg-down);
+ }
+ width: 140%;
+ height: 100%;
+ transform: rotate(-20deg);
+ transform-origin: bottom;
+ bottom: -40%;
+ @media (max-width: 580px) {
+ width: 200%;
+ bottom: -40%;
+ }
+ }
+}
+
+.theme-toggle {
+ position: fixed;
+ top: 1rem;
+ right: 1rem;
+ width: 1rem;
+ height: 1rem;
+ @include themed() {
+ color: t($base3);
+ // background: t($base3);
+ }
+ border-radius: 50%;
+ cursor: pointer;
+ @media (max-width: 580px) {
+ position: relative;
+ float: right;
+ top: 0;
+ right: 0;
+ }
+}
+
+.sun {
+ display: none
+}
+.moon {
+ display: block
+}
+
+.theme--dark {
+ .sun {
+ display: block
+ }
+ .moon {
+ display: none
+ }
+}
+
+.top {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 1rem 0;
+ justify-content: left;
+ @media (max-width: 580px) {
+ display: block;
+ width: 90%;
+ margin: 1rem auto 1rem auto;
+ font-size: 0.8rem;
+ }
+ span {
+ @include themed() {
+ color: t($accent1);
+ }
+ }
+}
+
+.pic-wrapper {
+ max-width: 100%;
+ overflow: hidden;
+ @media (max-width: 580px) {
+ flex-basis: 40%;
+ }
+ img.pic {
+ max-width: 100%;
+ width: 100%;
+ height: auto;
+ -webkit-clip-path: url(#svg-shape);
+ -moz-clip-path: url(#svg-shape);
+ -o-clip-path: url(#svg-shape);
+ -ms-clip-path: url(#svg-shape);
+ clip-path: url(#svg-shape);
+ }
+}
+
+.container_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ @media (max-width: 580px) {
+ display: block;
+ padding: 0 1rem;
+ margin: 0 auto;
+ }
+}
+.nostr_link {
+ flex-basis: 15%;
+ text-align: right;
+ text-decoration: none;
+}
+
+.container {
+ display: flex;
+ width: 70%;
+ justify-content: space-between;
+ gap: 4.8vw;
+
+ @media (max-width: 580px) {
+ display: block;
+ width: 100%;
+ }
+
+ .columnA {
+ flex-basis: 25%;
+ margin-top: 2rem;
+ @media (max-width: 580px) {
+ display: flex;
+ align-items: center;
+ margin-top: 0rem;
+ }
+ .info-wrapper {
+ display: none;
+ @media (max-width: 580px) {
+ display: block;
+ flex-basis: 64%;
+ max-width: 64%;
+ overflow: hidden;
+ font-size: 1.6rem;
+ .display {
+ display: block;
+ font-size: 1.2rem;
+ @include themed() {
+ color: t($base4);
+ }
+ }
+ }
+ }
+ .last_update {
+ font-size: 0.8em;
+ margin-top: 0.5rem;
+ text-align: center;
+ @include themed() {
+ color: t($base4);
+ }
+ @media (max-width: 580px) {
+ display: none;
+ }
+ }
+ }
+ .column_content {
+
+ flex-grow: 0;
+ flex-shrink: 0;
+ word-wrap: break-word;
+ margin-right: 1vw;
+
+ .info-wrapper {
+ font-size: 1.6rem;
+ .display {
+ @include themed() {
+ color: t($base4);
+ }
+ }
+ .npub {
+ font-size: 1rem;
+ @include themed() {
+ color: t($base4);
+ }
+ }
+ @media (max-width: 580px) {
+ display: none;
+ }
+ }
+ .separator {
+ height: 6px;
+ width: 30%;
+ margin-left: -0.6rem;
+ @include themed() {
+ background: t($separator);
+ }
+ &.long {
+ width: 50%;
+ }
+ @media (max-width: 580px) {
+ margin-left: -1rem;
+ }
+ }
+ .field {
+ margin-bottom: 1.5rem;
+ .label {
+ font-size: 0.8rem;
+ @include themed() {
+ color: t($accent1);
+ }
+ }
+ &.advanced {
+ display: none;
+ &.visible {
+ display: block;
+ }
+ &.boxed {
+ padding: 0 1rem 1rem;
+ margin-left: -1rem;
+ margin-right: -1rem;
+ @include themed() {
+ background: t($boxed-bg);
+ }
+ .label {
+ padding: 0.2rem 1rem;
+ margin: 0 -1rem;
+ @include themed() {
+ color: t($boxed-title);
+ }
+ @include themed() {
+ background: t($boxed-bg-title);
+ }
+ }
+ }
+ }
+ &.advanced-switch-wrapper {
+ display: flex;
+ align-items: center;
+
+ input[type=checkbox]{
+ height: 0;
+ width: 0;
+ visibility: hidden;
+ display: none;
+ }
+
+ label:first-of-type {
+ cursor: pointer;
+ text-indent: -9999px;
+ width: 2.6rem;
+ height: 1.2rem;
+ background: $color-base6;
+ display: inline-block;
+ border-radius: 100px;
+ position: relative;
+ margin-right: 0.5rem;
+ @media (max-width: 580px) {
+ width: 3rem;
+ height: 1.4rem;
+ }
+ }
+
+ label:first-of-type:after {
+ content: '';
+ position: absolute;
+ top: 2px;
+ left: 2px;
+ width: 1rem;
+ height: 1rem;
+ background: #fff;
+ border-radius: 1rem;
+ transition: 0.2s;
+ @media (max-width: 580px) {
+ width: 1.2rem;
+ height: 1.2rem;
+ }
+ }
+
+ input:checked + label {
+ @include themed() {
+ background: t($accent1);
+ }
+ }
+
+ input:checked + label:first-of-type:after {
+ left: calc(100% - 2px);
+ transform: translateX(-100%);
+ }
+
+ label:first-of-type:active:after {
+ width: 2rem;
+ }
+
+ }
+ &.content{
+ line-height: 1.4rem;
+ img {
+ max-width: 100%;
+ margin: 1rem 0;
+ }
+ }
+ .json, .data {
+ white-space: pre-wrap;
+ word-break: break-all;
+ margin-top: 1rem;
+ .key {
+ display: inline-block;
+ margin-top: 0.5rem;
+ @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);
+ }
+ }
+ }
+ &.last_update {
+ display: none;
+ @media (max-width: 580px) {
+ display: block;
+ font-size: 0.8em;
+ @include themed() {
+ color: t($base4);
+ }
+ }
+ }
+ }
+
+ }
+
+ .column_clients {
+ flex-basis: 25%;
+ margin-top: 2rem;
+ @media (max-width: 580px) {
+ position: fixed;
+ // top: calc(100vh - 4.6rem);
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ transition: all 500ms ease-in-out;
+ &.up {
+ .btn {
+ display: block;
+ }
+ .title span.open {
+ display: none;
+ }
+ }
+ }
+ .title {
+ font-size: 0.8rem;
+ margin-bottom: 1rem;
+ text-align: center;
+ span.open, span.close {
+ display: none;
+ }
+ @media (max-width: 580px) {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 2.6rem;
+ height: 2.6rem;
+ border-left: 1px solid #bc1150;
+ span.text {
+ display: none;
+ }
+ span.open, span.close {
+ display: inline;
+ svg {
+ width: 50%;
+ height: 50%;
+ margin: 28% auto auto auto;
+ display: block;
+ }
+ }
+ }
+ }
+ .btn {
+ display: flex;
+ align-items: center;
+ margin-bottom: 0.8rem;
+ @media (max-width: 580px) {
+ display: none;
+ margin-bottom: 0;
+ }
+ a {
+ flex-basis: 100%;
+ padding: 0.4rem;
+ text-align: center;
+ font-size: 0.9rem;
+ color: $color-base1;
+ background-color: $color-base6;
+ border-bottom: 1px solid darken($color-base7, 14%);
+ text-decoration: none;
+ border-radius: 8px;
+ @media (max-width: 580px) {
+ display: block;
+ padding: 0.8rem;
+ border-radius: 0px;
+ font-weight: 400;
+ text-align: left;
+ }
+ span {
+ display: none;
+ @media (max-width: 580px) {
+ display: inline;
+ color: $color-base1;
+ }
+ }
+ &:hover {
+ background: $color-base7;
+ }
+ }
+ &:first-of-type {
+ @media (max-width: 580px) {
+ display: block;
+ }
+ a {
+ @include themed() {
+ background: t($accent1);
+ }
+ border-bottom: none;
+ @media (max-width: 580px) {
+ border-radius: 8px 8px 0 0;
+ }
+ &:hover {
+ @include themed() {
+ background: t($accent2);
+ }
+ }
+ }
+ }
+ span {
+ flex-basis: 20%;
+ margin-left: 0.4rem;
+ color: $color-base1;
+ @media (max-width: 580px) {
+ display: none;
+ }
+ }
+ }
+ }
+
+}
+
+body.profile {
+ .column_content {
+ flex-basis: 50%;
+ max-width: 50%;
+ @media (max-width: 580px) {
+ flex-basis: 100%;
+ max-width: 100%;
+ margin-right: 0;
+ }
+ }
+}
+
+body.note {
+ .column_content {
+ flex-basis: 70%;
+ max-width: 70%;
+ @media (max-width: 580px) {
+ flex-basis: 100%;
+ max-width: 100%;
+ margin-right: 0;
+ }
+ .profile_intro {
+ display: flex;
+ max-width: 100%;
+ align-items: center;
+ a {
+ display: inherit;
+ align-items: inherit;
+ margin: 1rem 0 1rem 0;
+ text-decoration: none;
+ flex-wrap: wrap;
+ @media (max-width: 580px) {
+ margin-top: -0rem;
+ margin-bottom: -0.5rem;
+ }
+ }
+ .info-wrapper {
+ flex-basis: 80%;
+ @media (max-width: 580px) {
+ display: block;
+ }
+ .name, .npub {
+ @media (max-width: 580px) {
+ display: block-inline;
+ font-size: 0.9rem;
+ }
+ }
+ }
+ .pic-wrapper {
+ flex-basis: 16%;
+ margin-right: 1rem;
+ @media (max-width: 580px) {
+ margin-right: 0.5rem;
+ }
+ }
+ .published_at {
+ flex-grow: 1;
+ text-align: right;
+ align-self: end;
+ font-size: 0.8rem;
+ @include themed() {
+ color: t($base5);
+ }
+ @media (max-width: 580px) {
+ padding-top: 0.5rem;
+ }
+ }
+ }
+ }
+}
+
+.footer {
+ font-size: 0.8rem;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/static/top.html b/static/top.html
new file mode 100644
index 0000000..8fdb5ad
--- /dev/null
+++ b/static/top.html
@@ -0,0 +1,43 @@
+
+
+
\ No newline at end of file
diff --git a/utils.go b/utils.go
index 54c77b9..4b3d1ec 100644
--- a/utils.go
+++ b/utils.go
@@ -2,7 +2,9 @@ package main
import (
"encoding/json"
+ "fmt"
"net/http"
+ "regexp"
"strings"
"github.com/nbd-wtf/go-nostr"
@@ -38,28 +40,28 @@ func generateClientList(code string, event *nostr.Event) []map[string]string {
if strings.HasPrefix(code, "nevent") || strings.HasPrefix(code, "note") {
return []map[string]string{
{"name": "native client", "url": "nostr:" + code},
- {"name": "snort", "url": "https://snort.social/e/" + code},
- {"name": "coracle", "url": "https://coracle.social/" + code},
- {"name": "satellite", "url": "https://satellite.earth/thread/" + event.ID},
- {"name": "iris", "url": "https://iris.to/" + code},
- {"name": "yosup", "url": "https://yosup.app/thread/" + event.ID},
- {"name": "nostr.band", "url": "https://nostr.band/" + code},
- {"name": "primal", "url": "https://primal.net/thread/" + event.ID},
- {"name": "nostribe", "url": "https://www.nostribe.com/post/" + event.ID},
- {"name": "nostrid", "url": "https://web.nostrid.app/note/" + event.ID},
+ {"name": "Snort", "url": "https://Snort.social/e/" + code},
+ {"name": "Coracle", "url": "https://coracle.social/" + code},
+ {"name": "Satellite", "url": "https://satellite.earth/thread/" + event.ID},
+ {"name": "Iris", "url": "https://iris.to/" + code},
+ {"name": "Yosup", "url": "https://yosup.app/thread/" + event.ID},
+ {"name": "Nostr.band", "url": "https://nostr.band/" + code},
+ {"name": "Primal", "url": "https://primal.net/thread/" + event.ID},
+ {"name": "Nostribe", "url": "https://www.nostribe.com/post/" + event.ID},
+ {"name": "Nostrid", "url": "https://web.nostrid.app/note/" + event.ID},
}
} else if strings.HasPrefix(code, "npub") || strings.HasPrefix(code, "nprofile") {
return []map[string]string{
{"name": "native client", "url": "nostr:" + code},
- {"name": "snort", "url": "https://snort.social/p/" + code},
- {"name": "coracle", "url": "https://coracle.social/" + code},
- {"name": "satellite", "url": "https://satellite.earth/@" + code},
- {"name": "iris", "url": "https://iris.to/" + code},
- {"name": "yosup", "url": "https://yosup.app/profile/" + event.PubKey},
- {"name": "nostr.band", "url": "https://nostr.band/" + code},
- {"name": "primal", "url": "https://primal.net/profile/" + event.PubKey},
- {"name": "nostribe", "url": "https://www.nostribe.com/profile/" + event.PubKey},
- {"name": "nostrid", "url": "https://web.nostrid.app/account/" + event.PubKey},
+ {"name": "Snort", "url": "https://snort.social/p/" + code},
+ {"name": "Coracle", "url": "https://coracle.social/" + code},
+ {"name": "Satellite", "url": "https://satellite.earth/@" + code},
+ {"name": "Iris", "url": "https://iris.to/" + code},
+ {"name": "Yosup", "url": "https://yosup.app/profile/" + event.PubKey},
+ {"name": "Nostr.band", "url": "https://nostr.band/" + code},
+ {"name": "Primal", "url": "https://primal.net/profile/" + event.PubKey},
+ {"name": "Nostribe", "url": "https://www.nostribe.com/profile/" + event.PubKey},
+ {"name": "Nostrid", "url": "https://web.nostrid.app/account/" + event.PubKey},
}
} else if strings.HasPrefix(code, "naddr") {
return []map[string]string{
@@ -114,3 +116,53 @@ func getPreviewStyle(r *http.Request) string {
return "unknown"
}
}
+
+func BasicFormatting(input string) string {
+ lines := strings.Split(input, "\n")
+
+ var processedLines []string
+ for _, line := range lines {
+ processedLine := ReplaceURLsWithTags(line)
+ processedLines = append(processedLines, processedLine)
+ }
+
+ return strings.Join(processedLines, "
")
+}
+
+func ReplaceURLsWithTags(line string) string {
+
+ // Match and replace image URLs with
tags
+ imageExtensions := []string{".jpg", ".jpeg", ".png", ".webp", ".gif"}
+ for _, extension := range imageExtensions {
+ regexPattern := fmt.Sprintf(`\s*(https?://\S+%s)\s*`, extension)
+ regex := regexp.MustCompile(regexPattern)
+ matches := regex.FindAllString(line, -1)
+
+ for _, match := range matches {
+ imgTag := fmt.Sprintf(`
`, strings.ReplaceAll(match, "\n", ""))
+ line = strings.ReplaceAll(line, match, imgTag)
+ return line
+ }
+ }
+
+ // Match and replace npup1, nprofile1, note1, nevent1, etc
+ nostrRegexPattern := `\s*nostr:((npub|note|nevent|nprofile)1[a-z0-9]+)\s*`
+ nostrRegex := regexp.MustCompile(nostrRegexPattern)
+ line = nostrRegex.ReplaceAllStringFunc(line, func(match string) string {
+ submatch := nostrRegex.FindStringSubmatch(match)
+ if len(submatch) < 2 {
+ return match
+ }
+ capturedGroup := submatch[1]
+ first6 := capturedGroup[:6]
+ last6 := capturedGroup[len(capturedGroup)-6:]
+ replacement := fmt.Sprintf(`%s`, capturedGroup, first6+"…"+last6)
+ return replacement
+ })
+
+ // Match and replace other URLs with tags
+ otherRegexPattern := `\S*(https?://\S+)\S*`
+ otherRegex := regexp.MustCompile(otherRegexPattern)
+ line = otherRegex.ReplaceAllString(line, `$1`)
+ return line
+}