carousel, display logs

This commit is contained in:
bkfox 2023-11-28 01:04:39 +01:00
parent bc697bd4bd
commit cb5a6a3ee8
18 changed files with 636 additions and 264 deletions

View File

@ -163,7 +163,7 @@ class Log(Renderable, models.Model):
object_list += [cls(obj) for obj in items]
@classmethod
def merge_diffusions(cls, logs, diffs, count=None):
def merge_diffusions(cls, logs, diffs, count=None, diff_count=None):
"""Merge logs and diffusions together.
`logs` can either be a queryset or a list ordered by `Log.date`.
@ -172,7 +172,10 @@ class Log(Renderable, models.Model):
# FIXME: log may be iterable (in stats view)
if isinstance(logs, models.QuerySet):
logs = list(logs.order_by("-date"))
diffs = deque(diffs.on_air().before().order_by("-start"))
diffs = diffs.on_air().before().order_by("-start")
if diff_count:
diffs = diffs[:diff_count]
diffs = deque(diffs)
object_list = []
while True:

View File

@ -26,7 +26,8 @@ __all__ = (
)
headline_re = re.compile(r"(<p>)?" r"(?P<headline>[^\n]{1,140}(\n|[^\.]*?\.))" r"(</p>)?")
headline_clean_re = re.compile(r"\n(\s|&nbsp;)+", re.MULTILINE)
headline_re = re.compile(r"(?P<headline>([\S+]|\s+){1,240}\S+)", re.MULTILINE)
class Renderable:
@ -159,8 +160,19 @@ class BasePage(Renderable, models.Model):
if not self.content or not self.is_published:
return self.parent and self.parent.display_headline or ""
content = bleach.clean(self.content, tags=[], strip=True)
content = headline_clean_re.sub("\n", content)
if content.startswith("\n"):
content = content[1:]
headline = headline_re.search(content)
return mark_safe(headline.groupdict()["headline"]) if headline else ""
if not headline:
return ""
headline = headline.groupdict()["headline"]
suffix = "<b>...</b>" if len(headline) < len(content) else ""
headline = headline.split("\n")[:3]
headline[-1] += suffix
return mark_safe("<br>".join(headline))
@classmethod
def get_init_kwargs_from(cls, page, **kwargs):

View File

@ -1,3 +1,22 @@
/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css ***!
\*************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
.a-carousel-viewport[data-v-b79f173e] {
width: 100%;
overflow: hidden;
position: relative;
}
.a-carousel-container[data-v-b79f173e] {
display: flex;
flex-direction: row;
align-items: left;
}
.a-carousel-container > *[data-v-b79f173e] {
flex-shrink: 0;
}
/*!**************************************************************************************************************************************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js??clonedRuleSet-24.use[1]!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-24.use[2]!./node_modules/sass-loader/dist/cjs.js??clonedRuleSet-24.use[3]!./src/assets/styles.scss ***!
\**************************************************************************************************************************************************************************************************************************************/
@ -8069,14 +8088,14 @@ a.navbar-item.is-active {
--highlight-color-2: rgb(0, 0, 254);
--highlight-color-2-alpha: rgb(0, 0, 254, 0.7);
--highlight-color-2-grey: rgba(50, 200, 200, 1);
--header-height: 30em;
--heading-height: 30em;
--header-height: 30rem;
--heading-height: 30rem;
--heading-title-bg-color: rgba(255, 255, 0, 1);
--heading-bg-color: var(--highlight-color);
--heading-bg-highlight-color: var(--highlight-color-2);
--heading-font-family: default;
--preview-cover-size: 18em;
--preview-cover-small-size: 10em;
--preview-cover-size: 24rem;
--preview-cover-small-size: 10rem;
--player-panel-bg: var(--highlight-color);
--player-bar-bg: var(--highlight-color);
--progress-border-size: 1px;
@ -8181,6 +8200,14 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
border: 0px !important;
}
.highlight-color {
color: var(--highlight-color);
}
.highlight-color-2 {
color: var(--highlight-color-2);
}
.is-success {
background-color: #0e0 !important;
border-color: #0b0 !important;
@ -8241,23 +8268,6 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
color: var(--highlight-color-2);
border-color: var(--highlight-color-2-alpha);
}
.actions .button, .button.action, .actions a.button, a.button.action, .actions button.button, button.button.action, .actions .nav-urls a, .nav-urls a.action {
background-color: var(--highlight-color);
justify-content: center;
min-width: 2rem;
}
.actions .button .not-selected, .button.action .not-selected, .actions a.button .not-selected, a.button.action .not-selected, .actions button.button .not-selected, button.button.action .not-selected, .actions .nav-urls a .not-selected, .nav-urls a.action .not-selected {
opacity: 0.6;
}
.actions .button .icon, .button.action .icon, .actions a.button .icon, a.button.action .icon, .actions button.button .icon, button.button.action .icon, .actions .nav-urls a .icon, .nav-urls a.action .icon {
margin: 0em !important;
}
.actions .button label, .button.action label, .actions a.button label, a.button.action label, .actions button.button label, button.button.action label, .actions .nav-urls a label, .nav-urls a.action label {
margin-left: 0.4rem;
}
.actions .button:hover, .actions .button .selected, .button.action:hover, .button.action .selected, .actions a.button:hover, .actions a.button .selected, a.button.action:hover, a.button.action .selected, .actions button.button:hover, .actions button.button .selected, button.button.action:hover, button.button.action .selected, .actions .nav-urls a:hover, .actions .nav-urls a .selected, .nav-urls a.action:hover, .nav-urls a.action .selected {
color: var(--highlight-color-2) !important;
}
.button .dropdown-trigger, a.button .dropdown-trigger, button.button .dropdown-trigger, .nav-urls a .dropdown-trigger {
border-radius: 1.5em;
}
@ -8275,9 +8285,32 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
border-right: 0px;
}
.actions {
display: flex;
flex-direction: row;
gap: 0.6rem;
justify-content: right;
}
.actions.no-label label {
display: none;
}
.actions button, .actions .action {
background-color: var(--highlight-color);
justify-content: center;
min-width: 2rem;
}
.actions button .not-selected, .actions .action .not-selected {
opacity: 0.6;
}
.actions button .icon, .actions .action .icon {
margin: 0em !important;
}
.actions button label, .actions .action label {
margin-left: 0.4rem;
}
.actions button:hover, .actions button .selected, .actions .action:hover, .actions .action .selected {
color: var(--highlight-color-2) !important;
}
.title {
text-transform: uppercase;
@ -8307,6 +8340,9 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
display: flex;
background-color: var(--highlight-color);
}
.nav:empty {
display: none;
}
.nav .nav-item {
padding: 0.6rem;
flex-grow: 1;
@ -8391,9 +8427,6 @@ nav li a, nav li .button {
background-size: cover;
margin-bottom: 2rem !important;
}
.preview.preview-card:not(.wide) {
max-width: 30em;
}
.preview.preview-item {
width: 100%;
}
@ -8425,6 +8458,39 @@ nav li a, nav li .button {
color: var(--text-color);
}
.preview-cover {
background-size: cover;
background-color: transparent !important;
height: var(--preview-cover-size);
width: var(--preview-cover-size);
min-width: var(--preview-cover-size);
}
.preview-cover.small {
min-width: unset;
height: var(--preview-cover-small-size);
width: var(--preview-cover-small-size) !important;
min-width: var(--preview-cover-small-size);
}
.preview-header {
width: 100%;
}
.preview-header:not(.no-cover) {
min-height: var(--header-height);
}
.preview-header.no-cover {
height: unset;
}
.preview-header .headings {
padding-top: 2rem;
}
.preview-header .headings, .preview-header > .container {
width: 100%;
}
.preview-header > .container {
height: 100%;
}
.preview.comment .title {
font-size: 1.6rem;
}
@ -8439,16 +8505,23 @@ nav li a, nav li .button {
margin-top: 0.6rem;
}
.list-item .headings {
display: flex;
flex-direction: row;
padding-top: 0em;
margin-bottom: 1.2rem !important;
background-color: var(--heading-bg-color);
}
.list-item .headings .title {
flex-grow: 1;
}
.list-item .subtitle {
text-align: right;
}
.list-item .media-content {
display: flex;
flex-direction: column;
}
.list-item:not(.no-cover) .list-item .media-content {
min-height: var(--preview-cover-small-size);
}
.list-item .media-content .content {
@ -8479,7 +8552,7 @@ nav li a, nav li .button {
.preview-card {
height: var(--preview-cover-size);
min-width: var(--preview-cover-size);
width: var(--preview-cover-size);
}
.preview-card:not(.header) {
box-shadow: 0em 0em 1em rgba(0, 0, 0, 0.2);
@ -8496,21 +8569,7 @@ nav li a, nav li .button {
display: none;
}
.preview-cover {
background-size: cover;
height: var(--preview-cover-size);
width: var(--preview-cover-size);
}
.preview-cover.small {
min-width: unset;
height: var(--preview-cover-small-size);
width: var(--preview-cover-small-size) !important;
}
.preview-card-headings {
width: 100%;
min-width: var(--preview-cover-size);
min-height: 100%;
padding-top: 0.6rem;
}
.preview-card-headings > div:not(:last-child), .preview-card-headings .column > div {
@ -8520,25 +8579,6 @@ preview-header:not(.no-cover) .preview-card-headings .heading {
margin-bottom: 0.6rem;
}
.preview-header {
width: 100%;
}
.preview-header:not(.no-cover) {
min-height: var(--header-height);
}
.preview-header.no-cover {
height: unset;
}
.preview-header .headings {
padding-top: 2rem;
}
.preview-header .headings, .preview-header > .container {
width: 100%;
}
.preview-header > .container {
height: 100%;
}
.header {
background-size: cover;
}
@ -8567,20 +8607,38 @@ preview-header:not(.no-cover) .preview-card-headings .heading {
gap: 1.2rem;
}
.a-carousel-container {
width: 100%;
gap: 1.2rem;
transition: margin-left 1s;
}
.a-carousel-container > * {
flex-shrink: 0;
}
.a-carousel-button-container button, .a-carousel-button-container .button {
z-index: 1000;
position: absolute;
display: flex;
flex-direction: column;
top: calc(var(--preview-cover-size) - 1.4rem);
}
.a-carousel-button-container button.prev, .a-carousel-button-container .button.prev {
left: -0.6em;
}
.a-carousel-button-container button.next, .a-carousel-button-container .button.next {
right: -0.6em;
}
@media screen and (max-width: 1380px) {
.preview-card:not(.preview-header) {
height: 20em !important;
}
.card-grid .preview-card {
height: 20em;
:root {
--preview-cover-size: 18em;
}
}
@media screen and (max-width: 1024px) {
.card-grid {
grid-template-columns: 1fr 1fr;
}
.card-grid .preview-card:nth-child(3) {
display: none;
.page .container {
margin-left: 1.2rem;
margin-right: 1.2rem;
}
}
.a-progress {

View File

@ -29,6 +29,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mod
/***/ }),
/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=script&lang=js":
/*!*******************************************************************************************************************************************************************************************!*\
!*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=script&lang=js ***!
\*******************************************************************************************************************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm-bundler.js\");\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n setup() {\n return {\n viewport: (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(null),\n container: (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(null)\n };\n },\n data() {\n return {\n cards: [],\n index: 0,\n refresh_: 0\n };\n },\n props: {\n cardSelector: {\n type: String,\n default: ''\n },\n containerClass: {\n type: String,\n default: ''\n },\n buttonClass: {\n type: String,\n default: 'button'\n },\n leftButtonIcon: {\n type: String,\n default: \"fas fa-chevron-left\"\n },\n rightButtonIcon: {\n type: String,\n default: \"fas fa-chevron-right\"\n }\n },\n computed: {\n card() {\n return this.cards()[this.index];\n },\n showPrevButton() {\n return this.index > 0;\n },\n showNextButton() {\n if (!this.cards || this.cards.length <= 1) return false;\n let {\n count\n } = this.visibility;\n return this.index + count < this.cards.length;\n },\n visibility() {\n // force refresh on index\n [this.index, this.refresh_];\n if (!this.cards) return {\n min: -1,\n max: -1,\n count: 0\n };\n const vOff = this.offset(this.$refs.viewport);\n var [min, max] = [-1, -1];\n for (let at = 0; at < this.cards.length; at++) {\n const card = this.cards[at];\n const cOff = this.offset(card);\n const visible = vOff.min <= cOff.min && vOff.max >= cOff.max;\n if (visible) {\n if (min === -1) min = parseInt(at);\n max = parseInt(at);\n }\n }\n if (max !== -1) max++;\n return {\n min,\n max,\n count: min !== -1 ? max - min : 0\n };\n }\n },\n methods: {\n offset(el, parent = null) {\n const rect = el.getBoundingClientRect();\n const off = {\n min: rect.left,\n max: rect.right\n };\n if (parent === null) return off;\n const pOff = this.offset(parent);\n return {\n min: off.min - pOff.min,\n max: off.max - pOff.max\n };\n },\n getCards() {\n if (!this.cardSelector) return this.$refs.container.children;\n return this.$refs.container.querySelectorAll(this.cardSelector);\n },\n selectIndex(index, relative = false) {\n if (relative) index = this.index + index;\n index = Math.min(this.cards.length, index);\n const el = this.cards[index];\n const elOff = this.offset(el, this.$refs.container);\n this.$refs.container.style.marginLeft = `-${elOff.min}px`;\n this.index = index;\n return el;\n },\n next() {\n if (!this.visibility.count) return;\n let {\n count\n } = this.visibility;\n let at = Math.min(count === 1 ? this.index + count : this.index + count - 1, this.cards.length - count);\n this.selectIndex(at);\n },\n prev() {\n if (!this.visibility.count) return;\n const {\n min,\n count\n } = this.visibility;\n let at = Math.max(0, min - count);\n if (min < 0 || count <= 0) return;\n this.selectIndex(at);\n },\n refresh() {\n this.cards = this.getCards();\n this.selectIndex(this.index);\n this.refresh_++;\n }\n },\n mounted() {\n this.observer = [new MutationObserver(() => this.refresh()), new ResizeObserver(() => this.refresh())];\n this.observer[0].observe(this.$refs.container, {\n \"childList\": true\n });\n this.observer[1].observe(this.$refs.container);\n this.refresh();\n },\n unmounted() {\n for (var observer of this.observers) observer.disconnect();\n }\n});\n\n//# sourceURL=webpack://aircox-assets/./src/components/ACarousel.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use%5B0%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D");
/***/ }),
/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ADropdown.vue?vue&type=script&lang=js":
/*!*******************************************************************************************************************************************************************************************!*\
!*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ADropdown.vue?vue&type=script&lang=js ***!
@ -179,6 +189,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
/***/ }),
/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=template&id=b79f173e&scoped=true":
/*!***********************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=template&id=b79f173e&scoped=true ***!
\***********************************************************************************************************************************************************************************************************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm-bundler.js\");\n\nconst _withScopeId = n => ((0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)(\"data-v-b79f173e\"), n = n(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(), n);\nconst _hoisted_1 = {\n key: 0,\n class: \"a-carousel-button-container\"\n};\nconst _hoisted_2 = {\n class: \"icon\"\n};\nconst _hoisted_3 = {\n key: 1,\n class: \"a-carousel-button-container\"\n};\nconst _hoisted_4 = {\n class: \"icon\"\n};\nconst _hoisted_5 = {\n ref: \"viewport\",\n class: \"a-carousel-viewport\"\n};\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, [$options.showPrevButton ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_1, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"button\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([$props.buttonClass, 'prev']),\n \"aria-label\": \"Go left\",\n onClick: _cache[0] || (_cache[0] = (...args) => $options.prev && $options.prev(...args))\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", _hoisted_2, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"i\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)($props.leftButtonIcon)\n }, null, 2 /* CLASS */)])], 2 /* CLASS */)])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), $options.showNextButton ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_3, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"button\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([$props.buttonClass, 'next']),\n \"aria-label\": \"Go left\",\n onClick: _cache[1] || (_cache[1] = (...args) => $options.next && $options.next(...args))\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", _hoisted_4, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"i\", {\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)($props.rightButtonIcon)\n }, null, 2 /* CLASS */)])], 2 /* CLASS */)])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_5, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"section\", {\n ref: \"container\",\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)(['a-carousel-container', $props.containerClass])\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.renderSlot)(_ctx.$slots, \"default\", {}, undefined, true)], 2 /* CLASS */)], 512 /* NEED_PATCH */)], 64 /* STABLE_FRAGMENT */);\n}\n\n//# sourceURL=webpack://aircox-assets/./src/components/ACarousel.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use%5B0%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B3%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D");
/***/ }),
/***/ "./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ADropdown.vue?vue&type=template&id=a87ed2dc":
/*!***********************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ADropdown.vue?vue&type=template&id=a87ed2dc ***!
@ -335,7 +355,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
\*********************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ admin: function() { return /* binding */ admin; },\n/* harmony export */ base: function() { return /* binding */ base; }\n/* harmony export */ });\n/* harmony import */ var _AAutocomplete_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AAutocomplete.vue */ \"./src/components/AAutocomplete.vue\");\n/* harmony import */ var _ADropdown_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ADropdown.vue */ \"./src/components/ADropdown.vue\");\n/* harmony import */ var _AEpisode_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./AEpisode.vue */ \"./src/components/AEpisode.vue\");\n/* harmony import */ var _AList_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./AList.vue */ \"./src/components/AList.vue\");\n/* harmony import */ var _APage_vue__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./APage.vue */ \"./src/components/APage.vue\");\n/* harmony import */ var _APlayer_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./APlayer.vue */ \"./src/components/APlayer.vue\");\n/* harmony import */ var _APlaylist_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./APlaylist.vue */ \"./src/components/APlaylist.vue\");\n/* harmony import */ var _APlaylistEditor_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./APlaylistEditor.vue */ \"./src/components/APlaylistEditor.vue\");\n/* harmony import */ var _AProgress_vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./AProgress.vue */ \"./src/components/AProgress.vue\");\n/* harmony import */ var _ASoundItem_vue__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./ASoundItem.vue */ \"./src/components/ASoundItem.vue\");\n/* harmony import */ var _AStatistics_vue__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./AStatistics.vue */ \"./src/components/AStatistics.vue\");\n/* harmony import */ var _AStreamer_vue__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./AStreamer.vue */ \"./src/components/AStreamer.vue\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Core components\n */\nconst base = {\n AAutocomplete: _AAutocomplete_vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n ADropdown: _ADropdown_vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n AEpisode: _AEpisode_vue__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n AList: _AList_vue__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n APage: _APage_vue__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n APlayer: _APlayer_vue__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n APlaylist: _APlaylist_vue__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n AProgress: _AProgress_vue__WEBPACK_IMPORTED_MODULE_8__[\"default\"],\n ASoundItem: _ASoundItem_vue__WEBPACK_IMPORTED_MODULE_9__[\"default\"]\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (base);\nconst admin = {\n ...base,\n AStatistics: _AStatistics_vue__WEBPACK_IMPORTED_MODULE_10__[\"default\"],\n AStreamer: _AStreamer_vue__WEBPACK_IMPORTED_MODULE_11__[\"default\"],\n APlaylistEditor: _APlaylistEditor_vue__WEBPACK_IMPORTED_MODULE_7__[\"default\"]\n};\n\n//# sourceURL=webpack://aircox-assets/./src/components/index.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ admin: function() { return /* binding */ admin; },\n/* harmony export */ base: function() { return /* binding */ base; }\n/* harmony export */ });\n/* harmony import */ var _AAutocomplete_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AAutocomplete.vue */ \"./src/components/AAutocomplete.vue\");\n/* harmony import */ var _ACarousel_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ACarousel.vue */ \"./src/components/ACarousel.vue\");\n/* harmony import */ var _ADropdown_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ADropdown.vue */ \"./src/components/ADropdown.vue\");\n/* harmony import */ var _AEpisode_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./AEpisode.vue */ \"./src/components/AEpisode.vue\");\n/* harmony import */ var _AList_vue__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./AList.vue */ \"./src/components/AList.vue\");\n/* harmony import */ var _APage_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./APage.vue */ \"./src/components/APage.vue\");\n/* harmony import */ var _APlayer_vue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./APlayer.vue */ \"./src/components/APlayer.vue\");\n/* harmony import */ var _APlaylist_vue__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./APlaylist.vue */ \"./src/components/APlaylist.vue\");\n/* harmony import */ var _APlaylistEditor_vue__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./APlaylistEditor.vue */ \"./src/components/APlaylistEditor.vue\");\n/* harmony import */ var _AProgress_vue__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./AProgress.vue */ \"./src/components/AProgress.vue\");\n/* harmony import */ var _ASoundItem_vue__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./ASoundItem.vue */ \"./src/components/ASoundItem.vue\");\n/* harmony import */ var _AStatistics_vue__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./AStatistics.vue */ \"./src/components/AStatistics.vue\");\n/* harmony import */ var _AStreamer_vue__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./AStreamer.vue */ \"./src/components/AStreamer.vue\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Core components\n */\nconst base = {\n AAutocomplete: _AAutocomplete_vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n ACarousel: _ACarousel_vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n ADropdown: _ADropdown_vue__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n AEpisode: _AEpisode_vue__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n AList: _AList_vue__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n APage: _APage_vue__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n APlayer: _APlayer_vue__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n APlaylist: _APlaylist_vue__WEBPACK_IMPORTED_MODULE_7__[\"default\"],\n AProgress: _AProgress_vue__WEBPACK_IMPORTED_MODULE_9__[\"default\"],\n ASoundItem: _ASoundItem_vue__WEBPACK_IMPORTED_MODULE_10__[\"default\"]\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (base);\nconst admin = {\n ...base,\n AStatistics: _AStatistics_vue__WEBPACK_IMPORTED_MODULE_11__[\"default\"],\n AStreamer: _AStreamer_vue__WEBPACK_IMPORTED_MODULE_12__[\"default\"],\n APlaylistEditor: _APlaylistEditor_vue__WEBPACK_IMPORTED_MODULE_8__[\"default\"]\n};\n\n//# sourceURL=webpack://aircox-assets/./src/components/index.js?");
/***/ }),
@ -409,6 +429,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
/***/ }),
/***/ "./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css":
/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css ***!
\****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://aircox-assets/./src/components/ACarousel.vue?./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use%5B0%5D!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use%5B1%5D!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use%5B2%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D");
/***/ }),
/***/ "./src/assets/styles.scss":
/*!********************************!*\
!*** ./src/assets/styles.scss ***!
@ -439,6 +469,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _AAu
/***/ }),
/***/ "./src/components/ACarousel.vue":
/*!**************************************!*\
!*** ./src/components/ACarousel.vue ***!
\**************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ACarousel_vue_vue_type_template_id_b79f173e_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ACarousel.vue?vue&type=template&id=b79f173e&scoped=true */ \"./src/components/ACarousel.vue?vue&type=template&id=b79f173e&scoped=true\");\n/* harmony import */ var _ACarousel_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ACarousel.vue?vue&type=script&lang=js */ \"./src/components/ACarousel.vue?vue&type=script&lang=js\");\n/* harmony import */ var _ACarousel_vue_vue_type_style_index_0_id_b79f173e_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css */ \"./src/components/ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css\");\n/* harmony import */ var _media_data_code_projets_aircox_assets_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./node_modules/vue-loader/dist/exportHelper.js */ \"./node_modules/vue-loader/dist/exportHelper.js\");\n\n\n\n\n;\n\n\nconst __exports__ = /*#__PURE__*/(0,_media_data_code_projets_aircox_assets_node_modules_vue_loader_dist_exportHelper_js__WEBPACK_IMPORTED_MODULE_3__[\"default\"])(_ACarousel_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"], [['render',_ACarousel_vue_vue_type_template_id_b79f173e_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render],['__scopeId',\"data-v-b79f173e\"],['__file',\"src/components/ACarousel.vue\"]])\n/* hot reload */\nif (false) {}\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (__exports__);\n\n//# sourceURL=webpack://aircox-assets/./src/components/ACarousel.vue?");
/***/ }),
/***/ "./src/components/ADropdown.vue":
/*!**************************************!*\
!*** ./src/components/ADropdown.vue ***!
@ -589,6 +629,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
/***/ }),
/***/ "./src/components/ACarousel.vue?vue&type=script&lang=js":
/*!**************************************************************!*\
!*** ./src/components/ACarousel.vue?vue&type=script&lang=js ***!
\**************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": function() { return /* reexport safe */ _node_modules_babel_loader_lib_index_js_clonedRuleSet_40_use_0_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_ACarousel_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]; }\n/* harmony export */ });\n/* harmony import */ var _node_modules_babel_loader_lib_index_js_clonedRuleSet_40_use_0_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_ACarousel_vue_vue_type_script_lang_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./ACarousel.vue?vue&type=script&lang=js */ \"./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=script&lang=js\");\n \n\n//# sourceURL=webpack://aircox-assets/./src/components/ACarousel.vue?");
/***/ }),
/***/ "./src/components/ADropdown.vue?vue&type=script&lang=js":
/*!**************************************************************!*\
!*** ./src/components/ADropdown.vue?vue&type=script&lang=js ***!
@ -739,6 +789,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
/***/ }),
/***/ "./src/components/ACarousel.vue?vue&type=template&id=b79f173e&scoped=true":
/*!********************************************************************************!*\
!*** ./src/components/ACarousel.vue?vue&type=template&id=b79f173e&scoped=true ***!
\********************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* reexport safe */ _node_modules_babel_loader_lib_index_js_clonedRuleSet_40_use_0_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_3_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_ACarousel_vue_vue_type_template_id_b79f173e_scoped_true__WEBPACK_IMPORTED_MODULE_0__.render; }\n/* harmony export */ });\n/* harmony import */ var _node_modules_babel_loader_lib_index_js_clonedRuleSet_40_use_0_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_3_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_ACarousel_vue_vue_type_template_id_b79f173e_scoped_true__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!../../node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./ACarousel.vue?vue&type=template&id=b79f173e&scoped=true */ \"./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=template&id=b79f173e&scoped=true\");\n\n\n//# sourceURL=webpack://aircox-assets/./src/components/ACarousel.vue?");
/***/ }),
/***/ "./src/components/ADropdown.vue?vue&type=template&id=a87ed2dc":
/*!********************************************************************!*\
!*** ./src/components/ADropdown.vue?vue&type=template&id=a87ed2dc ***!
@ -867,6 +927,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* reexport safe */ _node_modules_babel_loader_lib_index_js_clonedRuleSet_40_use_0_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_3_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_AStreamer_vue_vue_type_template_id_06ef60ae__WEBPACK_IMPORTED_MODULE_0__.render; }\n/* harmony export */ });\n/* harmony import */ var _node_modules_babel_loader_lib_index_js_clonedRuleSet_40_use_0_node_modules_vue_loader_dist_templateLoader_js_ruleSet_1_rules_3_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_AStreamer_vue_vue_type_template_id_06ef60ae__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!../../node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./AStreamer.vue?vue&type=template&id=06ef60ae */ \"./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[3]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/AStreamer.vue?vue&type=template&id=06ef60ae\");\n\n\n//# sourceURL=webpack://aircox-assets/./src/components/AStreamer.vue?");
/***/ }),
/***/ "./src/components/ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css":
/*!**********************************************************************************************!*\
!*** ./src/components/ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css ***!
\**********************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_mini_css_extract_plugin_dist_loader_js_clonedRuleSet_12_use_0_node_modules_css_loader_dist_cjs_js_clonedRuleSet_12_use_1_node_modules_vue_loader_dist_stylePostLoader_js_node_modules_postcss_loader_dist_cjs_js_clonedRuleSet_12_use_2_node_modules_vue_loader_dist_index_js_ruleSet_0_use_0_ACarousel_vue_vue_type_style_index_0_id_b79f173e_scoped_true_lang_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!../../node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!../../node_modules/vue-loader/dist/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!../../node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css */ \"./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-12.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-12.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-12.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/ACarousel.vue?vue&type=style&index=0&id=b79f173e&scoped=true&lang=css\");\n\n\n//# sourceURL=webpack://aircox-assets/./src/components/ACarousel.vue?");
/***/ })
}]);

View File

@ -22,13 +22,13 @@
{% endwith %}
</div>
<div class="card-grid">
<a-carousel section-class="card-grid">
{% for obj in next_diffs|slice:"1:4" %}
{% if object != diffusion %}
{% page_widget "card" obj.episode diffusion=obj timetable=True %}
{% endif %}
{% endfor %}
</div>
</a-carousel>
</section>
{% endif %}
@ -40,7 +40,7 @@
{% endfor %}
<nav class="nav-urls">
<a href="{% url "diffusion-list" %}"
<a href="{% url "log-list" %}"
aria-label="{% translate "Show all program's for today" %}">
{% translate "Today" %}
</a>

View File

@ -40,11 +40,11 @@ Context:
<h3 class="title is-3">{% blocktranslate %}Related {{models}}{% endblocktranslate %}</h3>
{% endwith %}
<section class="card-grid">
<a-carousel section-class="card-grid">
{% for object in related_objects %}
{% page_widget "card" object %}
{% endfor %}
</section>
</a-carousel>
{% if related_url %}
<nav class="nav-urls">

View File

@ -3,12 +3,12 @@
{% load i18n aircox %}
{% block secondary-nav %}
<form class="nav secondary">
<nav class="nav secondary">
{% for id, title in view.categories.items %}
<a class="nav-item{% if category_id == id or parent and parent.category_id == id %} active{% endif %}"
href="?category__id={{ id }}">{{ title }}</a>
{% endfor %}
</form>
</nav>
{% endblock %}
{% block header %}

View File

@ -10,11 +10,11 @@
{% if episodes %}
<section class="container">
<h3 class="title is-3">{% translate "Last Episodes" %}</h3>
<section class="card-grid">
<a-carousel section-class="card-grid">
{% for object in episodes|slice:":3" %}
{% page_widget "card" object %}
{% endfor %}
</section>
</a-carousel>
<nav class="nav-urls">
<a href="{% url "episode-list" parent_slug=program.slug %}">
@ -29,11 +29,11 @@
<section class="container">
<h3 class="title is-3">{% translate "Last Articles" %}</h3>
<section class="card-grid">
<a-carousel section-class="card-grid">
{% for object in articles|slice:3 %}
{% page_widget "card" object %}
{% endfor %}
</section>
</a-carousel>
<nav class="nav-urls">
<a href="{% url "article-list" parent_slug=program.slug %}"

View File

@ -31,20 +31,18 @@
{{ block.super }}
{% if request.user.is_staff %}
<span class="float-right">
<a href="{% url "admin:aircox_comment_change" object.pk %}"
title="{% trans "Edit comment" %}"
aria-label="{% trans "Edit comment" %}">
<span class="fa fa-edit"></span>
</a>
<a class="has-text-danger"
title="{% trans "Delete comment" %}"
aria-label="{% trans "Delete comment" %}"
href="{% url "admin:aircox_comment_delete" object.pk %}">
<span class="fa fa-trash-alt"></span>
</a>
<a href="{% url "admin:aircox_comment_change" object.pk %}" class="button"
title="{% trans "Edit comment" %}"
aria-label="{% trans "Edit comment" %}">
<span class="fa fa-edit"></span>
</a>
<a class="button is-danger"
title="{% trans "Delete comment" %}"
aria-label="{% trans "Delete comment" %}"
href="{% url "admin:aircox_comment_delete" object.pk %}">
<span class="fa fa-trash-alt"></span>
</a>
{# <a href="mailto:{{ object.email }}">{{ object.nickname }}</a> #}
</span>
{# <a href="mailto:{{ object.email }}">{{ object.nickname }}</a> #}
{% endif %}
{% endblock %}

View File

@ -2,15 +2,14 @@
{% load i18n aircox %}
{% block tag-class %}list-item is-fullwidth{% endblock %}
{% block headings-class %} columns{% endblock %}
{% block headings %}
<div class="column">
<a href="{{ url|escape }}" class="heading title {% block title-class %}{% endblock %}">{% block title %}{{ title|default:"" }}{% endblock %}</a>
</div>
<div>
<span class="heading subtitle {% block subtitle-class %}{% endblock %}">{% block subtitle %}{{ subtitle|default:"" }}{% endblock %}</span>
</div>
<a href="{{ url|escape }}" class="heading title {% block title-class %}{% endblock %}">
{% block title %}{{ title|default:"" }}{% endblock %}
</a>
<span class="heading subtitle {% block subtitle-class %}{% endblock %}">
{% block subtitle %}{{ subtitle|default:"" }}{% endblock %}
</span>
{% endblock %}
{% block inner %}
@ -18,9 +17,10 @@
{% block content-container %}
<div class="media">
{% if object.cover %}
<div class="media-left preview-cover small"
<a href="{{ object.get_absolute_url }}"
class="media-left preview-cover small"
style="background-image: url({{ object.cover.url }})">
</div>
</a>
{% endif %}
<div class="media-content">
<section class="content">

View File

@ -5,8 +5,10 @@ Context:
- object: track to render
{% endcomment %}
<span class="content">
<span class="has-text-info">&#9836;</span>
<span class="content mr-2">
<span class="icon highlight-color-2 m-2">
<i class="fas fa-music"></i>
</span>
{% if log %}
<span>{{ log.date|date:"H:i" }} &mdash; </span>
{% endif %}

View File

@ -31,7 +31,5 @@ class EpisodeDetailView(ProgramPageDetailView):
class EpisodeListView(PageListView):
model = Episode
filterset_class = EpisodeFilters
item_template_name = "aircox/widgets/episode_item.html"
has_headline = True
parent_model = Program
attach_to_value = StaticPage.ATTACH_TO_EPISODES

View File

@ -1,4 +1,4 @@
from datetime import date
from datetime import date, timedelta
from django.utils import timezone as tz
from django.views.generic import ListView
@ -12,7 +12,7 @@ class HomeView(AttachedToMixin, BaseView, ListView):
template_name = "aircox/home.html"
attach_to_value = StaticPage.ATTACH_TO_HOME
model = Diffusion
queryset = Diffusion.objects.on_air().select_related("episode")
queryset = Diffusion.objects.on_air().select_related("episode").order_by("-start")
logs_count = 5
publications_count = 7
@ -21,9 +21,14 @@ class HomeView(AttachedToMixin, BaseView, ListView):
def get_logs(self, diffusions):
today = date.today()
logs = Log.objects.on_air().date(today).filter(track__isnull=False)
# diffs = Diffusion.objects.on_air().date(today)
return Log.merge_diffusions(logs, diffusions, self.logs_count)
object_list = self.object_list
diffs = list(object_list[: self.logs_count])
logs = Log.objects.on_air().date(today).filter(track__isnull=False)
if diffs:
min_date = diffs[-1].start - timedelta(hours=1)
logs = logs.after(min_date)
return Log.merge_diffusions(logs, object_list, diff_count=self.logs_count)
def get_next_diffs(self):
now = tz.now()

View File

@ -133,7 +133,7 @@ class PageDetailView(BasePageDetailView):
template_name = None
context_object_name = "page"
related_count = 3
related_count = 7
def get_related_queryset(self):
"""Return a queryset of related pages or None."""

View File

@ -33,7 +33,7 @@ class ProgramDetailView(BaseProgramMixin, PageDetailView):
.published()
.order_by("-pub_date")[:50]
)
return random.sample(list(queryset), self.related_count)
return random.sample(list(queryset), min(len(queryset), self.related_count))
def get_related_url(self):
return reverse("program-list") + f"?category__id={self.object.category_id}"

View File

@ -174,16 +174,16 @@ a.navbar-item.is-active {
--highlight-color-2-alpha: rgb(0, 0, 254, 0.7);
--highlight-color-2-grey: rgba(50, 200, 200, 1);
--header-height: 30em;
--header-height: 30rem;
--heading-height: 30em;
--heading-height: 30rem;
--heading-title-bg-color: rgba(255, 255, 0, 1);
--heading-bg-color: var(--highlight-color);
--heading-bg-highlight-color: var(--highlight-color-2);
--heading-font-family: default;
--preview-cover-size: 18em;
--preview-cover-small-size: 10em;
--preview-cover-size: 24rem;
--preview-cover-small-size: 10rem;
--player-panel-bg: var(--highlight-color);
--player-bar-bg: var(--highlight-color);
@ -262,6 +262,9 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
.no-border { border: 0px !important; }
// -- colors
.highlight-color { color: var(--highlight-color); }
.highlight-color-2 { color: var(--highlight-color-2); }
.is-success {
background-color: $green !important;
border-color: $green-dark !important;
@ -328,25 +331,6 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
border-color: var(--highlight-color-2-alpha);
}
.actions &, &.action {
background-color: var(--highlight-color);
justify-content: center;
min-width: 2rem;
.not-selected { opacity: 0.6; }
.icon { margin: 0em !important; }
label {
margin-left: $mp-2;
}
&:hover, .selected {
color: var(--highlight-color-2) !important;
}
}
.dropdown-trigger {
border-radius: 1.5em;
}
@ -366,9 +350,34 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
}
.actions {
display: flex;
flex-direction: row;
gap: $mp-3;
justify-content: right;
&.no-label label {
display: none;
}
button, .action {
background-color: var(--highlight-color);
justify-content: center;
min-width: 2rem;
.not-selected { opacity: 0.6; }
.icon { margin: 0em !important; }
label {
margin-left: $mp-2;
}
&:hover, .selected {
color: var(--highlight-color-2) !important;
}
}
}
@ -379,6 +388,7 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
&.is-3 {
margin-top: $mp-3;
}
}
.heading {
@ -406,6 +416,10 @@ h1, h2, h3, h4, h5, h6, .heading, .title, .subtitle {
display: flex;
background-color: var(--highlight-color);
&:empty {
display: none;
}
.nav-item {
padding: $mp-3;
flex-grow: 1;
@ -513,16 +527,11 @@ nav li {
background-size: cover;
margin-bottom: $mp-6 !important;
&.preview-card {
&:not(.wide) {
max-width: 30em;
}
}
&.preview-item {
width: 100%;
}
// FIXME: remove
&.columns, .headings.columns {
margin-left: 0em;
margin-right: 0em;
@ -553,123 +562,21 @@ nav li {
}
}
.preview.comment {
.title { font-size: $text-size-bigger; }
.subtitle { font-size: $text-size; }
}
.list-item {
width: 100%;
&:not(:first-child) {
margin-top: calc($mp-4 / 2);
}
.headings {
padding-top: 0em;
margin-bottom: $mp-4 !important;
background-color: var(--heading-bg-color);
}
.subtitle {
text-align: right;
}
.media-content {
display: flex;
flex-direction: column;
min-height: var(--preview-cover-small-size);
.content {
flex-grow: 1;
margin-bottom: auto;
}
.actions {
flex-grow: unset;
text-align: right;
margin-top: auto;
}
}
}
// ---- cards
.preview-wide {
height: var(--preview-cover-size);
&:not(.header) .headings {
box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
}
& .headings {
width: var(--preview-cover-size);
flex-grow: 0;
margin-right: $mp-4;
}
& .content {
font-size: $text-size-big;
flex-grow: 1;
}
}
.preview-card {
height: var(--preview-cover-size);
min-width: var(--preview-cover-size);
&:not(.header) {
box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
}
.card-grid & {
min-width: unset;
}
.actions {
position: absolute;
bottom: $mp-3;
right: $mp-3;
label {
display: none;
}
}
}
.preview-cover {
background-size: cover;
background-color: transparent !important;
height: var(--preview-cover-size);
width: var(--preview-cover-size);
min-width: var(--preview-cover-size);
&.small {
min-width: unset;
height: var(--preview-cover-small-size);
width: var(--preview-cover-small-size) !important;
min-width: var(--preview-cover-small-size);
}
}
.preview-card-headings {
width: 100%;
min-width: var(--preview-cover-size);
min-height: 100%;
padding-top: $mp-3;
& > div:not(:last-child),
& .column > div {
margin-bottom: $mp-3;
}
preview-header:not(.no-cover) & .heading {
margin-bottom: $mp-3;
}
}
.preview-header {
width: 100%;
@ -695,6 +602,120 @@ nav li {
}
// ---- specific
.preview.comment {
.title { font-size: $text-size-bigger; }
.subtitle { font-size: $text-size; }
}
// ---- list
.list-item {
width: 100%;
&:not(:first-child) {
margin-top: calc($mp-4 / 2);
}
.headings {
display: flex;
flex-direction: row;
padding-top: 0em;
margin-bottom: $mp-4 !important;
background-color: var(--heading-bg-color);
.title {
flex-grow: 1;
}
}
.subtitle {
text-align: right;
}
.media-content {
display: flex;
flex-direction: column;
.list-item:not(.no-cover) & {
min-height: var(--preview-cover-small-size);
}
.content {
flex-grow: 1;
margin-bottom: auto;
}
.actions {
flex-grow: unset;
text-align: right;
margin-top: auto;
}
}
}
// ---- wide
.preview-wide {
height: var(--preview-cover-size);
&:not(.header) .headings {
box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
}
& .headings {
width: var(--preview-cover-size);
flex-grow: 0;
margin-right: $mp-4;
}
& .content {
font-size: $text-size-big;
flex-grow: 1;
}
}
// ---- card
.preview-card {
height: var(--preview-cover-size);
width: var(--preview-cover-size);
&:not(.header) {
box-shadow: 0em 0em 1em rgba(0,0,0,0.2);
}
.card-grid & {
min-width: unset;
}
.actions {
position: absolute;
bottom: $mp-3;
right: $mp-3;
label {
display: none;
}
}
}
.preview-card-headings {
padding-top: $mp-3;
& > div:not(:last-child),
& .column > div {
margin-bottom: $mp-3;
}
preview-header:not(.no-cover) & .heading {
margin-bottom: $mp-3;
}
}
.header {
background-size: cover;
@ -723,34 +744,54 @@ nav li {
}
// -- program grid
// ---- card grid
.card-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: $mp-4;
}
.a-carousel-container {
width: 100%;
gap: $mp-4;
transition: margin-left 1s;
@media screen and (max-width: $screen-wide) {
.preview-card:not(.preview-header) {
height: 20em !important;
> * {
flex-shrink: 0;
}
}
.card-grid .preview-card {
height: 20em;
.a-carousel-button-container {
button, .button {
z-index:1000;
position: absolute;
display: flex;
flex-direction: column;
top: calc(var(--preview-cover-size) - $text-size-medium);
&.prev { left: -$mp-3e; }
&.next { right: -$mp-3e; }
}
}
// ---- responsive
@media screen and (max-width: $screen-wide) {
:root {
--preview-cover-size: 18em;
}
}
@media screen and (max-width: $screen-normal) {
.card-grid {
grid-template-columns: 1fr 1fr;
.preview-card:nth-child(3) {
display: none;
}
.page .container {
margin-left: $mp-4;
margin-right: $mp-4;
}
}
@media screen and (max-width: $screen-small) {
}
// ---- player

View File

@ -0,0 +1,184 @@
<template>
<div class="a-carousel-button-container" v-if="showPrevButton">
<button :class="[buttonClass, 'prev']" aria-label="Go left" @click="prev">
<span class="icon">
<i :class="leftButtonIcon"></i>
</span>
</button>
</div>
<div class="a-carousel-button-container" v-if="showNextButton">
<button :class="[buttonClass, 'next']" aria-label="Go left" @click="next">
<span class="icon">
<i :class="rightButtonIcon"></i>
</span>
</button>
</div>
<div ref="viewport" class="a-carousel-viewport">
<section ref="container" :class="['a-carousel-container', containerClass]">
<slot name="default"></slot>
</section>
</div>
</template>
<style scoped>
.a-carousel-viewport {
width: 100%;
overflow: hidden;
position: relative;
}
.a-carousel-container {
display: flex;
flex-direction: row;
align-items: left;
}
.a-carousel-container > * {
flex-shrink: 0;
}
</style>
<script>
import {ref} from 'vue'
export default {
setup() {
return {
viewport: ref(null),
container: ref(null),
}
},
data() {
return {
cards: [],
index: 0,
refresh_: 0,
}
},
props: {
cardSelector: {type: String, default: ''},
containerClass: {type: String, default: ''},
buttonClass: {type: String, default: 'button'},
leftButtonIcon: {type: String, default: "fas fa-chevron-left"},
rightButtonIcon: {type: String, default: "fas fa-chevron-right"},
},
computed: {
card() { return this.cards()[this.index] },
showPrevButton() {
return this.index > 0
},
showNextButton() {
if(!this.cards || this.cards.length <= 1)
return false
let { count } = this.visibility
return (this.index + count) < this.cards.length
},
visibility() {
// force refresh on index
[this.index, this.refresh_]
if(!this.cards)
return {min: -1, max: -1, count: 0};
const vOff = this.offset(this.$refs.viewport)
var [min, max] = [-1, -1]
for(let at=0; at < this.cards.length; at++) {
const card = this.cards[at]
const cOff = this.offset(card)
const visible = vOff.min <= cOff.min && vOff.max >= cOff.max
if(visible) {
if(min === -1)
min = parseInt(at)
max = parseInt(at)
}
}
if(max !== -1)
max++
return {
min, max,
count: (min !== -1) ? max-min : 0
}
},
},
methods: {
offset(el, parent=null) {
const rect = el.getBoundingClientRect()
const off = {min: rect.left, max: rect.right }
if(parent === null)
return off
const pOff = this.offset(parent)
return {
min: off.min - pOff.min,
max: off.max - pOff.max,
}
},
getCards() {
if(!this.cardSelector)
return this.$refs.container.children
return this.$refs.container.querySelectorAll(this.cardSelector)
},
selectIndex(index, relative=false) {
if(relative)
index = this.index + index
index = Math.min(this.cards.length, index)
const el = this.cards[index]
const elOff = this.offset(el, this.$refs.container)
this.$refs.container.style.marginLeft = `-${elOff.min}px`
this.index = index;
return el
},
next() {
if(!this.visibility.count)
return
let {count} = this.visibility
let at = Math.min(
count === 1 ? this.index+count : this.index+count-1,
this.cards.length-count
)
this.selectIndex(at)
},
prev() {
if(!this.visibility.count)
return
const {min, count} = this.visibility
let at = Math.max(0, min-count)
if(min < 0 || count <= 0)
return
this.selectIndex(at)
},
refresh() {
this.cards = this.getCards()
this.selectIndex(this.index)
this.refresh_++
}
},
mounted() {
this.observer = [
new MutationObserver(() => this.refresh()),
new ResizeObserver(() => this.refresh())
]
this.observer[0].observe(this.$refs.container, {"childList": true})
this.observer[1].observe(this.$refs.container)
this.refresh()
},
unmounted() {
for(var observer of this.observers)
observer.disconnect()
}
}
</script>

View File

@ -1,4 +1,5 @@
import AAutocomplete from './AAutocomplete.vue'
import ACarousel from './ACarousel.vue'
import ADropdown from "./ADropdown.vue"
import AEpisode from './AEpisode.vue'
import AList from './AList.vue'
@ -15,7 +16,7 @@ import AStreamer from './AStreamer.vue'
* Core components
*/
export const base = {
AAutocomplete, ADropdown, AEpisode, AList, APage, APlayer, APlaylist,
AAutocomplete, ACarousel, ADropdown, AEpisode, AList, APage, APlayer, APlaylist,
AProgress, ASoundItem,
}