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 @@ +
+ What is nostr? +
+ + +
+
+ + \ 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 +}