work on home page, fix views & templates issues

This commit is contained in:
bkfox 2019-09-10 17:57:24 +02:00
parent 215a6ac331
commit e30d1b54ef
51 changed files with 658 additions and 276 deletions

View File

@ -19,7 +19,7 @@ __all__ = ['Episode', 'Diffusion', 'DiffusionQuerySet']
class Episode(Page):
objects = ProgramChildQuerySet.as_manager()
detail_url_name = 'episode-detail'
item_template_name = 'aircox/episode_item.html'
item_template_name = 'aircox/widgets/episode_item.html'
@property
def program(self):
@ -75,7 +75,9 @@ class DiffusionQuerySet(BaseRerunQuerySet):
def today(self, today=None, order=True):
""" Diffusions occuring today. """
today = today or datetime.date.today()
qs = self.filter(Q(start__date=today) | Q(end__date=today))
start = tz.datetime.combine(today, datetime.time())
end = tz.datetime.combine(today, datetime.time(23, 59, 59, 999))
qs = self.filter(start__range = (start, end))
return qs.order_by('start') if order else qs
def at(self, date, order=True):
@ -90,9 +92,9 @@ class DiffusionQuerySet(BaseRerunQuerySet):
"""
date = utils.date_or_default(date)
if isinstance(date, tz.datetime):
qs = self.filter(start__gte=date)
qs = self.filter(Q(start__gte=date) | Q(end__gte=date))
else:
qs = self.filter(start__date__gte=date)
qs = self.filter(Q(start__date__gte=date) | Q(end__date__gte=date))
return qs.order_by('start')
def before(self, date=None):
@ -157,7 +159,7 @@ class Diffusion(BaseRerun):
# help_text = _('use this input port'),
# )
item_template_name = 'aircox/diffusion_item.html'
item_template_name = 'aircox/widgets/diffusion_item.html'
class Meta:
verbose_name = _('Diffusion')
@ -181,12 +183,10 @@ class Diffusion(BaseRerun):
# self.check_conflicts()
def save_rerun(self):
print('rerun save', self)
self.episode = self.initial.episode
self.program = self.episode.program
def save_initial(self):
print('initial save', self)
self.program = self.episode.program
if self.episode != self._initial['episode']:
self.rerun_set.update(episode=self.episode, program=self.program)
@ -221,6 +221,13 @@ class Diffusion(BaseRerun):
return tz.localtime(self.end, tz.get_current_timezone())
@property
def is_now(self):
""" True if diffusion is currently running """
now = tz.now()
return self.type == self.TYPE_ON_AIR and \
self.start <= now and self.end >= now
# TODO: property?
def is_live(self):
""" True if Diffusion is live (False if there are sounds files). """

View File

@ -271,21 +271,22 @@ class Log(models.Model):
object_list += logs[:index]
logs = logs[index:]
# - last log while diff is running
if logs[0].date > diff.start:
object_list.append(logs[0])
if len(logs):
# FIXME
# - last log while diff is running
#if logs[0].date > diff.start:
# object_list.append(logs[0])
# - skips logs while diff is running
index = next((i for i, v in enumerate(logs)
if v.date < diff.start), len(logs))
if index is not None and index > 0:
logs = logs[index:]
# - skips logs while diff is running
index = next((i for i, v in enumerate(logs)
if v.date < diff.start), len(logs))
if index is not None and index > 0:
logs = logs[index:]
# - add diff
object_list.append(diff)
return object_list
return object_list if count is None else object_list[:count]
def print(self):
r = []

View File

@ -92,7 +92,7 @@ class Page(models.Model):
objects = PageQuerySet.as_manager()
detail_url_name = None
item_template_name = 'aircox/page_item.html'
item_template_name = 'aircox/widgets/page_item.html'
def __str__(self):
return '{}'.format(self.title or self.pk)

View File

@ -1,6 +1,3 @@
.navbar {
box-shadow: 0em 0em 0.6em rgba(0, 0, 0, 0.4); }
.navbar .navbar-brand {
padding-right: 1em; }
@ -7211,6 +7208,28 @@ a.navbar-item.is-active {
margin: 0em;
padding: 0em; }
.card .title {
padding: 0.2em;
font-size: 1.25rem;
font-weight: 500; }
.card .title a {
color: #363636; }
.card.is-primary {
box-shadow: 0em 0em 0.5em #0a0a0a; }
.card-super-title {
position: absolute;
z-index: 1000;
font-size: 1.2em;
font-weight: 700;
padding: 0.2em;
top: 1em;
background-color: white; }
.card-super-title .fas {
padding: 0.1em;
font-size: 0.8em; }
.filters {
margin: 1em 0em;
background-color: transparent;
@ -7223,16 +7242,6 @@ a.navbar-item.is-active {
color: #7a7a7a;
font-weight: 300; }
/*
.navbar-brand img {
min-height: 6em;
}
.navbar-menu .navbar-item:not(:last-child) {
border-right: 1px $grey solid;
}
*/
/** page **/
.page > .cover {
float: right;
max-width: 45%; }
@ -7247,26 +7256,23 @@ a.navbar-item.is-active {
.page p {
padding: 0.4em 0em; }
section > .toolbar {
background-color: rgba(0, 0, 0, 0.05);
padding: 1em;
margin-bottom: 1.5em; }
main .cover {
margin: 1em 0em;
border: 0.2em black solid; }
main .small-cover {
width: 10em; }
aside .small-cover {
width: 4em; }
aside .media .subtitle {
font-size: 1em; }
aside .media .content {
display: none; }
.media.item .headline {
line-height: 1.2em;
max-height: calc(1.2em * 3);
overflow: hidden; }
.media.item .headline + .headline-overflow {
position: relative;
width: 100%;
height: 2em;
margin-top: -2em; }
.media.item .headline + .headline-overflow:before {
content: '';
width: 100%;
height: 100%;
position: absolute;
left: 0;
bottom: 0;
background: linear-gradient(transparent 1em, whitesmoke); }
.player {
box-shadow: 0em 1.5em 2.5em rgba(0, 0, 0, 0.6); }
@ -7287,3 +7293,37 @@ aside .media .content {
.player .title {
margin: 0em; }
.media .subtitle {
margin-bottom: 0.4em; }
.media .media-content .headline {
font-size: 1em;
font-weight: 400; }
body {
background-color: whitesmoke; }
section > .toolbar {
background-color: rgba(0, 0, 0, 0.05);
padding: 1em;
margin-bottom: 1.5em; }
main .cover {
margin: 1em 0em;
border: 0.2em black solid; }
main .small-cover {
width: 10em; }
aside > section {
margin-bottom: 2em; }
aside .cover {
margin-bottom: 2em; }
aside .small-cover {
width: 4em; }
aside .media .subtitle {
font-size: 1em; }

View File

@ -305,7 +305,7 @@ eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./asse
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nconst splitReg = new RegExp(`,\\s*`, 'g');\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n counts: {},\n }\n },\n\n methods: {\n update() {\n const items = this.$el.querySelectorAll('input[name=\"data\"]:checked')\n const counts = {};\n\n console.log(items)\n for(var item of items)\n if(item.value)\n for(var tag of item.value.split(splitReg))\n counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;\n this.counts = counts;\n }\n },\n\n mounted() {\n this.$refs.form.addEventListener('change', () => this.update())\n this.update()\n }\n});\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib??vue-loader-options");
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nconst splitReg = new RegExp(`,\\s*`, 'g');\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n counts: {},\n }\n },\n\n methods: {\n update() {\n const items = this.$el.querySelectorAll('input[name=\"data\"]:checked')\n const counts = {};\n\n console.log(items)\n for(var item of items)\n if(item.value)\n for(var tag of item.value.split(splitReg))\n counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;\n this.counts = counts;\n },\n\n onclick(event) {\n // TODO: row click => check checkbox\n }\n },\n\n mounted() {\n this.$refs.form.addEventListener('change', () => this.update())\n this.update()\n }\n});\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
@ -317,7 +317,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nc
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n paused: 0,\n playing: 1,\n loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n state: State.paused,\n liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n }\n },\n\n props: {\n buttonTitle: String,\n liveInfoUrl: String,\n liveInfoTimeout: { type: Number, default: 5},\n src: String,\n },\n\n computed: {\n paused() { return this.state == State.paused; },\n playing() { return this.state == State.playing; },\n loading() { return this.state == State.loading; },\n\n onAir() {\n return this.liveInfo.items && this.liveInfo.items[0];\n },\n\n buttonStyle() {\n if(!this.onAir)\n return;\n return { backgroundImage: `url(${this.onAir.cover})` }\n }\n },\n\n methods: {\n load(src) {\n const audio = this.$refs.audio;\n audio.src = src;\n audio.load()\n },\n\n play(src) {\n if(src)\n this.load(src);\n this.$refs.audio.play().catch(e => console.error(e))\n },\n\n pause() {\n this.$refs.audio.pause()\n },\n\n toggle() {\n if(this.paused)\n this.play()\n else\n this.pause()\n },\n\n onChange(event) {\n const audio = this.$refs.audio;\n this.state = audio.paused ? State.paused : State.playing;\n },\n },\n\n mounted() {\n this.liveInfo.refresh()\n },\n\n destroyed() {\n this.liveInfo.drop()\n },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n paused: 0,\n playing: 1,\n loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n state: State.paused,\n liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n }\n },\n\n props: {\n buttonTitle: String,\n liveInfoUrl: String,\n liveInfoTimeout: { type: Number, default: 5},\n src: String,\n },\n\n computed: {\n paused() { return this.state == State.paused; },\n playing() { return this.state == State.playing; },\n loading() { return this.state == State.loading; },\n\n onAir() {\n return this.liveInfo.items && this.liveInfo.items[0];\n },\n\n buttonStyle() {\n if(!this.onAir)\n return;\n return { backgroundImage: `url(${this.onAir.cover})` }\n }\n },\n\n methods: {\n load(src) {\n const audio = this.$refs.audio;\n audio.src = src;\n audio.load()\n },\n\n play(src) {\n if(src)\n this.load(src);\n this.$refs.audio.play().catch(e => console.error(e))\n },\n\n pause() {\n this.$refs.audio.pause()\n },\n\n toggle() {\n console.log('tooogle', this.paused, '-', this.$refs.audio.src)\n if(this.paused)\n this.play()\n else\n this.pause()\n },\n\n onChange(event) {\n const audio = this.$refs.audio;\n this.state = audio.paused ? State.paused : State.playing;\n },\n },\n\n mounted() {\n this.liveInfo.refresh()\n },\n\n destroyed() {\n this.liveInfo.drop()\n },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),

View File

@ -7190,6 +7190,28 @@ a.navbar-item.is-active {
margin: 0em;
padding: 0em; }
.card .title {
padding: 0.2em;
font-size: 1.25rem;
font-weight: 500; }
.card .title a {
color: #363636; }
.card.is-primary {
box-shadow: 0em 0em 0.5em #0a0a0a; }
.card-super-title {
position: absolute;
z-index: 1000;
font-size: 1.2em;
font-weight: 700;
padding: 0.2em;
top: 1em;
background-color: white; }
.card-super-title .fas {
padding: 0.1em;
font-size: 0.8em; }
.filters {
margin: 1em 0em;
background-color: transparent;
@ -7202,16 +7224,6 @@ a.navbar-item.is-active {
color: #7a7a7a;
font-weight: 300; }
/*
.navbar-brand img {
min-height: 6em;
}
.navbar-menu .navbar-item:not(:last-child) {
border-right: 1px $grey solid;
}
*/
/** page **/
.page > .cover {
float: right;
max-width: 45%; }
@ -7226,26 +7238,23 @@ a.navbar-item.is-active {
.page p {
padding: 0.4em 0em; }
section > .toolbar {
background-color: rgba(0, 0, 0, 0.05);
padding: 1em;
margin-bottom: 1.5em; }
main .cover {
margin: 1em 0em;
border: 0.2em black solid; }
main .small-cover {
width: 10em; }
aside .small-cover {
width: 4em; }
aside .media .subtitle {
font-size: 1em; }
aside .media .content {
display: none; }
.media.item .headline {
line-height: 1.2em;
max-height: calc(1.2em * 3);
overflow: hidden; }
.media.item .headline + .headline-overflow {
position: relative;
width: 100%;
height: 2em;
margin-top: -2em; }
.media.item .headline + .headline-overflow:before {
content: '';
width: 100%;
height: 100%;
position: absolute;
left: 0;
bottom: 0;
background: linear-gradient(transparent 1em, whitesmoke); }
.player {
box-shadow: 0em 1.5em 2.5em rgba(0, 0, 0, 0.6); }
@ -7266,3 +7275,37 @@ aside .media .content {
.player .title {
margin: 0em; }
.media .subtitle {
margin-bottom: 0.4em; }
.media .media-content .headline {
font-size: 1em;
font-weight: 400; }
body {
background-color: whitesmoke; }
section > .toolbar {
background-color: rgba(0, 0, 0, 0.05);
padding: 1em;
margin-bottom: 1.5em; }
main .cover {
margin: 1em 0em;
border: 0.2em black solid; }
main .small-cover {
width: 10em; }
aside > section {
margin-bottom: 2em; }
aside .cover {
margin-bottom: 2em; }
aside .small-cover {
width: 4em; }
aside .media .subtitle {
font-size: 1em; }

View File

@ -246,7 +246,7 @@ eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./asse
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n paused: 0,\n playing: 1,\n loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n state: State.paused,\n liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n }\n },\n\n props: {\n buttonTitle: String,\n liveInfoUrl: String,\n liveInfoTimeout: { type: Number, default: 5},\n src: String,\n },\n\n computed: {\n paused() { return this.state == State.paused; },\n playing() { return this.state == State.playing; },\n loading() { return this.state == State.loading; },\n\n onAir() {\n return this.liveInfo.items && this.liveInfo.items[0];\n },\n\n buttonStyle() {\n if(!this.onAir)\n return;\n return { backgroundImage: `url(${this.onAir.cover})` }\n }\n },\n\n methods: {\n load(src) {\n const audio = this.$refs.audio;\n audio.src = src;\n audio.load()\n },\n\n play(src) {\n if(src)\n this.load(src);\n this.$refs.audio.play().catch(e => console.error(e))\n },\n\n pause() {\n this.$refs.audio.pause()\n },\n\n toggle() {\n if(this.paused)\n this.play()\n else\n this.pause()\n },\n\n onChange(event) {\n const audio = this.$refs.audio;\n this.state = audio.paused ? State.paused : State.playing;\n },\n },\n\n mounted() {\n this.liveInfo.refresh()\n },\n\n destroyed() {\n this.liveInfo.drop()\n },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n paused: 0,\n playing: 1,\n loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n data() {\n return {\n state: State.paused,\n liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n }\n },\n\n props: {\n buttonTitle: String,\n liveInfoUrl: String,\n liveInfoTimeout: { type: Number, default: 5},\n src: String,\n },\n\n computed: {\n paused() { return this.state == State.paused; },\n playing() { return this.state == State.playing; },\n loading() { return this.state == State.loading; },\n\n onAir() {\n return this.liveInfo.items && this.liveInfo.items[0];\n },\n\n buttonStyle() {\n if(!this.onAir)\n return;\n return { backgroundImage: `url(${this.onAir.cover})` }\n }\n },\n\n methods: {\n load(src) {\n const audio = this.$refs.audio;\n audio.src = src;\n audio.load()\n },\n\n play(src) {\n if(src)\n this.load(src);\n this.$refs.audio.play().catch(e => console.error(e))\n },\n\n pause() {\n this.$refs.audio.pause()\n },\n\n toggle() {\n console.log('tooogle', this.paused, '-', this.$refs.audio.src)\n if(this.paused)\n this.play()\n else\n this.pause()\n },\n\n onChange(event) {\n const audio = this.$refs.audio;\n this.state = audio.paused ? State.paused : State.playing;\n },\n },\n\n mounted() {\n this.liveInfo.refresh()\n },\n\n destroyed() {\n this.liveInfo.drop()\n },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),

View File

@ -3,8 +3,14 @@
{% block content %}{{ block.super }}
<div id="app">
{# TODO: date subtitle #}
<div class="columns">
<nav class="navbar" role="menu">
{% with "admin:tools-stats" as url_name %}
{% include "aircox/widgets/dates_menu.html" %}
{% endwith %}
</nav>
<a-statistics class="column">
<template v-slot:default="{counts}">
@ -23,13 +29,12 @@
{% for track in tracks %}
<tr>
{% if forloop.first %}
<td rowspan="{{ tracks|length }}">{{ object.start|time:"H:i" }}</td>
<td rowspan="{{ tracks|length }}">{{ object.start|time:"H:i" }} {% if object|is_diffusion %} - {{ object.end|time:"H:i" }}{% endif %}</td>
<td rowspan="{{ tracks|length }}">{{ object.episode|default:"" }}</td>
{% endif %}
{% if not object|is_diffusion %}
{% with track as object %}
<td>{% include "aircox/track_item.html" %}</td>
<td>{% include "aircox/widgets/track_item.html" %}</td>
{% endwith %}
{% with track.tags.all|join:', ' as tags %}
<td>
@ -41,10 +46,17 @@
{% endif %}
</td>
{% endwith %}
{% else %}
</tr>
{% empty %}
{% if object|is_diffusion %}
<tr>
<td>{{ object.start|time:"H:i" }} - {{ object.end|time:"H:i" }}</td>
<td>{{ object.episode|default:"" }}</td>
<td></td>
<td></td>
</tr>
{% endif %}
{% endfor %}
<tr>
{% endwith %}
{% endfor %}
</tbody>
@ -65,14 +77,6 @@
</template>
</a-statistics>
<nav class="column menu is-one-fifth-desktop" role="menu">
{% with "admin:tools-stats" as url_name %}
{% include "aircox/widgets/dates_menu.html" %}
{% endwith %}
</nav>
</div>
{% endblock %}

View File

@ -29,11 +29,10 @@
data-admin-utc-offset="{% now "Z" %}">
<!-- Container -->
<div id="app">
<div>
{% if not is_popup %}
<!-- Header -->
<nav class="navbar is-dark">
<nav class="navbar is-dark has-shadow">
<div class="navbar-brand">
{% block branding %}{% endblock %}
</div>

View File

@ -37,7 +37,7 @@
{% block coltype %}flex{% endblock %}
{% block content %}
<div id="content-main">
<div id="content-main">
{% block object-tools %}
<ul class="object-tools">
{% block object-tools-items %}
@ -74,16 +74,16 @@
{% block date_hierarchy %}{% if cl.date_hierarchy %}{% date_hierarchy cl %}{% endif %}{% endblock %}
{% block filters %}
{% if cl.has_filters %}
<div id="changelist-filter">
<h2>{% trans 'Filter' %}</h2>
{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
</div>
{% endif %}
{% if cl.has_filters %}
<div id="changelist-filter">
<h2>{% trans 'Filter' %}</h2>
{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
</div>
{% endif %}
{% endblock %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -4,12 +4,12 @@
{% block sidebar %}
{{ block.super }}
{% if sidebar_items %}
{% if sidebar_object_list %}
<section>
<h4 class="title is-4">{% trans "Latest news" %}</h4>
{% for object in sidebar_items %}
{% include "aircox/page_item.html" %}
{% for object in sidebar_object_list %}
{% include "aircox/widgets/page_item.html" %}
{% endfor %}
<br>

View File

@ -1,10 +1,29 @@
{% load static i18n thumbnail aircox %}
{% comment %}
Context:
- cover: image cover
- site: current website
- has_filters: display filter bar (using block "filters")
- sidebar_object_list: item to display in sidebar
- sidebar_url_name: url name sidebar item complete list
- sidebar_url_parent: parent page for sidebar items complete list
Blocks:
- assets
- head_title
- head_extra
- top_nav
- header:
- title
- subtitle
- header_meta
- main:
- filters
- cover
- sidebar:
- sidebar_title
{% endcomment %}
{% load static i18n thumbnail aircox %}
<html>
<head>
<meta charset="utf-8" />
@ -72,14 +91,14 @@ Context:
{% endblock %}
</header>
{% if has_filters %}
<nav class="navbar filters"
aria-label="{% trans "list filters" %}">
{% block filters %}{% endblock %}
</nav>
{% endif %}
{% block main %}{% endblock main %}
{% block main %}
{% if has_filters %}
<nav class="navbar filters"
aria-label="{% trans "list filters" %}">
{% block filters %}{% endblock %}
</nav>
{% endif %}
{% endblock main %}
</main>
{% if has_sidebar %}
@ -92,28 +111,18 @@ Context:
{% endblock %}
{% block sidebar %}
{% if sidebar_items %}
{% 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 %}{% trans "Recently" %}{% endblock %}
</h4>
{% for object in sidebar_items %}
{% include "aircox/episode_item.html" %}
{% endfor %}
<br>
<nav class="pagination is-centered">
<ul class="pagination-list">
<li>
<a {% if parent %}href="{% url "page-list" parent_slug=parent.slug %}"{% else %}href="{% url "page-list" %}"{% endif %}
class="pagination-link"
aria-label="{% trans "Show all program's diffusions" %}">
{% trans "Show more" %}
</a>
</li>
</ul>
</nav>
{% include "aircox/widgets/page_list.html" %}
{% endwith %}
{% endwith %}
{% endwith %}
{% endif %}
</section>
{% endblock %}

View File

@ -16,7 +16,7 @@
{% endblock %}
{% block main %}{{ block.super }}
{% with True as hide_schedule %}
{% with hide_schedule=True %}
<section role="list">
<div id="timetable-{{ date|date:"Y-m-d" }}">
{% for diffusion in object_list %}
@ -24,12 +24,12 @@
<div class="columns {% if diffusion.start.date != date and diffusion.start.end <= date %}is-opacity-light{% endif %}">
<div class="column is-one-fifth has-text-right">
<time datetime="{{ diffusion.start|date:"c" }}">
{{ diffusion.start|date:"d H:i" }} - {{ diffusion.end|date:"d H:i" }}
{{ diffusion.start|date:"H:i" }} - {{ diffusion.end|date:"H:i" }}
</time>
</div>
<div class="column">
{% with diffusion.episode as object %}
{% include "aircox/episode_item.html" %}
{% include "aircox/widgets/episode_item.html" %}
{% endwith %}
</div>
</div>

View File

@ -50,7 +50,7 @@
<section class="column">
<h4 class="title is-4">{% trans "Podcasts" %}</h4>
{% for object in podcasts %}
{% include "aircox/podcast_item.html" %}
{% include "aircox/widgets/podcast_item.html" %}
{% endfor %}
</section>
{% endif %}

View File

@ -0,0 +1,83 @@
{% extends "aircox/page_list.html" %}
{% comment %}
Context:
-
-
TODO:
- sidebar:
- logs
- diffusions
- main:
- focused
- nav to 'publications' view
-
{% endcomment %}
{% load i18n %}
{% block head_title %}{% block title %}{{ station.name }}{% endblock %}{% endblock %}
{% block main %}
<div class="columns">
{% with render_card=True %}
{% for object in top_diffs %}
{% with is_primary=object.is_now %}
<div class="column is-relative">
<h4 class="card-super-title">
{% if is_primary %}
<span class="fas fa-play"></span>
{% trans "Currently" %}
{% else %}{{ object.start|date:"H:i" }}{% endif %}
</h4>
{% include object.item_template_name %}
</div>
{% endwith %}
{% endfor %}
{% endwith %}
</div>
<hr>
<h4 class="title is-4">{% trans "Last publications" %}</h4>
{{ block.super }}
{% endblock %}
{% block pagination %}
<ul class="pagination-list">
<li>
<a href="{% url "page-list" %}" class="pagination-link"
aria-label="{% trans "Show all publication" %}">
{% trans "More publications..." %}
</a>
</li>
</ul>
{% endblock %}
{% block sidebar %}
<section>
<h4 class="title is-4">{% trans "Previously on air" %}</h4>
{% with logs as object_list %}
{% include "aircox/widgets/log_list.html" %}
{% endwith %}
</section>
<section>
<h4 class="title is-4">{% trans "Today" %}</h4>
{% with hide_schedule=True %}
{% with has_headline=False %}
<table class="table is-fullwidth has-background-transparent">
{% for object in sidebar_object_list %}
<tr>
<td>{{ object.start|date:"H:i" }}</td>
<td>{% include "aircox/widgets/diffusion_item.html" %}</td>
</tr>
{% endfor %}
</table>
{% endwith %}
{% endwith %}
</section>
{% endblock %}

View File

@ -16,29 +16,10 @@
{% endwith %}
{% endblock %}
{% block main %}
{% block main %}{{ block.super }}
<section>
{# <h4 class="subtitle size-4">{{ date }}</h4> #}
{% with True as hide_schedule %}
<table class="table is-striped is-hoverable is-fullwidth">
{% for object in object_list %}
<tr>
<td>
{% if object|is_diffusion %}
<time datetime="{{ object.start }}" title="{{ object.start }}">
{{ object.start|date:"H:i" }} - {{ object.end|date:"H:i" }}
</time>
{% else %}
<time datetime="{{ object.date }}" title="{{ object.date }}">
{{ object.date|date:"H:i" }}
</time>
{% endif %}
</td>
<td>{% include "aircox/log_item.html" %}</td>
</tr>
{% endfor %}
</table>
{% endwith %}
{% include "aircox/widgets/log_list.html" %}
</section>
{% endblock %}

View File

@ -56,21 +56,23 @@
{% endblock %}
{% block main %}
{% block main %}{{ block.super }}
<section role="list">
{% with has_headline=True %}
{% for object in object_list %}
{% block list_object %}
{% include object.item_template_name|default:item_template_name %}
{% endblock %}
{% endfor %}
{% endwith %}
</section>
{% if is_paginated %}
<hr>
{% update_query request.GET.copy page=None as GET %}
{% with GET.urlencode as GET %}
<nav class="pagination is-centered" role="pagination" aria-label="{% trans "pagination" %}">
{% block pagination %}
{% if page_obj.has_previous %}
<a href="?{{ GET }}&page={{ page_obj.previous_page_number }}" class="pagination-previous">
{% else %}
@ -93,6 +95,7 @@
</li>
{% endfor %}
</ul>
{% endblock %}
</nav>
{% endwith %}
{% endif %}

View File

@ -3,13 +3,7 @@
{% block sidebar_title %}
{% with program.title as program %}
{% blocktrans %} Recently on {{ program }}{% endblocktrans %}
{% endwith %}
{% endblock %}
{% block sidebar %}
{% with program as parent %}
{{ block.super }}
{% blocktrans %}Recently on {{ program }}{% endblocktrans %}
{% endwith %}
{% endblock %}

View File

@ -10,15 +10,14 @@
{% block content %}{{ block.super }}
<br>
{% with show_headline=False %}
{% with has_headline=False %}
<div class="columns is-desktop">
{% if articles %}
<section class="column">
<h4 class="title is-4">{% trans "Articles" %}</h4>
{% for object in articles %}
{% include "aircox/page_item.html" %}
{% include "aircox/widgets/page_item.html" %}
{% endfor %}
<br>

View File

@ -5,7 +5,7 @@ Context:
{% endcomment %}
{% with object as diffusion %}
{% with object.episode as object %}
{% include "aircox/episode_item.html" %}
{% include "aircox/widgets/episode_item.html" %}
{% endwith %}
{% endwith %}

View File

@ -1,4 +1,4 @@
{% extends "aircox/page_item.html" %}
{% extends "aircox/widgets/page_item.html" %}
{% load i18n easy_thumbnails_tags aircox %}
{% comment %}

View File

@ -11,11 +11,11 @@ for design review.
{% if object|is_diffusion %}
{% with object as diffusion %}
{% include "aircox/diffusion_item.html" %}
{% include "aircox/widgets/diffusion_item.html" %}
{% endwith %}
{% else %}
{% with object.track as object %}
{% include "aircox/track_item.html" %}
{% include "aircox/widgets/track_item.html" %}
{% endwith %}
{% endif %}

View File

@ -0,0 +1,29 @@
{% comment %}
Render list of logs (as widget).
Context:
- object_list: list of logs to display
{% 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>
<td>
{% if object|is_diffusion %}
<time datetime="{{ object.start }}" title="{{ object.start }}">
{{ object.start|date:"H:i" }} - {{ object.end|date:"H:i" }}
</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 %}

View File

@ -1,15 +1,36 @@
{% load i18n easy_thumbnails_tags aircox %}
{% comment %}
Context variables:
- object: the actual diffusion
- show_headline: if True, display headline
- object: the object to render
- render_card: render as card
- is-primary: render as primary
- has_headline (=False): if True, display headline
- has_cover (=True): hide page cover
{% endcomment %}
<article class="media">
{% if render_card %}
<article class="card {% if is_primary %}is-primary{% endif %}">
<header class="card-image">
<figure class="image is-4by3">
<img src="{% thumbnail object.cover 480x480 %}">
</figure>
</header>
<div class="card-header">
<h4 class="title">
<a href="{{ object.get_absolute_url }}">{{ object.title }}</a>
</h4>
</div>
</article>
{% else %}
<article class="media item {% if is_primary %}is-primary{% endif %}">
{% if has_cover|default_if_none:True %}
<div class="media-left">
<img src="{% thumbnail object.cover 128x128 crop=scale %}"
class="small-cover">
</div>
{% endif %}
<div class="media-content">
<h5 class="title is-5 has-text-weight-normal">
{% block title %}
@ -26,8 +47,8 @@ Context variables:
{% endblock %}
</div>
{% if show_headline %}
<div class="">
{% if has_headline|default_if_none:True %}
<div class="headline">
{% block headline %}
{{ object.headline|safe }}
{% endblock %}
@ -35,4 +56,5 @@ Context variables:
{% endif %}
</div>
</article>
{% endif %}

View File

@ -0,0 +1,28 @@
{% comment %}
Display list of items as small list
Context:
- object_list: object list
- list_url: url to complete list page
{% endcomment %}
{% load i18n %}
{% for object in object_list %}
{% include object.item_template_name %}
{% endfor %}
{% if list_url %}
<br>
<nav class="pagination is-centered">
<ul class="pagination-list">
<li>
<a href="{{ list_url }}" class="pagination-link"
aria-label="{% trans "Show all publications" %}">
{% trans "Show more" %}
</a>
</li>
</ul>
</nav>
{% endif %}

View File

@ -24,8 +24,7 @@ api = [
urls = [
path(_(''),
views.DiffusionListView.as_view(), name='home'),
path('', views.HomeView.as_view(), name='home'),
path('api/', include(api)),
# path('', views.PageDetailView.as_view(model=models.Article),
@ -51,9 +50,9 @@ urls = [
# path('<page_path:path>', views.route_page, name='page'),
path(_('publications/'),
views.ProgramPageListView.as_view(), name='page-list'),
views.PageListView.as_view(model=models.Page), name='page-list'),
path(_('programs/'), views.PageListView.as_view(model=models.Program),
path(_('programs/'), views.ProgramListView.as_view(model=models.Program),
name='program-list'),
path(_('programs/<slug:slug>/'),
views.ProgramDetailView.as_view(), name='program-detail'),
@ -62,7 +61,7 @@ urls = [
path(_('programs/<slug:parent_slug>/articles/'),
views.ArticleListView.as_view(), name='article-list'),
path(_('programs/<slug:parent_slug>/publications/'),
views.ProgramPageListView.as_view(), name='page-list'),
views.ProgramPageListView.as_view(), name='program-page-list'),
]

View File

@ -1,9 +1,12 @@
from . import api, admin
from .article import ArticleDetailView, ArticleListView
from .base import BaseView
from .home import HomeView
from .article import ArticleDetailView, ArticleListView
from .episode import EpisodeDetailView, EpisodeListView, DiffusionListView
from .log import LogListView
from .page import PageDetailView, PageListView
from .program import ProgramDetailView, ProgramPageListView
from .program import ProgramDetailView, ProgramListView, \
ProgramPageDetailView, ProgramPageListView

View File

@ -44,8 +44,7 @@ class AdminSite(admin.AdminSite):
def get_urls(self):
from django.urls import path, include
urls = super().get_urls()
urls += [
urls = super().get_urls() + [
path('tools/statistics/',
self.admin_view(StatisticsView.as_view()),
name='tools-stats'),

View File

@ -4,7 +4,6 @@ from django.utils import timezone as tz
from rest_framework.generics import ListAPIView
from ..utils import str_to_date
from ..models import Log
from ..serializers import LogInfo, LogInfoSerializer
from .log import LogListMixin

View File

@ -25,7 +25,7 @@ class ArticleDetailView(PageDetailView):
class ArticleListView(ParentMixin, PageListView):
model = Article
template_name = 'aircox/article_list.html'
show_headline = True
has_headline = True
is_static = False
parent_model = Program

View File

@ -2,6 +2,7 @@
from django.http import Http404
from django.views.generic import DetailView, ListView
from django.views.generic.base import TemplateResponseMixin, ContextMixin
from django.urls import reverse
from ..models import Page
from ..utils import Redirect
@ -35,21 +36,25 @@ class BaseView(TemplateResponseMixin, ContextMixin):
return Page.objects.select_subclasses().published() \
.order_by('-pub_date')
def get_context_data(self, sidebar_items=None, **kwargs):
def get_sidebar_url(self):
return reverse('page-list')
def get_context_data(self, **kwargs):
kwargs.setdefault('station', self.station)
kwargs.setdefault('cover', self.cover)
kwargs.setdefault('has_filters', self.has_filters)
has_sidebar = kwargs.setdefault('has_sidebar', self.has_sidebar)
if has_sidebar and sidebar_items is None:
sidebar_items = self.get_sidebar_queryset()
sidebar_items = None if sidebar_items is None else \
sidebar_items[:self.list_count]
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()
if not 'audio_streams' in kwargs:
streams = self.station.audio_streams
streams = streams and streams.split('\n')
kwargs['audio_streams'] = streams
return super().get_context_data(sidebar_items=sidebar_items, **kwargs)
return super().get_context_data(**kwargs)

View File

@ -21,9 +21,6 @@ class EpisodeDetailView(ProgramPageDetailView):
return Sound.objects.diffusion(diffusion).podcasts()
def get_context_data(self, **kwargs):
self.program = kwargs.setdefault('program', self.object.program)
kwargs.setdefault('parent', self.program)
if not 'tracks' in kwargs:
kwargs['tracks'] = self.object.track_set.order_by('position')
if not 'podcasts' in kwargs:
@ -33,8 +30,8 @@ class EpisodeDetailView(ProgramPageDetailView):
class EpisodeListView(ParentMixin, PageListView):
model = Episode
item_template_name = 'aircox/episode_item.html'
show_headline = True
item_template_name = 'aircox/widgets/episode_item.html'
has_headline = True
parent_model = Program

44
aircox/views/home.py Normal file
View File

@ -0,0 +1,44 @@
import datetime
from django.utils.translation import ugettext as _
from django.utils import timezone as tz
from ..models import Diffusion, Log, Page
from .page import PageListView
class HomeView(PageListView):
template_name = 'aircox/home.html'
model = Page
queryset = Page.objects.select_subclasses()
paginate_by = 10
list_count = 40
logs_count = 5
has_filters = False
def get_logs(self):
today = datetime.date.today()
logs = Log.objects.on_air().today(today).filter(track__isnull=False)
diffs = Diffusion.objects.on_air().today(today)
return Log.merge_diffusions(logs, diffs, self.logs_count)
def get_sidebar_queryset(self):
today = datetime.date.today()
return Diffusion.objects.on_air().today(today)
def get_top_diffs(self):
now = tz.now()
current_diff = Diffusion.objects.on_air().now(now).first()
next_diffs = Diffusion.objects.on_air().after(now)
if current_diff:
diffs = [current_diff] + list(next_diffs.exclude(pk=current_diff.pk)[:2])
else:
diffs = next_diffs[:3]
return diffs
def get_context_data(self, **kwargs):
kwargs['logs'] = self.get_logs()
kwargs['top_diffs'] = self.get_top_diffs()
return super().get_context_data(**kwargs)

View File

@ -2,6 +2,7 @@ from collections import deque
import datetime
from django.views.generic import ListView
from django.utils import timezone as tz
from ..models import Diffusion, Log
from .base import BaseView
@ -23,12 +24,14 @@ class LogListMixin(GetDateMixin):
def get_queryset(self):
# only get logs for tracks: log for diffusion will be retrieved
# by the diffusions' queryset.
qs = super().get_queryset().on_air().filter(track__isnull=False)
qs = super().get_queryset().on_air().filter(track__isnull=False) \
.filter(date__lte=tz.now())
return qs.today(self.date) if self.date is not None else \
qs.after(self.min_date) if self.min_date is not None else qs
def get_diffusions_queryset(self):
qs = Diffusion.objects.station(self.station).on_air()
qs = Diffusion.objects.station(self.station).on_air() \
.filter(start__lte=tz.now())
return qs.today(self.date) if self.date is not None else \
qs.after(self.min_date) if self.min_date is not None else qs

View File

@ -63,9 +63,9 @@ class ParentMixin:
return super().get_queryset()
def get_context_data(self, **kwargs):
parent = kwargs.setdefault('parent', self.parent)
if parent is not None:
kwargs.setdefault('cover', parent.cover)
self.parent = kwargs.setdefault('parent', self.parent)
if self.parent is not None:
kwargs.setdefault('cover', self.parent.cover)
return super().get_context_data(**kwargs)

View File

@ -6,7 +6,7 @@ from django.views.generic import DetailView, ListView
from honeypot.decorators import check_honeypot
from ..forms import CommentForm
from ..models import Category, Comment
from ..models import Category, Comment, Page
from ..utils import Redirect
from .base import BaseView
@ -17,12 +17,12 @@ __all__ = ['PageDetailView', 'PageListView']
# TODO: pagination: in template, only a limited number of pages displayed
class PageListView(BaseView, ListView):
template_name = 'aircox/page_list.html'
item_template_name = 'aircox/page_item.html'
item_template_name = 'aircox/widgets/page_item.html'
has_sidebar = True
has_filters = True
paginate_by = 20
show_headline = True
has_headline = True
categories = None
def get(self, *args, **kwargs):
@ -30,7 +30,7 @@ class PageListView(BaseView, ListView):
return super().get(*args, **kwargs)
def get_queryset(self):
qs = super().get_queryset().published() \
qs = super().get_queryset().select_subclasses().published() \
.select_related('cover', 'category')
# category can be filtered based on request.GET['categories']
@ -50,7 +50,7 @@ class PageListView(BaseView, ListView):
kwargs.setdefault('item_template_name', self.item_template_name)
kwargs.setdefault('filter_categories', self.get_categories_queryset())
kwargs.setdefault('categories', self.categories)
kwargs.setdefault('show_headline', self.show_headline)
kwargs.setdefault('has_headline', self.has_headline)
return super().get_context_data(**kwargs)

View File

@ -1,6 +1,7 @@
from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import get_object_or_404
from django.urls import reverse
from ..models import Episode, Program, Page
from .mixins import ParentMixin
@ -10,30 +11,54 @@ from .page import PageDetailView, PageListView
__all__ = ['ProgramPageDetailView', 'ProgramDetailView', 'ProgramPageListView']
class ProgramPageDetailView(PageDetailView):
class BaseProgramMixin:
def get_program(self):
return self.object
def get_sidebar_url(self):
return reverse('program-page-list',
kwargs={"parent_slug": self.program.slug})
def get_context_data(self, **kwargs):
self.program = self.get_program()
kwargs['program'] = self.program
return super().get_context_data(**kwargs)
class ProgramDetailView(BaseProgramMixin, PageDetailView):
model = Program
def get_sidebar_queryset(self):
return super().get_sidebar_queryset().filter(parent=self.program)
class ProgramListView(PageListView):
model = Program
class ProgramPageDetailView(BaseProgramMixin, ParentMixin, PageDetailView):
"""
Base view class for a page that is displayed as a program's child page.
"""
program = None
has_sidebar = True
list_count = 5
parent_model = Program
def get_program(self):
self.parent = self.object.program
return self.object.program
def get_sidebar_queryset(self):
return super().get_sidebar_queryset().filter(parent=self.object)
return super().get_sidebar_queryset().filter(parent=self.program)
class ProgramPageListView(ParentMixin, PageListView):
class ProgramPageListView(BaseProgramMixin, ParentMixin, PageListView):
model = Page
parent_model = Program
queryset = Page.objects.select_subclasses()
class ProgramDetailView(ProgramPageDetailView):
model = Program
def get_program(self):
return self.parent
def get_context_data(self, **kwargs):
self.program = kwargs.setdefault('program', self.object)
kwargs.setdefault('sidebar_url_parent', None)
return super().get_context_data(**kwargs)

View File

@ -1,10 +1,4 @@
// @import './bulmacolors';
.navbar {
box-shadow: 0em 0em 0.6em rgba(0, 0, 0, 0.4);
}
.navbar .navbar-brand {
padding-right: 1em;
}

View File

@ -26,6 +26,10 @@ export default {
for(var tag of item.value.split(splitReg))
counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;
this.counts = counts;
},
onclick(event) {
// TODO: row click => check checkbox
}
},

View File

@ -83,6 +83,7 @@ export default {
},
toggle() {
console.log('tooogle', this.paused, '-', this.$refs.audio.src)
if(this.paused)
this.play()
else

View File

@ -3,7 +3,7 @@
$body-background-color: $light;
@import "~bulma/bulma";
@import "~bulma";
//-- helpers/modifiers
.is-fullwidth { width: 100%; }
@ -58,6 +58,38 @@ 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: 1.2em;
font-weight: $weight-bold;
padding: 0.2em;
top: 1em;
background-color: $white;
.fas {
padding: 0.1em;
font-size: 0.8em;
}
}
//-- filters
.filters {
@ -77,18 +109,7 @@ a.navbar-item.is-active {
}
/*
.navbar-brand img {
min-height: 6em;
}
.navbar-menu .navbar-item:not(:last-child) {
border-right: 1px $grey solid;
}
*/
/** page **/
//-- page
.page {
& > .cover {
float: right;
@ -109,39 +130,33 @@ a.navbar-item.is-active {
}
}
section > .toolbar {
background-color: rgba(0,0,0,0.05);
padding: 1em;
margin-bottom: 1.5em;
}
.media.item .headline {
line-height: 1.2em;
max-height: calc(1.2em * 3);
overflow: hidden;
main {
.cover {
margin: 1em 0em;
border: 0.2em black solid;
& + .headline-overflow {
position: relative;
width: 100%;
height: 2em;
margin-top: -2em;
}
.small-cover {
width: 10em;
}
}
aside {
.small-cover {
width: 4em;
}
.media .subtitle {
font-size: 1em;
}
.media .content {
display: none;
& + .headline-overflow:before {
content:'';
width:100%;
height:100%;
position:absolute;
left:0;
bottom:0;
background:linear-gradient(transparent 1em, $body-background-color);
}
}
//-- player
.player {
box-shadow: 0em 1.5em 2.5em rgba(0, 0, 0, 0.6);
@ -175,4 +190,57 @@ aside {
}
//-- media
.media {
.subtitle {
margin-bottom: 0.4em;
}
.media-content .headline {
font-size: 1em;
font-weight: 400;
}
}
//-- general
body {
background-color: $body-background-color;
}
section > .toolbar {
background-color: rgba(0,0,0,0.05);
padding: 1em;
margin-bottom: 1.5em;
}
main {
.cover {
margin: 1em 0em;
border: 0.2em black solid;
}
.small-cover {
width: 10em;
}
}
aside {
& > section {
margin-bottom: 2em;
}
.cover {
margin-bottom: 2em;
}
.small-cover {
width: 4em;
}
.media .subtitle {
font-size: 1em;
}
}

View File

@ -22,9 +22,8 @@ import aircox.urls
try:
urlpatterns = [
urlpatterns = aircox.urls.urls + [
path('admin/', admin.site.urls),
path('aircox/', include(aircox.urls.urls)),
]
if settings.DEBUG: