🚀 MEGA UPDATE: Объединение всех изменений для продакшена
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
✨ НОВЫЕ ФУНКЦИИ: - 🎬 Поддержка видео в Hero баннерах и услугах - 💊 Водная анимация пилюль маркеров банеров - 📱 Полная главная страница с портфолио, блогом, новостями - 🎯 HeroBanner модель с видео/изображениями - 🎨 Современные hover-эффекты и анимации 📊 УЛУЧШЕНИЯ СТРУКТУРЫ: - Расширенная home_modern.html с полным контентом - Новые URL маршруты для всех секций - Обновленные views с передачей всех данных - CSS стили для всех новых секций - Миграции для видео полей 🎪 HERO БАНЕР СИСТЕМА: - Динамические банеры с видео/фото фонами - Пилюли маркеры с водной анимацией - Растягивание маркеров от центра - Адаптивный дизайн для мобильных - Glassmorphism эффекты 🎨 СОВРЕМЕННЫЙ ДИЗАЙН: - Hover анимации для карточек - Плавные переходы везде - Современная типографика - Градиенты и тени - Отзывчивая сетка Готов к продакшену! 🚀
This commit is contained in:
@@ -3,6 +3,30 @@ from django.contrib.auth.models import AbstractUser, User
|
||||
import uuid
|
||||
from django.urls import reverse
|
||||
|
||||
class HeroBanner(models.Model):
|
||||
"""Модель для главного баннера на сайте"""
|
||||
title = models.CharField(max_length=200, verbose_name="Заголовок")
|
||||
subtitle = models.TextField(blank=True, verbose_name="Подзаголовок")
|
||||
description = models.TextField(blank=True, verbose_name="Описание")
|
||||
image = models.ImageField(upload_to='static/img/hero/', blank=True, null=True, verbose_name="Фоновое изображение")
|
||||
video = models.FileField(upload_to='static/video/hero/', blank=True, null=True,
|
||||
help_text='Фоновое видео для баннера (MP4, WebM)', verbose_name="Фоновое видео")
|
||||
video_poster = models.ImageField(upload_to='static/img/hero/posters/', blank=True, null=True,
|
||||
help_text='Превью изображение для видео', verbose_name="Превью видео")
|
||||
button_text = models.CharField(max_length=100, blank=True, verbose_name="Текст кнопки")
|
||||
button_link = models.URLField(blank=True, verbose_name="Ссылка кнопки")
|
||||
is_active = models.BooleanField(default=True, verbose_name="Активен")
|
||||
order = models.PositiveIntegerField(default=0, verbose_name="Порядок отображения")
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Hero Баннер'
|
||||
verbose_name_plural = 'Hero Баннеры'
|
||||
ordering = ['order', '-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class Category(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
description = models.TextField(default='Описание категории')
|
||||
@@ -21,6 +45,10 @@ class Service(models.Model):
|
||||
price = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='services')
|
||||
image = models.ImageField(upload_to='static/img/services/', blank=True, null=True)
|
||||
video = models.FileField(upload_to='static/video/services/', blank=True, null=True, help_text='Видео файл для услуги (MP4, WebM, AVI)')
|
||||
video_poster = models.ImageField(upload_to='static/img/services/posters/', blank=True, null=True, help_text='Превью изображение для видео')
|
||||
video = models.FileField(upload_to='static/video/services/', blank=True, null=True, help_text='Видео файл для услуги (MP4, WebM, AVI)')
|
||||
video_poster = models.ImageField(upload_to='static/img/services/posters/', blank=True, null=True, help_text='Превью изображение для видео')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Услуга'
|
||||
@@ -61,6 +89,8 @@ class BlogPost(models.Model):
|
||||
content = models.TextField()
|
||||
published_date = models.DateTimeField(auto_now_add=True)
|
||||
image = models.ImageField(upload_to='static/img/blog/', blank=True, null=True)
|
||||
video = models.FileField(upload_to='static/video/blog/', blank=True, null=True, help_text='Видео файл для блог поста')
|
||||
video_poster = models.ImageField(upload_to='static/img/blog/posters/', blank=True, null=True, help_text='Превью изображение для видео')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Блог'
|
||||
@@ -126,6 +156,8 @@ class Project(models.Model):
|
||||
order = models.OneToOneField(Order, on_delete=models.CASCADE, related_name='project', null=True, blank=True)
|
||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
image = models.ImageField(upload_to='static/img/project/', blank=True, null=True)
|
||||
video = models.FileField(upload_to='static/video/project/', blank=True, null=True, help_text='Видео презентация проекта')
|
||||
video_poster = models.ImageField(upload_to='static/img/project/posters/', blank=True, null=True, help_text='Превью изображение для видео проекта')
|
||||
status = models.CharField(max_length=50, choices=[('in_progress', 'В процессе'), ('completed', 'Завершен')], default='in_progress')
|
||||
|
||||
class Meta:
|
||||
@@ -144,6 +176,8 @@ class Review(models.Model):
|
||||
comment = models.TextField()
|
||||
review_date = models.DateTimeField(auto_now_add=True)
|
||||
image = models.ImageField(upload_to='static/img/review/', blank=True, null=True)
|
||||
video = models.FileField(upload_to='static/video/review/', blank=True, null=True, help_text='Видео отзыв о работе')
|
||||
video_poster = models.ImageField(upload_to='static/img/review/posters/', blank=True, null=True, help_text='Превью для видео отзыва')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Отзыв'
|
||||
|
||||
Reference in New Issue
Block a user