From 46a9008cda9538356c8f4cd5b14fce4b01478bb9 Mon Sep 17 00:00:00 2001 From: bkfox Date: Tue, 12 Dec 2023 20:07:58 +0100 Subject: [PATCH] navigation & breadcrumbs --- aircox/models/episode.py | 1 + aircox/models/page.py | 78 +++++++------ aircox/models/program.py | 1 + aircox/static/aircox/css/admin.css | 73 +++--------- aircox/static/aircox/css/public.css | 108 ++++++++---------- aircox/static/aircox/js/chunk-common.js | 2 +- aircox/templates/admin/index.html | 2 +- aircox/templates/aircox/base.html | 39 ++++--- aircox/templates/aircox/home.html | 4 +- aircox/templates/aircox/page_detail.html | 32 +++--- aircox/templates/aircox/page_list.html | 38 +++++- aircox/templates/aircox/timetable_list.html | 31 +++++ .../templates/aircox/widgets/breadcrumbs.html | 15 +++ aircox/templates/aircox/widgets/carousel.html | 4 +- aircox/templates/aircox/widgets/player.html | 3 +- aircox/urls.py | 52 ++++----- aircox/views/__init__.py | 14 ++- aircox/views/article.py | 2 +- aircox/views/base.py | 22 ++++ aircox/views/diffusion.py | 43 +++++-- aircox/views/episode.py | 4 +- aircox/views/home.py | 2 +- aircox/views/log.py | 5 +- aircox/views/mixins.py | 15 +-- aircox/views/page.py | 70 ++++++++---- aircox/views/program.py | 2 +- assets/src/assets/components.scss | 88 +++----------- assets/src/assets/public.scss | 49 +++++--- assets/src/index.js | 2 +- 29 files changed, 454 insertions(+), 347 deletions(-) create mode 100644 aircox/templates/aircox/timetable_list.html create mode 100644 aircox/templates/aircox/widgets/breadcrumbs.html diff --git a/aircox/models/episode.py b/aircox/models/episode.py index a329bfc..dfc1450 100644 --- a/aircox/models/episode.py +++ b/aircox/models/episode.py @@ -18,6 +18,7 @@ class EpisodeQuerySet(ProgramChildQuerySet): class Episode(Page): objects = EpisodeQuerySet.as_manager() detail_url_name = "episode-detail" + list_url_name = "episode-list" template_prefix = "episode" @property diff --git a/aircox/models/page.py b/aircox/models/page.py index f59fbd8..062c1ae 100644 --- a/aircox/models/page.py +++ b/aircox/models/page.py @@ -139,7 +139,9 @@ class BasePage(Renderable, models.Model): super().save(*args, **kwargs) def get_absolute_url(self): - return reverse(self.detail_url_name, kwargs={"slug": self.slug}) if self.is_published else "#" + if self.is_published: + return reverse(self.detail_url_name, kwargs={"slug": self.slug}) + return "" @property def is_draft(self): @@ -216,6 +218,8 @@ class Page(BasePage): ) objects = PageQuerySet.as_manager() + detail_url_name = "" + list_url_name = "page-list" @cached_property def parent_subclass(self): @@ -223,6 +227,15 @@ class Page(BasePage): return Page.objects.get_subclass(id=self.parent_id) return None + def get_absolute_url(self): + if not self.is_published and self.parent_subclass: + return self.parent_subclass.get_absolute_url() + return super().get_absolute_url() + + @classmethod + def get_list_url(cls, kwargs={}): + return reverse(cls.list_url_name, kwargs=kwargs) + class Meta: verbose_name = _("Publication") verbose_name_plural = _("Publications") @@ -243,46 +256,32 @@ class StaticPage(BasePage): detail_url_name = "static-page-detail" - ATTACH_TO_HOME = 0x00 - ATTACH_TO_DIFFUSIONS = 0x01 - ATTACH_TO_LOGS = 0x02 - ATTACH_TO_PROGRAMS = 0x03 - ATTACH_TO_EPISODES = 0x04 - ATTACH_TO_ARTICLES = 0x05 - ATTACH_TO_PAGES = 0x06 - ATTACH_TO_PODCASTS = 0x07 + class Target(models.TextChoices): + HOME = "", _("Home Page") + TIMETABLE = "timetable-list", _("Timetable") + PROGRAMS = "program-list", _("Programs list") + EPISODES = "episode-list", _("Episodes list") + ARTICLES = "article-list", _("Articles list") + PAGES = "page-list", _("Publications list") + PODCASTS = "podcast-list", _("Podcasts list") - ATTACH_TO_CHOICES = ( - (ATTACH_TO_HOME, _("Home page")), - (ATTACH_TO_DIFFUSIONS, _("Diffusions page")), - (ATTACH_TO_LOGS, _("Logs page")), - (ATTACH_TO_PROGRAMS, _("Programs list")), - (ATTACH_TO_EPISODES, _("Episodes list")), - (ATTACH_TO_ARTICLES, _("Articles list")), - (ATTACH_TO_PAGES, _("Publications list")), - (ATTACH_TO_PODCASTS, _("Podcasts list")), - ) - VIEWS = { - ATTACH_TO_HOME: "home", - ATTACH_TO_DIFFUSIONS: "diffusion-list", - ATTACH_TO_LOGS: "log-list", - ATTACH_TO_PROGRAMS: "program-list", - ATTACH_TO_EPISODES: "episode-list", - ATTACH_TO_ARTICLES: "article-list", - ATTACH_TO_PAGES: "page-list", - } - - attach_to = models.SmallIntegerField( + attach_to = models.CharField( _("attach to"), - choices=ATTACH_TO_CHOICES, + choices=Target.choices, + max_length=32, blank=True, null=True, help_text=_("display this page content to related element"), ) + def get_related_view(self): + from ..views import attached + + return self.attach_to and attached.get(self.attach_to) or None + def get_absolute_url(self): if self.attach_to: - return reverse(self.VIEWS[self.attach_to]) + return reverse(self.attach_to) return super().get_absolute_url() @@ -320,7 +319,7 @@ class NavItem(models.Model): station = models.ForeignKey(Station, models.CASCADE, verbose_name=_("station")) menu = models.SlugField(_("menu"), max_length=24) order = models.PositiveSmallIntegerField(_("order")) - text = models.CharField(_("title"), max_length=64) + text = models.CharField(_("title"), max_length=64, blank=True, null=True) url = models.CharField(_("url"), max_length=256, blank=True, null=True) page = models.ForeignKey( StaticPage, @@ -339,14 +338,21 @@ class NavItem(models.Model): def get_url(self): return self.url if self.url else self.page.get_absolute_url() if self.page else None + def get_label(self): + if self.text: + return self.text + elif self.page: + return self.page.title + def render(self, request, css_class="", active_class=""): url = self.get_url() + text = self.get_text() if active_class and request.path.startswith(url): css_class += " " + active_class if not url: - return self.text + return text elif not css_class: - return format_html('{}', url, self.text) + return format_html('{}', url, text) else: - return format_html('{}', url, css_class, self.text) + return format_html('{}', url, css_class, text) diff --git a/aircox/models/program.py b/aircox/models/program.py index 7a4fd16..c5c1d76 100644 --- a/aircox/models/program.py +++ b/aircox/models/program.py @@ -61,6 +61,7 @@ class Program(Page): objects = ProgramQuerySet.as_manager() detail_url_name = "program-detail" + list_url_name = "program-list" @property def path(self): diff --git a/aircox/static/aircox/css/admin.css b/aircox/static/aircox/css/admin.css index 1f4b425..dc72036 100644 --- a/aircox/static/aircox/css/admin.css +++ b/aircox/static/aircox/css/admin.css @@ -33,9 +33,9 @@ --a-player-panel-bg: var(--highlight-color); --a-player-bar-bg: var(--highlight-color); --a-player-bar-title-alone-sz: 1.6rem; - --button-fg: var(--text-color); + --button-fg: var(--highlight-color-2); --button-bg: var(--highlight-color); - --button-hg-fg: var(--highlight-color-2); + --button-hg-fg: var(--text-color); --button-hg-bg: var(--highlight-color); --button-active-fg: var(--highlight-color); --button-active-bg: var(--highlight-color-2); @@ -234,6 +234,14 @@ height: var(--preview-cover-size); width: var(--preview-cover-size); } +.preview-card.small { + height: var(--preview-cover-small-size); + width: var(--preview-cover-small-size); +} +.preview-card.tiny { + height: var(--preview-cover-tiny-size); + width: var(--preview-cover-tiny-size); +} .preview-card:not(.header) { box-shadow: 0em 0em 1em rgba(0, 0, 0, 0.2); } @@ -259,57 +267,6 @@ preview-header:not(.no-cover) .card-headings .heading, preview-header:not(.no-co margin-bottom: 0.6rem; } -.header.preview-header { - align-items: start; - gap: 0.6rem; - min-height: unset; - padding-top: 0.6rem !important; -} -.header .headings { - width: unset; - flex-grow: 1; - padding-top: 0 !important; - display: flex; - flex-direction: column; -} -.header.has-cover { - min-height: calc(var(--header-height) / 2); -} -.header .title { - font-size: 40px; -} -.header .subtitle { - font-size: 32px; -} - -.header-cover:not(:only-child) { - float: right; - height: var(--header-height); - max-width: calc(var(--header-height) * 2); - margin: 0 0 1.2rem 1.2rem; -} - -.header-cover:only-child { - with: 100%; -} - -@media screen and (max-width: 600px) { - .container.header { - width: 100%; - } - .container.header .headings { - width: 100%; - clear: both; - } - .container.header .header-cover { - float: none; - width: 100%; - max-width: unset; - height: unset; - margin-left: 0rem; - margin-right: 0rem; - } -} .card-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; @@ -430,6 +387,12 @@ preview-header:not(.no-cover) .card-headings .heading, preview-header:not(.no-co .a-player a { color: var(--a-player-url-fg); } +.a-player .button { + color: var(--text-black); +} +.a-player .button:hover { + color: var(--button-fg); +} .a-player-panels { background: var(--a-player-panel-bg); @@ -2719,12 +2682,12 @@ a.navbar-item:focus, a.navbar-item:focus-within, a.navbar-item:hover, a.navbar-i #player .button, #player a.button, #player button.button, #player .nav-urls a, .ax .button, .ax a.button, .ax button.button, .ax .nav-urls a { display: inline-block; - padding: 0.6em; - border-radius: 4px; + padding: 0.4em; border: 1px var(--highlight-color-2-alpha) solid; justify-content: center; text-align: center; font-size: 1.4rem; + color: var(--button-fg); background-color: var(--button-bg); } #player .button .icon, #player a.button .icon, #player button.button .icon, #player .nav-urls a .icon, .ax .button .icon, .ax a.button .icon, .ax button.button .icon, .ax .nav-urls a .icon { diff --git a/aircox/static/aircox/css/public.css b/aircox/static/aircox/css/public.css index 3cb24be..d68702e 100644 --- a/aircox/static/aircox/css/public.css +++ b/aircox/static/aircox/css/public.css @@ -33,9 +33,9 @@ --a-player-panel-bg: var(--highlight-color); --a-player-bar-bg: var(--highlight-color); --a-player-bar-title-alone-sz: 1.6rem; - --button-fg: var(--text-color); + --button-fg: var(--highlight-color-2); --button-bg: var(--highlight-color); - --button-hg-fg: var(--highlight-color-2); + --button-hg-fg: var(--text-color); --button-hg-bg: var(--highlight-color); --button-active-fg: var(--highlight-color); --button-active-bg: var(--highlight-color-2); @@ -234,6 +234,14 @@ height: var(--preview-cover-size); width: var(--preview-cover-size); } +.preview-card.small { + height: var(--preview-cover-small-size); + width: var(--preview-cover-small-size); +} +.preview-card.tiny { + height: var(--preview-cover-tiny-size); + width: var(--preview-cover-tiny-size); +} .preview-card:not(.header) { box-shadow: 0em 0em 1em rgba(0, 0, 0, 0.2); } @@ -259,57 +267,6 @@ preview-header:not(.no-cover) .card-headings .heading, preview-header:not(.no-co margin-bottom: 0.6rem; } -.header.preview-header { - align-items: start; - gap: 0.6rem; - min-height: unset; - padding-top: 0.6rem !important; -} -.header .headings { - width: unset; - flex-grow: 1; - padding-top: 0 !important; - display: flex; - flex-direction: column; -} -.header.has-cover { - min-height: calc(var(--header-height) / 2); -} -.header .title { - font-size: 40px; -} -.header .subtitle { - font-size: 32px; -} - -.header-cover:not(:only-child) { - float: right; - height: var(--header-height); - max-width: calc(var(--header-height) * 2); - margin: 0 0 1.2rem 1.2rem; -} - -.header-cover:only-child { - with: 100%; -} - -@media screen and (max-width: 600px) { - .container.header { - width: 100%; - } - .container.header .headings { - width: 100%; - clear: both; - } - .container.header .header-cover { - float: none; - width: 100%; - max-width: unset; - height: unset; - margin-left: 0rem; - margin-right: 0rem; - } -} .card-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; @@ -430,6 +387,12 @@ preview-header:not(.no-cover) .card-headings .heading, preview-header:not(.no-co .a-player a { color: var(--a-player-url-fg); } +.a-player .button { + color: var(--text-black); +} +.a-player .button:hover { + color: var(--button-fg); +} .a-player-panels { background: var(--a-player-panel-bg); @@ -7381,6 +7344,9 @@ a.tag:hover { text-decoration: none; padding: 0.4rem; } +.page a:hover { + color: var(--text-color); +} .page section.container { padding-top: 2rem; } @@ -7419,12 +7385,12 @@ a.tag:hover { .button, a.button, button.button, .nav-urls a { display: inline-block; - padding: 0.6em; - border-radius: 4px; + padding: 0.4em; border: 1px var(--highlight-color-2-alpha) solid; justify-content: center; text-align: center; font-size: 1.4rem; + color: var(--button-fg); background-color: var(--button-bg); } .button .icon, a.button .icon, button.button .icon, .nav-urls a .icon { @@ -7487,7 +7453,6 @@ a.tag:hover { display: none; } .actions button, .actions .action { - background-color: var(--highlight-color); justify-content: center; min-width: 2rem; } @@ -7500,9 +7465,6 @@ a.tag:hover { .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; -} .label, .textarea, .input, .select { font-size: 1.4rem; @@ -7520,6 +7482,10 @@ a.tag:hover { margin-top: 0.6rem; } +.navs { + position: relative; +} + .nav { display: flex; background-color: var(--highlight-color); @@ -7547,7 +7513,7 @@ a.tag:hover { vertical-align: top; display: inline-block; } -.nav .nav-item.active { +.nav .nav-item.active, .nav .nav-item:hover { background-color: var(--highlight-color-2); color: var(--highlight-color); } @@ -7581,12 +7547,32 @@ a.tag:hover { white-space: nowrap; } .nav.secondary { + position: absolute; + width: 100%; + z-index: 100; + box-shadow: 0em 0.5em 0.5em rgba(0, 0, 0, 0.05); justify-content: right; + display: none; +} +.nav-item:hover + .nav.secondary, .nav.secondary:hover { + display: flex; + top: var(--nav-primary-height); + left: 0rem; } .nav.secondary .nav-item { font-size: 1rem; } +.breadcrumbs { + text-align: right; + height: 2.2rem; + margin-bottom: 0.4rem; +} +.breadcrumbs a + a:before { + content: "/"; + margin: 0 0.4rem; +} + @media screen and (max-width: 1024px) { .page { margin-top: var(--nav-primary-height); @@ -7685,7 +7671,7 @@ nav li a, nav li .button { flex-direction: column; } .header.has-cover { - min-height: calc(var(--header-height) / 2); + min-height: calc(var(--header-height) / 3); } .header .title { font-size: 40px; diff --git a/aircox/static/aircox/js/chunk-common.js b/aircox/static/aircox/js/chunk-common.js index d3e6547..4f8dc18 100644 --- a/aircox/static/aircox/js/chunk-common.js +++ b/aircox/static/aircox/js/chunk-common.js @@ -375,7 +375,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 import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./app */ \"./src/app.js\");\n/* harmony import */ var _vueLoader__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./vueLoader */ \"./src/vueLoader.js\");\n/* harmony import */ var _sound__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./sound */ \"./src/sound.js\");\n/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./model */ \"./src/model.js\");\n/* harmony import */ var _assets_common_scss__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./assets/common.scss */ \"./src/assets/common.scss\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n//-- aircox\n\n\n\n\n\nwindow.aircox = {\n // main application\n loader: null,\n get app() {\n return this.loader.app;\n },\n // player application\n playerLoader: null,\n get playerApp() {\n return this.playerLoader && this.playerLoader.app;\n },\n get player() {\n return this.playerLoader.vm && this.playerLoader.vm.$refs.player;\n },\n Set: _model__WEBPACK_IMPORTED_MODULE_4__.Set,\n Sound: _sound__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n /**\n * Initialize main application and player.\n */\n init(props = null, {\n hotReload = false,\n el = null,\n config = null,\n playerConfig = null,\n initApp = true,\n initPlayer = true,\n loader = null,\n playerLoader = null\n } = {}) {\n if (initPlayer) {\n playerConfig = playerConfig || _app__WEBPACK_IMPORTED_MODULE_1__.PlayerApp;\n playerLoader = playerLoader || new _vueLoader__WEBPACK_IMPORTED_MODULE_2__[\"default\"](playerConfig);\n playerLoader.enable(false);\n this.playerLoader = playerLoader;\n }\n if (initApp) {\n config = config || window.App || _app__WEBPACK_IMPORTED_MODULE_1__[\"default\"];\n config.el = el || config.el;\n loader = loader || new _vueLoader__WEBPACK_IMPORTED_MODULE_2__[\"default\"]({\n el,\n props,\n ...config\n });\n loader.enable(hotReload);\n this.loader = loader;\n }\n },\n /**\n * Filter navbar dropdown menu items\n */\n filter_menu(event) {\n var filter = new RegExp(event.target.value, 'gi');\n var container = event.target.closest('.navbar-dropdown');\n if (event.target.value) for (let item of container.querySelectorAll('a.navbar-item')) item.style.display = item.innerHTML.search(filter) == -1 ? 'none' : null;else for (let item of container.querySelectorAll('a.navbar-item')) item.style.display = null;\n },\n pickDate(url, date) {\n url = `${url}?date=${date.id}`;\n this.builder.fetch(url);\n }\n};\n\n//# sourceURL=webpack://aircox-assets/./src/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./app */ \"./src/app.js\");\n/* harmony import */ var _vueLoader__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./vueLoader */ \"./src/vueLoader.js\");\n/* harmony import */ var _sound__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./sound */ \"./src/sound.js\");\n/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./model */ \"./src/model.js\");\n/* harmony import */ var _assets_common_scss__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./assets/common.scss */ \"./src/assets/common.scss\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n//-- aircox\n\n\n\n\n\nwindow.aircox = {\n // main application\n loader: null,\n get app() {\n return this.loader.app;\n },\n // player application\n playerLoader: null,\n get playerApp() {\n return this.playerLoader && this.playerLoader.app;\n },\n get player() {\n return this.playerLoader.vm && this.playerLoader.vm.$refs.player;\n },\n Set: _model__WEBPACK_IMPORTED_MODULE_4__.Set,\n Sound: _sound__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n /**\n * Initialize main application and player.\n */\n init(props = null, {\n hotReload = false,\n el = null,\n config = null,\n playerConfig = null,\n initApp = true,\n initPlayer = true,\n loader = null,\n playerLoader = null\n } = {}) {\n if (initPlayer) {\n playerConfig = playerConfig || _app__WEBPACK_IMPORTED_MODULE_1__.PlayerApp;\n playerLoader = playerLoader || new _vueLoader__WEBPACK_IMPORTED_MODULE_2__[\"default\"](playerConfig);\n playerLoader.enable(false);\n this.playerLoader = playerLoader;\n }\n if (initApp) {\n config = config || window.App || _app__WEBPACK_IMPORTED_MODULE_1__[\"default\"];\n config.el = el || config.el;\n loader = loader || new _vueLoader__WEBPACK_IMPORTED_MODULE_2__[\"default\"]({\n el,\n props,\n ...config\n });\n loader.enable(hotReload);\n this.loader = loader;\n }\n },\n /**\n * Filter navbar dropdown menu items\n */\n filter_menu(event) {\n var filter = new RegExp(event.target.value, 'gi');\n var container = event.target.closest('.navbar-dropdown');\n if (event.target.value) for (let item of container.querySelectorAll('a.navbar-item')) item.style.display = item.innerHTML.search(filter) == -1 ? 'none' : null;else for (let item of container.querySelectorAll('a.navbar-item')) item.style.display = null;\n },\n pickDate(url, date) {\n url = `${url}?date=${date.id}`;\n this.loader.pageLoad.load(url);\n }\n};\n\n//# sourceURL=webpack://aircox-assets/./src/index.js?"); /***/ }), diff --git a/aircox/templates/admin/index.html b/aircox/templates/admin/index.html index ca8d0d3..72447b5 100644 --- a/aircox/templates/admin/index.html +++ b/aircox/templates/admin/index.html @@ -14,7 +14,7 @@ {% if diffusions %}
{% for obj in diffusions %} - {% page_widget "card" obj.episode diffusion=obj timetable=True admin=True tag_class="small" %} + {% page_widget "card" obj.episode diffusion=obj timetable=True admin=True tag_class="" %} {% endfor %}
{% else %} diff --git a/aircox/templates/aircox/base.html b/aircox/templates/aircox/base.html index ade4a3b..b2d6f91 100644 --- a/aircox/templates/aircox/base.html +++ b/aircox/templates/aircox/base.html @@ -61,6 +61,22 @@ Usefull context: aria-label="{% translate "Main menu" %}"> {% endblock %} @@ -79,6 +96,14 @@ Usefull context: {% block secondary-nav %}{% endblock %} + {% spaceless %} + {% block breadcrumbs-container %} + + {% endblock %} + {% endspaceless %} + {% block main-container %}
{% block main %} @@ -99,20 +124,6 @@ Usefull context: {% block subtitle %} {% if subtitle %} {{ subtitle }} - {% elif parent and parent.is_published %} - - - - - {{ parent.title }} - - {% elif page and page.category %} - - - - - {{ page.category.title }} - {% endif %} {% endblock %} diff --git a/aircox/templates/aircox/home.html b/aircox/templates/aircox/home.html index 2360fae..0330e80 100644 --- a/aircox/templates/aircox/home.html +++ b/aircox/templates/aircox/home.html @@ -3,6 +3,8 @@ {% block head_title %}{{ station.name }}{% endblock %} +{% block breadcrumbs-container %}{% endblock %} + {% block content-container %} {{ block.super }} @@ -40,7 +42,7 @@ {% endfor %}