UI redesign: CS2 gambling aesthetic, glassmorphism, responsive layout, enhanced sounds, admin panel overhaul

This commit is contained in:
root
2026-07-05 14:22:49 +00:00
parent 01c6573f5f
commit 4b0fc594b4
21 changed files with 2750 additions and 9203 deletions
+125 -148
View File
@@ -1,155 +1,132 @@
// ─── Shared CS2 Simulator Utilities ─────────────────────────────────────────
// Logout
async function logout() {
try {
await fetch('/web/api/auth/logout', { method: 'POST' });
} catch (e) {}
window.location.href = '/';
try { await fetch('/web/api/auth/logout', { method: 'POST' }); } catch (e) {}
window.location.href = '/';
}
// Refresh balance display
async function refreshBalance() {
try {
const res = await fetch('/web/api/user/balance');
const data = await res.json();
if (data.success) {
document.querySelectorAll('.user-balance').forEach(el => {
el.textContent = `${Math.floor(data.balance)}`;
});
}
} catch (e) {}
}
// Rarity colors
function getRarityColor(rarity) {
const colors = {
'Consumer Grade': '#b0b0b0',
'Industrial Grade': '#5e98d9',
'Mil-Spec': '#4b69ff',
'Mil-Spec Grade': '#4b69ff',
'Restricted': '#8847ff',
'Classified': '#d32ce6',
'Covert': '#eb4b4b',
'Rare Special Item': '#ffd700',
'Extraordinary': '#ffd700',
};
return colors[rarity] || '#b0b0b0';
}
// Format number with spaces
function formatNumber(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
// Debounce
function debounce(fn, ms = 300) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), ms);
};
}
// Escape HTML
function escapeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
// Show notification
function showNotification(message, type = 'info', duration = 3000) {
const existing = document.querySelector('.notification-toast');
if (existing) existing.remove();
const colors = {
success: '#22c55e',
error: '#ef4444',
info: '#3b82f6',
warning: '#f59e0b',
};
const toast = document.createElement('div');
toast.className = 'notification-toast';
toast.style.cssText = `
position: fixed; top: 20px; right: 20px; z-index: 99999;
background: #1a1a2e; border: 1px solid ${colors[type] || colors.info};
color: white; padding: 12px 20px; border-radius: 8px;
font-size: 14px; box-shadow: 0 10px 40px rgba(0,0,0,0.5);
animation: slideInRight 0.3s ease; max-width: 400px;
`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.animation = 'slideOutRight 0.3s ease forwards';
setTimeout(() => toast.remove(), 300);
}, duration);
}
// Inject notification styles once
if (!document.getElementById('notificationStyles')) {
const style = document.createElement('style');
style.id = 'notificationStyles';
style.textContent = `
@keyframes slideInRight {
from { transform: translateX(120%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideOutRight {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(120%); opacity: 0; }
}
`;
document.head.appendChild(style);
}
// Show achievement popup (global function used by templates)
function showAchievementPopup(title, reward) {
let popup = document.getElementById('achievementGlobalPopup');
if (!popup) {
popup = document.createElement('div');
popup.id = 'achievementGlobalPopup';
popup.style.cssText = `
position: fixed; top: 20px; left: 50%; transform: translateX(-50%);
z-index: 99999; background: linear-gradient(135deg, #1a3a1a, #0d260d);
border: 1px solid #22c55e; border-radius: 12px; padding: 1rem 1.5rem;
box-shadow: 0 10px 40px rgba(0,0,0,0.5);
animation: slideInDown 0.5s ease; max-width: 400px; width: 90%;
text-align: center;
`;
popup.innerHTML = `
<div style="font-size:0.85rem;color:#94a3b8;margin-bottom:0.25rem;">🏆 Новое достижение!</div>
<div style="font-size:1.1rem;font-weight:600;" id="globalPopupTitle"></div>
<div style="color:#22c55e;font-size:0.9rem;margin-top:0.25rem;" id="globalPopupReward"></div>
`;
document.body.appendChild(popup);
if (!document.getElementById('slideInDownStyle')) {
const s = document.createElement('style');
s.id = 'slideInDownStyle';
s.textContent = `
@keyframes slideInDown {
from { transform: translateX(-50%) translateY(-120%); opacity: 0; }
to { transform: translateX(-50%) translateY(0); opacity: 1; }
}
`;
document.head.appendChild(s);
try {
const res = await fetch('/web/api/user/balance');
const data = await res.json();
if (data.success) {
document.querySelectorAll('.user-balance').forEach(el => {
const old = el.textContent;
const val = `${Math.floor(data.balance)}`;
if (old !== val) {
el.textContent = val;
el.classList.remove('animate-scaleIn');
void el.offsetWidth;
el.classList.add('animate-scaleIn');
}
});
}
document.getElementById('globalPopupTitle').textContent = title;
document.getElementById('globalPopupReward').textContent = reward ? `+${reward}` : '';
popup.style.display = 'block';
if (window.SoundManager) SoundManager.achievement();
setTimeout(() => {
popup.style.animation = 'slideInDown 0.5s ease reverse forwards';
setTimeout(() => {
popup.style.display = 'none';
popup.style.animation = 'slideInDown 0.5s ease';
}, 500);
}, 4000);
} catch (e) {}
}
function getRarityColor(rarity) {
const colors = {
'Consumer Grade': '#b0b0b0',
'Industrial Grade': '#5e98d9',
'Mil-Spec': '#4b69ff',
'Mil-Spec Grade': '#4b69ff',
'Restricted': '#8847ff',
'Classified': '#d32ce6',
'Covert': '#eb4b4b',
'Rare Special Item': '#ffd700',
'Extraordinary': '#ffd700',
};
return colors[rarity] || '#b0b0b0';
}
function formatNumber(n) {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
function debounce(fn, ms = 300) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), ms);
};
}
function escapeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
function showNotification(message, type = 'info', duration = 3000) {
let container = document.getElementById('toastContainer');
if (!container) {
container = document.createElement('div');
container.id = 'toastContainer';
container.className = 'toast-container';
document.body.appendChild(container);
}
const icons = { success: '✓', error: '✗', info: '', warning: '⚠' };
const toast = document.createElement('div');
toast.className = `toast toast-${type} animate-slideUp`;
toast.innerHTML = `<span>${icons[type] || ''}</span><span>${message}</span>`;
container.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transform = 'translateX(100%)';
toast.style.transition = 'all 0.3s ease';
setTimeout(() => toast.remove(), 300);
}, duration);
}
function showAchievementPopup(title, reward) {
let popup = document.getElementById('achievementGlobalPopup');
if (!popup) {
popup = document.createElement('div');
popup.id = 'achievementGlobalPopup';
popup.className = 'modal-overlay';
popup.style.background = 'rgba(0,0,0,0.5)';
popup.style.alignItems = 'flex-start';
popup.style.paddingTop = '60px';
popup.innerHTML = `
<div style="background:linear-gradient(135deg,#1a3a1a,#0d260d);border:1px solid #22c55e;border-radius:14px;padding:1.25rem 1.75rem;max-width:400px;width:90%;text-align:center;animation:modalSlideIn 0.3s ease;box-shadow:0 16px 48px rgba(0,0,0,0.6);">
<div style="font-size:0.8rem;color:var(--text-dim,#94a3b8);margin-bottom:0.25rem;text-transform:uppercase;letter-spacing:0.05em;">🏆 Достижение разблокировано!</div>
<div style="font-size:1.2rem;font-weight:600;font-family:var(--font-display,'Russo One',sans-serif);" id="globalPopupTitle"></div>
<div style="color:#22c55e;font-size:0.95rem;margin-top:0.35rem;font-weight:600;" id="globalPopupReward"></div>
</div>
`;
document.body.appendChild(popup);
}
document.getElementById('globalPopupTitle').textContent = title;
document.getElementById('globalPopupReward').textContent = reward ? `+${reward}` : '';
popup.style.display = 'flex';
if (window.SoundManager) SoundManager.achievement();
setTimeout(() => {
popup.style.display = 'none';
}, 4000);
}
document.addEventListener('DOMContentLoaded', () => {
const toggle = document.getElementById('mobileToggle');
const nav = document.getElementById('navLinks');
if (toggle && nav) {
toggle.addEventListener('click', () => {
nav.classList.toggle('open');
});
document.addEventListener('click', (e) => {
if (!toggle.contains(e.target) && !nav.contains(e.target)) {
nav.classList.remove('open');
}
});
}
const soundToggle = document.getElementById('soundToggle');
if (soundToggle && window.SoundManager) {
soundToggle.addEventListener('click', () => {
const enabled = SoundManager.toggle();
soundToggle.textContent = enabled ? '🔊' : '🔇';
});
}
});