Compare commits
No commits in common. "113530acb8480137d1a66ba1b123f37a351da219" and "903aedc8ce0366aa98f180c5e1c210746a646928" have entirely different histories.
113530acb8
...
903aedc8ce
14 changed files with 158 additions and 792 deletions
|
|
@ -257,10 +257,5 @@
|
||||||
"en-cat": "Meowlish",
|
"en-cat": "Meowlish",
|
||||||
"avatar.updated": "Avatar updated successfully",
|
"avatar.updated": "Avatar updated successfully",
|
||||||
"profile.updated": "Profile updated successfully",
|
"profile.updated": "Profile updated successfully",
|
||||||
"banner.updated": "Banner updated successfully",
|
"banner.updated": "Banner updated successfully"
|
||||||
"action.invite": "Invite, meow",
|
}
|
||||||
"action.leaving.group": "Leaving group, meow...",
|
|
||||||
"action.key.rotating": "Rotating keys, meow...",
|
|
||||||
"action.key.rotation": "Key rotation, meow",
|
|
||||||
"desc.leave.group.confirm": "Are you sure you want to leave this group, meow?"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -257,10 +257,5 @@
|
||||||
"success:avatar.updated": "Avatar updated successfully",
|
"success:avatar.updated": "Avatar updated successfully",
|
||||||
"en-us": "English",
|
"en-us": "English",
|
||||||
"pl-pl": "Polish",
|
"pl-pl": "Polish",
|
||||||
"en-cat": "Meowlish",
|
"en-cat": "Meowlish"
|
||||||
"action.invite": "Invite",
|
}
|
||||||
"action.leaving.group": "Leaving group...",
|
|
||||||
"action.key.rotating": "Rotating keys...",
|
|
||||||
"action.key.rotation": "Key rotation",
|
|
||||||
"desc.leave.group.confirm": "Are you sure you want to leave this group?"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -257,10 +257,5 @@
|
||||||
"success:avatar.updated": "Awatar został pomyślnie zaktualizowany",
|
"success:avatar.updated": "Awatar został pomyślnie zaktualizowany",
|
||||||
"en-us": "Angielski",
|
"en-us": "Angielski",
|
||||||
"pl-pl": "Polski",
|
"pl-pl": "Polski",
|
||||||
"en-cat": "Koci (Meowlish)",
|
"en-cat": "Koci (Meowlish)"
|
||||||
"action.invite": "Zaproś",
|
}
|
||||||
"action.leaving.group": "Opuszczanie grupy...",
|
|
||||||
"action.key.rotating": "Obracanie kluczy...",
|
|
||||||
"action.key.rotation": "Rotacja kluczy",
|
|
||||||
"desc.leave.group.confirm": "Czy na pewno chcesz opuścić tę grupę?"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -120,16 +120,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="generic-popup-container" class="profile-popup-container" style="display: none; z-index: 9999;">
|
<div id="rotation-popup-container" class="profile-popup-container" style="display: none; z-index: 9999;">
|
||||||
<div class="profile-popup-bg" onclick="closeGenericPopup()"></div>
|
<div class="profile-popup-bg" onclick="closeRotationPopup()"></div>
|
||||||
<div class="profile-popup-content popup-auto-height">
|
<div class="profile-popup-content">
|
||||||
<button class="profile-popup-close-btn" onclick="closeGenericPopup()">
|
<button class="profile-popup-close-btn" onclick="closeRotationPopup()">
|
||||||
<script>
|
<script>
|
||||||
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
|
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
|
||||||
document.currentScript.remove();
|
document.currentScript.remove();
|
||||||
</script>
|
</script>
|
||||||
</button>
|
</button>
|
||||||
<div id="generic-popup-inner" style="padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem; width: 100%; box-sizing: border-box;">
|
<div id="profile-popup-inner" style="padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem;">
|
||||||
|
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>title.key.rotation</blah></div>
|
||||||
|
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 1rem; margin-bottom: 1rem;" id="rotation-popup-desc">
|
||||||
|
<!-- content injected dynamically -->
|
||||||
|
</div>
|
||||||
|
<button class="profile-action-btn" onclick="executeKeyRotation()"><blah>action.rotate.keys</blah></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -408,126 +408,18 @@ async function getGroupKey(groupId, keyIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pendingRotationMessagePayload = null;
|
function closeRotationPopup() {
|
||||||
|
let popupContainer = document.getElementById("rotation-popup-container");
|
||||||
let genericPopupConfirmCallback = null;
|
if(popupContainer) {
|
||||||
let genericPopupCancelCallback = null;
|
|
||||||
|
|
||||||
function closeGenericPopup() {
|
|
||||||
let popupContainer = document.getElementById("generic-popup-container");
|
|
||||||
if (popupContainer) {
|
|
||||||
popupContainer.classList.remove("show");
|
popupContainer.classList.remove("show");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
popupContainer.style.display = "none";
|
popupContainer.style.display = "none";
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
if (genericPopupCancelCallback) {
|
clearAction("key_rotation");
|
||||||
genericPopupCancelCallback();
|
|
||||||
genericPopupCancelCallback = null;
|
|
||||||
}
|
|
||||||
genericPopupConfirmCallback = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showConfirmPopup(titleKey, descHtml, confirmActionKey, cancelActionKey, onConfirm, onCancel = null, isDestructive = false) {
|
let pendingRotationMessagePayload = null;
|
||||||
let popupContainer = document.getElementById("generic-popup-container");
|
|
||||||
let popupInner = document.getElementById("generic-popup-inner");
|
|
||||||
|
|
||||||
let confirmClass = isDestructive ? "popup-btn-danger" : "popup-btn-confirm";
|
|
||||||
|
|
||||||
genericPopupCancelCallback = onCancel;
|
|
||||||
|
|
||||||
genericPopupConfirmCallback = () => {
|
|
||||||
let cb = onConfirm;
|
|
||||||
genericPopupCancelCallback = null; // Prevent cancel from firing on confirm
|
|
||||||
closeGenericPopup();
|
|
||||||
if (cb) cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
let html = `
|
|
||||||
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>${titleKey}</blah></div>
|
|
||||||
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 1rem; margin-bottom: 1rem;">
|
|
||||||
${descHtml}
|
|
||||||
</div>
|
|
||||||
<div style="display: flex; gap: 0.5rem; justify-content: center; width: 100%;">
|
|
||||||
<button class="profile-action-btn popup-btn-cancel" onclick="closeGenericPopup()">
|
|
||||||
<blah>${cancelActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
<button class="profile-action-btn ${confirmClass}" onclick="if(genericPopupConfirmCallback) genericPopupConfirmCallback()">
|
|
||||||
<blah>${confirmActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
popupInner.innerHTML = html;
|
|
||||||
|
|
||||||
let blahTags = popupInner.getElementsByTagName("blah");
|
|
||||||
for (let i = 0; i < blahTags.length; i++) {
|
|
||||||
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
|
||||||
}
|
|
||||||
|
|
||||||
popupContainer.style.display = "flex";
|
|
||||||
popupContainer.offsetHeight; // trigger reflow
|
|
||||||
popupContainer.classList.add("show");
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPromptPopup(titleKey, descHtml, placeholderKey, confirmActionKey, cancelActionKey, onConfirm, onCancel = null, isDestructive = false) {
|
|
||||||
let popupContainer = document.getElementById("generic-popup-container");
|
|
||||||
let popupInner = document.getElementById("generic-popup-inner");
|
|
||||||
|
|
||||||
let confirmClass = isDestructive ? "popup-btn-danger" : "popup-btn-confirm";
|
|
||||||
|
|
||||||
genericPopupCancelCallback = onCancel;
|
|
||||||
|
|
||||||
genericPopupConfirmCallback = () => {
|
|
||||||
let val = document.getElementById("generic-popup-input").value;
|
|
||||||
let cb = onConfirm;
|
|
||||||
genericPopupCancelCallback = null; // Prevent cancel from firing on confirm
|
|
||||||
closeGenericPopup();
|
|
||||||
if (cb) cb(val);
|
|
||||||
};
|
|
||||||
|
|
||||||
let html = `
|
|
||||||
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>${titleKey}</blah></div>
|
|
||||||
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 0.5rem; margin-bottom: 1rem;">
|
|
||||||
${descHtml}
|
|
||||||
</div>
|
|
||||||
<input type="text" id="generic-popup-input" class="forminput" placeholder="{blah(${placeholderKey})}" style="width: 100%; margin-bottom: 1rem; box-sizing: border-box;" onkeydown="if(arguments[0].key === 'Enter') { if(genericPopupConfirmCallback) genericPopupConfirmCallback(); }">
|
|
||||||
<div style="display: flex; gap: 0.5rem; justify-content: center; width: 100%;">
|
|
||||||
<button class="profile-action-btn popup-btn-cancel" onclick="closeGenericPopup()">
|
|
||||||
<blah>${cancelActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
<button class="profile-action-btn ${confirmClass}" onclick="if(genericPopupConfirmCallback) genericPopupConfirmCallback()">
|
|
||||||
<blah>${confirmActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
popupInner.innerHTML = html;
|
|
||||||
|
|
||||||
let input = document.getElementById("generic-popup-input");
|
|
||||||
if (input && input.placeholder.includes("{blah(")) {
|
|
||||||
let key = input.placeholder.replace("{blah(", "").replace(")}", "");
|
|
||||||
input.placeholder = processBlah(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
let blahTags = popupInner.getElementsByTagName("blah");
|
|
||||||
for (let i = 0; i < blahTags.length; i++) {
|
|
||||||
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
|
||||||
}
|
|
||||||
|
|
||||||
popupContainer.style.display = "flex";
|
|
||||||
popupContainer.offsetHeight; // trigger reflow
|
|
||||||
popupContainer.classList.add("show");
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
let el = document.getElementById("generic-popup-input");
|
|
||||||
if (el) el.focus();
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeRotationPopup() {
|
|
||||||
closeGenericPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showRotationPopup(groupId, originalMessagePayload) {
|
async function showRotationPopup(groupId, originalMessagePayload) {
|
||||||
pendingRotationMessagePayload = originalMessagePayload;
|
pendingRotationMessagePayload = originalMessagePayload;
|
||||||
|
|
@ -539,16 +431,17 @@ async function showRotationPopup(groupId, originalMessagePayload) {
|
||||||
|
|
||||||
let members = JSON.parse(membersRaw);
|
let members = JSON.parse(membersRaw);
|
||||||
|
|
||||||
let descHtml = `<blah>desc.key.rotation.info</blah><br><br><b>${members.length} <blah>label.members</blah></b>`;
|
let desc = document.getElementById("rotation-popup-desc");
|
||||||
|
desc.innerHTML = `<blah>desc.key.rotation.info</blah><br><br><b>${members.length} <blah>label.members</blah></b>`;
|
||||||
|
let blahTags = desc.getElementsByTagName("blah");
|
||||||
|
for (let i = 0; i < blahTags.length; i++) {
|
||||||
|
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
||||||
|
}
|
||||||
|
|
||||||
showConfirmPopup(
|
let popupContainer = document.getElementById("rotation-popup-container");
|
||||||
"title.key.rotation",
|
popupContainer.style.display = "flex";
|
||||||
descHtml,
|
popupContainer.offsetHeight; // trigger reflow
|
||||||
"action.rotate.keys",
|
popupContainer.classList.add("show");
|
||||||
"action.cancel",
|
|
||||||
() => executeKeyRotation(),
|
|
||||||
() => clearAction("key_rotation")
|
|
||||||
);
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
clearAction("key_rotation");
|
clearAction("key_rotation");
|
||||||
showBlahNotification("error:something.wrong");
|
showBlahNotification("error:something.wrong");
|
||||||
|
|
@ -1590,11 +1483,11 @@ async function switchRoomContent(title, content, showRoomBar, icon = "", skipMob
|
||||||
let pinCallBtns = showRoomBar ? `${pinBtnHtml}${callBtnHtml}` : '';
|
let pinCallBtns = showRoomBar ? `${pinBtnHtml}${callBtnHtml}` : '';
|
||||||
|
|
||||||
let clickableContent = showRoomBar ?
|
let clickableContent = showRoomBar ?
|
||||||
`<button id="room-topbar-clickable" class="inherit" onclick="mobileNavDetails();" style="cursor: pointer; display: flex; align-items: center; border-radius: 0.65rem; background: transparent; outline: none; height: 100%; text-align: left; min-width: 0; width: auto; max-width: 100%;">
|
`<button id="room-topbar-clickable" class="inherit" onclick="mobileNavDetails();" style="cursor: pointer; display: flex; align-items: center; border-radius: 0.65rem; background: transparent; outline: none; height: 100%; text-align: left;">
|
||||||
${icon ? icon + '<space></space>' : ''}<inherit style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; min-width: 0; width: auto;">${processBlah(title)}</inherit>
|
${icon ? icon + '<space></space>' : ''}<inherit>${processBlah(title)}</inherit>
|
||||||
</button>` :
|
</button>` :
|
||||||
`<inherit style="display: flex; align-items: center; height: 100%; min-width: 0; width: auto; max-width: 100%;">
|
`<inherit style="display: flex; align-items: center; height: 100%;">
|
||||||
${icon ? icon + '<space></space>' : ''}<inherit style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; min-width: 0; width: auto;">${processBlah(title)}</inherit>
|
${icon ? icon + '<space></space>' : ''}<inherit>${processBlah(title)}</inherit>
|
||||||
</inherit>`;
|
</inherit>`;
|
||||||
roomsTopBarTransition.innerHTML = `${backBtnHtml}${clickableContent}<div class="flex-spacer"></div>${pinCallBtns}`;
|
roomsTopBarTransition.innerHTML = `${backBtnHtml}${clickableContent}<div class="flex-spacer"></div>${pinCallBtns}`;
|
||||||
|
|
||||||
|
|
@ -1661,9 +1554,6 @@ async function switchDetailsContent(title, content, showBack = false, backAction
|
||||||
|
|
||||||
|
|
||||||
let pinCallBtns = showBack ? `${callBtnHtml}` : `${pinBtnHtml}${callBtnHtml}`;
|
let pinCallBtns = showBack ? `${callBtnHtml}` : `${pinBtnHtml}${callBtnHtml}`;
|
||||||
if (window.currentRoomType === 'groups' && !showBack) {
|
|
||||||
pinCallBtns = `${groupMenuBtnHtml}${pinCallBtns}`;
|
|
||||||
}
|
|
||||||
let backBtn = showBack ? `<button class="topbar-action-btn" onclick="${backAction}" style="margin-right: 0.5rem">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>` : "";
|
let backBtn = showBack ? `<button class="topbar-action-btn" onclick="${backAction}" style="margin-right: 0.5rem">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>` : "";
|
||||||
roomsTopBarTransition.innerHTML = `<inherit style="display: flex; align-items: center;">${backBtn}<inherit>${processBlah(title)}</inherit></inherit><div class="flex-spacer"></div>${pinCallBtns}`;
|
roomsTopBarTransition.innerHTML = `<inherit style="display: flex; align-items: center;">${backBtn}<inherit>${processBlah(title)}</inherit></inherit><div class="flex-spacer"></div>${pinCallBtns}`;
|
||||||
|
|
||||||
|
|
@ -2171,7 +2061,7 @@ async function renderInvites(res, type) {
|
||||||
|
|
||||||
html += entry;
|
html += entry;
|
||||||
} else if (invite.type === "group") {
|
} else if (invite.type === "group") {
|
||||||
let groupId = invite.groupId || invite.id;
|
let groupId = invite.id;
|
||||||
let targetId = (type === "received") ? invite.sender : invite.receiver;
|
let targetId = (type === "received") ? invite.sender : invite.receiver;
|
||||||
|
|
||||||
if (!targetId.includes(":")) {
|
if (!targetId.includes(":")) {
|
||||||
|
|
@ -2652,7 +2542,7 @@ async function renderGroups(res) {
|
||||||
let pfp = await getGroupAvatarUrl(groupId, groupName);
|
let pfp = await getGroupAvatarUrl(groupId, groupName);
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
<button class="room-entry" id="group-btn-${groupId}" onclick="openDm('${groupId}', decodeURIComponent('${safeGroupName}'), '${groupId}', 'groups')" oncontextmenu="handleGroupContextMenu(event, '${groupId}')">
|
<button class="room-entry" id="group-btn-${groupId}" onclick="openDm('${groupId}', decodeURIComponent('${safeGroupName}'), '${groupId}', 'groups')">
|
||||||
<img src="${pfp}" class="room-pfp">
|
<img src="${pfp}" class="room-pfp">
|
||||||
<div style="display: flex; flex-direction: column; text-align: left; overflow: hidden; width: 100%; margin-left: 0.37rem;">
|
<div style="display: flex; flex-direction: column; text-align: left; overflow: hidden; width: 100%; margin-left: 0.37rem;">
|
||||||
<span class="room-name" style="${nameStyle}">${groupName}</span>
|
<span class="room-name" style="${nameStyle}">${groupName}</span>
|
||||||
|
|
@ -2739,47 +2629,35 @@ async function generateDmMembersHtml(targetId, targetUsername) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function inviteToGroupPrompt(groupId) {
|
async function inviteToGroupPrompt(groupId) {
|
||||||
showPromptPopup(
|
let targetUsername = prompt(processBlah("prompt.invite.username"));
|
||||||
"action.invite",
|
if (!targetUsername) return;
|
||||||
"",
|
|
||||||
"prompt.invite.username",
|
if (!targetUsername.includes(":")) {
|
||||||
"action.invite",
|
targetUsername += `:${host}`;
|
||||||
"action.cancel",
|
}
|
||||||
async (targetUsername) => {
|
|
||||||
if (targetUsername) {
|
let idRes = await fetchAsync(`${url}/nametoid?u=${targetUsername}`);
|
||||||
targetUsername = targetUsername.trim();
|
if (idRes.startsWith("error") || idRes.trim() === "0" || idRes.trim() === "") {
|
||||||
if (targetUsername.length > 0) {
|
showBlahNotification("error:user.not.found");
|
||||||
if (!targetUsername.includes(":")) {
|
return;
|
||||||
targetUsername += `:${host}`;
|
}
|
||||||
}
|
let targetId = idRes.trim();
|
||||||
let idRes = await fetchAsync(`${url}/nametoid?u=${targetUsername}`);
|
|
||||||
if (idRes.startsWith("error") || idRes.trim() === "0" || idRes.trim() === "") {
|
|
||||||
showBlahNotification("error:user.not.found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let targetId = idRes.trim();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showAction("action.invite.sending", "invite.action");
|
showAction("action.invite.sending", "invite.action");
|
||||||
|
|
||||||
let payload = JSON.stringify({
|
let payload = JSON.stringify({
|
||||||
string1: groupId,
|
string1: groupId,
|
||||||
string2: targetId
|
string2: targetId
|
||||||
});
|
});
|
||||||
|
|
||||||
let res = await fetchEncrypted("group/invite", payload);
|
let res = await fetchEncrypted("group/invite", payload);
|
||||||
clearAction("invite.action");
|
clearAction("invite.action");
|
||||||
showBlahNotification(res || "success:invite.sent");
|
showBlahNotification(res || "success:invite.sent");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
clearAction("invite.action");
|
clearAction("invite.action");
|
||||||
showBlahNotification("error:something.wrong");
|
showBlahNotification("error:something.wrong");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateGroupMembersHtml(groupId, groupName) {
|
async function generateGroupMembersHtml(groupId, groupName) {
|
||||||
|
|
@ -4817,152 +4695,3 @@ function scrollToPinnedMessage(e, msgId) {
|
||||||
}
|
}
|
||||||
scrollToMessage(msgId);
|
scrollToMessage(msgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTopbarSpace() {
|
|
||||||
if (typeof roomTopBar === 'undefined' || !roomTopBar) return;
|
|
||||||
|
|
||||||
let transitionEl = roomTopBar.children.item(0);
|
|
||||||
if (!transitionEl) return;
|
|
||||||
|
|
||||||
let children = Array.from(transitionEl.children);
|
|
||||||
let usedWidth = 0;
|
|
||||||
|
|
||||||
let isPinHidden = document.body.classList.contains('hide-topbar-pin');
|
|
||||||
let isCallHidden = document.body.classList.contains('hide-topbar-call');
|
|
||||||
|
|
||||||
for (let child of children) {
|
|
||||||
if (child.classList.contains('flex-spacer')) continue;
|
|
||||||
|
|
||||||
if (child.classList.contains('room-action-pin') && isPinHidden) continue;
|
|
||||||
if (child.classList.contains('room-action-call') && isCallHidden) continue;
|
|
||||||
|
|
||||||
let style = window.getComputedStyle(child);
|
|
||||||
let margins = (parseFloat(style.marginLeft) || 0) + (parseFloat(style.marginRight) || 0);
|
|
||||||
|
|
||||||
if (child.id === 'room-topbar-clickable' || child.tagName.toLowerCase() === 'inherit') {
|
|
||||||
let titleEl = child.querySelector('inherit');
|
|
||||||
if (titleEl) {
|
|
||||||
usedWidth += (child.offsetWidth - titleEl.offsetWidth) + titleEl.scrollWidth + margins;
|
|
||||||
} else {
|
|
||||||
usedWidth += child.offsetWidth + margins;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
usedWidth += child.offsetWidth + margins;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safety buffer for padding/rendering quirks
|
|
||||||
let diff = transitionEl.clientWidth - usedWidth - 5;
|
|
||||||
let iconWidth = 50;
|
|
||||||
|
|
||||||
if (diff < 0) {
|
|
||||||
if (!isPinHidden) {
|
|
||||||
document.body.classList.add('hide-topbar-pin');
|
|
||||||
} else if (!isCallHidden) {
|
|
||||||
document.body.classList.add('hide-topbar-call');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isCallHidden && diff > iconWidth) {
|
|
||||||
document.body.classList.remove('hide-topbar-call');
|
|
||||||
} else if (isPinHidden && !isCallHidden && diff > iconWidth) {
|
|
||||||
document.body.classList.remove('hide-topbar-pin');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof roomTopBar !== 'undefined' && roomTopBar) {
|
|
||||||
let topbarResizeObserver = new ResizeObserver(() => {
|
|
||||||
checkTopbarSpace();
|
|
||||||
});
|
|
||||||
topbarResizeObserver.observe(roomTopBar);
|
|
||||||
|
|
||||||
if (roomTopBar.children.length > 0) {
|
|
||||||
let topbarMutationObserver = new MutationObserver(() => {
|
|
||||||
setTimeout(checkTopbarSpace, 10);
|
|
||||||
});
|
|
||||||
topbarMutationObserver.observe(roomTopBar.children.item(0), { childList: true, subtree: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentContextMenuGroupId = null;
|
|
||||||
|
|
||||||
function handleGroupContextMenu(e, groupId) {
|
|
||||||
if (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
if (typeof clearContextMenuStyles === "function") clearContextMenuStyles();
|
|
||||||
currentContextMenuGroupId = groupId;
|
|
||||||
|
|
||||||
let btn = e ? (e.currentTarget || e.target) : null;
|
|
||||||
let rect;
|
|
||||||
if (e && e.type === "click") {
|
|
||||||
rect = btn.getBoundingClientRect();
|
|
||||||
showFixedContextMenu({top: rect.top, right: rect.left, bottom: rect.bottom, left: rect.left}, groupContextMenu);
|
|
||||||
} else if (e) {
|
|
||||||
let clientX = e.clientX !== undefined ? e.clientX : (e.touches && e.touches.length > 0 ? e.touches[0].clientX : 0);
|
|
||||||
let clientY = e.clientY !== undefined ? e.clientY : (e.touches && e.touches.length > 0 ? e.touches[0].clientY : 0);
|
|
||||||
showFixedContextMenu({top: clientY, right: clientX, bottom: clientY, left: clientX}, groupContextMenu);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let menuRect = fixedContextMenu.getBoundingClientRect();
|
|
||||||
let newLeft = e ? (e.clientX !== undefined ? e.clientX : (e.touches && e.touches.length > 0 ? e.touches[0].clientX : 0)) + 10 : 0;
|
|
||||||
let newTop = e ? (e.clientY !== undefined ? e.clientY : (e.touches && e.touches.length > 0 ? e.touches[0].clientY : 0)) : 0;
|
|
||||||
|
|
||||||
if (e && e.type === "click") {
|
|
||||||
newLeft = rect.left + 10;
|
|
||||||
newTop = rect.bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newLeft + menuRect.width > window.innerWidth) {
|
|
||||||
newLeft = window.innerWidth - menuRect.width - 10;
|
|
||||||
}
|
|
||||||
if (newTop + menuRect.height > window.innerHeight) {
|
|
||||||
newTop = window.innerHeight - menuRect.height - 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixedContextMenu.style.left = `${newLeft}px`;
|
|
||||||
fixedContextMenu.style.top = `${newTop}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gotoGroupSettings(groupId) {
|
|
||||||
if (fixedContextMenu) fixedContextMenu.classList.remove("show");
|
|
||||||
// Not implemented yet
|
|
||||||
}
|
|
||||||
|
|
||||||
function leaveGroupPrompt(groupId) {
|
|
||||||
if (fixedContextMenu) fixedContextMenu.classList.remove("show");
|
|
||||||
|
|
||||||
showConfirmPopup(
|
|
||||||
"title.leave.group",
|
|
||||||
`<blah>desc.leave.group.confirm</blah>`,
|
|
||||||
"title.leave.group",
|
|
||||||
"action.cancel",
|
|
||||||
() => confirmLeaveGroup(groupId),
|
|
||||||
null,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function confirmLeaveGroup(groupId) {
|
|
||||||
closeProfile();
|
|
||||||
showAction("action.leaving.group", "leavegroup");
|
|
||||||
try {
|
|
||||||
let payload = JSON.stringify({ string1: groupId });
|
|
||||||
let res = await fetchEncrypted("group/leave", payload);
|
|
||||||
if (res === "success") {
|
|
||||||
if (currentDmId === groupId) {
|
|
||||||
gotoHome();
|
|
||||||
}
|
|
||||||
refreshGroups(0, false);
|
|
||||||
} else if (res.startsWith("error:")) {
|
|
||||||
showBlahNotification(res);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
showBlahNotification("error:something.wrong");
|
|
||||||
}
|
|
||||||
clearAction("leavegroup");
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -250,16 +250,6 @@ var addSpaceMenu = `
|
||||||
${ICONS.createSpace()}
|
${ICONS.createSpace()}
|
||||||
<span class="blah">title.create.space</span>
|
<span class="blah">title.create.space</span>
|
||||||
</button>`
|
</button>`
|
||||||
var groupContextMenu = `
|
|
||||||
<button onclick="gotoGroupSettings(currentContextMenuGroupId)">
|
|
||||||
${ICONS.settings()}
|
|
||||||
<span class="blah">title.group.settings</span>
|
|
||||||
</button>
|
|
||||||
<button onclick="leaveGroupPrompt(currentContextMenuGroupId)">
|
|
||||||
${ICONS.delete({ fill: "var(--big-red)" })}
|
|
||||||
<span class="blah" style="color: var(--big-red)">title.leave.group</span>
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
var messageContextMenu = `
|
var messageContextMenu = `
|
||||||
<button onclick="replyMessage(currentContextMenuMsgId)">
|
<button onclick="replyMessage(currentContextMenuMsgId)">
|
||||||
${ICONS.replyAction()}
|
${ICONS.replyAction()}
|
||||||
|
|
@ -280,7 +270,6 @@ var messageContextMenu = `
|
||||||
var backBtnHtml = `<button class="mobile-nav-btn" onclick="mobileNavBack()">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
var backBtnHtml = `<button class="mobile-nav-btn" onclick="mobileNavBack()">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
||||||
var pinBtnHtml = `<button class="topbar-action-btn room-action-pin right" onclick="showPinnedMessages()">${ICONS.pin({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
var pinBtnHtml = `<button class="topbar-action-btn room-action-pin right" onclick="showPinnedMessages()">${ICONS.pin({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
||||||
var callBtnHtml = `<button class="topbar-action-btn room-action-call right">${ICONS.call({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
var callBtnHtml = `<button class="topbar-action-btn room-action-call right">${ICONS.call({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
||||||
var groupMenuBtnHtml = `<button class="topbar-action-btn right" onclick="handleGroupContextMenu(arguments[0], currentDmId)">${ICONS.menu({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
|
||||||
|
|
||||||
var settingsBar = `
|
var settingsBar = `
|
||||||
<div class="sidebar-section-header">
|
<div class="sidebar-section-header">
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,11 @@ sidebar {
|
||||||
border-right: var(--border-width) solid var(--light-border-color);
|
border-right: var(--border-width) solid var(--light-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sidebar:not(.second) {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
sidebar:not(.second)::-webkit-scrollbar {
|
sidebar:not(.second)::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -874,40 +879,6 @@ sidebarelement:has(.icon-button:active) indicator:not(.active) {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.popup-auto-height {
|
|
||||||
height: auto;
|
|
||||||
max-height: 85vh;
|
|
||||||
}
|
|
||||||
.popup-btn-cancel {
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
color: var(--text-color);
|
|
||||||
border: var(--border-width) solid var(--light-border-color);
|
|
||||||
flex: 1;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.popup-btn-cancel:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
.popup-btn-confirm {
|
|
||||||
background: var(--text-color);
|
|
||||||
color: var(--main-bg-color);
|
|
||||||
border: none;
|
|
||||||
flex: 1;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.popup-btn-confirm:hover {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
.popup-btn-danger {
|
|
||||||
background: var(--big-red);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
flex: 1;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.popup-btn-danger:hover {
|
|
||||||
background: #ff5252;
|
|
||||||
}
|
|
||||||
.profile-popup-container.show .profile-popup-content {
|
.profile-popup-container.show .profile-popup-content {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
@ -1067,8 +1038,12 @@ roomcontent roomtopbar .room-action-call {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.hide-topbar-pin roomcontent roomtopbar .room-action-pin { display: none !important; }
|
@media (max-width: 65rem) and (min-width: 55.001rem) {
|
||||||
body.hide-topbar-pin #roomdetailsbar roomtopbar .room-action-pin { display: flex !important; }
|
roomcontent roomtopbar .room-action-pin { display: none !important; }
|
||||||
|
#roomdetailsbar roomtopbar .room-action-pin { display: flex !important; }
|
||||||
|
}
|
||||||
|
|
||||||
body.hide-topbar-call roomcontent roomtopbar .room-action-call { display: none !important; }
|
@media (max-width: 58rem) and (min-width: 55.001rem) {
|
||||||
body.hide-topbar-call #roomdetailsbar roomtopbar .room-action-call { display: flex !important; }
|
roomcontent roomtopbar .room-action-call { display: none !important; }
|
||||||
|
#roomdetailsbar roomtopbar .room-action-call { display: flex !important; }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -257,10 +257,5 @@
|
||||||
"en-cat": "Meowlish",
|
"en-cat": "Meowlish",
|
||||||
"avatar.updated": "Avatar updated successfully",
|
"avatar.updated": "Avatar updated successfully",
|
||||||
"profile.updated": "Profile updated successfully",
|
"profile.updated": "Profile updated successfully",
|
||||||
"banner.updated": "Banner updated successfully",
|
"banner.updated": "Banner updated successfully"
|
||||||
"action.invite": "Invite, meow",
|
}
|
||||||
"action.leaving.group": "Leaving group, meow...",
|
|
||||||
"action.key.rotating": "Rotating keys, meow...",
|
|
||||||
"action.key.rotation": "Key rotation, meow",
|
|
||||||
"desc.leave.group.confirm": "Are you sure you want to leave this group, meow?"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -257,10 +257,5 @@
|
||||||
"success:avatar.updated": "Avatar updated successfully",
|
"success:avatar.updated": "Avatar updated successfully",
|
||||||
"en-us": "English",
|
"en-us": "English",
|
||||||
"pl-pl": "Polish",
|
"pl-pl": "Polish",
|
||||||
"en-cat": "Meowlish",
|
"en-cat": "Meowlish"
|
||||||
"action.invite": "Invite",
|
}
|
||||||
"action.leaving.group": "Leaving group...",
|
|
||||||
"action.key.rotating": "Rotating keys...",
|
|
||||||
"action.key.rotation": "Key rotation",
|
|
||||||
"desc.leave.group.confirm": "Are you sure you want to leave this group?"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -257,10 +257,5 @@
|
||||||
"success:avatar.updated": "Awatar został pomyślnie zaktualizowany",
|
"success:avatar.updated": "Awatar został pomyślnie zaktualizowany",
|
||||||
"en-us": "Angielski",
|
"en-us": "Angielski",
|
||||||
"pl-pl": "Polski",
|
"pl-pl": "Polski",
|
||||||
"en-cat": "Koci (Meowlish)",
|
"en-cat": "Koci (Meowlish)"
|
||||||
"action.invite": "Zaproś",
|
}
|
||||||
"action.leaving.group": "Opuszczanie grupy...",
|
|
||||||
"action.key.rotating": "Obracanie kluczy...",
|
|
||||||
"action.key.rotation": "Rotacja kluczy",
|
|
||||||
"desc.leave.group.confirm": "Czy na pewno chcesz opuścić tę grupę?"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -120,16 +120,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="generic-popup-container" class="profile-popup-container" style="display: none; z-index: 9999;">
|
<div id="rotation-popup-container" class="profile-popup-container" style="display: none; z-index: 9999;">
|
||||||
<div class="profile-popup-bg" onclick="closeGenericPopup()"></div>
|
<div class="profile-popup-bg" onclick="closeRotationPopup()"></div>
|
||||||
<div class="profile-popup-content popup-auto-height">
|
<div class="profile-popup-content">
|
||||||
<button class="profile-popup-close-btn" onclick="closeGenericPopup()">
|
<button class="profile-popup-close-btn" onclick="closeRotationPopup()">
|
||||||
<script>
|
<script>
|
||||||
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
|
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
|
||||||
document.currentScript.remove();
|
document.currentScript.remove();
|
||||||
</script>
|
</script>
|
||||||
</button>
|
</button>
|
||||||
<div id="generic-popup-inner" style="padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem; width: 100%; box-sizing: border-box;">
|
<div id="profile-popup-inner" style="padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem;">
|
||||||
|
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>title.key.rotation</blah></div>
|
||||||
|
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 1rem; margin-bottom: 1rem;" id="rotation-popup-desc">
|
||||||
|
<!-- content injected dynamically -->
|
||||||
|
</div>
|
||||||
|
<button class="profile-action-btn" onclick="executeKeyRotation()"><blah>action.rotate.keys</blah></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
369
webroot/main.js
369
webroot/main.js
|
|
@ -408,126 +408,18 @@ async function getGroupKey(groupId, keyIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pendingRotationMessagePayload = null;
|
function closeRotationPopup() {
|
||||||
|
let popupContainer = document.getElementById("rotation-popup-container");
|
||||||
let genericPopupConfirmCallback = null;
|
if(popupContainer) {
|
||||||
let genericPopupCancelCallback = null;
|
|
||||||
|
|
||||||
function closeGenericPopup() {
|
|
||||||
let popupContainer = document.getElementById("generic-popup-container");
|
|
||||||
if (popupContainer) {
|
|
||||||
popupContainer.classList.remove("show");
|
popupContainer.classList.remove("show");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
popupContainer.style.display = "none";
|
popupContainer.style.display = "none";
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
if (genericPopupCancelCallback) {
|
clearAction("key_rotation");
|
||||||
genericPopupCancelCallback();
|
|
||||||
genericPopupCancelCallback = null;
|
|
||||||
}
|
|
||||||
genericPopupConfirmCallback = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showConfirmPopup(titleKey, descHtml, confirmActionKey, cancelActionKey, onConfirm, onCancel = null, isDestructive = false) {
|
let pendingRotationMessagePayload = null;
|
||||||
let popupContainer = document.getElementById("generic-popup-container");
|
|
||||||
let popupInner = document.getElementById("generic-popup-inner");
|
|
||||||
|
|
||||||
let confirmClass = isDestructive ? "popup-btn-danger" : "popup-btn-confirm";
|
|
||||||
|
|
||||||
genericPopupCancelCallback = onCancel;
|
|
||||||
|
|
||||||
genericPopupConfirmCallback = () => {
|
|
||||||
let cb = onConfirm;
|
|
||||||
genericPopupCancelCallback = null; // Prevent cancel from firing on confirm
|
|
||||||
closeGenericPopup();
|
|
||||||
if (cb) cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
let html = `
|
|
||||||
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>${titleKey}</blah></div>
|
|
||||||
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 1rem; margin-bottom: 1rem;">
|
|
||||||
${descHtml}
|
|
||||||
</div>
|
|
||||||
<div style="display: flex; gap: 0.5rem; justify-content: center; width: 100%;">
|
|
||||||
<button class="profile-action-btn popup-btn-cancel" onclick="closeGenericPopup()">
|
|
||||||
<blah>${cancelActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
<button class="profile-action-btn ${confirmClass}" onclick="if(genericPopupConfirmCallback) genericPopupConfirmCallback()">
|
|
||||||
<blah>${confirmActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
popupInner.innerHTML = html;
|
|
||||||
|
|
||||||
let blahTags = popupInner.getElementsByTagName("blah");
|
|
||||||
for (let i = 0; i < blahTags.length; i++) {
|
|
||||||
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
|
||||||
}
|
|
||||||
|
|
||||||
popupContainer.style.display = "flex";
|
|
||||||
popupContainer.offsetHeight; // trigger reflow
|
|
||||||
popupContainer.classList.add("show");
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPromptPopup(titleKey, descHtml, placeholderKey, confirmActionKey, cancelActionKey, onConfirm, onCancel = null, isDestructive = false) {
|
|
||||||
let popupContainer = document.getElementById("generic-popup-container");
|
|
||||||
let popupInner = document.getElementById("generic-popup-inner");
|
|
||||||
|
|
||||||
let confirmClass = isDestructive ? "popup-btn-danger" : "popup-btn-confirm";
|
|
||||||
|
|
||||||
genericPopupCancelCallback = onCancel;
|
|
||||||
|
|
||||||
genericPopupConfirmCallback = () => {
|
|
||||||
let val = document.getElementById("generic-popup-input").value;
|
|
||||||
let cb = onConfirm;
|
|
||||||
genericPopupCancelCallback = null; // Prevent cancel from firing on confirm
|
|
||||||
closeGenericPopup();
|
|
||||||
if (cb) cb(val);
|
|
||||||
};
|
|
||||||
|
|
||||||
let html = `
|
|
||||||
<div style="font-size: 1.2rem; font-weight: 500; text-align: center;"><blah>${titleKey}</blah></div>
|
|
||||||
<div style="width: 100%; text-align: center; color: var(--text-color); opacity: 0.8; margin-top: 0.5rem; margin-bottom: 1rem;">
|
|
||||||
${descHtml}
|
|
||||||
</div>
|
|
||||||
<input type="text" id="generic-popup-input" class="forminput" placeholder="{blah(${placeholderKey})}" style="width: 100%; margin-bottom: 1rem; box-sizing: border-box;" onkeydown="if(arguments[0].key === 'Enter') { if(genericPopupConfirmCallback) genericPopupConfirmCallback(); }">
|
|
||||||
<div style="display: flex; gap: 0.5rem; justify-content: center; width: 100%;">
|
|
||||||
<button class="profile-action-btn popup-btn-cancel" onclick="closeGenericPopup()">
|
|
||||||
<blah>${cancelActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
<button class="profile-action-btn ${confirmClass}" onclick="if(genericPopupConfirmCallback) genericPopupConfirmCallback()">
|
|
||||||
<blah>${confirmActionKey}</blah>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
popupInner.innerHTML = html;
|
|
||||||
|
|
||||||
let input = document.getElementById("generic-popup-input");
|
|
||||||
if (input && input.placeholder.includes("{blah(")) {
|
|
||||||
let key = input.placeholder.replace("{blah(", "").replace(")}", "");
|
|
||||||
input.placeholder = processBlah(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
let blahTags = popupInner.getElementsByTagName("blah");
|
|
||||||
for (let i = 0; i < blahTags.length; i++) {
|
|
||||||
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
|
||||||
}
|
|
||||||
|
|
||||||
popupContainer.style.display = "flex";
|
|
||||||
popupContainer.offsetHeight; // trigger reflow
|
|
||||||
popupContainer.classList.add("show");
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
let el = document.getElementById("generic-popup-input");
|
|
||||||
if (el) el.focus();
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeRotationPopup() {
|
|
||||||
closeGenericPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function showRotationPopup(groupId, originalMessagePayload) {
|
async function showRotationPopup(groupId, originalMessagePayload) {
|
||||||
pendingRotationMessagePayload = originalMessagePayload;
|
pendingRotationMessagePayload = originalMessagePayload;
|
||||||
|
|
@ -539,16 +431,17 @@ async function showRotationPopup(groupId, originalMessagePayload) {
|
||||||
|
|
||||||
let members = JSON.parse(membersRaw);
|
let members = JSON.parse(membersRaw);
|
||||||
|
|
||||||
let descHtml = `<blah>desc.key.rotation.info</blah><br><br><b>${members.length} <blah>label.members</blah></b>`;
|
let desc = document.getElementById("rotation-popup-desc");
|
||||||
|
desc.innerHTML = `<blah>desc.key.rotation.info</blah><br><br><b>${members.length} <blah>label.members</blah></b>`;
|
||||||
|
let blahTags = desc.getElementsByTagName("blah");
|
||||||
|
for (let i = 0; i < blahTags.length; i++) {
|
||||||
|
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
||||||
|
}
|
||||||
|
|
||||||
showConfirmPopup(
|
let popupContainer = document.getElementById("rotation-popup-container");
|
||||||
"title.key.rotation",
|
popupContainer.style.display = "flex";
|
||||||
descHtml,
|
popupContainer.offsetHeight; // trigger reflow
|
||||||
"action.rotate.keys",
|
popupContainer.classList.add("show");
|
||||||
"action.cancel",
|
|
||||||
() => executeKeyRotation(),
|
|
||||||
() => clearAction("key_rotation")
|
|
||||||
);
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
clearAction("key_rotation");
|
clearAction("key_rotation");
|
||||||
showBlahNotification("error:something.wrong");
|
showBlahNotification("error:something.wrong");
|
||||||
|
|
@ -1590,11 +1483,11 @@ async function switchRoomContent(title, content, showRoomBar, icon = "", skipMob
|
||||||
let pinCallBtns = showRoomBar ? `${pinBtnHtml}${callBtnHtml}` : '';
|
let pinCallBtns = showRoomBar ? `${pinBtnHtml}${callBtnHtml}` : '';
|
||||||
|
|
||||||
let clickableContent = showRoomBar ?
|
let clickableContent = showRoomBar ?
|
||||||
`<button id="room-topbar-clickable" class="inherit" onclick="mobileNavDetails();" style="cursor: pointer; display: flex; align-items: center; border-radius: 0.65rem; background: transparent; outline: none; height: 100%; text-align: left; min-width: 0; width: auto; max-width: 100%;">
|
`<button id="room-topbar-clickable" class="inherit" onclick="mobileNavDetails();" style="cursor: pointer; display: flex; align-items: center; border-radius: 0.65rem; background: transparent; outline: none; height: 100%; text-align: left;">
|
||||||
${icon ? icon + '<space></space>' : ''}<inherit style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; min-width: 0; width: auto;">${processBlah(title)}</inherit>
|
${icon ? icon + '<space></space>' : ''}<inherit>${processBlah(title)}</inherit>
|
||||||
</button>` :
|
</button>` :
|
||||||
`<inherit style="display: flex; align-items: center; height: 100%; min-width: 0; width: auto; max-width: 100%;">
|
`<inherit style="display: flex; align-items: center; height: 100%;">
|
||||||
${icon ? icon + '<space></space>' : ''}<inherit style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; min-width: 0; width: auto;">${processBlah(title)}</inherit>
|
${icon ? icon + '<space></space>' : ''}<inherit>${processBlah(title)}</inherit>
|
||||||
</inherit>`;
|
</inherit>`;
|
||||||
roomsTopBarTransition.innerHTML = `${backBtnHtml}${clickableContent}<div class="flex-spacer"></div>${pinCallBtns}`;
|
roomsTopBarTransition.innerHTML = `${backBtnHtml}${clickableContent}<div class="flex-spacer"></div>${pinCallBtns}`;
|
||||||
|
|
||||||
|
|
@ -1661,9 +1554,6 @@ async function switchDetailsContent(title, content, showBack = false, backAction
|
||||||
|
|
||||||
|
|
||||||
let pinCallBtns = showBack ? `${callBtnHtml}` : `${pinBtnHtml}${callBtnHtml}`;
|
let pinCallBtns = showBack ? `${callBtnHtml}` : `${pinBtnHtml}${callBtnHtml}`;
|
||||||
if (window.currentRoomType === 'groups' && !showBack) {
|
|
||||||
pinCallBtns = `${groupMenuBtnHtml}${pinCallBtns}`;
|
|
||||||
}
|
|
||||||
let backBtn = showBack ? `<button class="topbar-action-btn" onclick="${backAction}" style="margin-right: 0.5rem">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>` : "";
|
let backBtn = showBack ? `<button class="topbar-action-btn" onclick="${backAction}" style="margin-right: 0.5rem">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>` : "";
|
||||||
roomsTopBarTransition.innerHTML = `<inherit style="display: flex; align-items: center;">${backBtn}<inherit>${processBlah(title)}</inherit></inherit><div class="flex-spacer"></div>${pinCallBtns}`;
|
roomsTopBarTransition.innerHTML = `<inherit style="display: flex; align-items: center;">${backBtn}<inherit>${processBlah(title)}</inherit></inherit><div class="flex-spacer"></div>${pinCallBtns}`;
|
||||||
|
|
||||||
|
|
@ -2171,7 +2061,7 @@ async function renderInvites(res, type) {
|
||||||
|
|
||||||
html += entry;
|
html += entry;
|
||||||
} else if (invite.type === "group") {
|
} else if (invite.type === "group") {
|
||||||
let groupId = invite.groupId || invite.id;
|
let groupId = invite.id;
|
||||||
let targetId = (type === "received") ? invite.sender : invite.receiver;
|
let targetId = (type === "received") ? invite.sender : invite.receiver;
|
||||||
|
|
||||||
if (!targetId.includes(":")) {
|
if (!targetId.includes(":")) {
|
||||||
|
|
@ -2652,7 +2542,7 @@ async function renderGroups(res) {
|
||||||
let pfp = await getGroupAvatarUrl(groupId, groupName);
|
let pfp = await getGroupAvatarUrl(groupId, groupName);
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
<button class="room-entry" id="group-btn-${groupId}" onclick="openDm('${groupId}', decodeURIComponent('${safeGroupName}'), '${groupId}', 'groups')" oncontextmenu="handleGroupContextMenu(event, '${groupId}')">
|
<button class="room-entry" id="group-btn-${groupId}" onclick="openDm('${groupId}', decodeURIComponent('${safeGroupName}'), '${groupId}', 'groups')">
|
||||||
<img src="${pfp}" class="room-pfp">
|
<img src="${pfp}" class="room-pfp">
|
||||||
<div style="display: flex; flex-direction: column; text-align: left; overflow: hidden; width: 100%; margin-left: 0.37rem;">
|
<div style="display: flex; flex-direction: column; text-align: left; overflow: hidden; width: 100%; margin-left: 0.37rem;">
|
||||||
<span class="room-name" style="${nameStyle}">${groupName}</span>
|
<span class="room-name" style="${nameStyle}">${groupName}</span>
|
||||||
|
|
@ -2739,47 +2629,35 @@ async function generateDmMembersHtml(targetId, targetUsername) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function inviteToGroupPrompt(groupId) {
|
async function inviteToGroupPrompt(groupId) {
|
||||||
showPromptPopup(
|
let targetUsername = prompt(processBlah("prompt.invite.username"));
|
||||||
"action.invite",
|
if (!targetUsername) return;
|
||||||
"",
|
|
||||||
"prompt.invite.username",
|
if (!targetUsername.includes(":")) {
|
||||||
"action.invite",
|
targetUsername += `:${host}`;
|
||||||
"action.cancel",
|
}
|
||||||
async (targetUsername) => {
|
|
||||||
if (targetUsername) {
|
let idRes = await fetchAsync(`${url}/nametoid?u=${targetUsername}`);
|
||||||
targetUsername = targetUsername.trim();
|
if (idRes.startsWith("error") || idRes.trim() === "0" || idRes.trim() === "") {
|
||||||
if (targetUsername.length > 0) {
|
showBlahNotification("error:user.not.found");
|
||||||
if (!targetUsername.includes(":")) {
|
return;
|
||||||
targetUsername += `:${host}`;
|
}
|
||||||
}
|
let targetId = idRes.trim();
|
||||||
let idRes = await fetchAsync(`${url}/nametoid?u=${targetUsername}`);
|
|
||||||
if (idRes.startsWith("error") || idRes.trim() === "0" || idRes.trim() === "") {
|
|
||||||
showBlahNotification("error:user.not.found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let targetId = idRes.trim();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showAction("action.invite.sending", "invite.action");
|
showAction("action.invite.sending", "invite.action");
|
||||||
|
|
||||||
let payload = JSON.stringify({
|
let payload = JSON.stringify({
|
||||||
string1: groupId,
|
string1: groupId,
|
||||||
string2: targetId
|
string2: targetId
|
||||||
});
|
});
|
||||||
|
|
||||||
let res = await fetchEncrypted("group/invite", payload);
|
let res = await fetchEncrypted("group/invite", payload);
|
||||||
clearAction("invite.action");
|
clearAction("invite.action");
|
||||||
showBlahNotification(res || "success:invite.sent");
|
showBlahNotification(res || "success:invite.sent");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
clearAction("invite.action");
|
clearAction("invite.action");
|
||||||
showBlahNotification("error:something.wrong");
|
showBlahNotification("error:something.wrong");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateGroupMembersHtml(groupId, groupName) {
|
async function generateGroupMembersHtml(groupId, groupName) {
|
||||||
|
|
@ -4817,152 +4695,3 @@ function scrollToPinnedMessage(e, msgId) {
|
||||||
}
|
}
|
||||||
scrollToMessage(msgId);
|
scrollToMessage(msgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTopbarSpace() {
|
|
||||||
if (typeof roomTopBar === 'undefined' || !roomTopBar) return;
|
|
||||||
|
|
||||||
let transitionEl = roomTopBar.children.item(0);
|
|
||||||
if (!transitionEl) return;
|
|
||||||
|
|
||||||
let children = Array.from(transitionEl.children);
|
|
||||||
let usedWidth = 0;
|
|
||||||
|
|
||||||
let isPinHidden = document.body.classList.contains('hide-topbar-pin');
|
|
||||||
let isCallHidden = document.body.classList.contains('hide-topbar-call');
|
|
||||||
|
|
||||||
for (let child of children) {
|
|
||||||
if (child.classList.contains('flex-spacer')) continue;
|
|
||||||
|
|
||||||
if (child.classList.contains('room-action-pin') && isPinHidden) continue;
|
|
||||||
if (child.classList.contains('room-action-call') && isCallHidden) continue;
|
|
||||||
|
|
||||||
let style = window.getComputedStyle(child);
|
|
||||||
let margins = (parseFloat(style.marginLeft) || 0) + (parseFloat(style.marginRight) || 0);
|
|
||||||
|
|
||||||
if (child.id === 'room-topbar-clickable' || child.tagName.toLowerCase() === 'inherit') {
|
|
||||||
let titleEl = child.querySelector('inherit');
|
|
||||||
if (titleEl) {
|
|
||||||
usedWidth += (child.offsetWidth - titleEl.offsetWidth) + titleEl.scrollWidth + margins;
|
|
||||||
} else {
|
|
||||||
usedWidth += child.offsetWidth + margins;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
usedWidth += child.offsetWidth + margins;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safety buffer for padding/rendering quirks
|
|
||||||
let diff = transitionEl.clientWidth - usedWidth - 5;
|
|
||||||
let iconWidth = 50;
|
|
||||||
|
|
||||||
if (diff < 0) {
|
|
||||||
if (!isPinHidden) {
|
|
||||||
document.body.classList.add('hide-topbar-pin');
|
|
||||||
} else if (!isCallHidden) {
|
|
||||||
document.body.classList.add('hide-topbar-call');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isCallHidden && diff > iconWidth) {
|
|
||||||
document.body.classList.remove('hide-topbar-call');
|
|
||||||
} else if (isPinHidden && !isCallHidden && diff > iconWidth) {
|
|
||||||
document.body.classList.remove('hide-topbar-pin');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof roomTopBar !== 'undefined' && roomTopBar) {
|
|
||||||
let topbarResizeObserver = new ResizeObserver(() => {
|
|
||||||
checkTopbarSpace();
|
|
||||||
});
|
|
||||||
topbarResizeObserver.observe(roomTopBar);
|
|
||||||
|
|
||||||
if (roomTopBar.children.length > 0) {
|
|
||||||
let topbarMutationObserver = new MutationObserver(() => {
|
|
||||||
setTimeout(checkTopbarSpace, 10);
|
|
||||||
});
|
|
||||||
topbarMutationObserver.observe(roomTopBar.children.item(0), { childList: true, subtree: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentContextMenuGroupId = null;
|
|
||||||
|
|
||||||
function handleGroupContextMenu(e, groupId) {
|
|
||||||
if (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
if (typeof clearContextMenuStyles === "function") clearContextMenuStyles();
|
|
||||||
currentContextMenuGroupId = groupId;
|
|
||||||
|
|
||||||
let btn = e ? (e.currentTarget || e.target) : null;
|
|
||||||
let rect;
|
|
||||||
if (e && e.type === "click") {
|
|
||||||
rect = btn.getBoundingClientRect();
|
|
||||||
showFixedContextMenu({top: rect.top, right: rect.left, bottom: rect.bottom, left: rect.left}, groupContextMenu);
|
|
||||||
} else if (e) {
|
|
||||||
let clientX = e.clientX !== undefined ? e.clientX : (e.touches && e.touches.length > 0 ? e.touches[0].clientX : 0);
|
|
||||||
let clientY = e.clientY !== undefined ? e.clientY : (e.touches && e.touches.length > 0 ? e.touches[0].clientY : 0);
|
|
||||||
showFixedContextMenu({top: clientY, right: clientX, bottom: clientY, left: clientX}, groupContextMenu);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let menuRect = fixedContextMenu.getBoundingClientRect();
|
|
||||||
let newLeft = e ? (e.clientX !== undefined ? e.clientX : (e.touches && e.touches.length > 0 ? e.touches[0].clientX : 0)) + 10 : 0;
|
|
||||||
let newTop = e ? (e.clientY !== undefined ? e.clientY : (e.touches && e.touches.length > 0 ? e.touches[0].clientY : 0)) : 0;
|
|
||||||
|
|
||||||
if (e && e.type === "click") {
|
|
||||||
newLeft = rect.left + 10;
|
|
||||||
newTop = rect.bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newLeft + menuRect.width > window.innerWidth) {
|
|
||||||
newLeft = window.innerWidth - menuRect.width - 10;
|
|
||||||
}
|
|
||||||
if (newTop + menuRect.height > window.innerHeight) {
|
|
||||||
newTop = window.innerHeight - menuRect.height - 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixedContextMenu.style.left = `${newLeft}px`;
|
|
||||||
fixedContextMenu.style.top = `${newTop}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gotoGroupSettings(groupId) {
|
|
||||||
if (fixedContextMenu) fixedContextMenu.classList.remove("show");
|
|
||||||
// Not implemented yet
|
|
||||||
}
|
|
||||||
|
|
||||||
function leaveGroupPrompt(groupId) {
|
|
||||||
if (fixedContextMenu) fixedContextMenu.classList.remove("show");
|
|
||||||
|
|
||||||
showConfirmPopup(
|
|
||||||
"title.leave.group",
|
|
||||||
`<blah>desc.leave.group.confirm</blah>`,
|
|
||||||
"title.leave.group",
|
|
||||||
"action.cancel",
|
|
||||||
() => confirmLeaveGroup(groupId),
|
|
||||||
null,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function confirmLeaveGroup(groupId) {
|
|
||||||
closeProfile();
|
|
||||||
showAction("action.leaving.group", "leavegroup");
|
|
||||||
try {
|
|
||||||
let payload = JSON.stringify({ string1: groupId });
|
|
||||||
let res = await fetchEncrypted("group/leave", payload);
|
|
||||||
if (res === "success") {
|
|
||||||
if (currentDmId === groupId) {
|
|
||||||
gotoHome();
|
|
||||||
}
|
|
||||||
refreshGroups(0, false);
|
|
||||||
} else if (res.startsWith("error:")) {
|
|
||||||
showBlahNotification(res);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
showBlahNotification("error:something.wrong");
|
|
||||||
}
|
|
||||||
clearAction("leavegroup");
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -250,16 +250,6 @@ var addSpaceMenu = `
|
||||||
${ICONS.createSpace()}
|
${ICONS.createSpace()}
|
||||||
<span class="blah">title.create.space</span>
|
<span class="blah">title.create.space</span>
|
||||||
</button>`
|
</button>`
|
||||||
var groupContextMenu = `
|
|
||||||
<button onclick="gotoGroupSettings(currentContextMenuGroupId)">
|
|
||||||
${ICONS.settings()}
|
|
||||||
<span class="blah">title.group.settings</span>
|
|
||||||
</button>
|
|
||||||
<button onclick="leaveGroupPrompt(currentContextMenuGroupId)">
|
|
||||||
${ICONS.delete({ fill: "var(--big-red)" })}
|
|
||||||
<span class="blah" style="color: var(--big-red)">title.leave.group</span>
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
var messageContextMenu = `
|
var messageContextMenu = `
|
||||||
<button onclick="replyMessage(currentContextMenuMsgId)">
|
<button onclick="replyMessage(currentContextMenuMsgId)">
|
||||||
${ICONS.replyAction()}
|
${ICONS.replyAction()}
|
||||||
|
|
@ -280,7 +270,6 @@ var messageContextMenu = `
|
||||||
var backBtnHtml = `<button class="mobile-nav-btn" onclick="mobileNavBack()">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
var backBtnHtml = `<button class="mobile-nav-btn" onclick="mobileNavBack()">${ICONS.arrowBack({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
||||||
var pinBtnHtml = `<button class="topbar-action-btn room-action-pin right" onclick="showPinnedMessages()">${ICONS.pin({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
var pinBtnHtml = `<button class="topbar-action-btn room-action-pin right" onclick="showPinnedMessages()">${ICONS.pin({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
||||||
var callBtnHtml = `<button class="topbar-action-btn room-action-call right">${ICONS.call({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
var callBtnHtml = `<button class="topbar-action-btn room-action-call right">${ICONS.call({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
||||||
var groupMenuBtnHtml = `<button class="topbar-action-btn right" onclick="handleGroupContextMenu(arguments[0], currentDmId)">${ICONS.menu({ width: "1.5rem", height: "1.5rem" })}</button>`;
|
|
||||||
|
|
||||||
var settingsBar = `
|
var settingsBar = `
|
||||||
<div class="sidebar-section-header">
|
<div class="sidebar-section-header">
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,11 @@ sidebar {
|
||||||
border-right: var(--border-width) solid var(--light-border-color);
|
border-right: var(--border-width) solid var(--light-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sidebar:not(.second) {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
sidebar:not(.second)::-webkit-scrollbar {
|
sidebar:not(.second)::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -874,40 +879,6 @@ sidebarelement:has(.icon-button:active) indicator:not(.active) {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.popup-auto-height {
|
|
||||||
height: auto;
|
|
||||||
max-height: 85vh;
|
|
||||||
}
|
|
||||||
.popup-btn-cancel {
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
color: var(--text-color);
|
|
||||||
border: var(--border-width) solid var(--light-border-color);
|
|
||||||
flex: 1;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.popup-btn-cancel:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
.popup-btn-confirm {
|
|
||||||
background: var(--text-color);
|
|
||||||
color: var(--main-bg-color);
|
|
||||||
border: none;
|
|
||||||
flex: 1;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.popup-btn-confirm:hover {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
.popup-btn-danger {
|
|
||||||
background: var(--big-red);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
flex: 1;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.popup-btn-danger:hover {
|
|
||||||
background: #ff5252;
|
|
||||||
}
|
|
||||||
.profile-popup-container.show .profile-popup-content {
|
.profile-popup-container.show .profile-popup-content {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
@ -1067,8 +1038,12 @@ roomcontent roomtopbar .room-action-call {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.hide-topbar-pin roomcontent roomtopbar .room-action-pin { display: none !important; }
|
@media (max-width: 65rem) and (min-width: 55.001rem) {
|
||||||
body.hide-topbar-pin #roomdetailsbar roomtopbar .room-action-pin { display: flex !important; }
|
roomcontent roomtopbar .room-action-pin { display: none !important; }
|
||||||
|
#roomdetailsbar roomtopbar .room-action-pin { display: flex !important; }
|
||||||
|
}
|
||||||
|
|
||||||
body.hide-topbar-call roomcontent roomtopbar .room-action-call { display: none !important; }
|
@media (max-width: 58rem) and (min-width: 55.001rem) {
|
||||||
body.hide-topbar-call #roomdetailsbar roomtopbar .room-action-call { display: flex !important; }
|
roomcontent roomtopbar .room-action-call { display: none !important; }
|
||||||
|
#roomdetailsbar roomtopbar .room-action-call { display: flex !important; }
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue