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 %}
+
+
+
+
+
+
+
+ Создаем будущее вашего бизнеса
+
+
+ Мы разрабатываем современные веб-приложения, мобильные решения и системы автоматизации,
+ которые помогают компаниям расти и быть конкурентоспособными.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 %}
+
+
+
+
+
+
+
+
+ {% for banner in hero_banners %}
+
+ {{ banner.title }}
+
+ {% endfor %}
+
+
-
-
-
-
50+
-
Проектов
+
+
+ {% for banner in hero_banners %}
+
+
+
+ {% if banner.video %}
+
+
+
+ {% if banner.image %}
+
+
+ {% endif %}
+
+ {% elif banner.image %}
+
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+ {{ banner.title }}
+
+ {% if banner.subtitle %}
+
+ {{ banner.subtitle }}
+
+ {% endif %}
+ {% if banner.description %}
+
+ {{ banner.description }}
+
+ {% endif %}
+
+
+
+
+
+
-
+
+
+ {% else %}
+
+
+
+
+
+
+ Создаем будущее вашего бизнеса
+
+
+ Мы разрабатываем современные веб-приложения, мобильные решения и системы автоматизации,
+ которые помогают компаниям расти и быть конкурентоспособными.
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
def create_future():
+
return innovation + passion
+
// SmartSolTech
+
-
-
def create_future():
-
return innovation + passion
-
// SmartSolTech
+
+
+
+
+
+
Мобильные
+
приложения
+
+
+
+
+
+
+
-
-
-
-
-
-
Мобильные
-
приложения
-
-
-
-
-
-
-
-
-
-
-
-
+ {% endif %}
+
+
+
+
+
+
+
+
+ 💼 Портфолио
+
+
+ Наши работы
+
+
+ Избранные проекты, которыми мы гордимся
+
+
+
+ {% if latest_projects %}
+
+ {% for project in latest_projects %}
+
+
+ {% if project.image %}
+
+
+
+
+ {% endif %}
+
+
{{ project.name }}
+
{{ project.description|truncatewords:15 }}
+
+ Подробнее
+
+
+
+
+ {% endfor %}
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+ 📝 Блог
+
+
+ Последние статьи
+
+
+
+ {% if latest_blog_posts %}
+
+ {% for post in latest_blog_posts %}
+
+
+ {% if post.image %}
+
+
+
+ {% endif %}
+
+
+ {{ post.created_at|date:"d F Y" }}
+
+
{{ post.title }}
+
{{ post.content|truncatewords:25 }}
+
+ Читать далее
+
+
+
+
+ {% endfor %}
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+ 📰 Новости
+
+
+ Последние новости
+
+
+
+
+
+
+
+ 24.11.2025
+
Новый сайт
+
+
+ Поздравляем всех наших клиентов с этой знаменательной датой!
+ Мы переписали свой сайт! теперь у нас современный дизайн и улучшенная функциональность...
+
+
+ Узнать больше
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 🚀 Карьера
+
+
+ Присоединяйтесь к нашей команде
+
+
+ Мы ищем талантливых специалистов, которые разделяют нашу страсть к технологиям и инновациям.
+
+
+
+
+
+
+
+
+
+
Профессиональный рост
+
Возможности для развития и обучения
+
+
+
+
+
+
+
+
+
Команда профессионалов
+
Работайте с лучшими специалистами
+
+
+
+
+
+
+
+
+
Гибкий график
+
Удаленная работа и гибкое расписание
+
+
+
+
+
+
+
0
+
Открыто вакансий
+
Найдите свою идеальную позицию
+
+
+
+
+ Смотреть вакансии
+
+
+ Посмотреть все
+
+
+
+
{% endblock %}
{% block extra_scripts %}