Added new sound effect for role mention in server
also added a cool little pop up for visual aid.
This commit is contained in:
parent
49d512b2b5
commit
e046b424ac
|
|
@ -1,3 +1,5 @@
|
|||
import { toastScript } from "./toasts";
|
||||
|
||||
export function injectSounds(webContents: Electron.WebContents) {
|
||||
webContents.on("did-finish-load", () => {
|
||||
webContents.executeJavaScript(`
|
||||
|
|
@ -5,9 +7,13 @@ export function injectSounds(webContents: Electron.WebContents) {
|
|||
if (window.__soundsInjected) return;
|
||||
window.__soundsInjected = true;
|
||||
|
||||
${toastScript}
|
||||
|
||||
let ctx = null;
|
||||
let currentUserId = null;
|
||||
let currentChannelId = null;
|
||||
const roleNameCache = {};
|
||||
const userNameCache = {};
|
||||
|
||||
function getAudioContext() {
|
||||
if (!ctx) ctx = new AudioContext();
|
||||
|
|
@ -41,13 +47,11 @@ export function injectSounds(webContents: Electron.WebContents) {
|
|||
}
|
||||
|
||||
function playUserJoinSound() {
|
||||
playTone(880, 0.15);
|
||||
setTimeout(() => playTone(1100, 0.2), 150);
|
||||
playTone(880, 0.15, 0.05);
|
||||
}
|
||||
|
||||
function playUserLeaveSound() {
|
||||
playTone(440, 0.15);
|
||||
setTimeout(() => playTone(220, 0.3), 150);
|
||||
playTone(440, 0.15, 0.05);
|
||||
}
|
||||
|
||||
function playMentionSound() {
|
||||
|
|
@ -65,9 +69,27 @@ export function injectSounds(webContents: Electron.WebContents) {
|
|||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if (data.type === "Ready" && data.users) {
|
||||
const self = data.users.find(u => u.relationship === "User");
|
||||
if (self) currentUserId = self._id;
|
||||
if (data.type === "Ready") {
|
||||
if (data.users) {
|
||||
const self = data.users.find(u => u.relationship === "User");
|
||||
if (self) currentUserId = self._id;
|
||||
for (const user of data.users) {
|
||||
if (user._id && user.username) userNameCache[user._id] = user.username;
|
||||
}
|
||||
}
|
||||
if (data.servers) {
|
||||
for (const server of data.servers) {
|
||||
if (server.roles) {
|
||||
for (const role of Object.values(server.roles)) {
|
||||
roleNameCache[role._id] = role.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.type === "UserUpdate" && data.id && data.data?.username) {
|
||||
userNameCache[data.id] = data.data.username;
|
||||
}
|
||||
|
||||
if (data.type === "VoiceChannelJoin" && data.state?.id === currentUserId) {
|
||||
|
|
@ -89,8 +111,14 @@ export function injectSounds(webContents: Electron.WebContents) {
|
|||
}
|
||||
|
||||
if (data.type === "Message" && data.role_mentions?.length > 0 && data.member?.roles?.length > 0) {
|
||||
const mentioned = data.role_mentions.some(roleId => data.member.roles.includes(roleId));
|
||||
if (mentioned) playMentionSound();
|
||||
const matchedRoleId = data.role_mentions.find(roleId => data.member.roles.includes(roleId));
|
||||
if (matchedRoleId) {
|
||||
playMentionSound();
|
||||
const senderName = userNameCache[data.author] || data.author || "Someone";
|
||||
const roleName = roleNameCache[matchedRoleId] || matchedRoleId;
|
||||
const content = data.content?.replace(/<%[^>]+>/g, '@' + roleName).trim() || "New message";
|
||||
__showMentionToast(senderName, roleName, content);
|
||||
}
|
||||
}
|
||||
|
||||
} catch {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
export const toastStyles = `
|
||||
#__stoat-toast-container {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.stoat-toast {
|
||||
background: #1e1e2e;
|
||||
border: 1px solid #3a3a55;
|
||||
border-left: 4px solid #7c6af7;
|
||||
border-radius: 8px;
|
||||
padding: 12px 16px;
|
||||
min-width: 280px;
|
||||
max-width: 340px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.5);
|
||||
pointer-events: all;
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
.stoat-toast.visible {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
.stoat-toast.hiding {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
.stoat-toast-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.stoat-toast-icon { font-size: 14px; }
|
||||
.stoat-toast-sender {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #c9c9e0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.stoat-toast-role {
|
||||
font-size: 11px;
|
||||
background: #7c6af720;
|
||||
color: #a89cf7;
|
||||
border: 1px solid #7c6af740;
|
||||
border-radius: 4px;
|
||||
padding: 1px 6px;
|
||||
font-family: sans-serif;
|
||||
margin-left: auto;
|
||||
}
|
||||
.stoat-toast-content {
|
||||
font-size: 12px;
|
||||
color: #8888aa;
|
||||
font-family: sans-serif;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 300px;
|
||||
}
|
||||
.stoat-toast-progress {
|
||||
height: 2px;
|
||||
background: #7c6af7;
|
||||
border-radius: 2px;
|
||||
margin-top: 10px;
|
||||
animation: stoat-progress 5s linear forwards;
|
||||
}
|
||||
@keyframes stoat-progress {
|
||||
from { width: 100%; }
|
||||
to { width: 0%; }
|
||||
}
|
||||
`;
|
||||
|
||||
export const toastScript = `
|
||||
function __initToasts() {
|
||||
if (!document.getElementById('__stoat-toast-styles')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = '__stoat-toast-styles';
|
||||
style.textContent = ${JSON.stringify(toastStyles)};
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}
|
||||
|
||||
function __getToastContainer() {
|
||||
let container = document.getElementById('__stoat-toast-container');
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.id = '__stoat-toast-container';
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
function __dismissToast(toast) {
|
||||
toast.classList.remove('visible');
|
||||
toast.classList.add('hiding');
|
||||
setTimeout(() => toast.remove(), 250);
|
||||
}
|
||||
|
||||
function __showMentionToast(senderName, roleName, content) {
|
||||
__initToasts();
|
||||
const container = __getToastContainer();
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'stoat-toast';
|
||||
toast.innerHTML =
|
||||
'<div class="stoat-toast-header">' +
|
||||
'<span class="stoat-toast-icon">🔔</span>' +
|
||||
'<span class="stoat-toast-sender">' + senderName + '</span>' +
|
||||
'<span class="stoat-toast-role">@' + roleName + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="stoat-toast-content">' + content + '</div>' +
|
||||
'<div class="stoat-toast-progress"></div>';
|
||||
toast.addEventListener('click', () => __dismissToast(toast));
|
||||
container.appendChild(toast);
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => toast.classList.add('visible'));
|
||||
});
|
||||
setTimeout(() => __dismissToast(toast), 5000);
|
||||
}
|
||||
`;
|
||||
Loading…
Reference in New Issue