Changement de présentation (en cours) après discussion avec Alice
This commit is contained in:
parent
be1fbe703d
commit
713e287210
@ -86,6 +86,9 @@ class Event(models.Model):
|
||||
|
||||
tags = ArrayField(models.CharField(max_length=64), verbose_name=_('Tags'), help_text=_("A list of tags that describe the event."), blank=True, null=True)
|
||||
|
||||
def single_day(self):
|
||||
return not self.end_day or self.end_day == self.start_day
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("view_event", kwargs={"pk": self.pk, "extra": self.title})
|
||||
|
||||
|
76
src/agenda_culturel/static/js/modal.js
Normal file
76
src/agenda_culturel/static/js/modal.js
Normal file
@ -0,0 +1,76 @@
|
||||
const isOpenClass = "modal-is-open";
|
||||
const openingClass = "modal-is-opening";
|
||||
const closingClass = "modal-is-closing";
|
||||
let visibleModal = null;
|
||||
|
||||
// Toggle modal
|
||||
const toggleModal = (event) => {
|
||||
event.preventDefault();
|
||||
const modal = document.getElementById(event.currentTarget.getAttribute("data-target"));
|
||||
typeof modal != "undefined" && modal != null && isModalOpen(modal)
|
||||
? closeModal(modal)
|
||||
: openModal(modal);
|
||||
};
|
||||
|
||||
// Is modal open
|
||||
const isModalOpen = (modal) => {
|
||||
return modal.hasAttribute("open") && modal.getAttribute("open") != "false" ? true : false;
|
||||
};
|
||||
|
||||
// Open modal
|
||||
const openModal = (modal) => {
|
||||
if (isScrollbarVisible()) {
|
||||
document.documentElement.style.setProperty("--scrollbar-width", `${getScrollbarWidth()}px`);
|
||||
}
|
||||
modal.setAttribute("open", true);
|
||||
};
|
||||
|
||||
// Close modal
|
||||
const closeModal = (modal) => {
|
||||
visibleModal = null;
|
||||
document.documentElement.style.removeProperty("--scrollbar-width");
|
||||
modal.removeAttribute("open");
|
||||
};
|
||||
|
||||
// Close with a click outside
|
||||
document.addEventListener("click", (event) => {
|
||||
if (visibleModal != null) {
|
||||
const modalContent = visibleModal.querySelector("article");
|
||||
const isClickInside = modalContent.contains(event.target);
|
||||
!isClickInside && closeModal(visibleModal);
|
||||
}
|
||||
});
|
||||
|
||||
// Close with Esc key
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape" && visibleModal != null) {
|
||||
closeModal(visibleModal);
|
||||
}
|
||||
});
|
||||
|
||||
// Get scrollbar width
|
||||
const getScrollbarWidth = () => {
|
||||
// Creating invisible container
|
||||
const outer = document.createElement("div");
|
||||
outer.style.visibility = "hidden";
|
||||
outer.style.overflow = "scroll"; // forcing scrollbar to appear
|
||||
outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
|
||||
document.body.appendChild(outer);
|
||||
|
||||
// Creating inner element and placing it in the container
|
||||
const inner = document.createElement("div");
|
||||
outer.appendChild(inner);
|
||||
|
||||
// Calculating difference between container's full width and the child width
|
||||
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
|
||||
|
||||
// Removing temporary elements from the DOM
|
||||
outer.parentNode.removeChild(outer);
|
||||
|
||||
return scrollbarWidth;
|
||||
};
|
||||
|
||||
// Is scrollbar visible
|
||||
const isScrollbarVisible = () => {
|
||||
return document.body.scrollHeight > screen.height;
|
||||
};
|
@ -160,4 +160,26 @@ footer {
|
||||
|
||||
.infos-and-buttons .buttons {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
article.day {
|
||||
margin: 0;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
article.day>ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
>li {
|
||||
list-style: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
.navigation {
|
||||
margin: 1em 0;
|
||||
}
|
66
src/agenda_culturel/templates/agenda_culturel/day-inc.html
Normal file
66
src/agenda_culturel/templates/agenda_culturel/day-inc.html
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
{% load cat_extra %}
|
||||
{% load static %}
|
||||
|
||||
{% with day.date|date:"Y-m-d" as daytag %}
|
||||
{% with "date-"|add:daytag as daytag %}
|
||||
|
||||
<article class="day" id="{{ daytag }}">
|
||||
<h2><a href="{% url 'day_view' day.date.year day.date.month day.date.day %}">{{ day.date | date:"l j" }}</a></h2>
|
||||
{% if day.events %}
|
||||
{% if resume %}
|
||||
<ul>
|
||||
{% for category, events in day.events_by_category.items %}
|
||||
<li>{{ events.0.category | circle_cat }}
|
||||
<a href="{{ daytag }}" data-target="{{ daytag }}-category-{{ category.id }}" onClick="toggleModal(event)">{{ events | length }} {{ category }}</a></li>
|
||||
<dialog id="{{ daytag }}-category-{{ category.id }}">
|
||||
<article>
|
||||
<header>
|
||||
<a href="#{{ daytag }}-category-{{ category.id }}"
|
||||
aria-label="Fermer"
|
||||
class="close"
|
||||
data-target="{{ daytag }}-category-{{ category.id }}"
|
||||
onClick="toggleModal(event)"></a>
|
||||
<h3>{{ events.0.category | small_cat }} du {{ day.date | date:"l j F" }}</h3>
|
||||
</header>
|
||||
<ul>
|
||||
{% for event in events %}
|
||||
<li>
|
||||
{% if event.single_day and event.start_time %}
|
||||
{{ event.start_time }}
|
||||
{% endif %}
|
||||
<a href="{{ event.get_absolute_url }}">{{ event.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<footer>
|
||||
<div class="buttons">
|
||||
<a href="{% url 'day_view' day.date.year day.date.month day.date.day %}" role="button">Voir la journée <svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-right" />
|
||||
</svg></a>
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
</dialog>
|
||||
{% endfor %}
|
||||
<ul>
|
||||
{% else %}
|
||||
{% for event in day.events %}
|
||||
<li>{{ event.category | circle_cat }}
|
||||
{% if event.single_day and event.start_time %}
|
||||
{{ event.start_time }}
|
||||
{% endif %}
|
||||
<a href="{{ daytag }}" data-target="event-{{ event.id }}" onClick="toggleModal(event)">{{ event.title }}</a>
|
||||
<dialog id="event-{{ event.id }}">
|
||||
{% include "agenda_culturel/event-inc.html" with event=event display="modal" close_button=1 %}
|
||||
</dialog>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
{% endwith %}
|
||||
{% endwith %}
|
@ -45,83 +45,120 @@
|
||||
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
||||
</em></p>
|
||||
{% endif %}
|
||||
{% elif display == "modal" %}
|
||||
|
||||
<header>
|
||||
<a href="#event-{{ event.id }}"
|
||||
aria-label="Fermer"
|
||||
class="close"
|
||||
data-target="event-{{ event.id }}"
|
||||
onClick="toggleModal(event)"></a>
|
||||
<h3>{{ event.category | small_cat }} {{ event.title }}</h3>
|
||||
|
||||
<p>
|
||||
<svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#map-pin" />
|
||||
</svg>
|
||||
{{ event.location }}
|
||||
</p>
|
||||
<p><svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#calendar" />
|
||||
</svg>
|
||||
{% if event.end_day %}du{% else %}le{% endif %}
|
||||
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
{% else %}
|
||||
<header>
|
||||
{% include "agenda_culturel/ephemeris-inc.html" with event=event %}
|
||||
<h1>{{ event.title }}</h1>
|
||||
<p>
|
||||
<svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#map-pin" />
|
||||
</svg>
|
||||
{{ event.location }}
|
||||
</p>
|
||||
<p><svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#calendar" />
|
||||
</svg>
|
||||
{% if event.end_day %}du{% else %}le{% endif %}
|
||||
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
||||
</p>
|
||||
<p>
|
||||
<svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#map-pin" />
|
||||
</svg>
|
||||
{{ event.location }}
|
||||
</p>
|
||||
</header>
|
||||
{% endif %}
|
||||
|
||||
{% if event.image %}
|
||||
{% if event.image and display != "modal" %}
|
||||
<article class='illustration{% if display in "in list by day" %}-small{% endif %}'>
|
||||
<img src="{{ event.image }}" alt="{{ event.image_alt }}" />
|
||||
</article>
|
||||
{% endif %}
|
||||
|
||||
{% if display in "in list by day" %}
|
||||
{% if display in "in list by day" or display == "modal" %}
|
||||
<p>{{ event.description |truncatewords:20 }}</p>
|
||||
{% else %}
|
||||
<p>{{ event.description }}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
{% comment %}
|
||||
On affiche le pied qui contient les informations de tags, catégories, etc
|
||||
{% endcomment %}
|
||||
<footer class="infos-and-buttons">
|
||||
<div class="infos">
|
||||
<p>
|
||||
{% if mode %}
|
||||
{% if category %}
|
||||
{{ event.category | small_cat }}
|
||||
{% else %}
|
||||
{% url 'view_mode_cat' selected_mode.name event.category.pk as url_cat %}
|
||||
{{ event.category | small_cat:url_cat }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ event.category | small_cat }}
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
{% for tag in event.tags %}
|
||||
<a href="{% url 'view_tag' tag %}" role="button" class="small-cat">{{ tag }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
{% if event.reference_urls %}
|
||||
{% if display in "in list by day" %}
|
||||
<p>Source{{ event.reference_urls|pluralize }} :
|
||||
{% else %}
|
||||
<p>Cet événement est proposé par :
|
||||
{% endif %}
|
||||
{% for eurl in event.reference_urls %}
|
||||
<a href="{{ eurl }}">{{ eurl|hostname }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% if display == "modal" %}
|
||||
<p>
|
||||
{% for tag in event.tags %}
|
||||
<a href="{% url 'view_tag' tag %}" role="button" class="small-cat">{{ tag }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% else %}
|
||||
<p><em>Cet événement est disponible uniquement sur les nuits énimagmatiques.</em></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if user.is_authenticated %}
|
||||
<div class="buttons">
|
||||
<a href="{% url 'edit_event' event.id %}" role="button">éditer</a>
|
||||
<a href="{% url 'delete_event' event.id %}" role="button">supprimer</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<footer class="infos-and-buttons">
|
||||
<div class="buttons">
|
||||
<a href="{{ event.get_absolute_url }}" role="button">Voir l'événement <svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-right" />
|
||||
</svg></a>
|
||||
</div>
|
||||
</footer>
|
||||
{% else %}
|
||||
|
||||
|
||||
<footer class="infos-and-buttons">
|
||||
<div class="infos">
|
||||
<p>
|
||||
{% if mode %}
|
||||
{% if category %}
|
||||
{{ event.category | small_cat }}
|
||||
{% else %}
|
||||
{% url 'view_mode_cat' selected_mode.name event.category.pk as url_cat %}
|
||||
{{ event.category | small_cat:url_cat }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ event.category | small_cat }}
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
{% for tag in event.tags %}
|
||||
<a href="{% url 'view_tag' tag %}" role="button" class="small-cat">{{ tag }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
{% if event.reference_urls %}
|
||||
{% if display in "in list by day" %}
|
||||
<p>Source{{ event.reference_urls|pluralize }} :
|
||||
{% else %}
|
||||
<p>Cet événement est proposé par :
|
||||
{% endif %}
|
||||
{% for eurl in event.reference_urls %}
|
||||
<a href="{{ eurl }}">{{ eurl|hostname }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% else %}
|
||||
<p><em>Cet événement est disponible uniquement sur les nuits énimagmatiques.</em></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if user.is_authenticated %}
|
||||
<div class="buttons">
|
||||
<a href="{% url 'edit_event' event.id %}" role="button">éditer</a>
|
||||
<a href="{% url 'delete_event' event.id %}" role="button">supprimer</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</footer>
|
||||
{% endif %}
|
||||
</article>
|
||||
|
||||
|
66
src/agenda_culturel/templates/agenda_culturel/page-day.html
Normal file
66
src/agenda_culturel/templates/agenda_culturel/page-day.html
Normal file
@ -0,0 +1,66 @@
|
||||
{% extends "agenda_culturel/page.html" %}
|
||||
|
||||
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% load cat_extra %}
|
||||
{% load event_extra %}
|
||||
{% load utils_extra %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
{% block entete_header %}
|
||||
{% css_categories %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
Événements du {{ date | date:"l j F" }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
<h1>Les événements du {{ day | date:"l j F" }}</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<article>
|
||||
<div class="grid navigation">
|
||||
<div>
|
||||
{% with day|shift_day:-1 as pred_day %}
|
||||
<a role="button" href="{% url 'day_view' pred_day.year pred_day.month pred_day.day %}"><svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-left" />
|
||||
</svg> Jour précédent</a>
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="right">
|
||||
{% with day|shift_day:1 as next_day %}
|
||||
<a role="button" href="{% url 'day_view' next_day.year next_day.month next_day.day %}">Jour suivant <svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-right" />
|
||||
</svg></a>
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{% if events %}
|
||||
{% for event in events %}
|
||||
{% include "agenda_culturel/event-inc.html" with event=event display="in list by day" %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<article>
|
||||
Il n'y a pas d'événement prévu à cette date.
|
||||
</article>
|
||||
{% endif %}
|
||||
|
||||
<article>
|
||||
<p>Voir aussi tous les événements
|
||||
<a href="{% url 'week_view' day.year day|week %}">de la semaine
|
||||
du {{ day|first_day_of_this_week }}
|
||||
au {{ day|last_day_of_this_week }}</a>.</p>
|
||||
</article>
|
||||
{% endblock %}
|
@ -0,0 +1,56 @@
|
||||
{% extends "agenda_culturel/page.html" %}
|
||||
|
||||
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% load cat_extra %}
|
||||
{% load event_extra %}
|
||||
{% load utils_extra %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
{% block entete_header %}
|
||||
{% css_categories %}
|
||||
<script src="{% static 'js/modal.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
Événements {{ calendar.firstdate | date:"F o"|add_de }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main-fluid %}-fluid{% endblock %}
|
||||
{% block footer-fluid %}-fluid{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Événements de {{ calendar.firstdate | date:"F o" }}</h1>
|
||||
|
||||
<article>
|
||||
<header>
|
||||
<div class="grid navigation">
|
||||
<div>
|
||||
<a role="button" href="{% url 'month_view' calendar.previous_month.year calendar.previous_month.month %}"><svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-left" />
|
||||
</svg> Mois précédent</a>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a role="button" href="{% url 'month_view' calendar.next_month.year calendar.next_month.month %}">Mois suivant <svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-right" />
|
||||
</svg></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="calendar">
|
||||
<div class="grid">
|
||||
{% for d in calendar.calendar_days_list %}
|
||||
{% if forloop.counter0|divisibleby:7 and not forloop.first %}</div><div class="grid">{% endif %}
|
||||
{% include "agenda_culturel/day-inc.html" with day=d resume=1 %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
65
src/agenda_culturel/templates/agenda_culturel/page-week.html
Normal file
65
src/agenda_culturel/templates/agenda_culturel/page-week.html
Normal file
@ -0,0 +1,65 @@
|
||||
{% extends "agenda_culturel/page.html" %}
|
||||
|
||||
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% load cat_extra %}
|
||||
{% load event_extra %}
|
||||
{% load utils_extra %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
{% block entete_header %}
|
||||
{% css_categories %}
|
||||
<script src="{% static 'js/modal.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
Événements de la semaine {{ week }} - {{ year }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main-fluid %}-fluid{% endblock %}
|
||||
{% block footer-fluid %}-fluid{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<hgroup>
|
||||
<h1>Les événements de la semaine {{ week }}</h1>
|
||||
<h2>Du {{ calendar.calendar_days_list.0.date }} au {{ calendar.calendar_days_list.6.date }} </h2>
|
||||
</hgroup>
|
||||
|
||||
|
||||
|
||||
|
||||
<article>
|
||||
<header>
|
||||
<div class="grid navigation">
|
||||
<div>
|
||||
<a role="button" href="{% url 'week_view' calendar.previous_week.year calendar.previous_week|week %}"><svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-left" />
|
||||
</svg> Semaine précédente</a>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a role="button" href="{% url 'week_view' calendar.next_week.year calendar.next_week|week %}">Semaine suivante <svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<use href="{% static 'images/feather-sprite.svg' %}#chevron-right" />
|
||||
</svg></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="grid" id="calendar">
|
||||
{% for d in calendar.calendar_days_list %}
|
||||
{% include "agenda_culturel/day-inc.html" with day=d %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>Voir aussi tous les événements du mois de
|
||||
<a href="{% url 'month_view' calendar.firstdate.year calendar.firstdate.month %}">{{ calendar.firstdate | date:"F o" }}</a>{% if calendar.firstdate.month != calendar.lastdate.month %}
|
||||
ou tous les événements du mois de <a href="{% url 'month_view' calendar.lastdate.year calendar.lastdate.month %}">{{ calendar.lastdate | date:"F o" }}</a>
|
||||
{% endif %}.</p>
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
|
||||
{% endblock %}
|
@ -27,15 +27,26 @@
|
||||
<nav class="container-fluid">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/" aria-label="Retour accueil">
|
||||
<a href="{% url 'home' %}" aria-label="Retour accueil">
|
||||
<img src="{% static 'images/favicon.svg' %}" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Les nuits énigmagmatiques
|
||||
<a href="{% url 'home' %}" aria-label="Retour accueil">Les nuits énimagmatiques</a>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<details role="list" dir="rtl">
|
||||
<summary aria-haspopup="listbox" role="link">Dates</summary>
|
||||
<ul role="listbox">
|
||||
<li><a href="{% url 'aujourdhui' %}">Aujourd'hui</a></li>
|
||||
<li><a href="{% url 'cette_semaine' %}">Cette semaine</a></li>
|
||||
<li><a href="{% url 'ce_mois_ci' %}">Ce mois-ci</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<details role="list" dir="rtl">
|
||||
<summary aria-haspopup="listbox" role="link">Événements</summary>
|
||||
@ -51,11 +62,11 @@
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main class="container">
|
||||
<main class="container{% block main-fluid %}{% endblock %}">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="container">
|
||||
<footer class="container{% block footer-fluid %}{% endblock %}">
|
||||
<div class="grid">
|
||||
<ul>
|
||||
<li><a href="{% url 'view_all_tags' %}">Toutes les étiquettes</a></li>
|
||||
|
@ -64,12 +64,11 @@ def css_categories():
|
||||
|
||||
for c in cats:
|
||||
|
||||
result += "a ." + c.css_class() + ","
|
||||
result += "span ." + c.css_class() + " {"
|
||||
result += "." + c.css_class() + " {"
|
||||
result += background_color_adjust_color(adjust_lightness_saturation(c.color, .2, 0.8), 0.8)
|
||||
result += "}"
|
||||
|
||||
result += "a:hover ." + c.css_class() + " {"
|
||||
result += "*:hover ." + c.css_class() + " {"
|
||||
result += background_color_adjust_color(adjust_lightness_saturation(c.color, 0.02, 1.0))
|
||||
result += "}"
|
||||
|
||||
@ -91,4 +90,8 @@ def small_cat(category, url=None, contrast=True):
|
||||
if url is None:
|
||||
return mark_safe('<span class="small-cat' + class_contrast +' selected" role="button"><span class="cat ' + category.css_class() + '"></span> ' + category.name + "</span>")
|
||||
else:
|
||||
return mark_safe('<a class="small-cat' + class_contrast +' selected" role="button" href="' + url + '"><span class="cat ' + category.css_class() + '"></span> ' + category.name + "</a>")
|
||||
return mark_safe('<a class="small-cat' + class_contrast +' selected" role="button" href="' + url + '"><span class="cat ' + category.css_class() + '"></span> ' + category.name + "</a>")
|
||||
|
||||
@register.filter
|
||||
def circle_cat(category):
|
||||
return mark_safe('<span class="cat ' + category.css_class() + '" data-tooltip="' + category.name + '"></span>')
|
@ -2,6 +2,7 @@ from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from urllib.parse import urlparse
|
||||
from datetime import timedelta, date
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@ -9,4 +10,25 @@ register = template.Library()
|
||||
@register.filter
|
||||
def hostname(url):
|
||||
obj = urlparse(url)
|
||||
return mark_safe(obj.hostname)
|
||||
return mark_safe(obj.hostname)
|
||||
|
||||
|
||||
@register.filter
|
||||
def add_de(txt):
|
||||
return ("d'" if txt[0].lower() in ['a', 'e', 'i', 'o', 'u', 'y'] else "de ") + txt
|
||||
|
||||
@register.filter
|
||||
def week(d):
|
||||
return d.isocalendar()[1]
|
||||
|
||||
@register.filter
|
||||
def shift_day(d, shift):
|
||||
return d + timedelta(days=shift)
|
||||
|
||||
@register.filter
|
||||
def first_day_of_this_week(d):
|
||||
return date.fromisocalendar(d.year, week(d), 1)
|
||||
|
||||
@register.filter
|
||||
def last_day_of_this_week(d):
|
||||
return date.fromisocalendar(d.year, week(d), 7)
|
||||
|
@ -7,12 +7,14 @@ from django.contrib.auth import views as auth_views
|
||||
|
||||
from .views import *
|
||||
|
||||
modes = '|'.join([dm.name for dm in DisplayMode])
|
||||
|
||||
urlpatterns = [
|
||||
path("", home, name="home"),
|
||||
re_path(r'^(?P<mode>' + modes + ')/$', view_mode, name='view_mode'),
|
||||
re_path(r'^(?P<mode>' + modes + ')/(?P<cat_id>\d+)/$', view_mode_cat, name='view_mode_cat'),
|
||||
path("semaine/<int:year>/<int:week>/", week_view, name='week_view'),
|
||||
path("mois/<int:year>/<int:month>/", month_view, name='month_view'),
|
||||
path("jour/<int:year>/<int:month>/<int:day>/", day_view, name='day_view'),
|
||||
path("aujourdhui/", day_view, name="aujourdhui"),
|
||||
path("cette-semaine/", week_view, name="cette_semaine"),
|
||||
path("ce-mois-ci", month_view, name="ce_mois_ci"),
|
||||
path("tag/<t>/", view_tag, name='view_tag'),
|
||||
path("tags/", tag_list, name='view_all_tags'),
|
||||
path("events/", event_list, name='view_all_events'),
|
||||
|
@ -9,7 +9,8 @@ from .celery import create_event_from_submission
|
||||
from .models import Event, Category
|
||||
from django.utils import timezone
|
||||
from enum import StrEnum
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, date
|
||||
import calendar
|
||||
from django.db.models import Q
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
@ -22,66 +23,167 @@ from django.contrib.auth.decorators import login_required
|
||||
import unicodedata
|
||||
|
||||
|
||||
class DisplayMode(StrEnum):
|
||||
this_week = "this week"
|
||||
this_weekend = "this weekend"
|
||||
next_week = "next week"
|
||||
next_weekend = "next weekend"
|
||||
this_month = "this month"
|
||||
next_month = "next month"
|
||||
def daterange(start, end, step=timedelta(1)):
|
||||
if end is None:
|
||||
yield start
|
||||
else:
|
||||
curr = start
|
||||
while curr <= end:
|
||||
yield curr
|
||||
curr += step
|
||||
|
||||
def i18n_value(self):
|
||||
return _(self.value)
|
||||
|
||||
def get_dates(self):
|
||||
now = datetime.now()
|
||||
if self in [DisplayMode.this_week, DisplayMode.next_week]:
|
||||
day = now.weekday() # 0: Monday, 6: Sunday
|
||||
start = now + timedelta(days=-day)
|
||||
if self == DisplayMode.next_week:
|
||||
start += timedelta(days=7)
|
||||
return [start + timedelta(days=x) for x in range(0, 7)]
|
||||
elif self in [DisplayMode.this_weekend, DisplayMode.next_weekend]:
|
||||
day = now.weekday() # 0: Monday, 6: Sunday
|
||||
start = now + timedelta(days=-day + 5)
|
||||
if self == DisplayMode.next_week:
|
||||
start += timedelta(days=7)
|
||||
return [start + timedelta(days=x) for x in range(0, 2)]
|
||||
elif self in [DisplayMode.this_month, DisplayMode.next_month]:
|
||||
start = now.replace(day=1)
|
||||
if self == DisplayMode.next_month:
|
||||
start = (start.replace(day=1) + timedelta(days=32)).replace(day=1)
|
||||
next_month = start.replace(day=28) + timedelta(days=4)
|
||||
end = next_month - timedelta(days=next_month.day)
|
||||
delta = end - start
|
||||
return [start + timedelta(days=x) for x in range(0, delta.days + 1)]
|
||||
class CalendarDay:
|
||||
|
||||
def __str__(self):
|
||||
return str(self.i18n_value())
|
||||
def __init__(self, d, on_requested_interval = True):
|
||||
self.date = d
|
||||
now = date.today()
|
||||
self.in_past = d < now
|
||||
self.events = []
|
||||
|
||||
self.events_by_category = {}
|
||||
|
||||
def is_in_past(self):
|
||||
return in_past
|
||||
|
||||
def add_event(self, event):
|
||||
self.events.append(event)
|
||||
if not event.category.name in self.events_by_category:
|
||||
self.events_by_category[event.category.name] = []
|
||||
self.events_by_category[event.category.name].append(event)
|
||||
|
||||
|
||||
class CalendarList:
|
||||
|
||||
def __init__(self, firstdate, lastdate):
|
||||
self.firstdate = firstdate
|
||||
self.lastdate = lastdate
|
||||
|
||||
# start the first day of the first week
|
||||
self.c_firstdate = firstdate + timedelta(days=-firstdate.weekday())
|
||||
# end the last day of the last week
|
||||
self.c_lastdate = lastdate + timedelta(days=6-lastdate.weekday())
|
||||
|
||||
|
||||
# create a list of CalendarDays
|
||||
self.create_calendar_days()
|
||||
|
||||
# fill CalendarDays with events
|
||||
self.fill_calendar_days()
|
||||
|
||||
|
||||
def fill_calendar_days(self):
|
||||
self.events = Event.objects.filter(start_day__lte=self.c_lastdate, start_day__gte=self.c_firstdate).order_by("start_day", "start_time")
|
||||
|
||||
for e in self.events:
|
||||
for d in daterange(e.start_day, e.end_day):
|
||||
if d.__str__() in self.calendar_days:
|
||||
self.calendar_days[d.__str__()].add_event(e)
|
||||
|
||||
|
||||
def create_calendar_days(self):
|
||||
# create daylist
|
||||
self.calendar_days = {}
|
||||
for d in daterange(self.c_firstdate, self.c_lastdate):
|
||||
self.calendar_days[d.strftime("%Y-%m-%d")] = CalendarDay(d, d >= self.firstdate and d <= self.lastdate)
|
||||
|
||||
|
||||
def is_single_week(self):
|
||||
return hasattr(self, "week")
|
||||
|
||||
|
||||
def is_full_month(self):
|
||||
return hasattr(self, "month")
|
||||
|
||||
|
||||
def calendar_days_list(self):
|
||||
return list(self.calendar_days.values())
|
||||
|
||||
class CalendarMonth(CalendarList):
|
||||
|
||||
def __init__(self, year, month):
|
||||
self.year = year
|
||||
self.month = month
|
||||
r = calendar.monthrange(year, month)
|
||||
|
||||
first = date(year, month, r[0])
|
||||
last = date(year, month, r[1])
|
||||
|
||||
super().__init__(first, last)
|
||||
|
||||
def get_month_name(self):
|
||||
return self.firstdate.strftime("%B")
|
||||
|
||||
def next_month(self):
|
||||
return self.lastdate + timedelta(days=7)
|
||||
|
||||
def previous_month(self):
|
||||
return self.firstdate + timedelta(days=-7)
|
||||
|
||||
|
||||
class CalendarWeek(CalendarList):
|
||||
|
||||
def __init__(self, year, week):
|
||||
self.year = year
|
||||
self.week = week
|
||||
|
||||
first = date.fromisocalendar(self.year, self.week, 1)
|
||||
last = date.fromisocalendar(self.year, self.week, 7)
|
||||
|
||||
super().__init__(first, last)
|
||||
|
||||
def next_week(self):
|
||||
return self.firstdate + timedelta(days=7)
|
||||
|
||||
def previous_week(self):
|
||||
return self.firstdate + timedelta(days=-7)
|
||||
|
||||
|
||||
def home(request):
|
||||
# TODO: si on est au début de la semaine, on affiche la semaine en entier
|
||||
# sinon, on affiche le week-end
|
||||
# sauf si on est dimanche après 23h, on affiche la semaine prochaine
|
||||
return view_mode(request, DisplayMode.this_week.name)
|
||||
return week_view(request)
|
||||
#return month_view(request, now.year, now.month)
|
||||
|
||||
def month_view(request, year = None, month = None):
|
||||
# TODO: filter by category, tag
|
||||
now = date.today()
|
||||
if year == None:
|
||||
year = now.year
|
||||
if month == None:
|
||||
month = now.month
|
||||
cmonth = CalendarMonth(year, month)
|
||||
|
||||
context = {"year": year, "month": cmonth.get_month_name(), "calendar": cmonth }
|
||||
return render(request, 'agenda_culturel/page-month.html', context)
|
||||
|
||||
|
||||
def view_mode(request, mode):
|
||||
categories = Category.objects.all()
|
||||
dates = DisplayMode[mode].get_dates()
|
||||
events = Event.objects.filter(Q(start_day__lte=dates[-1]) & Q(start_day__gte=dates[0])).order_by("start_day", "start_time")
|
||||
context = {"modes": list(DisplayMode), "selected_mode": DisplayMode[mode], "categories": categories, "events": events, "dates": dates}
|
||||
return render(request, 'agenda_culturel/page-events.html', context)
|
||||
def week_view(request, year = None, week = None):
|
||||
now = date.today()
|
||||
if year == None:
|
||||
year = now.year
|
||||
if week == None:
|
||||
week = now.isocalendar()[1]
|
||||
|
||||
cweek = CalendarWeek(year, week)
|
||||
|
||||
context = {"year": year, "week": week, "calendar": cweek }
|
||||
return render(request, 'agenda_culturel/page-week.html', context)
|
||||
|
||||
|
||||
def view_mode_cat(request, mode, cat_id):
|
||||
category = get_object_or_404(Category, pk=cat_id)
|
||||
categories = Category.objects.all()
|
||||
dates = DisplayMode[mode].get_dates()
|
||||
events = Event.objects.filter(start_day__lte=dates[-1], start_day__gte=dates[0], category=category).order_by("start_day", "start_time")
|
||||
context = {"modes": list(DisplayMode), "selected_mode": DisplayMode[mode], "category": category, "categories": categories, "events": events, "dates": dates}
|
||||
return render(request, 'agenda_culturel/page-events.html', context)
|
||||
def day_view(request, year = None, month = None, day = None):
|
||||
now = date.today()
|
||||
if year == None:
|
||||
year = now.year
|
||||
if month == None:
|
||||
month = now.month
|
||||
if day == None:
|
||||
day = now.day
|
||||
|
||||
day = date(year, month, day)
|
||||
|
||||
events = Event.objects.filter(start_day__lte=day, start_day__gte=day).order_by("start_day", "start_time")
|
||||
# TODO
|
||||
context = {"day": day, "events": events}
|
||||
return render(request, 'agenda_culturel/page-day.html', context)
|
||||
|
||||
|
||||
def view_tag(request, t):
|
||||
|
Loading…
Reference in New Issue
Block a user