mirror of
https://github.com/aljazceru/njump.git
synced 2025-12-17 14:24:27 +01:00
Setup up a first desktop version
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
njump
|
||||
.air.toml
|
||||
tmp/*
|
||||
102
event.html
102
event.html
@@ -47,32 +47,89 @@
|
||||
{{end}}
|
||||
<!----------->
|
||||
|
||||
<style>
|
||||
body {
|
||||
padding: 3%;
|
||||
}
|
||||
#event {
|
||||
margin: 5% 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
font-family: monospace;
|
||||
font-size: 130%;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/styles.css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
open {{.type}} in {{range .clients}}<br />
|
||||
<span style="color: #bbb"></span>
|
||||
<a class="client" href="{{.url}}">{{.name}}</a> {{end}}
|
||||
|
||||
<div class="top">
|
||||
<a href="https://nostr.com" class="nostr_link">What is nostr?</a>
|
||||
</div>
|
||||
<div id="event">{{.eventJSON}}</div>
|
||||
<div style="display: flex; justify-content: flex-end">
|
||||
|
||||
<div class="container_wrapper">
|
||||
<div class="container profile">
|
||||
<div class="column column1">
|
||||
<div class="pic-wrapper">
|
||||
<img class="pic" src="{{ .metadata.Picture }}" />
|
||||
<svg width="0" height="0" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<clipPath id="svg-shape" clipPathUnits="objectBoundingBox">
|
||||
<path
|
||||
transform="scale(0.005, 0.005)"
|
||||
d="M100,200c43.8,0,68.2,0,84.1-15.9C200,168.2,200,143.8,200,100s0-68.2-15.9-84.1C168.2,0,143.8,0,100,0S31.8,0,15.9,15.9C0,31.8,0,56.2,0,100s0,68.2,15.9,84.1C31.8,200,56.2,200,100,200z"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="last_update">
|
||||
Last update:<br/>
|
||||
{{.createdAt}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column column2">
|
||||
<div class="field name">
|
||||
{{.content_json.name}} <span class="display">{{.content_json.display_name}}</span>
|
||||
</div>
|
||||
<div class="field separator"></div>
|
||||
<div class="field">
|
||||
<a href="{{.content_json.website}}">{{.content_json.website}}</a>
|
||||
</div>
|
||||
<div class="field">
|
||||
{{.content_json.about}}
|
||||
</div>
|
||||
<div class="field separator"></div>
|
||||
<div class="field">
|
||||
<div class="label">Public key</div>
|
||||
{{.npub}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="label">NIP-05</div>
|
||||
{{.content_json.nip05}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="label">LN Address</div>
|
||||
{{.content_json.lud16}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="label">Metadata Event</div>
|
||||
{{.nevent}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="label">JSON</div>
|
||||
{{.eventJSON}}
|
||||
</div>
|
||||
<div class="field separator"></div>
|
||||
</div>
|
||||
<div class="column column3">
|
||||
<div class="title">Open {{.type}} in</div>
|
||||
<div class="clients">
|
||||
{{range .clients}}
|
||||
<div class="btn">
|
||||
<a class="client" href="{{.url}}">{{.name}}</a>
|
||||
<span></span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div style="display: flex; justify-content: flex-end">
|
||||
<span>
|
||||
powered by <a href="https://git.fiatjaf.com/njump">njump</a>
|
||||
</span>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<script>
|
||||
const type = '{{.type}}'
|
||||
let counts = []
|
||||
@@ -82,7 +139,7 @@
|
||||
let url = clients[i].href
|
||||
let key = 'nj:' + type + ':' + name
|
||||
let count = parseInt(localStorage.getItem(key) || 0)
|
||||
clients[i].previousElementSibling.innerText = count
|
||||
clients[i].nextElementSibling.innerText = count
|
||||
clients[i].addEventListener('click', () => {
|
||||
localStorage.setItem(key, count + 1)
|
||||
})
|
||||
@@ -97,5 +154,8 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="background"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
3
main.go
3
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)
|
||||
|
||||
16
render.go
16
render.go
@@ -8,7 +8,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"time"
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip19"
|
||||
)
|
||||
@@ -48,6 +48,7 @@ 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 {
|
||||
@@ -142,21 +143,23 @@ func render(w http.ResponseWriter, r *http.Request) {
|
||||
// : ''
|
||||
|
||||
textImageURL := ""
|
||||
description := ""
|
||||
content := ""
|
||||
content_json := make(map[string]interface{})
|
||||
if useTextImage {
|
||||
textImageURL = fmt.Sprintf("https://%s/image/%s", hostname, code)
|
||||
if subject != "" {
|
||||
description = fmt.Sprintf("%s -- %s", subject, seenOnRelays)
|
||||
content = fmt.Sprintf("%s -- %s", subject, seenOnRelays)
|
||||
} else {
|
||||
description = seenOnRelays
|
||||
content = seenOnRelays
|
||||
}
|
||||
} else {
|
||||
description = prettyJsonOrRaw(event.Content)
|
||||
content_json, content = prettyJsonOrRaw(event.Content)
|
||||
}
|
||||
|
||||
eventJSON, _ := json.MarshalIndent(event, "", " ")
|
||||
|
||||
params := map[string]any{
|
||||
"createdAt": createdAt,
|
||||
"clients": generateClientList(code, event),
|
||||
"type": typ,
|
||||
"title": title,
|
||||
@@ -166,7 +169,8 @@ func render(w http.ResponseWriter, r *http.Request) {
|
||||
"naddr": naddr,
|
||||
"metadata": metadata,
|
||||
"authorLong": authorLong,
|
||||
"description": description,
|
||||
"content": content,
|
||||
"content_json": content_json,
|
||||
"textImageURL": textImageURL,
|
||||
"videoType": videoType,
|
||||
"image": image,
|
||||
|
||||
167
static/styles.css
Normal file
167
static/styles.css
Normal file
@@ -0,0 +1,167 @@
|
||||
html {
|
||||
font-family: Helvetica, sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #373737;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #373737;
|
||||
}
|
||||
|
||||
.background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.background::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background-color: #FAFAFA;
|
||||
width: 140%;
|
||||
height: 100%;
|
||||
transform: rotate(-20deg);
|
||||
transform-origin: bottom;
|
||||
bottom: -40%;
|
||||
}
|
||||
|
||||
.top, .container_wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.top {
|
||||
margin: 1rem 0;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
.nostr_link {
|
||||
flex-basis: 15%;
|
||||
text-align: right;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
width: 70%;
|
||||
justify-content: space-between;
|
||||
gap: 4.8vw;
|
||||
}
|
||||
|
||||
.column {
|
||||
}
|
||||
|
||||
.column1 {
|
||||
flex-basis: 25%;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.container.profile .column1 .pic-wrapper {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container.profile .column1 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);
|
||||
}
|
||||
|
||||
.last_update {
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
color: #C9C9C9;
|
||||
}
|
||||
|
||||
.column2 {
|
||||
flex-basis: 50%;
|
||||
max-width: 50%;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
word-wrap: break-word;
|
||||
margin-right: 1vw;
|
||||
}
|
||||
|
||||
.column2 .name {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.column2 .name .display {
|
||||
color: #C9C9C9;
|
||||
}
|
||||
|
||||
.column2 .separator {
|
||||
height: 6px;
|
||||
width: 30%;
|
||||
margin-left: -0.6rem;
|
||||
background-color: #F3F3F3;
|
||||
}
|
||||
|
||||
.column2 .field {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.column2 .field .label {
|
||||
font-size: 0.8rem;
|
||||
color: #E32A6D;
|
||||
}
|
||||
|
||||
.column3 {
|
||||
flex-basis: 25%;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.column3 .title {
|
||||
font-size: 0.8rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.column3 .btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.column3 .btn a {
|
||||
flex-basis: 80%;
|
||||
padding: 0.4rem;
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
color: #FFFFFF;
|
||||
background-color: #5A5A5A;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.column3 .btn a:hover {
|
||||
background-color: #373737;
|
||||
}
|
||||
|
||||
.column3 .btn:first-child a {
|
||||
background-color: #E32A6D;
|
||||
}
|
||||
|
||||
.column3 .btn:first-child a:hover {
|
||||
background-color: #bc1150;
|
||||
}
|
||||
|
||||
.column3 .btn span {
|
||||
flex-basis: 20%;
|
||||
margin-left: 0.4rem;
|
||||
color: #9a9a9a;
|
||||
}
|
||||
8
utils.go
8
utils.go
@@ -81,14 +81,14 @@ func mergeMaps[K comparable, V any](m1 map[K]V, m2 map[K]V) map[K]V {
|
||||
return m1
|
||||
}
|
||||
|
||||
func prettyJsonOrRaw(j string) string {
|
||||
var parsedContent any
|
||||
func prettyJsonOrRaw(j string) (map[string]interface{}, string) {
|
||||
var parsedContent map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(j), &parsedContent); err == nil {
|
||||
if t, err := toml.Marshal(parsedContent); err == nil && len(t) > 0 {
|
||||
return string(t)
|
||||
return parsedContent, string(t)
|
||||
}
|
||||
}
|
||||
return j
|
||||
return nil, j
|
||||
}
|
||||
|
||||
func getPreviewStyle(r *http.Request) string {
|
||||
|
||||
Reference in New Issue
Block a user