194 lines
9 KiB
HTML
194 lines
9 KiB
HTML
{% extends "base.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
{% load mention_tags %}
|
|
|
|
{% block head %}
|
|
<style>
|
|
.discussion-item {
|
|
transition: all 0.15s ease-in-out;
|
|
border-left: 4px solid transparent;
|
|
}
|
|
.discussion-item.has-unread {
|
|
background-color: #f4f7ff;
|
|
border-left-color: var(--brand-color, #2f3e8b);
|
|
}
|
|
.discussion-item:hover {
|
|
background-color: #edf2fc;
|
|
text-decoration: none;
|
|
}
|
|
.avatar-discussion {
|
|
width: 44px;
|
|
height: 44px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
}
|
|
.avatar-group {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
}
|
|
.avatar-group .avatar-circle {
|
|
width: 26px;
|
|
height: 26px;
|
|
border-radius: 50%;
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 2px solid #ffffff;
|
|
margin-left: -6px;
|
|
transition: transform 0.15s ease, z-index 0.15s ease;
|
|
box-shadow: 0 1px 2px rgba(0,0,0,0.08);
|
|
cursor: default;
|
|
}
|
|
.avatar-group .avatar-circle:first-child {
|
|
margin-left: 0;
|
|
}
|
|
.avatar-group .avatar-circle:hover {
|
|
transform: translateY(-2px) scale(1.15);
|
|
z-index: 5;
|
|
}
|
|
.avatar-group .avatar-more {
|
|
background-color: #f1f5f9;
|
|
color: #475569;
|
|
font-size: 0.68rem;
|
|
font-weight: 700;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid py-4">
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1 class="h3 mb-0">
|
|
<i class="bi bi-chat-dots me-2 text-primary"></i>{% translate "Discussions" %}
|
|
</h1>
|
|
<div class="d-flex gap-2">
|
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#newDiscussionModal">
|
|
<i class="bi bi-chat-plus-fill me-1.5"></i>{% translate "Nouvelle discussion" %}
|
|
</button>
|
|
<a href="{% url 'notifications:inbox' %}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-bell me-1"></i>{% translate "Notifications" %}
|
|
</a>
|
|
<a href="{% url 'notifications:settings' %}" class="btn btn-outline-secondary" title="{% translate 'Paramètres' %}">
|
|
<i class="bi bi-gear me-1"></i>{% translate "Paramètres" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% if not items %}
|
|
<div class="card border-0 shadow-sm rounded-3">
|
|
<div class="card-body text-center py-5 text-muted">
|
|
<i class="bi bi-chat-square fs-1 d-block mb-3 text-primary opacity-50"></i>
|
|
<p class="mb-0">{% translate "Vous n'avez encore aucune discussion." %}</p>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="card border-0 shadow-sm rounded-3 overflow-hidden">
|
|
<div class="list-group list-group-flush">
|
|
{% for item in items %}
|
|
<a href="{% url 'notifications:discussion_detail' item.discussion.pk %}"
|
|
class="list-group-item list-group-item-action discussion-item px-3 px-md-4 py-3 {% if item.unread_count %}has-unread{% endif %}">
|
|
<div class="d-flex align-items-start gap-3">
|
|
<!-- Icône typée -->
|
|
{% with type_info=item.discussion.type_info %}
|
|
<div class="avatar-discussion {{ type_info.bg_class }} {{ type_info.text_class }} border {{ type_info.border_class }}" title="{{ type_info.label }}">
|
|
<i class="bi {{ type_info.icon }} fs-5"></i>
|
|
</div>
|
|
{% endwith %}
|
|
|
|
<!-- Contenu -->
|
|
<div class="flex-grow-1 min-width-0">
|
|
<div class="d-flex justify-content-between align-items-start gap-2 mb-1">
|
|
<div class="d-flex align-items-center gap-2 flex-wrap min-width-0">
|
|
<span class="fw-semibold text-dark text-truncate" style="font-size: 0.975rem;">
|
|
{{ item.discussion.title|default:item.discussion }}
|
|
</span>
|
|
{% if item.discussion.object_label and item.discussion.object_label != item.discussion.title %}
|
|
<span class="badge bg-light text-secondary border small rounded-pill px-2 py-0.5">
|
|
<i class="bi bi-link-45deg me-0.5"></i>{{ item.discussion.object_label }}
|
|
</span>
|
|
{% endif %}
|
|
{% if item.discussion.is_closed %}
|
|
<span class="badge bg-secondary-subtle text-secondary small rounded-pill px-2 py-0.5">
|
|
<i class="bi bi-lock-fill me-0.5"></i>{% translate "Clôturée" %}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
<span class="text-muted small ms-2 text-nowrap d-flex align-items-center gap-1">
|
|
<i class="bi bi-clock opacity-75"></i>
|
|
{{ item.discussion.updated_at|date:"d/m/Y H:i" }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Aperçu du message nettoyé des tags @[Nom](u:id) -->
|
|
{% if item.last_message %}
|
|
<p class="mb-2 small text-muted text-truncate mt-0.5" style="max-width: 780px;">
|
|
<strong class="text-secondary">{{ item.last_message.author.get_full_name|default:item.last_message.author.username }}</strong> :
|
|
<span class="text-dark opacity-75">{{ item.last_message.content|clean_mentions_preview|truncatechars:140 }}</span>
|
|
</p>
|
|
{% else %}
|
|
<p class="mb-2 small text-muted mt-0.5 fst-italic">{% translate "Aucun message encore." %}</p>
|
|
{% endif %}
|
|
|
|
<!-- Pied de ligne : Participants en avatars empilés & compteur non lu -->
|
|
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2 pt-1">
|
|
<div class="d-flex align-items-center gap-2">
|
|
<span class="text-muted small d-none d-sm-inline" style="font-size: 0.78rem;">
|
|
<i class="bi bi-people me-1 opacity-75"></i>{% translate "Participants" %} :
|
|
</span>
|
|
<div class="avatar-group">
|
|
{% for p in item.discussion.participants.all|slice:":6" %}
|
|
<div class="avatar-circle"
|
|
style="background-color: {{ p|avatar_bg_color }}; color: {{ p|avatar_text_color }};"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="top"
|
|
title="{{ p.get_full_name|default:p.username }}">
|
|
{{ p|user_initials }}
|
|
</div>
|
|
{% endfor %}
|
|
{% if item.discussion.participants.count > 6 %}
|
|
<div class="avatar-circle avatar-more"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="top"
|
|
title="{{ item.discussion.participants.count }} {% translate 'participants au total' %}">
|
|
+{{ item.discussion.participants.count|add:"-6" }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Badge non-lus -->
|
|
{% if item.unread_count %}
|
|
<span class="badge rounded-pill bg-primary px-2.5 py-1 small fw-semibold shadow-sm" style="background-color: var(--brand-color, #2f3e8b) !important;">
|
|
{{ item.unread_count }} {% translate "non lu(s)" %}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
</div>
|
|
{% include "notifications/_new_discussion_modal.html" %}
|
|
{% endblock content %}
|
|
|
|
{% block script %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
|
[...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
|
});
|
|
</script>
|
|
{% endblock script %}
|
|
|