From f22849878b38795e72c4bec73d151401e587a31a Mon Sep 17 00:00:00 2001 From: NikDizell Date: Tue, 7 Apr 2026 21:55:48 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D1=83=20=D0=BE?= =?UTF-8?q?=D1=82=D0=BF=D0=B0=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=B7=D0=B0?= =?UTF-8?q?=D1=8F=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- programmer/static/programmer/css/styles.css | 57 +++++++++++ .../static/programmer/js/floating-button.js | 63 ++++++++++++ programmer/static/programmer/js/recall.js | 95 ++++++------------- programmer/templates/programmer/about.html | 6 +- programmer/templates/programmer/base.html | 53 +++++++++++ programmer/templates/programmer/index.html | 81 ++-------------- programmer/templates/programmer/recall.html | 16 +++- programmer/templates/programmer/solution.html | 1 - programmer/views.py | 6 ++ static/programmer/css/styles.css | 57 +++++++++++ static/programmer/js/floating-button.js | 63 ++++++++++++ static/programmer/js/recall.js | 95 ++++++------------- 12 files changed, 385 insertions(+), 208 deletions(-) create mode 100644 programmer/static/programmer/js/floating-button.js create mode 100644 static/programmer/js/floating-button.js diff --git a/programmer/static/programmer/css/styles.css b/programmer/static/programmer/css/styles.css index 356160e..d539e73 100644 --- a/programmer/static/programmer/css/styles.css +++ b/programmer/static/programmer/css/styles.css @@ -1695,4 +1695,61 @@ body { padding: 0.75rem; font-size: 1rem; border-radius: 8px; +} + +.floating-btn { + position: fixed; + bottom: 30px; + right: 30px; + z-index: 10000; + animation: fadeInUp 0.5s ease; +} + +.floating-btn .btn { + box-shadow: 0 4px 15px rgba(0,0,0,0.2); + border-radius: 50px; + padding: 12px 24px; + font-size: 1.1rem; + background: #ff7300; + color: white; + border: none; + cursor: pointer; + transition: transform 0.2s; +} + +.floating-btn .btn:hover { + transform: scale(1.05); + background: #0056b3; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Пульсация для кнопки */ +@keyframes pulse { + 0% { + transform: scale(1); + box-shadow: 0 0 0 0 rgba(255, 107, 0, 0.7); + } + 70% { + transform: scale(1.1); + box-shadow: 0 0 0 15px rgba(255, 107, 0, 0); + } + 100% { + transform: scale(1); + box-shadow: 0 0 0 0 rgba(255, 107, 0, 0); + } +} + +.floating-btn .btn.pulse { + animation: pulse 1.5s infinite; + will-change: transform; } \ No newline at end of file diff --git a/programmer/static/programmer/js/floating-button.js b/programmer/static/programmer/js/floating-button.js new file mode 100644 index 0000000..16d5613 --- /dev/null +++ b/programmer/static/programmer/js/floating-button.js @@ -0,0 +1,63 @@ +// static/programmer/js/floating-button.js +const CallbackModal = { + shown: false, + modalId: 'callbackModal', + floatingBtnId: 'floatingButton', + + init() { + setTimeout(() => { + const btn = document.getElementById(this.floatingBtnId); + if (btn) { + btn.style.display = 'block'; + this.shown = true; + const button = btn.querySelector('.btn'); + if (button) button.classList.add('pulse'); + } + }, 5000); + }, + + open() { + const modal = document.getElementById(this.modalId); + if (modal) { + modal.style.display = 'block'; + const floatingBtn = document.getElementById(this.floatingBtnId); + if (floatingBtn && this.shown) { + floatingBtn.style.display = 'none'; + } + } + }, + + close() { + const modal = document.getElementById(this.modalId); + if (modal) { + modal.style.display = 'none'; + const floatingBtn = document.getElementById(this.floatingBtnId); + if (floatingBtn && this.shown) { + floatingBtn.style.display = 'block'; + const button = floatingBtn.querySelector('.btn.pulse'); + if (button) { + button.style.animation = 'none'; + setTimeout(() => button.style.animation = '', 10); + } + } + } + } +}; + +// Инициализация и глобальные обработчики +document.addEventListener('DOMContentLoaded', () => { + CallbackModal.init(); + + // Закрытие по клику вне модального окна + const modal = document.getElementById(CallbackModal.modalId); + if (modal) { + modal.addEventListener('click', (event) => { + if (event.target === modal) CallbackModal.close(); + }); + } + + // Закрытие по ESC + document.addEventListener('keydown', (event) => { + if (event.key === 'Escape') CallbackModal.close(); + }); +}); \ No newline at end of file diff --git a/programmer/static/programmer/js/recall.js b/programmer/static/programmer/js/recall.js index b8f2c6e..8114615 100644 --- a/programmer/static/programmer/js/recall.js +++ b/programmer/static/programmer/js/recall.js @@ -1,74 +1,41 @@ -// recall.js - Скрипты для страницы отзывов -function openModal(imageUrl, title) { - console.log('Opening modal with:', imageUrl); - const modal = document.getElementById('imageModal'); - const modalImg = document.getElementById('modalImage'); - const modalTitle = document.getElementById('modalTitle'); +// static/programmer/js/recall.js +const ImageModal = { + modalId: 'imageModal', + imageId: 'modalImage', + titleId: 'modalTitle', - if (modal && modalImg) { - modal.style.display = "block"; - modalImg.src = imageUrl; - if (title && modalTitle) { - modalTitle.textContent = title; + open(imageUrl, title) { + const modal = document.getElementById(this.modalId); + const img = document.getElementById(this.imageId); + const titleEl = document.getElementById(this.titleId); + if (modal && img && titleEl) { + img.src = imageUrl; + img.alt = title || 'Просмотр изображения'; + titleEl.textContent = title || 'Просмотр изображения'; + modal.style.display = 'block'; } + }, - // Добавляем класс для анимации - setTimeout(() => { - modal.classList.add('active'); - }, 10); - - // Подстраиваем размер изображения - adjustModalImageSize(); + close() { + const modal = document.getElementById(this.modalId); + if (modal) { + modal.style.display = 'none'; + const img = document.getElementById(this.imageId); + if (img) img.src = ''; + } } -} +}; -function closeModal() { - const modal = document.getElementById('imageModal'); +// Обработчики для модального окна изображений +document.addEventListener('DOMContentLoaded', () => { + const modal = document.getElementById(ImageModal.modalId); if (modal) { - modal.classList.remove('active'); - setTimeout(() => { - modal.style.display = "none"; - }, 300); + modal.addEventListener('click', (event) => { + if (event.target === modal) ImageModal.close(); + }); } -} -function adjustModalImageSize() { - const modalImg = document.getElementById('modalImage'); - const modalContent = document.querySelector('.modal-content'); - - if (modalImg && modalContent) { - const maxWidth = window.innerWidth * 0.9; - const maxHeight = window.innerHeight * 0.8; - - modalImg.style.maxWidth = `${maxWidth}px`; - modalImg.style.maxHeight = `${maxHeight}px`; - } -} - -// Инициализация после загрузки DOM -document.addEventListener('DOMContentLoaded', function() { - // Закрытие модального окна при клике вне изображения - document.addEventListener('click', function(event) { - const modal = document.getElementById('imageModal'); - if (event.target === modal) { - closeModal(); - } + document.addEventListener('keydown', (event) => { + if (event.key === 'Escape') ImageModal.close(); }); - - // Закрытие по ESC - document.addEventListener('keydown', function(event) { - if (event.key === 'Escape') { - closeModal(); - } - }); - - // Адаптация размера изображения при изменении размера окна - window.addEventListener('resize', function() { - const modalImg = document.getElementById('modalImage'); - if (modalImg && modalImg.src) { - adjustModalImageSize(); - } - }); - - console.log('Recall page scripts initialized'); }); \ No newline at end of file diff --git a/programmer/templates/programmer/about.html b/programmer/templates/programmer/about.html index 696fa6d..012d056 100644 --- a/programmer/templates/programmer/about.html +++ b/programmer/templates/programmer/about.html @@ -1,4 +1,5 @@ {% extends 'programmer/base.html' %} +{% load static %} {% load django_bootstrap5 %} {% block content %} @@ -151,4 +152,7 @@ } -{% endblock %} \ No newline at end of file + + +{% endblock %} + diff --git a/programmer/templates/programmer/base.html b/programmer/templates/programmer/base.html index 413a25a..2704f39 100644 --- a/programmer/templates/programmer/base.html +++ b/programmer/templates/programmer/base.html @@ -322,6 +322,59 @@ + + + + + + {% bootstrap_javascript %} diff --git a/programmer/templates/programmer/index.html b/programmer/templates/programmer/index.html index f1966c1..f8cd6ac 100644 --- a/programmer/templates/programmer/index.html +++ b/programmer/templates/programmer/index.html @@ -1,4 +1,5 @@ {% extends 'programmer/base.html' %} +{% load static %} {% load django_bootstrap5 %} {% block content %} @@ -17,94 +18,28 @@
{{p.content}}
-
+
{% endfor %} {% endautoescape %} - - - {% if not posts %}

🚀 Контент скоро появится

Мы готовим для вас интересные материалы и кейсы

-
+
{% endif %} - -function closeModal() { - document.getElementById('callbackModal').style.display = 'none'; -} +{% block extra_js %} -// Закрытие модального окна при клике вне его -window.onclick = function(event) { - const modal = document.getElementById('callbackModal'); - if (event.target === modal) { - closeModal(); - } -} +{% endblock %} -// Закрытие по ESC -document.addEventListener('keydown', function(event) { - if (event.key === 'Escape') { - closeModal(); - } -}); - {% endblock %} \ No newline at end of file diff --git a/programmer/templates/programmer/recall.html b/programmer/templates/programmer/recall.html index 28ec69b..6b2a6cb 100644 --- a/programmer/templates/programmer/recall.html +++ b/programmer/templates/programmer/recall.html @@ -2,6 +2,7 @@ {% load django_bootstrap5 %} {% load static %} {% load seo_tags %} +{% load programmer_tags %} {% block extra_css %} @@ -59,7 +60,7 @@ Отзыв от {{ p.title }} + onclick="ImageModal.open('{{ p.scan.url }}', '{{ p.title }}')">
🔍 Нажмите для увеличения @@ -88,15 +89,12 @@
{% endif %} - - -