Compare commits

...

10 Commits

15 changed files with 348 additions and 50 deletions

View File

@ -37,3 +37,4 @@ class EpisodeAdmin(SortableAdminBase, ChildPageAdmin):
# readonly_fields = ('parent',) # readonly_fields = ('parent',)
inlines = (TrackInline, EpisodeSoundInline, DiffusionInline) inlines = (TrackInline, EpisodeSoundInline, DiffusionInline)
ordering = ["-pub_date"]

View File

@ -181,8 +181,8 @@ class Settings(BaseSettings):
"""Allow comments.""" """Allow comments."""
# ---- bleach # ---- bleach
ALLOWED_TAGS = [*sanitizer.ALLOWED_TAGS, "br", "p", "h3", "h4", "h5"] ALLOWED_TAGS = [*sanitizer.ALLOWED_TAGS, "br", "p", "hr", "h2", "h3", "h4", "h5", "iframe", "pre"]
ALLOWED_ATTRIBUTES = sanitizer.ALLOWED_ATTRIBUTES ALLOWED_ATTRIBUTES = [*sanitizer.ALLOWED_ATTRIBUTES, "src", "width", "height", "frameborder", "href"]
ALLOWED_PROTOCOLS = sanitizer.ALLOWED_PROTOCOLS ALLOWED_PROTOCOLS = sanitizer.ALLOWED_PROTOCOLS

Binary file not shown.

View File

@ -93,6 +93,7 @@ body.yellow.home #grandlogo img {
} }
body.yellow .nav .nav-item.active { body.yellow .nav .nav-item.active {
color: #738EF2 !important; color: #738EF2 !important;
text-shadow: -3px 3px 17px rgb(0, 48, 111);
} }
body.blue #grandlogo img, body.yellow #grandlogo img { body.blue #grandlogo img, body.yellow #grandlogo img {
width: 120px; width: 120px;
@ -104,11 +105,10 @@ body.blue.home #grandlogo, body.yellow.home #grandlogo {
} }
body.blue.home #grandlogo img , body.yellow.home #grandlogo img { body.blue.home #grandlogo img , body.yellow.home #grandlogo img {
margin: 12px auto 0 auto; margin: 12px auto 0 auto;
width: 960px; width: 100%;
opacity: 0.8; opacity: 0.8;
} }
.a-player-bar { .a-player-bar {
border-top: 1px solid #555; border-top: 1px solid #555;
} }
@ -129,7 +129,8 @@ a.heading.title {
} }
a.heading.title:hover { a.heading.title:hover {
color: var(--link-hv-fg); /*color: var(--link-hv-fg); */
color: #738ef2;
} }
.button, a.button, button.button { .button, a.button, button.button {
border: 0; border: 0;
@ -141,23 +142,27 @@ a.heading.title:hover {
.header.has-cover { .header.has-cover {
min-height: unset; min-height: unset;
} }
.grid.listfive { .item-section {display:flex; align-items:end}
.fifty {
width: 55%;
}
.grid.list-emissions {
grid-template-columns: 1fr 1fr 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-auto-flow: dense; grid-auto-flow: dense;
gap: 0.2rem; gap: 0.2rem;
} }
.grid.listfive .media-content { .grid.list-emissions .media-content {
font-size: 0.84rem; font-size: 0.84rem;
} }
.today { .today {
color: yellow; color: yellow;
font-size: 1.4em !important; font-size: 1.4em !important;
} }
.lagrille:not(.homedisplay) article { .list-grille article {
border-bottom: 1px solid black; border-bottom: 1px solid black;
} }
.lagrille .category { .lagrille .category {
color: grey; color: white;
margin-left: 10px; margin-left: 10px;
vertical-align: text-bottom; vertical-align: text-bottom;
font-size: 0.8rem; font-size: 0.8rem;
@ -188,35 +193,35 @@ a.nav-item:hover {
flex-direction: column; flex-direction: column;
} }
.radiocampus-grid { .list-home {
display: block; display: block;
} }
.radiocampus-grid article div.media { .list-home article div.media {
line-height: 1; line-height: 1;
padding: 0; padding: 0;
} }
.radiocampus-grid article.active div.media div.media-content a, .radiocampus-grid article.active div.media div.media-content span { .list-home article.active div.media div.media-content a, .list-home article.active div.media div.media-content span {
color: yellow; color: yellow;
} }
.radiocampus-grid article.active div.media a:before { .list-home article.active div.media a:before {
content: "\2192"; content: "\2192";
margin-right: 6px; margin-right: 6px;
} }
.radiocampus-grid article div.media a.preview-cover { .list-home article div.media a.preview-cover {
display: none; display: none;
} }
.radiocampus-grid article div.media div.media-content.flex-column { .list-home article div.media div.media-content.flex-column {
display: unset; display: unset;
} }
.radiocampus-grid article div.media div.media-content section.content { .list-home article div.media div.media-content section.content {
display: none; display: none;
} }
.radiocampus-grid article div.media div.media-content div.episode-date { .list-home article div.media div.media-content div.episode-date {
display: none; display: none;
} }
.radiocampus-grid article div.media div.media-content span.heading.subtitle { .list-home article div.media div.media-content span.heading.subtitle {
float: right; float: right;
} }
.schedule { .schedule {
@ -263,7 +268,7 @@ a.nav-item:hover {
.dropdown.is-right .dropdown-menu { .dropdown.is-right .dropdown-menu {
left: 0; left: 0;
} }
.grid.listfive { .grid.list-emissions {
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
} }
#grandlogo { #grandlogo {
@ -297,7 +302,7 @@ a.nav-item:hover {
@media screen and (min-width: 1216px) { @media screen and (min-width: 1216px) {
.container:not(.is-max-desktop):not(.is-max-widescreen) { .container:not(.is-max-desktop):not(.is-max-widescreen) {
max-width: unset; max-width: unset;
margin: 10px 64px; margin: 0 64px;
} }
body.home .container:not(.is-max-desktop):not(.is-max-widescreen) { body.home .container:not(.is-max-desktop):not(.is-max-widescreen) {
max-width: 1152px; max-width: 1152px;
@ -306,7 +311,7 @@ a.nav-item:hover {
} }
@media screen and (max-width: 900px) { @media screen and (max-width: 900px) {
.grid.listfive { .grid.list-emissions {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} }
} }
@ -444,3 +449,113 @@ a.nav-item:hover {
} }
} }
*/ */
/* fred fixes */
.grid.list-emissions:not(.list-home) {display: flex !important;flex-wrap: wrap !important; gap: 20px 1rem;}
.grid.list-emissions:not(.list-home) > .list-item {width: calc(20% - 2rem) !important ;}
.grid.list-emissions:not(.list-home) > .list-item .preview-cover {max-width: 100% !important;
display: block;
width: 100% !important;
min-width: auto;
aspect-ratio: 1 / 1;
height: fit-content;
background-size: contain;
background-position: center;
background-color: white;
margin-bottom: 0.5rem;
}
.grid.list-emissions:not(.list-home) .media-content {margin-top: 0;}
.grid.list-emissions:not(.list-home) > .list-item .media .media-content > br, .grid.listfive > .list-item .media .media-content .episode-date > br {display: none;}
.grid.list-emissions:not(.list-home) .list-item .subtitle {text-align: left !important;font-size: 0.8rem !important;}
.grid.list-emissions:not(.list-home) .preview.active .heading:not(:empty) {
color: #738EF2 !important;
}
.grid.list-podcasts {display: flex !important;flex-wrap: wrap !important; gap: 20px 1rem;}
.grid.list-podcasts > .list-item {width: calc(50% - 2rem) !important ;}
.grid.list-podcasts > .list-item .preview-cover {max-width: 100% !important;
display: block;
width: 50% !important;
min-width: auto;
aspect-ratio: 1 / 1;
height: fit-content;
background-size: contain;
background-position: center;
background-color: white;
}
.grid.list-podcasts .media-content {margin-top: 0;}
.grid.list-podcasts .media .media-left {width: 25% !important;}
.grid.list-podcasts .media .media-content {width: 75%;}
.grid.list-podcasts > .list-item .media .media-content > br, .grid.list-emissions > .list-item .media .media-content .episode-date > br {display: none;}
.grid.list-podcasts .list-item .subtitle {text-align: left !important;font-size: 0.8rem !important;}
.grid.list-podcasts .preview.active .heading:not(:empty) {
color: #738EF2 !important;
}
@media screen and (max-width: 1224px) {
.grid.list-emissions:not(.list-home) > .list-item {width: calc(33% - 2rem) !important;;}
}
@media screen and (max-width: 924px) {
.grid.list-emissions:not(.list-home) > .list-item {width: calc(50% - 2rem) !important;}
}
@media screen and (max-width: 1024px) {
.grid.list-emissions > .list-item {width: 100% !important;}
.program-list {flex-direction: column;}
.grid.list-podcasts > .list-item {width: 100% !important ;}
}
.list-item .subtitle:not(:empty) {
min-width: auto !important;
}
@media screen and (max-width: 924px) {
.a-player-bar-content {overflow: hidden;}
.a-player-bar-content .title {
display: inline-block;
padding-right: 2em;
padding-left: 100%;
white-space: nowrap;
animation: defilement-rtl 55s infinite linear;
overflow: visible;}
@keyframes defilement-rtl {
0% {
transform: translate3d(0,0,0); /* position initiale à droite */
}
100% {
transform: translate3d(-100%,0,0); /* position finale à gauche */
}
}
}
@media screen and (max-width: 540px) {
.media {
flex-direction: column;
}
.grid.list-podcasts .media .media-content {width:100%}
.grid.list-emissions:not(.list-home) > .list-item {
width: 100% !important;
}
}
.list-item .media-content {height:auto;}

View File

@ -8,7 +8,7 @@
{% endblock %} {% endblock %}
{% block nav %} {% block nav %}
<div id="grandlogo"><a href="/"><img /></a></div> <div id="grandlogo" class="container"><a href="/"><img /></a></div>
{{ block.super }} {{ block.super }}
{% endblock %} {% endblock %}
@ -17,3 +17,9 @@
{{ block.super }} {{ block.super }}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block header-cover %}
{% if cover and not "emissions/episodes" in request.path %}
<img src="{{ cover }}" ref="cover" class="cover">
{% endif %}
{% endblock %}

View File

@ -21,3 +21,22 @@
{{ block.super }} {{ block.super }}
{% endwith %} {% endwith %}
{% endblock %} {% endblock %}
{% block secondary-nav %}
{% if not parent and categories %}
<nav class="nav secondary">
<div class="nav-menu nav-categories">
{% for cat in categories %}
<a class="nav-item{% if cat == category %} active{% endif %}"
href="{% url request.resolver_match.url_name category_slug=cat.slug %}">
{{ cat.title }}
</a>
{% endfor %}
</div>
<a-switch class="button burger"
el=".nav-categories" group="nav" icon="fas fa-tags"
aria-label="{% translate "Categories" %}">
</a-switch>
</nav>
{% endif %}
{% endblock %}

View File

@ -30,10 +30,14 @@ function display(id) {
if (id == "homedisplay") { if (id == "homedisplay") {
for(var i = 0; i < h.length; i++) { h[i].setAttribute('style', 'display:inline !important'); } for(var i = 0; i < h.length; i++) { h[i].setAttribute('style', 'display:inline !important'); }
for(var i = 0; i < h.length; i++) { r[i].setAttribute('style', 'display:none !important'); } for(var i = 0; i < r.length; i++) { r[i].setAttribute('style', 'display:none !important'); }
document.getElementById('recent-link').classList.remove('active');
document.getElementById('home-link').classList.add('active');
} else { } else {
for(var i = 0; i < h.length; i++) { h[i].setAttribute('style', 'display:none !important'); } for(var i = 0; i < h.length; i++) { h[i].setAttribute('style', 'display:none !important'); }
for(var i = 0; i < h.length; i++) { r[i].setAttribute('style', 'display:inline !important'); } for(var i = 0; i < r.length; i++) { r[i].setAttribute('style', 'display:inline !important'); }
document.getElementById('recent-link').classList.add('active');
document.getElementById('home-link').classList.remove('active');
} }
@ -55,7 +59,7 @@ function display(id) {
<!-- <a href="{% url "timetable-list" date=date %}">{{ date|date:"l d F Y" }}</a> --> <!-- <a href="{% url "timetable-list" date=date %}">{{ date|date:"l d F Y" }}</a> -->
<section class="clear-both list grid radiocampus-grid" role="list"> <section class="clear-both list grid radiocampus-grid" role="list">
</section> </section>
{% with list_class="radiocampus-grid" %} {% with list_class="list-home" %}
{{ block.super }} {{ block.super }}
{% endwith %} {% endwith %}
</div> </div>
@ -69,7 +73,7 @@ function display(id) {
<!-- <a href="{% url "timetable-list" date=date %}">{{ date|date:"l d F Y" }}</a> --> <!-- <a href="{% url "timetable-list" date=date %}">{{ date|date:"l d F Y" }}</a> -->
<section class="clear-both list grid radiocampus-grid" role="list"> <section class="clear-both list grid radiocampus-grid" role="list">
</section> </section>
{% with list_class="radiocampus-grid" %} {% with list_class="list-home" %}
{{ block.super }} {{ block.super }}
{% endwith %} {% endwith %}
</div> </div>

View File

@ -65,7 +65,7 @@
{% endblock %} {% endblock %}
{% block list-container %} {% block list-container %}
<section class="container clear-both list grid {{ list_class|default:"" }} listfive" role="list"> <section class="container clear-both list grid {{ list_class|default:"" }} list-emissions" role="list">
{% block list %} {% block list %}
{% with has_headline=True %} {% with has_headline=True %}
{% for object in object_list %} {% for object in object_list %}

View File

@ -0,0 +1,32 @@
{% extends "./base.html" %}
{% load aircox %}
{% comment %}
Override is a trick here: it allows to change title at two different different
places inside the page: inside `<title>` tag, and inside the page
content.
{% endcomment %}
{% block head-title %}
{% block title %}
{% if page and page.title %}{{ page.title }}{% endif %}
{% endblock %}
{% if page and page.title %}&mdash;{% endif %}
{{ station.name }}
{% endblock %}
{% block header %}{% if page %}{{ block.super }}{% endif %}{% endblock %}
{% block secondary-nav %}
{% if '/pages/' in request.path %}
<nav class="nav secondary">
<div class="nav-menu nav-categories">
{% nav_items "secondary" css_class="nav-item" active_class="active" as items %}
{% for item, render in items %}
{{ render }}
{% endfor %}
</div>
</nav>
{% endif %}
{% endblock %}

View File

@ -12,23 +12,13 @@
{% block breadcrumbs %} {% block breadcrumbs %}
{% if parent and model.list_url_name %} {% if page and model.list_url_name %}
{% include "./widgets/breadcrumbs.html" with page=parent %}
<a href="{% url model.list_url_name %}">{{ model|verbose_name:True }}</a>
{% elif page and model.list_url_name %}
<a href="{% url model.list_url_name %}">{{ page.title }}</a> <a href="{% url model.list_url_name %}">{{ page.title }}</a>
{% if category %} {% if category %}
<a href="{% url request.resolver_match.url_name category_slug=category.slug %}"> <a href="{% url request.resolver_match.url_name category_slug=category.slug %}">
{{ category.title }} {{ category.title }}
</a> </a>
{% endif %} {% endif %}
{% else %}
<a href="{% url request.resolver_match.url_name %}">{{ model|verbose_name:True }}</a>
{% if category %}
<a href="{% url request.resolver_match.url_name category_slug=category.slug %}">
{{ category.title }}
</a>
{% endif %}
{% endif %} {% endif %}
<a href="{% url "timetable-list" date=date %}">{{ date|date:"l d F Y" }}</a> <a href="{% url "timetable-list" date=date %}">{{ date|date:"l d F Y" }}</a>
{% endblock %} {% endblock %}
@ -36,9 +26,9 @@
{% block list-container %} {% block list-container %}
{% with list_class="grid" %} {% with list_class="grid" %}
<section class="container clear-both list grid radiocampus-grid listfive" role="list"> <section class="container clear-both list grid list-grille list-home list-emissions" role="list">
<section class="container" style="display:flex;justify-content:flex-end;min-height:600px"> <section class="container" style="display:flex;justify-content:flex-end;min-height:600px">
<div style="max-width:600px;"> <div class="fifty">
{% block list %} {% block list %}
{% with object_list=object_list timetable=True %} {% with object_list=object_list timetable=True %}
{% with widget|default:"item" as widget %} {% with widget|default:"item" as widget %}

View File

@ -32,7 +32,7 @@
</span> </span>
</br> </br>
<section class="content flex-grow-1"> <section class="content flex-grow-1 item-section">
{% block content %}{{ block.super }}{% endblock %} {% block content %}{{ block.super }}{% endblock %}
</section> </section>
{% block actions-container %}{{ block.super }}{% endblock %} {% block actions-container %}{{ block.super }}{% endblock %}

View File

@ -0,0 +1,71 @@
{% load i18n %}
{% comment %}
Content related context:
- object: object to display
- cover: cover
- title: title
- subtitle: subtitle
- content: content to display
Components:
- no_cover: don't show cover
- no_content: don't show content
Styling related context:
- is_active: add "active" css class
- is_small: add "small" css class
- is_tiny: add "tiny" css class
- tag
- tag_class: css class to set to main tag
- tag_extra: extra tag attributes
{% endcomment %}
{% load aircox %}
{% block outer %}
<{{ tag|default:"article" }} id="{{ object|object_id }}" class="preview {% if not cover %}no-cover {% endif %}{% if is_active %}active {% endif %}{% if is_tiny %}tiny{% elif is_small %}small{% endif %}{% block tag-class %}{{ tag_class|default:"" }} {% endblock %}" {% block tag-extra %}{% endblock %}>
{% block inner %}
{% block headings-container %}
<header class="headings{% block headings-class %}{% endblock %}"{% block headings-tag-extra %}{% endblock %}>
{% block headings %}
{% block title-container %}
<a href="{{ url|escape }}" class="heading title {% block title-class %}{% endblock %}"{% if title %} title="{{ title|escape }}"{% endif %}>
{% block title %}{{ title|default:"" }}{% endblock %}
</a>
{% endblock %}
{% block subtitle-container %}
<span class="heading subtitle {% block subtitle-class %}{% endblock %}">
{% block subtitle %}{{ subtitle|default:"" }}{% endblock %}
</span>
{% endblock %}
{% endblock %}
</header>
{% endblock %}
{% block content-container %}
<section class="content headings-container">
{% block content %}
{% if content and not no_content %}
{% autoescape off %}
{{ content|striptags|linebreaks }}
{% endautoescape %}
{% endif %}
{% spaceless %}
<div class="actions">
{% block actions %}
{% if admin and object.edit_url_name %}
<a href="{% url object.edit_url_name pk=object.pk %}" target="_self">{% translate "Edit" %}</a>
{% endif %}
{% endblock %}
</div>
{% endspaceless %}
{% endblock %}
</section>
{% endblock %}
{% endblock %}
</{{ tag|default:"article" }}>
{% endblock %}

View File

@ -2,25 +2,41 @@ from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from django.utils.translation import gettext_lazy as _
import aircox.urls from aircox.urls import urls
import aircox_streamer.urls import aircox_streamer.urls
from radiocampus.views import TimeTableView from radiocampus.views import HomeTimeTableView, TimeTableView
from aircox.views.dashboard import DashboardView
urlpatterns = [ urlpatterns = [
*aircox.urls.urls,
path("streamer/", include((aircox_streamer.urls.urls, "aircox_streamer"), namespace="streamer")), path("streamer/", include((aircox_streamer.urls.urls, "aircox_streamer"), namespace="streamer")),
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")), path("accounts/", include("django.contrib.auth.urls")),
path("filer/", include("filer.urls")), path("filer/", include("filer.urls")),
path("gestion/", DashboardView.as_view(), name="dashboard"),
] ]
for i, pa in enumerate(urlpatterns): for url in urls:
if "name" in pa.__dict__.keys() and pa.name == "home": if "name" in url.__dict__.keys():
urlpatterns.pop(i) if url.name == "home" or url.name == "timetable-list":
continue
urlpatterns.append(url)
urlpatterns.append(path("", TimeTableView.as_view(), name="home"))
urlpatterns.append(path("", HomeTimeTableView.as_view(), name="home"))
urlpatterns.extend(
[
path(_("timetable/"), TimeTableView.as_view(), name="timetable-list"),
path(
_("timetable/<date:date>/"),
TimeTableView.as_view(),
name="timetable-list",
),
]
)
if settings.DEBUG: if settings.DEBUG:
from debug_toolbar.toolbar import debug_toolbar_urls from debug_toolbar.toolbar import debug_toolbar_urls

View File

@ -1,7 +1,51 @@
import datetime
from django.urls import reverse
from aircox.models import Diffusion, Log, StaticPage
from aircox.views.diffusion import TimeTableView as AircoxTimeTableView from aircox.views.diffusion import TimeTableView as AircoxTimeTableView
from aircox.views.diffusion import BaseDiffusionListView
from aircox.views.mixins import GetDateMixin
from aircox.views.page import attach
__all__ = "TimeTableView" __all__ = ("HomeTimeTableView", "TimeTableView")
class TimeTableView(AircoxTimeTableView): class HomeTimeTableView(AircoxTimeTableView):
template_name = "aircox/home.html" template_name = "aircox/home.html"
@attach
class TimeTableView(GetDateMixin, BaseDiffusionListView):
model = Diffusion
redirect_date_url = "timetable-list"
attach_to_value = StaticPage.Target.TIMETABLE
template_name = "aircox/timetable_list.html"
def get_date(self, param="date"):
date = super().get_date(param)
return date if date is not None else datetime.date.today()
def get_logs(self, date):
return Log.objects.on_air().date(self.date).filter(track__isnull=False)
def get_queryset(self):
return super().get_queryset().date(self.date)
@classmethod
def get_secondary_nav(cls):
date = datetime.date.today()
start = date - datetime.timedelta(days=3)
dates = [start + datetime.timedelta(days=i) for i in range(0, 7)]
return tuple((date.strftime("%A %d"), reverse("timetable-list", kwargs={"date": date})) for date in dates)
def get_context_data(self, object_list=None, **kwargs):
start = self.date - datetime.timedelta(days=3)
dates = [start + datetime.timedelta(days=i) for i in range(0, 7)]
if object_list is None:
logs = self.get_logs(self.date)
object_list = Log.merge_diffusions(logs, self.object_list, group_logs=True)
object_list = list(reversed(object_list))
return super().get_context_data(date=self.date, dates=dates, object_list=object_list, **kwargs)