diff --git a/aircox/models/__pycache__/__init__.cpython-37.pyc b/aircox/models/__pycache__/__init__.cpython-37.pyc index cfebf45..4631e36 100644 Binary files a/aircox/models/__pycache__/__init__.cpython-37.pyc and b/aircox/models/__pycache__/__init__.cpython-37.pyc differ diff --git a/aircox/models/__pycache__/episode.cpython-37.pyc b/aircox/models/__pycache__/episode.cpython-37.pyc index 6059e25..e24c66e 100644 Binary files a/aircox/models/__pycache__/episode.cpython-37.pyc and b/aircox/models/__pycache__/episode.cpython-37.pyc differ diff --git a/aircox/models/__pycache__/log.cpython-37.pyc b/aircox/models/__pycache__/log.cpython-37.pyc index 0271250..1d2a826 100644 Binary files a/aircox/models/__pycache__/log.cpython-37.pyc and b/aircox/models/__pycache__/log.cpython-37.pyc differ diff --git a/aircox/models/__pycache__/page.cpython-37.pyc b/aircox/models/__pycache__/page.cpython-37.pyc index 1e1b877..e4ceab9 100644 Binary files a/aircox/models/__pycache__/page.cpython-37.pyc and b/aircox/models/__pycache__/page.cpython-37.pyc differ diff --git a/aircox/models/__pycache__/program.cpython-37.pyc b/aircox/models/__pycache__/program.cpython-37.pyc index 07c00dd..ae0e9b6 100644 Binary files a/aircox/models/__pycache__/program.cpython-37.pyc and b/aircox/models/__pycache__/program.cpython-37.pyc differ diff --git a/aircox/models/__pycache__/sound.cpython-37.pyc b/aircox/models/__pycache__/sound.cpython-37.pyc index db47a40..bb3264a 100644 Binary files a/aircox/models/__pycache__/sound.cpython-37.pyc and b/aircox/models/__pycache__/sound.cpython-37.pyc differ diff --git a/aircox/models/__pycache__/station.cpython-37.pyc b/aircox/models/__pycache__/station.cpython-37.pyc index fbb7e58..3b8c0b8 100644 Binary files a/aircox/models/__pycache__/station.cpython-37.pyc and b/aircox/models/__pycache__/station.cpython-37.pyc differ diff --git a/aircox/models/episode.py b/aircox/models/episode.py index 0412763..dd3c6a4 100644 --- a/aircox/models/episode.py +++ b/aircox/models/episode.py @@ -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). """ diff --git a/aircox/models/log.py b/aircox/models/log.py index 390d3f1..ac7765a 100644 --- a/aircox/models/log.py +++ b/aircox/models/log.py @@ -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 = [] diff --git a/aircox/models/page.py b/aircox/models/page.py index 6ccb5c8..b2dfc43 100644 --- a/aircox/models/page.py +++ b/aircox/models/page.py @@ -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) diff --git a/aircox/static/aircox/admin.css b/aircox/static/aircox/admin.css index fa1696a..515d1ee 100644 --- a/aircox/static/aircox/admin.css +++ b/aircox/static/aircox/admin.css @@ -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; } + diff --git a/aircox/static/aircox/admin.js b/aircox/static/aircox/admin.js index 81267d7..fbaf339 100644 --- a/aircox/static/aircox/admin.js +++ b/aircox/static/aircox/admin.js @@ -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"); /***/ }), diff --git a/aircox/static/aircox/main.css b/aircox/static/aircox/main.css index 5368918..6e70140 100644 --- a/aircox/static/aircox/main.css +++ b/aircox/static/aircox/main.css @@ -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; } + diff --git a/aircox/static/aircox/main.js b/aircox/static/aircox/main.js index b514119..5af8f05 100644 --- a/aircox/static/aircox/main.js +++ b/aircox/static/aircox/main.js @@ -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"); /***/ }), diff --git a/aircox/templates/admin/aircox/statistics.html b/aircox/templates/admin/aircox/statistics.html index 6dfa9b2..5f0156e 100644 --- a/aircox/templates/admin/aircox/statistics.html +++ b/aircox/templates/admin/aircox/statistics.html @@ -3,8 +3,14 @@ {% block content %}{{ block.super }} +
+ {# TODO: date subtitle #} -
+ - - - -
{% endblock %} diff --git a/aircox/templates/admin/base.html b/aircox/templates/admin/base.html index e66b147..3eb3808 100644 --- a/aircox/templates/admin/base.html +++ b/aircox/templates/admin/base.html @@ -29,11 +29,10 @@ data-admin-utc-offset="{% now "Z" %}"> -
- +
{% if not is_popup %} -
-
+
{% endblock %} diff --git a/aircox/templates/aircox/article_detail.html b/aircox/templates/aircox/article_detail.html index dce7ec4..ee86496 100644 --- a/aircox/templates/aircox/article_detail.html +++ b/aircox/templates/aircox/article_detail.html @@ -4,12 +4,12 @@ {% block sidebar %} {{ block.super }} -{% if sidebar_items %} +{% if sidebar_object_list %}

{% trans "Latest news" %}

- {% for object in sidebar_items %} - {% include "aircox/page_item.html" %} + {% for object in sidebar_object_list %} + {% include "aircox/widgets/page_item.html" %} {% endfor %}
diff --git a/aircox/templates/aircox/base.html b/aircox/templates/aircox/base.html index e06477f..c427aa5 100644 --- a/aircox/templates/aircox/base.html +++ b/aircox/templates/aircox/base.html @@ -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 %} + @@ -72,14 +91,14 @@ Context: {% endblock %} - {% if has_filters %} - - {% endif %} - - {% block main %}{% endblock main %} + {% block main %} + {% if has_filters %} + + {% endif %} + {% endblock 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 %}

{% block sidebar_title %}{% trans "Recently" %}{% endblock %}

- - {% for object in sidebar_items %} - {% include "aircox/episode_item.html" %} - {% endfor %} - -
- + {% include "aircox/widgets/page_list.html" %} + {% endwith %} + {% endwith %} + {% endwith %} {% endif %}
{% endblock %} diff --git a/aircox/templates/aircox/diffusion_list.html b/aircox/templates/aircox/diffusion_list.html index 78d60b4..47ebc29 100644 --- a/aircox/templates/aircox/diffusion_list.html +++ b/aircox/templates/aircox/diffusion_list.html @@ -16,7 +16,7 @@ {% endblock %} {% block main %}{{ block.super }} -{% with True as hide_schedule %} +{% with hide_schedule=True %}
{% for diffusion in object_list %} @@ -24,12 +24,12 @@
{% with diffusion.episode as object %} - {% include "aircox/episode_item.html" %} + {% include "aircox/widgets/episode_item.html" %} {% endwith %}
diff --git a/aircox/templates/aircox/episode_detail.html b/aircox/templates/aircox/episode_detail.html index 2d31754..43075f4 100644 --- a/aircox/templates/aircox/episode_detail.html +++ b/aircox/templates/aircox/episode_detail.html @@ -50,7 +50,7 @@

{% trans "Podcasts" %}

{% for object in podcasts %} - {% include "aircox/podcast_item.html" %} + {% include "aircox/widgets/podcast_item.html" %} {% endfor %}
{% endif %} diff --git a/aircox/templates/aircox/home.html b/aircox/templates/aircox/home.html new file mode 100644 index 0000000..3c76f5c --- /dev/null +++ b/aircox/templates/aircox/home.html @@ -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 %} +
+ {% with render_card=True %} + {% for object in top_diffs %} + {% with is_primary=object.is_now %} +
+

+ {% if is_primary %} + + {% trans "Currently" %} + {% else %}{{ object.start|date:"H:i" }}{% endif %} +

+ {% include object.item_template_name %} +
+ {% endwith %} + {% endfor %} + {% endwith %} +
+ +
+

{% trans "Last publications" %}

+{{ block.super }} +{% endblock %} + + +{% block pagination %} + +{% endblock %} + + +{% block sidebar %} +
+

{% trans "Previously on air" %}

+ {% with logs as object_list %} + {% include "aircox/widgets/log_list.html" %} + {% endwith %} +
+ +
+

{% trans "Today" %}

+ {% with hide_schedule=True %} + {% with has_headline=False %} + + {% for object in sidebar_object_list %} + + + + + {% endfor %} +
{{ object.start|date:"H:i" }}{% include "aircox/widgets/diffusion_item.html" %}
+ {% endwith %} + {% endwith %} +
+{% endblock %} + + diff --git a/aircox/templates/aircox/log_list.html b/aircox/templates/aircox/log_list.html index be03e6a..13d1772 100644 --- a/aircox/templates/aircox/log_list.html +++ b/aircox/templates/aircox/log_list.html @@ -16,29 +16,10 @@ {% endwith %} {% endblock %} -{% block main %} +{% block main %}{{ block.super }}
{#

{{ date }}

#} - {% with True as hide_schedule %} - - {% for object in object_list %} - - - - - {% endfor %} -
- {% if object|is_diffusion %} - - {% else %} - - {% endif %} - {% include "aircox/log_item.html" %}
- {% endwith %} + {% include "aircox/widgets/log_list.html" %}
{% endblock %} diff --git a/aircox/templates/aircox/page_list.html b/aircox/templates/aircox/page_list.html index 539a98c..ee5b01d 100644 --- a/aircox/templates/aircox/page_list.html +++ b/aircox/templates/aircox/page_list.html @@ -56,21 +56,23 @@ {% endblock %} -{% block main %} +{% block main %}{{ block.super }}
+{% with has_headline=True %} {% for object in object_list %} {% block list_object %} {% include object.item_template_name|default:item_template_name %} {% endblock %} {% endfor %} +{% endwith %}
{% if is_paginated %}
- {% update_query request.GET.copy page=None as GET %} {% with GET.urlencode as GET %} {% endwith %} {% endif %} diff --git a/aircox/templates/aircox/program_base.html b/aircox/templates/aircox/program_base.html index a3f5db2..d7a8e3e 100644 --- a/aircox/templates/aircox/program_base.html +++ b/aircox/templates/aircox/program_base.html @@ -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 %} diff --git a/aircox/templates/aircox/program_detail.html b/aircox/templates/aircox/program_detail.html index 9692562..e91a330 100644 --- a/aircox/templates/aircox/program_detail.html +++ b/aircox/templates/aircox/program_detail.html @@ -10,15 +10,14 @@ {% block content %}{{ block.super }}
- -{% with show_headline=False %} +{% with has_headline=False %}
{% if articles %}

{% trans "Articles" %}

{% for object in articles %} - {% include "aircox/page_item.html" %} + {% include "aircox/widgets/page_item.html" %} {% endfor %}
diff --git a/aircox/templates/aircox/diffusion_item.html b/aircox/templates/aircox/widgets/diffusion_item.html similarity index 81% rename from aircox/templates/aircox/diffusion_item.html rename to aircox/templates/aircox/widgets/diffusion_item.html index 8b5d651..2971908 100644 --- a/aircox/templates/aircox/diffusion_item.html +++ b/aircox/templates/aircox/widgets/diffusion_item.html @@ -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 %} diff --git a/aircox/templates/aircox/episode_item.html b/aircox/templates/aircox/widgets/episode_item.html similarity index 95% rename from aircox/templates/aircox/episode_item.html rename to aircox/templates/aircox/widgets/episode_item.html index a5d6911..d9c6a73 100644 --- a/aircox/templates/aircox/episode_item.html +++ b/aircox/templates/aircox/widgets/episode_item.html @@ -1,4 +1,4 @@ -{% extends "aircox/page_item.html" %} +{% extends "aircox/widgets/page_item.html" %} {% load i18n easy_thumbnails_tags aircox %} {% comment %} diff --git a/aircox/templates/aircox/log_item.html b/aircox/templates/aircox/widgets/log_item.html similarity index 79% rename from aircox/templates/aircox/log_item.html rename to aircox/templates/aircox/widgets/log_item.html index 9cbae9b..355f81c 100644 --- a/aircox/templates/aircox/log_item.html +++ b/aircox/templates/aircox/widgets/log_item.html @@ -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 %} diff --git a/aircox/templates/aircox/widgets/log_list.html b/aircox/templates/aircox/widgets/log_list.html new file mode 100644 index 0000000..0b1cae3 --- /dev/null +++ b/aircox/templates/aircox/widgets/log_list.html @@ -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 %} + + {% for object in object_list %} + + + + + {% endfor %} +
+ {% if object|is_diffusion %} + + {% else %} + + {% endif %} + {% include "aircox/widgets/log_item.html" %}
+{% endwith %} + diff --git a/aircox/templates/aircox/page_item.html b/aircox/templates/aircox/widgets/page_item.html similarity index 52% rename from aircox/templates/aircox/page_item.html rename to aircox/templates/aircox/widgets/page_item.html index 0d47cf8..67f422e 100644 --- a/aircox/templates/aircox/page_item.html +++ b/aircox/templates/aircox/widgets/page_item.html @@ -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 %} -
+{% if render_card %} + + + +{% else %} +
+ {% if has_cover|default_if_none:True %}
+ {% endif %}
{% block title %} @@ -26,8 +47,8 @@ Context variables: {% endblock %}
- {% if show_headline %} -
+ {% if has_headline|default_if_none:True %} +
{% block headline %} {{ object.headline|safe }} {% endblock %} @@ -35,4 +56,5 @@ Context variables: {% endif %}
+{% endif %} diff --git a/aircox/templates/aircox/widgets/page_list.html b/aircox/templates/aircox/widgets/page_list.html new file mode 100644 index 0000000..46a798b --- /dev/null +++ b/aircox/templates/aircox/widgets/page_list.html @@ -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 %} +
+ +{% endif %} + + diff --git a/aircox/templates/aircox/podcast_item.html b/aircox/templates/aircox/widgets/podcast_item.html similarity index 100% rename from aircox/templates/aircox/podcast_item.html rename to aircox/templates/aircox/widgets/podcast_item.html diff --git a/aircox/templates/aircox/track_item.html b/aircox/templates/aircox/widgets/track_item.html similarity index 100% rename from aircox/templates/aircox/track_item.html rename to aircox/templates/aircox/widgets/track_item.html diff --git a/aircox/urls.py b/aircox/urls.py index 6fbcf82..cb7c74e 100755 --- a/aircox/urls.py +++ b/aircox/urls.py @@ -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('', 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//'), views.ProgramDetailView.as_view(), name='program-detail'), @@ -62,7 +61,7 @@ urls = [ path(_('programs//articles/'), views.ArticleListView.as_view(), name='article-list'), path(_('programs//publications/'), - views.ProgramPageListView.as_view(), name='page-list'), + views.ProgramPageListView.as_view(), name='program-page-list'), ] diff --git a/aircox/views/__init__.py b/aircox/views/__init__.py index ed44b56..e031491 100644 --- a/aircox/views/__init__.py +++ b/aircox/views/__init__.py @@ -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 diff --git a/aircox/views/admin.py b/aircox/views/admin.py index 49ec58a..441d379 100644 --- a/aircox/views/admin.py +++ b/aircox/views/admin.py @@ -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'), diff --git a/aircox/views/api.py b/aircox/views/api.py index e00e2eb..9060d52 100644 --- a/aircox/views/api.py +++ b/aircox/views/api.py @@ -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 diff --git a/aircox/views/article.py b/aircox/views/article.py index e81cc1a..02dabbc 100644 --- a/aircox/views/article.py +++ b/aircox/views/article.py @@ -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 diff --git a/aircox/views/base.py b/aircox/views/base.py index eb4c0f0..c3a807c 100644 --- a/aircox/views/base.py +++ b/aircox/views/base.py @@ -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) diff --git a/aircox/views/episode.py b/aircox/views/episode.py index 8e1aa1a..36eb0fa 100644 --- a/aircox/views/episode.py +++ b/aircox/views/episode.py @@ -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 diff --git a/aircox/views/home.py b/aircox/views/home.py new file mode 100644 index 0000000..71c8a4a --- /dev/null +++ b/aircox/views/home.py @@ -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) + + + diff --git a/aircox/views/log.py b/aircox/views/log.py index f61670e..6f3de61 100644 --- a/aircox/views/log.py +++ b/aircox/views/log.py @@ -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 diff --git a/aircox/views/mixins.py b/aircox/views/mixins.py index 6b56260..28d3dc9 100644 --- a/aircox/views/mixins.py +++ b/aircox/views/mixins.py @@ -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) diff --git a/aircox/views/page.py b/aircox/views/page.py index 1dcaa7f..9ba3f13 100644 --- a/aircox/views/page.py +++ b/aircox/views/page.py @@ -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) diff --git a/aircox/views/program.py b/aircox/views/program.py index e9698fc..4388148 100644 --- a/aircox/views/program.py +++ b/aircox/views/program.py @@ -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) - - diff --git a/assets/admin/admin.scss b/assets/admin/admin.scss index 8b299d3..0cc5b67 100644 --- a/assets/admin/admin.scss +++ b/assets/admin/admin.scss @@ -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; } diff --git a/assets/admin/statistics.vue b/assets/admin/statistics.vue index bebbc65..518c1fe 100644 --- a/assets/admin/statistics.vue +++ b/assets/admin/statistics.vue @@ -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 } }, diff --git a/assets/public/player.vue b/assets/public/player.vue index 62dba06..5fcacdb 100644 --- a/assets/public/player.vue +++ b/assets/public/player.vue @@ -83,6 +83,7 @@ export default { }, toggle() { + console.log('tooogle', this.paused, '-', this.$refs.audio.src) if(this.paused) this.play() else diff --git a/assets/public/styles.scss b/assets/public/styles.scss index 1c4c987..e4e927c 100644 --- a/assets/public/styles.scss +++ b/assets/public/styles.scss @@ -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; + } +} + + diff --git a/instance/urls.py b/instance/urls.py index 38ae87f..2046b53 100755 --- a/instance/urls.py +++ b/instance/urls.py @@ -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: