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)
|
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):
|
def get_absolute_url(self):
|
||||||
return reverse("view_event", kwargs={"pk": self.pk, "extra": self.title})
|
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;
|
||||||
|
};
|
@ -161,3 +161,25 @@ footer {
|
|||||||
.infos-and-buttons .buttons {
|
.infos-and-buttons .buttons {
|
||||||
flex: auto;
|
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,10 +45,16 @@
|
|||||||
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
||||||
</em></p>
|
</em></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% elif display == "modal" %}
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
{% include "agenda_culturel/ephemeris-inc.html" with event=event %}
|
<a href="#event-{{ event.id }}"
|
||||||
<h1>{{ event.title }}</h1>
|
aria-label="Fermer"
|
||||||
|
class="close"
|
||||||
|
data-target="event-{{ event.id }}"
|
||||||
|
onClick="toggleModal(event)"></a>
|
||||||
|
<h3>{{ event.category | small_cat }} {{ event.title }}</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<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" />
|
<use href="{% static 'images/feather-sprite.svg' %}#map-pin" />
|
||||||
@ -62,27 +68,57 @@
|
|||||||
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
{% include "agenda_culturel/date-times-inc.html" with event=event %}
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</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' %}#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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% if event.image %}
|
{% if event.image and display != "modal" %}
|
||||||
<article class='illustration{% if display in "in list by day" %}-small{% endif %}'>
|
<article class='illustration{% if display in "in list by day" %}-small{% endif %}'>
|
||||||
<img src="{{ event.image }}" alt="{{ event.image_alt }}" />
|
<img src="{{ event.image }}" alt="{{ event.image_alt }}" />
|
||||||
</article>
|
</article>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if display in "in list by day" %}
|
{% if display in "in list by day" or display == "modal" %}
|
||||||
<p>{{ event.description |truncatewords:20 }}</p>
|
<p>{{ event.description |truncatewords:20 }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{{ event.description }}</p>
|
<p>{{ event.description }}</p>
|
||||||
{% endif %}
|
{% 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>
|
||||||
|
|
||||||
|
<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 %}
|
||||||
|
|
||||||
|
|
||||||
{% comment %}
|
<footer class="infos-and-buttons">
|
||||||
On affiche le pied qui contient les informations de tags, catégories, etc
|
|
||||||
{% endcomment %}
|
|
||||||
<footer class="infos-and-buttons">
|
|
||||||
<div class="infos">
|
<div class="infos">
|
||||||
<p>
|
<p>
|
||||||
{% if mode %}
|
{% if mode %}
|
||||||
@ -123,5 +159,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</footer>
|
</footer>
|
||||||
|
{% endif %}
|
||||||
</article>
|
</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">
|
<nav class="container-fluid">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="/" aria-label="Retour accueil">
|
<a href="{% url 'home' %}" aria-label="Retour accueil">
|
||||||
<img src="{% static 'images/favicon.svg' %}" />
|
<img src="{% static 'images/favicon.svg' %}" />
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Les nuits énigmagmatiques
|
<a href="{% url 'home' %}" aria-label="Retour accueil">Les nuits énimagmatiques</a>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<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>
|
<li>
|
||||||
<details role="list" dir="rtl">
|
<details role="list" dir="rtl">
|
||||||
<summary aria-haspopup="listbox" role="link">Événements</summary>
|
<summary aria-haspopup="listbox" role="link">Événements</summary>
|
||||||
@ -51,11 +62,11 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<main class="container">
|
<main class="container{% block main-fluid %}{% endblock %}">
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="container">
|
<footer class="container{% block footer-fluid %}{% endblock %}">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url 'view_all_tags' %}">Toutes les étiquettes</a></li>
|
<li><a href="{% url 'view_all_tags' %}">Toutes les étiquettes</a></li>
|
||||||
|
@ -64,12 +64,11 @@ def css_categories():
|
|||||||
|
|
||||||
for c in cats:
|
for c in cats:
|
||||||
|
|
||||||
result += "a ." + c.css_class() + ","
|
result += "." + c.css_class() + " {"
|
||||||
result += "span ." + c.css_class() + " {"
|
|
||||||
result += background_color_adjust_color(adjust_lightness_saturation(c.color, .2, 0.8), 0.8)
|
result += background_color_adjust_color(adjust_lightness_saturation(c.color, .2, 0.8), 0.8)
|
||||||
result += "}"
|
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 += background_color_adjust_color(adjust_lightness_saturation(c.color, 0.02, 1.0))
|
||||||
result += "}"
|
result += "}"
|
||||||
|
|
||||||
@ -92,3 +91,7 @@ def small_cat(category, url=None, contrast=True):
|
|||||||
return mark_safe('<span class="small-cat' + class_contrast +' selected" role="button"><span class="cat ' + category.css_class() + '"></span> ' + category.name + "</span>")
|
return mark_safe('<span class="small-cat' + class_contrast +' selected" role="button"><span class="cat ' + category.css_class() + '"></span> ' + category.name + "</span>")
|
||||||
else:
|
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 django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
from datetime import timedelta, date
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
@ -10,3 +11,24 @@ register = template.Library()
|
|||||||
def hostname(url):
|
def hostname(url):
|
||||||
obj = urlparse(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 *
|
from .views import *
|
||||||
|
|
||||||
modes = '|'.join([dm.name for dm in DisplayMode])
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", home, name="home"),
|
path("", home, name="home"),
|
||||||
re_path(r'^(?P<mode>' + modes + ')/$', view_mode, name='view_mode'),
|
path("semaine/<int:year>/<int:week>/", week_view, name='week_view'),
|
||||||
re_path(r'^(?P<mode>' + modes + ')/(?P<cat_id>\d+)/$', view_mode_cat, name='view_mode_cat'),
|
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("tag/<t>/", view_tag, name='view_tag'),
|
||||||
path("tags/", tag_list, name='view_all_tags'),
|
path("tags/", tag_list, name='view_all_tags'),
|
||||||
path("events/", event_list, name='view_all_events'),
|
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 .models import Event, Category
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from enum import StrEnum
|
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.db.models import Q
|
||||||
|
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
@ -22,66 +23,167 @@ from django.contrib.auth.decorators import login_required
|
|||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
|
|
||||||
class DisplayMode(StrEnum):
|
def daterange(start, end, step=timedelta(1)):
|
||||||
this_week = "this week"
|
if end is None:
|
||||||
this_weekend = "this weekend"
|
yield start
|
||||||
next_week = "next week"
|
else:
|
||||||
next_weekend = "next weekend"
|
curr = start
|
||||||
this_month = "this month"
|
while curr <= end:
|
||||||
next_month = "next month"
|
yield curr
|
||||||
|
curr += step
|
||||||
|
|
||||||
def i18n_value(self):
|
|
||||||
return _(self.value)
|
|
||||||
|
|
||||||
def get_dates(self):
|
class CalendarDay:
|
||||||
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)]
|
|
||||||
|
|
||||||
def __str__(self):
|
def __init__(self, d, on_requested_interval = True):
|
||||||
return str(self.i18n_value())
|
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):
|
def home(request):
|
||||||
# TODO: si on est au début de la semaine, on affiche la semaine en entier
|
return week_view(request)
|
||||||
# sinon, on affiche le week-end
|
#return month_view(request, now.year, now.month)
|
||||||
# sauf si on est dimanche après 23h, on affiche la semaine prochaine
|
|
||||||
return view_mode(request, DisplayMode.this_week.name)
|
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):
|
def week_view(request, year = None, week = None):
|
||||||
categories = Category.objects.all()
|
now = date.today()
|
||||||
dates = DisplayMode[mode].get_dates()
|
if year == None:
|
||||||
events = Event.objects.filter(Q(start_day__lte=dates[-1]) & Q(start_day__gte=dates[0])).order_by("start_day", "start_time")
|
year = now.year
|
||||||
context = {"modes": list(DisplayMode), "selected_mode": DisplayMode[mode], "categories": categories, "events": events, "dates": dates}
|
if week == None:
|
||||||
return render(request, 'agenda_culturel/page-events.html', context)
|
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):
|
def day_view(request, year = None, month = None, day = None):
|
||||||
category = get_object_or_404(Category, pk=cat_id)
|
now = date.today()
|
||||||
categories = Category.objects.all()
|
if year == None:
|
||||||
dates = DisplayMode[mode].get_dates()
|
year = now.year
|
||||||
events = Event.objects.filter(start_day__lte=dates[-1], start_day__gte=dates[0], category=category).order_by("start_day", "start_time")
|
if month == None:
|
||||||
context = {"modes": list(DisplayMode), "selected_mode": DisplayMode[mode], "category": category, "categories": categories, "events": events, "dates": dates}
|
month = now.month
|
||||||
return render(request, 'agenda_culturel/page-events.html', context)
|
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):
|
def view_tag(request, t):
|
||||||
|
Loading…
Reference in New Issue
Block a user