Дата: Среда, 18.02.2026, 12:51 | Сообщение # 1 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 211
Февральский стиль сдержанный, в серо-белых тонах, минималистичный. Пока ничего лучше придумать не удалось. Скрипт и основной блок остались без изменений корректировки внесены только в CSS-стили и настройки.Исходной код Код
<!-- ======= Блок подписок ======= --> <div class="vksub-block"> <div class="vksub-head"> <span>Подписки</span> <span class="vksub-count" id="subsCount"> <span class="subs-label">Подписок</span> <span class="subs-number">0</span> </span> </div> <div class="vksub-container" id="subsParser"> <div class="vksub-empty">Загрузка подписок...</div> </div> </div> <script> (async function() { const container = document.getElementById('subsParser'); const counter = document.getElementById('subsCount'); const parser = new DOMParser(); const forumURL = '/forum/0-0-1-46'; const localKey = 'cachedSubs'; const MAX_ITEMS = 5; // ограничение на количество выводимых материалов /* ===================== КЛИК ПО СЧЁТЧИКУ ===================== */ if(counter){ counter.style.cursor = 'pointer'; counter.title = 'Перейти к списку подписок'; counter.onclick = () => window.location.href = forumURL; } /* ===================== ПОКАЗ КЭША ===================== */ let cached = JSON.parse(localStorage.getItem(localKey) || 'null'); if(cached){ container.className=''; container.innerHTML = cached.html; if(counter.querySelector('.subs-number')) { counter.querySelector('.subs-number').textContent = cached.count; } } try { /* ===== грузим страницу подписок ===== */ let page = await fetch(forumURL, {credentials:'include'}); let html = await page.text(); let doc = parser.parseFromString(html,'text/html'); // Получаем все темы, но ограничиваем вывод MAX_ITEMS let rowsAll = doc.querySelectorAll('tr[id^="tt"]'); let totalCount = rowsAll.length; let rows = Array.from(rowsAll).slice(0, MAX_ITEMS); if(counter.querySelector('.subs-number')) { counter.querySelector('.subs-number').textContent = `${rows.length} | ${totalCount}`; } if(cached && cached.count === totalCount) return; if(!rows.length){ container.className = "vksub-empty"; container.textContent = "Нет подписок"; if(counter.querySelector('.subs-number')) { counter.querySelector('.subs-number').textContent = "0"; } localStorage.removeItem(localKey); return; } let resultHTML = ''; let delay = 0; /* ===================== ЦИКЛ ТЕМ ===================== */ for(let row of rows){ let topicEl = row.querySelector('.topic-item-title'); if(!topicEl) continue; let topic = topicEl.textContent.trim(); let topicLink = topicEl.href; let avatar = '/.s/img/icon/user.png'; let topicDesc = ''; try{ let topicPage = await fetch(topicLink,{credentials:'include'}); let topicHTML = await topicPage.text(); let topicDoc = parser.parseFromString(topicHTML,'text/html'); let firstImg = topicDoc.querySelector('.post-content-main img'); if(firstImg && firstImg.src) avatar = firstImg.src; let thDescrEl = topicDoc.querySelector('span.thDescr'); topicDesc = thDescrEl ? thDescrEl.textContent.trim() : ''; }catch(e){ console.warn('Не удалось получить тему', topicLink); } /* ===== HTML В СТИЛЕ СТАРОГО CSS ===== */ resultHTML += ` <div class="vksub-item" style="animation-delay:${delay}ms" onclick="location.href='${topicLink}'"> <img class="vksub-avatar" src="${avatar}" alt=""> <div class="vksub-info"> <div class="vksub-name"> <a href="${topicLink}">${topic}</a> </div> ${topicDesc ? `<div class="vksub-desc" style="font-style:italic;color:#555;margin-top:3px;">${topicDesc}</div>` : ''} </div> <div class="vksub-indicator"></div> </div>`; delay += 40; } container.className = ''; container.innerHTML = resultHTML; /* ===================== СОХРАНЯЕМ КЭШ ===================== */ localStorage.setItem(localKey, JSON.stringify({ count: totalCount, html: resultHTML })); } catch(e){ if(!cached){ container.className = "vksub-empty"; container.textContent = "Ошибка загрузки подписок"; if(counter.querySelector('.subs-number')) { counter.querySelector('.subs-number').textContent = "0"; } } console.error(e); } })(); </script> <style> /* ======= Стиль 2026 + миниатюризация ======= */ .vksub-block { background: #ffffff; border: 1px solid #ccd0d5; /* серая граница */ border-radius: 8px; /* мягкие скругления */ margin: 12px 0; overflow: hidden; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); /* очень лёгкая тень */ font-size: 13px; } /* Шапка */ .vksub-head { background: #f0f2f5; /* светлый фон */ padding: 8px 12px; border-bottom: 1px solid #e4e6eb; font-size: 14px; font-weight: 600; color: #050505; /* почти чёрный текст */ display: flex; justify-content: space-between; align-items: center; } .vksub-head span:first-child { color: #050505; } /* Счётчик — как бейджик */ .vksub-count { display: inline-flex; align-items: center; font-size: 12px; color: #65676b; } .subs-label { color: #65676b; margin-right: 4px; font-weight: 500; } .subs-number { background: #e4e6eb; /* серый бейджик */ color: #050505; padding: 2px 7px; border-radius: 10px; font-weight: 600; min-width: 18px; text-align: center; font-size: 12px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.6); } .vksub-count:hover .subs-number { background: #d8dade; } /* Контейнер компактный как список в сайдбаре */ .vksub-container { max-height: 210px; /* минитюризация: короче для сайдбара */ overflow-y: auto; padding: 4px 0; background: #fff; } /* Скроллбар в стиле (тонкий, серый) */ .vksub-container::-webkit-scrollbar { width: 6px; } .vksub-container::-webkit-scrollbar-track { background: transparent; } .vksub-container::-webkit-scrollbar-thumb { background: #c4c7cc; border-radius: 10px; } .vksub-container::-webkit-scrollbar-thumb:hover { background: #a0a4a9; } /* Элемент */ .vksub-item { display: flex; align-items: center; padding: 8px 12px; cursor: pointer; transition: background 0.12s ease; border-radius: 6px; margin: 2px 4px; animation: fbFadeIn 0.25s ease; } .vksub-item:hover { background: #e4e6eb; /* классический hover */ } .vksub-item:active { background: #d8dade; } /* Аватарка — круглая */ .vksub-avatar { width: 46px; /* минитюра: меньше, как в сайдбаре */ height: 46px; border-radius: 50%; object-fit: cover; margin-right: 10px; border: none; box-shadow: 0 1px 3px rgba(0,0,0,0.08); flex-shrink: 0; } /* Информация */ .vksub-info { flex: 1; min-width: 0; } .vksub-name { font-size: 13px; font-weight: 600; color: #050505; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.3; } .vksub-name a { color: #050505; text-decoration: none; } .vksub-name a:hover { text-decoration: underline; } .vksub-desc { font-size: 12px; color: #65676b; margin-top: 1px; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; } /* Индикатор — как зелёный "active" */ .vksub-indicator { width: 10px; height: 10px; background: #31a24c; /* зелёный онлайн */ border: 2px solid #fff; border-radius: 50%; box-shadow: 0 1px 4px rgba(49,162,76,0.3); margin-left: 8px; flex-shrink: 0; } .vksub-item:hover .vksub-indicator { box-shadow: 0 0 6px rgba(49,162,76,0.5); } /* Пустой блок */ .vksub-empty { padding: 16px 12px; text-align: center; color: #65676b; font-size: 13px; } /* Анимация появления — мягкая, */ @keyframes fbFadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } } .vksub-name a:hover { text-decoration: none; } /* Адаптив — ещё компактнее на мобильных */ @media (max-width: 900px) { .vksub-block { margin: 8px 0; border-radius: 6px; } .vksub-head { padding: 7px 10px; font-size: 13px; } .vksub-avatar { width: 32px; height: 32px; margin-right: 8px; } .vksub-item { padding: 7px 10px; margin: 1px 3px; } .vksub-name { font-size: 12.5px; } .vksub-container { max-height: 180px; } } </style>
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.