Add fetching invites
This commit is contained in:
parent
81145968a1
commit
81e222250d
10 changed files with 690 additions and 262 deletions
|
|
@ -74,12 +74,21 @@
|
|||
"title.unread": "Unread",
|
||||
"desc.no.invites": "No invites found",
|
||||
"desc.no.notifications": "No notifications found",
|
||||
"desc.fetching.invites": "Fetching invites...",
|
||||
"desc.fetching.notifications": "Fetching notifications...",
|
||||
"desc.invite.dm.received": "{0} ({1}) invited you to chat",
|
||||
"desc.invite.dm.sent": "You invited {0} ({1}) to chat",
|
||||
"desc.invite.group.received": "{0} ({1}) invited you to a group",
|
||||
"desc.invite.group.sent": "You invited {0} ({1}) to a group",
|
||||
|
||||
"action.fetching.invites.sent": "Fetching sent invites...",
|
||||
"action.fetching.invites.recv": "Fetching received invites...",
|
||||
"action.dm.fetch": "Fetching dms...",
|
||||
"action.dm.adding": "Adding...",
|
||||
"action.auth": "Authenticating...",
|
||||
"action.dm.adding": "Adding...",
|
||||
"action.invite.revoking": "Revoking invite...",
|
||||
"action.invite.accepting": "Accepting invite...",
|
||||
"action.invite.declining": "Declining invite...",
|
||||
|
||||
"title.sign.up": "Sign Up",
|
||||
"title.sign.in": "Sign In",
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@
|
|||
{
|
||||
await updateProtocolAndUrl(window.location.hostname);
|
||||
}
|
||||
sidebarPfp.src = await getAvatarUrl(username);
|
||||
sidebarPfp.src = await getAvatarUrl(`${username}:${host}`);
|
||||
|
||||
showAction("action.auth", "startauth");
|
||||
let res = await Auth(username, password);
|
||||
|
|
|
|||
|
|
@ -406,6 +406,7 @@ function showNotification(message, type = 'info', duration = 3500) {
|
|||
notif.addEventListener('transitionend', () => {
|
||||
notif.remove();
|
||||
});
|
||||
setTimeout(() => notif.remove(), 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
|
|
@ -419,7 +420,7 @@ function showAction(message, actionid) {
|
|||
}
|
||||
|
||||
const notif = document.createElement('div');
|
||||
notif.className = `notification action`;
|
||||
notif.className = `notification`;
|
||||
notif.textContent = processBlah(message);
|
||||
notif.id = `notification-${actionid}`;
|
||||
|
||||
|
|
@ -438,9 +439,10 @@ function clearAction(actionid) {
|
|||
notifications.forEach(notif => {
|
||||
notif.classList.remove('show');
|
||||
|
||||
notif.addEventListener('transitionend', () => {
|
||||
notif.addEventListener('transitionend', async () => {
|
||||
notif.remove();
|
||||
}, { once: true });
|
||||
setTimeout(() => notif.remove(), 300);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -596,13 +598,27 @@ async function initBlahs() {
|
|||
}
|
||||
}
|
||||
|
||||
function splitLimit(str, separator, limit) {
|
||||
const parts = str.split(separator);
|
||||
|
||||
if (parts.length <= limit) {
|
||||
return parts;
|
||||
}
|
||||
|
||||
return [
|
||||
...parts.slice(0, limit - 1),
|
||||
parts.slice(limit - 1).join(separator)
|
||||
];
|
||||
}
|
||||
|
||||
function processBlah(blahmessage) {
|
||||
try {
|
||||
if (!blahmessage.includes(":")) {
|
||||
blahmessage = `:${blahmessage}`;
|
||||
}
|
||||
|
||||
let split = blahmessage.split(":");
|
||||
let split = splitLimit(blahmessage, ":", 3);
|
||||
|
||||
let values = [];
|
||||
try {
|
||||
values = split[2].split(";");
|
||||
|
|
@ -614,6 +630,11 @@ function processBlah(blahmessage) {
|
|||
let valueslist = "";
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let value = processBlah(values[i]);
|
||||
if (value.startsWith(":"))
|
||||
{
|
||||
value = value.substring(1);
|
||||
}
|
||||
|
||||
valueslist+=`${value}, `;
|
||||
|
||||
message = message.replaceAll(`{${i}}`, value);
|
||||
|
|
@ -964,60 +985,153 @@ function setActiveRoombarItem(itemId) {
|
|||
}
|
||||
}
|
||||
|
||||
async function renderInvites(res, type) {
|
||||
let container = document.getElementById("invites-container");
|
||||
if (!container) return;
|
||||
|
||||
if (res && res != "") {
|
||||
|
||||
res = JSON.parse(res);
|
||||
|
||||
let invites = [
|
||||
...Object.entries(res.dms).map(([id, value]) => ({
|
||||
id,
|
||||
type: "dm",
|
||||
...value
|
||||
})),
|
||||
|
||||
...Object.entries(res.groups).map(([id, value]) => ({
|
||||
id,
|
||||
type: "group",
|
||||
...value
|
||||
}))
|
||||
].sort((a, b) => b.timestamp - a.timestamp);
|
||||
|
||||
container.classList.remove("empty");
|
||||
let html = "";
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < invites.length; i++) {
|
||||
let invite = invites[i];
|
||||
|
||||
|
||||
if (invite.type === "dm") {
|
||||
let id = invite.id;
|
||||
if (!id.includes(":")) {
|
||||
id += `:${host}`;
|
||||
}
|
||||
let username = await fetchAsync(`${url}/idtoname?id=${id}`);
|
||||
if (!(username && username.trim() !== "")) return;
|
||||
count++;
|
||||
|
||||
let pfp = await getAvatarUrl(username);
|
||||
|
||||
let actions = "";
|
||||
let desc = "";
|
||||
|
||||
if (type === "received") {
|
||||
desc = `:desc.invite.dm.received:${username};${id}`;
|
||||
actions = `
|
||||
<button class="icon-button" style="background-color: var(--big-green); border-color: transparent;" onclick="acceptInvite('${id}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#fff"><path d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z"/></svg>
|
||||
</button>
|
||||
<button class="icon-button" style="background-color: var(--big-red); border-color: transparent;" onclick="declineInvite('${id}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#fff"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
|
||||
</button>
|
||||
`;
|
||||
} else {
|
||||
desc = `:desc.invite.dm.sent:${username};${id}`;
|
||||
actions = `
|
||||
<button class="icon-button" style="background-color: var(--big-red); border-color: transparent;" onclick="revokeInvite('${id}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#fff"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
let entry = invitesEntry
|
||||
.replaceAll("{username}", username.split(':')[0])
|
||||
.replaceAll("{pfp}", pfp)
|
||||
.replaceAll("{desc}", desc)
|
||||
.replaceAll("{actions}", actions);
|
||||
|
||||
html += entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
container.innerHTML = html;
|
||||
} else {
|
||||
container.classList.add("empty");
|
||||
container.innerHTML = invitesEmptyState;
|
||||
}
|
||||
} else {
|
||||
container.classList.add("empty");
|
||||
container.innerHTML = invitesEmptyState;
|
||||
}
|
||||
|
||||
let blahTags = container.getElementsByTagName("blah");
|
||||
for (let i = 0; i < blahTags.length; i++) {
|
||||
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadInvites(tab) {
|
||||
try {
|
||||
showAction(`action.fetching.invites.${tab === 'received' ? 'recv' : 'sent'}`, `fetching.invites.${tab}`);
|
||||
let res = await fetchEncrypted(`user/invites/${tab}`);
|
||||
await renderInvites(res, tab);
|
||||
} catch (e) {
|
||||
showBlahNotification("error:something.wrong");
|
||||
console.error(e);
|
||||
await renderInvites("", tab);
|
||||
}
|
||||
clearAction(`fetching.invites.${tab}`);
|
||||
}
|
||||
|
||||
async function switchInvitesTab(tab) {
|
||||
if (!document.getElementById(`tab-invites-${tab}`).classList.contains('tab-inactive')) return;
|
||||
document.getElementById('tab-invites-received').classList.add('tab-inactive');
|
||||
document.getElementById('tab-invites-sent').classList.add('tab-inactive');
|
||||
document.getElementById(`tab-invites-${tab}`).classList.remove('tab-inactive');
|
||||
|
||||
let container = document.getElementById("invites-container");
|
||||
let innerString = "";
|
||||
await loadInvites(tab);
|
||||
}
|
||||
async function acceptInvite(username) { //TODO
|
||||
try {
|
||||
showAction("action.invite.accepting", "invite.action");
|
||||
let res = await fetchEncrypted("user/dm/create", username);
|
||||
clearAction("invite.action");
|
||||
showBlahNotification(res || "success:invite.accepted");
|
||||
await loadInvites('received');
|
||||
} catch (e) {
|
||||
clearAction("invite.action");
|
||||
showBlahNotification("error:something.wrong");
|
||||
}
|
||||
}
|
||||
|
||||
if (tab === "received")
|
||||
{
|
||||
async function declineInvite(username) { //TODO
|
||||
try {
|
||||
showAction("action.fetching.invites.recv", "fetching.invites.recv");
|
||||
let res = await fetchEncrypted("user/invites/received");
|
||||
if (res !== "")
|
||||
{
|
||||
if (res.includes(",")) {
|
||||
console.log(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(res);
|
||||
container.innerHTML = invitesEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
showAction("action.invite.declining", "invite.action");
|
||||
let res = await fetchEncrypted("user/dm/decline", username);
|
||||
clearAction("invite.action");
|
||||
showBlahNotification(res || "success:invite.declined");
|
||||
await loadInvites('received');
|
||||
} catch (e) {
|
||||
clearAction("invite.action");
|
||||
showBlahNotification("error:something.wrong");
|
||||
console.error(e);
|
||||
}
|
||||
clearAction("fetching.invites.recv");
|
||||
}
|
||||
else if (tab === "sent")
|
||||
{
|
||||
|
||||
async function revokeInvite(username) { //TODO
|
||||
try {
|
||||
showAction("action.fetching.invites.sent", "fetching.invites.sent");
|
||||
let res = await fetchEncrypted("user/invites/sent");
|
||||
if (res !== "")
|
||||
{
|
||||
if (res.includes(",")) {
|
||||
console.log(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(res);
|
||||
container.innerHTML = invitesEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
showAction("action.invite.revoking", "invite.action");
|
||||
let res = await fetchEncrypted("user/dm/revoke", username);
|
||||
clearAction("invite.action");
|
||||
showBlahNotification(res || "success:invite.revoked");
|
||||
await loadInvites('sent');
|
||||
} catch (e) {
|
||||
clearAction("invite.action");
|
||||
showBlahNotification("error:something.wrong");
|
||||
console.error(e);
|
||||
}
|
||||
clearAction("fetching.invites.sent");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,18 +73,33 @@ var joinSpaceScreen = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
var invitesEmptyState = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.no.invites</blah></p>
|
||||
`;
|
||||
var invitesLoadingState = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.fetching.invites</blah></p>
|
||||
`;
|
||||
|
||||
var invitesScreen = `
|
||||
<div style="display: flex; flex-direction: column; height: 100%;">
|
||||
<div style="display: flex; gap: 0.5rem; padding: 0.5rem 1rem; border-bottom: var(--border-width) solid var(--light-border-color); flex-shrink: 0;">
|
||||
<button id="tab-invites-received" class="submit-button blah tab-inactive" onclick="switchInvitesTab('received')" style="margin:0; padding: 0 1.5rem;">title.received</button>
|
||||
<button id="tab-invites-sent" class="submit-button blah tab-inactive" onclick="switchInvitesTab('sent')" style="margin:0; padding: 0 1.5rem;">title.sent</button>
|
||||
</div>
|
||||
<div id="invites-container" style="flex-grow: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; opacity: 0.5;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>
|
||||
<div id="invites-container" class="list-container empty">
|
||||
${invitesLoadingState}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
var notifisEmptyState = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-200v-80h80v-280q0-83 50-147.5T420-792v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v280h80v80H160Zm320-300Zm0 420q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-280h320v-280q0-66-47-113t-113-47q-66 0-113 47t-47 113v280Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.no.invites</blah></p>
|
||||
</div>
|
||||
</div>
|
||||
<p><blah>desc.no.notifications</blah></p>
|
||||
`;
|
||||
|
||||
var notifisScreen = `
|
||||
|
|
@ -93,10 +108,23 @@ var notifisScreen = `
|
|||
<button id="tab-notifis-all" class="submit-button blah tab-inactive" onclick="switchNotifisTab('all')" style="margin:0; padding: 0 1.5rem;">title.all</button>
|
||||
<button id="tab-notifis-unread" class="submit-button blah tab-inactive" onclick="switchNotifisTab('unread')" style="margin:0; padding: 0 1.5rem;">title.unread</button>
|
||||
</div>
|
||||
<div id="notifis-container" style="flex-grow: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; opacity: 0.5;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-200v-80h80v-280q0-83 50-147.5T420-792v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v280h80v80H160Zm320-300Zm0 420q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-280h320v-280q0-66-47-113t-113-47q-66 0-113 47t-47 113v280Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.no.notifications</blah></p>
|
||||
<div id="notifis-container" class="list-container empty">
|
||||
${notifisEmptyState}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
var invitesEntry = `
|
||||
<div class="invite-entry">
|
||||
<div class="invite-info">
|
||||
<img src="{pfp}" class="invite-pfp">
|
||||
<div class="invite-details">
|
||||
<span class="invite-name">{username}</span>
|
||||
<span class="invite-desc"><blah>{desc}</blah></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invite-actions">
|
||||
{actions}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -171,5 +199,3 @@ var addSpaceMenu = `
|
|||
//elements
|
||||
var detailsBtn = `<button class="mobile-nav-btn right" onclick="mobileNavDetails()"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/></svg></button>`;
|
||||
var backBtnHtml = `<button class="mobile-nav-btn" onclick="mobileNavBack()"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="m313-440 224 224-57 56-320-320 320-320 57 56-224 224h487v80H313Z"/></svg></button>`;
|
||||
|
||||
var invitesEntry = `???`;
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
--button-height: 2.4rem;
|
||||
--border-width: 0.09rem;
|
||||
|
||||
--big-default: rgb(207 207 207);
|
||||
--big-red: rgb(202 0 0);
|
||||
--big-green: rgb(25 189 0);
|
||||
--big-default: rgb(207, 207, 207);
|
||||
--big-red: rgb(195, 75, 75);
|
||||
--big-green: rgb(75, 165, 95);
|
||||
}
|
||||
*:focus {
|
||||
outline: none;
|
||||
|
|
@ -148,6 +148,7 @@ indicator.active {
|
|||
width: calc(var(--icon-button-height) - (var(--border-width) * 2));
|
||||
height: calc(var(--icon-button-height) - (var(--border-width) * 2));
|
||||
pointer-events: none !important;
|
||||
border-radius: 0.6rem;
|
||||
}
|
||||
|
||||
roomcontent {
|
||||
|
|
@ -252,11 +253,11 @@ hr {
|
|||
box-shadow: 0 0.5rem 2rem rgba(0, 0, 0, 0.4);
|
||||
|
||||
opacity: 0;
|
||||
transform: translateY(-1rem);
|
||||
transform: translateY(-2rem);
|
||||
transition:
|
||||
opacity 0.3s ease,
|
||||
transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275),
|
||||
background-color 0.2s ease;
|
||||
opacity 0.2s ease,
|
||||
transform 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275),
|
||||
background-color 0.15s ease;
|
||||
}
|
||||
.notification.show {
|
||||
opacity: 1;
|
||||
|
|
@ -330,52 +331,7 @@ herotitle {
|
|||
.bottom-element {
|
||||
margin-top: auto;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
sidebarelement:hover indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
button:hover, input:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
button:active, button.is-pressed, input:active, input.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: var(--press-scale);
|
||||
}
|
||||
button.active, input.active {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:active, .submit-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:active, .add-action-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
sidebarelement:has(.icon-button:active) indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
|
||||
blah, inherit, .inherit {
|
||||
all: inherit;
|
||||
padding: 0;
|
||||
|
|
@ -419,9 +375,7 @@ space{
|
|||
gap: 0.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.context-menu button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.mobile-nav-btn {
|
||||
display: none;
|
||||
background: transparent;
|
||||
|
|
@ -466,7 +420,7 @@ space{
|
|||
sidebar, sidebar.second, roomcontent {
|
||||
position: absolute !important;
|
||||
height: 100%;
|
||||
transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
transition: all 0.25s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
sidebar {
|
||||
|
|
@ -537,7 +491,7 @@ space{
|
|||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
transition: opacity 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
transition: all 0.25s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
main.mobile-details roomcontent::after {
|
||||
|
|
@ -554,3 +508,114 @@ space{
|
|||
background-color: transparent;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.list-container {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
overflow-y: auto;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.list-container.empty {
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.invite-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.8rem 1rem;
|
||||
border: var(--border-width) solid var(--light-border-color);
|
||||
border-radius: 0.8rem;
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.invite-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
.invite-pfp {
|
||||
width: 2.8rem;
|
||||
height: 2.8rem;
|
||||
border-radius: 0.8rem;
|
||||
object-fit: cover;
|
||||
}
|
||||
.invite-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
}
|
||||
.invite-name {
|
||||
font-weight: 700;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
.invite-desc {
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.invite-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.invite-actions button {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
sidebarelement:hover indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
button:hover, input:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
.context-menu button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
}
|
||||
button:active, button.is-pressed, input:active, input.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: var(--press-scale);
|
||||
}
|
||||
button.active, input.active {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:active, .submit-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:active, .add-action-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
.context-menu button:active, .context-menu button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
sidebarelement:has(.icon-button:active) indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
|
|
@ -74,12 +74,21 @@
|
|||
"title.unread": "Unread",
|
||||
"desc.no.invites": "No invites found",
|
||||
"desc.no.notifications": "No notifications found",
|
||||
"desc.fetching.invites": "Fetching invites...",
|
||||
"desc.fetching.notifications": "Fetching notifications...",
|
||||
"desc.invite.dm.received": "{0} ({1}) invited you to chat",
|
||||
"desc.invite.dm.sent": "You invited {0} ({1}) to chat",
|
||||
"desc.invite.group.received": "{0} ({1}) invited you to a group",
|
||||
"desc.invite.group.sent": "You invited {0} ({1}) to a group",
|
||||
|
||||
"action.fetching.invites.sent": "Fetching sent invites...",
|
||||
"action.fetching.invites.recv": "Fetching received invites...",
|
||||
"action.dm.fetch": "Fetching dms...",
|
||||
"action.dm.adding": "Adding...",
|
||||
"action.auth": "Authenticating...",
|
||||
"action.dm.adding": "Adding...",
|
||||
"action.invite.revoking": "Revoking invite...",
|
||||
"action.invite.accepting": "Accepting invite...",
|
||||
"action.invite.declining": "Declining invite...",
|
||||
|
||||
"title.sign.up": "Sign Up",
|
||||
"title.sign.in": "Sign In",
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@
|
|||
{
|
||||
await updateProtocolAndUrl(window.location.hostname);
|
||||
}
|
||||
sidebarPfp.src = await getAvatarUrl(username);
|
||||
sidebarPfp.src = await getAvatarUrl(`${username}:${host}`);
|
||||
|
||||
showAction("action.auth", "startauth");
|
||||
let res = await Auth(username, password);
|
||||
|
|
|
|||
202
webroot/main.js
202
webroot/main.js
|
|
@ -406,6 +406,7 @@ function showNotification(message, type = 'info', duration = 3500) {
|
|||
notif.addEventListener('transitionend', () => {
|
||||
notif.remove();
|
||||
});
|
||||
setTimeout(() => notif.remove(), 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
|
|
@ -419,7 +420,7 @@ function showAction(message, actionid) {
|
|||
}
|
||||
|
||||
const notif = document.createElement('div');
|
||||
notif.className = `notification action`;
|
||||
notif.className = `notification`;
|
||||
notif.textContent = processBlah(message);
|
||||
notif.id = `notification-${actionid}`;
|
||||
|
||||
|
|
@ -438,9 +439,10 @@ function clearAction(actionid) {
|
|||
notifications.forEach(notif => {
|
||||
notif.classList.remove('show');
|
||||
|
||||
notif.addEventListener('transitionend', () => {
|
||||
notif.addEventListener('transitionend', async () => {
|
||||
notif.remove();
|
||||
}, { once: true });
|
||||
setTimeout(() => notif.remove(), 300);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -596,13 +598,27 @@ async function initBlahs() {
|
|||
}
|
||||
}
|
||||
|
||||
function splitLimit(str, separator, limit) {
|
||||
const parts = str.split(separator);
|
||||
|
||||
if (parts.length <= limit) {
|
||||
return parts;
|
||||
}
|
||||
|
||||
return [
|
||||
...parts.slice(0, limit - 1),
|
||||
parts.slice(limit - 1).join(separator)
|
||||
];
|
||||
}
|
||||
|
||||
function processBlah(blahmessage) {
|
||||
try {
|
||||
if (!blahmessage.includes(":")) {
|
||||
blahmessage = `:${blahmessage}`;
|
||||
}
|
||||
|
||||
let split = blahmessage.split(":");
|
||||
let split = splitLimit(blahmessage, ":", 3);
|
||||
|
||||
let values = [];
|
||||
try {
|
||||
values = split[2].split(";");
|
||||
|
|
@ -614,6 +630,11 @@ function processBlah(blahmessage) {
|
|||
let valueslist = "";
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let value = processBlah(values[i]);
|
||||
if (value.startsWith(":"))
|
||||
{
|
||||
value = value.substring(1);
|
||||
}
|
||||
|
||||
valueslist+=`${value}, `;
|
||||
|
||||
message = message.replaceAll(`{${i}}`, value);
|
||||
|
|
@ -964,60 +985,153 @@ function setActiveRoombarItem(itemId) {
|
|||
}
|
||||
}
|
||||
|
||||
async function renderInvites(res, type) {
|
||||
let container = document.getElementById("invites-container");
|
||||
if (!container) return;
|
||||
|
||||
if (res && res != "") {
|
||||
|
||||
res = JSON.parse(res);
|
||||
|
||||
let invites = [
|
||||
...Object.entries(res.dms).map(([id, value]) => ({
|
||||
id,
|
||||
type: "dm",
|
||||
...value
|
||||
})),
|
||||
|
||||
...Object.entries(res.groups).map(([id, value]) => ({
|
||||
id,
|
||||
type: "group",
|
||||
...value
|
||||
}))
|
||||
].sort((a, b) => b.timestamp - a.timestamp);
|
||||
|
||||
container.classList.remove("empty");
|
||||
let html = "";
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < invites.length; i++) {
|
||||
let invite = invites[i];
|
||||
|
||||
|
||||
if (invite.type === "dm") {
|
||||
let id = invite.id;
|
||||
if (!id.includes(":")) {
|
||||
id += `:${host}`;
|
||||
}
|
||||
let username = await fetchAsync(`${url}/idtoname?id=${id}`);
|
||||
if (!(username && username.trim() !== "")) return;
|
||||
count++;
|
||||
|
||||
let pfp = await getAvatarUrl(username);
|
||||
|
||||
let actions = "";
|
||||
let desc = "";
|
||||
|
||||
if (type === "received") {
|
||||
desc = `:desc.invite.dm.received:${username};${id}`;
|
||||
actions = `
|
||||
<button class="icon-button" style="background-color: var(--big-green); border-color: transparent;" onclick="acceptInvite('${id}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#fff"><path d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z"/></svg>
|
||||
</button>
|
||||
<button class="icon-button" style="background-color: var(--big-red); border-color: transparent;" onclick="declineInvite('${id}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#fff"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
|
||||
</button>
|
||||
`;
|
||||
} else {
|
||||
desc = `:desc.invite.dm.sent:${username};${id}`;
|
||||
actions = `
|
||||
<button class="icon-button" style="background-color: var(--big-red); border-color: transparent;" onclick="revokeInvite('${id}')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#fff"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
let entry = invitesEntry
|
||||
.replaceAll("{username}", username.split(':')[0])
|
||||
.replaceAll("{pfp}", pfp)
|
||||
.replaceAll("{desc}", desc)
|
||||
.replaceAll("{actions}", actions);
|
||||
|
||||
html += entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
container.innerHTML = html;
|
||||
} else {
|
||||
container.classList.add("empty");
|
||||
container.innerHTML = invitesEmptyState;
|
||||
}
|
||||
} else {
|
||||
container.classList.add("empty");
|
||||
container.innerHTML = invitesEmptyState;
|
||||
}
|
||||
|
||||
let blahTags = container.getElementsByTagName("blah");
|
||||
for (let i = 0; i < blahTags.length; i++) {
|
||||
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadInvites(tab) {
|
||||
try {
|
||||
showAction(`action.fetching.invites.${tab === 'received' ? 'recv' : 'sent'}`, `fetching.invites.${tab}`);
|
||||
let res = await fetchEncrypted(`user/invites/${tab}`);
|
||||
await renderInvites(res, tab);
|
||||
} catch (e) {
|
||||
showBlahNotification("error:something.wrong");
|
||||
console.error(e);
|
||||
await renderInvites("", tab);
|
||||
}
|
||||
clearAction(`fetching.invites.${tab}`);
|
||||
}
|
||||
|
||||
async function switchInvitesTab(tab) {
|
||||
if (!document.getElementById(`tab-invites-${tab}`).classList.contains('tab-inactive')) return;
|
||||
document.getElementById('tab-invites-received').classList.add('tab-inactive');
|
||||
document.getElementById('tab-invites-sent').classList.add('tab-inactive');
|
||||
document.getElementById(`tab-invites-${tab}`).classList.remove('tab-inactive');
|
||||
|
||||
let container = document.getElementById("invites-container");
|
||||
let innerString = "";
|
||||
await loadInvites(tab);
|
||||
}
|
||||
async function acceptInvite(username) { //TODO
|
||||
try {
|
||||
showAction("action.invite.accepting", "invite.action");
|
||||
let res = await fetchEncrypted("user/dm/create", username);
|
||||
clearAction("invite.action");
|
||||
showBlahNotification(res || "success:invite.accepted");
|
||||
await loadInvites('received');
|
||||
} catch (e) {
|
||||
clearAction("invite.action");
|
||||
showBlahNotification("error:something.wrong");
|
||||
}
|
||||
}
|
||||
|
||||
if (tab === "received")
|
||||
{
|
||||
async function declineInvite(username) { //TODO
|
||||
try {
|
||||
showAction("action.fetching.invites.recv", "fetching.invites.recv");
|
||||
let res = await fetchEncrypted("user/invites/received");
|
||||
if (res !== "")
|
||||
{
|
||||
if (res.includes(",")) {
|
||||
console.log(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(res);
|
||||
container.innerHTML = invitesEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
showAction("action.invite.declining", "invite.action");
|
||||
let res = await fetchEncrypted("user/dm/decline", username);
|
||||
clearAction("invite.action");
|
||||
showBlahNotification(res || "success:invite.declined");
|
||||
await loadInvites('received');
|
||||
} catch (e) {
|
||||
clearAction("invite.action");
|
||||
showBlahNotification("error:something.wrong");
|
||||
console.error(e);
|
||||
}
|
||||
clearAction("fetching.invites.recv");
|
||||
}
|
||||
else if (tab === "sent")
|
||||
{
|
||||
|
||||
async function revokeInvite(username) { //TODO
|
||||
try {
|
||||
showAction("action.fetching.invites.sent", "fetching.invites.sent");
|
||||
let res = await fetchEncrypted("user/invites/sent");
|
||||
if (res !== "")
|
||||
{
|
||||
if (res.includes(",")) {
|
||||
console.log(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(res);
|
||||
container.innerHTML = invitesEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
showAction("action.invite.revoking", "invite.action");
|
||||
let res = await fetchEncrypted("user/dm/revoke", username);
|
||||
clearAction("invite.action");
|
||||
showBlahNotification(res || "success:invite.revoked");
|
||||
await loadInvites('sent');
|
||||
} catch (e) {
|
||||
clearAction("invite.action");
|
||||
showBlahNotification("error:something.wrong");
|
||||
console.error(e);
|
||||
}
|
||||
clearAction("fetching.invites.sent");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,18 +73,33 @@ var joinSpaceScreen = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
var invitesEmptyState = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.no.invites</blah></p>
|
||||
`;
|
||||
var invitesLoadingState = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.fetching.invites</blah></p>
|
||||
`;
|
||||
|
||||
var invitesScreen = `
|
||||
<div style="display: flex; flex-direction: column; height: 100%;">
|
||||
<div style="display: flex; gap: 0.5rem; padding: 0.5rem 1rem; border-bottom: var(--border-width) solid var(--light-border-color); flex-shrink: 0;">
|
||||
<button id="tab-invites-received" class="submit-button blah tab-inactive" onclick="switchInvitesTab('received')" style="margin:0; padding: 0 1.5rem;">title.received</button>
|
||||
<button id="tab-invites-sent" class="submit-button blah tab-inactive" onclick="switchInvitesTab('sent')" style="margin:0; padding: 0 1.5rem;">title.sent</button>
|
||||
</div>
|
||||
<div id="invites-container" style="flex-grow: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; opacity: 0.5;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>
|
||||
<div id="invites-container" class="list-container empty">
|
||||
${invitesLoadingState}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
var notifisEmptyState = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-200v-80h80v-280q0-83 50-147.5T420-792v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v280h80v80H160Zm320-300Zm0 420q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-280h320v-280q0-66-47-113t-113-47q-66 0-113 47t-47 113v280Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.no.invites</blah></p>
|
||||
</div>
|
||||
</div>
|
||||
<p><blah>desc.no.notifications</blah></p>
|
||||
`;
|
||||
|
||||
var notifisScreen = `
|
||||
|
|
@ -93,10 +108,23 @@ var notifisScreen = `
|
|||
<button id="tab-notifis-all" class="submit-button blah tab-inactive" onclick="switchNotifisTab('all')" style="margin:0; padding: 0 1.5rem;">title.all</button>
|
||||
<button id="tab-notifis-unread" class="submit-button blah tab-inactive" onclick="switchNotifisTab('unread')" style="margin:0; padding: 0 1.5rem;">title.unread</button>
|
||||
</div>
|
||||
<div id="notifis-container" style="flex-grow: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; opacity: 0.5;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="4rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M160-200v-80h80v-280q0-83 50-147.5T420-792v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v280h80v80H160Zm320-300Zm0 420q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-280h320v-280q0-66-47-113t-113-47q-66 0-113 47t-47 113v280Z"/></svg>
|
||||
<br>
|
||||
<p><blah>desc.no.notifications</blah></p>
|
||||
<div id="notifis-container" class="list-container empty">
|
||||
${notifisEmptyState}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
var invitesEntry = `
|
||||
<div class="invite-entry">
|
||||
<div class="invite-info">
|
||||
<img src="{pfp}" class="invite-pfp">
|
||||
<div class="invite-details">
|
||||
<span class="invite-name">{username}</span>
|
||||
<span class="invite-desc"><blah>{desc}</blah></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invite-actions">
|
||||
{actions}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -171,5 +199,3 @@ var addSpaceMenu = `
|
|||
//elements
|
||||
var detailsBtn = `<button class="mobile-nav-btn right" onclick="mobileNavDetails()"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/></svg></button>`;
|
||||
var backBtnHtml = `<button class="mobile-nav-btn" onclick="mobileNavBack()"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="m313-440 224 224-57 56-320-320 320-320 57 56-224 224h487v80H313Z"/></svg></button>`;
|
||||
|
||||
var invitesEntry = `???`;
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
--button-height: 2.4rem;
|
||||
--border-width: 0.09rem;
|
||||
|
||||
--big-default: rgb(207 207 207);
|
||||
--big-red: rgb(202 0 0);
|
||||
--big-green: rgb(25 189 0);
|
||||
--big-default: rgb(207, 207, 207);
|
||||
--big-red: rgb(195, 75, 75);
|
||||
--big-green: rgb(75, 165, 95);
|
||||
}
|
||||
*:focus {
|
||||
outline: none;
|
||||
|
|
@ -148,6 +148,7 @@ indicator.active {
|
|||
width: calc(var(--icon-button-height) - (var(--border-width) * 2));
|
||||
height: calc(var(--icon-button-height) - (var(--border-width) * 2));
|
||||
pointer-events: none !important;
|
||||
border-radius: 0.6rem;
|
||||
}
|
||||
|
||||
roomcontent {
|
||||
|
|
@ -252,11 +253,11 @@ hr {
|
|||
box-shadow: 0 0.5rem 2rem rgba(0, 0, 0, 0.4);
|
||||
|
||||
opacity: 0;
|
||||
transform: translateY(-1rem);
|
||||
transform: translateY(-2rem);
|
||||
transition:
|
||||
opacity 0.3s ease,
|
||||
transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275),
|
||||
background-color 0.2s ease;
|
||||
opacity 0.2s ease,
|
||||
transform 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275),
|
||||
background-color 0.15s ease;
|
||||
}
|
||||
.notification.show {
|
||||
opacity: 1;
|
||||
|
|
@ -330,52 +331,7 @@ herotitle {
|
|||
.bottom-element {
|
||||
margin-top: auto;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
sidebarelement:hover indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
button:hover, input:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
button:active, button.is-pressed, input:active, input.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: var(--press-scale);
|
||||
}
|
||||
button.active, input.active {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:active, .submit-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:active, .add-action-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
sidebarelement:has(.icon-button:active) indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
|
||||
blah, inherit, .inherit {
|
||||
all: inherit;
|
||||
padding: 0;
|
||||
|
|
@ -419,9 +375,7 @@ space{
|
|||
gap: 0.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.context-menu button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.mobile-nav-btn {
|
||||
display: none;
|
||||
background: transparent;
|
||||
|
|
@ -466,7 +420,7 @@ space{
|
|||
sidebar, sidebar.second, roomcontent {
|
||||
position: absolute !important;
|
||||
height: 100%;
|
||||
transition: transform 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
transition: all 0.25s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
sidebar {
|
||||
|
|
@ -537,7 +491,7 @@ space{
|
|||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
transition: opacity 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
transition: all 0.25s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
}
|
||||
|
||||
main.mobile-details roomcontent::after {
|
||||
|
|
@ -554,3 +508,114 @@ space{
|
|||
background-color: transparent;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.list-container {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
overflow-y: auto;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.list-container.empty {
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.invite-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.8rem 1rem;
|
||||
border: var(--border-width) solid var(--light-border-color);
|
||||
border-radius: 0.8rem;
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.invite-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
.invite-pfp {
|
||||
width: 2.8rem;
|
||||
height: 2.8rem;
|
||||
border-radius: 0.8rem;
|
||||
object-fit: cover;
|
||||
}
|
||||
.invite-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
}
|
||||
.invite-name {
|
||||
font-weight: 700;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
.invite-desc {
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.invite-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.invite-actions button {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
sidebarelement:hover indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
button:hover, input:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
.context-menu button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
}
|
||||
button:active, button.is-pressed, input:active, input.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: var(--press-scale);
|
||||
}
|
||||
button.active, input.active {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.submit-button:active, .submit-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.add-action-button:active, .add-action-button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-color);
|
||||
}
|
||||
.context-menu button:active, .context-menu button.is-pressed {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
sidebarelement:has(.icon-button:active) indicator:not(.active) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 1.2rem;
|
||||
left: -0.08rem;
|
||||
border: 0.15rem solid var(--text-color);
|
||||
border-radius: 0.8rem;
|
||||
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue