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

1
Админ
Постов: 211
2
VIP
Постов: 72
3
Элита
Постов: 50
4
Проверенные
Постов: 35
5
VIP
Постов: 35
6
Проверенные
Постов: 32
7
Пользователи
Постов: 31
8
Проверенные
Постов: 29

  • Страница 1 из 1
  • 1
Модуль ВК «Подписки » для Ucoz v 2.0 упрощённая логика
Дата: Четверг, 12.02.2026, 21:49 | Сообщение # 1 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:211
         Регистрация:20.10.2016

Дизайн блока подписок обновлён, а логика работы упрощена проверок стало меньше. Пока сложно сказать, как это отразится на стабильности и работе, но со временем станет ясно: чем меньше нагрузка, тем быстрее и плавнее будет работать скрипт, проще говоря «летать» по сайту без задержек.

Приглашаю всех делиться своими идеями! Если умеете работать в Photoshop, нарисуйте собственный вариант блока, а я реализую его в коде и опубликую на форуме. Предлагайте свои варианты , вместе сможем совершенствовать дизайн и функциональность.

Общая цель скрипта

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

Основные переменные

Код
const container = document.getElementById('subsParser'); // блок, куда выводятся подписки
const counter = document.getElementById('subsCount');    // счётчик числа подписок
const parser = new DOMParser();                          // для парсинга HTML страниц
const forumURL = '/forum/0-0-1-46';                     // URL страницы подписок
const localKey = 'cachedSubs';                           // ключ для кэша в localStorage


1. container - куда будут вставляться блоки подписок.

2. counter - элемент, показывающий число подписок.

3. parser - позволяет превращать HTML в DOM для работы через JS.

4. forumURL - адрес страницы форума, где хранятся подписки.

5. localKey - ключ для сохранения кэша, чтобы не грузить страницу полностью каждый раз

Клик по счётчику

Код
if(counter){
  counter.style.cursor = 'pointer';
  counter.title = 'Перейти к списку подписок';
  counter.onclick = () => window.location.href = forumURL;
}


1. Если есть элемент counter, делаем его кликабельным.

2. При клике пользователь переходит на страницу подписок форума.

Отображение кэша (LocalStorage)

Код
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;
  }
}


1. Скрипт проверяет, есть ли сохранённый HTML и число подписок в localStorage.

2. Если есть сразу показывает старый кэш, чтобы не ждать загрузки с сервера.

3. Обновляет счетчик подписок.

Загрузка актуальных данных

Код
let page = await fetch(forumURL, {credentials:'include'});
let html = await page.text();
let doc = parser.parseFromString(html,'text/html');
let rows = doc.querySelectorAll('tr[id^="tt"]');
let count = rows.length;


1. Загружается страница подписок через fetch с учётом куки (credentials:'include').

2. Парсится HTML в DOM.

3. Считаются все строки tr с id, начинающимся на tt — это темы форума.

4. Определяется количество подписок count.

Проверка кэша

Код
if(cached && cached.count === count) return;


Если кэш есть и число подписок не изменилось , скрипт прекращает работу, засыпает впадает в спячку, чтобы не перезагружать HTML.

Если подписок нет

Код
if(!rows.length){
  container.className = "vksub-empty";
  container.textContent = "Нет подписок";
  if(counter.querySelector('.subs-number')) {
    counter.querySelector('.subs-number').textContent = "0";
  }
  localStorage.removeItem(localKey);
  return;
}



1. Если список пустой показывается сообщение "Нет подписок".

2. Кэш удаляется, счетчик обновляется на 0.

Генерация HTML для каждой темы

Цикл по всем строкам таблицы:

Код
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);
  }

  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;
}


1. Для каждой темы создаётся блок
Код
.vksub-item.


2. Загружается страница темы, чтобы получить:

3. первую картинку поста (аватар темы)

4. описание темы (span.thDescr)

5. HTML блока включает: название темы, ссылку, аватар, описание и индикатор.

6. Анимация появления реализована через animation-delay.

Отображение и кэширование

Код
container.className = '';
container.innerHTML = resultHTML;

localStorage.setItem(localKey, JSON.stringify({
  count,
  html: resultHTML
}));



1. Вставляется готовый HTML в container.

2. Результат и количество подписок сохраняются в localStorage для ускорения следующего открытия страницы.

Обработка ошибок

Код
} catch(e){
  if(!cached){
    container.className = "vksub-empty";
    container.textContent = "Ошибка загрузки подписок";
    if(counter.querySelector('.subs-number')) {
      counter.querySelector('.subs-number').textContent = "0";
    }
  }
  console.error(e);
}


1. Если что-то пошло не так при загрузке с сервера:

2. показывается сообщение об ошибке,

3. счетчик сбрасывается на 0,

4. ошибки выводятся в консоль для разработчика.

Итого

Скрипт делает:

Делает счетчик подписок кликабельным.

Показывает кэшированные данные сразу, чтобы не ждать загрузки.

Загружает страницу подписок и считает темы.

Если кэш актуален прекращает работу.

Если нет подписок выводит сообщение.

Для каждой темы:

получает аватар и описание темы,

создаёт HTML блок с анимацией и кликом.

Сохраняет HTML и количество подписок в localStorage.

Обрабатывает ошибки загрузки.

Исходник

Код
<!-- ======= Блок подписок ======= -->
<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';

  /* ===================== КЛИК ПО СЧЁТЧИКУ ===================== */
  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');

    let rows = doc.querySelectorAll('tr[id^="tt"]');
    let count = rows.length;

    if(counter.querySelector('.subs-number')) {
      counter.querySelector('.subs-number').textContent = count;
    }

    if(cached && cached.count === count) 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,
      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>
/* ===== Основной блок подписок ===== */
.vksub-block {
  background: #fff;
  border-radius: 6px;
  border: 1px solid #d8dce1;
  box-shadow: 0 1px 4px rgba(0,0,0,0.08);
  margin-bottom: 10px;
  overflow: hidden;
  font-family: Arial,sans-serif;
  padding: 0px; /* внутренние отступы сверху/снизу и слева/справа */
}

/* ===== Шапка блока ===== */
.vksub-head {
  background: linear-gradient(#f7f7f7,#ececec);
  padding: 8px 12px;
  border-bottom: 1px solid #e1e5e8;
  font-size: 13px;
  font-weight: bold;
  color: #2b587a;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.vksub-head:hover {
  background: linear-gradient(#f9f9f9,#f0f0f0);
}

/* ===== Счётчик подписок ===== */
.vksub-count {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
}
.vksub-count .subs-label { color: #68777d; }

.vksub-count .subs-number {
  background: #f0f2f5;       /* светлый серый фон */
  color: #4a4a4a;            /* тёмно-серый цвет цифры */
  border: 1px solid #d0d3d9; /* мягкая граница */
  border-radius: 12px;        /* более округлый блок */
  padding: 3px 8px;           /* увеличенный внутренний отступ */
  font-weight: 600;            /* чуть плотнее */
  min-width: 20px;             /* ширина блока */
  text-align: center;
  transition: all 0.2s ease;  /* плавное взаимодействие при hover */
}

/* ===== При наведении на счётчик можно сделать лёгкий эффект ===== */
.vksub-count:hover .subs-number {
  background: #e6e9ed;        /* чуть светлее фон */
  border-color: #c8ccd2;      /* мягкая граница */
}

/* ===== Контейнер с подписками ===== */
.vksub-container {
  max-height: 340px;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 12px 0; /* увеличенные верх/низ */
  box-sizing: border-box;
  scrollbar-width: thin;
  scrollbar-color: #c8d4e1 #f7f7f7;
}
.vksub-container::-webkit-scrollbar { width: 6px; }
.vksub-container::-webkit-scrollbar-track { background: #f7f7f7; border-radius: 3px; }
.vksub-container::-webkit-scrollbar-thumb { background: linear-gradient(#bdc7d8,#c8d4e1); border-radius: 3px; border: 1px solid #fff; }
.vksub-container::-webkit-scrollbar-thumb:hover { background: linear-gradient(#b0bdd0,#bdc7d8); }

/* ===== Элемент подписки ===== */
.vksub-item {
  display: flex;
  align-items: center;
  padding: 10px 14px; /* внутренние отступы темы */
  margin: 6px 0;      /* расстояние между темами */
  cursor: pointer;
  position: relative;
  min-height: 52px;
  box-sizing: border-box;
  overflow: hidden;
  animation: vksubFadeSlideIn 0.25s ease forwards;
  transition: all .2s ease;
  border-radius: 6px;
  width: 100%; /* теперь фон растягивается на всю ширину контейнера */
  background: #fff;
}
.vksub-item:hover { background: #edf3ff; }

/* ===== Аватар ===== */
.vksub-avatar {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  margin-right: 12px;
  border: 2px solid #fff;
  box-shadow: 0 2px 4px rgba(0,0,0,0.15);
  transition: transform .2s ease, box-shadow .2s ease;
}
.vksub-item:hover .vksub-avatar {
  transform: scale(1.05);
  box-shadow: 0 4px 12px rgba(0,0,0,0.25);
}

/* ===== Информация о подписке ===== */
.vksub-info {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  padding-right: 12px;
}
.vksub-name {
  font-size: 14px;
  font-weight: 600;
  color: #2b587a;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
  margin-bottom: 2px;
}
.vksub-name a { color: inherit; text-decoration: none; }
.vksub-name a:hover { text-decoration: underline; }
.vksub-desc {
  font-size: 12px;
  color: #555;
  line-height: 1.4;
  margin-top: 4px;
  word-break: break-word;
  overflow-wrap: break-word;
}

/* ===== Пустой блок подписок ===== */
.vksub-empty {
  padding: 50px 20px;
  text-align: center;
  color: #a9afba;
  font-size: 13px;
  word-break: break-word;
}
.vksub-empty::before {
  content: "👥";
  display: block;
  font-size: 48px;
  margin-bottom: 12px;
  opacity: 0.4;
}

/* ===== Анимация ===== */
@keyframes vksubFadeSlideIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ===== Индикатор справа ===== */
.vksub-indicator {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 10px;
  background: #fff;
  border: 1px solid #5db15d;
  border-radius: 50%;
  transition: all 0.2s ease;
  pointer-events: none;
}
.vksub-item:hover .vksub-indicator {
  width: 14px;
  height: 14px;
  border-width: 3px;
  border-color: #5db15d;
  box-shadow: 0 0 6px rgba(93,177,93,0.5);
}

/* ===== Адаптив ===== */
@media (max-width:900px) {
  .vksub-container { max-height: 280px; padding: 10px 0; }
  .vksub-item { padding: 8px 10px; min-height: 46px; margin: 4px 0; width: 100%; }
  .vksub-avatar { width: 36px; height: 36px; }
  .vksub-name, .vksub-desc { font-size: 12px; }
}
</style>



Мурчанн

Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
Дата: Пятница, 13.02.2026, 00:26 | Сообщение # 2 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:211
         Регистрация:20.10.2016

Совсем забыл добавить ограничение на количество выводимых подписок. Если этого не сделать, колонка будет постоянно расти без каких-либо ограничений.

В скрипте прописано ограничение.

Код
  const MAX_ITEMS = 5; // ограничение на количество выводимых материалов


«Просто меняем число больше или меньше и колонка будет отображать соответственно больше или меньше подписок.»

Код
<!-- ======= Блок подписок ======= -->
<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>
/* ===== Основной блок подписок ===== */
.vksub-block {
background: #fff;
border-radius: 6px;
border: 1px solid #d8dce1;
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
margin-bottom: 10px;
margin-top: 10px; /* отступ сверху блока */
overflow: hidden;
font-family: Arial,sans-serif;
padding: 0px; /* внутренние отступы сверху/снизу и слева/справа */
}

/* ===== Шапка блока ===== */
.vksub-head {
background: linear-gradient(#f7f7f7,#ececec);
padding: 8px 12px;
border-bottom: 1px solid #e1e5e8;
font-size: 13px;
font-weight: bold;
color: #2b587a;
display: flex;
justify-content: space-between;
align-items: center;
}
.vksub-head:hover {
background: linear-gradient(#f9f9f9,#f0f0f0);
}

/* ===== Счётчик подписок ===== */
.vksub-count {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 11px;
}
.vksub-count .subs-label { color: #68777d; }

.vksub-count .subs-number {
background: #f0f2f5; /* светлый серый фон */
color: #4a4a4a; /* тёмно-серый цвет цифры */
border: 1px solid #d0d3d9; /* мягкая граница */
border-radius: 12px; /* более округлый блок */
padding: 3px 8px; /* увеличенный внутренний отступ */
font-weight: 600; /* чуть плотнее */
min-width: 20px; /* ширина блока */
text-align: center;
transition: all 0.2s ease; /* плавное взаимодействие при hover */
}

/* ===== При наведении на счётчик можно сделать лёгкий эффект ===== */
.vksub-count:hover .subs-number {
background: #e6e9ed; /* чуть светлее фон */
border-color: #c8ccd2; /* мягкая граница */
}

/* ===== Контейнер с подписками ===== */
.vksub-container {
max-height: 340px;
overflow-y: auto;
overflow-x: hidden;
padding: 12px 0; /* увеличенные верх/низ */
box-sizing: border-box;
scrollbar-width: thin;
scrollbar-color: #c8d4e1 #f7f7f7;
}
.vksub-container::-webkit-scrollbar { width: 6px; }
.vksub-container::-webkit-scrollbar-track { background: #f7f7f7; border-radius: 3px; }
.vksub-container::-webkit-scrollbar-thumb { background: linear-gradient(#bdc7d8,#c8d4e1); border-radius: 3px; border: 1px solid #fff; }
.vksub-container::-webkit-scrollbar-thumb:hover { background: linear-gradient(#b0bdd0,#bdc7d8); }

/* ===== Элемент подписки ===== */
.vksub-item {
display: flex;
align-items: center;
padding: 10px 14px; /* внутренние отступы темы */
margin: 6px 0; /* расстояние между темами */
cursor: pointer;
position: relative;
min-height: 52px;
box-sizing: border-box;
overflow: hidden;
animation: vksubFadeSlideIn 0.25s ease forwards;
transition: all .2s ease;
border-radius: 6px;
width: 100%; /* теперь фон растягивается на всю ширину контейнера */
background: #fff;
}
.vksub-item:hover { background: #edf3ff; }

/* ===== Аватар ===== */
.vksub-avatar {
width: 52px;
height: 52px;
border-radius: 50%;
object-fit: cover;
margin-right: 12px;
border: 2px solid #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.15);
transition: transform .2s ease, box-shadow .2s ease;
}
.vksub-item:hover .vksub-avatar {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(0,0,0,0.25);
}

/* ===== Информация о подписке ===== */
.vksub-info {
display: flex;
flex-direction: column;
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
padding-right: 12px;
}
.vksub-name {
font-size: 14px;
font-weight: 600;
color: #2b587a;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.3;
margin-bottom: 2px;
}
.vksub-name a { color: inherit; text-decoration: none; }
.vksub-name a:hover { text-decoration: underline; }
.vksub-desc {
font-size: 12px;
color: #555;
line-height: 1.4;
margin-top: 4px;
word-break: break-word;
overflow-wrap: break-word;
}

/* ===== Пустой блок подписок ===== */
.vksub-empty {
padding: 50px 20px;
text-align: center;
color: #a9afba;
font-size: 13px;
word-break: break-word;
}
.vksub-empty::before {
content: "👥";
display: block;
font-size: 48px;
margin-bottom: 12px;
opacity: 0.4;
}

/* ===== Анимация ===== */
@keyframes vksubFadeSlideIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}

/* ===== Индикатор справа ===== */
.vksub-indicator {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
width: 10px;
height: 10px;
background: #fff;
border: 1px solid #5db15d;
border-radius: 50%;
transition: all 0.2s ease;
pointer-events: none;
}
.vksub-item:hover .vksub-indicator {
width: 14px;
height: 14px;
border-width: 3px;
border-color: #5db15d;
box-shadow: 0 0 6px rgba(93,177,93,0.5);
}

/* ===== Адаптив ===== */
@media (max-width:900px) {
.vksub-container { max-height: 280px; padding: 10px 0; }
.vksub-item { padding: 8px 10px; min-height: 46px; margin: 4px 0; width: 100%; }
.vksub-avatar { width: 36px; height: 36px; }
.vksub-name, .vksub-desc { font-size: 12px; }
}
</style>


«Формат отображения: Подписок 5 | 6, где 5 это количество подписок, выводимых в колонке (настройка), а 6 общее число новостей.»

Мурчанн

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