341 lines
14 KiB
HTML
341 lines
14 KiB
HTML
{% extends "base.html" %}
|
||
{% import "/components/header.html" as header %}
|
||
{% import "/components/footer.html" as footer %}
|
||
{% import "components/share.html" as share %}
|
||
|
||
{% block title %}{{paint.title}}{% endblock %}
|
||
|
||
{% block head %}
|
||
<meta property="og:title" content="{{paint.title}}">
|
||
<meta property="og:description" content="{{description}}">
|
||
<meta property="og:type" content="product">
|
||
<meta property="og:image" content="https://avtopost.kultmost.ru/b/posts/{{paint.medias[0]}}">
|
||
<meta property="og:url" content="https://avtopost.kultmost.ru/paintings/{{paint._id}}">
|
||
<meta name="description" content="{{description}}">
|
||
<meta property="og:site_name" content="Картины | KULTMOST.АВТОПОСТ">
|
||
{{ header.style() }}
|
||
|
||
<style>
|
||
.swiper {
|
||
position: relative;
|
||
max-width: 900px;
|
||
margin: 0 auto;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.swiper-wrapper {
|
||
display: flex;
|
||
max-height: 520px;
|
||
transition: transform 0.75s cubic-bezier(0.32, 0.72, 0, 1);
|
||
will-change: transform;
|
||
align-items: center;
|
||
}
|
||
|
||
.swiper-slide {
|
||
flex: 0 0 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
transition: background-color 0.8s ease;
|
||
overflow: hidden;
|
||
display: flex;
|
||
}
|
||
|
||
.swiper-slide img {
|
||
max-height: 520px;
|
||
width: 100%;
|
||
object-fit: scale-down;
|
||
|
||
}
|
||
|
||
.caption {
|
||
position: absolute;
|
||
bottom: 40px;
|
||
left: 40px;
|
||
color: white;
|
||
font-size: 2.1rem;
|
||
font-weight: 700;
|
||
text-shadow: 0 4px 15px rgba(0,0,0,0.8);
|
||
z-index: 5;
|
||
}
|
||
|
||
.swiper-button {
|
||
position: absolute;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
background: rgba(255, 255, 255, 0);
|
||
color: #683185;
|
||
border: 1px solid #683185;
|
||
width: 58px;
|
||
height: 58px;
|
||
font-size: 2.2rem;
|
||
cursor: pointer;
|
||
border-radius: 50%;
|
||
z-index: 10;
|
||
text-align: center;
|
||
}
|
||
|
||
.swiper-button:hover { background: rgba(0,0,0,0.9); }
|
||
|
||
.swiper-button.prev { left: 25px; }
|
||
.swiper-button.next { right: 25px; }
|
||
|
||
.swiper-pagination {
|
||
position: absolute;
|
||
bottom: 25px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
display: flex;
|
||
gap: 12px;
|
||
z-index: 10;
|
||
}
|
||
|
||
.swiper-pagination-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
background: rgba(95,23,152,.4);
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.swiper-pagination-dot.active {
|
||
background: #683185;
|
||
transform: scale(1.35);
|
||
}
|
||
</style>
|
||
<style>/* Base (common) styles */
|
||
.b_mmlhf { border-radius: 1em;
|
||
height: 70px;
|
||
min-width: 70px;
|
||
object-fit: cover;
|
||
max-width: 170px;
|
||
object-position: top; }
|
||
.b_n91ga { color: #3A3A3A; font-family: Inter; font-size: 14px; font-style: italic; font-weight: 400; line-height: normal; }
|
||
.b_01urj { -webkit-box-orient: vertical; -webkit-line-clamp: 1; color: #000; display: -webkit-box; font-family: Inter; font-size: 16px; font-style: normal; font-weight: 700; line-height: normal; overflow: hidden; text-overflow: ellipsis; }
|
||
.b_mxr38 { -webkit-box-orient: vertical; -webkit-line-clamp: 1; color: #000; display: -webkit-box; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; overflow: hidden; text-overflow: ellipsis; }
|
||
.b_x7dj6 { align-items: flex-start; display: flex; flex-direction: column; flex: 1 0 0; justify-content: center; }
|
||
.b_etnpf { align-items: center; align-self: stretch; display: flex; gap: 13px; }
|
||
.b_o7w2c { -webkit-box-orient: vertical; color: #000; display: -webkit-box; flex: 1 0 0; font-family: Inter; font-size: 24px; font-style: normal; font-weight: 700; line-height: normal; overflow: hidden; text-overflow: ellipsis; }
|
||
.b_4sh8z { align-items: center; align-self: stretch; display: flex; justify-content: center; }
|
||
.b_frv5u { -webkit-box-orient: vertical; -webkit-line-clamp: 3; align-self: stretch; color: rgba(58, 58, 58, 0.75); display: -webkit-box; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; overflow: hidden; text-overflow: ellipsis; }
|
||
.b_a1gdl { align-items: flex-start; align-self: stretch; display: flex; flex-direction: column; }
|
||
.b_mwej0 { align-self: stretch; color: rgba(58, 58, 58, 0.75); font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; }
|
||
.b_6atmo { color: #000; font-family: Inter; font-size: 20px; font-style: normal; font-weight: 700; height: 29px; line-height: normal; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
|
||
.b_ik47g { align-items: flex-start; align-self: stretch; display: flex; flex-direction: column; padding: 5px 0; }
|
||
.b_7efyd { white-space: pre-line; align-self: stretch; color: rgba(58, 58, 58, 0.75); font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; }
|
||
.b_v0d1u { color: #FFF; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; }
|
||
.b_gk0ob { align-items: center; background: #5F1798; border-radius: 5px; display: flex; height: 51px; justify-content: center; padding: 19px 33px; }
|
||
.b_tssu9 { align-items: flex-start; max-width: 620px; background: #FFF; display: flex; flex-direction: column; flex: 1 0 0; gap: 10px; justify-content: center; min-width: 335px; padding: 10px 20px; }
|
||
.c_m3jeo{background: #fdfaff;margin: auto;
|
||
border-radius: 10px;margin-bottom: 111px;}
|
||
/* Mobile */
|
||
@media (max-width: 699px) {
|
||
.c_gnsfq { flex-shrink: 0; height: 400px; width: 355px; }
|
||
.c_m3jeo { align-content: flex-start; align-items: flex-start; background: #FFF; display: flex; flex-wrap: wrap; gap: 30px; justify-content: center; width: 375px; }
|
||
}
|
||
|
||
/* Tablet */
|
||
@media (min-width: 700px) and (max-width: 900px) {
|
||
.c_gnsfq { flex-shrink: 0; height: 400px; width: 668px; }
|
||
.c_m3jeo { align-content: flex-start; align-items: flex-start; background: #FFF; display: flex; flex-wrap: wrap; gap: 30px; justify-content: center; width: 800px; }
|
||
}
|
||
|
||
/* Desktop */
|
||
@media (min-width: 901px) {
|
||
.c_gnsfq { flex: 1 0 0; height: 400px; }
|
||
.c_la1ap { color: rgba(58, 58, 58, 0.75); font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; }
|
||
.c_w6ecf { -webkit-box-orient: vertical; -webkit-line-clamp: 1; align-self: stretch; color: #000; display: -webkit-box; font-family: Inter; font-size: 20px; font-style: normal; font-weight: 700; line-height: normal; overflow: hidden; text-overflow: ellipsis; }
|
||
.c_m3jeo { align-content: flex-start; align-items: flex-start; background: #FFF; display: flex; flex-wrap: wrap; gap: 30px; justify-content: center; width: 1600px; }
|
||
}
|
||
.b_gagrr { align-items: center; align-self: stretch; display: flex; justify-content: space-between; }
|
||
.b_rhbo8 { color: #5F1798; font-family: Inter; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; }
|
||
.c_eiyz0{cursor: pointer;}
|
||
</style>
|
||
{{ footer.style() }}
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
{{ header.section(user) }}
|
||
<section class="c_m3jeo">
|
||
<div class="swiper" id="swiper">
|
||
<div class="swiper-wrapper" id="wrapper"></div>
|
||
{% if paint.medias|length > 1%}
|
||
<button class="swiper-button prev" id="prev">‹</button>
|
||
<button class="swiper-button next" id="next">›</button>
|
||
{% endif %}
|
||
<div class="swiper-pagination" id="pagination" {% if paint.medias_original|length == 1%}style="display: none;"{% endif %}></div>
|
||
</div>
|
||
<div class="c_kuvu7 b_tssu9">
|
||
<a class="c_068ki b_etnpf" href="/artists/{{paint.user._id}}"><img class="c_1qh64 b_mmlhf" src="/a/{{paint.user._id}}" crossorigin="anonymous" fetchpriority="high" loading="eager">
|
||
<div class="c_pjz1r b_x7dj6">
|
||
<p class="c_x2iws b_n91ga">{{paint.city or ''}}</p>
|
||
<p class="c_wqjcc b_01urj">{{paint.author or ''}}</p>
|
||
<p class="c_x2ptw b_mxr38">{{paint.grade or ''}}</p>
|
||
</div>
|
||
</a>
|
||
<header class="c_qt7dd b_4sh8z">
|
||
<h3 class="c_78gsr b_o7w2c">{{paint.title}}</h3>
|
||
</header>
|
||
<div class="c_wgfe6 b_a1gdl">
|
||
<p class="c_sbnel b_frv5u">{{paint.size or ''}}</p>
|
||
<p class="c_sbnel b_frv5u">{{paint.material or ''}}</p>
|
||
<p class="c_sbnel b_frv5u">{{paint.genre or ''}}</p>
|
||
</div>
|
||
<div class="c_4g9xz b_ik47g">
|
||
<p class="c_la1ap b_mwej0">Стоимость</p>
|
||
<h3 class="c_w6ecf b_6atmo">{{paint.price or ''}}</h3>
|
||
</div>
|
||
<p class="c_zlnpy b_7efyd">{{paint.description or ''}}</p>
|
||
<p class="c_sbnel b_frv5u">{{ (paint._id.generation_time.strftime('%d.%m.%Y')) if paint._id else ''}}</p>
|
||
{% if user and user._id == post.user._id %}
|
||
<div class="c_ybfp2 b_gagrr">
|
||
<a class="c_eiyz0 b_rhbo8" href="/form/post/{{post._id}}">Редактировать</a>
|
||
<button class="c_eiyz0 b_rhbo8" onclick="deletePost('{{post._id}}')">Удалить</button>
|
||
</div>
|
||
{% else %}
|
||
<a class="c_75ykb b_gk0ob" href="https://telegram.me/gennadiy0605"><span class="c_dlut5 b_v0d1u">Обсудить покупку картины </span></a>
|
||
{% endif %}
|
||
<div class="c_sbnel b_frv5u">{{ share.share('/paintings/{}'.format(paint._id), paint.title, '/b/posts/{}'.format(paint.medias[0])) }}</div>
|
||
<p class="c_sbnel b_frv5u">👁 {{total_watch_count}} (+{{today_watch_count}} Сегодня)</p>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
<script>
|
||
const images = [
|
||
{% for media in paint.medias_original %}
|
||
{ src: "/b/posts/{{media}}" },
|
||
{% endfor %}
|
||
];
|
||
|
||
const wrapper = document.getElementById('wrapper');
|
||
const swiper = document.getElementById('swiper');
|
||
const prevBtn = document.getElementById('prev');
|
||
const nextBtn = document.getElementById('next');
|
||
const pagination = document.getElementById('pagination');
|
||
|
||
let currentIndex = 0;
|
||
let isDragging = false;
|
||
let startX = 0;
|
||
|
||
|
||
function createSlides() {
|
||
wrapper.innerHTML = '';
|
||
pagination.innerHTML = '';
|
||
|
||
images.forEach((item, i) => {
|
||
const slide = document.createElement('div');
|
||
slide.className = 'swiper-slide';
|
||
|
||
const img = document.createElement('img');
|
||
img.crossOrigin = "anonymous";
|
||
img.src = item.src;
|
||
img.loading = "lazy";
|
||
|
||
|
||
slide.append(img);
|
||
wrapper.appendChild(slide);
|
||
|
||
// Пагинация
|
||
const dot = document.createElement('div');
|
||
dot.className = `swiper-pagination-dot ${i === 0 ? 'active' : ''}`;
|
||
dot.onclick = () => goToSlide(i);
|
||
pagination.appendChild(dot);
|
||
});
|
||
|
||
wrapper.style.width = `${100}%`;
|
||
}
|
||
|
||
function updateTransform() {
|
||
wrapper.style.transform = `translate3d(-${currentIndex * 100}%, 0, 0)`;
|
||
|
||
document.querySelectorAll('.swiper-pagination-dot').forEach((dot, i) => {
|
||
dot.classList.toggle('active', i === currentIndex);
|
||
});
|
||
}
|
||
|
||
function goToSlide(index) {
|
||
currentIndex = Math.max(0, Math.min(index, images.length - 1));
|
||
updateTransform();
|
||
}
|
||
|
||
function nextSlide() { currentIndex = (currentIndex + 1) % images.length; updateTransform(); }
|
||
function prevSlide() { currentIndex = (currentIndex - 1 + images.length) % images.length; updateTransform(); }
|
||
|
||
// Drag
|
||
function touchStart(e) {
|
||
isDragging = true;
|
||
startX = e.type.includes('mouse') ? e.pageX : e.touches[0].clientX;
|
||
wrapper.style.transition = 'none';
|
||
}
|
||
|
||
function touchMove(e) {
|
||
if (!isDragging) return;
|
||
const x = e.type.includes('mouse') ? e.pageX : e.touches[0].clientX;
|
||
const percentMoved = ((x - startX) / swiper.clientWidth) * 100;
|
||
wrapper.style.transform = `translate3d(${-currentIndex * 100 + percentMoved}%, 0, 0)`;
|
||
}
|
||
|
||
function touchEnd(e) {
|
||
if (!isDragging) return;
|
||
isDragging = false;
|
||
wrapper.style.transition = 'transform 0.75s cubic-bezier(0.32, 0.72, 0, 1)';
|
||
|
||
const movedPercent = ((e.type.includes('mouse') ? e.pageX : e.changedTouches[0].clientX) - startX) / swiper.clientWidth * 100;
|
||
|
||
if (movedPercent < -25) nextSlide();
|
||
else if (movedPercent > 25) prevSlide();
|
||
else updateTransform();
|
||
}
|
||
|
||
function init() {
|
||
prevBtn.onclick = prevSlide;
|
||
nextBtn.onclick = nextSlide;
|
||
|
||
swiper.addEventListener('touchstart', touchStart, { passive: true });
|
||
swiper.addEventListener('touchmove', touchMove, { passive: true });
|
||
swiper.addEventListener('touchend', touchEnd);
|
||
|
||
swiper.addEventListener('mousedown', touchStart);
|
||
window.addEventListener('mousemove', touchMove);
|
||
window.addEventListener('mouseup', touchEnd);
|
||
|
||
window.addEventListener('resize', updateTransform);
|
||
}
|
||
|
||
// Запуск
|
||
createSlides();
|
||
init();
|
||
setTimeout(updateTransform, 100); // даём браузеру время на рендер
|
||
</script>
|
||
<script>
|
||
function deletePost(postId) {
|
||
fetch(`/api/post/${postId}`, {
|
||
method: 'DELETE'
|
||
})
|
||
.then(response => {
|
||
if (response.ok) {
|
||
// Find and delete the parent figure
|
||
const postElement = document.querySelector(`figure[data-postId='${postId}']`);
|
||
if (postElement) {
|
||
postElement.remove();
|
||
}
|
||
} else {
|
||
showToast({
|
||
message: 'Ошибка соединения с сервером!',
|
||
status: 'error',
|
||
duration: 2500
|
||
});
|
||
}
|
||
})
|
||
.catch(error => {
|
||
// Handle network errors
|
||
showToast({
|
||
message: 'Ошибка соединения с сервером!',
|
||
status: 'error',
|
||
duration: 2500
|
||
});
|
||
});
|
||
}
|
||
</script>
|
||
{{ footer.section(user) }}
|
||
{% endblock %}
|