Add VIP presence themes and custom greetings

This commit is contained in:
2026-04-11 15:44:30 +08:00
parent 9fb7710079
commit 4eba9dfc12
21 changed files with 1126 additions and 49 deletions
@@ -68,6 +68,89 @@
let autoScroll = true;
let _maxMsgId = 0; // 记录当前收到的最大消息 ID
/**
* 转义会员横幅文本,避免横幅层被注入 HTML。
*/
function escapePresenceText(text) {
return escapeHtml(String(text ?? '')).replace(/\n/g, '<br>');
}
/**
* 根据不同的会员横幅风格返回渐变与光影配置。
*/
function getVipPresenceStyleConfig(style, color) {
const fallback = color || '#f59e0b';
const map = {
aurora: {
gradient: `linear-gradient(135deg, ${fallback}, #fde68a, #fff7ed)`,
glow: `${fallback}66`,
accent: '#fff7ed',
},
storm: {
gradient: `linear-gradient(135deg, #1e3a8a, ${fallback}, #dbeafe)`,
glow: '#60a5fa88',
accent: '#dbeafe',
},
royal: {
gradient: `linear-gradient(135deg, #111827, ${fallback}, #fbbf24)`,
glow: '#fbbf2488',
accent: '#fef3c7',
},
cosmic: {
gradient: `linear-gradient(135deg, #312e81, ${fallback}, #ec4899)`,
glow: '#c084fc99',
accent: '#f5d0fe',
},
farewell: {
gradient: `linear-gradient(135deg, #334155, ${fallback}, #94a3b8)`,
glow: '#cbd5e188',
accent: '#f8fafc',
},
};
return map[style] || map.aurora;
}
/**
* 显示会员进退场豪华横幅。
*/
function showVipPresenceBanner(payload) {
if (!payload || !payload.presence_text) {
return;
}
const existing = document.getElementById('vip-presence-banner');
if (existing) {
existing.remove();
}
const styleConfig = getVipPresenceStyleConfig(payload.presence_banner_style, payload.presence_color);
const banner = document.createElement('div');
banner.id = 'vip-presence-banner';
banner.className = 'vip-presence-banner';
banner.innerHTML = `
<div class="vip-presence-banner__glow" style="background:${styleConfig.glow};"></div>
<div class="vip-presence-banner__card" style="background:${styleConfig.gradient}; border-color:${payload.presence_color || '#fff'};">
<div class="vip-presence-banner__meta">
<span class="vip-presence-banner__icon">${escapeHtml(payload.presence_icon || '👑')}</span>
<span class="vip-presence-banner__level">${escapeHtml(payload.presence_level_name || '尊贵会员')}</span>
<span class="vip-presence-banner__type">${payload.presence_type === 'leave' ? '离场提示' : '闪耀登场'}</span>
</div>
<div class="vip-presence-banner__text" style="color:${styleConfig.accent};">${escapePresenceText(payload.presence_text)}</div>
</div>
`;
document.body.appendChild(banner);
setTimeout(() => {
banner.classList.add('is-leaving');
setTimeout(() => banner.remove(), 700);
}, 4200);
}
window.showVipPresenceBanner = showVipPresenceBanner;
// ── Tab 切换 ──────────────────────────────────────
let _roomsRefreshTimer = null;
@@ -539,6 +622,31 @@
html = `${iconImg} ${parsedContent}`;
}
// 会员专属进退场播报:更醒目的卡片化样式,同时由外层额外触发豪华横幅。
else if (msg.action === 'vip_presence') {
div.style.cssText =
'background:linear-gradient(135deg, rgba(15,23,42,.96), rgba(30,41,59,.9)); border:1px solid rgba(255,255,255,.14); border-radius:12px; padding:10px 12px; margin:6px 0; box-shadow:0 10px 26px rgba(15,23,42,.22);';
const icon = escapeHtml(msg.presence_icon || '👑');
const levelName = escapeHtml(msg.presence_level_name || '尊贵会员');
const typeLabel = msg.presence_type === 'leave' ? '华丽离场' : '荣耀入场';
const accent = msg.presence_color || '#f59e0b';
const safeText = escapePresenceText(msg.presence_text || '');
html = `
<div style="display:flex;align-items:center;gap:10px;">
<div style="width:42px;height:42px;border-radius:14px;background:radial-gradient(circle at top, ${accent}, #111827);display:flex;align-items:center;justify-content:center;font-size:22px;box-shadow:0 0 22px ${accent}55;">${icon}</div>
<div style="min-width:0;flex:1;">
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
<span style="font-size:12px;font-weight:800;letter-spacing:.08em;color:${accent};text-transform:uppercase;">${typeLabel}</span>
<span style="font-size:12px;color:#e2e8f0;">${levelName}</span>
<span style="font-size:11px;color:#94a3b8;">(${timeStr})</span>
</div>
<div style="margin-top:4px;font-size:14px;line-height:1.6;color:#f8fafc;">${safeText}</div>
</div>
</div>
`;
timeStrOverride = true;
}
// 贾妖语 —— 蓝色左边框渐变样式,比 系统公告 低调
else if (msg.action === '欢迎') {
div.style.cssText =
@@ -759,6 +867,11 @@
return;
}
appendMessage(msg);
if (msg.action === 'vip_presence') {
showVipPresenceBanner(msg);
}
// 若消息携带 toast_notification 字段且当前用户是接收者,弹右下角小卡片
if (msg.toast_notification && msg.to_user === window.chatContext.username) {
const t = msg.toast_notification;