Этот скрипт — это «умный индикатор прочтения» для страниц сайта, похожий на закладки в браузере, но работающий на самом сайте. Он помогает пользователю отслеживать, какие статьи или посты он уже просматривал, и когда это было в последний раз.

Как это работает:
​Определение типа страницы: Скрипт проверяет, является ли текущая страница статьей, новостью или другим основным контентом (например, ищет теги article, .post и т.д.). Если это не такая страница, скрипт бездействует.

Запоминание визита:
Когда пользователь заходит на подходящую страницу, скрипт записывает текущую дату и время в локальное хранилище браузера (это как небольшая память, которая хранится только в вашем браузере).

Отображение уведомления:
При следующем визите на ту же страницу, скрипт:
​Проверяет, есть ли запись о предыдущем посещении.

​Если запись есть и она не слишком старая (по умолчанию, не старше 180 дней), то он показывает небольшое, стильное уведомление сверху контента: «Вы уже читали эту страницу.
Последний визит: [дата и время]».

​Кнопка «Скрыть» позволяет убрать это уведомление, если оно мешает.

​Очистка старых записей: Записи о посещениях, которым более 180 дней, автоматически удаляются, чтобы не засорять память браузера.


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

​Автоматизация: Не требует от пользователя никаких действий для отслеживания.

​Легкость интеграции: Просто добавьте скрипт на сайт, и он начнет работать.

​Настраиваемость: Можно легко изменить срок хранения информации о посещениях (180 дней).


Код
<style>.uc-read-flag {  
position: relative;  
margin: 14px 0;  
padding: 12px 14px;  
border-radius: 12px;  
background: rgba(0, 0, 0, 0.06);  
border: 1px solid rgba(0, 0, 0, 0.10);  
line-height: 1.35;  
font-size: 14px;  
  }  

  @media (prefers-color-scheme: dark) {  
.uc-read-flag {  
background: rgba(255, 255, 255, 0.06);  
border: 1px solid rgba(255, 255, 255, 0.12);  
}  
  }  

  .uc-read-flag__title {  
font-weight: 700;  
margin: 0 0 4px 0;  
font-size: 15px;  
  }  

  .uc-read-flag__meta {  
opacity: 0.85;  
margin: 0;  
  }  

  .uc-read-flag__btn {  
position: absolute;  
top: 10px;  
right: 10px;  
border: 0;  
border-radius: 10px;  
padding: 6px 10px;  
cursor: pointer;  
background: rgba(0, 0, 0, 0.10);  
font-size: 13px;  
  }  

  @media (prefers-color-scheme: dark) {  
.uc-read-flag__btn {  
background: rgba(255, 255, 255, 0.12);  
}  
  }</style>


Код
<script>  
  (function () {  
'use strict';  

var KEEP_DAYS = 180;  
var SAVE_AFTER_MS = 2500;  

function nowMs() { return Date.now(); }  

function pad2(n) { return (n < 10 ? '0' : '') + n; }  

function formatDate(ts) {  
var d = new Date(ts);  
return pad2(d.getDate()) + '.' + pad2(d.getMonth() + 1) + '.' + d.getFullYear() +  
' ' + pad2(d.getHours()) + ':' + pad2(d.getMinutes());  
}  

function safeJsonParse(s) {  
try { return JSON.parse(s); } catch (e) { return null; }  
}  

function normUrl(u) {  
try {  
var x = new URL(u, location.href);  
return x.origin + x.pathname.replace(/\/+$/, '');  
} catch (e) {  
return (u || '').split('#')[0].split('?')[0].replace(/\/+$/, '');  
}  
}  

function getPageKey() {  
var canonical = document.querySelector('link[rel="canonical"]');  
var base = canonical && canonical.href ? canonical.href : location.href;  
return normUrl(base);  
}  

function isEntryPage() {  
if (document.querySelector('.eMessage')) return true;  
if (document.querySelector('article, .entry, .post, .article-post')) return true;  
var og = document.querySelector('meta[property="og:type"][content="article"]');  
return !!og;  
}  

function findEntryNode() {  
return document.querySelector('article.article-post') ||  
document.querySelector('.article-post') ||  
document.querySelector('.post') ||  
document.querySelector('.entry') ||  
document.querySelector('.eMessage') ||  
document.querySelector('article');  
}  

if (!isEntryPage()) return;  

var entryNode = findEntryNode();  
if (!entryNode) return;  

var STORAGE_KEY = 'uc_read_flag:' + getPageKey();  

var prevRaw = localStorage.getItem(STORAGE_KEY);  
var prev = prevRaw ? safeJsonParse(prevRaw) : null;  

if (prev && prev.last && (nowMs() - prev.last) > KEEP_DAYS * 86400000) {  
localStorage.removeItem(STORAGE_KEY);  
prev = null;  
}  

if (prev && prev.last) {  
var el = document.createElement('div');  
el.className = 'uc-read-flag';  
el.innerHTML =  
'<div class="uc-read-flag__title">Вы уже читали эту страницу.</div>' +  
'<p class="uc-read-flag__meta">Последний визит: <b>' + formatDate(prev.last) + '</b>.</p>' +  
'<button class="uc-read-flag__btn" type="button">Скрыть</button>';  

el.querySelector('.uc-read-flag__btn').onclick = function () {  
el.remove();  
};  

entryNode.parentNode.insertBefore(el, entryNode);  
}  

setTimeout(function () {  
try {  
localStorage.setItem(STORAGE_KEY, JSON.stringify({ last: nowMs() }));  
} catch (e) {}  
}, SAVE_AFTER_MS);  

  })();  
  </script>


Если у тебя другой контейнер статьи, просто добавь его в функцию findEntryNode().
Например, если статья лежит в .article-post-content, добавь первой строкой:

Код
return document.querySelector('.article-post-content') || ...

Логика скрипта от этого не ломается.

Комментарии

Минимальная длина комментария - 50 знаков. комментарии модерируются
HTMLSTART » CSS3 - JS - SVG Примеры » Прочие скрипты для сайтов » Этот скрипт — это «умный индикатор прочтения» для страниц сайта