Skip to content

Commit 397283b

Browse files
committed
add: new Status Animations
1 parent 05fb28d commit 397283b

File tree

4 files changed

+73
-21
lines changed

4 files changed

+73
-21
lines changed

src/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ <h3 id="account-name" class="cutoff chat-contact-with-status btn"></h3>
245245
<div id="chat-header-avatar-container"></div>
246246
<h3 id="chat-contact" class="cutoff chat-contact-with-status btn"></h3>
247247
</div>
248-
<span class="cutoff chat-contact-status btn" id="chat-contact-status"></span>
248+
<span class="cutoff chat-contact-status status-hidden btn" id="chat-contact-status"></span>
249249
</div>
250250
</div>
251251
<div id="msg-top-fade" class="fadeout-top-msgs" style="top: 60px;"></div>

src/main.js

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,18 +1031,30 @@ async function fetchProfiles() {
10311031
await invoke("sync_all_profiles");
10321032
}
10331033

1034+
// Track pending status hide timeout
1035+
let statusHideTimeout = null;
1036+
10341037
/**
10351038
* Update the chat header subtext (status/typing indicator) for the currently open chat
10361039
* @param {Object} chat - The chat object
10371040
*/
10381041
function updateChatHeaderSubtext(chat) {
10391042
if (!chat) return;
10401043

1044+
// Clear any pending hide timeout
1045+
if (statusHideTimeout) {
1046+
clearTimeout(statusHideTimeout);
1047+
statusHideTimeout = null;
1048+
}
1049+
1050+
let newStatusText = '';
1051+
let shouldAddGradient = false;
1052+
10411053
const isGroup = chat.chat_type === 'MlsGroup';
10421054
const fNotes = chat.id === strPubkey;
10431055
if (fNotes) {
1044-
domChatContactStatus.textContent = 'Encrypted Notes to Self';
1045-
domChatContactStatus.classList.remove('text-gradient');
1056+
newStatusText = 'Encrypted Notes to Self';
1057+
shouldAddGradient = false;
10461058
} else if (isGroup) {
10471059
// Check for typing indicators in groups
10481060
const activeTypers = chat.active_typers || [];
@@ -1053,36 +1065,36 @@ function updateChatHeaderSubtext(chat) {
10531065
if (activeTypers.length === 1) {
10541066
const typer = getProfile(activeTypers[0]);
10551067
const name = typer?.nickname || typer?.name || 'Someone';
1056-
domChatContactStatus.textContent = `${name} is typing...`;
1068+
newStatusText = `${name} is typing...`;
10571069
} else if (activeTypers.length === 2) {
10581070
const typer1 = getProfile(activeTypers[0]);
10591071
const typer2 = getProfile(activeTypers[1]);
10601072
const name1 = typer1?.nickname || typer1?.name || 'Someone';
10611073
const name2 = typer2?.nickname || typer2?.name || 'Someone';
1062-
domChatContactStatus.textContent = `${name1} and ${name2} are typing...`;
1074+
newStatusText = `${name1} and ${name2} are typing...`;
10631075
} else if (activeTypers.length === 3) {
10641076
const typer1 = getProfile(activeTypers[0]);
10651077
const typer2 = getProfile(activeTypers[1]);
10661078
const typer3 = getProfile(activeTypers[2]);
10671079
const name1 = typer1?.nickname || typer1?.name || 'Someone';
10681080
const name2 = typer2?.nickname || typer2?.name || 'Someone';
10691081
const name3 = typer3?.nickname || typer3?.name || 'Someone';
1070-
domChatContactStatus.textContent = `${name1}, ${name2}, and ${name3} are typing...`;
1082+
newStatusText = `${name1}, ${name2}, and ${name3} are typing...`;
10711083
} else {
10721084
// 4+ people typing
1073-
domChatContactStatus.textContent = `Several people are typing...`;
1085+
newStatusText = `Several people are typing...`;
10741086
}
1075-
domChatContactStatus.classList.add('text-gradient');
1087+
shouldAddGradient = true;
10761088
} else {
10771089
const memberCount = chat.metadata?.custom_fields?.member_count ? parseInt(chat.metadata.custom_fields.member_count) : null;
10781090
if (typeof memberCount === 'number') {
10791091
const label = memberCount === 1 ? 'member' : 'members';
1080-
domChatContactStatus.textContent = `${memberCount} ${label}`;
1092+
newStatusText = `${memberCount} ${label}`;
10811093
} else {
10821094
// Avoid misleading "0 members" before first count refresh
1083-
domChatContactStatus.textContent = 'Members syncing...';
1095+
newStatusText = 'Members syncing...';
10841096
}
1085-
domChatContactStatus.classList.remove('text-gradient');
1097+
shouldAddGradient = false;
10861098
}
10871099
} else {
10881100
// Check for typing indicators in DMs (using chat.active_typers)
@@ -1093,20 +1105,42 @@ function updateChatHeaderSubtext(chat) {
10931105
// For DMs, there should only be one typer (the other person)
10941106
const typer = getProfile(activeTypers[0]);
10951107
const name = typer?.nickname || typer?.name || 'User';
1096-
domChatContactStatus.textContent = `${name} is typing...`;
1097-
domChatContactStatus.classList.add('text-gradient');
1108+
newStatusText = `${name} is typing...`;
1109+
shouldAddGradient = true;
10981110
} else {
10991111
const profile = getProfile(chat.id);
1100-
domChatContactStatus.textContent = profile?.status?.title || '';
1101-
domChatContactStatus.classList.remove('text-gradient');
1102-
twemojify(domChatContactStatus);
1112+
newStatusText = profile?.status?.title || '';
1113+
shouldAddGradient = false;
11031114
}
11041115
}
11051116

1106-
// Update visibility based on whether there's content to show
1107-
domChatContactStatus.style.display = !domChatContactStatus.textContent ? 'none' : '';
1108-
domChatContact.classList.toggle('chat-contact', !domChatContactStatus.textContent);
1109-
domChatContact.classList.toggle('chat-contact-with-status', !!domChatContactStatus.textContent);
1117+
const currentHasStatus = !!domChatContactStatus.textContent && !domChatContactStatus.classList.contains('status-hidden');
1118+
const newHasStatus = !!newStatusText;
1119+
1120+
if (newHasStatus) {
1121+
// Show status: remove hidden class, update content
1122+
domChatContactStatus.classList.remove('status-hidden');
1123+
domChatContactStatus.textContent = newStatusText;
1124+
domChatContactStatus.classList.toggle('text-gradient', shouldAddGradient);
1125+
if (!shouldAddGradient) {
1126+
twemojify(domChatContactStatus);
1127+
}
1128+
domChatContact.classList.remove('chat-contact');
1129+
domChatContact.classList.add('chat-contact-with-status');
1130+
} else if (currentHasStatus) {
1131+
// Hide status: add hidden class, wait for animation, then clear content
1132+
domChatContactStatus.classList.add('status-hidden');
1133+
domChatContact.classList.remove('chat-contact-with-status');
1134+
domChatContact.classList.add('chat-contact');
1135+
1136+
// Clear content after animation completes (300ms matches CSS transition)
1137+
statusHideTimeout = setTimeout(() => {
1138+
domChatContactStatus.textContent = '';
1139+
domChatContactStatus.classList.remove('text-gradient');
1140+
statusHideTimeout = null;
1141+
}, 300);
1142+
}
1143+
// If both are false (no status before, no status now), do nothing
11101144
}
11111145

11121146
// Store a hash of the last rendered state to detect actual changes
@@ -4575,6 +4609,13 @@ async function closeChat() {
45754609
previousChatBeforeProfile = ""; // Clear when closing chat
45764610
nLastTypingIndicator = 0;
45774611

4612+
// Clear the chat header to prevent flicker when opening next chat
4613+
domChatContact.textContent = '';
4614+
domChatContactStatus.textContent = '';
4615+
domChatContactStatus.classList.add('status-hidden');
4616+
domChatContactStatus.classList.remove('text-gradient');
4617+
domChatHeaderAvatarContainer.innerHTML = '';
4618+
45784619
// Reset procedural scroll state
45794620
resetProceduralScroll();
45804621

src/styles.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,7 @@ html, body {
10411041
margin-bottom: 0;
10421042
margin-left: auto;
10431043
margin-right: auto;
1044+
transition: margin-top 0.3s cubic-bezier(0.34, 1, 0.64, 1), margin-bottom 0.3s cubic-bezier(0.34, 1, 0.64, 1);
10441045
}
10451046

10461047
.chat-contact {
@@ -1051,6 +1052,7 @@ html, body {
10511052
margin-bottom: 12px;
10521053
margin-left: auto;
10531054
margin-right: auto;
1055+
transition: margin-top 0.3s cubic-bezier(0.34, 1, 0.64, 1), margin-bottom 0.3s cubic-bezier(0.34, 1, 0.64, 1);
10541056
}
10551057

10561058
.chat h3 img {
@@ -1071,6 +1073,15 @@ html, body {
10711073
margin-left: auto;
10721074
margin-right: auto;
10731075
margin-top: -1px;
1076+
transition: opacity 0.25s cubic-bezier(0.22, 1, 0.36, 1), max-height 0.3s cubic-bezier(0.34, 1, 0.64, 1), margin-bottom 0.3s cubic-bezier(0.34, 1, 0.64, 1);
1077+
max-height: 30px;
1078+
overflow: hidden;
1079+
}
1080+
1081+
.chat-contact-status.status-hidden {
1082+
opacity: 0;
1083+
max-height: 0;
1084+
margin-bottom: 0;
10741085
}
10751086

10761087
.chat-contact-status .emoji {

src/themes/vector/dark.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
}
1818

1919
.text-gradient {
20-
background: linear-gradient(to right, #ffffff 13.87%, #59fcb3 60%);
20+
background: linear-gradient(to right, #ffffff 13.87%, #808080 60%);
2121
background-size: 200% 200%;
2222
background-clip: text;
2323
}

0 commit comments

Comments
 (0)