Add example notifications and invites tab and improve ux

This commit is contained in:
olcxja 2026-05-19 23:28:08 +02:00
commit f63f8dd77c
8 changed files with 264 additions and 24 deletions

View file

@ -131,13 +131,11 @@
}
}
async function addDm() {
try {
showAction("Adding...", "dmadd");
let res = await fetchEncrypted("user/dm/invite", document.getElementById("addchat-username").value);
console.log(res);
let ressplit = res.split(":");
clearAction("dmadd");
showBlahNotification(res);
}

View file

@ -687,7 +687,15 @@ function showFixedContextMenu(rect, html) {
fixedContextMenu.classList.add("show");
}
var currentRoomsBarTitle = null;
var currentRoomsBarHtml = null;
async function switchRoomsBar(title, content) {
if (currentRoomsBarTitle === title && currentRoomsBarHtml === content) return;
currentRoomsBarTitle = title;
currentRoomsBarHtml = content;
let roomsTopBarTransition = roomsTopBar.children.item(0);
roomsBar.style.transform = "scale(0.85)";
@ -731,8 +739,23 @@ async function switchRoomsBar(title, content) {
roomsTopBarTransition.style.transform = "";
roomsTopBarTransition.style.opacity = "";
}
var currentRoomContentTitle = null;
var currentRoomContentHtml = null;
async function switchRoomContent(title, content, showRoomBar, icon = "", skipMobileSlide = false)
{
if (currentRoomContentTitle === title && currentRoomContentHtml === content) {
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
if (window.innerWidth <= 52 * rem && !skipMobileSlide) {
if (title != "title.splash") { //do not show splash on mobile
mainScreen.classList.remove('mobile-details');
mainScreen.classList.add('mobile-content');
}
}
return;
}
currentRoomContentTitle = title;
currentRoomContentHtml = content;
let roomsTopBarTransition = roomTopBar.children.item(0);
roomContentMain.style.transform = "scale(0.85)";
@ -791,8 +814,14 @@ async function switchRoomContent(title, content, showRoomBar, icon = "", skipMob
}
var currentDetailsContentTitle = null;
var currentDetailsContentHtml = null;
async function switchDetailsContent(title, content)
{
if (currentDetailsContentTitle === title && currentDetailsContentHtml === content) return;
currentDetailsContentTitle = title;
currentDetailsContentHtml = content;
let roomsTopBarTransition = detailsTopBar.children.item(0);
roomDetailsMain.style.transform = "scale(0.85)";
@ -925,11 +954,51 @@ function popstate()
function gotoSideProfilePopup() {
}
function gotoInbox() {
function setActiveRoombarItem(itemId) {
let items = document.querySelectorAll('.collapse-text-button');
items.forEach(item => item.classList.remove('selected'));
if (itemId) {
let activeItem = document.getElementById(itemId);
if (activeItem) activeItem.classList.add('selected');
}
}
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');
}
function switchNotifisTab(tab) {
if (!document.getElementById(`tab-notifis-${tab}`).classList.contains('tab-inactive')) return;
document.getElementById('tab-notifis-all').classList.add('tab-inactive');
document.getElementById('tab-notifis-unread').classList.add('tab-inactive');
document.getElementById(`tab-notifis-${tab}`).classList.remove('tab-inactive');
}
async function gotoInbox() {
if (roomsBarContainer) roomsBarContainer.style.display = ""; //show roombar
setActiveSidebarIndicator(sidebarInboxIndicator);
switchRoomsBar("title.inbox", inboxRoomBar);
await switchRoomsBar("title.inbox", inboxRoomBar);
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
if (window.innerWidth > 52 * rem) {
gotoInvites();
}
}
function gotoInvites() {
setActiveRoombarItem('collapse-invites');
switchRoomContent("title.invites", invitesScreen, false);
}
function gotoNotifis() {
setActiveRoombarItem('collapse-notifis');
switchRoomContent("title.notifications", notifisScreen, false);
}
function gotoCreateSpace() {
@ -949,6 +1018,7 @@ function gotoHome() {
setActiveSidebarIndicator(sidebarHomeIndicator);
switchRoomContent("title.splash", splashScreen, false);
switchRoomsBar("title.home", homeRoomBar);
setActiveRoombarItem(null);
}
function setActiveSidebarIndicator(element, isTemporary = false) {
@ -972,11 +1042,15 @@ function mobileNavBack() {
setActiveSidebarIndicator(currentMainIndicator);
} else {
setActiveRoombarItem(null);
if (roomsBarContainer) {
roomsBarContainer.style.display = ""; //restore roombar on mobile
void roomsBarContainer.offsetWidth;
}
mainScreen.classList.remove('mobile-content');
setActiveSidebarIndicator(currentMainIndicator);
if (roomsBarContainer) roomsBarContainer.style.display = ""; //restore roombar on mobile
}
}
function mobileNavDetails() {
@ -1026,10 +1100,18 @@ document.addEventListener('touchend', e => {
activeTouchButton.classList.remove('is-pressed');
if (!touchMoved) {
if (activeTouchButton.tagName !== 'INPUT') {
if (document.activeElement && document.activeElement.tagName === 'INPUT') {
document.activeElement.blur();
}
if (e.cancelable) {
e.preventDefault();
}
activeTouchButton.click();
} else {
activeTouchButton.focus();
}
}
activeTouchButton = null;
}

View file

@ -73,6 +73,34 @@ var joinSpaceScreen = `
</div>
`;
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" 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 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>
<br>
<p><blah>desc.no.invites</blah></p>
</div>
</div>
`;
var notifisScreen = `
<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-notifis-all" class="submit-button blah" 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 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>
</div>
`;
//roombars
var homeRoomBar = `
<div class="sidebar-section-header">
@ -112,7 +140,7 @@ var homeRoomBar = `
var inboxRoomBar = `
<div class="sidebar-section-header">
<button class="collapse-text-button active" id="collapse-invites" onclick="gotoInvites()">
<button class="collapse-text-button" id="collapse-invites" onclick="gotoInvites()">
<svg xmlns="http://www.w3.org/2000/svg" class="chevron" 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>
<span><blah>title.invites</blah></span>
</button>

View file

@ -40,6 +40,7 @@ html {
}
body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
background-color: var(--main-bg-color);
overflow: hidden;
display: flex;
@ -94,6 +95,8 @@ button, input {
input {
padding-left: calc(var(--button-margin) * 2);
-webkit-touch-callout: default;
user-select: text !important;
-webkit-user-select: text !important;
}
@ -542,3 +545,12 @@ space{
pointer-events: auto;
}
}
.collapse-text-button.selected {
background-color: rgba(240, 240, 245, 0.1);
}
.submit-button.tab-inactive {
background-color: transparent;
color: var(--text-color);
}

View file

@ -131,13 +131,11 @@
}
}
async function addDm() {
try {
showAction("Adding...", "dmadd");
let res = await fetchEncrypted("user/dm/invite", document.getElementById("addchat-username").value);
console.log(res);
let ressplit = res.split(":");
clearAction("dmadd");
showBlahNotification(res);
}

View file

@ -687,7 +687,15 @@ function showFixedContextMenu(rect, html) {
fixedContextMenu.classList.add("show");
}
var currentRoomsBarTitle = null;
var currentRoomsBarHtml = null;
async function switchRoomsBar(title, content) {
if (currentRoomsBarTitle === title && currentRoomsBarHtml === content) return;
currentRoomsBarTitle = title;
currentRoomsBarHtml = content;
let roomsTopBarTransition = roomsTopBar.children.item(0);
roomsBar.style.transform = "scale(0.85)";
@ -731,8 +739,23 @@ async function switchRoomsBar(title, content) {
roomsTopBarTransition.style.transform = "";
roomsTopBarTransition.style.opacity = "";
}
var currentRoomContentTitle = null;
var currentRoomContentHtml = null;
async function switchRoomContent(title, content, showRoomBar, icon = "", skipMobileSlide = false)
{
if (currentRoomContentTitle === title && currentRoomContentHtml === content) {
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
if (window.innerWidth <= 52 * rem && !skipMobileSlide) {
if (title != "title.splash") { //do not show splash on mobile
mainScreen.classList.remove('mobile-details');
mainScreen.classList.add('mobile-content');
}
}
return;
}
currentRoomContentTitle = title;
currentRoomContentHtml = content;
let roomsTopBarTransition = roomTopBar.children.item(0);
roomContentMain.style.transform = "scale(0.85)";
@ -791,8 +814,14 @@ async function switchRoomContent(title, content, showRoomBar, icon = "", skipMob
}
var currentDetailsContentTitle = null;
var currentDetailsContentHtml = null;
async function switchDetailsContent(title, content)
{
if (currentDetailsContentTitle === title && currentDetailsContentHtml === content) return;
currentDetailsContentTitle = title;
currentDetailsContentHtml = content;
let roomsTopBarTransition = detailsTopBar.children.item(0);
roomDetailsMain.style.transform = "scale(0.85)";
@ -925,11 +954,51 @@ function popstate()
function gotoSideProfilePopup() {
}
function gotoInbox() {
function setActiveRoombarItem(itemId) {
let items = document.querySelectorAll('.collapse-text-button');
items.forEach(item => item.classList.remove('selected'));
if (itemId) {
let activeItem = document.getElementById(itemId);
if (activeItem) activeItem.classList.add('selected');
}
}
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');
}
function switchNotifisTab(tab) {
if (!document.getElementById(`tab-notifis-${tab}`).classList.contains('tab-inactive')) return;
document.getElementById('tab-notifis-all').classList.add('tab-inactive');
document.getElementById('tab-notifis-unread').classList.add('tab-inactive');
document.getElementById(`tab-notifis-${tab}`).classList.remove('tab-inactive');
}
async function gotoInbox() {
if (roomsBarContainer) roomsBarContainer.style.display = ""; //show roombar
setActiveSidebarIndicator(sidebarInboxIndicator);
switchRoomsBar("title.inbox", inboxRoomBar);
await switchRoomsBar("title.inbox", inboxRoomBar);
const rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
if (window.innerWidth > 52 * rem) {
gotoInvites();
}
}
function gotoInvites() {
setActiveRoombarItem('collapse-invites');
switchRoomContent("title.invites", invitesScreen, false);
}
function gotoNotifis() {
setActiveRoombarItem('collapse-notifis');
switchRoomContent("title.notifications", notifisScreen, false);
}
function gotoCreateSpace() {
@ -949,6 +1018,7 @@ function gotoHome() {
setActiveSidebarIndicator(sidebarHomeIndicator);
switchRoomContent("title.splash", splashScreen, false);
switchRoomsBar("title.home", homeRoomBar);
setActiveRoombarItem(null);
}
function setActiveSidebarIndicator(element, isTemporary = false) {
@ -972,11 +1042,15 @@ function mobileNavBack() {
setActiveSidebarIndicator(currentMainIndicator);
} else {
setActiveRoombarItem(null);
if (roomsBarContainer) {
roomsBarContainer.style.display = ""; //restore roombar on mobile
void roomsBarContainer.offsetWidth;
}
mainScreen.classList.remove('mobile-content');
setActiveSidebarIndicator(currentMainIndicator);
if (roomsBarContainer) roomsBarContainer.style.display = ""; //restore roombar on mobile
}
}
function mobileNavDetails() {
@ -1026,10 +1100,18 @@ document.addEventListener('touchend', e => {
activeTouchButton.classList.remove('is-pressed');
if (!touchMoved) {
if (activeTouchButton.tagName !== 'INPUT') {
if (document.activeElement && document.activeElement.tagName === 'INPUT') {
document.activeElement.blur();
}
if (e.cancelable) {
e.preventDefault();
}
activeTouchButton.click();
} else {
activeTouchButton.focus();
}
}
activeTouchButton = null;
}

View file

@ -73,6 +73,34 @@ var joinSpaceScreen = `
</div>
`;
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" 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 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>
<br>
<p><blah>desc.no.invites</blah></p>
</div>
</div>
`;
var notifisScreen = `
<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-notifis-all" class="submit-button blah" 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 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>
</div>
`;
//roombars
var homeRoomBar = `
<div class="sidebar-section-header">
@ -112,7 +140,7 @@ var homeRoomBar = `
var inboxRoomBar = `
<div class="sidebar-section-header">
<button class="collapse-text-button active" id="collapse-invites" onclick="gotoInvites()">
<button class="collapse-text-button" id="collapse-invites" onclick="gotoInvites()">
<svg xmlns="http://www.w3.org/2000/svg" class="chevron" 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>
<span><blah>title.invites</blah></span>
</button>

View file

@ -40,6 +40,7 @@ html {
}
body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
background-color: var(--main-bg-color);
overflow: hidden;
display: flex;
@ -94,6 +95,8 @@ button, input {
input {
padding-left: calc(var(--button-margin) * 2);
-webkit-touch-callout: default;
user-select: text !important;
-webkit-user-select: text !important;
}
@ -542,3 +545,12 @@ space{
pointer-events: auto;
}
}
.collapse-text-button.selected {
background-color: rgba(240, 240, 245, 0.1);
}
.submit-button.tab-inactive {
background-color: transparent;
color: var(--text-color);
}