add: finish ui rewrite
This commit is contained in:
parent
e9846016e6
commit
5dec98d698
119 changed files with 8776 additions and 9350 deletions
912
crates/app/src/public/html/communities/settings.lisp
Normal file
912
crates/app/src/public/html/communities/settings.lisp
Normal file
|
@ -0,0 +1,912 @@
|
|||
(text "{% extends \"root.html\" %} {% block head %}")
|
||||
(title
|
||||
(text "Community settings - {{ config.name }}"))
|
||||
|
||||
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
|
||||
(main
|
||||
("class" "flex flex-col gap-2")
|
||||
(div
|
||||
("class" "pillmenu")
|
||||
(a
|
||||
("href" "#/general")
|
||||
("data-tab-button" "general")
|
||||
("class" "active")
|
||||
(text "{{ icon \"settings\" }}")
|
||||
(span
|
||||
(text "{{ text \"settings:tab.general\" }}")))
|
||||
(a
|
||||
("href" "#/images")
|
||||
("data-tab-button" "images")
|
||||
(text "{{ icon \"image\" }}")
|
||||
(span
|
||||
(text "{{ text \"settings:tab.images\" }}")))
|
||||
(a
|
||||
("href" "#/members")
|
||||
("data-tab-button" "members")
|
||||
(text "{{ icon \"users-round\" }}")
|
||||
(span
|
||||
(text "{{ text \"communities:tab.members\" }}")))
|
||||
(text "{% if can_manage_channels -%}")
|
||||
(a
|
||||
("href" "#/channels")
|
||||
("data-tab-button" "channels")
|
||||
(text "{{ icon \"rss\" }}")
|
||||
(span
|
||||
(text "{{ text \"communities:tab.channels\" }}")))
|
||||
(text "{%- endif %} {% if can_manage_emojis -%}")
|
||||
(a
|
||||
("href" "#/emojis")
|
||||
("data-tab-button" "emojis")
|
||||
(text "{{ icon \"smile\" }}")
|
||||
(span
|
||||
(text "{{ text \"communities:tab.emojis\" }}")))
|
||||
(text "{%- endif %}"))
|
||||
(div
|
||||
("class" "w-full flex flex-col gap-2")
|
||||
("data-tab" "general")
|
||||
(div
|
||||
("id" "manage_fields")
|
||||
("class" "card tertiary flex flex-col gap-2")
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "read_access")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "Read access")))
|
||||
(div
|
||||
("class" "card")
|
||||
(select
|
||||
("onchange" "save_access(event, 'read')")
|
||||
(option
|
||||
("value" "Everybody")
|
||||
("selected" "{% if community.read_access == 'Everybody' -%}true{% else %}false{%- endif %}")
|
||||
(text "Everybody"))
|
||||
(option
|
||||
("value" "Joined")
|
||||
("selected" "{% if community.read_access == 'Joined' -%}true{% else %}false{%- endif %}")
|
||||
(text "Joined")))))
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "join_access")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "Join access")))
|
||||
(div
|
||||
("class" "card")
|
||||
(select
|
||||
("onchange" "save_access(event, 'join')")
|
||||
(option
|
||||
("value" "Everybody")
|
||||
("selected" "{% if community.join_access == 'Everybody' -%}true{% else %}false{%- endif %}")
|
||||
(text "Everybody"))
|
||||
(option
|
||||
("value" "Request")
|
||||
("selected" "{% if community.join_access == 'Request' -%}true{% else %}false{%- endif %}")
|
||||
(text "Request"))
|
||||
(option
|
||||
("value" "Nobody")
|
||||
("selected" "{% if community.join_access == 'Nobody' -%}true{% else %}false{%- endif %}")
|
||||
(text "Nobody")))))
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "write_access")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "Post permission")))
|
||||
(div
|
||||
("class" "card")
|
||||
(select
|
||||
("onchange" "save_access(event, 'write')")
|
||||
(option
|
||||
("value" "Everybody")
|
||||
("selected" "{% if community.write_access == 'Everybody' -%}true{% else %}false{%- endif %}")
|
||||
(text "Everybody"))
|
||||
(option
|
||||
("value" "Joined")
|
||||
("selected" "{% if community.write_access == 'Joined' -%}true{% else %}false{%- endif %}")
|
||||
(text "Joined"))
|
||||
(option
|
||||
("value" "Owner")
|
||||
("selected" "{% if community.write_access == 'Owner' -%}true{% else %}false{%- endif %}")
|
||||
(text "Owner only")))))
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "change_title")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "{{ text \"communities:label.change_title\" }}")))
|
||||
(form
|
||||
("class" "card flex flex-col gap-2")
|
||||
("onsubmit" "change_title(event)")
|
||||
(div
|
||||
("class" "flex flex-col gap-1")
|
||||
(label
|
||||
("for" "new_title")
|
||||
(text "{{ text \"communities:label.new_title\" }}"))
|
||||
(input
|
||||
("type" "text")
|
||||
("name" "new_title")
|
||||
("id" "new_title")
|
||||
("placeholder" "new_title")
|
||||
("required" "")
|
||||
("minlength" "2")))
|
||||
(button
|
||||
("class" "primary")
|
||||
(text "{{ icon \"check\" }}")
|
||||
(span
|
||||
(text "{{ text \"general:action.save\" }}"))))))
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "danger_zone")
|
||||
(div
|
||||
("class" "card small flex gap-1 items-center red")
|
||||
(text "{{ icon \"skull\" }}")
|
||||
(b
|
||||
(text "{{ text \"communities:label.danger_zone\" }}")))
|
||||
(div
|
||||
("class" "card flex flex-wrap gap-2")
|
||||
(button
|
||||
("class" "red quaternary")
|
||||
("onclick" "delete_community()")
|
||||
(text "{{ icon \"trash\" }}")
|
||||
(span
|
||||
(text "{{ text \"communities:label.delete_community\" }}")))))
|
||||
(div
|
||||
("class" "flex gap-2 flex-wrap")
|
||||
(button
|
||||
("onclick" "save_context()")
|
||||
(text "{{ icon \"check\" }}")
|
||||
(span
|
||||
(text "{{ text \"general:action.save\" }}")))
|
||||
(a
|
||||
("href" "/community/{{ community.title }}")
|
||||
("class" "button secondary")
|
||||
(text "{{ icon \"arrow-left\" }}")
|
||||
(span
|
||||
(text "{{ text \"general:action.back\" }}")))))
|
||||
(div
|
||||
("class" "card tertiary w-full hidden flex flex-col gap-2")
|
||||
("data-tab" "images")
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "change_avatar")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "{{ text \"settings:label.change_avatar\" }}")))
|
||||
(form
|
||||
("class" "card flex gap-2 flex-row flex-wrap items-center")
|
||||
("method" "post")
|
||||
("enctype" "multipart/form-data")
|
||||
("onsubmit" "upload_avatar(event)")
|
||||
(input
|
||||
("id" "avatar_file")
|
||||
("name" "file")
|
||||
("type" "file")
|
||||
("accept" "image/png,image/jpeg,image/avif,image/webp,image/gif")
|
||||
("class" "w-content"))
|
||||
(button
|
||||
("class" "primary")
|
||||
(text "{{ icon \"check\" }}"))))
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "change_banner")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "{{ text \"settings:label.change_banner\" }}")))
|
||||
(form
|
||||
("class" "card flex flex-col gap-2")
|
||||
("method" "post")
|
||||
("enctype" "multipart/form-data")
|
||||
("onsubmit" "upload_banner(event)")
|
||||
(div
|
||||
("class" "flex gap-2 flex-row flex-wrap items-center")
|
||||
(input
|
||||
("id" "banner_file")
|
||||
("name" "file")
|
||||
("type" "file")
|
||||
("accept" "image/png,image/jpeg,image/avif,image/webp")
|
||||
("class" "w-content"))
|
||||
(button
|
||||
("class" "primary")
|
||||
(text "{{ icon \"check\" }}")))
|
||||
(span
|
||||
("class" "fade")
|
||||
(text "Use an image of 1100x350px for the best results.")))))
|
||||
(div
|
||||
("class" "card tertiary w-full hidden flex flex-col gap-2")
|
||||
("data-tab" "members")
|
||||
(div
|
||||
("class" "card-nest")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "{{ text \"communities:label.select_member\" }}")))
|
||||
(form
|
||||
("class" "card flex-col gap-2")
|
||||
("onsubmit" "select_user_from_form(event)")
|
||||
(div
|
||||
("class" "flex flex-col gap-1")
|
||||
(div
|
||||
("class" "flex flex-col gap-1")
|
||||
(label
|
||||
("for" "uid")
|
||||
(text "{{ text \"communities:label.user_id\" }}"))
|
||||
(input
|
||||
("type" "number")
|
||||
("name" "uid")
|
||||
("id" "uid")
|
||||
("placeholder" "user id")
|
||||
("required" "")
|
||||
("minlength" "18")))
|
||||
(button
|
||||
("class" "primary")
|
||||
(text "{{ text \"communities:action.select\" }}")))))
|
||||
(div
|
||||
("class" "card flex flex-col gap-2 w-full")
|
||||
("id" "membership_info")))
|
||||
(text "{% if can_manage_channels -%}")
|
||||
(div
|
||||
("class" "card tertiary w-full hidden flex flex-col gap-2")
|
||||
("data-tab" "channels")
|
||||
(div
|
||||
("class" "card-nest")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "{{ text \"communities:action.create_channel\" }}")))
|
||||
(form
|
||||
("class" "card flex flex-col gap-2")
|
||||
("onsubmit" "create_channel_from_form(event)")
|
||||
(div
|
||||
("class" "flex flex-col gap-1")
|
||||
(label
|
||||
("for" "title")
|
||||
(text "{{ text \"communities:label.name\" }}"))
|
||||
(input
|
||||
("type" "text")
|
||||
("name" "title")
|
||||
("id" "title")
|
||||
("placeholder" "name")
|
||||
("required" "")
|
||||
("minlength" "2")
|
||||
("maxlength" "32")))
|
||||
(button
|
||||
("class" "primary")
|
||||
(text "{{ text \"communities:action.create\" }}"))))
|
||||
(text "{% for channel in channels %}")
|
||||
(div
|
||||
("class" "card-nest")
|
||||
(div
|
||||
("class" "card small")
|
||||
(b
|
||||
(text "{{ channel.position }} "))
|
||||
(text "{{ channel.title }}"))
|
||||
(div
|
||||
("class" "card flex gap-2")
|
||||
(button
|
||||
("class" "red quaternary small")
|
||||
("onclick" "delete_channel('{{ channel.id }}')")
|
||||
(text "{{ text \"general:action.delete\" }}"))
|
||||
(button
|
||||
("class" "quaternary small")
|
||||
("onclick" "update_channel_position('{{ channel.id }}')")
|
||||
(text "{{ text \"chats:action.move\" }}"))
|
||||
(button
|
||||
("class" "quaternary small")
|
||||
("onclick" "update_channel_title('{{ channel.id }}')")
|
||||
(text "{{ text \"chats:action.rename\" }}"))))
|
||||
(text "{% endfor %}"))
|
||||
(script
|
||||
(text "globalThis.delete_channel = async (id) => {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this?\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/channels/${id}`, {
|
||||
method: \"DELETE\",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.update_channel_position = async (id) => {
|
||||
await trigger(\"atto::debounce\", [\"channels::move\"]);
|
||||
|
||||
const position = Number.parseInt(
|
||||
await trigger(\"atto::prompt\", [
|
||||
\"New channel position (number):\",
|
||||
]),
|
||||
);
|
||||
|
||||
if (!position && position !== 0) {
|
||||
return alert(\"Must be a number!\");
|
||||
}
|
||||
|
||||
fetch(`/api/v1/channels/${id}/move`, {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
position,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.update_channel_title = async (id) => {
|
||||
await trigger(\"atto::debounce\", [\"channels::update_title\"]);
|
||||
const title = await trigger(\"atto::prompt\", [\"New channel title:\"]);
|
||||
|
||||
if (!title) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/channels/${id}/title`, {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
async function create_channel_from_form(e) {
|
||||
e.preventDefault();
|
||||
await trigger(\"atto::debounce\", [\"channels::create\"]);
|
||||
|
||||
fetch(\"/api/v1/channels\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: e.target.title.value,
|
||||
community: \"{{ community.id }}\",
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (res.ok) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}"))
|
||||
(text "{%- endif %} {% if can_manage_emojis -%}")
|
||||
(div
|
||||
("class" "card tertiary w-full hidden flex flex-col gap-2")
|
||||
("data-tab" "emojis")
|
||||
(text "{{ components::supporter_ad(body=\"Become a supporter to upload GIF animated emojis!\") }}")
|
||||
(div
|
||||
("class" "card-nest")
|
||||
("ui_ident" "change_banner")
|
||||
(div
|
||||
("class" "card small flex items-center gap-2")
|
||||
(text "{{ icon \"upload\" }}")
|
||||
(b
|
||||
(text "{{ text \"communities:label.upload\" }}")))
|
||||
(form
|
||||
("class" "card flex flex-col gap-2")
|
||||
("onsubmit" "upload_emoji(event)")
|
||||
(div
|
||||
("class" "flex flex-col gap-1")
|
||||
(label
|
||||
("for" "name")
|
||||
(text "{{ text \"communities:label.name\" }}"))
|
||||
(input
|
||||
("type" "text")
|
||||
("name" "name")
|
||||
("id" "name")
|
||||
("placeholder" "name")
|
||||
("required" "")
|
||||
("minlength" "2")
|
||||
("maxlength" "32")))
|
||||
(div
|
||||
("class" "flex flex-col gap-1")
|
||||
(label
|
||||
("for" "file")
|
||||
(text "{{ text \"communities:label.file\" }}"))
|
||||
(input
|
||||
("id" "banner_file")
|
||||
("name" "file")
|
||||
("type" "file")
|
||||
("accept" "image/png,image/jpeg,image/avif,image/webp")
|
||||
("class" "w-full")))
|
||||
(button
|
||||
(text "{{ text \"communities:action.create\" }}"))
|
||||
(span
|
||||
("class" "fade")
|
||||
(text "Emojis can be a maximum of 256 KiB, or 512x512px (width x
|
||||
height)."))))
|
||||
(text "{% for emoji in emojis %}")
|
||||
(div
|
||||
("class" "card secondary flex flex-wrap gap-2 items-center justify-between")
|
||||
(div
|
||||
("class" "flex gap-2 items-center")
|
||||
(img
|
||||
("src" "/api/v1/communities/{{ community.id }}/emojis/{{ emoji.name }}")
|
||||
("alt" "{{ emoji.name }}")
|
||||
("class" "emoji")
|
||||
("loading" "lazy"))
|
||||
(b
|
||||
(text "{{ emoji.name }}")))
|
||||
(div
|
||||
("class" "flex gap-2")
|
||||
(button
|
||||
("class" "quaternary small")
|
||||
("onclick" "rename_emoji('{{ emoji.id }}')")
|
||||
(text "{{ icon \"pencil\" }}")
|
||||
(span
|
||||
(text "{{ text \"chats:action.rename\" }}")))
|
||||
(button
|
||||
("class" "quaternary small red")
|
||||
("onclick" "remove_emoji('{{ emoji.id }}')")
|
||||
(text "{{ icon \"x\" }}")
|
||||
(span
|
||||
(text "{{ text \"stacks:label.remove\" }}")))))
|
||||
(text "{% endfor %}"))
|
||||
(script
|
||||
(text "globalThis.upload_emoji = (e) => {
|
||||
e.preventDefault();
|
||||
e.target.querySelector(\"button\").style.display = \"none\";
|
||||
|
||||
fetch(
|
||||
`/api/v1/communities/{{ community.id }}/emojis/${e.target.name.value}`,
|
||||
{
|
||||
method: \"POST\",
|
||||
body: e.target.file.files[0],
|
||||
},
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
e.target.querySelector(\"button\").removeAttribute(\"style\");
|
||||
});
|
||||
|
||||
alert(\"Emoji upload in progress. Please wait!\");
|
||||
};
|
||||
|
||||
globalThis.rename_emoji = async (id) => {
|
||||
const name = await trigger(\"atto::prompt\", [\"New emoji name:\"]);
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/emojis_id/${id}/name`, {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.remove_emoji = async (id) => {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this? This action is permanent.\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/emojis_id/${id}`, {
|
||||
method: \"DELETE\",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};"))
|
||||
(text "{%- endif %}"))
|
||||
|
||||
(script
|
||||
(text "setTimeout(() => {
|
||||
const element = document.getElementById(\"membership_info\");
|
||||
const ui = ns(\"ui\");
|
||||
|
||||
const uid = new URLSearchParams(window.location.search).get(\"uid\");
|
||||
if (uid) {
|
||||
document.getElementById(\"uid\").value = uid;
|
||||
}
|
||||
|
||||
globalThis.update_user_role = async (uid, new_role) => {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this?\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(
|
||||
`/api/v1/communities/{{ community.id }}/memberships/${uid}/role`,
|
||||
{
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
role: Number.parseInt(new_role),
|
||||
}),
|
||||
},
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.kick_user = async (uid, new_role) => {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this?\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/communities/{{ community.id }}/memberships/${uid}`, {
|
||||
method: \"DELETE\",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.transfer_ownership = async (uid) => {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this?\n\nThis action is PERMANENT!\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/communities/{{ community.id }}/transfer_ownership`, {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user: uid,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.select_user_from_form = (e) => {
|
||||
e.preventDefault();
|
||||
fetch(
|
||||
`/api/v1/communities/{{ community.id }}/memberships/${e.target.uid.value}`,
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
if (!res.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
// permissions manager
|
||||
const get_permissions_html = trigger(
|
||||
\"ui::generate_permissions_ui\",
|
||||
[
|
||||
{
|
||||
// https://trisuaso.github.io/tetratto/tetratto/model/communities_permissions/struct.CommunityPermission.html
|
||||
DEFAULT: 1 << 0,
|
||||
ADMINISTRATOR: 1 << 1,
|
||||
MEMBER: 1 << 2,
|
||||
MANAGE_POSTS: 1 << 3,
|
||||
MANAGE_ROLES: 1 << 4,
|
||||
BANNED: 1 << 5,
|
||||
REQUESTED: 1 << 6,
|
||||
MANAGE_PINS: 1 << 7,
|
||||
MANAGE_COMMUNITY: 1 << 8,
|
||||
MANAGE_QUESTIONS: 1 << 9,
|
||||
MANAGE_CHANNELS: 1 << 10,
|
||||
MANAGE_MESSAGES: 1 << 11,
|
||||
MANAGE_EMOJIS: 1 << 12,
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
// ...
|
||||
element.innerHTML = `<div class=\"flex gap-2 flex-wrap\" ui_ident=\"actions\">
|
||||
<a target=\"_blank\" class=\"button\" href=\"/api/v1/auth/user/find/${e.target.uid.value}\">Open user profile</a>
|
||||
${res.payload.role !== 33 ? `<button class=\"red quaternary\" onclick=\"update_user_role('${e.target.uid.value}', 33)\">Ban</button>` : `<button class=\"quaternary\" onclick=\"update_user_role('${e.target.uid.value}', 5)\">Unban</button>`}
|
||||
${res.payload.role !== 65 ? `<button class=\"red quaternary\" onclick=\"update_user_role('${e.target.uid.value}', 65)\">Send to review</button>` : `<button class=\"green quaternary\" onclick=\"update_user_role('${e.target.uid.value}', 5)\">Accept join request</button>`}
|
||||
<button class=\"red quaternary\" onclick=\"kick_user('${e.target.uid.value}')\">Kick</button>
|
||||
<button class=\"red quaternary\" onclick=\"transfer_ownership('${e.target.uid.value}')\">Transfer ownership</button>
|
||||
</div>
|
||||
|
||||
<div class=\"flex flex-col gap-2\" ui_ident=\"permissions\" id=\"permissions\">
|
||||
${get_permissions_html(res.payload.role, \"permissions\")}
|
||||
</div>`;
|
||||
|
||||
ui.refresh_container(element, [\"actions\", \"permissions\"]);
|
||||
ui.generate_settings_ui(
|
||||
element,
|
||||
[
|
||||
[
|
||||
[\"role\", \"Permission level\"],
|
||||
res.payload.role,
|
||||
\"input\",
|
||||
],
|
||||
],
|
||||
null,
|
||||
{
|
||||
role: (new_role) => {
|
||||
const [matching, _] =
|
||||
all_matching_permissions(new_role);
|
||||
|
||||
document.getElementById(
|
||||
\"permissions\",
|
||||
).innerHTML = get_permissions_html(
|
||||
rebuild_role(matching),
|
||||
\"permissions\",
|
||||
);
|
||||
|
||||
return update_user_role(
|
||||
e.target.uid.value,
|
||||
new_role,
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
}, 250);"))
|
||||
|
||||
(script
|
||||
("type" "application/json")
|
||||
("id" "settings_json")
|
||||
(text "{{ community.context|json_encode()|safe }}"))
|
||||
|
||||
(script
|
||||
(text "setTimeout(() => {
|
||||
const ui = ns(\"ui\");
|
||||
const settings = JSON.parse(
|
||||
document.getElementById(\"settings_json\").innerHTML,
|
||||
);
|
||||
|
||||
globalThis.upload_avatar = (e) => {
|
||||
e.preventDefault();
|
||||
e.target.querySelector(\"button\").style.display = \"none\";
|
||||
|
||||
fetch(\"/api/v1/communities/{{ community.id }}/upload/avatar\", {
|
||||
method: \"POST\",
|
||||
body: e.target.file.files[0],
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
e.target.querySelector(\"button\").removeAttribute(\"style\");
|
||||
});
|
||||
|
||||
alert(\"Avatar upload in progress. Please wait!\");
|
||||
};
|
||||
|
||||
globalThis.upload_banner = (e) => {
|
||||
e.preventDefault();
|
||||
e.target.querySelector(\"button\").style.display = \"none\";
|
||||
|
||||
fetch(\"/api/v1/communities/{{ community.id }}/upload/banner\", {
|
||||
method: \"POST\",
|
||||
body: e.target.file.files[0],
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
|
||||
e.target.querySelector(\"button\").removeAttribute(\"style\");
|
||||
});
|
||||
|
||||
alert(\"Banner upload in progress. Please wait!\");
|
||||
};
|
||||
|
||||
globalThis.save_context = () => {
|
||||
fetch(\"/api/v1/communities/{{ community.id }}/context\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
context: settings,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.save_access = (event, mode) => {
|
||||
const selected = event.target.selectedOptions[0];
|
||||
fetch(`/api/v1/communities/{{ community.id }}/access/${mode}`, {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
access: selected.value,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.change_title = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this?\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(\"/api/v1/communities/{{ community.id }}/title\", {
|
||||
method: \"POST\",
|
||||
headers: {
|
||||
\"Content-Type\": \"application/json\",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: e.target.new_title.value,
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
globalThis.delete_community = async () => {
|
||||
if (
|
||||
!(await trigger(\"atto::confirm\", [
|
||||
\"Are you sure you would like to do this? This action is permanent.\",
|
||||
]))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/v1/communities/{{ community.id }}`, {
|
||||
method: \"DELETE\",
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
trigger(\"atto::toast\", [
|
||||
res.ok ? \"success\" : \"error\",
|
||||
res.message,
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
ui.refresh_container(document.getElementById(\"manage_fields\"), [
|
||||
\"read_access\",
|
||||
\"join_access\",
|
||||
\"write_access\",
|
||||
\"change_title\",
|
||||
\"change_avatar\",
|
||||
\"change_banner\",
|
||||
]);
|
||||
|
||||
ui.generate_settings_ui(
|
||||
document.getElementById(\"manage_fields\"),
|
||||
[
|
||||
[
|
||||
[\"display_name\", \"Display title\"],
|
||||
\"{{ community.context.display_name }}\",
|
||||
\"input\",
|
||||
],
|
||||
[
|
||||
[\"description\", \"Description\"],
|
||||
settings.description,
|
||||
\"textarea\",
|
||||
],
|
||||
[
|
||||
[\"is_nsfw\", \"Mark as NSFW\"],
|
||||
\"{{ community.context.is_nsfw }}\",
|
||||
\"checkbox\",
|
||||
],
|
||||
[
|
||||
[
|
||||
\"enable_questions\",
|
||||
\"Allow users to ask questions in this community\",
|
||||
],
|
||||
\"{{ community.context.enable_questions }}\",
|
||||
\"checkbox\",
|
||||
],
|
||||
],
|
||||
settings,
|
||||
);
|
||||
}, 250);"))
|
||||
|
||||
(text "{% endblock %}")
|
Loading…
Add table
Add a link
Reference in a new issue