Remove TOC
This commit is contained in:
@ -1,34 +1,34 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-lg-3">{{ toc|safe }}</div>
|
||||
<div class="col-lg-9">
|
||||
<div class="row">
|
||||
{% for game in games %}
|
||||
<div class="col-xl-3 col-lg-4 col-md-6 col-sm-12 mb-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<img src="{{ game.image_url }}"
|
||||
class="card-img-top"
|
||||
alt="{{ game.display_name }}">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title">{{ game.display_name }}</h5>
|
||||
<div class="mt-auto">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="new">
|
||||
<label class="form-check-label" for="new">Notify when new</label>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="live">
|
||||
<label class="form-check-label" for="live">Notify when farmable</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="container mt-4">
|
||||
{% for game in games %}
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-2">
|
||||
<img src="{{ game.box_art_url }}" alt="{{ game.name }} box art" class="img-fluid rounded-start"
|
||||
height="283" width="212" loading="lazy">
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title h5">
|
||||
<a href="https://www.twitch.tv/directory/category/{{ game.slug }}"
|
||||
class="text-decoration-none">{{ game.name }}</a>
|
||||
</h2>
|
||||
<div>
|
||||
<a href="" class="text-decoration-none">See previous drops</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="" class="text-decoration-none">Subscribe to new drops</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="" class="text-decoration-none">Subscribe to active drops</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,30 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static campaign_tags game_tags %}
|
||||
{% load static %}
|
||||
{% load campaign_tags %}
|
||||
{% load game_tags %}
|
||||
{% block content %}
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-lg-3">{{ toc|safe }}</div>
|
||||
<div class="col-lg-9">
|
||||
{% include "partials/info_box.html" %}
|
||||
{% include "partials/news.html" %}
|
||||
<h2>
|
||||
Reward campaign -
|
||||
<div class="d-inline text-muted">
|
||||
{{ reward_campaigns.count }}
|
||||
campaign{{ reward_campaigns.count|pluralize }}
|
||||
</div>
|
||||
</h2>
|
||||
{% for campaign in reward_campaigns %}
|
||||
{% render_campaign campaign %} {# Stored in /core/templatetags/campaign_tags.py #}
|
||||
{% endfor %}
|
||||
<h2>
|
||||
Drop campaigns -
|
||||
<div class="d-inline text-muted ">{{ games.count }} game{{ games.count|pluralize }}</div>
|
||||
</h2>
|
||||
{% for game in games %}
|
||||
{% render_game_card game %} {# Stored in /core/templatetags/game_tags.py #}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% include "partials/info_box.html" %}
|
||||
{% include "partials/news.html" %}
|
||||
<h2>
|
||||
Reward campaign -
|
||||
<span class="d-inline text-muted">
|
||||
{{ reward_campaigns.count }}
|
||||
campaign{{ reward_campaigns.count|pluralize }}
|
||||
</span>
|
||||
</h2>
|
||||
{% for campaign in reward_campaigns %}
|
||||
{% render_campaign campaign %}
|
||||
{% endfor %}
|
||||
<h2>
|
||||
Drop campaigns -
|
||||
<span class="d-inline text-muted ">{{ games.count }} game{{ games.count|pluralize }}</span>
|
||||
</h2>
|
||||
{% for game in games %}
|
||||
{% render_game_card game %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,17 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load campaign_tags %}
|
||||
{% load game_tags %}
|
||||
{% block content %}
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-lg-3">{{ toc }}</div>
|
||||
<div class="col-lg-9">
|
||||
<h2>Reward Campaigns</h2>
|
||||
<div>
|
||||
{% for campaign in reward_campaigns %}
|
||||
{% include "partials/reward_campaign_card.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container mt-4">
|
||||
<div class="row">
|
||||
<h2>Reward Campaigns</h2>
|
||||
{% for campaign in reward_campaigns %}
|
||||
{% render_campaign campaign %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -19,14 +19,13 @@ def render_game_card(game: Game) -> SafeText:
|
||||
Returns:
|
||||
The rendered HTML string.
|
||||
"""
|
||||
twitch_id: str = game.twitch_id
|
||||
box_art_url: str = game.box_art_url or "https://static-cdn.jtvnw.net/ttv-static/404_boxart.jpg"
|
||||
name: str = game.name or "Game name unknown"
|
||||
slug: str = game.slug or "game-name-unknown"
|
||||
drop_campaigns: list[DropCampaign] = game.drop_campaigns.all() # type: ignore # noqa: PGH003
|
||||
return format_html(
|
||||
"""
|
||||
<div class="card mb-4 shadow-sm" id="#{}">
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-2">
|
||||
<img src="{}" alt="{} box art" class="img-fluid rounded-start" height="283" width="212" loading="lazy">
|
||||
@ -45,7 +44,6 @@ def render_game_card(game: Game) -> SafeText:
|
||||
</div>
|
||||
</div>
|
||||
""",
|
||||
twitch_id,
|
||||
box_art_url,
|
||||
name,
|
||||
slug,
|
||||
|
@ -1,8 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import requests_cache
|
||||
from django.db.models import Prefetch
|
||||
@ -21,38 +20,6 @@ if TYPE_CHECKING:
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TOCItem:
|
||||
"""Table of contents item."""
|
||||
|
||||
name: str
|
||||
toc_id: str
|
||||
|
||||
|
||||
def build_toc(list_of_things: list[TOCItem]) -> str:
|
||||
"""Build the table of contents.
|
||||
|
||||
Args:
|
||||
list_of_things (list[TOCItem]): The list of table of contents items.
|
||||
|
||||
Returns:
|
||||
str: The HTML for the table of contents.
|
||||
"""
|
||||
html: str = """
|
||||
<div class="position-sticky d-none d-lg-block toc">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div id="toc-list" class="list-group">
|
||||
"""
|
||||
|
||||
for item in list_of_things:
|
||||
html += (
|
||||
f'<a class="list-group-item list-group-item-action plain-text-item" href="#{item.toc_id}">{item.name}</a>'
|
||||
)
|
||||
html += """</div></div></div></div>"""
|
||||
return html
|
||||
|
||||
|
||||
def get_reward_campaigns() -> BaseManager[RewardCampaign]:
|
||||
"""Get the reward campaigns.
|
||||
|
||||
@ -68,32 +35,25 @@ def get_games_with_drops() -> BaseManager[Game]:
|
||||
Returns:
|
||||
BaseManager[Game]: The games with drops.
|
||||
"""
|
||||
# Filter active drop campaigns
|
||||
active_campaigns: BaseManager[DropCampaign] = DropCampaign.objects.filter(ends_at__gte=timezone.now())
|
||||
|
||||
# Prefetch Benefits for each TimeBasedDrop
|
||||
benefits_prefetch = Prefetch(lookup="benefits", queryset=Benefit.objects.all())
|
||||
|
||||
# Filter active time-based drops
|
||||
active_campaigns_query: BaseManager[DropCampaign] = DropCampaign.objects.filter(ends_at__gte=timezone.now())
|
||||
active_time_based_drops: BaseManager[TimeBasedDrop] = TimeBasedDrop.objects.filter(ends_at__gte=timezone.now())
|
||||
|
||||
# Prefetch Benefits for each active TimeBasedDrop
|
||||
benefits_prefetch = Prefetch(lookup="benefits", queryset=Benefit.objects.all())
|
||||
|
||||
# Prefetch TimeBasedDrops for each DropCampaign and include the prefetch of Benefits
|
||||
time_based_drops_prefetch = Prefetch(
|
||||
lookup="drops",
|
||||
queryset=active_time_based_drops.prefetch_related(benefits_prefetch),
|
||||
)
|
||||
|
||||
# Prefetch DropCampaigns for each Game and include the prefetch of TimeBasedDrops
|
||||
campaigns_prefetch = Prefetch(
|
||||
lookup="drop_campaigns",
|
||||
queryset=active_campaigns.prefetch_related(time_based_drops_prefetch),
|
||||
queryset=active_campaigns_query.prefetch_related(time_based_drops_prefetch),
|
||||
)
|
||||
|
||||
# Query the games with the prefetched data
|
||||
return Game.objects.filter(drop_campaigns__in=active_campaigns).prefetch_related(campaigns_prefetch).distinct()
|
||||
return (
|
||||
Game.objects.filter(drop_campaigns__in=active_campaigns_query)
|
||||
.distinct()
|
||||
.prefetch_related(campaigns_prefetch)
|
||||
.order_by("name")
|
||||
)
|
||||
|
||||
|
||||
def index(request: HttpRequest) -> HttpResponse:
|
||||
@ -105,21 +65,19 @@ def index(request: HttpRequest) -> HttpResponse:
|
||||
Returns:
|
||||
HttpResponse: The response object
|
||||
"""
|
||||
reward_campaigns: BaseManager[RewardCampaign] = get_reward_campaigns()
|
||||
games: BaseManager[Game] = get_games_with_drops()
|
||||
tocs: list[TOCItem] = []
|
||||
for game in games.all():
|
||||
game_name: str = game.name or "<div class='text-muted'>Game name unknown</div>"
|
||||
tocs.append(TOCItem(name=game_name, toc_id=f"#{game.twitch_id}"))
|
||||
try:
|
||||
reward_campaigns: BaseManager[RewardCampaign] = get_reward_campaigns()
|
||||
games: BaseManager[Game] = get_games_with_drops()
|
||||
|
||||
toc: str = build_toc(tocs)
|
||||
except Exception:
|
||||
logger.exception("Error fetching reward campaigns or games.")
|
||||
return HttpResponse(status=500)
|
||||
|
||||
context: dict[str, BaseManager[RewardCampaign] | str | BaseManager[Game]] = {
|
||||
context: dict[str, Any] = {
|
||||
"reward_campaigns": reward_campaigns,
|
||||
"games": games,
|
||||
"toc": toc,
|
||||
}
|
||||
return TemplateResponse(request=request, template="index.html", context=context)
|
||||
return TemplateResponse(request, "index.html", context)
|
||||
|
||||
|
||||
def game_view(request: HttpRequest) -> HttpResponse:
|
||||
|
@ -1,16 +0,0 @@
|
||||
// Create a new ScrollSpy instance that will track scroll position and update the active item in the table of contents
|
||||
const scrollSpy = new bootstrap.ScrollSpy(document.body, {
|
||||
target: '.toc' // The target element that contains the table of contents
|
||||
});
|
||||
|
||||
// Listen for the 'activate.bs.scrollspy' event, which is triggered when a new item becomes active in the table of contents
|
||||
// This is needed because the toc can be longer than our screen and we want to scroll the active item into view
|
||||
document.body.addEventListener('activate.bs.scrollspy', function (event) {
|
||||
// Find the currently active item in the table of contents
|
||||
const activeItem = document.querySelector('.toc .active');
|
||||
|
||||
// If an active item is found, scroll it into view smoothly
|
||||
if (activeItem) {
|
||||
activeItem.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user