diff --git a/internal/webserver/handler_messages.go b/internal/webserver/handler_messages.go new file mode 100644 index 0000000..a697a13 --- /dev/null +++ b/internal/webserver/handler_messages.go @@ -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 +// } diff --git a/internal/webserver/server.go b/internal/webserver/server.go index 06f185b..0816b5f 100644 --- a/internal/webserver/server.go +++ b/internal/webserver/server.go @@ -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) } diff --git a/internal/webserver/static/styles.css b/internal/webserver/static/styles.css index a60d7bc..64219eb 100644 --- a/internal/webserver/static/styles.css +++ b/internal/webserver/static/styles.css @@ -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; +} diff --git a/internal/webserver/tpl/includes/nav_sidebar.tpl b/internal/webserver/tpl/includes/nav_sidebar.tpl index 4f5cb94..fcf1800 100644 --- a/internal/webserver/tpl/includes/nav_sidebar.tpl +++ b/internal/webserver/tpl/includes/nav_sidebar.tpl @@ -25,7 +25,7 @@ Notifications - + Messages diff --git a/internal/webserver/tpl/messages.tpl b/internal/webserver/tpl/messages.tpl new file mode 100644 index 0000000..b01ffc5 --- /dev/null +++ b/internal/webserver/tpl/messages.tpl @@ -0,0 +1,9 @@ +{{define "title"}}Followed Users{{end}} + +{{define "main"}} + + {{template "chat-list" .}} + {{template "chat-view" .}} + + +{{end}} diff --git a/internal/webserver/tpl/tweet_page_includes/chat_list.tpl b/internal/webserver/tpl/tweet_page_includes/chat_list.tpl new file mode 100644 index 0000000..db31cec --- /dev/null +++ b/internal/webserver/tpl/tweet_page_includes/chat_list.tpl @@ -0,0 +1,18 @@ +{{define "chat-list"}} + + {{range .RoomIDs}} + {{$room := (index $.Rooms .)}} + + {{range $room.Participants}} + {{if (ne .UserID (active_user).ID)}} + + + {{template "author-info" (user .UserID)}} + + {{end}} + {{end}} + {{(index $.DMTrove.Messages $room.LastMessageID).Text}} + + {{end}} + +{{end}} diff --git a/internal/webserver/tpl/tweet_page_includes/chat_view.tpl b/internal/webserver/tpl/tweet_page_includes/chat_view.tpl new file mode 100644 index 0000000..b4b7bb6 --- /dev/null +++ b/internal/webserver/tpl/tweet_page_includes/chat_view.tpl @@ -0,0 +1,25 @@ +{{define "chat-view"}} + + {{range .MessageIDs}} + {{$message := (index $.DMTrove.Messages .)}} + {{$user := (user $message.SenderID)}} + {{$is_us := (eq $message.SenderID (active_user).ID)}} + + + + + + + + {{$message.Text}} + + + {{range $message.Reactions}} + {{$sender := (user .SenderID)}} + {{.Emoji}} + {{end}} + + + {{end}} + +{{end}}
{{(index $.DMTrove.Messages $room.LastMessageID).Text}}
{{$message.Text}}