diff --git a/dicquo/templates/base.html b/dicquo/templates/base.html
index 1a116c9..8184fd2 100644
--- a/dicquo/templates/base.html
+++ b/dicquo/templates/base.html
@@ -1,58 +1,34 @@
-
-{% load static %}
+{% load static %}
+
-
-
-
-
-
-
-
- {% if DQ.szIntroHTML %}
-
{{ DQ.szIntroHTML|safe }}
- {% endif %}
-
-
-
- {{ DQ.szContentHTML|safe }}
-
-
-
-
-
- {% if AUTHOR %}
- {{ AUTHOR.szAuthorHTML|default:AUTHOR.szAuthor|safe }}
- {% endif %}
-
+{% block CONTENT %}
{# Основной контент: Текст + Картинка #}
+ {# Текстовая ряб. Задает высоту двум колонкам: текст и картина #}
+ {# КОЛОНКА С ТЕКСТОМ #}{% if DQ.szIntroHTML %}
+ {# Интро/Вступление (например "Вася Пупкин как-то сказа". Может отсутствовать #}{{ DQ.szIntroHTML|safe }}
{% endif %}
+ {{ DQ.szContentHTML|safe }} {% if AUTHOR %}
+ {# Автор #}{{ AUTHOR.szAuthorHTML|default:AUTHOR.szAuthor|safe }} {% endif %}
+ {% if IMAGE %}
+ {# КОЛОНКА С КАРТИНКОЙ #}
+
+
+
+
-
-
-
- {% if IMAGE %}
-
- {% endif %}
-
-
-
-
{% endif %}
+
+
+
+
-
-
-
-
-
-
-
-
-{% if not cookie_accept %}{% include "blocks/cookie_warning.html" %}{% endif %}
-{% endblock %}
+
+
+
+
+ {% endblock %}
\ No newline at end of file
diff --git a/public/static/css/dicquo.css b/public/static/css/dicquo.css
index ccd2bde..6ef89ba 100644
--- a/public/static/css/dicquo.css
+++ b/public/static/css/dicquo.css
@@ -1,143 +1,11 @@
@charset "utf-8";
-
-.tags{
- color: silver;
- font-size:1.5vh;
- line-height:1.9vh;
- padding-top: 7vh;
-}
-
-/*****************************************************************
- * Настройки для анимирования цвета ссылок:
- * рецепт взят из: https://habr.com/ru/company/ruvds/blog/491702/
- *****************************************************************/
-.tags a {
- text-decoration: none;
- position: relative;
- padding: 0 0.5ex;
- display: inline-block;
- color: white;
- border-bottom: dotted 1px silver;
- /* градиент для цвета ссылки */
- background: linear-gradient(to right, rgba(255,255,255,0.9) 40%, slategray, silver, lightyellow 50%, rgba(255,255,255,0.4));
- /* обрезка градиента */
- background-clip: initial;
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-size: 250% 100%;
- -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
- background-position: 100%;
- /* плавное позиионирование градиента */
- transition: background-position 0.65s ease;
- margin-right: 2vh;
-}
-
-.tags a:hover {
- color: white;
- background-position: 0 100%;
- border-bottom: solid 1px white;
-}
-
-div[name="cookies_accept"] {
- font-family:'Roboto', 'Lucida Grande', Verdana, Arial, sans-serif;
- position:fixed;
- bottom: 0; left: 0;
- width: 100%;
- padding: 2vh 2vw;
- color: black;
- background-color: gray;
- text-align: center;
-}
-
-div[name="cookies_accept"] button {
- padding:0.5vh 0.5vw;
- background: silver;
- color: black;
- margin-left: 2vw;
- cursor: pointer;
-}
-
-#logo {
- margin-top:1vh;
- filter: alpha(Opacity=75); /* Полупрозрачность для IE */
- opacity: 0.75;
- float: left;
-}
-
-#logo a {
- border: none;
- text-decoration: none;
-}
-
-table { width: 80%; }
-
-#menu {
- display: none;
- color: silver;
-}
-
-#mm {
- text-decoration: none;
- color: silver;
-}
-
-#image {
- width: 30vw;
- text-align: center;
- vertical-align: center;
-}
-
-#image > center > div {
- width: 22vw;
- height: 22vw;
- padding:0.5vw;
- border-radius: 50%;
-}
-
-#image > center > div > div {
- border-radius:50%;
- overflow: hidden;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-#image > center > div > div > img {
- width: auto;
- height: 22vw;
-}
-
-#author {
- color: silver;
- font-size: 3.5vh;
- line-height: 4vh;
- text-align: right;
- padding-top: 4vh;
- font-style: italic;
-}
-
-#info {
- color: silver;
- font-size: 2.5vh;
- line-height: 3vh;
- padding-bottom: 2vh;
-}
-
-#bb {
- color: whitesmoke;
- font-size: 4.5vh;
- line-height: 5vh
-}
-
-#next { float: right; }
-
-#next a { border-bottom: none; }
-
-/* --- NEW STYLES for FLEXBOX LAYOUT --- */
-.container {
- width: 90%;
- max-width: 1200px;
- margin: 0 auto;
+body {
+ margin: 0;
+ min-height: 100vh;
+ min-width: 100vw;
+ background-color: #111; /* Изначально темный фон */
+ opacity: 0; /* Скрываем контент до расчета цвета */
+ transition: opacity 0.9s ease-in-out; /* Очень плавное появление */
}
/* Header */
@@ -145,46 +13,101 @@ header {
display: flex;
justify-content: space-between;
align-items: center;
- padding: 1vh 0;
+ padding: 1vh 4vw;
}
-/* Main Content Area */
-.main-content {
- display: flex;
- flex-direction: column;
- justify-content: center;
- min-height: 80vh;
+header > #logo {
+ margin-top: 1vh;
+ float: left;
}
-.content-row {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 2vw;
+header > #logo a {
+ border: none;
+ text-decoration: none;
}
-.text-col {
- flex: 1;
+header > #logo a > img {
+ width:50px;
+ height:46px;
}
-.image-col {
- flex: 0 0 30vw;
- display: flex;
- justify-content: center;
+header > nav {
+ border: #555555;
+ min-height: 50px;
}
-/* --- Icons for Header Stats (SVG in Base64) --- */
-.stats-icon {
+header > nav > a { /* бургер */
+ color: silver;
+ text-decoration: none;
+ font-size: 1.2em;
+ padding: 0 0.5em;
+ margin-right: -0.5em;
+ border: solid 1px transparent;
+ transition: border-color 0.8s ease, color 0.8s ease;
+ vertical-align: top;
+}
+
+header > nav > a:hover {
+ color: white;
+ border: solid 1px silver;
+ transition: border-color 0.8s ease, color 0.8s ease;
+}
+
+header > nav > #stats-menu {
+ display: none;
+ color: silver;
+ font-size: 0.9em;
+ margin-right: 15px;
+ text-align: right;
+ vertical-align: top;
+}
+
+header > nav > #stats-menu > b {
+ font-weight: normal;
+ margin: 0 1ex;
+}
+
+header > nav > #stats-menu > p {
+ font-style: italic; display: inline-block;
+ margin: 0 1vw;
+ padding-right: 1vw;
+ border-right: 1px dotted silver;
+}
+
+header > nav > #stats-menu > i.stats-icon {
display: inline-block;
width: 0.9em;
height: 0.9em;
vertical-align: middle;
background-size: contain;
background-repeat: no-repeat;
- margin-right: 0.2em;
+ margin-right: .2em;
opacity: 0.7; /* Slight transparency for subtle look */
}
+header > nav > #stats-menu > i.stats-icon.icon-views {
+ margin-left: .2em;
+}
+
+
+header > nav > #stats-menu > a {
+ color: silver;
+ text-decoration: none;
+ border: solid 1px gray;
+ border-radius: 2em;
+ padding: 1.5px 0.2em 0 0.2em;
+ margin-left: 1em;
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+header > nav > #stats-menu > a:hover {
+ background-color: tan;
+ color: black;
+ border: solid 1px white;
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+/* --- Icons for Header Stats (SVG in Base64) --- */
/* Clock Icon (Time) */
.icon-time {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='silver' fill='none' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");
@@ -195,30 +118,194 @@ header {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='silver' fill='none' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3C/svg%3E");
}
-/* Responsive: on mobile stack columns */
+/* MAIN ARTICLE CONTENT */
+main {
+ /*justify-content: space-between;*/
+ /*align-items: center;*/
+ padding: 1vh 8vw;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ min-height: 60vh;
+ /*width: 90%;*/
+ /*max-width: 1200px;*/
+ /*margin: 0 auto;*/
+}
+
+main > article {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 2vw;
+}
+
+main > article > figure {
+ flex: 1;
+}
+
+main > article > figure > p { /* Интро/Вступление */
+ color: silver;
+ font-size: 3vmin;
+ line-height: 3.5vmin;
+ padding-bottom: 2vmin;
+ font-style: italic;
+}
+
+main > article > figure > blockquote { /* Цитата */
+ color: whitesmoke;
+ font-size: 4.5vmin;
+ line-height: 5vmin;
+ border:none;
+ margin:0;
+ padding:0;
+}
+
+main > article > figure > cite { /* Автор цитаты */
+ color: silver;
+ font-size: 3.5vmin;
+ line-height: 4vmin;
+ text-align: right;
+ padding-top: 4vmin;
+ font-style: italic;
+}
+
+main > article > div {
+ flex: 0 0 30vw;
+ display: flex;
+ justify-content: center;
+ width: 30vw;
+ text-align: right;
+ margin-bottom: 10vh;
+}
+
+main > article > div > div {
+ width: 26vmax;
+ height: 26vmax;
+ padding: 0.5vw;
+ border-radius: 50%;
+}
+
+main > article > div > div > div {
+ border-radius: 50%;
+ overflow: hidden;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+main > article > div > div > div > img {
+ width: auto;
+ height: 26vmax;
+}
+
+/* НАВИГАЦИЯ (ТЕГИ И ДАЛЕЕ) В КОНЦЕ */
+nav {
+ padding: 1vh 4vw;
+}
+nav > div {
+ color: silver;
+ font-size: 1.5vmin;
+ line-height: 1.9vmin;
+ padding-top: 7vh;
+}
+nav > div a {
+ text-decoration: none;
+ position: relative;
+ padding: 0 0.5ex;
+ display: inline-block;
+ color: white;
+ border-bottom: dotted 1px silver;
+ /* градиент для цвета ссылки */
+ background: linear-gradient(to right, rgba(255, 255, 255, 0.9) 40%, slategray, silver, lightyellow 50%, rgba(255, 255, 255, 0.4));
+ /* обрезка градиента */
+ background-clip: initial;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-size: 250% 100%;
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
+ background-position: 100%;
+ /* плавное позиионирование градиента */
+ transition: background-position 0.65s ease;
+ margin-right: 2vmin;
+}
+
+nav > div a:hover {
+ color: white;
+ background-position: 0 100%;
+ border-bottom: solid 1px white;
+}
+
+nav > div > div {
+ float: right;
+}
+
+nav > div > div a {
+ border-bottom: none;
+}
+
+/* --- ПОДВАЛ-КУКИ (ДЗЕН-СТИЛЬ) --- */
+footer {
+ font-family: 'Roboto', sans-serif;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ padding: 2vh 4vw;
+ color: silver; /* Мягкий серый цвет текста */
+ background-color: rgba(30, 30, 30, 0.8); /* Темный полупрозрачный фон */
+ backdrop-filter: blur(5px); /* Эффект матового стекла (современно и медитативно) */
+ text-align: center;
+ border-top: 1px solid #444; /* Тонкая грань */
+ font-size: 0.9em;
+ z-index: 1000; /* Чтобы точно было поверх всего */
+}
+
+footer small {
+ display: inline-block;
+ margin-right: 2vw;
+ letter-spacing: 0.05em; /* Немного воздуха в тексте */
+}
+
+footer button {
+ padding: 0.5vh 1.5vw;
+ background: transparent;
+ color: silver;
+ border: 1px solid silver;
+ border-radius: 2em; /* Округлые, мягкие формы */
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.9em;
+ transition: all 0.4s ease;
+}
+
+footer button:hover {
+ background: silver;
+ color: #111;
+ box-shadow: 0 0 10px rgba(255, 255, 255, 0.2); /* Легкое свечение при наведении */
+}
+
+/* Отзывчивость: для мобильных устройств колонки свапаются */
@media (max-width: 768px) {
- .content-row {
+ main > article {
flex-direction: column-reverse;
}
- .image-col {
+
+ main > article > div {
flex: 0 0 auto;
margin-bottom: 2vh;
}
}
/* --- ВЫРАВНИВАНИЕ СИМВОЛОВ ВИСЯЧЕЙ ПУНКТУАЦИИ (Hanging Punctuation) ТИПОГРАФА ETPGRF --- */
-/* --- ЛЕВЫЕ ВИСЯЧИЕ СИМВОЛЫ (выравнивание по левому краю) --- */
-.etp-laquo { margin-left: -0.44em; } /* « */
-.etp-ldquo, .etp-bdquo { margin-left: -0.4em; } /* “ „ */
-.etp-lsquo { margin-left: -0.22em; } /* ‘ */
-.etp-lpar, .etp-lsqb, .etp-lcub { margin-left: -0.25em; } /* ( [ { */
+/* --- В ПРОЕКТЕ ТОЛЬКО ЛЕВЫЕ ВИСЯЧИЕ СИМВОЛЫ (выравнивание по левому краю) --- */
+.etp-laquo {margin-left: -0.44em;} /* « */
+.etp-ldquo, .etp-bdquo { margin-left: -0.4em;} /* “ „ */
+.etp-lsquo {margin-left: -0.22em;} /* ‘ */
+.etp-lpar, .etp-lsqb, .etp-lcub {margin-left: -0.25em;}/* ( [ { */
-/* --- ПРАВЫЕ ВИСЯЧИЕ СИМВОЛЫ (выравнивание по правому краю) --- */
-/* Общая механика: "вырываем" символ из потока для идеального выравнивания текста */
-[class^="etp-r"], [class*=" etp-r"] { position: absolute; }
-/* Точечная настройка смещения для каждого символа */
-.etp-raquo { right: -0.44em; } /* » */
-.etp-rdquo { right: -0.4em; } /* ” */
-.etp-rsquo { right: -0.22em; } /* ’ */
-.etp-rpar, .etp-rsqb, .etp-rcub { right: -0.25em; } /* ) ] } */
-.etp-r-dot, .etp-r-comma, .etp-r-colon { right: -0.15em; } /* . , : */
+/* --- СЧЕТЧИКИ (СКРЫТЫЙ ПИКСЕЛЬ) --- */
+.counter-pixel {
+ border: 0;
+ position: absolute;
+ left: -9999px;
+}
diff --git a/public/static/js/bg-generator.js b/public/static/js/bg-generator.js
index 4c31786..94017ad 100644
--- a/public/static/js/bg-generator.js
+++ b/public/static/js/bg-generator.js
@@ -1,25 +1,29 @@
-// bg-generator.js: Generates a unique gradient background based on text content
+// bg-generator.js:
+// - Генерирует уникальный градиентный фон на основе текстового содержимого
+// - Реализует плавное появление и исчезновение при навигации
+// - Авто-редирект через 15 секунд для создания "медитативного" слайд-шоу эффекта
+// - Обрабатывает принятие Cookie
document.addEventListener("DOMContentLoaded", function() {
- // 1. Get the text to hash (from hidden span in base.html)
+ // 1. Получаем текст для хеширования (из скрытого span в base.html)
const rawSpan = document.getElementById('dq-content-raw');
let text = rawSpan ? rawSpan.innerText.trim() : "";
if (!text) {
- text = "DictumAndQuotesDefault" + Math.random(); // Fallback random if no text
+ text = "DictumAndQuotesDefault" + Math.random(); // Случайный вариант, если текста нет
}
- // 2. Hash function (DJB2)
+ // 2. Хеш-функция (DJB2)
let hash = 5381;
for (let i = 0; i < text.length; i++) {
- // Force 32-bit integer arithmetic
+ // Принудительная 32-битная целочисленная арифметика
hash = ((hash << 5) + hash) + text.charCodeAt(i);
- hash = hash & hash; // Convert to 32bit integer
+ hash = hash & hash; // Преобразование в 32-битное целое
}
- // 3. Generate 6 color components deterministically from the hash
- // We need 6 numbers between 0 and 255.
- // Let's use pseudo-random generator seeded by hash
+ // 3. Детерминированная генерация 6 цветовых компонентов из хеша
+ // Нам нужно 6 чисел от 0 до 255.
+ // Используем генератор псевдослучайных чисел с затравкой из хеша
function Mulberry32(a) {
return function() {
@@ -30,53 +34,53 @@ document.addEventListener("DOMContentLoaded", function() {
}
}
- const rand = Mulberry32(hash); // Seeded random generator
+ const rand = Mulberry32(hash); // Генератор случайных чисел с seed
- // Generate 6 color components with darker range for "meditative" feel
+ // Генерация 6 цветовых компонентов в темном диапазоне для "медитативного" ощущения
let colors = [];
for(let i=0; i<6; i++) {
- // Generate number between 10 and 80 (dark colors)
+ // Генерируем число от 10 до 80 (темные цвета)
colors.push(Math.floor(rand() * 70) + 10);
}
- // Shuffle slightly based on random to allow variation on refresh (optional)
- // colors.sort(() => Math.random() - 0.5);
+ // Немного перетасовываем на основе случайности, чтобы позволить вариации при обновлении (опционально)
+ colors.sort(() => Math.random() - 0.5);
const rgb1 = `rgb(${colors[0]}, ${colors[1]}, ${colors[2]})`;
const rgb2 = `rgb(${colors[3]}, ${colors[4]}, ${colors[5]})`;
console.log("DQ BG Generator:", text.substring(0, 20) + "...", hash, rgb1, rgb2);
- // 4. Apply to body
- // Using linear-gradient to right with standard syntax
+ // 4. Применяем к body.
+ // Используем линейный градиент вправо со стандартным синтаксисом
const bgString = `linear-gradient(90deg, ${rgb1} 0%, ${rgb2} 100%)`;
document.body.style.background = bgString;
- // 5. Apply to image background container (if exists on index page)
+ // 5. Применяем к контейнеру фона изображения (если он есть на главной странице)
const imgBgContainer = document.querySelector('.image-col center > div');
if (imgBgContainer) {
- // Use the first color of the gradient with opacity 0.7
+ // Используем первый цвет градиента с прозрачностью 0.7
imgBgContainer.style.background = `rgba(${colors[0]}, ${colors[1]}, ${colors[2]}, 0.7)`;
}
- // 6. Reveal content (Fade In effect)
+ // 6. Показываем контент (эффект плавного появления - Fade In)
setTimeout(() => {
document.body.style.opacity = 1;
}, 50);
- // 7. Handle Fade Out on link clicks
+ // 7. Обработка плавного исчезновения (Fade Out) при клике по ссылкам
document.body.addEventListener('click', function(e) {
- // Find if a link was clicked (bubble up)
+ // Ищем, была ли нажата ссылка (всплытие)
const link = e.target.closest('a');
if (link && link.href && link.target !== '_blank') {
const hrefAttr = link.getAttribute('href');
if (hrefAttr && !hrefAttr.startsWith('#') && !link.href.includes('javascript:')) {
- // Check if it is an internal link (same domain)
+ // Проверяем, является ли ссылка внутренней (тот же домен)
if (new URL(link.href).origin === window.location.origin) {
- e.preventDefault(); // Stop immediate navigation
- document.body.style.opacity = 0; // Start Fade Out
+ e.preventDefault(); // Останавливаем немедленный переход
+ document.body.style.opacity = 0; // Запускаем Fade Out
- // Wait for transition (matches CSS transition time 1.5s)
+ // Ждем завершения перехода (соответствует времени CSS transition 0.9s (было 1.5s))
setTimeout(() => {
window.location.href = link.href;
}, 900);
@@ -85,14 +89,28 @@ document.addEventListener("DOMContentLoaded", function() {
}
});
- // 8. Auto-redirect ("meditative" slideshow)
- // Find the NEXT link and simulate a click on it after 15 seconds
+ // 8. Авто-редирект ("медитативное" слайд-шоу)
+ // Ищем ссылку "ДАЛЕЕ" и симулируем клик по ней через 15 секунд
const nextLink = document.querySelector('#next a');
if (nextLink) {
setTimeout(() => {
- // Trigger the click event on the link so our handler above (step 7) catches it
- // and performs the smooth fade out animation.
+ // Вызываем событие клика по ссылке, чтобы наш обработчик выше (шаг 7) поймал его
+ // и выполнил анимацию плавного исчезновения.
nextLink.click();
}, 15000);
}
+
+ // 9. Логика принятия Cookie
+ const cookieBanner = document.querySelector('footer');
+ if (cookieBanner) {
+ const acceptButton = cookieBanner.querySelector('button');
+ if (acceptButton) {
+ acceptButton.addEventListener('click', function() {
+ const date = new Date();
+ date.setTime(date.getTime() + (92 * 24 * 60 * 60 * 1000)); // ~3 месяца (7948800000ms)
+ document.cookie = "cookie_accept=1; expires=" + date.toUTCString() + "; path=/; SameSite=Lax";
+ cookieBanner.remove();
+ });
+ }
+ }
});
diff --git a/public/static/js/counters.js b/public/static/js/counters.js
new file mode 100644
index 0000000..16db91f
--- /dev/null
+++ b/public/static/js/counters.js
@@ -0,0 +1,22 @@
+// Rating Mail.ru counter
+var _tmr = window._tmr || (window._tmr = []);
+_tmr.push({id: "3744288", type: "pageView", start: (new Date()).getTime()});
+(function (d, w, id) {
+ if (d.getElementById(id)) return;
+ var ts = d.createElement("script");
+ ts.type = "text/javascript";
+ ts.async = true;
+ ts.id = id;
+ ts.src = "https://top-fwz1.mail.ru/js/code.js";
+ var f = function () {
+ var s = d.getElementsByTagName("script")[0];
+ s.parentNode.insertBefore(ts, s);
+ };
+ if (w.opera == "[object Opera]") {
+ d.addEventListener("DOMContentLoaded", f, false);
+ } else {
+ f();
+ }
+})(document, window, "tmr-code");
+// //Rating Mail.ru counter
+