655ba8c31a
Список публикаций, форма создания/редактирования, детальная (комментарии,
публикация в Mattermost, важное/закреплённое), JS-строки (загрузка картинок,
свернуть/развернуть) помечены {% trans %} и переведены на uk/en.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
175 lines
11 KiB
HTML
175 lines
11 KiB
HTML
{% load i18n %}
|
|
<div class="page-content">
|
|
|
|
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:1.5rem;">
|
|
<div>
|
|
<h1 style="font-size:1.25rem; font-weight:500; color:var(--color-foreground);">{% trans "Новости" %}</h1>
|
|
<p style="font-size:0.875rem; color:var(--color-muted-foreground); margin-top:0.25rem;">{% trans "Объявления и важные события компании" %}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{% if form_error %}
|
|
<div style="background:color-mix(in srgb, var(--color-destructive) 8%, transparent); border:1px solid color-mix(in srgb, var(--color-destructive) 30%, transparent); border-radius:0.75rem; padding:0.875rem 1.25rem; margin-bottom:1rem; font-size:0.875rem; color:var(--color-destructive);">
|
|
{{ form_error }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if request.user.is_staff %}
|
|
<!-- Створення поста (staff) -->
|
|
<details style="margin-bottom:1.25rem;" {% if form_error %}open{% endif %}>
|
|
<summary class="btn btn-primary" style="display:inline-flex; align-items:center; gap:0.375rem; cursor:pointer; list-style:none; width:fit-content;">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
|
|
</svg>
|
|
{% trans "Новая публикация" %}
|
|
</summary>
|
|
<form id="post-create-form" hx-post="/news/" hx-target="#main-content" hx-indicator="#loader"
|
|
style="margin-top:0.75rem; background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; padding:1.25rem; display:flex; flex-direction:column; gap:0.875rem;">
|
|
{% csrf_token %}
|
|
<input type="text" name="title" required maxlength="250" placeholder="{% trans 'Заголовок' %}" class="input" style="width:100%; font-weight:500;">
|
|
<textarea name="body" id="post-body-editor" placeholder="{% trans 'Текст публикации...' %}"
|
|
style="width:100%; min-height:6rem;"></textarea>
|
|
<script>
|
|
(function() {
|
|
if (!window.tinymce) return;
|
|
tinymce.remove('#post-body-editor');
|
|
tinymce.init({
|
|
selector: '#post-body-editor',
|
|
height: 320,
|
|
menubar: false,
|
|
plugins: 'lists link table autolink image',
|
|
toolbar: 'undo redo | blocks | bold italic underline strikethrough | ' +
|
|
'forecolor | alignleft aligncenter alignright | ' +
|
|
'bullist numlist | link table image | removeformat',
|
|
language: 'uk',
|
|
license_key: 'gpl',
|
|
promotion: false,
|
|
branding: false,
|
|
convert_urls: false,
|
|
// Держим textarea синхронизированной постоянно — HTMX собирает
|
|
// данные формы до события configRequest
|
|
setup: function (editor) {
|
|
editor.on('change input undo redo SetContent keyup', function () {
|
|
editor.save();
|
|
});
|
|
},
|
|
// Вставленные/загруженные картинки уходят на сервер,
|
|
// в пост попадает обычный /media/-URL (data:-URI срезает санитизатор)
|
|
paste_data_images: true,
|
|
automatic_uploads: true,
|
|
images_upload_handler: function (blobInfo) {
|
|
return new Promise(function (resolve, reject) {
|
|
var form = document.getElementById('post-create-form');
|
|
var token = form.querySelector('input[name=csrfmiddlewaretoken]').value;
|
|
var data = new FormData();
|
|
data.append('file', blobInfo.blob(), blobInfo.filename());
|
|
fetch('/news/upload-image/', {
|
|
method: 'POST',
|
|
headers: {'X-CSRFToken': token},
|
|
body: data,
|
|
}).then(function (r) {
|
|
return r.json().then(function (j) { return {ok: r.ok, j: j}; });
|
|
}).then(function (res) {
|
|
if (res.ok && res.j.location) resolve(res.j.location);
|
|
else reject(res.j.error || '{% trans "Ошибка загрузки изображения" %}');
|
|
}).catch(function () {
|
|
reject('{% trans "Ошибка загрузки изображения" %}');
|
|
});
|
|
});
|
|
},
|
|
});
|
|
})();
|
|
</script>
|
|
<div style="display:flex; align-items:center; gap:1.25rem; flex-wrap:wrap;">
|
|
<select name="category" class="input" style="width:auto; font-size:0.8125rem;">
|
|
{% for value, label in categories %}
|
|
<option value="{{ value }}">{{ label }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<label style="display:flex; align-items:center; gap:0.375rem; font-size:0.8125rem; color:var(--color-foreground); cursor:pointer;">
|
|
<input type="checkbox" name="is_important"> {% trans "Важно" %}
|
|
</label>
|
|
<label style="display:flex; align-items:center; gap:0.375rem; font-size:0.8125rem; color:var(--color-foreground); cursor:pointer;">
|
|
<input type="checkbox" name="is_pinned"> {% trans "Закрепить" %}
|
|
</label>
|
|
<span style="font-size:0.75rem; color:var(--color-muted-foreground);">{% trans "Опубликовать в чат:" %}</span>
|
|
{% for code, label in mattermost_target_teams %}
|
|
<label style="display:flex; align-items:center; gap:0.375rem; font-size:0.8125rem; color:var(--color-foreground); cursor:pointer;">
|
|
<input type="checkbox" name="mattermost_targets" value="{{ code }}"> {{ label }}
|
|
</label>
|
|
{% endfor %}
|
|
<button type="submit" class="btn btn-primary" style="margin-left:auto;">{% trans "Опубликовать" %}</button>
|
|
</div>
|
|
</form>
|
|
</details>
|
|
{% endif %}
|
|
|
|
<!-- Фільтри -->
|
|
<div style="display:flex; gap:0.25rem; margin-bottom:1.25rem; background:var(--color-muted); border-radius:var(--radius); padding:0.25rem; width:fit-content;">
|
|
{% with base_style="display:inline-flex; align-items:center; gap:0.375rem; padding:0.375rem 0.875rem; border-radius:calc(var(--radius) - 2px); font-size:0.8125rem; font-weight:500; text-decoration:none; cursor:pointer;" %}
|
|
<a href="/news/" hx-get="/news/" hx-target="#main-content" hx-push-url="/news/" hx-indicator="#loader"
|
|
style="{{ base_style }} {% if not active_filter %}background:var(--color-primary); color:var(--color-primary-foreground);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Все" %}</a>
|
|
<a href="/news/?category=important" hx-get="/news/?category=important" hx-target="#main-content" hx-push-url="/news/?category=important" hx-indicator="#loader"
|
|
style="{{ base_style }} {% if active_filter == 'important' %}background:var(--color-primary); color:var(--color-primary-foreground);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Важные" %}</a>
|
|
{% for value, label in categories %}
|
|
<a href="/news/?category={{ value }}" hx-get="/news/?category={{ value }}" hx-target="#main-content" hx-push-url="/news/?category={{ value }}" hx-indicator="#loader"
|
|
style="{{ base_style }} {% if active_filter == value %}background:var(--color-primary); color:var(--color-primary-foreground);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{{ label }}</a>
|
|
{% endfor %}
|
|
{% endwith %}
|
|
</div>
|
|
|
|
<style>
|
|
.post-body img { max-width: 100%; height: auto; border-radius: 0.5rem; }
|
|
.post-body table { border-collapse: collapse; }
|
|
.post-body td, .post-body th { border: 1px solid var(--color-border); padding: 0.375rem 0.625rem; }
|
|
|
|
/* Сворачивание длинных постов */
|
|
.post-collapse { position: relative; max-height: 19rem; overflow: hidden; margin-bottom: 0.75rem; }
|
|
.post-collapse.expanded { max-height: none; }
|
|
.post-collapse .post-fade { display: none; position: absolute; bottom: 0; left: 0; right: 0; height: 4.5rem; background: linear-gradient(transparent, var(--color-card)); pointer-events: none; }
|
|
.post-collapse.overflowing:not(.expanded) .post-fade { display: block; }
|
|
</style>
|
|
<script>
|
|
window.feedTogglePost = function (btn) {
|
|
var wrap = btn.previousElementSibling;
|
|
var expanded = wrap.classList.toggle('expanded');
|
|
btn.textContent = expanded ? '{% trans "Свернуть" %} ↑' : '{% trans "Показать полностью" %} ↓';
|
|
if (!expanded) wrap.scrollIntoView({block: 'nearest'});
|
|
};
|
|
(function () {
|
|
document.querySelectorAll('.post-collapse:not([data-collapse-init])').forEach(function (el) {
|
|
el.setAttribute('data-collapse-init', '1');
|
|
var btn = el.nextElementSibling;
|
|
function check() {
|
|
if (el.classList.contains('expanded')) return;
|
|
if (el.scrollHeight > el.clientHeight + 24) {
|
|
el.classList.add('overflowing');
|
|
if (btn) btn.style.display = 'inline-flex';
|
|
}
|
|
}
|
|
check();
|
|
// картинки грузятся позже — перепроверяем высоту после каждой
|
|
el.querySelectorAll('img').forEach(function (img) {
|
|
if (!img.complete) img.addEventListener('load', check);
|
|
});
|
|
});
|
|
})();
|
|
</script>
|
|
|
|
<!-- Стрічка: пости повністю -->
|
|
{% for post in pinned_posts %}
|
|
{% include 'partials/feed-post-card.html' with post=post pinned=True %}
|
|
{% endfor %}
|
|
|
|
{% for post in posts %}
|
|
{% include 'partials/feed-post-card.html' with post=post pinned=False %}
|
|
{% empty %}
|
|
{% if not pinned_posts %}
|
|
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:2.5rem; text-align:center; color:var(--color-muted-foreground); font-size:0.875rem;">
|
|
{% if active_filter %}{% trans "По этому фильтру публикаций нет" %}{% else %}{% trans "Публикаций пока нет" %}{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
</div>
|