From 189d329e76ce32d753425eda1cbffc094dd7142b Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Tue, 24 Mar 2026 16:46:46 -0400 Subject: [PATCH] new applet structure for apps.billboard, incl. My Scrolls, Contacts & Most Recent applets; completely revamped _billboard.scss, tho some styling inconsistencies persist; ensured #id_billboard_applets_container inherited base styles found in _applets.scss; a pair of new migrations in apps.applets to support new applet models & fields; billboard gets its first ITs, new urls & views; pair of new FT classes in FTs.test_billboard --- .../migrations/0006_billboard_applets.py | 48 +++++++ .../migrations/0007_fix_billboard_applets.py | 29 +++++ src/apps/applets/models.py | 2 + src/apps/billboard/tests/__init__.py | 0 .../billboard/tests/integrated/__init__.py | 0 .../tests/integrated/test_billboard_views.py | 111 ++++++++++++++++ src/apps/billboard/urls.py | 1 + src/apps/billboard/views.py | 44 ++++++- src/functional_tests/test_billboard.py | 119 +++++++++++++++++- src/static_src/scss/_applets.scss | 7 +- src/static_src/scss/_billboard.scss | 78 ++++++++++-- .../_applet-billboard-most-recent.html | 14 +++ .../_applet-billboard-my-contacts.html | 7 ++ .../_applet-billboard-my-scrolls.html | 15 +++ .../_partials/_applet-billboard-scroll.html | 4 + .../apps/billboard/_partials/_applets.html | 27 ++++ src/templates/apps/billboard/billboard.html | 12 +- src/templates/apps/billboard/room_scroll.html | 5 +- 18 files changed, 492 insertions(+), 31 deletions(-) create mode 100644 src/apps/applets/migrations/0006_billboard_applets.py create mode 100644 src/apps/applets/migrations/0007_fix_billboard_applets.py create mode 100644 src/apps/billboard/tests/__init__.py create mode 100644 src/apps/billboard/tests/integrated/__init__.py create mode 100644 src/apps/billboard/tests/integrated/test_billboard_views.py create mode 100644 src/templates/apps/billboard/_partials/_applet-billboard-most-recent.html create mode 100644 src/templates/apps/billboard/_partials/_applet-billboard-my-contacts.html create mode 100644 src/templates/apps/billboard/_partials/_applet-billboard-my-scrolls.html create mode 100644 src/templates/apps/billboard/_partials/_applet-billboard-scroll.html create mode 100644 src/templates/apps/billboard/_partials/_applets.html diff --git a/src/apps/applets/migrations/0006_billboard_applets.py b/src/apps/applets/migrations/0006_billboard_applets.py new file mode 100644 index 0000000..bd17d0f --- /dev/null +++ b/src/apps/applets/migrations/0006_billboard_applets.py @@ -0,0 +1,48 @@ +from django.db import migrations, models + + +def seed_billboard_applets(apps, schema_editor): + Applet = apps.get_model("applets", "Applet") + for slug, name, cols, rows in [ + ("billboard-my-scrolls", "My Scrolls", 4, 3), + ("billboard-my-contacts", "Contacts", 4, 3), + ("billboard-most-recent", "Most Recent", 8, 6), + ]: + Applet.objects.get_or_create( + slug=slug, + defaults={"name": name, "grid_cols": cols, "grid_rows": rows, "context": "billboard"}, + ) + + +def remove_billboard_applets(apps, schema_editor): + Applet = apps.get_model("applets", "Applet") + Applet.objects.filter(slug__in=[ + "billboard-my-scrolls", + "billboard-my-contacts", + "billboard-most-recent", + ]).delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ("applets", "0005_gameboard_applet_heights"), + ] + + operations = [ + migrations.AlterField( + model_name="applet", + name="context", + field=models.CharField( + choices=[ + ("dashboard", "Dashboard"), + ("gameboard", "Gameboard"), + ("wallet", "Wallet"), + ("billboard", "Billboard"), + ], + default="dashboard", + max_length=20, + ), + ), + migrations.RunPython(seed_billboard_applets, remove_billboard_applets), + ] diff --git a/src/apps/applets/migrations/0007_fix_billboard_applets.py b/src/apps/applets/migrations/0007_fix_billboard_applets.py new file mode 100644 index 0000000..fa31d32 --- /dev/null +++ b/src/apps/applets/migrations/0007_fix_billboard_applets.py @@ -0,0 +1,29 @@ +from django.db import migrations + + +def fix_billboard_applets(apps, schema_editor): + Applet = apps.get_model("applets", "Applet") + # billboard-scroll belongs only to the billscroll page template, not the grid + Applet.objects.filter(slug="billboard-scroll").delete() + # Rename "My Contacts" → "Contacts" + Applet.objects.filter(slug="billboard-my-contacts").update(name="Contacts") + + +def reverse_fix_billboard_applets(apps, schema_editor): + Applet = apps.get_model("applets", "Applet") + Applet.objects.get_or_create( + slug="billboard-scroll", + defaults={"name": "Billscroll", "grid_cols": 12, "grid_rows": 6, "context": "billboard"}, + ) + Applet.objects.filter(slug="billboard-my-contacts").update(name="My Contacts") + + +class Migration(migrations.Migration): + + dependencies = [ + ("applets", "0006_billboard_applets"), + ] + + operations = [ + migrations.RunPython(fix_billboard_applets, reverse_fix_billboard_applets), + ] diff --git a/src/apps/applets/models.py b/src/apps/applets/models.py index 95f4ea6..d7ec370 100644 --- a/src/apps/applets/models.py +++ b/src/apps/applets/models.py @@ -4,10 +4,12 @@ class Applet(models.Model): DASHBOARD = "dashboard" GAMEBOARD = "gameboard" WALLET = "wallet" + BILLBOARD = "billboard" CONTEXT_CHOICES = [ (DASHBOARD, "Dashboard"), (GAMEBOARD, "Gameboard"), (WALLET, "Wallet"), + (BILLBOARD, "Billboard"), ] slug = models.SlugField(unique=True) diff --git a/src/apps/billboard/tests/__init__.py b/src/apps/billboard/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/billboard/tests/integrated/__init__.py b/src/apps/billboard/tests/integrated/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/apps/billboard/tests/integrated/test_billboard_views.py b/src/apps/billboard/tests/integrated/test_billboard_views.py new file mode 100644 index 0000000..5114109 --- /dev/null +++ b/src/apps/billboard/tests/integrated/test_billboard_views.py @@ -0,0 +1,111 @@ +from django.test import TestCase +from django.urls import reverse + +from apps.applets.models import Applet +from apps.drama.models import GameEvent, record +from apps.epic.models import Room +from apps.lyric.models import User + + +def _seed_billboard_applets(): + for slug, name, cols, rows in [ + ("billboard-my-scrolls", "My Scrolls", 4, 3), + ("billboard-my-contacts", "Contacts", 4, 3), + ("billboard-most-recent", "Most Recent", 8, 6), + ]: + Applet.objects.get_or_create( + slug=slug, + defaults={"name": name, "grid_cols": cols, "grid_rows": rows, "context": "billboard"}, + ) + + +class BillboardViewTest(TestCase): + def setUp(self): + self.user = User.objects.create(email="test@billboard.io") + self.client.force_login(self.user) + _seed_billboard_applets() + + def test_uses_billboard_template(self): + response = self.client.get("/billboard/") + self.assertTemplateUsed(response, "apps/billboard/billboard.html") + + def test_passes_applets_context(self): + response = self.client.get("/billboard/") + self.assertIn("applets", response.context) + slugs = [e["applet"].slug for e in response.context["applets"]] + self.assertIn("billboard-my-scrolls", slugs) + self.assertIn("billboard-my-contacts", slugs) + self.assertIn("billboard-most-recent", slugs) + + def test_passes_my_rooms_context(self): + room = Room.objects.create(name="Test Room", owner=self.user) + response = self.client.get("/billboard/") + self.assertIn(room, response.context["my_rooms"]) + + def test_passes_recent_room_and_events(self): + room = Room.objects.create(name="Test Room", owner=self.user) + record( + room, GameEvent.SLOT_FILLED, actor=self.user, + slot_number=1, token_type="coin", + token_display="Coin-on-a-String", renewal_days=7, + ) + response = self.client.get("/billboard/") + self.assertEqual(response.context["recent_room"], room) + self.assertEqual(len(response.context["recent_events"]), 1) + + def test_recent_room_is_none_when_no_events(self): + response = self.client.get("/billboard/") + self.assertIsNone(response.context["recent_room"]) + self.assertEqual(list(response.context["recent_events"]), []) + + +class ToggleBillboardAppletsTest(TestCase): + def setUp(self): + self.user = User.objects.create(email="test@toggle.io") + self.client.force_login(self.user) + _seed_billboard_applets() + + def test_toggle_hides_unchecked_applets(self): + response = self.client.post( + reverse("billboard:toggle_applets"), + {"applets": ["billboard-my-scrolls"]}, + ) + self.assertEqual(response.status_code, 302) + from apps.applets.models import UserApplet + contacts = Applet.objects.get(slug="billboard-my-contacts") + ua = UserApplet.objects.get(user=self.user, applet=contacts) + self.assertFalse(ua.visible) + + def test_toggle_returns_partial_on_htmx(self): + response = self.client.post( + reverse("billboard:toggle_applets"), + {"applets": ["billboard-my-scrolls"]}, + HTTP_HX_REQUEST="true", + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "apps/billboard/_partials/_applets.html") + + +class BillscrollViewTest(TestCase): + def setUp(self): + self.user = User.objects.create(email="test@billscroll.io") + self.client.force_login(self.user) + self.room = Room.objects.create(name="Test Room", owner=self.user) + record( + self.room, GameEvent.SLOT_FILLED, actor=self.user, + slot_number=1, token_type="coin", + token_display="Coin-on-a-String", renewal_days=7, + ) + + def test_uses_room_scroll_template(self): + response = self.client.get(f"/billboard/room/{self.room.id}/scroll/") + self.assertTemplateUsed(response, "apps/billboard/room_scroll.html") + + def test_passes_events_context(self): + response = self.client.get(f"/billboard/room/{self.room.id}/scroll/") + self.assertIn("events", response.context) + self.assertEqual(response.context["events"].count(), 1) + + def test_passes_page_class_billscroll(self): + response = self.client.get(f"/billboard/room/{self.room.id}/scroll/") + self.assertEqual(response.context["page_class"], "page-billscroll") diff --git a/src/apps/billboard/urls.py b/src/apps/billboard/urls.py index d986dc1..e4527d3 100644 --- a/src/apps/billboard/urls.py +++ b/src/apps/billboard/urls.py @@ -6,5 +6,6 @@ app_name = "billboard" urlpatterns = [ path("", views.billboard, name="billboard"), + path("toggle-applets", views.toggle_billboard_applets, name="toggle_applets"), path("room//scroll/", views.room_scroll, name="scroll"), ] diff --git a/src/apps/billboard/views.py b/src/apps/billboard/views.py index 65d693a..b2a0826 100644 --- a/src/apps/billboard/views.py +++ b/src/apps/billboard/views.py @@ -1,7 +1,9 @@ from django.contrib.auth.decorators import login_required -from django.db.models import Q -from django.shortcuts import render +from django.db.models import Max, Q +from django.shortcuts import redirect, render +from apps.applets.models import Applet, UserApplet +from apps.applets.utils import applet_context from apps.drama.models import GameEvent from apps.epic.models import GateSlot, Room, RoomInvite @@ -13,12 +15,48 @@ def billboard(request): Q(gate_slots__gamer=request.user) | Q(invites__invitee_email=request.user.email, invites__status=RoomInvite.PENDING) ).distinct().order_by("-created_at") + + recent_room = ( + Room.objects.filter( + Q(owner=request.user) | Q(gate_slots__gamer=request.user) + ) + .annotate(last_event=Max("events__timestamp")) + .filter(last_event__isnull=False) + .order_by("-last_event") + .distinct() + .first() + ) + recent_events = ( + recent_room.events.select_related("actor").order_by("-timestamp")[:10] + if recent_room else [] + ) + return render(request, "apps/billboard/billboard.html", { "my_rooms": my_rooms, + "recent_room": recent_room, + "recent_events": recent_events, + "viewer": request.user, + "applets": applet_context(request.user, "billboard"), "page_class": "page-billboard", }) +@login_required(login_url="/") +def toggle_billboard_applets(request): + checked = request.POST.getlist("applets") + for applet in Applet.objects.filter(context="billboard"): + UserApplet.objects.update_or_create( + user=request.user, + applet=applet, + defaults={"visible": applet.slug in checked}, + ) + if request.headers.get("HX-Request"): + return render(request, "apps/billboard/_partials/_applets.html", { + "applets": applet_context(request.user, "billboard"), + }) + return redirect("billboard:billboard") + + @login_required(login_url="/") def room_scroll(request, room_id): room = Room.objects.get(id=room_id) @@ -27,5 +65,5 @@ def room_scroll(request, room_id): "room": room, "events": events, "viewer": request.user, - "page_class": "page-billboard", + "page_class": "page-billscroll", }) diff --git a/src/functional_tests/test_billboard.py b/src/functional_tests/test_billboard.py index 0163d6d..f699d19 100644 --- a/src/functional_tests/test_billboard.py +++ b/src/functional_tests/test_billboard.py @@ -1,6 +1,7 @@ from selenium.webdriver.common.by import By from .base import FunctionalTest +from apps.applets.models import Applet from apps.drama.models import GameEvent, record from apps.epic.models import Room, GateSlot from apps.lyric.models import User @@ -18,8 +19,17 @@ class BillboardScrollTest(FunctionalTest): def setUp(self): super().setUp() - self.founder = User.objects.create(email="founder@scroll.io") - self.other = User.objects.create(email="other@scroll.io") + for slug, name, cols, rows in [ + ("billboard-my-scrolls", "My Scrolls", 4, 3), + ("billboard-my-contacts", "Contacts", 4, 3), + ("billboard-most-recent", "Most Recent", 8, 6), + ]: + Applet.objects.get_or_create( + slug=slug, + defaults={"name": name, "grid_cols": cols, "grid_rows": rows, "context": "billboard"}, + ) + self.founder = User.objects.create(email="founder@test.io") + self.other = User.objects.create(email="other@test.io") self.room = Room.objects.create(name="Blissful Ignorance", owner=self.founder) # Simulate two gate fills — one by founder, one by the other gamer record( @@ -44,7 +54,7 @@ class BillboardScrollTest(FunctionalTest): def test_footer_scroll_icon_leads_to_billboard_with_rooms(self): # Founder logs in and lands on the dashboard - self.create_pre_authenticated_session("founder@scroll.io") + self.create_pre_authenticated_session("founder@test.io") self.browser.get(self.live_server_url + "/") # Footer contains a scroll icon link pointing to /billboard/ @@ -65,7 +75,7 @@ class BillboardScrollTest(FunctionalTest): # ------------------------------------------------------------------ # def test_scroll_shows_human_readable_event_log(self): - self.create_pre_authenticated_session("founder@scroll.io") + self.create_pre_authenticated_session("founder@test.io") self.browser.get(self.live_server_url + "/billboard/") # Click the room link to reach the scroll @@ -93,7 +103,7 @@ class BillboardScrollTest(FunctionalTest): # ------------------------------------------------------------------ # def test_scroll_aligns_own_events_right_and_others_left(self): - self.create_pre_authenticated_session("founder@scroll.io") + self.create_pre_authenticated_session("founder@test.io") self.browser.get(self.live_server_url + "/billboard/") self.wait_for( lambda: self.browser.find_element(By.LINK_TEXT, "Blissful Ignorance") @@ -111,3 +121,102 @@ class BillboardScrollTest(FunctionalTest): # The other gamer's event mentions their display name self.assertIn("other", theirs_events[0].text) + + +class BillboardAppletsTest(FunctionalTest): + """ + FT: billboard page renders three applets in the grid — My Scrolls, + My Contacts, and Most Recent — with a functioning gear menu. + """ + + def setUp(self): + super().setUp() + self.founder = User.objects.create(email="founder@test.io") + self.room = Room.objects.create(name="Arcane Assembly", owner=self.founder) + for slug, name, cols, rows in [ + ("billboard-my-scrolls", "My Scrolls", 4, 3), + ("billboard-my-contacts", "Contacts", 4, 3), + ("billboard-most-recent", "Most Recent", 8, 6), + ]: + Applet.objects.get_or_create( + slug=slug, + defaults={"name": name, "grid_cols": cols, "grid_rows": rows, "context": "billboard"}, + ) + + def test_billboard_shows_three_applets(self): + # 1. Log in, navigate to billboard + self.create_pre_authenticated_session("founder@test.io") + self.browser.get(self.live_server_url + "/billboard/") + # 2. Assert all three applet sections present + self.wait_for( + lambda: self.browser.find_element(By.ID, "id_applet_billboard_my_scrolls") + ) + self.browser.find_element(By.ID, "id_applet_billboard_my_contacts") + self.browser.find_element(By.ID, "id_applet_billboard_most_recent") + + def test_billboard_my_scrolls_lists_rooms(self): + # 1. Log in, navigate to billboard + self.create_pre_authenticated_session("founder@test.io") + self.browser.get(self.live_server_url + "/billboard/") + # 2. My Scrolls applet contains a link to the room's scroll + self.wait_for( + lambda: self.assertIn( + "Arcane Assembly", + self.browser.find_element(By.ID, "id_applet_billboard_my_scrolls").text, + ) + ) + + def test_billboard_gear_btn_opens_applet_menu(self): + # 1. Log in, navigate to billboard + self.create_pre_authenticated_session("founder@test.io") + self.browser.get(self.live_server_url + "/billboard/") + # 2. Gear button is visible + gear_btn = self.wait_for( + lambda: self.browser.find_element(By.CSS_SELECTOR, ".billboard-page .gear-btn") + ) + # 3. Menu is hidden before click + menu = self.browser.find_element(By.ID, "id_billboard_applet_menu") + self.assertFalse(menu.is_displayed()) + # 4. Clicking gear opens the menu (JS click bypasses kit-bag overlap in headless) + self.browser.execute_script("arguments[0].click()", gear_btn) + self.wait_for_slow(lambda: self.assertTrue(menu.is_displayed())) + + +class BillscrollAppletsTest(FunctionalTest): + """ + FT: billscroll page renders as a single full-width applet that fills + the viewport aperture and contains the room's drama events. + """ + + def setUp(self): + super().setUp() + self.founder = User.objects.create(email="founder@billtest.io") + self.room = Room.objects.create(name="Spectral Council", owner=self.founder) + record( + self.room, GameEvent.SLOT_FILLED, actor=self.founder, + slot_number=1, token_type="coin", + token_display="Coin-on-a-String", renewal_days=7, + ) + + def test_billscroll_shows_full_width_applet(self): + # 1. Log in, navigate to the room's scroll + self.create_pre_authenticated_session("founder@billtest.io") + self.browser.get( + self.live_server_url + f"/billboard/room/{self.room.id}/scroll/" + ) + # 2. The full-width applet section is present + self.wait_for( + lambda: self.browser.find_element(By.ID, "id_applet_billboard_scroll") + ) + + def test_billscroll_applet_contains_drama_events(self): + # 1. Log in, navigate to the room's scroll + self.create_pre_authenticated_session("founder@billtest.io") + self.browser.get( + self.live_server_url + f"/billboard/room/{self.room.id}/scroll/" + ) + # 2. Drama scroll is inside the applet and shows the event + scroll = self.wait_for( + lambda: self.browser.find_element(By.ID, "id_drama_scroll") + ) + self.assertIn("Coin-on-a-String", scroll.text) diff --git a/src/static_src/scss/_applets.scss b/src/static_src/scss/_applets.scss index ecbbf4a..f6f5b42 100644 --- a/src/static_src/scss/_applets.scss +++ b/src/static_src/scss/_applets.scss @@ -205,6 +205,7 @@ } } -#id_applets_container { @extend %applets-grid; } -#id_game_applets_container { @extend %applets-grid; } -#id_wallet_applets_container { @extend %applets-grid; } +#id_applets_container { @extend %applets-grid; } +#id_game_applets_container { @extend %applets-grid; } +#id_wallet_applets_container { @extend %applets-grid; } +#id_billboard_applets_container { @extend %applets-grid; } diff --git a/src/static_src/scss/_billboard.scss b/src/static_src/scss/_billboard.scss index 21efb62..00b4464 100644 --- a/src/static_src/scss/_billboard.scss +++ b/src/static_src/scss/_billboard.scss @@ -1,8 +1,21 @@ -html:has(body.page-billboard) { +// ── Shared aperture fill for both billboard pages ────────────────────────── + +%billboard-page-base { + flex: 1; + min-width: 0; + min-height: 0; + overflow-y: auto; + position: relative; + padding: 0.75rem; +} + +html:has(body.page-billboard), +html:has(body.page-billscroll) { overflow: hidden; } -body.page-billboard { +body.page-billboard, +body.page-billscroll { overflow: hidden; .container { @@ -19,10 +32,61 @@ body.page-billboard { } } +// ── Billboard page (three-applet grid) ───────────────────────────────────── + .billboard-page { - flex: 1; - min-width: 0; - overflow-y: auto; - position: relative; - padding: 0.75rem; + @extend %billboard-page-base; + + // Gear btn positioning mirrors dashboard/wallet pattern + > .gear-btn { + position: fixed; + bottom: calc(var(--footer-w, 4rem) + 0.75rem); + right: calc(var(--footer-w, 4rem) + 0.75rem); + z-index: 10; + } +} + +// ── Billscroll page (single full-aperture applet) ────────────────────────── + +.billscroll-page { + @extend %billboard-page-base; + display: flex; + flex-direction: column; + padding: 0.75rem; + + // The single scroll applet stretches to fill the remaining aperture + .applet-billboard-scroll { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + // Override grid-row span — this applet fills height via flex, not grid rows + grid-row: unset; + + #id_drama_scroll { + flex: 1; + min-height: 0; + overflow-y: auto; + } + } +} + +// ── My Scrolls list ──────────────────────────────────────────────────────── + +#id_applet_billboard_my_scrolls { + .scroll-list { + list-style: none; + padding: 0; + margin: 0; + overflow-y: auto; + + li { + padding: 0.25rem 0; + border-bottom: 1px solid rgba(var(--priUser), 0.15); + + &:last-child { border-bottom: none; } + + a { text-decoration: none; } + } + } } diff --git a/src/templates/apps/billboard/_partials/_applet-billboard-most-recent.html b/src/templates/apps/billboard/_partials/_applet-billboard-most-recent.html new file mode 100644 index 0000000..9a04953 --- /dev/null +++ b/src/templates/apps/billboard/_partials/_applet-billboard-most-recent.html @@ -0,0 +1,14 @@ +
+

Most Recent

+ {% if recent_room %} + {{ recent_room.name }} + {% with events=recent_events %} + {% include "core/_partials/_scroll.html" %} + {% endwith %} + {% else %} +

No recent activity.

+ {% endif %} +
diff --git a/src/templates/apps/billboard/_partials/_applet-billboard-my-contacts.html b/src/templates/apps/billboard/_partials/_applet-billboard-my-contacts.html new file mode 100644 index 0000000..d277a2d --- /dev/null +++ b/src/templates/apps/billboard/_partials/_applet-billboard-my-contacts.html @@ -0,0 +1,7 @@ +
+

Contacts

+

Coming soon.

+
diff --git a/src/templates/apps/billboard/_partials/_applet-billboard-my-scrolls.html b/src/templates/apps/billboard/_partials/_applet-billboard-my-scrolls.html new file mode 100644 index 0000000..cd2ac3f --- /dev/null +++ b/src/templates/apps/billboard/_partials/_applet-billboard-my-scrolls.html @@ -0,0 +1,15 @@ +
+

My Scrolls

+
    + {% for room in my_rooms %} +
  • + {{ room.name }} +
  • + {% empty %} +
  • No scrolls yet.
  • + {% endfor %} +
+
diff --git a/src/templates/apps/billboard/_partials/_applet-billboard-scroll.html b/src/templates/apps/billboard/_partials/_applet-billboard-scroll.html new file mode 100644 index 0000000..b172314 --- /dev/null +++ b/src/templates/apps/billboard/_partials/_applet-billboard-scroll.html @@ -0,0 +1,4 @@ +
+

{{ room.name }}

+ {% include "core/_partials/_scroll.html" %} +
diff --git a/src/templates/apps/billboard/_partials/_applets.html b/src/templates/apps/billboard/_partials/_applets.html new file mode 100644 index 0000000..a5082f3 --- /dev/null +++ b/src/templates/apps/billboard/_partials/_applets.html @@ -0,0 +1,27 @@ +
+ + {% include "apps/applets/_partials/_applets.html" %} +
diff --git a/src/templates/apps/billboard/billboard.html b/src/templates/apps/billboard/billboard.html index aaa604c..be350d4 100644 --- a/src/templates/apps/billboard/billboard.html +++ b/src/templates/apps/billboard/billboard.html @@ -5,15 +5,7 @@ {% block content %}
-

My Scrolls

-
    - {% for room in my_rooms %} -
  • - {{ room.name }} -
  • - {% empty %} -
  • No scrolls yet.
  • - {% endfor %} -
+ {% include "apps/applets/_partials/_gear.html" with menu_id="id_billboard_applet_menu" %} + {% include "apps/billboard/_partials/_applets.html" %}
{% endblock %} diff --git a/src/templates/apps/billboard/room_scroll.html b/src/templates/apps/billboard/room_scroll.html index 567fc0e..05b5120 100644 --- a/src/templates/apps/billboard/room_scroll.html +++ b/src/templates/apps/billboard/room_scroll.html @@ -4,8 +4,7 @@ {% block header_text %}Billscroll{% endblock header_text %} {% block content %} -
-

{{ room.name }}

- {% include "core/_partials/_scroll.html" %} +
+ {% include "apps/billboard/_partials/_applet-billboard-scroll.html" %}
{% endblock %}