Files
mont_vendor_maps/templates/news_article.html
T

253 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ article.title }} — MONT</title>
<meta name="description" content="{{ article.body[:160] | replace('\n',' ') }}" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="{{ base_url }}/news/{{ article.slug }}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{ base_url }}/news/{{ article.slug }}" />
<meta property="og:title" content="{{ article.title }} — MONT" />
<meta property="og:description" content="{{ article.body[:200] | replace('\n',' ') }}" />
{% if article.image %}<meta property="og:image" content="{{ base_url }}/static/{{ article.image }}" />{% endif %}
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
<link rel="icon" type="image/png" href="/static/favicon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@600;700&family=Manrope:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
:root { --brand: #1f4ea3; --brand2: #3978e0; --bg: #eef4ff; --radius: 16px; }
* { box-sizing: border-box; }
body { margin: 0; font-family: Manrope, sans-serif; background: var(--bg); color: #15203b; min-height: 100vh; }
.wrap { width: min(1100px, calc(100% - 32px)); margin: 0 auto; padding: 28px 0 60px; }
.back-btn {
display: inline-flex; align-items: center; gap: 6px;
font-size: 13px; font-weight: 700; color: var(--brand);
text-decoration: none; margin-bottom: 20px;
padding: 8px 16px; border-radius: 999px;
background: #fff; border: 1px solid #c8d8f7; transition: .15s ease;
}
.back-btn:hover { background: #eef4ff; transform: translateX(-2px); }
.article-card {
background: #fff; border-radius: 20px;
border: 1px solid #dae6ff;
box-shadow: 0 12px 40px rgba(16,43,95,.1);
overflow: hidden;
}
.article-header { display: flex; gap: 20px; align-items: flex-start; padding: 28px 32px 0; }
.article-hero-img {
flex-shrink: 0;
width: 160px; height: 106px;
object-fit: cover;
border-radius: 12px;
display: block;
}
.article-header-text { flex: 1; min-width: 0; }
.article-body-wrap { padding: 20px 32px 36px; }
.article-date { font-size: 12px; color: #8aa0c0; font-weight: 600; margin-bottom: 8px; }
.article-title { font-size: 24px; font-weight: 800; color: #1a3e79; margin: 0; line-height: 1.25; }
.article-body { font-size: 15px; color: #2e3f58; line-height: 1.75; }
.article-body p { margin: 0 0 16px; }
.article-body p:last-child { margin-bottom: 0; }
.article-body a { color: var(--brand); font-weight: 600; text-decoration: none; }
.article-body a:hover { text-decoration: underline; }
.article-body strong, .article-body b { font-weight: 700; color: #1a3e79; }
.article-body em, .article-body i { font-style: italic; }
.article-body ul, .article-body ol { margin: 0 0 16px 20px; padding: 0; }
.article-body li { margin-bottom: 6px; }
.article-body h2, .article-body h3, .article-body h4 { font-weight: 800; color: #1a3e79; margin: 20px 0 10px; line-height: 1.3; }
.article-body h2 { font-size: 20px; }
.article-body h3 { font-size: 17px; }
.article-body blockquote { border-left: 3px solid var(--brand); margin: 16px 0; padding: 8px 16px; background: #f0f5ff; border-radius: 0 8px 8px 0; color: #526079; }
.article-body table { width: 100%; border-collapse: collapse; margin: 0 0 16px; font-size: 14px; }
.article-body th, .article-body td { border: 1px solid #dae6ff; padding: 8px 12px; text-align: left; }
.article-body th { background: #eef4ff; font-weight: 700; color: #1a3e79; }
.article-contact {
margin-top: 28px; padding-top: 20px;
border-top: 1px solid #e8f0ff;
font-size: 13px; color: #526079;
}
.article-contact a { color: var(--brand); font-weight: 700; text-decoration: none; }
.article-contact a:hover { text-decoration: underline; }
.credit {
text-align: center; margin-top: 24px;
}
.credit button {
font-family: 'Caveat', cursive; font-size: 18px;
color: #1c3f7c; background: none; border: none;
cursor: pointer; padding: 0;
transition: opacity .15s;
}
.credit button:hover { opacity: .7; }
.edit-btn {
display: inline-flex; align-items: center; gap: 6px;
font-size: 13px; font-weight: 700; color: #1f4ea3;
text-decoration: none; padding: 7px 16px;
border-radius: 999px; background: #eef4ff;
border: 1px solid #c8d8f7; transition: .15s;
margin-bottom: 16px; float: right;
}
.edit-btn:hover { background: #dceeff; }
@media (max-width: 640px) {
.article-header { flex-direction: column; padding: 20px 20px 0; }
.article-hero-img { width: 100%; height: 140px; }
.article-body-wrap { padding: 16px 20px 28px; }
.article-title { font-size: 20px; }
}
</style>
</head>
<body>
<div class="wrap">
<a href="/" class="back-btn">← На главную</a>
{% if is_news_editor %}
<a href="/news-admin" class="edit-btn">✏ Редактировать</a>
<div style="clear:both;"></div>
{% endif %}
<article class="article-card">
<div class="article-header">
{% if article.image %}
<img class="article-hero-img" src="/static/{{ article.image }}" alt="{{ article.title }}" />
{% endif %}
<div class="article-header-text">
<div class="article-date">{{ article.created_at[8:10] }}.{{ article.created_at[5:7] }}.{{ article.created_at[:4] }}</div>
<h1 class="article-title">{{ article.title }}</h1>
</div>
</div>
<div class="article-body-wrap">
<div class="article-body">
{% if '<' in article.body %}
{{ article.body | safe }}
{% else %}
{% for paragraph in article.body.split('\n\n') %}
<p>{{ paragraph }}</p>
{% endfor %}
{% endif %}
</div>
<div class="article-contact">
По вопросам сотрудничества: <a href="mailto:mshamov@mont.com">mshamov@mont.com</a>
</div>
</div>
</article>
<div class="credit">
<button type="button" id="btn-contact-ruslan">Made by Galyaviev</button>
</div>
</div>
<!-- Contact modal -->
<div id="contact-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:9000;align-items:center;justify-content:center;padding:1rem;">
<div style="background:#fff;border-radius:20px;width:100%;max-width:460px;max-height:90vh;overflow-y:auto;box-shadow:0 24px 64px rgba(16,43,95,.22);">
<div style="padding:1.5rem 1.75rem .75rem;display:flex;align-items:center;justify-content:space-between;">
<div style="font-size:1.15rem;font-weight:800;color:#1a3e79;">Связаться с Русланом</div>
<button onclick="window._closeContact()" style="background:none;border:none;font-size:1.4rem;color:#8aa;cursor:pointer;line-height:1;padding:0 4px;">×</button>
</div>
<div id="cm-body" style="padding:.5rem 1.75rem;display:flex;flex-direction:column;gap:.9rem;"></div>
<div id="cm-footer" style="display:flex;justify-content:flex-end;gap:.75rem;padding:.75rem 1.75rem 1.5rem;"></div>
</div>
</div>
<script>
(function() {
const overlay = document.getElementById('contact-modal');
const fieldStyle = 'width:100%;box-sizing:border-box;margin-top:.3rem;padding:.6rem .85rem;' +
'background:#f7faff;border:1px solid #c8d8f7;border-radius:9px;color:#1a3060;' +
'font-size:.92rem;outline:none;font-family:Manrope,sans-serif;';
const labelStyle = 'color:#526079;font-size:.8rem;font-weight:700;letter-spacing:.2px;';
function buildForm() {
document.getElementById('cm-body').innerHTML =
'<div><label style="' + labelStyle + '">Ваше имя *</label>' +
'<input id="cm-name" type="text" placeholder="Иван Иванов" style="' + fieldStyle + '"/></div>' +
'<div><label style="' + labelStyle + '">Email *</label>' +
'<input id="cm-email" type="email" placeholder="ivan@company.ru" style="' + fieldStyle + '"/></div>' +
'<div><label style="' + labelStyle + '">Телефон *</label>' +
'<input id="cm-phone" type="tel" placeholder="+7 (999) 000-00-00" style="' + fieldStyle + '"/></div>' +
'<div><label style="' + labelStyle + '">Сообщение *</label>' +
'<textarea id="cm-text" rows="4" placeholder="Ваш вопрос или предложение..." style="' + fieldStyle + 'resize:vertical;"></textarea></div>' +
'<div id="cm-error" style="display:none;background:#fff0f0;border:1px solid #fcc;border-radius:8px;' +
'padding:.5rem .85rem;color:#c0392b;font-size:.85rem;"></div>';
document.getElementById('cm-footer').innerHTML =
'<button onclick="window._closeContact()" style="background:#f0f5ff;border:1px solid #c8d8f7;border-radius:9px;' +
'padding:.6rem 1.25rem;color:#526079;cursor:pointer;font-family:Manrope,sans-serif;font-weight:600;">Отмена</button>' +
'<button id="cm-submit" style="background:linear-gradient(135deg,#1f4ea3,#3978e0);border:none;border-radius:9px;' +
'padding:.6rem 1.5rem;color:#fff;font-weight:700;cursor:pointer;font-family:Manrope,sans-serif;">Отправить</button>';
document.getElementById('cm-submit').addEventListener('click', submit);
}
function openModal() {
buildForm();
overlay.style.display = 'flex';
document.body.style.overflow = 'hidden';
setTimeout(() => { const n = document.getElementById('cm-name'); if (n) n.focus(); }, 80);
}
window._closeContact = function() {
overlay.style.display = 'none';
document.body.style.overflow = '';
};
async function submit() {
const name = document.getElementById('cm-name').value.trim();
const email = document.getElementById('cm-email').value.trim();
const phone = document.getElementById('cm-phone').value.trim();
const text = document.getElementById('cm-text').value.trim();
const errEl = document.getElementById('cm-error');
const btn = document.getElementById('cm-submit');
const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phoneRe = /^[\+\d][\d\s\-\(\)]{6,18}$/;
const errors = [];
[[!name, 'cm-name'], [!emailRe.test(email), 'cm-email'],
[!phoneRe.test(phone), 'cm-phone'], [!text, 'cm-text']].forEach(([bad, id]) => {
document.getElementById(id).style.borderColor = bad ? '#e74c3c' : '#c8d8f7';
if (bad) errors.push(id);
});
if (errors.length) {
errEl.textContent = 'Пожалуйста, заполните все поля корректно';
errEl.style.display = 'block';
return;
}
btn.disabled = true;
btn.textContent = 'Отправка...';
errEl.style.display = 'none';
try {
const res = await fetch('/api/contact', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({name, email, phone, text}),
});
if (!res.ok) {
const d = await res.json().catch(() => ({}));
throw new Error(d.detail || 'Ошибка отправки');
}
document.getElementById('cm-body').innerHTML =
'<div style="text-align:center;padding:2rem 0">' +
'<div style="width:56px;height:56px;border-radius:50%;background:linear-gradient(135deg,#1f4ea3,#3978e0);' +
'color:#fff;font-size:1.8rem;display:flex;align-items:center;justify-content:center;margin:0 auto 1rem;">✓</div>' +
'<div style="font-size:1.1rem;font-weight:800;color:#1a3e79;">Отправлено!</div>' +
'<div style="color:#526079;font-size:.9rem;margin-top:.4rem;">Постараюсь ответить в ближайшее время</div></div>';
document.getElementById('cm-footer').innerHTML =
'<button onclick="window._closeContact()" style="background:linear-gradient(135deg,#1f4ea3,#3978e0);border:none;' +
'border-radius:9px;padding:.6rem 1.5rem;color:#fff;font-weight:700;cursor:pointer;font-family:Manrope,sans-serif;">Закрыть</button>';
} catch(e) {
errEl.textContent = e.message || 'Ошибка отправки';
errEl.style.display = 'block';
btn.disabled = false;
btn.textContent = 'Отправить';
}
}
document.getElementById('btn-contact-ruslan').addEventListener('click', openModal);
overlay.addEventListener('click', e => { if (e.target === overlay) window._closeContact(); });
document.addEventListener('keydown', e => { if (e.key === 'Escape') window._closeContact(); });
})();
</script>
</body>
</html>