| 1 | diff --git a/internal/webui/components.js b/internal/webui/components.js |
| 2 | index eadc778..1857ab6 100644 |
| 3 | --- a/internal/webui/components.js |
| 4 | +++ b/internal/webui/components.js |
| 5 | @@ -636,16 +636,16 @@ |
| 6 | if (footer.childNodes.length) node.append(footer); |
| 7 | return node; |
| 8 | }; |
| 9 | - const roomBox = () => document.getElementById("content"); |
| 10 | + // The timeline scrolls inside the content column on desktop and with the |
| 11 | + // page body on phones; roomBox finds whichever holds the overflow. |
| 12 | + const roomBox = () => [document.getElementById("content"), document.body, document.documentElement].find(node => node && node.scrollHeight > node.clientHeight + 1 && /auto|scroll/.test(getComputedStyle(node).overflowY)) || null; |
| 13 | const roomNearBottom = () => { |
| 14 | const box = roomBox(); |
| 15 | - if (box && box.scrollHeight > box.clientHeight + 1 && getComputedStyle(box).overflowY !== "visible") return box.scrollHeight - box.scrollTop - box.clientHeight < 120; |
| 16 | - return document.documentElement.scrollHeight - window.scrollY - window.innerHeight < 120; |
| 17 | + return !box || box.scrollHeight - box.scrollTop - box.clientHeight < 120; |
| 18 | }; |
| 19 | const roomScroll = () => { |
| 20 | const box = roomBox(); |
| 21 | if (box) box.scrollTop = box.scrollHeight; |
| 22 | - window.scrollTo(0, document.documentElement.scrollHeight); |
| 23 | }; |
| 24 | // roomAppend adds one message to the timeline unless it is already there, |
| 25 | // keeps the list bounded and follows the newest message when the viewer |
| 26 | diff --git a/internal/webui/rooms.html b/internal/webui/rooms.html |
| 27 | index c160d8e..3a0c41e 100644 |
| 28 | --- a/internal/webui/rooms.html |
| 29 | +++ b/internal/webui/rooms.html |
| 30 | @@ -43,7 +43,7 @@ |
| 31 | </section> |
| 32 | {{else}}{{$data := asMap .Event}}{{$room := asMap (index $data "room")}}{{$id := str (index $room "id")}}{{$root := roomRoot .Event}}<section id="thread"> |
| 33 | <p id="crumbs"><a href="/rooms/{{$id}}">{{or (str (index $room "name")) $id}}</a></p> |
| 34 | -<h1>Thread <small>{{$root.Replies}} replies</small></h1> |
| 35 | +<h1>Thread <small>{{$root.Replies}} {{if eq $root.Replies 1}}reply{{else}}replies{{end}}</small></h1> |
| 36 | <div id="root">{{template "roomMessage" $root}}</div> |
| 37 | <div id="messages">{{range roomItems .Event "replies"}} |
| 38 | {{template "roomMessage" .}}{{else}}<p id="empty">No replies yet.</p>{{end}} |
| 39 | @@ -60,5 +60,5 @@ |
| 40 | {{define "roomMessage"}}<room-message id="msg-{{.ID}}" data-id="{{.ID}}" data-kind="{{.Kind}}" data-pubkey="{{.PubKey}}"{{if .Agent}} data-agent{{end}}{{if .Notice}} data-notice{{end}}> |
| 41 | <header><b>{{template "nostrKey" .PubKey}}</b>{{if .Role}} | {{.Role}}{{end}}<small><time datetime="{{datetime .CreatedAt}}" title="{{when .CreatedAt}}">{{clock .CreatedAt}}</time></small></header> |
| 42 | <p>{{if .Notice}}{{.Notice}}{{else}}{{roomContent .Content}}{{end}}</p> |
| 43 | -{{if or .Mentions (and (not .InThread) (or (eq .Kind "11") .Root)) .Reactions}}<footer>{{if .Mentions}}<span>to {{range .Mentions}}{{template "nostrKey" .}} {{end}}</span>{{end}}{{if not .InThread}}{{if eq .Kind "11"}}<a href="/rooms/{{.Room}}/thread/{{.ID}}">thread{{if .Replies}} | {{.Replies}} replies{{end}}</a>{{else if .Root}}<a href="/rooms/{{.Room}}/thread/{{.Root}}">in thread</a>{{end}}{{end}}{{range .Reactions}}<span data-reaction="{{.Content}}">{{.Content}} {{.Count}}</span>{{end}}</footer>{{end}} |
| 44 | +{{if or .Mentions (and (not .InThread) (or (eq .Kind "11") .Root)) .Reactions}}<footer>{{if .Mentions}}<span>to {{range .Mentions}}{{template "nostrKey" .}} {{end}}</span>{{end}}{{if not .InThread}}{{if eq .Kind "11"}}<a href="/rooms/{{.Room}}/thread/{{.ID}}">thread{{if .Replies}} | {{.Replies}} {{if eq .Replies 1}}reply{{else}}replies{{end}}{{end}}</a>{{else if .Root}}<a href="/rooms/{{.Room}}/thread/{{.Root}}">in thread</a>{{end}}{{end}}{{range .Reactions}}<span data-reaction="{{.Content}}">{{.Content}} {{.Count}}</span>{{end}}</footer>{{end}} |
| 45 | </room-message>{{end}} |
| 46 | diff --git a/internal/webui/rooms_test.go b/internal/webui/rooms_test.go |
| 47 | index bd002fa..8cb074a 100644 |
| 48 | --- a/internal/webui/rooms_test.go |
| 49 | +++ b/internal/webui/rooms_test.go |
| 50 | @@ -146,7 +146,7 @@ func TestRoomPageRendersMessagesOldestFirstWithMarkers(t *testing.T) { |
| 51 | `<script>alert(1)</script>`, |
| 52 | `<span>to <nostr-key hex="` + roomAgent + `"`, |
| 53 | `<span data-reaction="+1">+1 1</span>`, |
| 54 | - `<a href="/rooms/general/thread/` + roomThread + `">thread | 1 replies</a>`, |
| 55 | + `<a href="/rooms/general/thread/` + roomThread + `">thread | 1 reply</a>`, |
| 56 | `<a href="/rooms/general/thread/` + roomThread + `">in thread</a>`, |
| 57 | `<room-live room="general"></room-live>`, |
| 58 | `<room-compose room="general" pubkey="` + roomOwner + `">`, |
| 59 | @@ -197,7 +197,7 @@ func TestThreadPageRendersRootRepliesAndReplyCompose(t *testing.T) { |
| 60 | app, _ := roomsApp(t, roomOwner) |
| 61 | body := roomsPage(t, app, "/rooms/general/thread/"+roomThread) |
| 62 | for _, want := range []string{ |
| 63 | - `<p id="crumbs"><a href="/rooms/general">General</a></p>`, `<h1>Thread <small>1 replies</small></h1>`, |
| 64 | + `<p id="crumbs"><a href="/rooms/general">General</a></p>`, `<h1>Thread <small>1 reply</small></h1>`, |
| 65 | `<div id="root"><room-message id="msg-` + roomThread + `"`, `<div id="messages">`, `id="msg-` + roomReply + `"`, |
| 66 | `<room-live room="general" root="` + roomThread + `"></room-live>`, |
| 67 | `<room-compose room="general" pubkey="` + roomOwner + `" kind="12" root="` + roomThread + `" root-pubkey="` + roomAgent + `">`, |