Add Messages page
This commit is contained in:
parent
0b4ed73605
commit
f67fc443f6
54
internal/webserver/handler_messages.go
Normal file
54
internal/webserver/handler_messages.go
Normal file
@ -0,0 +1,54 @@
|
||||
package webserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence"
|
||||
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
|
||||
)
|
||||
|
||||
type MessageData persistence.DMChatView
|
||||
|
||||
func (t MessageData) Tweet(id scraper.TweetID) scraper.Tweet {
|
||||
return t.Tweets[id]
|
||||
}
|
||||
func (t MessageData) User(id scraper.UserID) scraper.User {
|
||||
return t.Users[id]
|
||||
}
|
||||
func (t MessageData) Retweet(id scraper.TweetID) scraper.Retweet {
|
||||
return t.Retweets[id]
|
||||
}
|
||||
func (t MessageData) Space(id scraper.SpaceID) scraper.Space {
|
||||
return t.Spaces[id]
|
||||
}
|
||||
func (t MessageData) FocusedTweetID() scraper.TweetID {
|
||||
return scraper.TweetID(0)
|
||||
}
|
||||
|
||||
func (app *Application) Messages(w http.ResponseWriter, r *http.Request) {
|
||||
app.traceLog.Printf("'Lists' handler (path: %q)", r.URL.Path)
|
||||
|
||||
// TODO: what if no active user?
|
||||
|
||||
chat_view := app.Profile.GetChatRoomsPreview(app.ActiveUser.ID)
|
||||
if strings.Trim(r.URL.Path, "/") != "" {
|
||||
message_id := scraper.DMChatRoomID(strings.Trim(r.URL.Path, "/"))
|
||||
chat_contents := app.Profile.GetChatRoomContents(message_id)
|
||||
chat_view.MergeWith(chat_contents.DMTrove)
|
||||
chat_view.MessageIDs = chat_contents.MessageIDs
|
||||
|
||||
if r.Header.Get("HX-Request") == "true" {
|
||||
app.buffered_render_tweet_htmx(w, "chat-view", MessageData(chat_view))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
app.buffered_render_tweet_page(w, "tpl/messages.tpl", MessageData(chat_view))
|
||||
}
|
||||
|
||||
// type DMChatView struct {
|
||||
// scraper.DMTrove
|
||||
// RoomIDs []scraper.DMChatRoomID
|
||||
// MessageIDs []scraper.DMMessageID
|
||||
// }
|
@ -123,6 +123,8 @@ func (app *Application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
http.StripPrefix("/search", http.HandlerFunc(app.Search)).ServeHTTP(w, r)
|
||||
case "lists":
|
||||
app.Lists(w, r)
|
||||
case "messages":
|
||||
http.StripPrefix("/messages", http.HandlerFunc(app.Messages)).ServeHTTP(w, r)
|
||||
default:
|
||||
app.UserFeed(w, r)
|
||||
}
|
||||
|
@ -208,6 +208,7 @@ h3 {
|
||||
.profile-image {
|
||||
border-radius: 50%;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
display: inline;
|
||||
border: 1px solid var(--color-outline-gray);
|
||||
}
|
||||
@ -221,6 +222,7 @@ h3 {
|
||||
}
|
||||
.user-feed-header .profile-image {
|
||||
width: 8em;
|
||||
height: 8em;
|
||||
}
|
||||
.tabs-container {
|
||||
outline: 1px solid var(--color-outline-gray);
|
||||
@ -612,6 +614,7 @@ ul.dropdown-items {
|
||||
}
|
||||
.users-list-container .author-info .profile-image {
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
}
|
||||
.users-list-container .user {
|
||||
border-color: var(--color-twitter-off-white-dark);
|
||||
@ -636,3 +639,72 @@ ul.dropdown-items {
|
||||
.sort-order-container .sort-order-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.chats-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
/** Setup to allow the two panes to scroll independently **/
|
||||
height: 100vh;
|
||||
padding-top: 4em;
|
||||
margin-top: -4em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.chats-container .chat-list {
|
||||
width: 30%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.chats-container .chat-list .chat {
|
||||
border-bottom: 1px solid var(--color-outline-gray);
|
||||
padding: 0.5em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.chats-container #chat-view {
|
||||
width: 70%;
|
||||
border-left: 1px solid var(--color-outline-gray);
|
||||
overflow-y: scroll;
|
||||
padding: 0.5em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.chats-container #chat-view .our-message {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.dm-message-and-reacts-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 1em 0;
|
||||
}
|
||||
p.dm-message-text {
|
||||
display: inline-block;
|
||||
padding: 1em;
|
||||
background-color: #ddd;
|
||||
border-radius: 1em;
|
||||
margin: 0;
|
||||
}
|
||||
.our-message p.dm-message-text {
|
||||
background-color: var(--color-twitter-blue-light);
|
||||
}
|
||||
.sender-profile-image-container {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.sender-profile-image-container a {
|
||||
line-height: 0; /* TODO: This is redundant with ".author-info a" rule above */
|
||||
}
|
||||
.dm-message-container {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 0.5em;
|
||||
}
|
||||
.our-message .dm-message-container {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.dm-message-reactions {
|
||||
display: flex;
|
||||
padding: 0 4em;
|
||||
}
|
||||
.our-message .dm-message-reactions {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
<span>Notifications</span>
|
||||
</li>
|
||||
</a>
|
||||
<a class="unstyled-link" href="#">
|
||||
<a class="unstyled-link" href="/messages">
|
||||
<li class="quick-link">
|
||||
<img class="svg-icon" src="/static/icons/messages.svg" />
|
||||
<span>Messages</span>
|
||||
|
9
internal/webserver/tpl/messages.tpl
Normal file
9
internal/webserver/tpl/messages.tpl
Normal file
@ -0,0 +1,9 @@
|
||||
{{define "title"}}Followed Users{{end}}
|
||||
|
||||
{{define "main"}}
|
||||
<div class="chats-container">
|
||||
{{template "chat-list" .}}
|
||||
{{template "chat-view" .}}
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
{{end}}
|
18
internal/webserver/tpl/tweet_page_includes/chat_list.tpl
Normal file
18
internal/webserver/tpl/tweet_page_includes/chat_list.tpl
Normal file
@ -0,0 +1,18 @@
|
||||
{{define "chat-list"}}
|
||||
<div class="chat-list">
|
||||
{{range .RoomIDs}}
|
||||
{{$room := (index $.Rooms .)}}
|
||||
<div class="chat" hx-get="/messages/{{$room.ID}}" hx-target="#chat-view" hx-swap="outerHTML" hx-push-url="true">
|
||||
{{range $room.Participants}}
|
||||
{{if (ne .UserID (active_user).ID)}}
|
||||
<!-- This is some fuckery; I have no idea why "hx-target" is needed, but otherwise it targets the #chat-view. -->
|
||||
<div class="click-eater" hx-trigger="click consume" hx-target="body">
|
||||
{{template "author-info" (user .UserID)}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<p class="chat-preview">{{(index $.DMTrove.Messages $room.LastMessageID).Text}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
25
internal/webserver/tpl/tweet_page_includes/chat_view.tpl
Normal file
25
internal/webserver/tpl/tweet_page_includes/chat_view.tpl
Normal file
@ -0,0 +1,25 @@
|
||||
{{define "chat-view"}}
|
||||
<div id="chat-view">
|
||||
{{range .MessageIDs}}
|
||||
{{$message := (index $.DMTrove.Messages .)}}
|
||||
{{$user := (user $message.SenderID)}}
|
||||
{{$is_us := (eq $message.SenderID (active_user).ID)}}
|
||||
<div class="dm-message-and-reacts-container {{if $is_us}} our-message {{end}}">
|
||||
<div class="dm-message-container">
|
||||
<div class="sender-profile-image-container">
|
||||
<a class="unstyled-link" href="/{{$user.Handle}}">
|
||||
<img class="profile-image" src="/content/{{$user.GetProfileImageLocalPath}}" />
|
||||
</a>
|
||||
</div>
|
||||
<p class="dm-message-text">{{$message.Text}}</p>
|
||||
</div>
|
||||
<div class="dm-message-reactions">
|
||||
{{range $message.Reactions}}
|
||||
{{$sender := (user .SenderID)}}
|
||||
<span title="{{$sender.DisplayName}} (@{{$sender.Handle}})">{{.Emoji}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
Loading…
x
Reference in New Issue
Block a user