Add unread messages notification indicator bubble in the nav sidebar

This commit is contained in:
Alessio 2024-04-28 15:21:39 -07:00
parent 0196cb681b
commit 3fedde7aa5
7 changed files with 64 additions and 29 deletions

View File

@ -107,13 +107,16 @@ func (app *Application) ChangeSession(w http.ResponseWriter, r *http.Request) {
form := struct { form := struct {
AccountName string `json:"account"` AccountName string `json:"account"`
}{} }{}
data, err := io.ReadAll(r.Body) formdata, err := io.ReadAll(r.Body)
panic_if(err) panic_if(err)
panic_if(json.Unmarshal(data, &form)) // TODO: HTTP 400 not 500 panic_if(json.Unmarshal(formdata, &form)) // TODO: HTTP 400 not 500
err = app.SetActiveUser(scraper.UserHandle(form.AccountName)) err = app.SetActiveUser(scraper.UserHandle(form.AccountName))
if err != nil { if err != nil {
app.error_400_with_message(w, fmt.Sprintf("User not in database: %s", form.AccountName)) app.error_400_with_message(w, fmt.Sprintf("User not in database: %s", form.AccountName))
return return
} }
app.buffered_render_htmx(w, "nav-sidebar", PageGlobalData{}, nil) data := Notifications{
NumMessageNotifications: len(app.Profile.GetUnreadConversations(app.ActiveUser.ID)),
}
app.buffered_render_htmx(w, "nav-sidebar", PageGlobalData{}, data)
} }

View File

@ -15,11 +15,16 @@ import (
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper" "gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
) )
type Notifications struct {
NumMessageNotifications int
}
// TODO: this name sucks // TODO: this name sucks
type PageGlobalData struct { type PageGlobalData struct {
scraper.TweetTrove scraper.TweetTrove
SearchText string SearchText string
FocusedTweetID scraper.TweetID FocusedTweetID scraper.TweetID
Notifications
} }
func (d PageGlobalData) Tweet(id scraper.TweetID) scraper.Tweet { func (d PageGlobalData) Tweet(id scraper.TweetID) scraper.Tweet {
@ -41,6 +46,9 @@ func (d PageGlobalData) GetSearchText() string {
fmt.Println(d.SearchText) fmt.Println(d.SearchText)
return d.SearchText return d.SearchText
} }
func (d PageGlobalData) GlobalData() PageGlobalData {
return d
}
// Config object for buffered rendering // Config object for buffered rendering
type renderer struct { type renderer struct {
@ -80,6 +88,8 @@ func (r renderer) BufferedRender(w io.Writer) {
func (app *Application) buffered_render_page(w http.ResponseWriter, tpl_file string, global_data PageGlobalData, tpl_data interface{}) { func (app *Application) buffered_render_page(w http.ResponseWriter, tpl_file string, global_data PageGlobalData, tpl_data interface{}) {
partials := append(glob("tpl/includes/*.tpl"), glob("tpl/tweet_page_includes/*.tpl")...) partials := append(glob("tpl/includes/*.tpl"), glob("tpl/tweet_page_includes/*.tpl")...)
global_data.Notifications.NumMessageNotifications = len(app.Profile.GetUnreadConversations(app.ActiveUser.ID))
r := renderer{ r := renderer{
Funcs: app.make_funcmap(global_data), Funcs: app.make_funcmap(global_data),
Filenames: append(partials, get_filepath(tpl_file)), Filenames: append(partials, get_filepath(tpl_file)),
@ -112,6 +122,7 @@ func (app *Application) make_funcmap(global_data PageGlobalData) template.FuncMa
"space": global_data.Space, "space": global_data.Space,
"focused_tweet_id": global_data.GetFocusedTweetID, "focused_tweet_id": global_data.GetFocusedTweetID,
"search_text": global_data.GetSearchText, "search_text": global_data.GetSearchText,
"global_data": global_data.GlobalData, // This fucking sucks
"active_user": func() scraper.User { "active_user": func() scraper.User {
return app.ActiveUser return app.ActiveUser
}, },

View File

@ -535,8 +535,8 @@ main {
* Create some extra space for the pin icon at the top of a pinned tweet * Create some extra space for the pin icon at the top of a pinned tweet
*/ */
.pinned-tweet & { .pinned-tweet & {
margin-top: -2em; margin-top: -2em;
padding-top: 1.5em; padding-top: 1.5em;
} }
.timeline > &, .pinned-tweet & { .timeline > &, .pinned-tweet & {
/* not for nested (i.e., quoted) tweets */ /* not for nested (i.e., quoted) tweets */
@ -929,7 +929,24 @@ main {
align-items: flex-start; align-items: flex-start;
padding: 0 2em; padding: 0 2em;
} }
/* Enable positioning the notifications indicator relative to this */
.labelled-icon {
position: relative;
}
.nav-sidebar__notifications-count {
position: absolute;
left: 0.3em;
top: 0.3em;
background-color: var(--color-twitter-blue);
min-width: 1em;
line-height: 1em;
/* height: 1.2em; */
border-radius: 1em;
font-size: 0.7em;
color: white;
text-align: center;
padding: 0.2em;
}
#logged-in-user-info { #logged-in-user-info {
font-size: 0.8em; font-size: 0.8em;
margin-top: 1em; margin-top: 1em;
@ -1210,11 +1227,11 @@ main {
} }
.chat-list-entry__unread-indicator { .chat-list-entry__unread-indicator {
display: none; display: none;
background-color: var(--color-twitter-blue); background-color: var(--color-twitter-blue);
height: 0.5em; height: 0.5em;
width: 0.5em; width: 0.5em;
border-radius: 50%; border-radius: 50%;
flex: auto 0 0; /* Otherwise it gets squished if the message preview is long */ flex: auto 0 0; /* Otherwise it gets squished if the message preview is long */
.chat-list-entry--unread & { .chat-list-entry--unread & {
display: revert; display: revert;
@ -1307,15 +1324,15 @@ main {
/** /**
* Compact mode: * Compact mode:
* *
display: inline-block; display: inline-block;
padding: 0.5em 1em; padding: 0.5em 1em;
background-color: #ddd; background-color: #ddd;
border-radius: 1em; border-radius: 1em;
margin: auto; margin: auto;
min-height: 2em; min-height: 2em;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-around; justify-content: space-around;
*/ */
.our-message & { .our-message & {
background-color: var(--color-twitter-blue-light); background-color: var(--color-twitter-blue-light);

View File

@ -35,7 +35,7 @@
/> />
</form> </form>
</header> </header>
{{template "nav-sidebar"}} {{template "nav-sidebar" (global_data).Notifications}}
<main> <main>
{{template "main" .}} {{template "main" .}}
</main> </main>

View File

@ -19,16 +19,19 @@
<label class="nav-sidebar__button-label">Explore</label> <label class="nav-sidebar__button-label">Explore</label>
</li> </li>
</a> </a>
<a href="#">
<li class="button labelled-icon">
<img class="svg-icon" src="/static/icons/notifications.svg" width="24" height="24" />
<label class="nav-sidebar__button-label">Notifications</label>
</li>
</a>
{{if (not (eq (active_user).Handle "[nobody]"))}} {{if (not (eq (active_user).Handle "[nobody]"))}}
<a href="/messages"> <a href="#">
<li class="button labelled-icon"> <li class="button labelled-icon">
<img class="svg-icon" src="/static/icons/notifications.svg" width="24" height="24" />
<label class="nav-sidebar__button-label">Notifications</label>
</li>
</a>
<a href="/messages">
<li class="nav-sidebar__messages button labelled-icon">
<img class="svg-icon" src="/static/icons/messages.svg" width="24" height="24" /> <img class="svg-icon" src="/static/icons/messages.svg" width="24" height="24" />
{{if .NumMessageNotifications}}
<span class="nav-sidebar__notifications-count">{{.NumMessageNotifications}}</span>
{{end}}
<label class="nav-sidebar__button-label">Messages</label> <label class="nav-sidebar__button-label">Messages</label>
</li> </li>
</a> </a>

View File

@ -1,6 +1,6 @@
{{define "chat-list-entry"}} {{define "chat-list-entry"}}
{{$room := $.room}} {{$room := $.room}}
<div class="chat-list-entry {{if .is_active}}chat-list-entry--active-chat{{end}}" <div class="chat-list-entry {{if .is_active}}chat-list-entry--active-chat{{end}} {{if .is_unread}}chat-list-entry--unread{{end}}"
hx-get="/messages/{{$room.ID}}" hx-get="/messages/{{$room.ID}}"
hx-push-url="true" hx-push-url="true"
hx-swap="outerHTML" hx-swap="outerHTML"

View File

@ -229,6 +229,7 @@ func (p Profile) GetChatRoomsPreview(id UserID) DMChatView {
for _, room := range rooms { for _, room := range rooms {
// Fetch the latest message // Fetch the latest message
var msg DMMessage var msg DMMessage
msg.Reactions = make(map[UserID]DMReaction)
q, args, err := sqlx.Named(` q, args, err := sqlx.Named(`
select `+CHAT_MESSAGES_ALL_SQL_FIELDS+` select `+CHAT_MESSAGES_ALL_SQL_FIELDS+`
from chat_messages from chat_messages