518 lines
30 KiB
HTML
518 lines
30 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}
|
|
{{ category.name }} — Kick Game
|
|
{% endblock title %}
|
|
{% block extra_head %}
|
|
<link rel="alternate"
|
|
type="application/rss+xml"
|
|
title="{{ category.name }} campaigns (RSS)"
|
|
href="{% url 'kick:game_campaign_feed' category.kick_id %}" />
|
|
<link rel="alternate"
|
|
type="application/atom+xml"
|
|
title="{{ category.name }} campaigns (Atom)"
|
|
href="{% url 'kick:game_campaign_feed_atom' category.kick_id %}" />
|
|
<link rel="alternate"
|
|
type="application/atom+xml"
|
|
title="{{ category.name }} campaigns (Discord)"
|
|
href="{% url 'kick:game_campaign_feed_discord' category.kick_id %}" />
|
|
{% endblock extra_head %}
|
|
{% block content %}
|
|
<main>
|
|
<nav aria-label="Breadcrumb">
|
|
<a href="{% url 'kick:dashboard' %}">Kick</a> >
|
|
<a href="{% url 'kick:game_list' %}">Games</a> >
|
|
{{ category.name }}
|
|
</nav>
|
|
<div style="display: flex;
|
|
align-items: flex-start;
|
|
gap: 1.5rem;
|
|
margin-bottom: 1rem">
|
|
<div style="flex-shrink: 0;">
|
|
{% if category.image_url %}
|
|
<img src="{{ category.image_url }}"
|
|
alt="{{ category.name }} image"
|
|
width="200"
|
|
height="200"
|
|
loading="lazy"
|
|
style="max-width: 100%;
|
|
height: auto;
|
|
border-radius: 8px" />
|
|
{% else %}
|
|
<div style="width: 200px;
|
|
height: 200px;
|
|
background-color: #eee;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 8px">No Image</div>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<h1 style="margin: 0 0 0.25rem 0;">{{ category.name }}</h1>
|
|
<div>
|
|
<a href="{% url 'kick:game_campaign_feed' category.kick_id %}"
|
|
title="RSS feed for {{ category.name }} campaigns">[rss]</a>
|
|
<a href="{% url 'kick:game_campaign_feed_atom' category.kick_id %}"
|
|
title="Atom feed for {{ category.name }} campaigns">[atom]</a>
|
|
<a href="{% url 'kick:game_campaign_feed_discord' category.kick_id %}"
|
|
title="Discord feed for {{ category.name }} campaigns">[discord]</a>
|
|
<a href="{% url 'core:docs_rss' %}" title="RSS feed documentation">[explain]</a>
|
|
</div>
|
|
{% if category.kick_url %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<a href="{{ category.kick_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ category.kick_url }}</a>
|
|
</p>
|
|
{% endif %}
|
|
<p style="margin: 0.25rem 0; font-size: 0.85rem; color: #666;">
|
|
ID: {{ category.kick_id }}
|
|
- Added: <time datetime="{{ category.added_at|date:'c' }}"
|
|
title="{{ category.added_at|date:'DATETIME_FORMAT' }}">{{ category.added_at|date:"M d, Y" }}</time>
|
|
({{ category.added_at|timesince }} ago)
|
|
- Updated: <time datetime="{{ category.updated_at|date:'c' }}"
|
|
title="{{ category.updated_at|date:'DATETIME_FORMAT' }}">{{ category.updated_at|date:"M d, Y" }}</time>
|
|
({{ category.updated_at|timesince }} ago)
|
|
</p>
|
|
<p style="margin: 0.25rem 0; color: #666;">
|
|
Active: {{ active_campaigns|length }}
|
|
- Upcoming: {{ upcoming_campaigns|length }}
|
|
- Expired: {{ expired_campaigns|length }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<hr />
|
|
{% if active_campaigns %}
|
|
<h2>Active Campaigns ({{ active_campaigns|length }})</h2>
|
|
{% for campaign in active_campaigns %}
|
|
<article>
|
|
<header>
|
|
<h3>
|
|
<a href="{% url 'kick:campaign_detail' campaign.kick_id %}">{{ campaign.name }}</a>
|
|
</h3>
|
|
<div style="font-size: 0.9rem; color: #666;">
|
|
{% if campaign.organization %}
|
|
Organization:
|
|
<a href="{% url 'kick:organization_detail' campaign.organization.kick_id %}">{{ campaign.organization.name }}</a>
|
|
-
|
|
{% endif %}
|
|
Status: {{ campaign.status|default:"unknown"|capfirst }}
|
|
</div>
|
|
</header>
|
|
<div style="display: flex; gap: 1rem;">
|
|
<div style="flex-shrink: 0;">
|
|
{% if campaign.image_url %}
|
|
<img src="{{ campaign.image_url }}"
|
|
width="200"
|
|
height="200"
|
|
alt="{{ campaign.name }} image"
|
|
loading="lazy"
|
|
style="width: 200px;
|
|
height: auto;
|
|
border-radius: 8px" />
|
|
{% else %}
|
|
<div style="width: 200px;
|
|
height: 200px;
|
|
background-color: #eee;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 8px">No Image</div>
|
|
{% endif %}
|
|
</div>
|
|
<div style="flex: 1;">
|
|
{% if campaign.starts_at %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Starts:</strong>
|
|
<time datetime="{{ campaign.starts_at|date:'c' }}"
|
|
title="{{ campaign.starts_at|date:'DATETIME_FORMAT' }}">
|
|
{{ campaign.starts_at|date:"M d, Y H:i" }}
|
|
</time>
|
|
{% if campaign.starts_at < now %}
|
|
(started {{ campaign.starts_at|timesince }} ago)
|
|
{% else %}
|
|
(in {{ campaign.starts_at|timeuntil }})
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
{% 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>
|
|
{% if campaign.ends_at < now %}
|
|
(ended {{ campaign.ends_at|timesince }} ago)
|
|
{% else %}
|
|
(in {{ campaign.ends_at|timeuntil }})
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.duration %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Duration:</strong> {{ campaign.duration }}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.rule_name %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Rule:</strong> {{ campaign.rule_name }}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.connect_url %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<a href="{{ campaign.connect_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">Connect account</a>
|
|
</p>
|
|
{% endif %}
|
|
<div style="margin-top: 0.5rem; font-size: 0.9rem;">
|
|
<strong>Participating channels:</strong>
|
|
{% if campaign.channels.all %}
|
|
<ul style="margin: 0.25rem 0 0 0; padding-left: 1rem;">
|
|
{% for channel in campaign.channels.all|slice:":5" %}
|
|
<li>
|
|
{% if channel.user %}
|
|
<a href="{{ channel.channel_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ channel.user.username }}</a>
|
|
{% else %}
|
|
<a href="{{ channel.channel_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ channel.slug }}</a>
|
|
{% endif %}
|
|
</li>
|
|
{% endfor %}
|
|
{% if campaign.channels.count > 5 %}
|
|
<li style="color: #666; font-style: italic;">... and {{ campaign.channels.count|add:"-5" }} more</li>
|
|
{% endif %}
|
|
</ul>
|
|
{% else %}
|
|
<p style="margin: 0.25rem 0 0 0;">
|
|
{% if category.kick_url %}
|
|
<a href="{{ category.kick_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ category.name }}</a> is game wide.
|
|
{% else %}
|
|
Game wide.
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
{% if campaign.merged_rewards %}
|
|
<div style="margin-top: 0.75rem;">
|
|
<strong>Rewards:</strong>
|
|
<ul style="margin: 0.25rem 0 0 0; padding-left: 1rem;">
|
|
{% for reward in campaign.merged_rewards %}
|
|
<li>
|
|
{% if reward.full_image_url %}
|
|
<img src="{{ reward.full_image_url }}"
|
|
alt="{{ reward.name }}"
|
|
width="56"
|
|
height="56"
|
|
loading="lazy"
|
|
style="vertical-align: middle;
|
|
border-radius: 4px" />
|
|
{% endif %}
|
|
{{ reward.name }} ({{ reward.required_units }} min)
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</article>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% if upcoming_campaigns %}
|
|
<h2>Upcoming Campaigns ({{ upcoming_campaigns|length }})</h2>
|
|
{% for campaign in upcoming_campaigns %}
|
|
<article>
|
|
<header>
|
|
<h3>
|
|
<a href="{% url 'kick:campaign_detail' campaign.kick_id %}">{{ campaign.name }}</a>
|
|
</h3>
|
|
<div style="font-size: 0.9rem; color: #666;">
|
|
{% if campaign.organization %}
|
|
Organization:
|
|
<a href="{% url 'kick:organization_detail' campaign.organization.kick_id %}">{{ campaign.organization.name }}</a>
|
|
-
|
|
{% endif %}
|
|
Status: {{ campaign.status|default:"unknown"|capfirst }}
|
|
</div>
|
|
</header>
|
|
<div style="display: flex; gap: 1rem;">
|
|
<div style="flex-shrink: 0;">
|
|
{% if campaign.image_url %}
|
|
<img src="{{ campaign.image_url }}"
|
|
width="200"
|
|
height="200"
|
|
alt="{{ campaign.name }} image"
|
|
loading="lazy"
|
|
style="width: 200px;
|
|
height: auto;
|
|
border-radius: 8px" />
|
|
{% else %}
|
|
<div style="width: 200px;
|
|
height: 200px;
|
|
background-color: #eee;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 8px">No Image</div>
|
|
{% endif %}
|
|
</div>
|
|
<div style="flex: 1;">
|
|
{% if campaign.starts_at %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Starts:</strong>
|
|
<time datetime="{{ campaign.starts_at|date:'c' }}"
|
|
title="{{ campaign.starts_at|date:'DATETIME_FORMAT' }}">
|
|
{{ campaign.starts_at|date:"M d, Y H:i" }}
|
|
</time>
|
|
{% if campaign.starts_at < now %}
|
|
(started {{ campaign.starts_at|timesince }} ago)
|
|
{% else %}
|
|
(in {{ campaign.starts_at|timeuntil }})
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
{% 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>
|
|
{% if campaign.ends_at < now %}
|
|
(ended {{ campaign.ends_at|timesince }} ago)
|
|
{% else %}
|
|
(in {{ campaign.ends_at|timeuntil }})
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.duration %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Duration:</strong> {{ campaign.duration }}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.rule_name %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Rule:</strong> {{ campaign.rule_name }}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.connect_url %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<a href="{{ campaign.connect_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">Connect account</a>
|
|
</p>
|
|
{% endif %}
|
|
<div style="margin-top: 0.5rem; font-size: 0.9rem;">
|
|
<strong>Participating channels:</strong>
|
|
{% if campaign.channels.all %}
|
|
<ul style="margin: 0.25rem 0 0 0; padding-left: 1rem;">
|
|
{% for channel in campaign.channels.all|slice:":5" %}
|
|
<li>
|
|
{% if channel.user %}
|
|
<a href="{{ channel.channel_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ channel.user.username }}</a>
|
|
{% else %}
|
|
<a href="{{ channel.channel_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ channel.slug }}</a>
|
|
{% endif %}
|
|
</li>
|
|
{% endfor %}
|
|
{% if campaign.channels.count > 5 %}
|
|
<li style="color: #666; font-style: italic;">... and {{ campaign.channels.count|add:"-5" }} more</li>
|
|
{% endif %}
|
|
</ul>
|
|
{% else %}
|
|
<p style="margin: 0.25rem 0 0 0;">
|
|
{% if category.kick_url %}
|
|
<a href="{{ category.kick_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ category.name }}</a> is game wide.
|
|
{% else %}
|
|
Game wide.
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
{% if campaign.merged_rewards %}
|
|
<div style="margin-top: 0.75rem;">
|
|
<strong>Rewards:</strong>
|
|
<ul style="margin: 0.25rem 0 0 0; padding-left: 1rem;">
|
|
{% for reward in campaign.merged_rewards %}
|
|
<li>
|
|
{% if reward.full_image_url %}
|
|
<img src="{{ reward.full_image_url }}"
|
|
alt="{{ reward.name }}"
|
|
width="56"
|
|
height="56"
|
|
loading="lazy"
|
|
style="vertical-align: middle;
|
|
border-radius: 4px" />
|
|
{% endif %}
|
|
{{ reward.name }} ({{ reward.required_units }} min)
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</article>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% if expired_campaigns %}
|
|
<h2>Expired Campaigns ({{ expired_campaigns|length }})</h2>
|
|
{% for campaign in expired_campaigns %}
|
|
<article>
|
|
<header>
|
|
<h3>
|
|
<a href="{% url 'kick:campaign_detail' campaign.kick_id %}">{{ campaign.name }}</a>
|
|
</h3>
|
|
<div style="font-size: 0.9rem; color: #666;">
|
|
{% if campaign.organization %}
|
|
Organization:
|
|
<a href="{% url 'kick:organization_detail' campaign.organization.kick_id %}">{{ campaign.organization.name }}</a>
|
|
-
|
|
{% endif %}
|
|
Status: {{ campaign.status|default:"unknown"|capfirst }}
|
|
</div>
|
|
</header>
|
|
<div style="display: flex; gap: 1rem;">
|
|
<div style="flex-shrink: 0;">
|
|
{% if campaign.image_url %}
|
|
<img src="{{ campaign.image_url }}"
|
|
width="200"
|
|
height="200"
|
|
alt="{{ campaign.name }} image"
|
|
loading="lazy"
|
|
style="width: 200px;
|
|
height: auto;
|
|
border-radius: 8px" />
|
|
{% else %}
|
|
<div style="width: 200px;
|
|
height: 200px;
|
|
background-color: #eee;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 8px">No Image</div>
|
|
{% endif %}
|
|
</div>
|
|
<div style="flex: 1;">
|
|
{% if campaign.starts_at %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Starts:</strong>
|
|
<time datetime="{{ campaign.starts_at|date:'c' }}"
|
|
title="{{ campaign.starts_at|date:'DATETIME_FORMAT' }}">
|
|
{{ campaign.starts_at|date:"M d, Y H:i" }}
|
|
</time>
|
|
{% if campaign.starts_at < now %}
|
|
(started {{ campaign.starts_at|timesince }} ago)
|
|
{% else %}
|
|
(in {{ campaign.starts_at|timeuntil }})
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
{% 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>
|
|
{% if campaign.ends_at < now %}
|
|
(ended {{ campaign.ends_at|timesince }} ago)
|
|
{% else %}
|
|
(in {{ campaign.ends_at|timeuntil }})
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.duration %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Duration:</strong> {{ campaign.duration }}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.rule_name %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<strong>Rule:</strong> {{ campaign.rule_name }}
|
|
</p>
|
|
{% endif %}
|
|
{% if campaign.connect_url %}
|
|
<p style="margin: 0.25rem 0;">
|
|
<a href="{{ campaign.connect_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">Connect account</a>
|
|
</p>
|
|
{% endif %}
|
|
<div style="margin-top: 0.5rem; font-size: 0.9rem;">
|
|
<strong>Participating channels:</strong>
|
|
{% if campaign.channels.all %}
|
|
<ul style="margin: 0.25rem 0 0 0; padding-left: 1rem;">
|
|
{% for channel in campaign.channels.all|slice:":5" %}
|
|
<li>
|
|
{% if channel.user %}
|
|
<a href="{{ channel.channel_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ channel.user.username }}</a>
|
|
{% else %}
|
|
<a href="{{ channel.channel_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ channel.slug }}</a>
|
|
{% endif %}
|
|
</li>
|
|
{% endfor %}
|
|
{% if campaign.channels.count > 5 %}
|
|
<li style="color: #666; font-style: italic;">... and {{ campaign.channels.count|add:"-5" }} more</li>
|
|
{% endif %}
|
|
</ul>
|
|
{% else %}
|
|
<p style="margin: 0.25rem 0 0 0;">
|
|
{% if category.kick_url %}
|
|
<a href="{{ category.kick_url }}"
|
|
rel="nofollow noopener"
|
|
target="_blank">{{ category.name }}</a> is game wide.
|
|
{% else %}
|
|
Game wide.
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
{% if campaign.merged_rewards %}
|
|
<div style="margin-top: 0.75rem;">
|
|
<strong>Rewards:</strong>
|
|
<ul style="margin: 0.25rem 0 0 0; padding-left: 1rem;">
|
|
{% for reward in campaign.merged_rewards %}
|
|
<li>
|
|
{% if reward.full_image_url %}
|
|
<img src="{{ reward.full_image_url }}"
|
|
alt="{{ reward.name }}"
|
|
width="56"
|
|
height="56"
|
|
loading="lazy"
|
|
style="vertical-align: middle;
|
|
border-radius: 4px" />
|
|
{% endif %}
|
|
{{ reward.name }} ({{ reward.required_units }} min)
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</article>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% if not active_campaigns and not upcoming_campaigns and not expired_campaigns %}
|
|
<p>No campaigns found for this game.</p>
|
|
{% endif %}
|
|
</main>
|
|
{% endblock content %}
|