diff --git a/frontend/pet.html b/frontend/pet.html index 85f3353..7ded3d0 100644 --- a/frontend/pet.html +++ b/frontend/pet.html @@ -315,6 +315,20 @@ /* B3 — Rainbow collar keyframe */ @keyframes rbRot { to { transform:rotate(360deg); } } + /* ── Customize panel (аксессуары / цвет / фон) ── */ + .pet-customize { margin-bottom:18px; } + .pc-tabs { display:flex; gap:6px; margin:4px 0 14px; flex-wrap:wrap; } + .pc-tab { padding:7px 16px; border-radius:99px; border:1.5px solid var(--border-h); background:transparent; + color:var(--text-2); font:700 .78rem 'Manrope',sans-serif; cursor:pointer; transition:all .15s; } + .pc-tab:hover { border-color:var(--violet); color:var(--text); } + .pc-tab.active { background:var(--violet); border-color:var(--violet); color:#fff; } + .pc-hint { font-size:.72rem; color:var(--text-3); margin-bottom:11px; line-height:1.5; } + .pc-panel .pet-color-picker { display:flex; gap:9px; flex-wrap:wrap; } + .pc-panel .pet-color-dot { width:30px; height:30px; } + .pc-bg-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(118px,1fr)); gap:10px; } + .pet-evo-legend { font-size:.6rem; color:var(--text-3); margin-top:7px; line-height:1.45; text-align:center; + cursor:help; max-width:230px; } + @media(max-width:768px) { .pet-hero { grid-template-columns:1fr; } .pet-bottom { grid-template-columns:1fr; } @@ -385,20 +399,9 @@
Эволюция
+
облик растёт с XP — наведи, чтобы узнать, что добавляется на каждом уровне
- -
-
Цвет
-
- -
- -
- + + + +
+
Нажми, чтобы надеть или снять. Заблокированные открываются за достижения. По одному предмету на зону (голова / лицо / шея / уши / акцент).
+
+
+ + + +
@@ -632,6 +657,7 @@ let _petCooldownTimer = null; applyTimeOfDay(); scheduleNextStar(); + setupCustomizeTabs(); loadPet(); })(); @@ -877,6 +903,60 @@ async function selectBg(id, price, owned, card) { } } +/* ── Кастомизация: вкладки ── */ +function setupCustomizeTabs() { + const tabs = document.querySelectorAll('.pc-tab'); + tabs.forEach(t => t.addEventListener('click', () => { + tabs.forEach(x => x.classList.remove('active')); + t.classList.add('active'); + const which = t.dataset.tab; + document.getElementById('pc-acc').style.display = which === 'acc' ? '' : 'none'; + document.getElementById('pc-color').style.display = which === 'color' ? '' : 'none'; + document.getElementById('pc-bg').style.display = which === 'bg' ? '' : 'none'; + if (which === 'bg') renderBgPicker(); + })); +} + +/* ── Фоны (инлайн-выбор во вкладке) ── */ +async function renderBgPicker() { + const grid = document.getElementById('pc-bg-grid'); + if (!grid) return; + const data = await LS.api('/api/pet/shop').catch(() => null); + if (!data) { grid.innerHTML = '
Не удалось загрузить
'; return; } + const coinsEl = document.getElementById('pc-bg-coins'); + if (coinsEl) coinsEl.innerHTML = `Монет: ${data.coins}`; + const items = [{ id: 'default', name: 'Стандарт', price: 0, owned: true }, ...data.items]; + grid.innerHTML = items.map(item => { + const isActive = data.currentBg === item.id; + const isOwned = item.owned || item.price === 0; + const status = isActive ? 'Активен' : isOwned ? 'Выбрать' : item.price + ' монет'; + return `
+
+
${escHtml(item.name)}
+
${status}
+
`; + }).join(''); + grid.querySelectorAll('.pet-bg-card').forEach(c => + c.addEventListener('click', () => selectBgInline(c.dataset.id, +c.dataset.price, c.dataset.owned === '1'))); +} +async function selectBgInline(id, price, owned) { + const endpoint = owned ? '/api/pet/bg' : '/api/pet/shop/buy'; + const res = await LS.api(endpoint, { method: owned ? 'PATCH' : 'POST', body: JSON.stringify({ id }) }).catch(e => { + if (e?.data?.error === 'insufficient_coins') LS.toast?.('Недостаточно монет', 'error'); + return null; + }); + if (!res?.ok) return; + const scene = document.getElementById('pet-scene'); + scene.className = scene.className.replace(/\bbg-\S+/g, '') + (id !== 'default' ? ` bg-${id}` : ''); + if (_petData) _petData.petBg = id; + applyBgFX(id); + if (res.coins !== undefined) { + document.getElementById('stat-coins').textContent = res.coins; + if (_petData) _petData.coins = res.coins; + } + renderBgPicker(); +} + /* ── Eye tracking + A2 Parallax ── */ function onStageMouse(e) { const wrap = document.getElementById('pet-svg-wrap');