RPU v2, promo/bank система, админка, оптимизации
— RPU v2: бюджет удачи, потолок (ceiling), комбек после проигрышей, hot/cold анализ, интеграция с promo-фазами — Bank API: mock-банк для карты (депозит/вывод с балансом 1000₽) — Promo-сервис: автогенерация промокодов каждый час, типы (card_to_site, luck_boost, ceiling_boost, free_case, reset_streak) — Promo-фазы: LUCKY/NEUTRAL/UNLUCKY, переключение каждые 1-6ч — Admin: история транзакций (user_history), управление промокодами, управление promo-фазами, API фильтров/коллекций, RPU info — Database: WAL mode, новые поля RPU v2, TransactionLog, карточный баланс, статистики (streaks, ceiling, budget) — Frontend: /deposit, /promo/activate, /withdraw, /card-balance, /online-count, /rpu-info, lifespan вместо startup event — UI: user_history.html, улучшения профиля, кейсов, навигации — Cases: обновление cases.json (1892 строки новых данных) — Achievements: кэш коллекций, оптимизация is_custom проверок — Sounds: дополнительные звуковые эффекты — Upgrade: интеграция с RPU (множители, streaks) — .gitignore: исключены .db, .bak, __pycache__
This commit is contained in:
@@ -140,6 +140,56 @@
|
||||
from { opacity: 0; transform: translateY(-5px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* Иммерсивные эффекты для ленты */
|
||||
.asi-effect {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.asi-effect::before {
|
||||
content: attr(data-effect-text);
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 2.5rem;
|
||||
font-weight: 900;
|
||||
color: currentColor;
|
||||
opacity: 0.06;
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
line-height: 1;
|
||||
}
|
||||
.asi-effect-glow {
|
||||
box-shadow: 0 0 15px 2px rgba(255, 200, 50, 0.15), inset 0 0 20px rgba(255, 200, 50, 0.05);
|
||||
animation: glowPulse 2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes glowPulse {
|
||||
0%,100% { box-shadow: 0 0 15px 2px rgba(255,200,50,0.15), inset 0 0 20px rgba(255,200,50,0.05); }
|
||||
50% { box-shadow: 0 0 25px 5px rgba(255,200,50,0.25), inset 0 0 30px rgba(255,200,50,0.08); }
|
||||
}
|
||||
.asi-effect-shimmer {
|
||||
position: absolute;
|
||||
top: 0; left: -100%;
|
||||
width: 100%; height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.07), transparent);
|
||||
animation: shimmer 3s ease-in-out infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
@keyframes shimmer {
|
||||
0% { left: -100%; }
|
||||
50% { left: 200%; }
|
||||
100% { left: -100%; }
|
||||
}
|
||||
.asi-effect-badge {
|
||||
display: inline-block;
|
||||
font-size: 0.6rem;
|
||||
font-weight: 700;
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
.asi-effect-badge.upgrade { background: rgba(139,92,246,0.25); color: #a78bfa; }
|
||||
.asi-effect-badge.drop { background: rgba(251,191,36,0.25); color: #fbbf24; }
|
||||
.has-activity-sidebar {
|
||||
padding-left: 260px;
|
||||
transition: padding-left 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
|
||||
@@ -157,9 +207,6 @@
|
||||
<div class="activity-sidebar" id="activitySidebar">
|
||||
<div class="activity-sidebar-header">
|
||||
<h3><span class="live-dot"></span> Лента</h3>
|
||||
<span style="font-size:0.7rem;color:var(--text-secondary);display:flex;align-items:center;gap:0.25rem;">
|
||||
<span id="onlineCount">0</span> 👤
|
||||
</span>
|
||||
<button class="activity-sidebar-close" onclick="toggleActivitySidebar()" title="Скрыть">✕</button>
|
||||
</div>
|
||||
<div class="activity-sidebar-list" id="activitySidebarList">
|
||||
@@ -198,11 +245,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
WS.on('online_count', (data) => {
|
||||
const el = document.getElementById('onlineCount');
|
||||
if (el) el.textContent = data.online || 0;
|
||||
});
|
||||
|
||||
WS.on('activity', (data) => {
|
||||
const act = data.activity;
|
||||
if (!act || !list) return;
|
||||
@@ -241,8 +283,32 @@ function createActivityItem(act) {
|
||||
|
||||
const raritySlug = (act.data && act.data.rarity || '').toLowerCase().replace(/ /g, '-').replace(/_/g, '-').replace(/™/g, '');
|
||||
const rarityColor = ACTIVITY_RARITY_COLORS[raritySlug] || '';
|
||||
if (rarityColor) {
|
||||
item.style.background = `rgba(${hexToRgb(rarityColor)}, 0.08)`;
|
||||
|
||||
// ── Эффект ──
|
||||
const effect = act.data && act.data.effect;
|
||||
let effectBadgeHtml = '';
|
||||
if (effect) {
|
||||
const isUpgrade = effect.startsWith('upgrade:');
|
||||
const isDrop = effect.startsWith('drop:');
|
||||
const label = effect.replace('upgrade:', '').replace('drop:', '');
|
||||
const cls = isUpgrade ? 'upgrade' : 'drop';
|
||||
effectBadgeHtml = `<span class="asi-effect-badge ${cls}">${label}</span>`;
|
||||
item.classList.add('asi-effect');
|
||||
item.dataset.effectText = label;
|
||||
if (isDrop) {
|
||||
item.classList.add('asi-effect-glow');
|
||||
const sh = document.createElement('div');
|
||||
sh.className = 'asi-effect-shimmer';
|
||||
item.appendChild(sh);
|
||||
}
|
||||
if (rarityColor) {
|
||||
item.style.background = `rgba(${hexToRgb(rarityColor)}, 0.12)`;
|
||||
item.style.borderLeft = `3px solid ${rarityColor}`;
|
||||
}
|
||||
} else {
|
||||
if (rarityColor) {
|
||||
item.style.background = `rgba(${hexToRgb(rarityColor)}, 0.08)`;
|
||||
}
|
||||
}
|
||||
|
||||
item.addEventListener('click', () => window.location.href = `/profiles/${act.user_id}`);
|
||||
@@ -260,6 +326,7 @@ function createActivityItem(act) {
|
||||
<span class="asi-username">${escapeHtml(act.username)}</span>
|
||||
<span>${escapeHtml(act.message)}</span>
|
||||
<div class="asi-time">${timeStr}</div>
|
||||
${effectBadgeHtml}
|
||||
</div>
|
||||
${imgHtml}
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user