diff --git a/create_hero_banner.py b/create_hero_banner.py new file mode 100644 index 0000000..135b6c4 --- /dev/null +++ b/create_hero_banner.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +""" +Создание тестового Hero баннера с видео +""" + +import os +import sys + +# Добавляем путь к Django проекту +sys.path.append('/home/data/smartsoltech.kr/smartsoltech') + +# Настройка Django +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'smartsoltech.settings') + +import django +django.setup() + +from web.models import HeroBanner + +def create_hero_banner(): + """Создает тестовый Hero баннер с видео""" + + # Создаем баннер с видео + hero_video = HeroBanner.objects.create( + title="Smart Solutions для вашего бизнеса", + subtitle="Профессиональная разработка и внедрение IT-решений", + description="Мы создаем инновативные технологические решения, которые помогут вашему бизнесу достичь новых высот эффективности и успеха.", + button_text="Получить консультацию", + button_link="/contact/", + video="static/video/hero/hero-demo.mp4", + is_active=True, + order=1 + ) + + # Создаем баннер с изображением (fallback) + hero_image = HeroBanner.objects.create( + title="Цифровые решения нового поколения", + subtitle="Автоматизация, интеграция, оптимизация", + description="Трансформируйте свой бизнес с помощью наших передовых IT-решений и экспертного подхода к каждому проекту.", + button_text="Наши услуги", + button_link="/services/", + image="static/img/about/about-1.jpg", + is_active=True, + order=2 + ) + + print(f"✅ Создан Hero баннер с видео: {hero_video.title}") + print(f"✅ Создан Hero баннер с изображением: {hero_image.title}") + + # Показываем все активные баннеры + active_banners = HeroBanner.objects.filter(is_active=True).order_by('order') + print(f"\n📋 Всего активных баннеров: {active_banners.count()}") + for banner in active_banners: + media_type = "🎬 Видео" if banner.video else "🖼️ Изображение" + print(f" {banner.order}. {banner.title} ({media_type})") + +if __name__ == "__main__": + create_hero_banner() \ No newline at end of file diff --git a/hero_script.py b/hero_script.py new file mode 100644 index 0000000..d1979db --- /dev/null +++ b/hero_script.py @@ -0,0 +1,35 @@ +from web.models import HeroBanner + +# Создаем баннер с видео +hero_video = HeroBanner.objects.create( + title="Smart Solutions для вашего бизнеса", + subtitle="Профессиональная разработка и внедрение IT-решений", + description="Мы создаем инновативные технологические решения, которые помогут вашему бизнесу достичь новых высот эффективности и успеха.", + button_text="Получить консультацию", + button_link="/contact/", + video="static/video/hero/hero-demo.mp4", + is_active=True, + order=1 +) + +# Создаем баннер с изображением (fallback) +hero_image = HeroBanner.objects.create( + title="Цифровые решения нового поколения", + subtitle="Автоматизация, интеграция, оптимизация", + description="Трансформируйте свой бизнес с помощью наших передовых IT-решений и экспертного подхода к каждому проекту.", + button_text="Наши услуги", + button_link="/services/", + image="static/img/about/about-1.jpg", + is_active=True, + order=2 +) + +print(f"✅ Создан Hero баннер с видео: {hero_video.title}") +print(f"✅ Создан Hero баннер с изображением: {hero_image.title}") + +# Показываем все активные баннеры +active_banners = HeroBanner.objects.filter(is_active=True).order_by('order') +print(f"\n📋 Всего активных баннеров: {active_banners.count()}") +for banner in active_banners: + media_type = "🎬 Видео" if banner.video else "🖼️ Изображение" + print(f" {banner.order}. {banner.title} ({media_type})") \ No newline at end of file diff --git a/original_home_modern.html b/original_home_modern.html new file mode 100644 index 0000000..1cec7f3 --- /dev/null +++ b/original_home_modern.html @@ -0,0 +1,361 @@ +{% extends 'web/base_modern.html' %} +{% load static %} +{% block title %}SmartSolTech - Современные IT-решения для вашего бизнеса{% endblock %} + +{% block content %} + +
+
+
+
+
+

+ Создаем будущее вашего бизнеса +

+

+ Мы разрабатываем современные веб-приложения, мобильные решения и системы автоматизации, + которые помогают компаниям расти и быть конкурентоспособными. +

+ +
+
+
+

50+

+

Проектов

+
+
+
+
+

3+

+

Лет опыта

+
+
+
+
+

24/7

+

Поддержка

+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
def create_future():
+
return innovation + passion
+
// SmartSolTech
+
+
+ + +
+
+ +
Мобильные
+

приложения

+
+
+ + +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+
+

+ Полный спектр IT-услуг +

+

+ От идеи до реализации - мы предоставляем комплексные решения для вашего цифрового успеха +

+
+ +
+ {% for service in services %} +
+
+ +
+

{{ service.name }}

+

{{ service.description|truncatewords:20 }}

+ + Подробнее + +
+ {% endfor %} +
+ + +
+
+ + +
+
+
+
+
+

+ Ваш надежный IT-партнер +

+

+ Мы не просто выполняем проекты - мы создаем долгосрочные партнерские отношения + и помогаем бизнесу расти с помощью технологий. +

+ +
+
+
+ +
+
+
Быстрая разработка
+

Agile-методология и современные инструменты для быстрой доставки результата

+
+
+ +
+
+ +
+
+
Высокое качество
+

Тщательное тестирование и code review обеспечивают надежность решений

+
+
+ +
+
+ +
+
+
24/7 Поддержка
+

Постоянная техническая поддержка и сопровождение проектов

+
+
+
+
+
+
+
+ +
+
+
+
+ 1 +
+
+
Анализ требований
+

Детальное изучение ваших потребностей

+
+
+
+ +
+
+
+ 2 +
+
+
Проектирование
+

Создание архитектуры и дизайна

+
+
+
+ +
+
+
+ 3 +
+
+
Разработка
+

Программирование и тестирование

+
+
+
+ +
+
+
+ 4 +
+
+
Запуск и поддержка
+

Деплой и техническая поддержка

+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+

+ Готовы начать свой проект? +

+

+ Свяжитесь с нами сегодня и получите бесплатную консультацию по вашему проекту +

+ +
+
+
+
+{% endblock %} + +{% block extra_scripts %} + + + +{% endblock %} \ No newline at end of file diff --git a/smartsoltech/static/assets/css/modern-styles.css b/smartsoltech/static/assets/css/modern-styles.css index 2c92861..802ed6a 100644 --- a/smartsoltech/static/assets/css/modern-styles.css +++ b/smartsoltech/static/assets/css/modern-styles.css @@ -523,4 +523,625 @@ p { right: 8px; top: 38px; } +} + +/* Video Support Styles */ +.hero-video { + transition: opacity 0.3s ease; +} + +.service-video { + transition: transform 0.3s ease; +} + +.service-video:hover { + transform: scale(1.05); +} + +.carousel-item { + transition: transform 0.6s ease-in-out; +} + +.hero-bg { + position: relative; + overflow: hidden; +} + +.hero-bg::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(45deg, rgba(99, 102, 241, 0.3) 0%, rgba(139, 92, 246, 0.3) 100%); + z-index: 1; +} + +/* Video Loading States */ +.video-loading { + background: linear-gradient(45deg, #f3f4f6, #e5e7eb); + background-size: 400% 400%; + animation: shimmer 1.5s ease-in-out infinite; +} + +@keyframes shimmer { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +/* Video Controls */ +.video-controls { + position: absolute; + bottom: 20px; + right: 20px; + z-index: 2; +} + +.video-play-btn { + background: rgba(255, 255, 255, 0.9); + border: none; + border-radius: 50%; + width: 50px; + height: 50px; + display: flex; + align-items: center; + justify-content: center; + color: var(--primary-color); + font-size: 18px; + transition: all 0.3s ease; +} + +.video-play-btn:hover { + background: rgba(255, 255, 255, 1); + transform: scale(1.1); +} + +/* Responsive Video */ +@media (max-width: 768px) { + .hero-video, + .service-video { + height: 300px !important; + } + + .carousel-item { + min-height: 400px; + } +} + +/* Hero Container Styles */ +.hero-modern { + padding: 0; + background: var(--bg-light); +} + +.hero-container { + background: var(--gradient-primary); + border-radius: 24px; + overflow: hidden; + box-shadow: 0 25px 50px -12px rgba(99, 102, 241, 0.25); + position: relative; + margin: 1.5rem auto; + max-width: 1200px; +} + +.hero-bg { + position: relative; + min-height: 600px; +} + +.hero-video, +.hero-bg img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + z-index: 1; +} + +.hero-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(135deg, rgba(99, 102, 241, 0.8) 0%, rgba(139, 92, 246, 0.6) 100%); + z-index: 2; +} + +.hero-content { + position: relative; + z-index: 3; + padding: 4rem 2rem; + display: flex; + align-items: center; + min-height: 600px; +} + +/* Custom Carousel Indicators - Pill System */ +.carousel-indicators-container { + position: absolute; + bottom: 2.5rem; + left: 50%; + transform: translateX(-50%); + z-index: 4; +} + +.outer-pill { + position: relative; + display: inline-flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem; + background: rgba(0, 0, 0, 0.3); + -webkit-backdrop-filter: blur(20px); + backdrop-filter: blur(20px); + border-radius: 50px; + border: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), + inset 0 1px 0 rgba(255, 255, 255, 0.1); + min-height: 50px; + transition: none; + overflow: visible; +} + +/* Удаляем старую структуру inner-pill */ + +.pill-indicators { + display: flex; + gap: 0.75rem; + align-items: center; + flex-wrap: nowrap; + white-space: nowrap; +} + +.pill-indicator { + height: 36px; + border-radius: 18px; + border: 2px solid rgba(255, 255, 255, 0.4); + background: rgba(255, 255, 255, 0.1); + position: relative; + z-index: 1; + transition: width 0.8s cubic-bezier(0.23, 1, 0.32, 1), + padding 0.8s cubic-bezier(0.23, 1, 0.32, 1), + border-color 0.3s ease; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + width: 36px; + overflow: visible; + transform-origin: center; + flex-shrink: 0; +} + +.pill-indicator.active { + border: 2px solid rgba(255, 255, 255, 0.8); + background: rgba(255, 255, 255, 0.1); + width: fit-content; + min-width: 36px; + padding: 0 1rem; + border-radius: 18px; +} + +.pill-indicator:not(.active):hover { + border-color: rgba(255, 255, 255, 0.7); + background: rgba(255, 255, 255, 0.2); + transform: scale(1.05); +} + +.pill-indicator::before { + content: ''; + width: 8px; + height: 8px; + background: rgba(255, 255, 255, 0.8); + border-radius: 50%; + transition: opacity 0.4s cubic-bezier(0.23, 1, 0.32, 1), + transform 0.4s cubic-bezier(0.23, 1, 0.32, 1); + display: block; + flex-shrink: 0; + position: absolute; + transform-origin: center; + opacity: 1; + z-index: 1; +} + +.pill-indicator.active::before { + opacity: 0; + transform: scale(0); +} + +.pill-indicator:hover:not(.active)::before { + background: rgba(255, 255, 255, 1); + transform: scale(1.2); +} + +.pill-indicator-title { + font-size: 0.875rem; + font-weight: 600; + color: rgba(255, 255, 255, 0.95); + white-space: nowrap; + opacity: 0; + transform: scale(0.8); + transition: opacity 0.6s cubic-bezier(0.23, 1, 0.32, 1) 0.2s, + transform 0.6s cubic-bezier(0.23, 1, 0.32, 1) 0.2s; + margin: 0; + position: relative; + transform-origin: center; + z-index: 2; +} + +.pill-indicator.active .pill-indicator-title { + opacity: 1; + transform: scale(1); +} + +/* Плавная анимация как вода */ +.pill-indicator:not(.active):hover { + border-color: rgba(255, 255, 255, 0.7); + background: rgba(255, 255, 255, 0.2); + transform: scale(1.05); + transition: all 0.3s ease; +} + +/* Новые стили для расширенной главной страницы */ +.project-card { + transition: all 0.3s ease; +} + +.project-card:hover { + transform: translateY(-10px); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15) !important; +} + +.project-image { + position: relative; + overflow: hidden; + height: 200px; +} + +.project-image img { + height: 100%; + object-fit: cover; + transition: transform 0.3s ease; +} + +.project-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.7); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.3s ease; +} + +.project-card:hover .project-overlay { + opacity: 1; +} + +.project-card:hover .project-image img { + transform: scale(1.1); +} + +.blog-card { + transition: all 0.3s ease; +} + +.blog-card:hover { + transform: translateY(-5px); + box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1) !important; +} + +.blog-image { + height: 200px; + overflow: hidden; +} + +.blog-image img { + height: 100%; + object-fit: cover; + transition: transform 0.3s ease; +} + +.blog-card:hover .blog-image img { + transform: scale(1.05); +} + +.news-card { + transition: all 0.3s ease; +} + +.news-card:hover { + transform: translateY(-3px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1) !important; +} + +.career-feature { + transition: all 0.3s ease; +} + +.career-feature:hover { + transform: translateY(-5px); +} + +.career-icon { + transition: all 0.3s ease; +} + +.career-feature:hover .career-icon { + transform: scale(1.1); +} + +.career-stats { + transition: all 0.3s ease; +} + +.career-stats:hover { + transform: scale(1.05); +} + +.hover-lift { + transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); +} + +.hover-lift:hover { + transform: translateY(-8px); + box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15); +} + + + +/* Carousel Controls */ +.hero-container { + position: relative; +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + width: 50px; + height: 50px; + background: rgba(0, 0, 0, 0.3); + -webkit-backdrop-filter: blur(20px); + backdrop-filter: blur(20px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 50%; + top: 50%; + transform: translateY(-50%); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + opacity: 0.8; + z-index: 5; +} + +.carousel-control-prev { + left: 1.5rem; +} + +.carousel-control-next { + right: 1.5rem; +} + +.carousel-control-prev:hover, +.carousel-control-next:hover { + background: rgba(0, 0, 0, 0.5); + transform: translateY(-50%) scale(1.1); + opacity: 1; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); +} + +/* Hero Text Styles */ +.hero-title { + font-size: 3.5rem; + font-weight: 800; + background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + text-shadow: 0 2px 20px rgba(0, 0, 0, 0.3); + margin-bottom: 1.5rem; + line-height: 1.1; +} + +.hero-subtitle { + font-size: 1.5rem; + font-weight: 500; + color: rgba(255, 255, 255, 0.9); + margin-bottom: 1.5rem; +} + +.hero-description { + font-size: 1.25rem; + color: rgba(255, 255, 255, 0.8); + margin-bottom: 2.5rem; + line-height: 1.6; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .hero-container { + border-radius: 16px; + margin: 1rem; + } + + .hero-content { + padding: 2rem 1.5rem; + min-height: 500px; + } + + .hero-title { + font-size: 2.5rem; + } + + .hero-subtitle { + font-size: 1.25rem; + } + + .hero-description { + font-size: 1.125rem; + } + + .carousel-indicators-container { + bottom: 8px; + } + + .outer-pill { + gap: 0.5rem; + padding: 0.5rem; + } + + .pill-indicators { + gap: 0.5rem; + } + + .pill-indicator.active { + padding: 0 0.75rem; + font-size: 0.8rem; + } + + .pill-indicator-title { + font-size: 0.8rem; + } + + .pill-indicator { + width: 32px; + height: 32px; + } + + .inner-pill { + height: 32px; + width: 32px; + } + + .inner-pill.active { + min-width: 100px; + } + + .pill-title { + font-size: 0.75rem; + } +} + +/* Дополнительные эффекты для пилюль */ +.inner-pill::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, + transparent 0%, + rgba(99, 102, 241, 0.2) 50%, + transparent 100%); + border-radius: 25px; + opacity: 0; + animation: pillShimmer 3s infinite; +} + +.outer-pill.expanded .inner-pill::before { + opacity: 1; +} + +/* Эффект пульсации для внешней пилюли */ +.outer-pill::after { + content: ''; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + background: linear-gradient(45deg, + rgba(99, 102, 241, 0.3) 0%, + rgba(139, 92, 246, 0.3) 100%); + border-radius: 52px; + opacity: 0; + z-index: -1; + transition: opacity 0.3s ease; +} + +.outer-pill.expanded::after { + opacity: 1; + animation: pillGlow 2s infinite alternate; +} + +@keyframes pillShimmer { + 0% { + transform: translateX(-100%); + } + 100% { + transform: translateX(100%); + } +} + +@keyframes pillGlow { + 0% { + opacity: 0.3; + } + 100% { + opacity: 0.7; + } +} + +@keyframes shimmerSlide { + 0% { + transform: translateX(-100%); + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + transform: translateX(100%); + opacity: 0; + } +} + +/* Animations */ +@keyframes pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +@keyframes ripple { + 0% { + transform: translate(-50%, -50%) scale(1); + opacity: 1; + } + 100% { + transform: translate(-50%, -50%) scale(2); + opacity: 0; + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.animate-fade-in-up { + animation: fadeInUp 0.8s ease-out; } \ No newline at end of file diff --git a/smartsoltech/static/img/logo.svg b/smartsoltech/static/img/logo.svg new file mode 100644 index 0000000..79e2c29 --- /dev/null +++ b/smartsoltech/static/img/logo.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SMARTSOLTECH + + + FUTURE BEGINS HERE + + + + diff --git a/smartsoltech/web/admin.py b/smartsoltech/web/admin.py index 29b0498..8298beb 100644 --- a/smartsoltech/web/admin.py +++ b/smartsoltech/web/admin.py @@ -1,18 +1,40 @@ from django.contrib import admin -from .models import Service, Project, Client, Order, Review, BlogPost, Category, ServiceRequest +from .models import Service, Project, Client, Order, Review, BlogPost, Category, ServiceRequest, HeroBanner from .forms import ProjectForm +@admin.register(HeroBanner) +class HeroBannerAdmin(admin.ModelAdmin): + list_display = ('title', 'is_active', 'order', 'created_at') + list_filter = ('is_active', 'created_at') + search_fields = ('title', 'subtitle') + fields = ('title', 'subtitle', 'description', 'image', 'video', 'video_poster', + 'button_text', 'button_link', 'is_active', 'order') + list_editable = ('is_active', 'order') + @admin.register(Service) class ServiceAdmin(admin.ModelAdmin): - list_display = ('name', 'category', 'price') + list_display = ('name', 'category', 'price', 'has_video') search_fields = ('name', 'category') + fields = ('name', 'description', 'price', 'category', 'image', 'video', 'video_poster') + + def has_video(self, obj): + return bool(obj.video) + has_video.boolean = True + has_video.short_description = 'Есть видео' @admin.register(Project) class ProjectAdmin(admin.ModelAdmin): form = ProjectForm - list_display = ('name', 'client','service', 'status', 'order', 'description') + list_display = ('name', 'client','service', 'status', 'order', 'has_video') list_filter = ('name', 'client','service', 'status', 'order') search_fields = ('name', 'client','service', 'status', 'order', 'client__first_name', 'client__last_name') + fields = ('name', 'description', 'completion_date', 'client', 'service', 'order', + 'category', 'image', 'video', 'video_poster', 'status') + + def has_video(self, obj): + return bool(obj.video) + has_video.boolean = True + has_video.short_description = 'Есть видео' @admin.register(Client) class ClientAdmin(admin.ModelAdmin): @@ -27,14 +49,26 @@ class OrderAdmin(admin.ModelAdmin): @admin.register(Review) class ReviewAdmin(admin.ModelAdmin): - list_display = ('client', 'service', 'rating', 'review_date') + list_display = ('client', 'service', 'rating', 'review_date', 'has_video') list_filter = ('rating',) search_fields = ('client__first_name', 'service__name') + fields = ('client', 'service', 'project', 'rating', 'comment', 'image', 'video', 'video_poster') + + def has_video(self, obj): + return bool(obj.video) + has_video.boolean = True + has_video.short_description = 'Есть видео' @admin.register(BlogPost) class BlogPostAdmin(admin.ModelAdmin): - list_display = ('title', 'published_date') + list_display = ('title', 'published_date', 'has_video') search_fields = ('title',) + fields = ('title', 'content', 'image', 'video', 'video_poster') + + def has_video(self, obj): + return bool(obj.video) + has_video.boolean = True + has_video.short_description = 'Есть видео' @admin.register(Category) class CategoryAdmin(admin.ModelAdmin): diff --git a/smartsoltech/web/migrations/0010_herobanner_blogpost_video_blogpost_video_poster_and_more.py b/smartsoltech/web/migrations/0010_herobanner_blogpost_video_blogpost_video_poster_and_more.py new file mode 100644 index 0000000..1e600ba --- /dev/null +++ b/smartsoltech/web/migrations/0010_herobanner_blogpost_video_blogpost_video_poster_and_more.py @@ -0,0 +1,75 @@ +# Generated by Django 5.1.1 on 2025-11-24 23:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0009_alter_servicerequest_options_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='HeroBanner', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('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(blank=True, null=True, upload_to='static/img/hero/', verbose_name='Фоновое изображение')), + ('video', models.FileField(blank=True, help_text='Фоновое видео для баннера (MP4, WebM)', null=True, upload_to='static/video/hero/', verbose_name='Фоновое видео')), + ('video_poster', models.ImageField(blank=True, help_text='Превью изображение для видео', null=True, upload_to='static/img/hero/posters/', verbose_name='Превью видео')), + ('button_text', models.CharField(blank=True, max_length=100, 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)), + ], + options={ + 'verbose_name': 'Hero Баннер', + 'verbose_name_plural': 'Hero Баннеры', + 'ordering': ['order', '-created_at'], + }, + ), + migrations.AddField( + model_name='blogpost', + name='video', + field=models.FileField(blank=True, help_text='Видео файл для блог поста', null=True, upload_to='static/video/blog/'), + ), + migrations.AddField( + model_name='blogpost', + name='video_poster', + field=models.ImageField(blank=True, help_text='Превью изображение для видео', null=True, upload_to='static/img/blog/posters/'), + ), + migrations.AddField( + model_name='project', + name='video', + field=models.FileField(blank=True, help_text='Видео презентация проекта', null=True, upload_to='static/video/project/'), + ), + migrations.AddField( + model_name='project', + name='video_poster', + field=models.ImageField(blank=True, help_text='Превью изображение для видео проекта', null=True, upload_to='static/img/project/posters/'), + ), + migrations.AddField( + model_name='review', + name='video', + field=models.FileField(blank=True, help_text='Видео отзыв о работе', null=True, upload_to='static/video/review/'), + ), + migrations.AddField( + model_name='review', + name='video_poster', + field=models.ImageField(blank=True, help_text='Превью для видео отзыва', null=True, upload_to='static/img/review/posters/'), + ), + migrations.AddField( + model_name='service', + name='video', + field=models.FileField(blank=True, help_text='Видео файл для услуги (MP4, WebM, AVI)', null=True, upload_to='static/video/services/'), + ), + migrations.AddField( + model_name='service', + name='video_poster', + field=models.ImageField(blank=True, help_text='Превью изображение для видео', null=True, upload_to='static/img/services/posters/'), + ), + ] diff --git a/smartsoltech/web/migrations/0011_add_video_fields.py b/smartsoltech/web/migrations/0011_add_video_fields.py new file mode 100644 index 0000000..063f5fd --- /dev/null +++ b/smartsoltech/web/migrations/0011_add_video_fields.py @@ -0,0 +1,13 @@ +# Generated by Django 5.1.1 on 2025-11-25 01:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0010_herobanner_blogpost_video_blogpost_video_poster_and_more'), + ] + + operations = [ + ] diff --git a/smartsoltech/web/models.py b/smartsoltech/web/models.py index 4f28d69..f192de8 100644 --- a/smartsoltech/web/models.py +++ b/smartsoltech/web/models.py @@ -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 = 'Отзыв' diff --git a/smartsoltech/web/templates/web/about_modern.html b/smartsoltech/web/templates/web/about_modern.html index 4466d5c..547c789 100644 --- a/smartsoltech/web/templates/web/about_modern.html +++ b/smartsoltech/web/templates/web/about_modern.html @@ -9,7 +9,7 @@
- 🚀 О нас + О нас

Мы создаем цифровое будущее @@ -87,7 +87,7 @@
- 🎯 Наша миссия + Наша миссия

Делаем технологии доступными @@ -291,7 +291,7 @@
- ⚡ Технологии + Технологии

Современный технологический стек diff --git a/smartsoltech/web/templates/web/home_modern.html b/smartsoltech/web/templates/web/home_modern.html index 1cec7f3..f7ff260 100644 --- a/smartsoltech/web/templates/web/home_modern.html +++ b/smartsoltech/web/templates/web/home_modern.html @@ -5,104 +5,192 @@ {% block content %}
-
-
-
-
-

- Создаем будущее вашего бизнеса -

-

- Мы разрабатываем современные веб-приложения, мобильные решения и системы автоматизации, - которые помогают компаниям расти и быть конкурентоспособными. -

-
- - - Начать проект - - - - Узнать больше - + {% if hero_banners %} + +
- - + {% endif %} +
@@ -272,11 +360,256 @@
+ + +
+
+
+ + + 💼 Портфолио + +

+ Наши работы +

+

+ Избранные проекты, которыми мы гордимся +

+
+ + {% if latest_projects %} +
+ {% for project in latest_projects %} +
+
+ {% if project.image %} +
+ {{ project.name }} +
+ + + +
+
+ {% endif %} +
+
{{ project.name }}
+

{{ project.description|truncatewords:15 }}

+ + Подробнее + +
+
+
+ {% endfor %} +
+ {% endif %} + + +
+
+ + +
+
+
+ + + 📝 Блог + +

+ Последние статьи +

+
+ + {% if latest_blog_posts %} +
+ {% for post in latest_blog_posts %} +
+
+ {% if post.image %} +
+ {{ post.title }} +
+ {% endif %} +
+
+ {{ post.created_at|date:"d F Y" }} +
+
{{ post.title }}
+

{{ post.content|truncatewords:25 }}

+ + Читать далее + +
+
+
+ {% endfor %} +
+ {% endif %} + + +
+
+ + +
+
+
+ + + 📰 Новости + +

+ Последние новости +

+
+ +
+
+
+
+ 24.11.2025 +
Новый сайт
+
+

+ Поздравляем всех наших клиентов с этой знаменательной датой! + Мы переписали свой сайт! теперь у нас современный дизайн и улучшенная функциональность... +

+ + Узнать больше + +
+
+
+ + +
+
+ + +
+
+
+ + + 🚀 Карьера + +

+ Присоединяйтесь к нашей команде +

+

+ Мы ищем талантливых специалистов, которые разделяют нашу страсть к технологиям и инновациям. +

+
+ +
+
+
+
+ +
+
Профессиональный рост
+

Возможности для развития и обучения

+
+
+ +
+
+
+ +
+
Команда профессионалов
+

Работайте с лучшими специалистами

+
+
+ +
+
+
+ +
+
Гибкий график
+

Удаленная работа и гибкое расписание

+
+
+
+ +
+
+

0

+
Открыто вакансий
+

Найдите свою идеальную позицию

+
+ + + + Смотреть вакансии + + + Посмотреть все + +
+
+
{% endblock %} {% block extra_scripts %}