Добавлена система проектов с автоматическим ресайзом изображений и адаптивным дизайном
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
- Удалена старая система портфолио (PortfolioCategory, PortfolioItem) - Расширена модель Project: slug, categories (M2M), thumbnail, media files, meta fields - Объединены категории: ProjectCategory удалена, используется общая Category - Автоматический ресайз thumbnail до 600x400px с умным кропом по центру - Создан /projects/ - страница списка проектов с фильтрацией по категориям - Создан /project/<pk>/ - детальная страница проекта с галереей Swiper - Адаптивный дизайн: 3 карточки в ряд (десктоп), 2 (планшет), 1 (мобильный) - Параллакс-эффект на изображениях при наведении - Lazy loading для оптимизации загрузки - Фильтры категорий в виде пилюль как на странице услуг - Компактные карточки с фиксированной шириной - Кликабельные проекты в service_detail с отображением всех медиа
This commit is contained in:
@@ -72,11 +72,6 @@
|
||||
<!-- Footer -->
|
||||
{% include 'web/footer_modern.html' %}
|
||||
|
||||
<!-- Theme Toggle Button -->
|
||||
<button id="theme-toggle" class="theme-toggle" aria-label="Переключить тему">
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
|
||||
<!-- Scroll to Top Button -->
|
||||
<button id="scroll-to-top" class="position-fixed bottom-0 end-0 m-4 btn btn-primary-modern rounded-circle" style="width: 50px; height: 50px; display: none; z-index: 999;">
|
||||
<i class="fas fa-arrow-up"></i>
|
||||
|
||||
@@ -65,11 +65,6 @@
|
||||
О нас
|
||||
</a>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<a href="#" class="text-light opacity-75 text-decoration-none hover-primary">
|
||||
Портфолио
|
||||
</a>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<a href="#" class="text-light opacity-75 text-decoration-none hover-primary">
|
||||
Команда
|
||||
|
||||
@@ -65,11 +65,6 @@
|
||||
О нас
|
||||
</a>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<a href="#" class="text-light opacity-75 text-decoration-none hover-primary">
|
||||
Портфолио
|
||||
</a>
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<a href="#" class="text-light opacity-75 text-decoration-none hover-primary">
|
||||
Команда
|
||||
|
||||
@@ -404,7 +404,7 @@
|
||||
{% endif %}
|
||||
|
||||
<div class="text-center mt-5">
|
||||
<a href="{% url 'portfolio' %}" class="btn btn-primary-modern btn-lg">
|
||||
<a href="{% url 'projects_list' %}" class="btn btn-primary-modern btn-lg">
|
||||
<i class="fas fa-th-large me-2"></i>
|
||||
Смотреть все проекты
|
||||
</a>
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
<i class="fas fa-cog me-2"></i>Услуги
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link-modern {% if 'project' in request.resolver_match.url_name %}active{% endif %}"
|
||||
href="{% url 'projects_list' %}">
|
||||
<i class="fas fa-briefcase me-2"></i>Проекты
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link-modern {% if request.resolver_match.url_name == 'about' %}active{% endif %}"
|
||||
href="{% url 'about' %}">
|
||||
@@ -40,7 +46,7 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link-modern {% if request.resolver_match.url_name == 'career' %}active{% endif %}"
|
||||
href="{% url 'career' %}">
|
||||
<i class="fas fa-briefcase me-2"></i>Карьера
|
||||
<i class="fas fa-user-tie me-2"></i>Карьера
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
|
||||
305
smartsoltech/web/templates/web/portfolio_detail.html
Normal file
305
smartsoltech/web/templates/web/portfolio_detail.html
Normal file
@@ -0,0 +1,305 @@
|
||||
{% extends 'web/base_modern.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{{ portfolio.title }} - Портфолио - SmartSolTech{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.11.3/css/lightbox.min.css">
|
||||
<style>
|
||||
.portfolio-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 100px 0 60px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.portfolio-gallery {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.portfolio-info {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 600;
|
||||
color: #667eea;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.portfolio-content {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.portfolio-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.tech-badge {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 20px;
|
||||
margin: 0.25rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.similar-project {
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
||||
transition: transform 0.3s ease;
|
||||
background: white;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.similar-project:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.similar-thumb {
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.similar-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.similar-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="portfolio-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<h1 class="display-4 fw-bold mb-3">{{ portfolio.title }}</h1>
|
||||
<p class="lead mb-3">{{ portfolio.short_description }}</p>
|
||||
<div class="d-flex gap-3 flex-wrap">
|
||||
{% for category in portfolio.categories.all %}
|
||||
<span class="badge bg-light text-dark px-3 py-2">
|
||||
<i class="{{ category.icon }} me-2"></i>{{ category.name }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 text-lg-end mt-4 mt-lg-0">
|
||||
<div class="d-flex justify-content-lg-end gap-3">
|
||||
{% if portfolio.project_url %}
|
||||
<a href="{{ portfolio.project_url }}" target="_blank" class="btn btn-light btn-lg">
|
||||
<i class="fas fa-external-link-alt me-2"></i>Посетить сайт
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if portfolio.github_url %}
|
||||
<a href="{{ portfolio.github_url }}" target="_blank" class="btn btn-outline-light btn-lg">
|
||||
<i class="fab fa-github me-2"></i>GitHub
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container py-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
{% if media_items %}
|
||||
<div class="portfolio-gallery">
|
||||
<div class="swiper portfolioSwiper">
|
||||
<div class="swiper-wrapper">
|
||||
{% for media in media_items %}
|
||||
{% if media.media_type == 'image' %}
|
||||
<div class="swiper-slide">
|
||||
<a href="{{ media.image.url }}" data-lightbox="portfolio-{{ portfolio.id }}" data-title="{{ media.caption }}">
|
||||
<img src="{{ media.image.url }}" alt="{{ media.alt_text }}">
|
||||
</a>
|
||||
</div>
|
||||
{% elif media.media_type == 'video' %}
|
||||
<div class="swiper-slide">
|
||||
<video controls style="width:100%; height:100%; object-fit:cover;">
|
||||
<source src="{{ media.video.url }}" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
{% elif media.media_type == 'embed_video' %}
|
||||
<div class="swiper-slide">
|
||||
<div style="width:100%; height:100%; display:flex; align-items:center; justify-content:center;">
|
||||
{{ media.embed_code|safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="swiper-button-next"></div>
|
||||
<div class="swiper-button-prev"></div>
|
||||
<div class="swiper-pagination"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="portfolio-content">
|
||||
<h2 class="mb-4">Описание проекта</h2>
|
||||
{{ portfolio.description|safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="portfolio-info">
|
||||
<h3 class="mb-4">Информация о проекте</h3>
|
||||
|
||||
{% if portfolio.client_name %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-user me-2"></i>Клиент
|
||||
</div>
|
||||
<div>{{ portfolio.client_name }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if portfolio.completion_date %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-calendar me-2"></i>Дата завершения
|
||||
</div>
|
||||
<div>{{ portfolio.completion_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if portfolio.duration %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-clock me-2"></i>Длительность
|
||||
</div>
|
||||
<div>{{ portfolio.duration }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if portfolio.team_size %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-users me-2"></i>Размер команды
|
||||
</div>
|
||||
<div>{{ portfolio.team_size }} человек</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-chart-line me-2"></i>Статистика
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-eye me-1"></i> {{ portfolio.views_count }} просмотров<br>
|
||||
<i class="fas fa-heart me-1"></i> {{ portfolio.likes_count }} лайков
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if portfolio.technologies %}
|
||||
<div class="portfolio-info">
|
||||
<h3 class="mb-3">Технологии</h3>
|
||||
<div>
|
||||
{% for tech in portfolio.technologies.split %}
|
||||
<span class="tech-badge">{{ tech }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if similar_projects %}
|
||||
<div class="mt-5">
|
||||
<h2 class="mb-4">Похожие проекты</h2>
|
||||
<div class="row">
|
||||
{% for item in similar_projects %}
|
||||
<div class="col-md-4">
|
||||
<div class="similar-project">
|
||||
<div class="similar-thumb">
|
||||
{% if item.thumbnail %}
|
||||
<img src="{{ item.thumbnail.url }}" alt="{{ item.title }}">
|
||||
{% else %}
|
||||
<img src="{% static 'img/default-portfolio.jpg' %}" alt="{{ item.title }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="similar-content">
|
||||
<h4 class="h6 mb-2">{{ item.title }}</h4>
|
||||
<p class="text-muted small mb-3">{{ item.short_description|truncatewords:10 }}</p>
|
||||
<a href="{% url 'portfolio_detail' item.slug %}" class="btn btn-sm btn-primary">
|
||||
Подробнее
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.11.3/js/lightbox.min.js"></script>
|
||||
<script>
|
||||
const swiper = new Swiper('.portfolioSwiper', {
|
||||
loop: true,
|
||||
navigation: {
|
||||
nextEl: '.swiper-button-next',
|
||||
prevEl: '.swiper-button-prev',
|
||||
},
|
||||
pagination: {
|
||||
el: '.swiper-pagination',
|
||||
clickable: true,
|
||||
},
|
||||
autoplay: {
|
||||
delay: 5000,
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
effect: 'fade',
|
||||
fadeEffect: {
|
||||
crossFade: true
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
211
smartsoltech/web/templates/web/portfolio_list.html
Normal file
211
smartsoltech/web/templates/web/portfolio_list.html
Normal file
@@ -0,0 +1,211 @@
|
||||
{% extends 'web/base_modern.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Портфолио - SmartSolTech{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css">
|
||||
<style>
|
||||
.portfolio-hero {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 100px 0 60px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.category-filter {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
margin: 2rem 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.category-btn {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: 2px solid #667eea;
|
||||
background: white;
|
||||
color: #667eea;
|
||||
border-radius: 50px;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.category-btn:hover,
|
||||
.category-btn.active {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.portfolio-card {
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
transition: all 0.3s ease;
|
||||
background: white;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.portfolio-card:hover {
|
||||
transform: translateY(-10px);
|
||||
box-shadow: 0 20px 50px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.portfolio-thumb {
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.portfolio-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.portfolio-card:hover .portfolio-thumb img {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.portfolio-content {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.portfolio-categories {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.portfolio-badge {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.portfolio-stats {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
color: #6c757d;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.featured-badge {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
color: white;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-weight: 600;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="portfolio-hero">
|
||||
<div class="container text-center">
|
||||
<h1 class="display-4 fw-bold mb-3">Наше Портфолио</h1>
|
||||
<p class="lead">Проекты, которыми мы гордимся</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container py-5">
|
||||
<div class="category-filter">
|
||||
<a href="{% url 'portfolio_list' %}" class="category-btn {% if not request.GET.category %}active{% endif %}">
|
||||
<i class="fas fa-th me-2"></i>Все проекты
|
||||
</a>
|
||||
{% for category in categories %}
|
||||
<a href="?category={{ category.slug }}" class="category-btn {% if request.GET.category == category.slug %}active{% endif %}">
|
||||
<i class="{{ category.icon }} me-2"></i>{{ category.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if featured %}
|
||||
<div class="mb-5">
|
||||
<h2 class="mb-4"><i class="fas fa-star text-warning me-2"></i>Избранные проекты</h2>
|
||||
<div class="row">
|
||||
{% for item in featured %}
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="portfolio-card">
|
||||
<div class="portfolio-thumb">
|
||||
<span class="featured-badge"><i class="fas fa-star me-1"></i>Избранное</span>
|
||||
{% if item.thumbnail %}
|
||||
<img src="{{ item.thumbnail.url }}" alt="{{ item.title }}">
|
||||
{% else %}
|
||||
<img src="{% static 'img/default-portfolio.jpg' %}" alt="{{ item.title }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="portfolio-content">
|
||||
<div class="portfolio-categories">
|
||||
{% for cat in item.categories.all %}
|
||||
<span class="portfolio-badge">{{ cat.name }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h3 class="h5 mb-2">{{ item.title }}</h3>
|
||||
<p class="text-muted mb-3">{{ item.short_description|truncatewords:20 }}</p>
|
||||
<div class="portfolio-stats mb-3">
|
||||
<span><i class="fas fa-eye me-1"></i>{{ item.views_count }}</span>
|
||||
<span><i class="fas fa-heart me-1"></i>{{ item.likes_count }}</span>
|
||||
<span><i class="fas fa-calendar me-1"></i>{{ item.completion_date|date:"Y" }}</span>
|
||||
</div>
|
||||
<a href="{% url 'portfolio_detail' item.slug %}" class="btn btn-primary">
|
||||
Подробнее <i class="fas fa-arrow-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2 class="mb-4">Все проекты</h2>
|
||||
<div class="row">
|
||||
{% for item in portfolios %}
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="portfolio-card">
|
||||
<div class="portfolio-thumb">
|
||||
{% if item.thumbnail %}
|
||||
<img src="{{ item.thumbnail.url }}" alt="{{ item.title }}">
|
||||
{% else %}
|
||||
<img src="{% static 'img/default-portfolio.jpg' %}" alt="{{ item.title }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="portfolio-content">
|
||||
<div class="portfolio-categories">
|
||||
{% for cat in item.categories.all %}
|
||||
<span class="portfolio-badge">{{ cat.name }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h3 class="h5 mb-2">{{ item.title }}</h3>
|
||||
<p class="text-muted mb-3">{{ item.short_description|truncatewords:20 }}</p>
|
||||
<div class="portfolio-stats mb-3">
|
||||
<span><i class="fas fa-eye me-1"></i>{{ item.views_count }}</span>
|
||||
<span><i class="fas fa-heart me-1"></i>{{ item.likes_count }}</span>
|
||||
<span><i class="fas fa-calendar me-1"></i>{{ item.completion_date|date:"Y" }}</span>
|
||||
</div>
|
||||
<a href="{% url 'portfolio_detail' item.slug %}" class="btn btn-primary">
|
||||
Подробнее <i class="fas fa-arrow-right ms-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col-12 text-center py-5">
|
||||
<i class="fas fa-folder-open fa-4x text-muted mb-3"></i>
|
||||
<h3 class="text-muted">Проектов пока нет</h3>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
444
smartsoltech/web/templates/web/project_detail.html
Normal file
444
smartsoltech/web/templates/web/project_detail.html
Normal file
@@ -0,0 +1,444 @@
|
||||
{% extends 'web/base_modern.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{{ project.name }} - Проекты - SmartSolTech{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.11.3/css/lightbox.min.css">
|
||||
<style>
|
||||
.project-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 100px 0 60px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.project-gallery {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.swiper-slide video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.project-info {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
margin-bottom: 2rem;
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 600;
|
||||
color: #667eea;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.project-content {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.project-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.tech-badge {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 20px;
|
||||
margin: 0.25rem;
|
||||
font-size: 0.9rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.similar-project {
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
background: white;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.similar-project:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.similar-thumb {
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, #667eea20 0%, #764ba220 100%);
|
||||
}
|
||||
|
||||
.similar-thumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.similar-project:hover .similar-thumb img {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.similar-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.embed-responsive {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.embed-responsive iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Адаптивность */
|
||||
@media (max-width: 992px) {
|
||||
.project-info {
|
||||
position: static;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.project-header {
|
||||
padding: 80px 0 40px;
|
||||
}
|
||||
|
||||
.project-header h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.project-header .lead {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.swiper {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.project-content,
|
||||
.project-info {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.similar-thumb {
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.embed-responsive {
|
||||
min-height: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.project-header {
|
||||
padding: 60px 0 30px;
|
||||
}
|
||||
|
||||
.project-header h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.swiper {
|
||||
height: 250px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.tech-badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.4rem 0.8rem;
|
||||
}
|
||||
|
||||
.project-gallery {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Swiper навигация для мобильных */
|
||||
@media (max-width: 768px) {
|
||||
.swiper-button-next,
|
||||
.swiper-button-prev {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.swiper-button-next:after,
|
||||
.swiper-button-prev:after {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.swiper-pagination-bullet {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="project-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<h1 class="display-4 fw-bold mb-3">{{ project.name }}</h1>
|
||||
<p class="lead mb-3">{{ project.short_description }}</p>
|
||||
<div class="d-flex gap-3 flex-wrap">
|
||||
{% for category in project.categories.all %}
|
||||
<span class="badge bg-light text-dark px-3 py-2">
|
||||
<i class="{{ category.icon }} me-2"></i>{{ category.name }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 text-lg-end mt-4 mt-lg-0">
|
||||
<div class="d-flex justify-content-lg-end gap-3 flex-wrap">
|
||||
{% if project.project_url %}
|
||||
<a href="{{ project.project_url }}" target="_blank" class="btn btn-light btn-lg">
|
||||
<i class="fas fa-external-link-alt me-2"></i>Посетить сайт
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if project.github_url %}
|
||||
<a href="{{ project.github_url }}" target="_blank" class="btn btn-outline-light btn-lg">
|
||||
<i class="fab fa-github me-2"></i>GitHub
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container py-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
{% if project.media_files.exists %}
|
||||
<div class="project-gallery">
|
||||
<div class="swiper projectSwiper">
|
||||
<div class="swiper-wrapper">
|
||||
{% for media in project.media_files.all %}
|
||||
{% if media.media_type == 'image' %}
|
||||
<div class="swiper-slide">
|
||||
<a href="{{ media.image.url }}" data-lightbox="project-{{ project.id }}" data-title="{{ media.caption }}">
|
||||
<img src="{{ media.image.url }}" alt="{{ media.alt_text|default:project.name }}">
|
||||
</a>
|
||||
</div>
|
||||
{% elif media.media_type == 'video' %}
|
||||
<div class="swiper-slide">
|
||||
<video controls {% if media.video_poster %}poster="{{ media.video_poster.url }}"{% endif %}>
|
||||
<source src="{{ media.video.url }}" type="video/mp4">
|
||||
Ваш браузер не поддерживает видео.
|
||||
</video>
|
||||
</div>
|
||||
{% elif media.media_type == 'embed' and media.embed_url %}
|
||||
<div class="swiper-slide">
|
||||
<div class="embed-responsive">
|
||||
<iframe src="{{ media.embed_url }}" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="swiper-button-next"></div>
|
||||
<div class="swiper-button-prev"></div>
|
||||
<div class="swiper-pagination"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="project-content">
|
||||
<h2 class="mb-4">Описание проекта</h2>
|
||||
{{ project.description|safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="project-info">
|
||||
<h3 class="mb-4">Информация о проекте</h3>
|
||||
|
||||
{% if project.client %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-user me-2"></i>Клиент
|
||||
</div>
|
||||
<div>{{ project.client.name }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if project.completion_date %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-calendar me-2"></i>Дата завершения
|
||||
</div>
|
||||
<div>{{ project.completion_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if project.duration %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-clock me-2"></i>Длительность
|
||||
</div>
|
||||
<div>{{ project.duration }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if project.team_size %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-users me-2"></i>Размер команды
|
||||
</div>
|
||||
<div>{{ project.team_size }} человек</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-chart-line me-2"></i>Статистика
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-eye me-1"></i> {{ project.views_count }} просмотров<br>
|
||||
<i class="fas fa-heart me-1"></i> {{ project.likes_count }} лайков
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if project.status %}
|
||||
<div class="info-item">
|
||||
<div class="info-label">
|
||||
<i class="fas fa-info-circle me-2"></i>Статус
|
||||
</div>
|
||||
<div>
|
||||
{% if project.status == 'completed' %}
|
||||
<span class="badge bg-success">Завершён</span>
|
||||
{% elif project.status == 'in_progress' %}
|
||||
<span class="badge bg-warning">В процессе</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ project.get_status_display }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if project.technologies %}
|
||||
<div class="project-info">
|
||||
<h3 class="mb-3">Технологии</h3>
|
||||
<div>
|
||||
{% for tech in project.technologies_list %}
|
||||
<span class="tech-badge">{{ tech }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if similar_projects %}
|
||||
<div class="mt-5">
|
||||
<h2 class="mb-4">Похожие проекты</h2>
|
||||
<div class="row">
|
||||
{% for item in similar_projects %}
|
||||
<div class="col-md-4">
|
||||
<div class="similar-project">
|
||||
<div class="similar-thumb">
|
||||
{% if item.thumbnail %}
|
||||
<img src="{{ item.thumbnail.url }}" alt="{{ item.name }}">
|
||||
{% elif item.image %}
|
||||
<img src="{{ item.image.url }}" alt="{{ item.name }}">
|
||||
{% else %}
|
||||
<img src="{% static 'img/default-project.jpg' %}" alt="{{ item.name }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="similar-content">
|
||||
<h4 class="h6 mb-2">{{ item.name }}</h4>
|
||||
{% if item.short_description %}
|
||||
<p class="text-muted small mb-3">{{ item.short_description|truncatewords:10 }}</p>
|
||||
{% endif %}
|
||||
<a href="{% url 'project_detail' item.pk %}" class="btn btn-sm btn-primary">
|
||||
Подробнее
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.11.3/js/lightbox.min.js"></script>
|
||||
<script>
|
||||
const swiper = new Swiper('.projectSwiper', {
|
||||
loop: true,
|
||||
navigation: {
|
||||
nextEl: '.swiper-button-next',
|
||||
prevEl: '.swiper-button-prev',
|
||||
},
|
||||
pagination: {
|
||||
el: '.swiper-pagination',
|
||||
clickable: true,
|
||||
},
|
||||
autoplay: {
|
||||
delay: 5000,
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
effect: 'fade',
|
||||
fadeEffect: {
|
||||
crossFade: true
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
362
smartsoltech/web/templates/web/projects_list.html
Normal file
362
smartsoltech/web/templates/web/projects_list.html
Normal file
@@ -0,0 +1,362 @@
|
||||
{% extends 'web/base_modern.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Наши проекты - SmartSolTech{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Projects Page v2.0 - Force Update */
|
||||
.projects-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 100px 0 60px;
|
||||
color: white;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.category-filter {
|
||||
margin-bottom: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.category-btn {
|
||||
display: inline-block;
|
||||
padding: 0.75rem 1.5rem;
|
||||
margin: 0.5rem 0.25rem;
|
||||
border-radius: 25px;
|
||||
background: white;
|
||||
border: 2px solid #e2e8f0;
|
||||
color: #4a5568;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.category-btn:hover {
|
||||
border-color: #667eea;
|
||||
color: #667eea;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
.category-btn.active {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-color: transparent;
|
||||
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.projects-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.projects-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.projects-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.project-card {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
transition: box-shadow 0.3s ease !important;
|
||||
margin-bottom: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
box-shadow: 0 15px 40px rgba(0,0,0,0.2) !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.project-thumbnail {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: linear-gradient(135deg, #667eea20 0%, #764ba220 100%);
|
||||
}
|
||||
|
||||
.project-thumbnail img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.project-card:hover .project-thumbnail img {
|
||||
transform: scale(1.15) translateY(-10px) !important;
|
||||
}
|
||||
|
||||
.project-thumbnail::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 50%;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.3), transparent);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.project-badge {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 0.35rem 0.75rem;
|
||||
border-radius: 15px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
z-index: 1;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.project-content {
|
||||
padding: 1rem;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.project-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.3;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.project-description {
|
||||
color: #718096;
|
||||
margin-bottom: 0.75rem;
|
||||
flex-grow: 1;
|
||||
line-height: 1.5;
|
||||
font-size: 0.9rem;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.project-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
margin-top: auto;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.project-stats {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
color: #718096;
|
||||
}
|
||||
|
||||
.project-stats i {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.project-categories {
|
||||
margin-bottom: 0.75rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.category-tag {
|
||||
display: inline-block;
|
||||
padding: 0.2rem 0.6rem;
|
||||
background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
|
||||
color: #667eea;
|
||||
border-radius: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.no-projects {
|
||||
text-align: center;
|
||||
padding: 4rem 2rem;
|
||||
color: #718096;
|
||||
}
|
||||
|
||||
.no-projects i {
|
||||
font-size: 4rem;
|
||||
color: #e2e8f0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Адаптивность */
|
||||
@media (max-width: 768px) {
|
||||
.projects-header {
|
||||
padding: 80px 0 40px;
|
||||
}
|
||||
|
||||
.projects-header h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.projects-header .lead {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.project-thumbnail {
|
||||
height: 180px;
|
||||
}
|
||||
|
||||
.project-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.project-meta {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.project-thumbnail {
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.category-btn {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
}
|
||||
|
||||
.project-content {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Скелетон загрузка */
|
||||
.skeleton {
|
||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: loading 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="projects-header">
|
||||
<div class="container">
|
||||
<div class="text-center">
|
||||
<h1 class="display-4 fw-bold mb-3">Наши проекты</h1>
|
||||
<p class="lead mb-0">Портфолио завершённых работ и успешных внедрений</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
{% if categories %}
|
||||
<div class="category-filter">
|
||||
<a href="{% url 'projects_list' %}" class="category-btn {% if not selected_category %}active{% endif %}">
|
||||
<i class="fas fa-th me-2"></i>Все проекты
|
||||
</a>
|
||||
{% for category in categories %}
|
||||
<a href="{% url 'projects_list' %}?category={{ category.id }}"
|
||||
class="category-btn {% if selected_category == category.id|stringformat:'s' %}active{% endif %}">
|
||||
<i class="{{ category.icon }} me-2"></i>{{ category.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if projects %}
|
||||
<div class="projects-grid">
|
||||
{% for project in projects %}
|
||||
<a href="{% url 'project_detail' project.pk %}" class="text-decoration-none">
|
||||
<div class="project-card">
|
||||
<div class="project-thumbnail">
|
||||
{% if project.thumbnail %}
|
||||
<img src="{{ project.thumbnail.url }}" alt="{{ project.name }}" loading="lazy" decoding="async">
|
||||
{% elif project.image %}
|
||||
<img src="{{ project.image.url }}" alt="{{ project.name }}" loading="lazy" decoding="async">
|
||||
{% else %}
|
||||
<img src="{% static 'img/default-project.jpg' %}" alt="{{ project.name }}" loading="lazy" decoding="async">
|
||||
{% endif %}
|
||||
|
||||
{% if project.is_featured %}
|
||||
<div class="project-badge">
|
||||
<i class="fas fa-star me-1"></i>Избранное
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="project-content">
|
||||
<h3 class="project-title">{{ project.name }}</h3>
|
||||
|
||||
{% if project.categories.exists %}
|
||||
<div class="project-categories">
|
||||
{% for category in project.categories.all %}
|
||||
<span class="category-tag">
|
||||
<i class="{{ category.icon }} me-1"></i>{{ category.name }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if project.short_description %}
|
||||
<p class="project-description">{{ project.short_description|truncatewords:20 }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="project-meta">
|
||||
<div class="project-stats">
|
||||
<span><i class="fas fa-eye me-1"></i>{{ project.views_count }}</span>
|
||||
<span><i class="fas fa-heart me-1"></i>{{ project.likes_count }}</span>
|
||||
</div>
|
||||
{% if project.completion_date %}
|
||||
<small class="text-muted">{{ project.completion_date|date:"Y" }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="no-projects">
|
||||
<i class="fas fa-folder-open"></i>
|
||||
<h3>Проектов не найдено</h3>
|
||||
<p>В данной категории пока нет завершённых проектов</p>
|
||||
<a href="{% url 'projects_list' %}" class="btn btn-primary-modern mt-3">
|
||||
<i class="fas fa-th me-2"></i>Посмотреть все проекты
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -224,32 +224,58 @@
|
||||
<div class="row g-4">
|
||||
{% for project in service.projects.all %}
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card-modern h-100">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<span class="badge bg-primary">{{ project.get_status_display }}</span>
|
||||
<a href="{% url 'project_detail' project.pk %}" class="text-decoration-none">
|
||||
<div class="card-modern h-100 hover-lift">
|
||||
{% if project.thumbnail %}
|
||||
<div style="height: 200px; overflow: hidden; border-radius: 15px 15px 0 0;">
|
||||
<img src="{{ project.thumbnail.url }}" alt="{{ project.name }}"
|
||||
style="width: 100%; height: 100%; object-fit: cover; object-position: center;"
|
||||
loading="lazy" decoding="async">
|
||||
</div>
|
||||
<h5 class="mb-3">{{ project.name }}</h5>
|
||||
<p class="text-muted mb-3">{{ project.description|truncatewords:15 }}</p>
|
||||
|
||||
<div class="mb-3">
|
||||
<strong>Требования заказчика:</strong>
|
||||
<p class="text-muted small">{{ project.order.message|truncatewords:10 }}</p>
|
||||
{% elif project.image %}
|
||||
<div style="height: 200px; overflow: hidden; border-radius: 15px 15px 0 0;">
|
||||
<img src="{{ project.image.url }}" alt="{{ project.name }}"
|
||||
style="width: 100%; height: 100%; object-fit: cover; object-position: center;"
|
||||
loading="lazy" decoding="async">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-calendar-check me-1"></i>
|
||||
{{ project.completion_date|date:"d.m.Y" }}
|
||||
</small>
|
||||
<div class="project-rating">
|
||||
{% for i in "12345" %}
|
||||
<i class="fas fa-star text-warning"></i>
|
||||
{% endfor %}
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<span class="badge bg-primary">{{ project.get_status_display }}</span>
|
||||
{% if project.media_files.count > 0 %}
|
||||
<span class="badge bg-info ms-2">
|
||||
<i class="fas fa-images me-1"></i>{{ project.media_files.count }} фото
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h5 class="mb-3 text-dark">{{ project.name }}</h5>
|
||||
|
||||
{% if project.short_description %}
|
||||
<p class="text-muted mb-3">{{ project.short_description|truncatewords:15 }}</p>
|
||||
{% else %}
|
||||
<p class="text-muted mb-3">{{ project.description|striptags|truncatewords:15 }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-calendar-check me-1"></i>
|
||||
{% if project.completion_date %}
|
||||
{{ project.completion_date|date:"d.m.Y" }}
|
||||
{% else %}
|
||||
Не указано
|
||||
{% endif %}
|
||||
</small>
|
||||
<div class="project-stats">
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-eye me-1"></i>{{ project.views_count }}
|
||||
<i class="fas fa-heart ms-2 me-1"></i>{{ project.likes_count }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -510,6 +536,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Hover lift effect for project cards */
|
||||
.hover-lift {
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-lift:hover {
|
||||
transform: translateY(-10px);
|
||||
box-shadow: 0 15px 40px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Success Animation Styles */
|
||||
.success-checkmark {
|
||||
width: 80px;
|
||||
|
||||
Reference in New Issue
Block a user