Compare commits
12 Commits
develop-1.
...
6a21a9d094
Author | SHA1 | Date | |
---|---|---|---|
6a21a9d094 | |||
b4c12def13 | |||
36ae12af3d | |||
0a86d4e0a3 | |||
a53aebb5b8 | |||
1af0348c89 | |||
8ab8ef5b1c | |||
bf9da835b2 | |||
7b28149d7e | |||
87a2ee5a45 | |||
ab231e9a89 | |||
1661601caf |
@ -30,9 +30,9 @@ class DiffusionAdmin(DiffusionBaseAdmin, admin.ModelAdmin):
|
||||
|
||||
end_date.short_description = _("end")
|
||||
|
||||
list_display = ("episode", "start_date", "end_date", "type", "initial")
|
||||
list_display = ("episode", "start", "end", "type", "initial")
|
||||
list_filter = ("type", "start", "program")
|
||||
list_editable = ("type",)
|
||||
list_editable = ("type", "start", "end")
|
||||
ordering = ("-start", "id")
|
||||
|
||||
fields = ("type", "start", "end", "initial", "program", "schedule")
|
||||
|
@ -10,7 +10,7 @@ class PageFilters(filters.FilterSet):
|
||||
class Meta:
|
||||
model = Page
|
||||
fields = {
|
||||
"category__id": ["in"],
|
||||
"category__id": ["in", "exact"],
|
||||
"pub_date": ["exact", "gte", "lte"],
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ __all__ = ("Article",)
|
||||
|
||||
class Article(Page):
|
||||
detail_url_name = "article-detail"
|
||||
template_prefix = "article"
|
||||
|
||||
objects = ProgramChildQuerySet.as_manager()
|
||||
|
||||
|
@ -137,8 +137,6 @@ class Diffusion(Rerun):
|
||||
# help_text = _('use this input port'),
|
||||
# )
|
||||
|
||||
item_template_name = "aircox/widgets/diffusion_item.html"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Diffusion")
|
||||
verbose_name_plural = _("Diffusions")
|
||||
@ -208,6 +206,11 @@ class Diffusion(Rerun):
|
||||
and self.end >= now
|
||||
)
|
||||
|
||||
@property
|
||||
def is_today(self):
|
||||
"""True if diffusion is currently today."""
|
||||
return self.start.date() == datetime.date.today()
|
||||
|
||||
@property
|
||||
def is_live(self):
|
||||
"""True if Diffusion is live (False if there are sounds files)."""
|
||||
|
@ -13,11 +13,15 @@ __all__ = ("Episode",)
|
||||
class Episode(Page):
|
||||
objects = ProgramChildQuerySet.as_manager()
|
||||
detail_url_name = "episode-detail"
|
||||
item_template_name = "aircox/widgets/episode_item.html"
|
||||
template_prefix = "episode"
|
||||
|
||||
@property
|
||||
def program(self):
|
||||
return getattr(self.parent, "program", None)
|
||||
return self.parent_subclass
|
||||
|
||||
@program.setter
|
||||
def program(self, value):
|
||||
self.parent = value
|
||||
|
||||
@cached_property
|
||||
def podcasts(self):
|
||||
@ -40,10 +44,6 @@ class Episode(Page):
|
||||
podcasts[index]["page_title"] = self.title
|
||||
return podcasts
|
||||
|
||||
@program.setter
|
||||
def program(self, value):
|
||||
self.parent = value
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Episode")
|
||||
verbose_name_plural = _("Episodes")
|
||||
|
@ -9,6 +9,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from .diffusion import Diffusion
|
||||
from .sound import Sound, Track
|
||||
from .station import Station
|
||||
from .page import Renderable
|
||||
|
||||
logger = logging.getLogger("aircox")
|
||||
|
||||
@ -54,13 +55,15 @@ class LogQuerySet(models.QuerySet):
|
||||
return self.filter(track__isnull=not with_it)
|
||||
|
||||
|
||||
class Log(models.Model):
|
||||
class Log(Renderable, models.Model):
|
||||
"""Log sounds and diffusions that are played on the station.
|
||||
|
||||
This only remember what has been played on the outputs, not on each
|
||||
source; Source designate here which source is responsible of that.
|
||||
"""
|
||||
|
||||
template_prefix = "log"
|
||||
|
||||
TYPE_STOP = 0x00
|
||||
"""Source has been stopped, e.g. manually."""
|
||||
# Rule: \/ diffusion != null \/ sound != null
|
||||
|
@ -16,6 +16,7 @@ from model_utils.managers import InheritanceQuerySet
|
||||
from .station import Station
|
||||
|
||||
__all__ = (
|
||||
"Renderable",
|
||||
"Category",
|
||||
"PageQuerySet",
|
||||
"Page",
|
||||
@ -30,6 +31,17 @@ headline_re = re.compile(
|
||||
)
|
||||
|
||||
|
||||
class Renderable:
|
||||
template_prefix = "page"
|
||||
template_name = "aircox/widgets/{prefix}.html"
|
||||
|
||||
def get_template_name(self, widget):
|
||||
"""Return template name for the provided widget."""
|
||||
return self.template_name.format(
|
||||
prefix=self.template_prefix, widget=widget
|
||||
)
|
||||
|
||||
|
||||
class Category(models.Model):
|
||||
title = models.CharField(_("title"), max_length=64)
|
||||
slug = models.SlugField(_("slug"), max_length=64, db_index=True)
|
||||
@ -52,6 +64,9 @@ class BasePageQuerySet(InheritanceQuerySet):
|
||||
def trash(self):
|
||||
return self.filter(status=Page.STATUS_TRASH)
|
||||
|
||||
def by_last(self):
|
||||
return self.order_by("-pub_date")
|
||||
|
||||
def parent(self, parent=None, id=None):
|
||||
"""Return pages having this parent."""
|
||||
return (
|
||||
@ -68,7 +83,7 @@ class BasePageQuerySet(InheritanceQuerySet):
|
||||
return self.filter(title__icontains=q)
|
||||
|
||||
|
||||
class BasePage(models.Model):
|
||||
class BasePage(Renderable, models.Model):
|
||||
"""Base class for publishable content."""
|
||||
|
||||
STATUS_DRAFT = 0x00
|
||||
@ -112,7 +127,6 @@ class BasePage(models.Model):
|
||||
objects = BasePageQuerySet.as_manager()
|
||||
|
||||
detail_url_name = None
|
||||
item_template_name = "aircox/widgets/page_item.html"
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
@ -152,14 +166,14 @@ class BasePage(models.Model):
|
||||
|
||||
@property
|
||||
def display_title(self):
|
||||
if self.is_published():
|
||||
if self.is_published:
|
||||
return self.title
|
||||
return self.parent.display_title()
|
||||
return self.parent and self.parent.display_title or ""
|
||||
|
||||
@cached_property
|
||||
def headline(self):
|
||||
if not self.content:
|
||||
return ""
|
||||
def display_headline(self):
|
||||
if not self.content or not self.is_published:
|
||||
return self.parent and self.parent.display_headline or ""
|
||||
content = bleach.clean(self.content, tags=[], strip=True)
|
||||
headline = headline_re.search(content)
|
||||
return mark_safe(headline.groupdict()["headline"]) if headline else ""
|
||||
@ -207,6 +221,12 @@ class Page(BasePage):
|
||||
|
||||
objects = PageQuerySet.as_manager()
|
||||
|
||||
@cached_property
|
||||
def parent_subclass(self):
|
||||
if self.parent_id:
|
||||
return Page.objects.get_subclass(id=self.parent_id)
|
||||
return None
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Publication")
|
||||
verbose_name_plural = _("Publications")
|
||||
@ -265,7 +285,7 @@ class StaticPage(BasePage):
|
||||
return super().get_absolute_url()
|
||||
|
||||
|
||||
class Comment(models.Model):
|
||||
class Comment(Renderable, models.Model):
|
||||
page = models.ForeignKey(
|
||||
Page,
|
||||
models.CASCADE,
|
||||
@ -278,7 +298,7 @@ class Comment(models.Model):
|
||||
date = models.DateTimeField(auto_now_add=True)
|
||||
content = models.TextField(_("content"), max_length=1024)
|
||||
|
||||
item_template_name = "aircox/widgets/comment_item.html"
|
||||
template_prefix = "comment"
|
||||
|
||||
@cached_property
|
||||
def parent(self):
|
||||
@ -286,7 +306,7 @@ class Comment(models.Model):
|
||||
return Page.objects.select_subclasses().filter(id=self.page_id).first()
|
||||
|
||||
def get_absolute_url(self):
|
||||
return self.parent.get_absolute_url()
|
||||
return self.parent.get_absolute_url() + f"#comment-{self.pk}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Comment")
|
||||
|
@ -43,6 +43,7 @@ def user_default_groups(sender, instance, created, *args, **kwargs):
|
||||
|
||||
@receiver(signals.post_save, sender=Page)
|
||||
def page_post_save(sender, instance, created, *args, **kwargs):
|
||||
return
|
||||
if not created and instance.cover:
|
||||
Page.objects.filter(parent=instance, cover__isnull=True).update(
|
||||
cover=instance.cover
|
||||
@ -67,6 +68,7 @@ def program_post_save(sender, instance, created, *args, **kwargs):
|
||||
|
||||
@receiver(signals.pre_save, sender=Schedule)
|
||||
def schedule_pre_save(sender, instance, *args, **kwargs):
|
||||
return
|
||||
if getattr(instance, "pk") is not None:
|
||||
instance._initial = Schedule.objects.get(pk=instance.pk)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
16095
aircox/static/aircox/vue.esm-browser.js
Normal file
16095
aircox/static/aircox/vue.esm-browser.js
Normal file
File diff suppressed because it is too large
Load Diff
1
aircox/static/aircox/vue.esm-browser.prod.js
Normal file
1
aircox/static/aircox/vue.esm-browser.prod.js
Normal file
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
||||
{% extends "admin/index.html" %}
|
||||
{% load i18n thumbnail %}
|
||||
{% load i18n thumbnail aircox %}
|
||||
|
||||
|
||||
{% block app %}
|
||||
@ -62,7 +62,9 @@
|
||||
<span>{% translate "Latest comments" %}</span>
|
||||
</h1>
|
||||
{% if comments %}
|
||||
{% include "aircox/widgets/page_list.html" with object_list=comments with_title=True %}
|
||||
{% for object in comments %}
|
||||
{% page_widget "preview" object with_title=True %}
|
||||
{% endfor %}
|
||||
<div class="has-text-centered">
|
||||
<a href="{% url "admin:aircox_comment_changelist" %}" class="float-center">{% translate "All comments" %}</a>
|
||||
</div>
|
||||
|
@ -48,120 +48,48 @@ Usefull context:
|
||||
})
|
||||
</script>
|
||||
<div id="app">
|
||||
{% block top-nav-container %}
|
||||
<nav class="navbar has-shadow" role="navigation" aria-label="main navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
<a href="/" title="{% translate "Home" %}" class="navbar-item">
|
||||
<img src="{{ station.logo.url }}" class="logo"/>
|
||||
{% block nav %}
|
||||
<nav class="nav primary" role="navigation" aria-label="main navigation">
|
||||
{% block nav-primary %}
|
||||
<a class="nav-brand" href="{% url "home" %}">
|
||||
<img src="{{ station.logo.url }}">
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
{% block top-nav %}
|
||||
{% nav_items "top" css_class="navbar-item" active_class="is-active" as items %}
|
||||
<div class="nav-menu">
|
||||
{% block nav-primary-menu %}
|
||||
{% nav_items "top" css_class="nav-item" active_class="active" as items %}
|
||||
{% for item, render in items %}
|
||||
{{ render }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
{% block top-nav-tools %}
|
||||
{% endblock %}
|
||||
{% block top-nav-end %}
|
||||
<div class="navbar-item">
|
||||
<form action="{% url 'page-list' %}" method="GET">
|
||||
<div class="control has-icons-left">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-search"></i>
|
||||
</span>
|
||||
<input type="text" name="q" class="input"
|
||||
placeholder="{% translate "Search" %}" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
<div class="container">
|
||||
<div class="columns is-desktop">
|
||||
<main class="column page">
|
||||
<header class="header">
|
||||
{% block header %}
|
||||
<h1 class="title is-1">
|
||||
{% block title %}
|
||||
{% if page and page.title %}
|
||||
{{ page.title }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</h1>
|
||||
|
||||
<h3 class="subtitle is-3">
|
||||
{% block subtitle %}{% endblock %}
|
||||
</h3>
|
||||
|
||||
<div class="columns is-size-4">
|
||||
{% block header_nav %}
|
||||
<span class="column">
|
||||
{% block header_crumbs %}
|
||||
{% if parent %}
|
||||
<a href="{{ parent.get_absolute_url }}">
|
||||
{{ parent.title }}</a></li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</span>
|
||||
{% endblock %}
|
||||
{% block secondary-nav %}{% endblock %}
|
||||
</div>
|
||||
|
||||
{% block main-container %}
|
||||
<main class="page">
|
||||
{% block main %}
|
||||
<header class="container header {% if cover %}has-cover{% endif %}">
|
||||
{% block header %}
|
||||
{% include header_template_name|default:"./widgets/header.html" %}
|
||||
{% endblock %}
|
||||
</header>
|
||||
|
||||
{% block main %}
|
||||
{% block content-container %}
|
||||
<div class="container content">
|
||||
{% block content %}
|
||||
{% if page and page.content %}
|
||||
<section class="page-content mb-2">{{ page.content|safe }}</section>
|
||||
<section class="page-content">{{ page.content|safe }}</section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock main %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
{% if has_sidebar %}
|
||||
{% comment %}Translators: main sidebar {% endcomment %}
|
||||
<aside class="column is-one-third-desktop">
|
||||
{# FIXME: block cover into sidebar one #}
|
||||
{% block cover %}
|
||||
{% if page and page.cover %}
|
||||
<img class="cover mb-4" src="{{ page.cover.url }}" class="cover"/>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% with is_thin=True %}
|
||||
{% block sidebar %}
|
||||
{% if sidebar_object_list %}
|
||||
{% with object_list=sidebar_object_list %}
|
||||
{% with list_url=sidebar_list_url %}
|
||||
{% with has_headline=False %}
|
||||
<section>
|
||||
<h4 class="title is-4">
|
||||
{% block sidebar_title %}{% translate "Recently" %}{% endblock %}
|
||||
</h4>
|
||||
{% include "aircox/widgets/page_list.html" %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% endwith %}
|
||||
</aside>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
</div>
|
||||
{% block player-container %}
|
||||
<div id="player">{% include "aircox/widgets/player.html" %}</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "aircox/base.html" %}
|
||||
{% extends "./base.html" %}
|
||||
|
||||
{% comment %}Display a list of BasePages{% endcomment %}
|
||||
{% load i18n aircox %}
|
||||
@ -22,20 +22,24 @@
|
||||
{{ station.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}{{ block.super }}
|
||||
|
||||
{% block content-container %}
|
||||
{{ block.super }}
|
||||
|
||||
<div class="container">
|
||||
|
||||
{% block before_list %}{% endblock %}
|
||||
|
||||
<section role="list">
|
||||
{% block pages_list %}
|
||||
{% with has_headline=True %}
|
||||
{% for object in object_list %}
|
||||
{% block list_object %}
|
||||
{% include object.item_template_name|default:item_template_name %}
|
||||
{% endblock %}
|
||||
{% empty %}
|
||||
{% blocktranslate %}There is nothing published here...{% endblocktranslate %}
|
||||
{% endfor %}
|
||||
{% for object in object_list %}
|
||||
{% block list_object %}
|
||||
{% page_widget item_widget|default:"item" object %}
|
||||
{% endblock %}
|
||||
{% empty %}
|
||||
{% blocktranslate %}There is nothing published here...{% endblocktranslate %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
</section>
|
||||
@ -83,4 +87,5 @@
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -12,18 +12,24 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}{{ date|date:"l d F Y" }}{% endblock %}
|
||||
|
||||
{% block before_list %}
|
||||
{% with "diffusion-list" as url_name %}
|
||||
{% include "aircox/widgets/dates_menu.html" %}
|
||||
{% block header %}
|
||||
{% with "./widgets/dated_list_header.html" as header_template_name %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block secondary-nav %}
|
||||
<nav class="nav secondary">
|
||||
{% include "./widgets/dates_menu.html" with url_name="diffusion-list" %}
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
{% block pages_list %}
|
||||
{% with hide_schedule=True %}
|
||||
<section role="list">
|
||||
{% include 'aircox/widgets/diffusion_list.html' %}
|
||||
<section role="list" class="list">
|
||||
{% for object in object_list %}
|
||||
{% page_widget "item" object.episode diffusion=object timetable=True %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
@ -2,79 +2,50 @@
|
||||
{% comment %}List of a show's episodes for a specific{% endcomment %}
|
||||
{% load i18n aircox %}
|
||||
|
||||
{% include "aircox/program_sidebar.html" %}
|
||||
|
||||
{% block header %}
|
||||
{% with "aircox/widgets/episode_header.html" as header_template_name %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<a-episode :page="{title: "{{ page.title }}", podcasts: {{ object.podcasts|json }}}">
|
||||
<template v-slot="{podcasts,page}">
|
||||
{{ block.super }}
|
||||
{{ block.super }}
|
||||
|
||||
{% if object.podcasts %}
|
||||
<section>
|
||||
{% if tracks %}
|
||||
<section>
|
||||
<h3 class="title is-3">{% translate "Playlist" %}</h3>
|
||||
<table class="table is-hoverable is-fullwidth">
|
||||
<tbody>
|
||||
{% for track in tracks %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ track.artist }}</td>
|
||||
<td>{{ track.title }}</td>
|
||||
<td>{{ track.info|default:"" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<ol>
|
||||
</ol>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% if object.podcasts %}
|
||||
<section>
|
||||
<a-playlist v-if="page" :set="podcasts"
|
||||
name="{{ page.title }}"
|
||||
list-class="menu-list" item-class="menu-item"
|
||||
:player="player" :actions="['play']"
|
||||
@select="player.playItems('queue', $event.item)">
|
||||
<template v-slot:header>
|
||||
<h4 class="title is-4">{% translate "Podcasts" %}</h4>
|
||||
<h3 class="title is-3">{% translate "Podcasts" %}</h3>
|
||||
</template>
|
||||
</a-playlist>
|
||||
{% comment %}
|
||||
{% for object in podcasts %}
|
||||
{% include "aircox/widgets/podcast_item.html" %}
|
||||
{% endfor %}
|
||||
{% endcomment %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% if tracks %}
|
||||
<section>
|
||||
<h4 class="title is-4">{% translate "Playlist" %}</h4>
|
||||
<ol>
|
||||
{% for track in tracks %}
|
||||
<li><span>{{ track.title }}</span>
|
||||
<span class="has-text-grey-dark has-text-weight-light">
|
||||
— {{ track.artist }}
|
||||
{% if track.info %}(<i>{{ track.info }}</i>){% endif %}
|
||||
</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
</template></a-episode>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<section>
|
||||
<h4 class="title is-4">{% translate "Diffusions" %}</h4>
|
||||
<ul>
|
||||
{% for diffusion in object.diffusion_set.all %}
|
||||
<li>
|
||||
{% with diffusion.start as start %}
|
||||
{% with diffusion.end as end %}
|
||||
<time datetime="{{ start }}">{{ start|date:"D. d F Y, H:i" }}</time>
|
||||
—
|
||||
<time datetime="{{ end }}">{{ end|date:"H:i" }}</time>
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
|
||||
<small>
|
||||
{% if diffusion.initial %}
|
||||
{% with diffusion.initial.date as date %}
|
||||
<span title="{% blocktranslate %}Rerun of {{ date }}{% endblocktranslate %}">
|
||||
({% translate "rerun" %})
|
||||
</span>
|
||||
{% endwith %}
|
||||
</section>
|
||||
{% endif %}
|
||||
</small>
|
||||
<br>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{{ block.super }}
|
||||
</template>
|
||||
</a-episode>
|
||||
{% endblock %}
|
||||
|
@ -1,85 +1,57 @@
|
||||
{% extends "aircox/page_list.html" %}
|
||||
{% comment %}Home page{% endcomment %}
|
||||
{% load i18n %}
|
||||
{% load i18n aircox %}
|
||||
|
||||
{% block head_title %}{{ station.name }}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
{% if not page or not page.title %}{{ station.name }}
|
||||
{% else %}{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block content-container %}
|
||||
{{ block.super }}
|
||||
|
||||
{% block before_list %}{% endblock %}
|
||||
|
||||
{% block pages_list %}
|
||||
{% if page and page.content %}<hr/>{% endif %}
|
||||
{% if next_diffs %}
|
||||
<div class="columns">
|
||||
{% with render_card=True %}
|
||||
{% for object in next_diffs %}
|
||||
{% with is_primary=object.is_now %}
|
||||
<div class="column is-relative">
|
||||
<h4 class="card-super-title" title="{{ object.start }}">
|
||||
{% if is_primary %}
|
||||
<span class="fas fa-play"></span>
|
||||
<time datetime="{{ object.start }}">
|
||||
{% translate "Currently" %}
|
||||
</time>
|
||||
{% else %}
|
||||
{{ object.start|date:"H:i" }}
|
||||
{% endif %}
|
||||
<section class="container">
|
||||
<h2 class="title is-3 p-2">
|
||||
{% with station.name as station %}
|
||||
{% blocktrans %}
|
||||
Today on {{ station }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</h2>
|
||||
|
||||
{% if object.episode.category %}
|
||||
// {{ object.episode.category.title }}
|
||||
{% endif %}
|
||||
</h4>
|
||||
{% include object.item_template_name %}
|
||||
<div class="mb-3">
|
||||
{% with next_diffs.0 as obj %}
|
||||
{% page_widget "wide" obj.episode diffusion=obj timetable=True %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
<div class="card-grid">
|
||||
{% for obj in next_diffs|slice:"1:4" %}
|
||||
{% if object != diffusion %}
|
||||
{% page_widget "card" obj.episode diffusion=obj timetable=True %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if object_list %}
|
||||
<h4 class="title is-4">{% translate "Today" %}</h4>
|
||||
<section role="list">
|
||||
{% include 'aircox/widgets/diffusion_list.html' %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block pagination %}
|
||||
<ul class="pagination-list">
|
||||
<li>
|
||||
<a href="{% url "page-list" %}" class="pagination-link"
|
||||
aria-label="{% translate "Show all publication" %}">
|
||||
{% translate "More publications..." %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block sidebar %}
|
||||
<section>
|
||||
<h4 class="title is-4">{% translate "Previously on air" %}</h4>
|
||||
{% with has_cover=False %}
|
||||
{% with logs as object_list %}
|
||||
{% include "aircox/widgets/log_list.html" %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% if logs %}
|
||||
<section class="container">
|
||||
<h2 class="title is-3 p-2">{% translate "It just happened" %}</h2>
|
||||
{% for object in logs %}
|
||||
{% include "./widgets/log.html" with widget="item" %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<section>
|
||||
<h4 class="title is-4">{% translate "Last publications" %}</h4>
|
||||
{% with hide_schedule=True %}
|
||||
{% with has_headline=False %}
|
||||
{% if last_publications %}
|
||||
<section class="container">
|
||||
<h2 class="title is-3 p-2">{% translate "Last publications" %}</h2>
|
||||
|
||||
<div role="list">
|
||||
{% for object in last_publications %}
|
||||
{% include object.item_template_name|default:'aircox/widgets/page_item.html' %}
|
||||
{% page_widget "item" object open=True %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block pages_list %}{% endblock %}
|
||||
|
@ -15,15 +15,37 @@
|
||||
|
||||
{% block subtitle %}{{ date|date:"l d F Y" }}{% endblock %}
|
||||
|
||||
{% block before_list %}
|
||||
{% with "log-list" as url_name %}
|
||||
{% include "aircox/widgets/dates_menu.html" %}
|
||||
{% block header %}
|
||||
{% with "./widgets/dated_list_header.html" as header_template_name %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block pages_list %}
|
||||
|
||||
{% block secondary-nav %}
|
||||
<nav class="nav secondary">
|
||||
{% include "./widgets/dates_menu.html" with url_name="log-list" %}
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block pages_list_ %}
|
||||
<section>
|
||||
{# <h4 class="subtitle size-4">{{ date }}</h4> #}
|
||||
{% include "aircox/widgets/log_list.html" %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block pages_list %}
|
||||
{% with hide_schedule=True %}
|
||||
<section role="list" class="list">
|
||||
{% for object in object_list %}
|
||||
{% if object.episode %}
|
||||
{% page_widget "item" object.episode diffusion=object timetable=True %}
|
||||
{% else %}
|
||||
{% page_widget "item" object timetable=True %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
@ -32,41 +32,29 @@ Context:
|
||||
{{ block.super }}
|
||||
|
||||
{% block comments %}
|
||||
{% if comments or comment_form %}
|
||||
<section class="mt-6">
|
||||
<h4 class="title is-4">{% translate "Comments" %}</h4>
|
||||
{% if comments %}
|
||||
<section class="container">
|
||||
<h2 class="title">{% translate "Comments" %}</h2>
|
||||
|
||||
{% for comment in comments %}
|
||||
<div class="media box">
|
||||
<div class="media-content">
|
||||
<p>
|
||||
<strong class="mr-2">{{ comment.nickname }}</strong>
|
||||
<time datetime="{{ comment.date }}" title="{{ comment.date }}">
|
||||
<small>{{ comment.date|naturaltime }}</small>
|
||||
</time>
|
||||
<br>
|
||||
{{ comment.content }}
|
||||
</p>
|
||||
</div>
|
||||
{% for object in comments %}
|
||||
<div id="comment-{{ object.pk }}">
|
||||
{% page_widget "item" object %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% if comment_form %}
|
||||
{% if comment_form %}
|
||||
<section class="container">
|
||||
<form method="POST">
|
||||
<h5 class="title is-5">{% translate "Post a comment" %}</h5>
|
||||
<h2 class="title">{% translate "Post a comment" %}</h2>
|
||||
{% csrf_token %}
|
||||
{% render_honeypot_field "website" %}
|
||||
|
||||
{% for field in comment_form %}
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">
|
||||
{{ field.label_tag }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<p class="control is-expanded">{{ field }}</p>
|
||||
<label class="label">{{ field.label_tag }}</label>
|
||||
<div class="control">{{ field }}</div>
|
||||
{% if field.errors %}
|
||||
<p class="help is-danger">{{ field.errors }}</p>
|
||||
{% endif %}
|
||||
@ -74,15 +62,13 @@ Context:
|
||||
<p class="help">{{ field.help_text|safe }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="has-text-right">
|
||||
<button type="reset" class="button is-danger">{% translate "Reset" %}</button>
|
||||
<button type="reset" class="button is-danger mr-3">{% translate "Reset" %}</button>
|
||||
<button type="submit" class="button is-success">{% translate "Post comment" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
|
@ -2,61 +2,21 @@
|
||||
{% comment %}Display a list of Pages{% endcomment %}
|
||||
{% load i18n aircox %}
|
||||
|
||||
{% block before_list %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if view.has_filters and object_list %}
|
||||
<form method="GET" action="" class="media">
|
||||
<div class="media-content">
|
||||
{% block filters %}
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">{% translate "Search" %}</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control has-icons-left">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fa fa-search"></i>
|
||||
</span>
|
||||
<input class="input" type="text" name="q"
|
||||
value="{{ filterset_data.q }}"
|
||||
placeholder="{% translate "Search content" %}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
<label class="label">{% translate "Categories" %}</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field is-narrow">
|
||||
<div class="control">
|
||||
{% for label, value in categories %}
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" class="checkbox" name="category__id__in"
|
||||
value="{{ value }}"
|
||||
{% if value in filterset_data.category__id__in %}checked{% endif %} />
|
||||
{{ label }}
|
||||
</label>
|
||||
{% block secondary-nav %}
|
||||
<form class="nav secondary">
|
||||
{% for id, title in view.categories.items %}
|
||||
<a class="nav-item{% if category_id == id %} active{% endif %}"
|
||||
href="?category__id={{ id }}">{{ title }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<div class="field is-grouped is-grouped-right">
|
||||
<div class="control">
|
||||
<button class="button is-primary"/>{% translate "Apply" %}</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="?" class="button is-secondary">{% translate "Reset" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
{% if page and not object %}
|
||||
{% with page as object %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -1,41 +1,54 @@
|
||||
{% extends "aircox/page_detail.html" %}
|
||||
{% comment %}Detail page of a show{% endcomment %}
|
||||
{% load i18n %}
|
||||
{% load i18n aircox %}
|
||||
|
||||
{% include "aircox/program_sidebar.html" %}
|
||||
|
||||
|
||||
{% block header_nav %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% block content-container %}
|
||||
{{ block.super }}
|
||||
<br>
|
||||
{% with has_headline=False %}
|
||||
{% if articles %}
|
||||
<section>
|
||||
<h4 class="title is-4">{% translate "Articles" %}</h4>
|
||||
|
||||
{% for object in articles %}
|
||||
{% include "aircox/widgets/page_item.html" %}
|
||||
{% if episodes %}
|
||||
<section class="container">
|
||||
<h4 class="title is-3">{% translate "Last Episodes" %}</h4>
|
||||
<section class="card-grid">
|
||||
{% for object in episodes|slice:":3" %}
|
||||
{% page_widget "card" object %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<br>
|
||||
<nav class="pagination is-centered">
|
||||
<ul class="pagination-list">
|
||||
<li>
|
||||
<a href="{% url "article-list" parent_slug=program.slug %}"
|
||||
class="pagination-link"
|
||||
aria-label="{% translate "Show all program's articles" %}">
|
||||
{% translate "More articles" %}
|
||||
<nav class="has-text-right">
|
||||
<li class="nav-item">
|
||||
<a href="{% url "episode-list" parent_slug=program.slug %}"
|
||||
class="button action">
|
||||
{% translate "All episodes" %}
|
||||
</a>
|
||||
</li>
|
||||
</nav>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if articles %}
|
||||
<section class="container">
|
||||
<h4 class="title is-4">{% translate "Last Articles" %}</h4>
|
||||
|
||||
<section class="card-grid">
|
||||
{% for object in articles|slice:3 %}
|
||||
{% page_widget "card" object %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<nav class="has-text-right">
|
||||
<li class="nav-item">
|
||||
<a href="{% url "article-list" parent_slug=program.slug %}"
|
||||
class="button action"
|
||||
aria-label="{% translate "Show all program's articles" %}">
|
||||
{% translate "All articles" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
4
aircox/templates/aircox/widgets/article.html
Normal file
4
aircox/templates/aircox/widgets/article.html
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "./page.html" %}
|
||||
{% load humanize %}
|
||||
|
||||
{% block subtitle %}{{ object.pub_date.date }}{% endblock %}
|
@ -11,63 +11,48 @@ Context variables:
|
||||
- is_thin (=False): if True, smaller cover and display less info
|
||||
{% endcomment %}
|
||||
|
||||
{% if render_card %}
|
||||
<article class="card {% if is_primary %}is-primary{% endif %}">
|
||||
<header class="card-image">
|
||||
<a href="{{ object.get_absolute_url }}">
|
||||
<figure class="image is-4by3">
|
||||
<img src="{% thumbnail object.cover|default:station.default_cover 480x480 %}">
|
||||
</figure>
|
||||
</a>
|
||||
{% block outer %}
|
||||
<article class="preview preview-item{% if is_primary %}is-primary{% endif %}{% block card_class %}{% endblock %}">
|
||||
{% block inner %}
|
||||
<header class="headings"
|
||||
style="background-image: url({{ object.cover.url }})">
|
||||
{% block headings %}
|
||||
<div>
|
||||
<span class="heading subtitle">{% block subtitle %}{% endblock %}</span>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</header>
|
||||
<div class="card-header">
|
||||
<h4 class="title">
|
||||
<a href="{{ object.get_absolute_url }}">
|
||||
{% block card_title %}{{ object.title }}{% endblock %}
|
||||
|
||||
<div class="">
|
||||
<div>
|
||||
<h2 class="heading title">{% block title %}{% endblock %}</h2>
|
||||
</div>
|
||||
|
||||
<summary class="heading-container">
|
||||
{% block content %}
|
||||
{% if content and with_content %}
|
||||
{% autoescape off %}
|
||||
{{ content|striptags|truncatewords:64|linebreaks }}
|
||||
{% endautoescape %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</summary>
|
||||
|
||||
<div class="actions">
|
||||
{% block actions %}
|
||||
<a class="button btn-hg float-right" href="{{ object.get_absolute_url|escape }}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-external-link"></i>
|
||||
</span>
|
||||
<label>{% translate "More infos" %}</label>
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
||||
{% else %}
|
||||
<article class="media item {% block css %}{% endblock%}">
|
||||
{% if has_cover|default_if_none:True %}
|
||||
<div class="media-left">
|
||||
{% if is_thin %}
|
||||
<img src="{% thumbnail object.cover|default:station.default_cover 64x64 crop=scale %}"
|
||||
class="cover is-tiny">
|
||||
{% else %}
|
||||
<img src="{% thumbnail object.cover|default:station.default_cover 128x128 crop=scale %}"
|
||||
class="cover is-small">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="media-content">
|
||||
<h5 class="title is-5 has-text-weight-normal">
|
||||
{% block title %}
|
||||
{% if object.is_published %}
|
||||
<a href="{{ object.get_absolute_url }}">{{ object.title }}</a>
|
||||
{% else %}
|
||||
{{ object.title }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</h5>
|
||||
<div class="subtitle is-6 has-text-weight-light">
|
||||
{% block subtitle %}
|
||||
{% if object.category %}{{ object.category.title }}{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% if has_headline|default_if_none:True %}
|
||||
<div class="headline">
|
||||
{% block headline %}{{ object.headline }}{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% if not no_actions %}
|
||||
{% block actions %}{% endblock %}
|
||||
{% if with_container %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</article>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
18
aircox/templates/aircox/widgets/card.html
Normal file
18
aircox/templates/aircox/widgets/card.html
Normal file
@ -0,0 +1,18 @@
|
||||
{% extends "./preview.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block tag-class %}{{ block.super }} preview-card{% endblock %}
|
||||
{% block tag-extra %}
|
||||
{{ block.super }}
|
||||
{% if cover %}
|
||||
style="background-image: url({{ cover }});"
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block headings-class %}{{ block.super }} preview-card-headings{% endblock %}
|
||||
|
||||
{% block inner %}
|
||||
{% block headings-container %}
|
||||
{{ block.super }}
|
||||
{% block actions-container %}{{ block.super }}{% endblock %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
7
aircox/templates/aircox/widgets/carousel.html
Normal file
7
aircox/templates/aircox/widgets/carousel.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% load aircox %}
|
||||
|
||||
<div class="card-grid">
|
||||
{% for object in object_list %}
|
||||
{% page_widget "card" object.episode diffusion=object %}
|
||||
{% endfor %}
|
||||
</div>
|
50
aircox/templates/aircox/widgets/comment.html
Normal file
50
aircox/templates/aircox/widgets/comment.html
Normal file
@ -0,0 +1,50 @@
|
||||
{% extends "./page.html" %}
|
||||
{% load i18n humanize aircox %}
|
||||
|
||||
{% block tag-class %}{{ block.super }} comment{% endblock %}
|
||||
|
||||
{% block outer %}
|
||||
{% if with_title %}
|
||||
{% with url=object.parent.get_absolute_url %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block title %}
|
||||
{{ object.nickname }} — {{ object.date }}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}
|
||||
{% if with_title %}
|
||||
{{ object.parent.title }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}{{ object.content }}{% endblock %}
|
||||
|
||||
{% block actions %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if request.user.is_staff %}
|
||||
<span class="float-right">
|
||||
<a href="{% url "admin:aircox_comment_change" object.pk %}"
|
||||
title="{% trans "Edit comment" %}"
|
||||
aria-label="{% trans "Edit comment" %}">
|
||||
<span class="fa fa-edit"></span>
|
||||
</a>
|
||||
<a class="has-text-danger"
|
||||
title="{% trans "Delete comment" %}"
|
||||
aria-label="{% trans "Delete comment" %}"
|
||||
href="{% url "admin:aircox_comment_delete" object.pk %}">
|
||||
<span class="fa fa-trash-alt"></span>
|
||||
</a>
|
||||
|
||||
{# <a href="mailto:{{ object.email }}">{{ object.nickname }}</a> #}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
7
aircox/templates/aircox/widgets/dated_list_header.html
Normal file
7
aircox/templates/aircox/widgets/dated_list_header.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% extends "./header.html" %}
|
||||
|
||||
{% block outer %}
|
||||
{% with date|date:"l d F Y" as subtitle %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
@ -11,36 +11,26 @@ An empty date results to a title or a separator
|
||||
{% endcomment %}
|
||||
{% load i18n %}
|
||||
|
||||
<div class="media" role="menu"
|
||||
aria-label="{% translate "pick a date" %}">
|
||||
<div class="media-content">
|
||||
<div class="tabs is-toggle">
|
||||
<ul>
|
||||
{% for day in dates %}
|
||||
<li class="{% if day == date %}is-active{% endif %}">
|
||||
<a href="{% url url_name date=day %}">
|
||||
{{ day|date:"D. d" }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% for day in dates %}
|
||||
<a href="{% url url_name date=day %}" class="nav-item {% if day == date %}active{% endif %}">
|
||||
{{ day|date:"l d" }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
|
||||
<div class="media-right">
|
||||
<form action="{% url url_name %}" method="GET" class="navbar-body"
|
||||
aria-label="{% translate "Jump to date" %}">
|
||||
<div class="field has-addons">
|
||||
<div class="control has-icons-left">
|
||||
<span class="icon is-small is-left"><span class="far fa-calendar"></span></span>
|
||||
<input type="{{ date_input|default:"date" }}" class="input date"
|
||||
name="date" value="{{ date|date:"Y-m-d" }}">
|
||||
</div>
|
||||
<div class="control">
|
||||
{% comment %}Translators: form button to select a date{% endcomment %}
|
||||
<button class="button is-primary">{% translate "Go" %}</button>
|
||||
<a-dropdown class="nav-item align-right flex-grow-0 dropdown is-right"
|
||||
content-class="dropdown-menu"
|
||||
button-tag="span" button-class="dropdown-trigger"
|
||||
button-icon-open="fa-solid fa-plus" button-icon-close="fa-solid fa-minus">
|
||||
<template #default>
|
||||
<div class="dropdown-content">
|
||||
<div class="dropdown-item">
|
||||
<h4>{% translate "Pick a date" %}</h4>
|
||||
<v-calendar mode="date" borderless
|
||||
:initial-page="{month: {{date.month}}, year: {{date.year}}}"
|
||||
@dayclick="(event) => window.aircox.pickDate({% url url_name %}, event)"
|
||||
color="yellow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
|
@ -3,19 +3,4 @@ Context:
|
||||
- object_list: object list
|
||||
- date: date for list
|
||||
{% endcomment %}
|
||||
<table id="timetable{% if date %}-{{ date|date:"Y-m-d" }}{% endif %}" class="timetable">
|
||||
{% for diffusion in object_list %}
|
||||
<tr class="{% if diffusion.is_now %}has-background-primary{% endif %}">
|
||||
<td class="pr-2 pb-2">
|
||||
<time datetime="{{ diffusion.start|date:"c" }}">
|
||||
{{ diffusion.start|date:"H:i" }} - {{ diffusion.end|date:"H:i" }}
|
||||
</time>
|
||||
</td>
|
||||
<td class="pb-2">
|
||||
{% with diffusion.episode as object %}
|
||||
{% include "aircox/widgets/episode_item.html" %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% load aircox %}
|
||||
|
32
aircox/templates/aircox/widgets/episode.html
Normal file
32
aircox/templates/aircox/widgets/episode.html
Normal file
@ -0,0 +1,32 @@
|
||||
{% extends "./page.html" %}
|
||||
{% load i18n humanize aircox %}
|
||||
|
||||
{% block subtitle %}
|
||||
{% if diffusion %}
|
||||
{% if timetable %}
|
||||
{{ diffusion.start|date:"H:i" }}
|
||||
—
|
||||
{{ diffusion.end|date:"H:i" }}
|
||||
{% else %}
|
||||
{{ diffusion.start|naturalday }},
|
||||
{{ diffusion.start|date:"H:i" }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block actions %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if object.sound_set.count %}
|
||||
<button class="button action" @click="player.playButtonClick($event)"
|
||||
data-sounds="{{ object.podcasts|json }}">
|
||||
<span class="icon is-small">
|
||||
<span class="fas fa-play"></span>
|
||||
</span>
|
||||
<label>{% translate "Listen" %}</label>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock %}
|
10
aircox/templates/aircox/widgets/episode_header.html
Normal file
10
aircox/templates/aircox/widgets/episode_header.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% extends "aircox/widgets/header.html" %}
|
||||
|
||||
{% block header-nav %}
|
||||
{{ block.super }}
|
||||
<div>
|
||||
<a class="heading" href="{{ object.program.get_absolute_url }}">
|
||||
{{ object.program.display_title }}
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,58 +1,36 @@
|
||||
{% extends "aircox/widgets/page_item.html" %}
|
||||
{% comment %}
|
||||
List item for an episode.
|
||||
|
||||
Context variables:
|
||||
- object: episode
|
||||
- diffusion: episode's diffusion
|
||||
- hide_schedule: if True, do not display start time
|
||||
{% endcomment %}
|
||||
|
||||
{% load i18n easy_thumbnails_tags aircox %}
|
||||
{% extends "./basepage_item.html" %}
|
||||
{% load i18n humanize %}
|
||||
|
||||
{% block title %}
|
||||
{% if not object.is_published and object.program.is_published %}
|
||||
<a href="{{ object.program.get_absolute_url }}">
|
||||
<a href="{{ object.program.get_absolute_url }}">
|
||||
{{ object.program.title }}
|
||||
{% if diffusion %}
|
||||
—
|
||||
{{ diffusion.start|date:"d F" }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</a>
|
||||
{% else %}
|
||||
{{ block.super }}
|
||||
{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block class %}
|
||||
{% if object.is_now %}is-active{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if diffusion %}
|
||||
{% if not hide_schedule %}
|
||||
{% if object.category %}—{% endif %}
|
||||
<time datetime="{{ diffusion.start|date:"c" }}" title="{{ diffusion.start }}">
|
||||
{{ diffusion.start|date:"d M, H:i" }}
|
||||
</time>
|
||||
{% endif %}
|
||||
{{ diffusion.start|naturalday }},
|
||||
{{ diffusion.start|date:"g:i" }}
|
||||
{% else %}
|
||||
{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% if diffusion.initial %}
|
||||
{% with diffusion.initial.date as date %}
|
||||
<span title="{% blocktranslate %}Rerun of {{ date }}{% endblocktranslate %}">
|
||||
{% translate "(rerun)" %}
|
||||
</span>
|
||||
|
||||
{% block content %}
|
||||
{% if not object.content %}
|
||||
{% with object.parent.content as content %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block actions %}
|
||||
{% if object.sound_set.public.count %}
|
||||
<button class="button" @click="player.playButtonClick($event)"
|
||||
data-sounds="{{ object.podcasts|json }}">
|
||||
<span class="icon is-small">
|
||||
<span class="fas fa-play"></span>
|
||||
</span>
|
||||
</button>
|
||||
{% else %}
|
||||
{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
20
aircox/templates/aircox/widgets/header.html
Normal file
20
aircox/templates/aircox/widgets/header.html
Normal file
@ -0,0 +1,20 @@
|
||||
{% extends "./card.html" %}
|
||||
|
||||
{% block tag-class %}preview-header{% endblock %}
|
||||
{% block headings-class %}{{ block.super }} preview-card-headings{% endblock %}
|
||||
|
||||
|
||||
{% block headings %}
|
||||
{{ block.super }}
|
||||
|
||||
{% if parent and parent.is_published %}
|
||||
<div>
|
||||
<a href="{{ parent.get_absolute_url|escape }}" class="heading subtitle">
|
||||
<span class="icon">
|
||||
<i class="fa fa-angles-right"></i>
|
||||
</span>
|
||||
{{ parent.title }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
42
aircox/templates/aircox/widgets/item.html
Normal file
42
aircox/templates/aircox/widgets/item.html
Normal file
@ -0,0 +1,42 @@
|
||||
{% extends "./preview.html" %}
|
||||
{% load i18n aircox %}
|
||||
|
||||
{% block tag-class %}list-item is-fullwidth{% endblock %}
|
||||
{% block headings-class %} columns{% endblock %}
|
||||
|
||||
{% block headings %}
|
||||
<div class="column">
|
||||
<a href="{{ url|escape }}" class="heading title {% block title-class %}{% endblock %}">{% block title %}{{ title|default:"" }}{% endblock %}</a>
|
||||
</div>
|
||||
<div>
|
||||
<span class="heading subtitle {% block subtitle-class %}{% endblock %}">{% block subtitle %}{{ subtitle|default:"" }}{% endblock %}</span>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block inner %}
|
||||
{% block headings-container %}{{ block.super }}{% endblock %}
|
||||
{% block content-container %}
|
||||
<div class="media">
|
||||
{% if object.cover %}
|
||||
<div class="media-left preview-cover small"
|
||||
style="background-image: url({{ object.cover.url }})">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="media-content">
|
||||
<section class="content">
|
||||
{% block content %}
|
||||
{% if content and with_content %}
|
||||
{% autoescape off %}
|
||||
{{ content|striptags|linebreaks }}
|
||||
{% endautoescape %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</section>
|
||||
|
||||
{% block actions-container %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
@ -11,12 +11,10 @@ for design review.
|
||||
|
||||
{% endcomment %}
|
||||
|
||||
{% block outer %}
|
||||
{% if object|is_diffusion %}
|
||||
{% with object as diffusion %}
|
||||
{% include "aircox/widgets/diffusion_item.html" %}
|
||||
{% endwith %}
|
||||
{% page_widget widget object.episode diffusion=object %}
|
||||
{% else %}
|
||||
{% with object.track as object %}
|
||||
{% include "aircox/widgets/track_item.html" %}
|
||||
{% endwith %}
|
||||
{% include "./track_item.html" with object=object.track log=object %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -1,30 +0,0 @@
|
||||
{% comment %}
|
||||
Render list of logs (as widget).
|
||||
|
||||
Context:
|
||||
- object_list: list of logs to display
|
||||
- is_thin: if True, hide some information in order to fit in a thin container
|
||||
{% endcomment %}
|
||||
{% load aircox %}
|
||||
|
||||
{% with True as hide_schedule %}
|
||||
<table class="table is-striped is-hoverable is-fullwidth" role="list">
|
||||
{% for object in object_list %}
|
||||
<tr {% if object|is_diffusion and object.is_now %}class="is-selected"{% endif %}>
|
||||
<td>
|
||||
{% if object|is_diffusion %}
|
||||
<time datetime="{{ object.start }}" title="{{ object.start }}">
|
||||
{{ object.start|date:"H:i" }}
|
||||
{% if not is_thin %} - {{ object.end|date:"H:i" }}{% endif %}
|
||||
</time>
|
||||
{% else %}
|
||||
<time datetime="{{ object.date }}" title="{{ object.date }}">
|
||||
{{ object.date|date:"H:i" }}
|
||||
</time>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{% include "aircox/widgets/log_item.html" %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endwith %}
|
30
aircox/templates/aircox/widgets/page.html
Normal file
30
aircox/templates/aircox/widgets/page.html
Normal file
@ -0,0 +1,30 @@
|
||||
{% extends widget_template %}
|
||||
{% load i18n %}
|
||||
|
||||
|
||||
{% block outer %}
|
||||
{% with object.get_absolute_url as url %}
|
||||
{% with object.cover.url as cover %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block title %}
|
||||
{% if title %}
|
||||
{{ block.super }}
|
||||
{% elif object %}
|
||||
{{ object.display_title }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% if content %}
|
||||
{{ content }}
|
||||
{% elif object %}
|
||||
{{ block.super }}
|
||||
{{ object.display_headline }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
13
aircox/templates/aircox/widgets/page_card.html
Normal file
13
aircox/templates/aircox/widgets/page_card.html
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends widget|default:"./card.html" %}
|
||||
|
||||
{% block outer %}
|
||||
{% if object %}
|
||||
{% with content=object.get_display_excerpt() %}
|
||||
{% with title=object.get_display_title() %}
|
||||
{{ block.super }}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
{{ block.super }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -3,3 +3,11 @@
|
||||
{% block card_title %}
|
||||
{% block title %}{{ block.super }}{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block card_subtitle %}
|
||||
{% block subtitle %}{{ block.super }}{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block card_class %}
|
||||
{% block class %}{{ block.super }}{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -5,10 +5,10 @@ Context:
|
||||
- object_list: object list
|
||||
- list_url: url to complete list page
|
||||
{% endcomment %}
|
||||
{% load i18n %}
|
||||
{% load i18n aircox %}
|
||||
|
||||
{% for object in object_list %}
|
||||
{% include object.item_template_name %}
|
||||
{% page_widget "item" object %}
|
||||
{% endfor %}
|
||||
|
||||
{% if list_url %}
|
||||
|
52
aircox/templates/aircox/widgets/preview.html
Normal file
52
aircox/templates/aircox/widgets/preview.html
Normal file
@ -0,0 +1,52 @@
|
||||
{% load i18n %}
|
||||
{% comment %}
|
||||
Content related context:
|
||||
- object: object to display
|
||||
- cover: cover
|
||||
- title: title
|
||||
- subtitle: subtitle
|
||||
- content: content to display
|
||||
|
||||
Styling related context:
|
||||
- tag_class: css class to set to main tag
|
||||
- tag_style: css styles to set to main tag
|
||||
- child_tag_class: css class to set to direct component node children
|
||||
|
||||
{% endcomment %}
|
||||
|
||||
{% block outer %}
|
||||
<article class="preview {% if not cover %}no-cover {% endif %}{% if is_active %}is-active{% 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 %}
|
||||
<div>
|
||||
<a href="{{ url|escape }}" class="heading title {% block title-class %}{% endblock %}">{% block title %}{{ title|default:"" }}{% endblock %}</a>
|
||||
</div>
|
||||
<div>
|
||||
<span class="heading subtitle {% block subtitle-class %}{% endblock %}">{% block subtitle %}{{ subtitle|default:"" }}{% endblock %}</span>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
{% block content-container %}
|
||||
<section class="content headings-container">
|
||||
{% block content %}
|
||||
{% if content and with_content %}
|
||||
{% autoescape off %}
|
||||
{{ content|striptags|linebreaks }}
|
||||
{% endautoescape %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block actions-container %}
|
||||
<div class="actions">
|
||||
{% block actions %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
</article>
|
||||
{% endblock %}
|
@ -5,9 +5,16 @@ Context:
|
||||
- object: track to render
|
||||
{% endcomment %}
|
||||
|
||||
<span class="has-text-info is-size-5">♬</span>
|
||||
<span>{{ object.title }}</span>
|
||||
<span class="has-text-grey-dark has-text-weight-light">
|
||||
— {{ object.artist }}
|
||||
{% if object.info %}(<i>{{ object.info }}</i>){% endif %}
|
||||
<span class="content">
|
||||
<span class="has-text-info">♬</span>
|
||||
{% if log %}
|
||||
<span>{{ log.date|date:"H:i" }} — </span>
|
||||
{% endif %}
|
||||
<span class="has-text-weight-bold">{{ object.title }}</span>
|
||||
{% if object.artist and object.artist != object.title %}
|
||||
<span>
|
||||
— {{ object.artist }}
|
||||
{% if object.info %}(<i>{{ object.info }}</i>){% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
|
20
aircox/templates/aircox/widgets/wide.html
Normal file
20
aircox/templates/aircox/widgets/wide.html
Normal file
@ -0,0 +1,20 @@
|
||||
{% extends "./preview.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block tag-class %}{{ block.super }} preview-wide columns{% endblock %}
|
||||
{% block headings-class %}{{ block.super }} preview-card-headings{% endblock %}
|
||||
{% block headings-tag-extra %}
|
||||
{{ block.super }}
|
||||
{% if cover %}
|
||||
style="background-image: url({{ cover }});"
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block inner %}
|
||||
{% block headings-container %}{{ block.super }}{% endblock %}
|
||||
<div class="is-flex-direction-column">
|
||||
{% block content-container %}{{ block.super }}{% endblock %}
|
||||
{% block actions-container %}{{ block.super }}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
@ -3,14 +3,32 @@ import random
|
||||
|
||||
from django import template
|
||||
from django.contrib.admin.templatetags.admin_urls import admin_urlname
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
|
||||
from aircox.models import Diffusion, Log
|
||||
|
||||
|
||||
random.seed()
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag(name="page_widget", takes_context=True)
|
||||
def do_page_widget(context, widget, object, dir="aircox/widgets", **ctx):
|
||||
"""Render widget for the provided page and context."""
|
||||
ctx["request"] = context["request"]
|
||||
ctx["object"] = object
|
||||
ctx["widget"] = widget
|
||||
ctx["widget_template"] = f"{dir}/{widget}.html"
|
||||
return render_to_string(object.get_template_name(widget), ctx)
|
||||
|
||||
|
||||
@register.filter(name="page_template")
|
||||
def do_page_template(self, page, component):
|
||||
"""For a provided page object and component name, return template name."""
|
||||
return page.get_template(component)
|
||||
|
||||
|
||||
@register.filter(name="admin_url")
|
||||
def do_admin_url(obj, arg, pass_id=True):
|
||||
"""Reverse admin url for object."""
|
||||
|
@ -57,9 +57,6 @@ class TestBaseView:
|
||||
"station": station,
|
||||
"page": None, # get_page() returns None
|
||||
"has_sidebar": base_view.has_sidebar,
|
||||
"has_filters": False,
|
||||
"sidebar_object_list": published_pages[: base_view.list_count],
|
||||
"sidebar_list_url": base_view.get_sidebar_url(),
|
||||
"audio_streams": station.streams,
|
||||
"model": base_view.model,
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ __all__ = ["ArticleDetailView", "ArticleListView"]
|
||||
|
||||
|
||||
class ArticleDetailView(PageDetailView):
|
||||
has_sidebar = True
|
||||
model = Article
|
||||
|
||||
def get_sidebar_queryset(self):
|
||||
|
@ -2,18 +2,12 @@ from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from django.views.generic.base import ContextMixin, TemplateResponseMixin
|
||||
|
||||
from ..models import Page
|
||||
|
||||
__all__ = ("BaseView", "BaseAPIView")
|
||||
|
||||
|
||||
class BaseView(TemplateResponseMixin, ContextMixin):
|
||||
has_sidebar = True
|
||||
"""Show side navigation."""
|
||||
has_filters = False
|
||||
"""Show filters nav."""
|
||||
list_count = 5
|
||||
"""Item count for small lists displayed on page."""
|
||||
header_template_name = "aircox/widgets/header.html"
|
||||
|
||||
@property
|
||||
def station(self):
|
||||
@ -22,31 +16,13 @@ class BaseView(TemplateResponseMixin, ContextMixin):
|
||||
# def get_queryset(self):
|
||||
# return super().get_queryset().station(self.station)
|
||||
|
||||
def get_sidebar_queryset(self):
|
||||
"""Return a queryset of items to render on the side nav."""
|
||||
return (
|
||||
Page.objects.select_subclasses().published().order_by("-pub_date")
|
||||
)
|
||||
|
||||
def get_sidebar_url(self):
|
||||
return reverse("page-list")
|
||||
|
||||
def get_page(self):
|
||||
return None
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.setdefault("station", self.station)
|
||||
kwargs.setdefault("page", self.get_page())
|
||||
kwargs.setdefault("has_filters", self.has_filters)
|
||||
|
||||
has_sidebar = kwargs.setdefault("has_sidebar", self.has_sidebar)
|
||||
if has_sidebar and "sidebar_object_list" not in kwargs:
|
||||
sidebar_object_list = self.get_sidebar_queryset()
|
||||
if sidebar_object_list is not None:
|
||||
kwargs["sidebar_object_list"] = sidebar_object_list[
|
||||
: self.list_count
|
||||
]
|
||||
kwargs["sidebar_list_url"] = self.get_sidebar_url()
|
||||
kwargs.setdefault("header_template_name", self.header_template_name)
|
||||
|
||||
if "audio_streams" not in kwargs:
|
||||
kwargs["audio_streams"] = self.station.streams
|
||||
@ -59,6 +35,11 @@ class BaseView(TemplateResponseMixin, ContextMixin):
|
||||
)
|
||||
kwargs["model"] = model
|
||||
|
||||
page = kwargs.get("page")
|
||||
if page:
|
||||
kwargs["title"] = page.display_title
|
||||
kwargs["cover"] = page.cover and page.cover.url
|
||||
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
|
@ -13,7 +13,6 @@ class DiffusionListView(GetDateMixin, AttachedToMixin, BaseView, ListView):
|
||||
"""View for timetables."""
|
||||
|
||||
model = Diffusion
|
||||
has_filters = True
|
||||
redirect_date_url = "diffusion-list"
|
||||
attach_to_value = StaticPage.ATTACH_TO_DIFFUSIONS
|
||||
|
||||
|
@ -5,16 +5,16 @@ from django.views.generic import ListView
|
||||
|
||||
from ..models import Diffusion, Log, Page, StaticPage
|
||||
from .base import BaseView
|
||||
from .mixins import AttachedToMixin
|
||||
|
||||
|
||||
class HomeView(BaseView, ListView):
|
||||
class HomeView(AttachedToMixin, BaseView, ListView):
|
||||
template_name = "aircox/home.html"
|
||||
model = Diffusion
|
||||
attach_to_value = StaticPage.ATTACH_TO_HOME
|
||||
model = Diffusion
|
||||
queryset = Diffusion.objects.on_air().select_related("episode")
|
||||
logs_count = 5
|
||||
publications_count = 5
|
||||
has_filters = False
|
||||
publications_count = 7
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().date(date.today())
|
||||
@ -27,14 +27,15 @@ class HomeView(BaseView, ListView):
|
||||
|
||||
def get_next_diffs(self):
|
||||
now = tz.now()
|
||||
current_diff = Diffusion.objects.on_air().now(now).first()
|
||||
next_diffs = Diffusion.objects.on_air().after(now)
|
||||
query = Diffusion.objects.on_air().select_related("episode")
|
||||
current_diff = query.now(now).first()
|
||||
next_diffs = query.after(now)
|
||||
if current_diff:
|
||||
diffs = [current_diff] + list(
|
||||
next_diffs.exclude(pk=current_diff.pk)[:2]
|
||||
next_diffs.exclude(pk=current_diff.pk)[:9]
|
||||
)
|
||||
else:
|
||||
diffs = next_diffs[:3]
|
||||
diffs = next_diffs[:10]
|
||||
return diffs
|
||||
|
||||
def get_last_publications(self):
|
||||
@ -52,8 +53,16 @@ class HomeView(BaseView, ListView):
|
||||
return items
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["logs"] = self.get_logs(context["object_list"])
|
||||
context["next_diffs"] = self.get_next_diffs()
|
||||
context["last_publications"] = self.get_last_publications()[:5]
|
||||
return context
|
||||
next_diffs = self.get_next_diffs()
|
||||
current_diff = next_diffs and next_diffs[0]
|
||||
|
||||
kwargs.update(
|
||||
{
|
||||
"object": current_diff.episode,
|
||||
"diffusion": current_diff,
|
||||
"logs": self.get_logs(self.object_list),
|
||||
"next_diffs": next_diffs,
|
||||
"last_publications": self.get_last_publications(),
|
||||
}
|
||||
)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
@ -72,7 +72,6 @@ class LogListView(AttachedToMixin, BaseView, LogListMixin, ListView):
|
||||
`request.GET`, defaults to today)."""
|
||||
|
||||
redirect_date_url = "log-list"
|
||||
has_filters = True
|
||||
attach_to_value = StaticPage.ATTACH_TO_LOGS
|
||||
|
||||
def get_date(self):
|
||||
|
@ -71,7 +71,7 @@ class ParentMixin:
|
||||
def get_context_data(self, **kwargs):
|
||||
self.parent = kwargs.setdefault("parent", self.parent)
|
||||
if self.parent is not None:
|
||||
kwargs.setdefault("cover", self.parent.cover)
|
||||
kwargs.setdefault("cover", self.parent.cover.url)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
|
@ -22,8 +22,6 @@ class BasePageListView(AttachedToMixin, ParentMixin, BaseView, ListView):
|
||||
"""Base view class for BasePage list."""
|
||||
|
||||
template_name = "aircox/basepage_list.html"
|
||||
item_template_name = "aircox/widgets/page_item.html"
|
||||
has_sidebar = True
|
||||
|
||||
paginate_by = 30
|
||||
has_headline = True
|
||||
@ -41,9 +39,23 @@ class BasePageListView(AttachedToMixin, ParentMixin, BaseView, ListView):
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs.setdefault("item_template_name", self.item_template_name)
|
||||
kwargs.setdefault("has_headline", self.has_headline)
|
||||
return super().get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
parent = context.get("parent")
|
||||
if not context.get("page"):
|
||||
if not context.get("title"):
|
||||
model = self.model._meta.verbose_name_plural
|
||||
if parent:
|
||||
parent = parent.display_title
|
||||
title = _("{model} of {parent}")
|
||||
else:
|
||||
title = _("{model}")
|
||||
context["title"] = title.format(model=model, parent=parent)
|
||||
|
||||
if not context.get("cover") and parent and parent.cover:
|
||||
context["cover"] = parent.cover.url
|
||||
return context
|
||||
|
||||
|
||||
class BasePageDetailView(BaseView, DetailView):
|
||||
@ -51,7 +63,13 @@ class BasePageDetailView(BaseView, DetailView):
|
||||
|
||||
template_name = "aircox/basepage_detail.html"
|
||||
context_object_name = "page"
|
||||
has_filters = False
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
if self.object.cover:
|
||||
kwargs.setdefault("cover", self.object.cover.url)
|
||||
if self.object.title:
|
||||
kwargs.setdefault("title", self.object.display_title)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().select_related("cover")
|
||||
@ -84,7 +102,6 @@ class PageListView(FiltersMixin, BasePageListView):
|
||||
|
||||
filterset_class = PageFilters
|
||||
template_name = None
|
||||
has_filters = True
|
||||
categories = None
|
||||
filters = None
|
||||
|
||||
@ -106,12 +123,17 @@ class PageListView(FiltersMixin, BasePageListView):
|
||||
return qs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs["categories"] = (
|
||||
self.model.objects.published()
|
||||
self.categories = {
|
||||
id: title
|
||||
for title, id in self.model.objects.published()
|
||||
.filter(category__isnull=False)
|
||||
.values_list("category__title", "category__id")
|
||||
.distinct()
|
||||
)
|
||||
}
|
||||
cat_id = self.request.GET.get("category__id")
|
||||
if cat_id:
|
||||
cat_id = int(cat_id)
|
||||
kwargs["category_id"] = cat_id
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
@ -120,7 +142,6 @@ class PageDetailView(BasePageDetailView):
|
||||
|
||||
template_name = None
|
||||
context_object_name = "page"
|
||||
has_filters = False
|
||||
|
||||
def get_template_names(self):
|
||||
return super().get_template_names() + ["aircox/page_detail.html"]
|
||||
@ -134,6 +155,8 @@ class PageDetailView(BasePageDetailView):
|
||||
kwargs["comments"] = Comment.objects.filter(page=self.object).order_by(
|
||||
"-date"
|
||||
)
|
||||
if self.object.parent_subclass:
|
||||
kwargs["parent"] = self.object.parent_subclass
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
@classmethod
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.urls import reverse
|
||||
|
||||
from ..models import Page, Program, StaticPage
|
||||
from ..models import Article, Page, Program, StaticPage, Episode
|
||||
from .mixins import ParentMixin
|
||||
from .page import PageDetailView, PageListView
|
||||
|
||||
@ -25,8 +25,20 @@ class BaseProgramMixin:
|
||||
class ProgramDetailView(BaseProgramMixin, PageDetailView):
|
||||
model = Program
|
||||
|
||||
def get_sidebar_queryset(self):
|
||||
return super().get_sidebar_queryset().filter(parent=self.program)
|
||||
def get_context_data(self, **kwargs):
|
||||
episodes = (
|
||||
Episode.objects.program(self.object)
|
||||
.published()
|
||||
.order_by("-pub_date")
|
||||
)
|
||||
articles = (
|
||||
Article.objects.parent(self.object)
|
||||
.published()
|
||||
.order_by("-pub_date")
|
||||
)
|
||||
return super().get_context_data(
|
||||
articles=articles, episodes=episodes, **kwargs
|
||||
)
|
||||
|
||||
|
||||
class ProgramListView(PageListView):
|
||||
|
@ -10,9 +10,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.0.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"core-js": "^3.8.3",
|
||||
"lodash": "^4.17.21",
|
||||
"vue": "^3.2.13"
|
||||
"v-calendar": "^3.1.2",
|
||||
"vue": "^3.2.13",
|
||||
"vue3-carousel": "^0.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
@ -20,7 +23,7 @@
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"bulma": "^0.9.3",
|
||||
"bulma": "^0.9.4",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-vue": "^8.0.3",
|
||||
"sass": "^1.49.9",
|
||||
|
@ -1,13 +1,51 @@
|
||||
import {Calendar, DatePicker} from 'v-calendar';
|
||||
import components from './components'
|
||||
|
||||
import { Carousel, Pagination, Navigation, Slide } from 'vue3-carousel'
|
||||
|
||||
const App = {
|
||||
el: '#app',
|
||||
delimiters: ['[[', ']]'],
|
||||
components: {...components},
|
||||
components: {
|
||||
...components,
|
||||
Slide,
|
||||
Carousel,
|
||||
Pagination,
|
||||
Navigation,
|
||||
...{
|
||||
VCalendar: Calendar,
|
||||
VDatepicker: DatePicker
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
player() { return window.aircox.player; },
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
carouselBreakpoints: {
|
||||
400: {
|
||||
itemsToShow: 1
|
||||
},
|
||||
600: {
|
||||
itemsToShow: 1.75
|
||||
},
|
||||
800: {
|
||||
itemsToShow: 3
|
||||
},
|
||||
1024: {
|
||||
itemsToShow: 4
|
||||
},
|
||||
1280: {
|
||||
itemsToShow: 4
|
||||
},
|
||||
1380: {
|
||||
itemsToShow: 5
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PlayerApp = {
|
||||
|
@ -15,14 +15,17 @@ export default class Builder {
|
||||
/**
|
||||
* Fetch app from remote and mount application.
|
||||
*/
|
||||
fetch(url, {el='#app', ...options}={}) {
|
||||
return fetch(url, options).then(response => response.text())
|
||||
fetch(url, {el='#app', historySave=true, ...options}={}) {
|
||||
const fut = fetch(url, options).then(response => response.text())
|
||||
.then(content => {
|
||||
let doc = new DOMParser().parseFromString(content, 'text/html')
|
||||
let app = doc.querySelector(el)
|
||||
content = app ? app.innerHTML : content
|
||||
return this.mount({content, title: doc.title, reset:true, url })
|
||||
})
|
||||
if(historySave)
|
||||
fut.then(() => this.historySave(url))
|
||||
return fut
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,7 +64,9 @@ export default class Builder {
|
||||
container.innerHTML = content
|
||||
if(title)
|
||||
document.title = title
|
||||
return createApp(config, props)
|
||||
const app = createApp(config, props)
|
||||
app.config.globalProperties.window = window
|
||||
return app
|
||||
}
|
||||
|
||||
unmount() {
|
||||
@ -106,7 +111,7 @@ export default class Builder {
|
||||
else
|
||||
options = {...options, method: target.method, body: formData}
|
||||
}
|
||||
this.fetch(url, options).then(() => this.historySave(url))
|
||||
this.fetch(url, options)
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
@ -1,13 +1,50 @@
|
||||
@charset "utf-8";
|
||||
|
||||
@import "~bulma/sass/utilities/_all.sass";
|
||||
@import "~bulma/sass/components/dropdown.sass";
|
||||
$font-special: "bagnard";
|
||||
$font-special-url: url("assets/Bagnard.otf");
|
||||
|
||||
$body-background-color: $light;
|
||||
$menu-item-hover-background-color: #dfdfdf;
|
||||
$menu-item-active-background-color: #d2d2d2;
|
||||
$black: #000;
|
||||
$white: #fff;
|
||||
|
||||
$mp-1: 0.2em;
|
||||
$mp-2: 0.4em;
|
||||
$mp-3: 0.8em;
|
||||
$mp-4: 1.2em;
|
||||
$mp-5: 1.6em;
|
||||
$mp-6: 2em;
|
||||
$mp-7: 4em;
|
||||
|
||||
$text-size-small: 0.6em;
|
||||
$text-size-smaller: 0.8em;
|
||||
$text-size: 1em;
|
||||
$text-size-medium: 1.4em;
|
||||
$text-size-bigger: 1.6em;
|
||||
$text-size-big: 2em;
|
||||
|
||||
$h1-size: 40px;
|
||||
$h2-size: 32px;
|
||||
$h3-size: 28px;
|
||||
$h4-size: 24px;
|
||||
$h5-size: 20px;
|
||||
$h6-size: 14px;
|
||||
|
||||
$weight-light: 100;
|
||||
$weight-lighter: 300;
|
||||
$weight-normal: 400;
|
||||
$weight-bolder: 500;
|
||||
$weight-bold: 700;
|
||||
|
||||
$screen-very-small: 400px;
|
||||
//TODO: switch small & smaller
|
||||
$screen-small: 600px;
|
||||
$screen-smaller: 800px;
|
||||
$screen-normal: 1024px;
|
||||
$screen-wider: 1280px;
|
||||
$screen-wide: 1380px;
|
||||
|
||||
|
||||
@import "./vendor";
|
||||
|
||||
@import "~bulma";
|
||||
|
||||
//-- helpers/modifiers
|
||||
.is-fullwidth { width: 100%; }
|
||||
@ -65,10 +102,6 @@ input.half-field:not(:active):not(:hover) {
|
||||
|
||||
|
||||
//-- navbar
|
||||
.navbar + .container {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.navbar.has-shadow, .navbar.is-fixed-bottom.has-shadow {
|
||||
box-shadow: 0em 0em 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
@ -78,6 +111,10 @@ a.navbar-item.is-active {
|
||||
}
|
||||
|
||||
.navbar {
|
||||
& + .container {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.navbar-dropdown {
|
||||
z-index: 2000;
|
||||
}
|
||||
@ -112,93 +149,6 @@ a.navbar-item.is-active {
|
||||
}
|
||||
}
|
||||
|
||||
//-- cards
|
||||
.card {
|
||||
.title {
|
||||
a {
|
||||
color: $dark;
|
||||
}
|
||||
|
||||
padding: 0.2em;
|
||||
font-size: $size-5;
|
||||
font-weight: $weight-medium;
|
||||
}
|
||||
|
||||
&.is-primary {
|
||||
box-shadow: 0em 0em 0.5em $black
|
||||
}
|
||||
}
|
||||
|
||||
.card-super-title {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
font-size: $size-6;
|
||||
font-weight: $weight-bold;
|
||||
padding: 0.2em;
|
||||
top: 1em;
|
||||
background-color: #ffffffc7;
|
||||
max-width: 90%;
|
||||
|
||||
.fas {
|
||||
padding: 0.1em;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-- page
|
||||
.page {
|
||||
& > .cover {
|
||||
float: right;
|
||||
max-width: 45%;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.headline {
|
||||
font-size: 1.4em;
|
||||
padding: 0.2em 0em;
|
||||
}
|
||||
|
||||
p { padding: 0.4em 0em; }
|
||||
hr { background-color: $grey-light; }
|
||||
|
||||
.page-content {
|
||||
h1 { font-size: $size-1; font-weight: bolder; margin-top:0.4em; margin-bottom:0.2em; }
|
||||
h2 { font-size: $size-3; font-weight: bolder; margin-top:0.4em; margin-bottom:0.2em; }
|
||||
h3 { font-size: $size-4; font-weight: bolder; margin-top:0.4em; margin-bottom:0.2em; }
|
||||
h4 { font-size: $size-5; font-weight: bolder; margin-top:0.4em; margin-bottom:0.2em; }
|
||||
h5 { font-size: $size-6; font-weight: bolder; margin-top:0.4em; margin-bottom:0.2em; }
|
||||
h6 { font-size: $size-6; margin-top:0.4em; margin-bottom:0.2em; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.media.item .headline {
|
||||
line-height: 1.2em;
|
||||
max-height: calc(1.2em * 3);
|
||||
overflow: hidden;
|
||||
|
||||
& + .headline-overflow {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 2em;
|
||||
margin-top: -2em;
|
||||
}
|
||||
|
||||
& + .headline-overflow:before {
|
||||
content:'';
|
||||
width:100%;
|
||||
height:100%;
|
||||
position:absolute;
|
||||
left:0;
|
||||
bottom:0;
|
||||
background:linear-gradient(transparent 1em, $body-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-- player
|
||||
.player {
|
||||
@ -267,18 +217,31 @@ a.navbar-item.is-active {
|
||||
|
||||
}
|
||||
|
||||
//-- media
|
||||
.media {
|
||||
.subtitle {
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
.media-content .headline {
|
||||
font-size: 1em;
|
||||
font-weight: 400;
|
||||
}
|
||||
//-- general
|
||||
:root {
|
||||
--text-color: black;
|
||||
--highlight-color: rgba(255, 255, 0, 1);
|
||||
--highlight-color-alpha: rgba(255, 255, 0, 0.6);
|
||||
--highlight-color-2: rgb(0, 0, 254);
|
||||
--highlight-color-2-alpha: rgb(0, 0, 254, 0.6);
|
||||
|
||||
--header-height: 30em;
|
||||
|
||||
--heading-height: 30em;
|
||||
--heading-title-bg-color: rgba(255, 255, 0, 1);
|
||||
--heading-bg-color: var(--highlight-color);
|
||||
--heading-bg-highlight-color: var(--highlight-color-2);
|
||||
|
||||
--preview-media-height: 10em;
|
||||
--preview-media-cover-size: 10em;
|
||||
|
||||
--preview-cover-size: 24em;
|
||||
--preview-cover-small-size: 10em;
|
||||
|
||||
--heading-font-family: default;
|
||||
}
|
||||
|
||||
//-- general
|
||||
|
||||
body {
|
||||
background-color: $body-background-color;
|
||||
}
|
||||
@ -290,12 +253,6 @@ section > .toolbar {
|
||||
}
|
||||
|
||||
|
||||
main {
|
||||
.cover.is-small { width: 10em; }
|
||||
.cover.is-tiny { height: 2em; }
|
||||
}
|
||||
|
||||
|
||||
aside {
|
||||
& > section {
|
||||
margin-bottom: 2em;
|
||||
@ -321,7 +278,445 @@ aside {
|
||||
}
|
||||
|
||||
|
||||
.timetable {
|
||||
width: 100%;
|
||||
border: none;
|
||||
// ---- main theme & layout
|
||||
h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
|
||||
font-family: var(--heading-font-family);
|
||||
}
|
||||
|
||||
.page {
|
||||
padding-bottom: 5em;
|
||||
|
||||
a {
|
||||
background-color: var(--highlight-color-alpha);
|
||||
color: var(--highlight-color-2);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: $text-size-big;
|
||||
}
|
||||
|
||||
section.container {
|
||||
padding-top: $mp-6;
|
||||
|
||||
> .title {
|
||||
margin-top: unset;
|
||||
padding-top: unset !important;
|
||||
margin-bottom: $mp-4;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: $mp-6;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---- helpers
|
||||
.d-inline { display: inline; }
|
||||
.d-block { display: block; }
|
||||
.d-inline-block { display: inline-block; }
|
||||
|
||||
.p-relative { position: relative }
|
||||
.p-absolute { position: absolute }
|
||||
.p-fixed { position: fixed }
|
||||
.p-sticky { position: sticky }
|
||||
.p-static { position: static }
|
||||
|
||||
.align-right { text-align: right; justify-content: right; }
|
||||
|
||||
.height-full { height: 100%; }
|
||||
.flex-push-right { margin-left: auto; }
|
||||
.flex-grow-0 { flex-grow: 0 !important; }
|
||||
|
||||
|
||||
.is-clickable { cursor: pointer; }
|
||||
|
||||
|
||||
// ---- components
|
||||
.btn-hg, .btn-outline-hg {
|
||||
border: 0.1em var(--highlight-color) solid;
|
||||
background-color: var(--highlight-color-alpha) !important;
|
||||
border-radius: 0.2em;
|
||||
}
|
||||
|
||||
.button {
|
||||
&.action {
|
||||
background-color: var(--highlight-color);
|
||||
justify-content: center;
|
||||
padding: $mp-2 !important;
|
||||
min-width: 2em;
|
||||
|
||||
.icon { margin: 0em !important; }
|
||||
|
||||
label {
|
||||
margin-left: $mp-2;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-trigger {
|
||||
border-radius: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.list-filters {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-transform: uppercase;
|
||||
|
||||
&.is-3 {
|
||||
margin-top: $mp-3;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
display: inline-block;
|
||||
|
||||
&:not(:empty) {
|
||||
background-color: var(--heading-bg-color);
|
||||
padding: $mp-2;
|
||||
margin-top: 0em !important;
|
||||
vertical-align: top;
|
||||
|
||||
&.highlight {
|
||||
background-color: var(--heading-bg-highlight-color);
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.title {
|
||||
background-color: var(--heading-title-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
&.no-label label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
font-size: unset !important
|
||||
}
|
||||
|
||||
|
||||
.vc-weekday-1, .vc-weekday-7 {
|
||||
color: var(--highlight-color-2) !important;
|
||||
}
|
||||
|
||||
|
||||
// ---- main navigation
|
||||
.nav {
|
||||
display: flex;
|
||||
background-color: var(--highlight-color);
|
||||
|
||||
.nav-item {
|
||||
padding: $mp-3;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
text-align: center;
|
||||
|
||||
font-family: var(--heading-font-family);
|
||||
text-transform: uppercase;
|
||||
|
||||
&.active {
|
||||
background-color: var(--highlight-color-2);
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.primary {
|
||||
.nav-brand {
|
||||
display: inline-block;
|
||||
margin-right: $mp-3;
|
||||
padding: $mp-3;
|
||||
|
||||
img {
|
||||
width: 14em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: $text-size-medium;
|
||||
font-weight: $weight-bold;
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
justify-content: right;
|
||||
|
||||
.nav-item {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nav li {
|
||||
list-style: none;
|
||||
|
||||
a, .button {
|
||||
font-size: $text-size-medium;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---- ---- detail
|
||||
.page-content {
|
||||
margin-top: $mp-6;
|
||||
margin-bottom: $mp-6;
|
||||
}
|
||||
|
||||
// ---- ---- previews & page items
|
||||
.preview {
|
||||
position: relative;
|
||||
background-size: cover;
|
||||
margin-bottom: $mp-4 !important;
|
||||
|
||||
&.preview-card {
|
||||
&:not(.wide) {
|
||||
max-width: 30em;
|
||||
}
|
||||
}
|
||||
|
||||
&.preview-item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.columns, .headings.columns {
|
||||
margin-left: 0em;
|
||||
margin-right: 0em;
|
||||
.column { padding: 0em; }
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: $weight-bold;
|
||||
font-size: $text-size-bigger;
|
||||
}
|
||||
.subtitle {
|
||||
font-weight: $weight-bolder;
|
||||
font-size: $text-size-bigger;
|
||||
}
|
||||
//.content, .actions {
|
||||
// font-size: $text-size-bigger;
|
||||
//}
|
||||
|
||||
.headings {
|
||||
background-size: cover;
|
||||
|
||||
* { margin: 0em; }
|
||||
.column { padding: 0em; }
|
||||
|
||||
a {
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.preview.comment {
|
||||
.title { font-size: $text-size-bigger; }
|
||||
.subtitle { font-size: $text-size; }
|
||||
}
|
||||
|
||||
|
||||
.list-item {
|
||||
width: 100%;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: calc($mp-4 / 2);
|
||||
}
|
||||
|
||||
.headings {
|
||||
padding-top: 0em;
|
||||
margin-bottom: $mp-4 !important;
|
||||
background-color: var(--heading-bg-color);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.media-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: var(--preview-cover-small-size);
|
||||
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.actions {
|
||||
flex-grow: unset;
|
||||
text-align: right;
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---- cards
|
||||
.preview-wide {
|
||||
height: var(--preview-cover-size);
|
||||
|
||||
&:not(.header) .headings {
|
||||
box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
& .headings {
|
||||
width: var(--preview-cover-size);
|
||||
flex-grow: 0;
|
||||
margin-right: $mp-4;
|
||||
}
|
||||
|
||||
& .content {
|
||||
font-size: $text-size-big;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-card {
|
||||
height: var(--preview-cover-size);
|
||||
min-width: var(--preview-cover-size);
|
||||
|
||||
&:not(.header) {
|
||||
box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.card-grid & {
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.actions {
|
||||
position: absolute;
|
||||
bottom: $mp-3;
|
||||
right: $mp-3;
|
||||
|
||||
label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.preview-cover {
|
||||
background-size: cover;
|
||||
height: var(--preview-cover-size);
|
||||
width: var(--preview-cover-size);
|
||||
|
||||
&.small {
|
||||
min-width: unset;
|
||||
height: var(--preview-cover-small-size);
|
||||
width: var(--preview-cover-small-size) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-card-headings {
|
||||
width: 100%;
|
||||
min-width: var(--preview-cover-size);
|
||||
min-height: 100%;
|
||||
|
||||
padding-top: $mp-3;
|
||||
|
||||
& > div:not(:last-child),
|
||||
& .column > div {
|
||||
margin-bottom: $mp-3;
|
||||
}
|
||||
|
||||
preview-header:not(.no-cover) & .heading {
|
||||
margin-bottom: $mp-3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.preview-header {
|
||||
width: 100%;
|
||||
|
||||
&:not(.no-cover) {
|
||||
min-height: var(--header-height);
|
||||
}
|
||||
|
||||
&.no-cover {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
.headings {
|
||||
padding-top: $mp-6;
|
||||
}
|
||||
|
||||
.headings, > .container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .container, {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.header {
|
||||
background-size: cover;
|
||||
|
||||
.preview-card {
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: $h1-size;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: $h2-size;
|
||||
}
|
||||
.content {
|
||||
display: inline !important;
|
||||
font-size: $text-size-medium;
|
||||
font-weight: $weight-bolder;
|
||||
text-align: right;
|
||||
|
||||
|
||||
p {
|
||||
margin-bottom: $mp-3
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -- program grid
|
||||
|
||||
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: $mp-4;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: $screen-wide) {
|
||||
.preview-card:not(.preview-header) {
|
||||
height: 20em !important;
|
||||
}
|
||||
|
||||
.card-grid .preview-card {
|
||||
height: 20em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $screen-normal) {
|
||||
.card-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
||||
.preview-card:nth-child(3) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
assets/src/assets/vendor.scss
Normal file
31
assets/src/assets/vendor.scss
Normal file
@ -0,0 +1,31 @@
|
||||
@import 'v-calendar/style.css';
|
||||
@import "~bulma/sass/utilities/_all.sass";
|
||||
|
||||
$body-background-color: $light;
|
||||
$menu-item-hover-background-color: #dfdfdf;
|
||||
$menu-item-active-background-color: #d2d2d2;
|
||||
|
||||
@import "~bulma/sass/base/_all";
|
||||
@import "~bulma/sass/components/breadcrumb";
|
||||
@import "~bulma/sass/components/dropdown";
|
||||
@import "~bulma/sass/components/navbar";
|
||||
@import "~bulma/sass/components/media";
|
||||
@import "~bulma/sass/components/message";
|
||||
@import "~bulma/sass/components/modal";
|
||||
@import "~bulma/sass/components/pagination";
|
||||
|
||||
@import "~bulma/sass/form/_all";
|
||||
@import "~bulma/sass/grid/_all";
|
||||
@import "~bulma/sass/helpers/_all";
|
||||
@import "~bulma/sass/layout/_all";
|
||||
@import "~bulma/sass/elements/box";
|
||||
@import "~bulma/sass/elements/button";
|
||||
@import "~bulma/sass/elements/container";
|
||||
@import "~bulma/sass/elements/content";
|
||||
@import "~bulma/sass/elements/icon";
|
||||
// @import "~bulma/sass/elements/image";
|
||||
// @import "~bulma/sass/elements/notification";
|
||||
@import "~bulma/sass/elements/progress";
|
||||
@import "~bulma/sass/elements/table";
|
||||
@import "~bulma/sass/elements/tag";
|
||||
@import "~bulma/sass/elements/title";
|
45
assets/src/components/ADropdown.vue
Normal file
45
assets/src/components/ADropdown.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<component :is="tag" :class="[itemClass, active ? activeClass : '']">
|
||||
<slot name="before-button"></slot>
|
||||
<slot name="button" :toggle="toggle" :active="active">
|
||||
<component :is="buttonTag" :class="buttonClass" @click="toggle()">
|
||||
<span class="icon">
|
||||
<i v-if="!active" :class="buttonIconOpen"></i>
|
||||
<i v-if="active" :class="buttonIconClose"></i>
|
||||
</span>
|
||||
{{ label }}
|
||||
</component>
|
||||
</slot>
|
||||
<div :class="contentClass" v-show="active">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</component>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
active: this.open,
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
tag: {type: String, default: "div"},
|
||||
label: {type: String, default: ""},
|
||||
buttonTag: {type: String, default: "button"},
|
||||
activeClass: {type: String, default: "is-active"},
|
||||
buttonClass: {type: String, default: "button"},
|
||||
buttonIconOpen: { type: String, default:"fa fa-angle-down"},
|
||||
buttonIconClose: { type: String, default:"fa fa-angle-up"},
|
||||
contentClass: String,
|
||||
open: {type: Boolean, default: false},
|
||||
noButton: {type: Boolean, default: false},
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggle() {
|
||||
this.active = !this.active
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,4 +1,5 @@
|
||||
import AAutocomplete from './AAutocomplete.vue'
|
||||
import ADropdown from "./ADropdown.vue"
|
||||
import AEpisode from './AEpisode.vue'
|
||||
import AList from './AList.vue'
|
||||
import APage from './APage.vue'
|
||||
@ -14,7 +15,7 @@ import AStreamer from './AStreamer.vue'
|
||||
* Core components
|
||||
*/
|
||||
export const base = {
|
||||
AAutocomplete, AEpisode, AList, APage, APlayer, APlaylist,
|
||||
AAutocomplete, ADropdown, AEpisode, AList, APage, APlayer, APlaylist,
|
||||
AProgress, ASoundItem,
|
||||
}
|
||||
|
||||
|
@ -68,5 +68,10 @@ window.aircox = {
|
||||
else
|
||||
for(let item of container.querySelectorAll('a.navbar-item'))
|
||||
item.style.display = null;
|
||||
},
|
||||
|
||||
pickDate(url, date) {
|
||||
url = `${url}?date=${date.id}`
|
||||
this.builder.fetch(url)
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +189,7 @@ THUMBNAIL_PROCESSORS = (
|
||||
|
||||
# Enabled applications
|
||||
INSTALLED_APPS = (
|
||||
"radiocampus",
|
||||
"aircox.apps.AircoxConfig",
|
||||
"aircox.apps.AircoxAdminConfig",
|
||||
"aircox_streamer.apps.AircoxStreamerConfig",
|
||||
|
0
radiocampus/__init__.py
Normal file
0
radiocampus/__init__.py
Normal file
6
radiocampus/apps.py
Normal file
6
radiocampus/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class RadiocampusConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "radiocampus"
|
0
radiocampus/migrations/__init__.py
Normal file
0
radiocampus/migrations/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
BIN
radiocampus/static/radiocampus/fonts/CampusGroteskv8-Regular.otf
Normal file
BIN
radiocampus/static/radiocampus/fonts/CampusGroteskv8-Regular.otf
Normal file
Binary file not shown.
16
radiocampus/templates/aircox/base.html
Normal file
16
radiocampus/templates/aircox/base.html
Normal file
@ -0,0 +1,16 @@
|
||||
{% extends "aircox/base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block head_extra %}
|
||||
{{ block.super }}
|
||||
<style>
|
||||
:root {
|
||||
--heading-font-family: "campus_heading";
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'campus_heading';
|
||||
src: url('{% static "radiocampus/fonts/CampusGroteskv12-Regular.otf" %}');
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user