forked from rc/aircox
work on home page, fix views & templates issues
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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). """
|
||||
|
@ -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 = []
|
||||
|
@ -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)
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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");
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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");
|
||||
|
||||
/***/ }),
|
||||
|
||||
|
@ -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 %}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
83
aircox/templates/aircox/home.html
Normal file
83
aircox/templates/aircox/home.html
Normal 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 %}
|
||||
|
||||
|
@ -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 %}
|
||||
|
||||
|
@ -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 %}
|
||||
|
@ -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 %}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "aircox/page_item.html" %}
|
||||
{% extends "aircox/widgets/page_item.html" %}
|
||||
{% load i18n easy_thumbnails_tags aircox %}
|
||||
|
||||
{% comment %}
|
@ -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 %}
|
||||
|
29
aircox/templates/aircox/widgets/log_list.html
Normal file
29
aircox/templates/aircox/widgets/log_list.html
Normal 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 %}
|
||||
|
@ -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 %}
|
||||
|
28
aircox/templates/aircox/widgets/page_list.html
Normal file
28
aircox/templates/aircox/widgets/page_list.html
Normal 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 %}
|
||||
|
||||
|
@ -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'),
|
||||
|
||||
|
||||
]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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'),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
44
aircox/views/home.py
Normal 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)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -83,6 +83,7 @@ export default {
|
||||
},
|
||||
|
||||
toggle() {
|
||||
console.log('tooogle', this.paused, '-', this.$refs.audio.src)
|
||||
if(this.paused)
|
||||
this.play()
|
||||
else
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
Reference in New Issue
Block a user