Список пользователей

1
Админ
Постов: 162
2
Элита
Постов: 45
3
VIP
Постов: 35
4
Проверенные
Постов: 31
5
Проверенные
Постов: 30
6
Пользователи
Постов: 27
7
VIP
Постов: 26
8
Пользователи
Постов: 24

  • Страница 1 из 1
  • 1
Финальная версия модуль Подарков ВК для Ucoz версия 4.0
Дата: Среда, 07.01.2026, 11:10 | Сообщение # 1 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:162
         Регистрация:20.10.2016

Да, это финальная версия модуля - скрипта, который выводит подарки на главную страницу.

Хочу объяснить, почему я называю его последним.

Разместить кнопки редактирования или удалить невозможно для обычных пользователей: эта функция предусмотрена только для администрации, поэтому смысла в ней нет. Я создал версию скрипта с такой возможностью, но я решил её убрать, чтобы модуль стал легче и быстрее.

Вывод подарков в стиле «ВКонтакте» тоже не полностью реализован: я пытался привязать последовательно к дате, чтобы отображались только последние подарки, но скрипт постоянно путался и показывал либо чужие аватарки, либо сами подарки некорректно. Я потратил на это много времени, но сделать продвинутый вариант так и не получилось.

Поэтому, скорее всего, этот модуль будет последним: он уже успел «подпортить мне нервы неслабо».

Передаю эстафету: пробуйте, меняйте дизайн, меняйте логику, добавляйте новые функции, прокачивайте.

Если что-то непонятно - смотрите исходный код:



Код
<!-- ======= Блок подарков ======= -->
<div class="gifts-block">
<div class="gifts-header">Подарки</div>
<div class="gifts-footer" id="gifts-count">Загрузка…</div>
<div class="gifts-container" id="gifts-container"></div>
</div>

<style>
.gifts-block {
background: #fff;
border: 1px solid #d1d5da;
font-family: Tahoma, Arial, sans-serif;
font-size: 13px;
color: #000;
max-width: 600px;
}

.gifts-header {
background: #f0f2f5;
padding: 6px 8px;
border-bottom: 1px solid #d1d5da;
color: #45688e;
font-weight: bold;
}

.gifts-footer {
background: #f7f7f7;
border-top: 1px solid #d1d5da;
padding: 5px 8px;
color: #666;
}

.gifts-container {
display: flex;
gap: 10px;
padding: 10px 8px;
flex-direction: row-reverse; /* последние подарки справа налево */
}

.gift-card {
width: 140px;
text-align: center;
position: relative;
cursor: pointer;
}

.gift-card img {
width: 90px;
height: 90px;
border-radius: 0%;
object-fit: cover;
margin: 0 auto;
transition: .25s ease;
}

.gift-card::after {
content: '';
position: absolute;
inset: 0;
border-radius: 5%;
background: rgba(0,0,0,.25);
opacity: 0;
transition: .25s ease;
}

.gift-card:hover::after {
opacity: 0.1;
}

.vk-reply a {
display: inline-block;
text-decoration: none;
color: #fff; /* белый текст */
background: linear-gradient(
145deg,
#4a76a8, /* светлый синий */
#3f6aa0,
#365d8c, /* основной синий */
#2d4b70,
#25395a /* темный синий */
); /* плавный градиент в стиле современного ВК */

border: 1px solid #2e4a6b;
padding: 10px 20px; /* чуть больше паддинга */
border-radius: 50px; /* супер скругление */
cursor: pointer;
font-weight: 600;
font-size: 13px;
transition: all 0.3s ease; /* плавная анимация */
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}

/* Hover эффект */
.vk-reply a:hover {
background: linear-gradient(
145deg,
#5a88b5,
#4d79a7,
#3f6aa0,
#365d8c,
#2d4b70
);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
transform: translateY(0px); /* эффект поднятия */
}

.vk-comment {
  position: relative;
  margin-top: 12px;
  font-size: 13px;
  color: #333;
  background: #f5f7fa;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid #dce1e6;
  max-width: 400px;
}

/* Хвостик сверху */
.vk-comment::before {
  content: "";
  position: absolute;
  top: -8px; /* сдвигаем над блоком */
  left: 3px; /* позиция от левого края блока */
  width: 0px;
  height: 0px;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 8px solid #f5f7fa; /* тот же цвет фона */
}

</style>

<script>
(async function(){

const container = document.getElementById('gifts-container');
const counter = document.getElementById('gifts-count');
const userId = <?$JSENCODE$($USER_ID$)?>;
const STORAGE_KEY = `giftsData_${userId}`;

let allGifts = [];

/* =======================
   СТИЛИ POPUP (СТАРЫЙ ВК)
======================= */
const style = document.createElement('style');
style.innerHTML = `
.gifts-popup-overlay{position:fixed; inset:0; background:rgba(0,0,0,.45); display:flex; align-items:center; justify-content:center; z-index:9999;}
.gifts-popup{background:#fff; width:520px; max-height:75vh; border-radius:6px; overflow:hidden; display:flex; flex-direction:column; box-shadow:0 10px 40px rgba(0,0,0,.35); font-family:Tahoma,Arial,sans-serif;}
.gifts-popup-header{background:#f0f2f5; padding:10px 14px; font-weight:bold; color:#2a5885; border-bottom:1px solid #dce1e6; display:flex; justify-content:space-between; align-items:center;}
.gifts-popup-header span{cursor:pointer; font-size:18px; color:#666;}
.gifts-popup-list{padding:14px; overflow-y:auto;}
.vk-gift{padding-bottom:20px; margin-bottom:20px; border-bottom:1px solid #eee; position:relative;}
.vk-user{display:flex; gap:10px; align-items:center; margin-bottom:10px;}
.vk-user img{width:55px; height:55px; border-radius:50%; margin-top:-18px;}
.vk-user .name{font-weight:bold; color:#2a5885; font-size:13px;}
.vk-user .date{font-size:11px; color:#777;}
.vk-comment{margin-top:6px; font-size:12px; color:#333; background:#f5f7fa; padding:6px 8px; border-radius:6px;}
.vk-gift-img{text-align:center; margin:10px 0;}
.vk-gift-img img{max-width:240px;}
.vk-reply{text-align:center;}
.vk-reply a{display:inline-block; text-decoration:none; color:#2a5885; background:#e9eff6; border:1px solid #c5d0db; padding:6px 14px; border-radius:4px; cursor:pointer;}
`;
document.head.appendChild(style);

/* =======================
   ЗАГРУЗКА ПОДАРКОВ
======================= */
async function loadGifts(){
    allGifts = [];
    container.innerHTML = '';
    try{
        const res = await fetch(`/index/54-${userId}-`);
        const text = await res.text();
        const xml = new DOMParser().parseFromString(text,'application/xml');
        const cmd = xml.querySelector('cmd[p="content"]');
        if(!cmd){ counter.textContent='0 подарков'; return; }

        const temp = document.createElement('div');
        temp.innerHTML = cmd.textContent;
        const tds = [...temp.querySelectorAll('td[onclick*="_uWnd.reload"]')];
        if(!tds.length){ counter.textContent='0 подарков'; return; }

        let total = 0;
        for(const td of tds){
            const img = td.querySelector('img');
            if(!img) continue;
            const count = td.querySelector('b') ? +td.querySelector('b').textContent || 1 : 1;
            total += count;
            const onclick = td.getAttribute('onclick');
            for(let i=0;i<count;i++){
                allGifts.push({
                    img: img.src,
                    onclick,
                    nick: 'Загрузка...',
                    avatar: '/.s/src/profile/img/profile_photo_thumbnail.png',
                    date: '',
                    comment: '',
                    profile: '#',
                    recipientId: null
                });
            }
        }

        counter.textContent = total + (total===1?' подарок':total<5?' подарка':' подарков');

        // Вывод последних 3 подарков
        const cached = JSON.parse(localStorage.getItem(STORAGE_KEY)||'[]');
        allGifts.forEach(g=>{
            const saved = cached.find(c=>c.img===g.img && c.profile===g.profile);
            if(saved){
                g.nick = saved.nick;
                g.avatar = saved.avatar;
                g.date = saved.date;
                g.comment = saved.comment;
                g.profile = saved.profile;
                g.recipientId = saved.recipientId;
            }
        });
        allGifts.forEach(g=>{ if(!g.date) g.date = new Date().toISOString(); });
        allGifts.sort((a,b)=> new Date(b.date) - new Date(a.date));

        allGifts.slice(0,3).forEach(g=>{
            const div = document.createElement('div');
            div.className='gift-card';
            div.title = g.nick;
            div.innerHTML = `<img src="${g.img}" alt="">`;
            container.appendChild(div);
        });

    }catch(e){ console.error(e); counter.textContent='Ошибка загрузки'; }
}

/* =======================
   POPUP
======================= */
async function showPopup(){
    if(!allGifts.length) return;

    const overlay = document.createElement('div');
    overlay.className='gifts-popup-overlay';

    const popup = document.createElement('div');
    popup.className='gifts-popup';
    popup.innerHTML=`
        <div class="gifts-popup-header">
          Мои подарки
          <span>×</span>
        </div>
        <div class="gifts-popup-list"></div>
    `;

    overlay.appendChild(popup);
    document.body.appendChild(overlay);

    popup.querySelector('span').onclick = ()=>overlay.remove();
    overlay.onclick = e=>{ if(e.target===overlay) overlay.remove(); };

    const list = popup.querySelector('.gifts-popup-list');
    let cached = JSON.parse(localStorage.getItem(STORAGE_KEY)||'[]');

    allGifts.forEach((g, idx)=>{
        const saved = cached[idx];
        if(saved){
            g.nick = saved.nick;
            g.avatar = saved.avatar;
            g.date = saved.date;
            g.comment = saved.comment || '';
            g.profile = saved.profile || '#';
            g.recipientId = saved.recipientId || null;
        }

        if(!g.recipientId && g.onclick){
            const match = g.onclick.match(/url:'\/index\/55-(\d+)'/);
            if(match) g.recipientId = match[1];
            cached[idx] = {...g};
            localStorage.setItem(STORAGE_KEY, JSON.stringify(cached));
        }

        const div = document.createElement('div');
        div.className='vk-gift';
        div.dataset.idx=idx;
        div.innerHTML=`
            <div class="vk-user">
              <img src="${g.avatar}">
              <div>
                <div class="name">${g.nick}</div>
                <div class="date">${g.date}</div>
                ${g.comment ? `<div class="vk-comment">${g.comment}</div>` : ''}
              </div>
            </div>
            <div class="vk-gift-img"><img src="${g.img}"></div>
            <div class="vk-reply"></div>
        `;

        // Кнопки редактирования и удаления убраны

        const replyDiv = div.querySelector('.vk-reply');
        replyDiv.innerHTML='';
        if(g.recipientId && g.recipientId != userId){
            const btn = document.createElement('a');
            btn.href="javascript:;";
            btn.textContent='🎁 Вручить подарок';
            btn.onclick = ()=>new _uWnd('AwD','Вручить награду',380,200,
              {maxh:300,minh:100,closeonesc:1},
              {url:'/index/55-'+g.recipientId});
            replyDiv.appendChild(btn);
        } else {
            replyDiv.textContent = 'Нельзя вручить себе';
        }

        list.appendChild(div);
    });

    setTimeout(async ()=>{
        const newData = [];
        for(const [idx,g] of allGifts.entries()){
            try{
                const urlMatch = g.onclick.match(/url:'([^']+)'/);
                if(!urlMatch) continue;
                const giftPage = await fetch(urlMatch[1]).then(r=>r.text());
                const giftDoc = new DOMParser().parseFromString(giftPage,'text/html');
                const legend = giftDoc.querySelector('legend a');
                g.nick = legend ? legend.textContent.trim() : g.nick;
                g.profile = legend ? legend.href : g.profile;
                g.comment = giftDoc.querySelector('[id^="mtx"]')?.textContent.trim() || g.comment;
                g.date = giftDoc.querySelector('div[style*="text-align:right"]')?.textContent.trim() || g.date;

                if(g.profile && g.profile!=='#'){
                    const prof = await fetch(g.profile).then(r=>r.text());
                    const pdoc = new DOMParser().parseFromString(prof,'text/html');
                    const photoDiv = pdoc.querySelector('.profile-photo');
                    if(photoDiv){
                        const bg = photoDiv.style.backgroundImage;
                        if(bg && bg!=='none'){
                            g.avatar = bg.replace(/^url\(["']?|["']?\)$/g,'');
                        }
                    }
                    const match = g.profile.match(/-(\d+)$/);
                    if(match) g.recipientId = match[1];
                }

                const giftDiv = list.children[idx];
                giftDiv.querySelector('.name').textContent = g.nick;
                giftDiv.querySelector('.date').textContent = g.date;
                giftDiv.querySelector('.vk-user img').src = g.avatar;

                let commentDiv = giftDiv.querySelector('.vk-comment');
                if(!commentDiv && g.comment){
                    commentDiv = document.createElement('div');
                    commentDiv.className='vk-comment';
                    giftDiv.querySelector('.vk-user div').appendChild(commentDiv);
                }
                if(commentDiv) commentDiv.textContent = g.comment;

                const replyDiv = giftDiv.querySelector('.vk-reply');
                replyDiv.innerHTML='';
                if(g.recipientId && g.recipientId!=userId){
                    const btn = document.createElement('a');
                    btn.href="javascript:;";
                    btn.textContent='🎁 Вручить подарок';
                    btn.onclick = ()=>new _uWnd('AwD','Вручить награду',380,200,
                      {maxh:300,minh:100,closeonesc:1},
                      {url:'/index/55-'+g.recipientId});
                    replyDiv.appendChild(btn);
                } else {
                    replyDiv.textContent='Нельзя вручить себе';
                }

                newData.push({...g});
            }catch(e){console.error(e);}
        }
        localStorage.setItem(STORAGE_KEY, JSON.stringify(newData));
    },100);
}

counter.style.cursor='pointer';
counter.onclick=showPopup;

loadGifts();

})();
</script>



Мурчанн

Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
  • Страница 1 из 1
  • 1
Поиск: