diff --git a/nostr.go b/nostr.go index af598ba..740ae06 100644 --- a/nostr.go +++ b/nostr.go @@ -98,3 +98,29 @@ func getEvent(ctx context.Context, code string) (*nostr.Event, error) { return nil, fmt.Errorf("couldn't find this %s", prefix) } + +func getLastNotes(ctx context.Context, npub string) ([]nostr.Event, error) { + var filter nostr.Filters + relays := make([]string, 0, 7) + relays = append(relays, always...) + lastNotes := make([]nostr.Event, 0) + if _, v, err := nip19.Decode(npub); err == nil { + pub := v.(string) + filter = nostr.Filters{ + { + Kinds: []int{nostr.KindTextNote}, + Authors: []string{pub}, + Limit: 20, + }, + } + } else { + panic(err) + } + ctx, cancel := context.WithTimeout(ctx, time.Second*4) + defer cancel() + events := pool.SubManyEose(ctx, relays, filter) + for event := range events { + lastNotes = append(lastNotes, *event) + } + return lastNotes, nil +} diff --git a/render.go b/render.go index 21c6ae5..167457c 100644 --- a/render.go +++ b/render.go @@ -22,6 +22,13 @@ var static embed.FS //go:embed templates/* var templates embed.FS +type Event struct { + Nevent string + Content string + CreatedAt string + // ... +} + func render(w http.ResponseWriter, r *http.Request) { fmt.Println(r.URL.Path, ":~", r.Header.Get("user-agent")) w.Header().Set("Content-Type", "text/html") @@ -49,17 +56,35 @@ func render(w http.ResponseWriter, r *http.Request) { npub, _ := nip19.EncodePublicKey(event.PubKey) nevent, _ := nip19.EncodeEvent(event.ID, []string{}, event.PubKey) + note := "" naddr := "" createdAt := time.Unix(int64(event.CreatedAt), 0).Format("2006-01-02 15:04:05") typ := "" author := event + lastNotes := make([]Event, 0) if event.Kind == 0 { typ = "profile" + thisLastNotes, err := getLastNotes(r.Context(), code) + lastNotes = make([]Event, len(thisLastNotes)) + for i, n := range thisLastNotes { + this_nevent, _ := nip19.EncodeEvent(n.ID, []string{}, n.PubKey) + this_date := time.Unix(int64(n.CreatedAt), 0).Format("2006-01-02 15:04:05") + lastNotes[i] = Event{ + Nevent: this_nevent, + Content: n.Content, + CreatedAt: this_date, + } + } + if err != nil { + http.Error(w, "error fetching event: "+err.Error(), 404) + return + } } else { if event.Kind == 1 || event.Kind == 7 || event.Kind == 30023 { typ = "note" + note, _ = nip19.EncodeNote(event.ID) } else if event.Kind >= 30000 && event.Kind < 40000 { typ = "address" if d := event.Tags.GetFirst([]string{"d", ""}); d != nil { @@ -179,6 +204,7 @@ func render(w http.ResponseWriter, r *http.Request) { "npub": npub, "npubShort": npubShort, "nevent": nevent, + "note": note, "naddr": naddr, "metadata": metadata, "authorLong": authorLong, @@ -193,6 +219,7 @@ func render(w http.ResponseWriter, r *http.Request) { "kindID": event.Kind, "kindDescription": kindDescription, "kindNIP": kindNIP, + "lastNotes": lastNotes, } // Use a mapping to expressly link the templates and share them between more kinds/types diff --git a/static/styles.css b/static/styles.css index f3d4926..da39ef1 100644 --- a/static/styles.css +++ b/static/styles.css @@ -32,6 +32,10 @@ body { } } +h1, h2 { + font-weight: 100; +} + .theme--default a { color: #373737; } @@ -323,6 +327,40 @@ body { .theme--dark .container .column_content .field.boxed .label { background: #191919; } +.container .column_content .field.last_notes a { + display: block; + text-decoration: none; +} +.container .column_content .field.last_notes a.note { + margin-bottom: 1rem; +} +.container .column_content .field.last_notes a.note .published_at { + font-size: 0.8rem; +} +.theme--default .container .column_content .field.last_notes a.note .published_at { + color: #e32a6d; +} +.theme--dark .container .column_content .field.last_notes a.note .published_at { + color: #e32a6d; +} +.container .column_content .field.last_notes a.note .content { + max-height: 160px; + overflow: hidden; +} +.container .column_content .field.last_notes a.note .content.gradient { + -webkit-mask-image: linear-gradient(to bottom, rgb(0, 0, 0) 50%, rgba(0, 0, 0, 0) 100%); + mask-image: linear-gradient(to bottom, rgb(0, 0, 0) 50%, rgba(0, 0, 0, 0) 100%); +} +.container .column_content .field.last_notes a:hover { + padding-left: 1rem; + margin-left: -1.5rem; +} +.theme--default .container .column_content .field.last_notes a:hover { + border-left: 0.5rem solid #f3f3f3; +} +.theme--dark .container .column_content .field.last_notes a:hover { + border-left: 0.5rem solid #2d2d2d; +} .container .column_content .field.advanced-switch-wrapper { display: flex; align-items: center; @@ -667,6 +705,7 @@ body.note .column_content .profile_intro .published_at, body.raw .column_content } .footer { + margin-top: 2rem; color: #9a9a9a; font-size: 0.8rem; text-align: center; diff --git a/static/styles.scss b/static/styles.scss index 47fd6e7..4bc5aa9 100644 --- a/static/styles.scss +++ b/static/styles.scss @@ -24,7 +24,7 @@ $themes: ( boxed-title: $color-base7, boxed-bg-title: $color-base4, boxed-bg: $color-base3, - separator: $color-base3, + over-bg: $color-base3, theme-toggle: $color-base3, ), dark: ( @@ -42,7 +42,7 @@ $themes: ( boxed-title: $color-base5, boxed-bg-title: darken($color-base6, 14%), boxed-bg: darken($color-base7, 14%), - separator: darken($color-base7, 4%), + over-bg: darken($color-base7, 4%), theme-toggle: $color-base6, ) ); @@ -61,7 +61,7 @@ $bg-down: 'bg-down'; $boxed-title: 'boxed-title'; $boxed-bg-title: 'boxed-bg-title'; $boxed-bg: 'boxed-bg'; -$separator: 'separator'; +$over-bg: 'over-bg'; $theme-toggle: 'theme-toggle'; $theme-map: null; @@ -112,6 +112,9 @@ body { } } } +h1, h2 { + font-weight: 100; +} a { @include themed() { color: t($base7); @@ -306,7 +309,7 @@ a { width: 30%; margin-left: -0.6rem; @include themed() { - background: t($separator); + background: t($over-bg); } &.long { width: 50%; @@ -347,6 +350,36 @@ a { } } } + &.last_notes { + a { + display: block; + text-decoration: none; + &.note { + margin-bottom: 1rem; + .published_at { + font-size: 0.8rem; + @include themed() { + color: t($accent1); + } + } + .content { + max-height: 160px; + overflow: hidden; + &.gradient { + -webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 100%); + mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 100%); + } + } + } + } + a:hover { + padding-left: 1rem; + margin-left: -1.5rem; + @include themed() { + border-left: 0.5rem solid t($over-bg); + } + } + } &.advanced-switch-wrapper { display: flex; align-items: center; @@ -647,6 +680,7 @@ body.note, body.raw { } .footer { + margin-top: 2rem; color: $color-base5; font-size: 0.8rem; text-align: center; diff --git a/templates/head.html b/templates/head.html index 144b608..aafae05 100644 --- a/templates/head.html +++ b/templates/head.html @@ -23,6 +23,7 @@ + {{ if .textImageURL }} @@ -61,5 +62,5 @@ {{end}} - + diff --git a/templates/profile.html b/templates/profile.html index bef5103..777b59b 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -72,6 +72,21 @@ {{template "details.html" .}}
+ +