add: user status
This commit is contained in:
parent
1724f798ca
commit
a009ef9e34
10 changed files with 259 additions and 138 deletions
|
@ -107,7 +107,7 @@ article {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
body .card:not(.card *):not(#stream *),
|
||||
body .card:not(.card *):not(#stream *):not(.user_plate),
|
||||
body .pillmenu:not(.card *) > a,
|
||||
body .card-nest:not(.card *) > .card,
|
||||
body .banner {
|
||||
|
@ -340,6 +340,18 @@ img.contain {
|
|||
max-height: 350px;
|
||||
}
|
||||
|
||||
.user_status span {
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.user_status .icon {
|
||||
min-width: 1em;
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
/* table */
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
|
@ -416,6 +428,10 @@ table ol {
|
|||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.card.tiny {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.card.secondary {
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
@ -477,6 +493,12 @@ button.small,
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
button.small.square,
|
||||
.button.small.square {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
button.big_icon svg,
|
||||
.button.big_icon svg {
|
||||
height: 16px;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{% extends "root.html" %} {% block head %}
|
||||
<title>Chats - {{ config.name }}</title>
|
||||
{% endblock %} {% block body %} {{ macros::nav(selected="chats") }}
|
||||
{% endblock %} {% block body %} {{ macros::nav(selected="chats",
|
||||
hide_user_menu=true) }}
|
||||
<nav class="chats_nav">
|
||||
<button
|
||||
class="flex gap-2 items-center active"
|
||||
|
@ -44,59 +45,64 @@
|
|||
{% endif %} {% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="sidebar flex flex-col gap-2" id="channels_list">
|
||||
<div class="title flex justify-between">
|
||||
{% if community %}
|
||||
<b class="name shorter">
|
||||
{% if community.context.display_name %} {{
|
||||
community.context.display_name }} {% else %} {{ community.title
|
||||
}} {% endif %}
|
||||
</b>
|
||||
{% else %}
|
||||
<b>{{ text "chats:label.my_chats" }}</b>
|
||||
{% endif %}
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="camo small"
|
||||
onclick="trigger('atto::hooks::dropdown', [event])"
|
||||
exclude="dropdown"
|
||||
>
|
||||
{{ icon "ellipsis" }}
|
||||
</button>
|
||||
<div class="sidebar flex flex-col gap-2 justify-between" id="channels_list">
|
||||
<div class="flex flex-col gap-2 w-full">
|
||||
<div class="title flex justify-between">
|
||||
{% if community %}
|
||||
<b class="name shorter">
|
||||
{% if community.context.display_name %} {{
|
||||
community.context.display_name }} {% else %} {{
|
||||
community.title }} {% endif %}
|
||||
</b>
|
||||
{% else %}
|
||||
<b>{{ text "chats:label.my_chats" }}</b>
|
||||
{% endif %}
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="camo small"
|
||||
onclick="trigger('atto::hooks::dropdown', [event])"
|
||||
exclude="dropdown"
|
||||
>
|
||||
{{ icon "ellipsis" }}
|
||||
</button>
|
||||
|
||||
<div class="inner">
|
||||
{% if selected_community != 0 %}
|
||||
<a href="/community/{{ selected_community }}">
|
||||
{{ icon "book-heart" }}
|
||||
<span
|
||||
>{{ text "communities:label.show_community" }}</span
|
||||
>
|
||||
</a>
|
||||
{% endif %} {% if can_manage_channels %}
|
||||
<a href="/community/{{ selected_community }}/manage">
|
||||
{{ icon "settings" }}
|
||||
<span>{{ text "general:action.manage" }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<div class="inner">
|
||||
{% if selected_community != 0 %}
|
||||
<a href="/community/{{ selected_community }}">
|
||||
{{ icon "book-heart" }}
|
||||
<span
|
||||
>{{ text "communities:label.show_community"
|
||||
}}</span
|
||||
>
|
||||
</a>
|
||||
{% endif %} {% if can_manage_channels %}
|
||||
<a href="/community/{{ selected_community }}/manage">
|
||||
{{ icon "settings" }}
|
||||
<span>{{ text "general:action.manage" }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if can_manage_channels %}
|
||||
<a
|
||||
class="button w-full justify-start quaternary"
|
||||
href="/community/{{ selected_community }}/manage#/channels"
|
||||
>
|
||||
{{ icon "plus" }}
|
||||
<span>{{ text "communities:action.create_channel" }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<turbo-frame
|
||||
id="channels_list_frame"
|
||||
src="/chats/{{ selected_community }}/{{ selected_channel }}/_channels"
|
||||
target="_top"
|
||||
></turbo-frame>
|
||||
</div>
|
||||
|
||||
{% if can_manage_channels %}
|
||||
<a
|
||||
class="button w-full justify-start quaternary"
|
||||
href="/community/{{ selected_community }}/manage#/channels"
|
||||
>
|
||||
{{ icon "plus" }}
|
||||
<span>{{ text "communities:action.create_channel" }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<turbo-frame
|
||||
id="channels_list_frame"
|
||||
src="/chats/{{ selected_community }}/{{ selected_channel }}/_channels"
|
||||
target="_top"
|
||||
></turbo-frame>
|
||||
{{ components::user_plate(user=user, show_menu=true) }}
|
||||
</div>
|
||||
|
||||
{% if channel %}
|
||||
|
@ -253,7 +259,7 @@
|
|||
z-index: 1;
|
||||
}
|
||||
|
||||
.sidebar .title {
|
||||
.sidebar .title:not(.dropdown *) {
|
||||
padding: 1rem;
|
||||
border-bottom: solid 1px var(--color-super-lowered);
|
||||
}
|
||||
|
@ -321,6 +327,10 @@
|
|||
.chats_nav {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
height: calc(100dvh - 42px * 2);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -973,4 +973,128 @@ can_manage_message=false, grouped=false) -%}
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro %} {% macro user_menu() -%}
|
||||
<div class="inner">
|
||||
<b class="title">{{ user.username }}</b>
|
||||
<a href="/@{{ user.username }}">
|
||||
{{ icon "circle-user-round" }}
|
||||
<span>{{ text "auth:link.my_profile" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/settings">
|
||||
{{ icon "settings" }}
|
||||
<span>{{ text "auth:link.settings" }}</span>
|
||||
</a>
|
||||
|
||||
{% if is_helper %}
|
||||
<b class="title">{{ text "general:label.mod" }}</b>
|
||||
|
||||
<a href="/mod_panel/audit_log">
|
||||
{{ icon "scroll-text" }}
|
||||
<span>{{ text "general:link.audit_log" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/mod_panel/reports">
|
||||
{{ icon "flag" }}
|
||||
<span>{{ text "general:link.reports" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/mod_panel/ip_bans">
|
||||
{{ icon "ban" }}
|
||||
<span>{{ text "general:link.ip_bans" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/mod_panel/stats">
|
||||
{{ icon "chart-line" }}
|
||||
<span>{{ text "general:link.stats" }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<b class="title">{{ config.name }}</b>
|
||||
|
||||
<a href="https://github.com/trisuaso/tetratto">
|
||||
{{ icon "code" }}
|
||||
<span>{{ text "general:link.source_code" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="https://trisuaso.github.io/tetratto">
|
||||
{{ icon "book" }}
|
||||
<span>{{ text "general:link.reference" }}</span>
|
||||
</a>
|
||||
|
||||
<div class="title"></div>
|
||||
<button onclick="trigger('me::switch_account')">
|
||||
{{ icon "ellipsis" }}
|
||||
<span>{{ text "general:action.switch_account" }}</span>
|
||||
</button>
|
||||
|
||||
<button class="red" onclick="trigger('me::logout')">
|
||||
{{ icon "log-out" }}
|
||||
<span>{{ text "auth:action.logout" }}</span>
|
||||
</button>
|
||||
</div>
|
||||
{%- endmacro %} {% macro user_status(other_user) -%} {% if
|
||||
other_user.settings.status %}
|
||||
<div class="flex items-center gap-2">
|
||||
<span>{{ other_user.settings.status }}</span>
|
||||
|
||||
<!-- connection icon -->
|
||||
{% if (other_user.connections.LastFm[1].data and
|
||||
other_user.connections.LastFm[1].data.track) or
|
||||
(other_user.connections.Spotify[1].data and
|
||||
other_user.connections.Spotify[1].data.track) %} {{ icon "music" }} {% endif
|
||||
%}
|
||||
</div>
|
||||
{% elif other_user.connections.LastFm[0].data.name and
|
||||
other_user.connections.LastFm[1].data and
|
||||
other_user.connections.LastFm[1].data.track %}
|
||||
<div class="flex items-center gap-2">
|
||||
{{ icon "music" }}
|
||||
<span
|
||||
><b>Listening to</b> {{ other_user.connections.LastFm[1].data.artist
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
{% elif other_user.connections.Spotify[0].data.name and
|
||||
other_user.connections.Spotify[1].data and
|
||||
other_user.connections.Spotify[1].data.track %}
|
||||
<div class="flex items-center gap-2">
|
||||
{{ icon "music" }}
|
||||
<span
|
||||
><b>Listening to</b> {{ other_user.connections.Spotify[1].data.artist
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
{% endif %} {%- endmacro %} {% macro user_plate(user, show_menu=false,
|
||||
secondary=false) -%}
|
||||
<div
|
||||
class="flex gap-2 items-center card tiny user_plate {% if secondary %}secondary{% endif %}"
|
||||
>
|
||||
<a href="/@{{ user.username }}">
|
||||
{{ self::avatar(username=user.username, size="42px",
|
||||
selector_type="username") }}
|
||||
</a>
|
||||
|
||||
<div
|
||||
class="flex justify-center flex-col"
|
||||
style="{% if show_menu %}width: 60%{% endif %}"
|
||||
>
|
||||
{{ self::full_username(user=user) }}
|
||||
<div class="user_status">{{ self::user_status(other_user=user) }}</div>
|
||||
</div>
|
||||
|
||||
{% if show_menu %}
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="camo small square"
|
||||
onclick="trigger('atto::hooks::dropdown', [event])"
|
||||
exclude="dropdown"
|
||||
>
|
||||
{{ icon "settings" c(dropdown-arrow) }}
|
||||
</button>
|
||||
|
||||
{{ self::user_menu() }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% macro nav(selected="", show_lhs=true) -%}
|
||||
{% macro nav(selected="", show_lhs=true, hide_user_menu=false) -%}
|
||||
<nav>
|
||||
<div class="content_container">
|
||||
<div class="flex nav_side">
|
||||
|
@ -72,79 +72,21 @@
|
|||
>
|
||||
</a>
|
||||
|
||||
{% if not hide_user_menu %}
|
||||
<div class="dropdown">
|
||||
<!-- prettier-ignore -->
|
||||
<button
|
||||
class="flex-row title"
|
||||
onclick="trigger('atto::hooks::dropdown', [event])"
|
||||
exclude="dropdown"
|
||||
style="gap: 0.25rem !important"
|
||||
>
|
||||
{{ components::avatar(username=user.username, size="24px") }}
|
||||
{{ icon "chevron-down" c(dropdown-arrow) }}
|
||||
{{ components::avatar(username=user.username, size="24px")
|
||||
}} {{ icon "chevron-down" c(dropdown-arrow) }}
|
||||
</button>
|
||||
|
||||
<div class="inner">
|
||||
<b class="title">{{ user.username }}</b>
|
||||
<a href="/@{{ user.username }}">
|
||||
{{ icon "circle-user-round" }}
|
||||
<span>{{ text "auth:link.my_profile" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/settings">
|
||||
{{ icon "settings" }}
|
||||
<span>{{ text "auth:link.settings" }}</span>
|
||||
</a>
|
||||
|
||||
{% if is_helper %}
|
||||
<b class="title">{{ text "general:label.mod" }}</b>
|
||||
|
||||
<a href="/mod_panel/audit_log">
|
||||
{{ icon "scroll-text" }}
|
||||
<span>{{ text "general:link.audit_log" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/mod_panel/reports">
|
||||
{{ icon "flag" }}
|
||||
<span>{{ text "general:link.reports" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/mod_panel/ip_bans">
|
||||
{{ icon "ban" }}
|
||||
<span>{{ text "general:link.ip_bans" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="/mod_panel/stats">
|
||||
{{ icon "chart-line" }}
|
||||
<span>{{ text "general:link.stats" }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<b class="title">{{ config.name }}</b>
|
||||
|
||||
<a href="https://github.com/trisuaso/tetratto">
|
||||
{{ icon "code" }}
|
||||
<span>{{ text "general:link.source_code" }}</span>
|
||||
</a>
|
||||
|
||||
<a href="https://trisuaso.github.io/tetratto">
|
||||
{{ icon "book" }}
|
||||
<span>{{ text "general:link.reference" }}</span>
|
||||
</a>
|
||||
|
||||
<div class="title"></div>
|
||||
<button onclick="trigger('me::switch_account')">
|
||||
{{ icon "ellipsis" }}
|
||||
<span>{{ text "general:action.switch_account" }}</span>
|
||||
</button>
|
||||
|
||||
<button class="red" onclick="trigger('me::logout')">
|
||||
{{ icon "log-out" }}
|
||||
<span>{{ text "auth:action.logout" }}</span>
|
||||
</button>
|
||||
</div>
|
||||
{{ components::user_menu() }}
|
||||
</div>
|
||||
{% else %}
|
||||
{% endif %} {% else %}
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="title"
|
||||
|
|
|
@ -5,17 +5,23 @@
|
|||
<span>{{ text "auth:label.followers" }}</span>
|
||||
</div>
|
||||
|
||||
<div class="card flex flex-col gap-4">
|
||||
<div class="card flex flex-wrap gap-4 flex-collapse">
|
||||
<!-- prettier-ignore -->
|
||||
{% for item in list %}
|
||||
<div class="card-nest">
|
||||
<div class="card small">
|
||||
Since <span class="date">{{ item[0].created }}</span>
|
||||
</div>
|
||||
|
||||
{{ components::user_card(user=item[1]) }}
|
||||
</div>
|
||||
{{ components::user_plate(user=item[1], secondary=true) }}
|
||||
{% endfor %} {{ components::pagination(page=page, items=list|length) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.user_plate {
|
||||
width: calc(50% - 0.5rem);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
.user_plate {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
|
|
@ -5,17 +5,23 @@
|
|||
<span>{{ text "auth:label.following" }}</span>
|
||||
</div>
|
||||
|
||||
<div class="card flex flex-col gap-4">
|
||||
<div class="card flex flex-wrap gap-4 flex-collapse">
|
||||
<!-- prettier-ignore -->
|
||||
{% for item in list %}
|
||||
<div class="card-nest">
|
||||
<div class="card small">
|
||||
Since <span class="date">{{ item[0].created }}</span>
|
||||
</div>
|
||||
|
||||
{{ components::user_card(user=item[1]) }}
|
||||
</div>
|
||||
{{ components::user_plate(user=item[1], secondary=true) }}
|
||||
{% endfor %} {{ components::pagination(page=page, items=list|length) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.user_plate {
|
||||
width: calc(50% - 0.5rem);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
.user_plate {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
|
|
@ -926,6 +926,11 @@
|
|||
settings.biography,
|
||||
"textarea",
|
||||
],
|
||||
[
|
||||
["status", "Status"],
|
||||
settings.status,
|
||||
"textarea",
|
||||
],
|
||||
[
|
||||
["warning", "Profile warning"],
|
||||
settings.warning,
|
||||
|
|
|
@ -51,6 +51,8 @@ pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: Str
|
|||
let mut user: Option<User> = None;
|
||||
let mut headers: Option<SocketHeaders> = None;
|
||||
|
||||
let channel_id = format!("chats/{community_id}");
|
||||
|
||||
// handle incoming messages on socket
|
||||
let dbc = db.clone();
|
||||
if let Some(Ok(WsMessage::Text(text))) = stream.next().await {
|
||||
|
@ -185,12 +187,13 @@ pub async fn handle_socket(socket: WebSocket, db: DataManager, community_id: Str
|
|||
});
|
||||
|
||||
let dbc = db.clone();
|
||||
let channel_id_c = channel_id.clone();
|
||||
let mut redis_task = tokio::spawn(async move {
|
||||
// forward messages from redis to the socket
|
||||
let mut pubsub = dbc.2.client.get_async_pubsub().await.unwrap();
|
||||
|
||||
pubsub.subscribe(user.id).await.unwrap();
|
||||
pubsub.subscribe(community_id.clone()).await.unwrap();
|
||||
pubsub.subscribe(channel_id_c).await.unwrap();
|
||||
|
||||
// listen for pubsub messages
|
||||
let mut pubsub = pubsub.into_on_message();
|
||||
|
|
|
@ -165,13 +165,13 @@ impl DataManager {
|
|||
// post event
|
||||
let mut con = self.2.get_con().await;
|
||||
|
||||
if let Err(e) = con.publish::<usize, String, ()>(
|
||||
if let Err(e) = con.publish::<String, String, ()>(
|
||||
if channel.community != 0 {
|
||||
// broadcast to community ws
|
||||
channel.community
|
||||
format!("chats/{}", channel.community)
|
||||
} else {
|
||||
// broadcast to channel ws
|
||||
channel.id
|
||||
format!("chats/{}", channel.id)
|
||||
},
|
||||
serde_json::to_string(&SocketMessage {
|
||||
method: SocketMethod::Message,
|
||||
|
@ -224,13 +224,13 @@ impl DataManager {
|
|||
// post event
|
||||
let mut con = self.2.get_con().await;
|
||||
|
||||
if let Err(e) = con.publish::<usize, String, ()>(
|
||||
if let Err(e) = con.publish::<String, String, ()>(
|
||||
if channel.community != 0 {
|
||||
// broadcast to community ws
|
||||
channel.community
|
||||
format!("chats/{}", channel.community)
|
||||
} else {
|
||||
// broadcast to channel ws
|
||||
channel.id
|
||||
format!("chats/{}", channel.id)
|
||||
},
|
||||
serde_json::to_string(&SocketMessage {
|
||||
method: SocketMethod::Delete,
|
||||
|
|
|
@ -200,6 +200,9 @@ pub struct UserSettings {
|
|||
/// If other users that you aren't following can add you to chats.
|
||||
#[serde(default)]
|
||||
pub private_chats: bool,
|
||||
/// The user's status. Shows over connection info.
|
||||
#[serde(default)]
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
impl Default for User {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue