Add unread messages notification indicator bubble in the nav sidebar
This commit is contained in:
parent
0196cb681b
commit
3fedde7aa5
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user