generated from t/malachite
add: chats list page
This commit is contained in:
parent
c48cf78314
commit
747a05d649
16 changed files with 576 additions and 24 deletions
26
app/templates_src/chat.lisp
Normal file
26
app/templates_src/chat.lisp
Normal file
|
@ -0,0 +1,26 @@
|
|||
(text "{% extends \"root.lisp\" %} {% block head %}")
|
||||
(title
|
||||
(text "{{ components::chat_name(chat=chat, members=members) }} - {{ name }}"))
|
||||
(text "{% endblock %} {% block body %}")
|
||||
(div
|
||||
("class" "flex w_full gap_2 justify_between items_center")
|
||||
(div
|
||||
("class" "tabs short bar flex")
|
||||
(a
|
||||
("class" "button tab camo")
|
||||
("href" "/chats")
|
||||
(text "chats"))
|
||||
(a
|
||||
("class" "button tab")
|
||||
("href" "/chats/{{ chat.id }}")
|
||||
(text "{{ components::chat_name(chat=chat, members=members, advanced=true, avatar_size=\"18px\") }}"))))
|
||||
(div
|
||||
("class" "card flex flex_col gap_2")
|
||||
("style" "flex: 1 0 auto")
|
||||
(text "{% if messages|length == 0 -%}")
|
||||
(i ("class" "flex gap_ch items_center fade") (text "{{ icon \"star\" }} This is the start of the chat!"))
|
||||
(text "{%- endif %}"))
|
||||
|
||||
(script
|
||||
(text ""))
|
||||
(text "{% endblock %}")
|
217
app/templates_src/chats.lisp
Normal file
217
app/templates_src/chats.lisp
Normal file
|
@ -0,0 +1,217 @@
|
|||
(text "{% extends \"root.lisp\" %} {% block head %}")
|
||||
(title
|
||||
(text "My chats - {{ name }}"))
|
||||
(text "{% endblock %} {% block body %}")
|
||||
(div
|
||||
("class" "flex w_full gap_2 justify_between items_center")
|
||||
(div
|
||||
("class" "tabs short bar")
|
||||
(a
|
||||
("class" "button tab")
|
||||
("href" "/chats")
|
||||
(text "chats")))
|
||||
(button
|
||||
("class" "button")
|
||||
("title" "Create chat")
|
||||
("onclick" "document.getElementById('create_dialog').showModal()")
|
||||
(text "{{ icon \"plus\" }}")))
|
||||
(div
|
||||
("class" "card flex flex_col gap_2")
|
||||
(text "{% for chat in chats -%}")
|
||||
(div
|
||||
("class" "card surface w_full flex justify_between items_center gap_2")
|
||||
(a
|
||||
("class" "flex gap_ch items_center")
|
||||
("href" "/chats/{{ chat[0].id }}")
|
||||
(text "{{ components::chat_name(chat=chat[0], members=chat[1], advanced=true) }}"))
|
||||
(div
|
||||
("class" "dropdown")
|
||||
(button
|
||||
("onclick" "open_dropdown(event)")
|
||||
("exclude" "dropdown")
|
||||
("class" "button")
|
||||
(text "{{ icon \"ellipsis\" }}"))
|
||||
(div
|
||||
("class" "inner")
|
||||
(a
|
||||
("class" "button")
|
||||
("href" "/chats/{{ chat[0].id }}")
|
||||
("target" "_blank")
|
||||
(text "pop open"))
|
||||
|
||||
(text "{% if chat[0].style != \"Direct\" -%}")
|
||||
; group chat only
|
||||
(button
|
||||
("class" "button")
|
||||
("onclick" "rename_gc('{{ chat[0].id }}')")
|
||||
(text "rename"))
|
||||
(text "{%- endif %}")
|
||||
|
||||
(button
|
||||
("class" "button red")
|
||||
("onclick" "leave_chat('{{ chat[0].id }}')")
|
||||
(text "leave")))))
|
||||
(text "{%- endfor %}")
|
||||
|
||||
(text "{% if chats|length == 0 -%}")
|
||||
(i ("class" "flex gap_ch items_center fade") (text "{{ icon \"smile\" }} No results, yet!"))
|
||||
(text "{%- endif %}")
|
||||
|
||||
; pagination
|
||||
(div
|
||||
("class" "flex w_full items_center gap_2 justify_between")
|
||||
(text "{% if page > 0 -%}")
|
||||
(a
|
||||
("href" "?page={{ page - 1 }}")
|
||||
("class" "button surface")
|
||||
(text "{{ icon \"arrow-left\" }} Back"))
|
||||
(text "{%- else -%}")
|
||||
(div null?)
|
||||
(text "{%- endif %}")
|
||||
|
||||
(text "{% if chats|length > 0 -%}")
|
||||
(a
|
||||
("href" "?page={{ page + 1 }}")
|
||||
("class" "button surface")
|
||||
(text "Next {{ icon \"arrow-right\" }}"))
|
||||
(text "{%- endif %}")))
|
||||
|
||||
(dialog
|
||||
("id" "create_dialog")
|
||||
(div
|
||||
("class" "inner")
|
||||
(h2
|
||||
("class" "text_center w_full")
|
||||
(text "Create chat"))
|
||||
|
||||
(ul ("id" "members_list"))
|
||||
(form
|
||||
("class" "flex flex_row gap_2 w_full")
|
||||
("onsubmit" "add_member(event)")
|
||||
(input
|
||||
("type" "text")
|
||||
("list" "users_search")
|
||||
("name" "username")
|
||||
("id" "username")
|
||||
("placeholder" "username")
|
||||
("oninput" "search_users(event)"))
|
||||
(button
|
||||
("class" "button")
|
||||
(text "Add")))
|
||||
|
||||
(hr ("class" "margin"))
|
||||
|
||||
(div
|
||||
("class" "flex gap_2 justify_between")
|
||||
(button
|
||||
("onclick" "document.getElementById('create_dialog').close()")
|
||||
("class" "button red")
|
||||
(text "Cancel"))
|
||||
|
||||
(button
|
||||
("class" "button green")
|
||||
("onclick" "create_chat_from_form()")
|
||||
(text "Create")))))
|
||||
|
||||
(datalist ("id" "users_search"))
|
||||
|
||||
(script
|
||||
(text "globalThis.CHAT_MEMBERS = [];
|
||||
|
||||
function render_members() {
|
||||
document.getElementById('members_list').innerHTML = \"\";
|
||||
for (const member of CHAT_MEMBERS) {
|
||||
document.getElementById('members_list').innerHTML += `<li>${member} (<a href=\"javascript:remove_member('${member}')\" class=\"red\">remove</a>)</li>`;
|
||||
}
|
||||
}
|
||||
|
||||
function add_member(e) {
|
||||
e.preventDefault();
|
||||
const member = e.target.username.value;
|
||||
|
||||
if (CHAT_MEMBERS.includes(member)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHAT_MEMBERS.push(member);
|
||||
render_members();
|
||||
e.target.reset();
|
||||
}
|
||||
|
||||
function remove_member(member) {
|
||||
CHAT_MEMBERS.splice(CHAT_MEMBERS.indexOf(member), 1);
|
||||
render_members();
|
||||
}
|
||||
|
||||
function create_chat_from_form(e) {
|
||||
document.getElementById('create_dialog').close();
|
||||
|
||||
fetch(\"/api/v1/chats\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
style: CHAT_MEMBERS.length > 1 ? { Group: { name: \"Untitled\" } } : \"Direct\",
|
||||
members: CHAT_MEMBERS,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
show_message(res.message, res.ok);
|
||||
|
||||
if (res.ok) {
|
||||
window.location.href = `/chats/${res.payload}`;
|
||||
e.target.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let search_users_timeout;
|
||||
function search_users(e) {
|
||||
if (search_users_timeout) {
|
||||
clearTimeout(search_users_timeout);
|
||||
}
|
||||
|
||||
if (e.target.value.trim().length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
search_users_timeout = setTimeout(() => {
|
||||
fetch(\"/api/v1/auth/users/search\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
prefix: e.target.value.trim(),
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
if (res.ok) {
|
||||
document.getElementById(\"users_search\").innerHTML = \"\";
|
||||
for (const username of res.payload) {
|
||||
document.getElementById(\"users_search\").innerHTML += `<option value=\"${username}\">${username}</option>`;
|
||||
}
|
||||
} else {
|
||||
show_message(res.message, res.ok);
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function leave_chat(id) {
|
||||
if (!confirm(\"Are you sure you would like to do this?\")) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/chats/${id}/leave`, {
|
||||
method: \"POST\",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
show_message(res.message, res.ok);
|
||||
});
|
||||
}"))
|
||||
(text "{% endblock %}")
|
|
@ -7,3 +7,36 @@
|
|||
("loading" "lazy")
|
||||
("style" "--size: {{ size }}"))
|
||||
(text "{%- endmacro %}")
|
||||
|
||||
(text "{% macro username(user) -%}")
|
||||
(b
|
||||
(text "{% if user.settings.display_name|length > 0 -%}")
|
||||
(text "{{ user.settings.display_name }}")
|
||||
(text "{%- else -%}")
|
||||
(text "{{ user.username }}")
|
||||
(text "{%- endif %}"))
|
||||
(text "{%- endmacro %}")
|
||||
|
||||
(text "{% macro chat_name(chat, members, advanced=false, avatar_size=\"24px\") -%}")
|
||||
(text "{% if advanced -%}")
|
||||
; advanced
|
||||
(text "{% if chat.style == \"Direct\" -%} {% for member in members -%} {% if member.id != user.id -%}")
|
||||
; direct message; user that ISN'T the current user
|
||||
(text "{{ components::avatar(id=member.id, size=avatar_size) }}")
|
||||
(text "{{ components::username(user=member) }}")
|
||||
(text "{%- endif %} {%- endfor %} {%- else -%}")
|
||||
; group chat
|
||||
(text "{% for member in members -%} {{ components::avatar(id=member.id, size=avatar_size) }} {%- endfor %}")
|
||||
(b (text "{{ chat.style.Group.name }}"))
|
||||
(text "{%- endif %}")
|
||||
(text "{%- else -%}")
|
||||
; NOT advanced
|
||||
(text "{% if chat.style == \"Direct\" -%} {% for member in members -%} {% if member.id != user.id -%}")
|
||||
; direct message; user that ISN'T the current user
|
||||
(text "{{ user.username }}")
|
||||
(text "{%- endif %} {%- endfor %} {%- else -%}")
|
||||
; group chat
|
||||
(text "{{ chat.style.Group.name }}")
|
||||
(text "{%- endif %}")
|
||||
(text "{%- endif %}")
|
||||
(text "{%- endmacro %}")
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
(link ("rel" "stylesheet") ("href" "https://repodelivery.tetratto.com/tetratto/crates/app/src/public/css/utility.css"))
|
||||
(link ("rel" "stylesheet") ("href" "/public/style.css?v={{ build_code }}"))
|
||||
|
||||
(style (text ":root { --color-primary: {{ theme_color }}; }"))
|
||||
|
||||
(meta ("name" "theme-color") ("content" "{{ theme_color }}"))
|
||||
(meta ("property" "og:type") ("content" "website"))
|
||||
(meta ("property" "og:site_name") ("content" "{{ name }}"))
|
||||
|
@ -28,7 +26,7 @@
|
|||
(body
|
||||
; nav
|
||||
(nav
|
||||
("class" "flex w_full justify_between gap_2 sticky")
|
||||
("class" "flex w_full justify_between gap_2")
|
||||
(div
|
||||
("class" "flex side")
|
||||
(div
|
||||
|
@ -76,8 +74,7 @@
|
|||
("onclick" "user_logout()")
|
||||
(text "logout"))
|
||||
(text "{%- endif %}")
|
||||
(text "{% block dropdown %}{% endblock %}")))
|
||||
(a ("class" "button camo") ("href" "/") (b (text "{{ name }}"))))
|
||||
(text "{% block dropdown %}{% endblock %}"))))
|
||||
|
||||
(div
|
||||
("class" "side flex")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue