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

1
Админ
Постов: 288
2
VIP
Постов: 75
3
Элита
Постов: 62
4
Проверенные
Постов: 46
5
Проверенные
Постов: 45
6
Проверенные
Постов: 40
7
VIP
Постов: 36
8
VIP
Постов: 35

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