ttvdrops/templates/core/dashboard.html
Joakim Hellsén a74b550406
All checks were successful
Deploy to Server / deploy (push) Successful in 27s
Add icons to dashboard
2026-07-21 06:38:09 +02:00

348 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% load image_tags %}
{% block title %}
Drops Dashboard
{% endblock title %}
{% block extra_head %}
<link rel="alternate"
type="application/rss+xml"
title="All Twitch campaigns (RSS)"
href="{% url 'core:campaign_feed' %}" />
<link rel="alternate"
type="application/atom+xml"
title="All Twitch campaigns (Atom)"
href="{% url 'core:campaign_feed_atom' %}" />
<link rel="alternate"
type="application/atom+xml"
title="All Twitch campaigns (Discord)"
href="{% url 'core:campaign_feed_discord' %}" />
<link rel="alternate"
type="application/rss+xml"
title="All Kick campaigns (RSS)"
href="{% url 'kick:campaign_feed' %}" />
<link rel="alternate"
type="application/atom+xml"
title="All Kick campaigns (Atom)"
href="{% url 'kick:campaign_feed_atom' %}" />
<link rel="alternate"
type="application/atom+xml"
title="All Kick campaigns (Discord)"
href="{% url 'kick:campaign_feed_discord' %}" />
{% endblock extra_head %}
{% block content %}
<style>
.campaign-entry:hover {
background: color-mix(in srgb, CanvasText 5%, transparent 95%);
}
</style>
<main>
<h1>Open Drop Campaigns</h1>
<p>
Some Drops campaigns may not be available in your region.
<a href="https://help.twitch.tv/s/article/mission-based-drops">Learn more about Drops</a>.
</p>
<hr />
<section id="twitch-campaigns-section">
<header style="margin-bottom: 1rem;">
<h2 style="margin: 0 0 0.5rem 0;">Twitch Campaigns</h2>
<div>
<a href="{% url 'core:campaign_feed' %}"
title="RSS feed for all Twitch campaigns">[rss]</a>
<a href="{% url 'core:campaign_feed_atom' %}"
title="Atom feed for Twitch campaigns">[atom]</a>
<a href="{% url 'core:campaign_feed_discord' %}"
title="Discord feed for Twitch campaigns">[discord]</a>
<a href="{% url 'api-v1:twitch-api-v1_list_campaigns' %}"
title="Twitch campaigns API">[api]</a>
<a href="{% url 'core:docs_rss' %}" title="RSS feed documentation">[explain]</a>
</div>
</header>
{% if campaigns_by_game %}
{% for game_id, game_data in campaigns_by_game.items %}
<article id="twitch-game-article-{{ game_id }}"
style="margin-bottom: 2rem;
border: 1px solid color-mix(in srgb, CanvasText 25%, transparent 75%);
border-radius: 6px;
padding: 1rem;">
<header style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.25rem;">
<a href="{% url 'twitch:game_detail' game_id %}" style="flex-shrink: 0; line-height: 0;">
{% picture game_data.box_art alt="Box art for "|add:game_data.name width=72 %}
</a>
<div>
<h3 style="margin: 0; font-size: 1.5rem;">
<a href="{% url 'twitch:game_detail' game_id %}" style="text-decoration: none; color: inherit;">{{ game_data.name }}</a>
</h3>
{% if game_data.owners %}
<div style="font-size: 1.1rem; color: color-mix(in srgb, CanvasText 75%, transparent 25%);">
{% for org in game_data.owners %}
<a href="{% url 'twitch:organization_detail' org.twitch_id %}" style="color: inherit;">{{ org.name }}</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
</div>
{% endif %}
</div>
</header>
<div style="overflow-x: auto; padding: 0.25rem 0;">
<div style="display: flex; gap: 1rem; min-width: max-content;">
{% for campaign_data in game_data.campaigns %}
<article class="campaign-entry" style="display: flex;
flex-direction: column;
flex-shrink: 0;
width: 450px;
padding: 0.9rem;
border-radius: 8px;">
<div style="display: flex; gap: 1rem;">
<a href="{% url 'twitch:campaign_detail' campaign_data.campaign.twitch_id %}"
style="flex-shrink: 0; line-height: 0;">
{% picture campaign_data.campaign.image_best_url|default:campaign_data.campaign.image_url alt="Image for "|add:campaign_data.campaign.name width=120 %}
</a>
<div style="flex: 1; min-width: 0;">
<a href="{% url 'twitch:campaign_detail' campaign_data.campaign.twitch_id %}"
style="text-decoration: none; color: inherit;">
<h4 style="margin: 0 0 0.2rem 0; font-size: 1.3rem; line-height: 1.2;">{{ campaign_data.campaign.clean_name }}</h4>
</a>
{% if campaign_data.publisher %}
<div style="font-size: 1rem; color: color-mix(in srgb, CanvasText 75%, transparent 25%);">{{ campaign_data.publisher }}</div>
{% endif %}
<div style="font-size: 0.9rem; color: color-mix(in srgb, CanvasText 70%, transparent 30%); margin-top: 0.4rem;">
{% if campaign_data.watch_range %}{{ campaign_data.watch_range }} &middot; {% endif %}
ends in {{ campaign_data.campaign.end_at|timeuntil }}
</div>
<div style="font-size: 0.85rem; margin-top: 0.1rem;">
{% if campaign_data.allowed_channels %}
<a href="{% url 'twitch:campaign_detail' campaign_data.campaign.twitch_id %}#allowed-channels"
style="color: color-mix(in srgb, CanvasText 60%, transparent 40%); text-decoration: none;">
{{ campaign_data.allowed_channels.0.display_name }}{% if campaign_data.allowed_channels|length > 1 %} +{{ campaign_data.allowed_channels|length|add:'-1' }} more{% endif %}
</a>
{% else %}
<a href="{{ campaign_data.campaign.game.twitch_directory_url }}"
style="color: color-mix(in srgb, CanvasText 60%, transparent 40%); text-decoration: none;">
any channel
</a>
{% endif %}
</div>
</div>
</div>
{% if campaign_data.benefits %}
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem;">
{% for benefit in campaign_data.benefits %}
<span style="display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.25rem 0.6rem; font-size: 1.1rem; background: color-mix(in srgb, CanvasText 8%, transparent 92%); border-radius: 6px;">
{% if benefit.image_best_url %}
<img src="{{ benefit.image_best_url }}"
alt="{{ benefit.name }}"
style="width: 30px; height: 30px; border-radius: 4px; object-fit: contain;"
loading="lazy" />
{% endif %}
{{ benefit.name }}
</span>
{% endfor %}
</div>
{% endif %}
</article>
{% endfor %}
</div>
</div>
</article>
{% endfor %}
{% else %}
<p>No active Twitch campaigns at the moment.</p>
{% endif %}
</section>
{% if active_reward_campaigns %}
<section id="reward-campaigns-section"
style="margin-top: 2rem;
border-top: 2px solid #ddd;
padding-top: 1rem">
<header style="margin-bottom: 1rem;">
<h2 style="margin: 0 0 0.5rem 0;">
<a href="{% url 'twitch:reward_campaign_list' %}">Open Reward Campaigns</a>
</h2>
<p>
Rewards are limited-time offers from top brands that you can unlock by
supporting your favorite Twitch creators. Visit <a href="https://www.twitch.tv/drops/inventory">your inventory</a>
to access unlocked rewards.
</p>
</header>
<ul>
{% for campaign in active_reward_campaigns %}
<li id="reward-campaign-{{ campaign.twitch_id }}"
style="display: flex;
gap: 1rem;
margin-bottom: 1rem;
align-items: flex-start">
<a href="{% url 'twitch:reward_campaign_detail' campaign.twitch_id %}"
style="flex-shrink: 0;
display: block;
line-height: 0">
{% picture campaign.image_best_url alt="Image for "|add:campaign.name width=120 %}
</a>
<div>
<h3 style="margin: 0;">
<a href="{% url 'twitch:reward_campaign_detail' campaign.twitch_id %}">
{% if campaign.brand %}
{{ campaign.brand }}: {{ campaign.name }}
{% else %}
{{ campaign.name }}
{% endif %}
</a>
</h3>
{% if campaign.ends_at %}
<p style="margin: 0.25rem 0;">
<strong>Ends:</strong>
<time datetime="{{ campaign.ends_at|date:'c' }}"
title="{{ campaign.ends_at|date:'DATETIME_FORMAT' }}">
{{ campaign.ends_at|date:"M d, Y H:i" }}
</time>
</p>
{% endif %}
{% if campaign.game %}
<p style="margin: 0.25rem 0;">
<strong>Game:</strong>
<a href="{% url 'twitch:game_detail' campaign.game.twitch_id %}">{{ campaign.game.display_name }}</a>
</p>
{% elif campaign.is_sitewide %}
<p style="margin: 0.25rem 0;">
<strong>Type:</strong> Site-wide reward campaign
</p>
{% endif %}
{% if campaign.summary %}
<p>{{ campaign.summary }}</p>
{% endif %}
</div>
</li>
{% endfor %}
</ul>
</section>
{% endif %}
<section id="kick-campaigns-section"
style="margin-top: 2rem;
border-top: 2px solid #ddd;
padding-top: 1rem">
<header style="margin-bottom: 1rem;">
<h2 style="margin: 0 0 0.5rem 0;">Kick Campaigns</h2>
<div>
<a href="{% url 'kick:campaign_feed' %}"
title="RSS feed for all Kick campaigns">[rss]</a>
<a href="{% url 'kick:campaign_feed_atom' %}"
title="Atom feed for all Kick campaigns">[atom]</a>
<a href="{% url 'kick:campaign_feed_discord' %}"
title="Discord feed for all Kick campaigns">[discord]</a>
<a href="{% url 'core:docs_rss' %}" title="RSS feed documentation">[explain]</a>
</div>
</header>
{% if kick_campaigns_by_game %}
{% for game_id, game_data in kick_campaigns_by_game.items %}
<article id="kick-game-article-{{ game_id }}"
style="margin-bottom: 2rem;
border: 1px solid color-mix(in srgb, CanvasText 25%, transparent 75%);
border-radius: 6px;
padding: 1rem;">
<header style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.25rem;">
{% if game_data.image %}
<img src="{{ game_data.image }}"
width="48"
height="48"
alt="Image for {{ game_data.name }}"
style="width: 72px; height: 72px; border-radius: 8px; object-fit: cover; flex-shrink: 0;" />
{% endif %}
<div>
<h3 style="margin: 0; font-size: 1.5rem;">
{% if game_data.kick_id %}
<a href="{% url 'kick:game_detail' game_data.kick_id %}" style="text-decoration: none; color: inherit;">{{ game_data.name }}</a>
{% elif game_data.organizations %}
{% for org in game_data.organizations %}
<a href="{% url 'kick:organization_detail' org.kick_id %}" style="text-decoration: none; color: inherit;">{{ org.name }}</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
{% else %}
{{ game_data.name }}
{% endif %}
</h3>
{% if game_data.kick_id and game_data.organizations %}
<div style="font-size: 1.1rem; color: color-mix(in srgb, CanvasText 75%, transparent 25%);">
{% for org in game_data.organizations %}
<a href="{% url 'kick:organization_detail' org.kick_id %}" style="color: inherit;">{{ org.name }}</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
</div>
{% endif %}
</div>
</header>
<div style="overflow-x: auto; padding: 0.25rem 0;">
<div style="display: flex; gap: 1rem; min-width: max-content;">
{% for campaign_data in game_data.campaigns %}
{% with rewards=campaign_data.rewards %}
{% with min_watch=rewards.0.required_units|default:0 max_watch=rewards.last.required_units|default:0 %}
<article class="campaign-entry" style="display: flex;
flex-direction: column;
flex-shrink: 0;
width: 450px;
padding: 0.9rem;
border-radius: 8px;">
<div style="display: flex; gap: 1rem;">
<a href="{% url 'kick:campaign_detail' campaign_data.campaign.kick_id %}"
style="flex-shrink: 0; line-height: 0;">
{% if campaign_data.campaign.image_url %}
<img src="{{ campaign_data.campaign.image_url }}"
width="120"
height="120"
alt="Image for {{ campaign_data.campaign.name }}"
style="width: 120px; height: 120px; border-radius: 8px; object-fit: cover;" />
{% endif %}
</a>
<div style="flex: 1; min-width: 0;">
<a href="{% url 'kick:campaign_detail' campaign_data.campaign.kick_id %}"
style="text-decoration: none; color: inherit;">
<h4 style="margin: 0 0 0.2rem 0; font-size: 1.3rem; line-height: 1.2;">{{ campaign_data.campaign.name }}</h4>
</a>
{% if campaign_data.campaign.organization %}
<div style="font-size: 1rem; color: color-mix(in srgb, CanvasText 75%, transparent 25%);">{{ campaign_data.campaign.organization.name }}</div>
{% endif %}
<div style="font-size: 0.9rem; color: color-mix(in srgb, CanvasText 70%, transparent 30%); margin-top: 0.4rem;">
{% if min_watch %}{% if min_watch == max_watch %}{{ min_watch }}m watch{% else %}{{ min_watch }}m{{ max_watch }}m watch{% endif %} &middot; {% endif %}
ends in {{ campaign_data.campaign.ends_at|timeuntil }}
</div>
<div style="font-size: 0.85rem; margin-top: 0.1rem;">
{% if campaign_data.channels %}
<a href="{% url 'kick:campaign_detail' campaign_data.campaign.kick_id %}#allowed-channels"
style="color: color-mix(in srgb, CanvasText 60%, transparent 40%); text-decoration: none;">
{{ campaign_data.channels.0.user.username|default:campaign_data.channels.0.slug }}{% if campaign_data.channels|length > 1 %} +{{ campaign_data.channels|length|add:'-1' }} more{% endif %}
</a>
{% else %}
<a href="{{ campaign_data.campaign.url }}"
style="color: color-mix(in srgb, CanvasText 60%, transparent 40%); text-decoration: none;">
any channel
</a>
{% endif %}
</div>
</div>
</div>
{% if rewards %}
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem;">
{% for reward in rewards %}
<span style="display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.25rem 0.6rem; font-size: 1.1rem; background: color-mix(in srgb, CanvasText 8%, transparent 92%); border-radius: 6px;">
{% if reward.full_image_url %}
<img src="{{ reward.full_image_url }}"
alt="{{ reward.name }}"
style="width: 30px; height: 30px; border-radius: 4px; object-fit: contain;"
loading="lazy" />
{% endif %}
{{ reward.name }}
</span>
{% endfor %}
</div>
{% endif %}
</article>
{% endwith %}
{% endwith %}
{% endfor %}
</div>
</div>
</article>
{% endfor %}
{% else %}
<p>No active Kick campaigns at the moment.</p>
{% endif %}
</section>
</main>
{% endblock content %}