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 @@
+
+
🚀 Контент скоро появится
Мы готовим для вас интересные материалы и кейсы
-
+
{% 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 @@

+ onclick="ImageModal.open('{{ p.scan.url }}', '{{ p.title }}')">
🔍
Нажмите для увеличения
@@ -88,15 +89,12 @@
{% endif %}
-
-
-
![]()
@@ -104,4 +102,12 @@
+
+
+
+{% block extra_js %}
+
+{% endblock %}
+
+
{% endblock %}
\ No newline at end of file
diff --git a/programmer/templates/programmer/solution.html b/programmer/templates/programmer/solution.html
index 62ec156..957a2e4 100644
--- a/programmer/templates/programmer/solution.html
+++ b/programmer/templates/programmer/solution.html
@@ -46,7 +46,6 @@
window.totalPages = {{ paginator.num_pages }};
-
{% endblock %}
{% block extra_js %}
diff --git a/programmer/views.py b/programmer/views.py
index 68457b7..8c0bac4 100644
--- a/programmer/views.py
+++ b/programmer/views.py
@@ -102,8 +102,10 @@ class AboutPageView(BasePageView, BreadcrumbMixin):
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
+ form = CallbackForm()
context.update({
+ 'form': form,
'title': "Программист 1С Николай Сердюк - 10+ лет опыта | Услуги 1С",
'meta_description': (
"Николай Сердюк - сертифицированный программист 1С с 10+ лет опыта. "
@@ -135,8 +137,10 @@ class SolutionListView(BaseListView, BreadcrumbMixin):
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
+ form = CallbackForm()
context.update({
+ 'form': form,
'title': "Проекты автоматизации 1С | Реализованные кейсы и решения",
'meta_description': (
"Реализованные проекты по автоматизации 1С: складской учет с ТСД, "
@@ -167,8 +171,10 @@ class RecallListView(BaseListView, BreadcrumbMixin):
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
+ form = CallbackForm()
context.update({
+ 'form': form,
'title': "Отзывы клиентов о работе программиста 1С | Реальные кейсы",
'meta_description': (
"Реальные отзывы клиентов о работе программиста 1С Николая Сердюка. "
diff --git a/static/programmer/css/styles.css b/static/programmer/css/styles.css
index 356160e..d539e73 100644
--- a/static/programmer/css/styles.css
+++ b/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/static/programmer/js/floating-button.js b/static/programmer/js/floating-button.js
new file mode 100644
index 0000000..16d5613
--- /dev/null
+++ b/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/static/programmer/js/recall.js b/static/programmer/js/recall.js
index b8f2c6e..8114615 100644
--- a/static/programmer/js/recall.js
+++ b/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