This commit is contained in:
parent
4627d1cea0
commit
d762081bd5
26 changed files with 5048 additions and 1 deletions
|
|
@ -73,6 +73,42 @@
|
|||
type="application/atom+xml"
|
||||
title="Newly added reward campaigns (Discord)"
|
||||
href="{% url 'twitch:reward_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' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="All Kick games (RSS)"
|
||||
href="{% url 'kick:game_feed' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick games (Atom)"
|
||||
href="{% url 'kick:game_feed_atom' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick games (Discord)"
|
||||
href="{% url 'kick:game_feed_discord' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="All Kick organizations (RSS)"
|
||||
href="{% url 'kick:organization_feed' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick organizations (Atom)"
|
||||
href="{% url 'kick:organization_feed_atom' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick organizations (Discord)"
|
||||
href="{% url 'kick:organization_feed_discord' %}" />
|
||||
{# Allow child templates to inject page-specific alternates into the head #}
|
||||
{% block extra_head %}
|
||||
{% endblock extra_head %}
|
||||
|
|
@ -234,9 +270,14 @@
|
|||
<a href="{% url 'twitch:emote_gallery' %}">Emotes</a> |
|
||||
<a href="https://www.twitch.tv/drops/inventory">Inventory</a>
|
||||
<br />
|
||||
<strong>Kick</strong>
|
||||
<a href="{% url 'kick:dashboard' %}">Dashboard</a> |
|
||||
<a href="{% url 'kick:campaign_list' %}">Campaigns</a> |
|
||||
<a href="{% url 'kick:game_list' %}">Games</a> |
|
||||
<a href="{% url 'kick:organization_list' %}">Organizations</a>
|
||||
<br />
|
||||
<strong>Other sites</strong>
|
||||
<a href="#">Steam</a> |
|
||||
<a href="#">Kick</a> |
|
||||
<a href="#">YouTube</a> |
|
||||
<a href="#">TikTok</a> |
|
||||
<a href="#">Discord</a>
|
||||
|
|
|
|||
224
templates/kick/campaign_detail.html
Normal file
224
templates/kick/campaign_detail.html
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
{{ campaign.name }} — Kick Campaign
|
||||
{% endblock title %}
|
||||
{% block extra_head %}
|
||||
{% if campaign.category %}
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="{{ campaign.category.name }} campaigns (RSS)"
|
||||
href="{% url 'kick:game_campaign_feed' campaign.category.kick_id %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="{{ campaign.category.name }} campaigns (Atom)"
|
||||
href="{% url 'kick:game_campaign_feed_atom' campaign.category.kick_id %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="{{ campaign.category.name }} campaigns (Discord)"
|
||||
href="{% url 'kick:game_campaign_feed_discord' campaign.category.kick_id %}" />
|
||||
{% endif %}
|
||||
{% endblock extra_head %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<nav aria-label="Breadcrumb">
|
||||
<a href="{% url 'kick:dashboard' %}">Kick</a> >
|
||||
<a href="{% url 'kick:campaign_list' %}">Campaigns</a> >
|
||||
{{ campaign.name }}
|
||||
</nav>
|
||||
<div style="display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1rem">
|
||||
<div style="flex-shrink: 0;">
|
||||
{% if campaign.image_url %}
|
||||
<img src="{{ campaign.image_url }}"
|
||||
alt="{{ campaign.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;">{{ campaign.name }}</h1>
|
||||
{% if campaign.category %}
|
||||
<div>
|
||||
<a href="{% url 'kick:game_campaign_feed' campaign.category.kick_id %}"
|
||||
title="RSS feed for {{ campaign.category.name }} campaigns">[rss]</a>
|
||||
<a href="{% url 'kick:game_campaign_feed_atom' campaign.category.kick_id %}"
|
||||
title="Atom feed for {{ campaign.category.name }} campaigns">[atom]</a>
|
||||
<a href="{% url 'kick:game_campaign_feed_discord' campaign.category.kick_id %}"
|
||||
title="Discord feed for {{ campaign.category.name }} campaigns">[discord]</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<p style="margin: 0.25rem 0; color: #666;">
|
||||
Status: {{ campaign.status|default:"unknown"|capfirst }}
|
||||
{% if campaign.rule_name %}- Rule: {{ campaign.rule_name }}{% endif %}
|
||||
</p>
|
||||
{% if campaign.category or campaign.organization %}
|
||||
<p style="margin: 0.25rem 0;">
|
||||
{% if campaign.category %}
|
||||
<a href="{% url 'kick:game_detail' campaign.category.kick_id %}">{{ campaign.category.name }}</a>
|
||||
{% endif %}
|
||||
{% if campaign.organization %}
|
||||
{% if campaign.category %}-{% endif %}
|
||||
<a href="{% url 'kick:organization_detail' campaign.organization.kick_id %}">{{ campaign.organization.name }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p style="margin: 0.25rem 0; font-size: 0.85rem; color: #666;">
|
||||
ID: {{ campaign.kick_id }}
|
||||
{% if campaign.rule_id %}- Rule ID: {{ campaign.rule_id }}{% endif %}
|
||||
- Added: <time datetime="{{ campaign.added_at|date:'c' }}"
|
||||
title="{{ campaign.added_at|date:'DATETIME_FORMAT' }}">{{ campaign.added_at|date:"M d, Y" }}</time>
|
||||
({{ campaign.added_at|timesince }} ago)
|
||||
- Updated: <time datetime="{{ campaign.updated_at|date:'c' }}"
|
||||
title="{{ campaign.updated_at|date:'DATETIME_FORMAT' }}">{{ campaign.updated_at|date:"M d, Y" }}</time>
|
||||
({{ campaign.updated_at|timesince }} ago)
|
||||
</p>
|
||||
{% 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.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.duration %}
|
||||
<p style="margin: 0.25rem 0;">
|
||||
<strong>Duration:</strong> {{ campaign.duration }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p style="margin: 0.25rem 0;">
|
||||
{% if reward_count %}
|
||||
{{ reward_count }} reward{{ reward_count|pluralize }}
|
||||
({{ total_watch_minutes }} total watch minute{{ total_watch_minutes|pluralize }})
|
||||
{% else %}
|
||||
No rewards
|
||||
{% endif %}
|
||||
</p>
|
||||
<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.name }}</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;">
|
||||
<!-- Is game wide-->
|
||||
<a href="{{ campaign.category.kick_url }}"
|
||||
rel="nofollow noopener"
|
||||
target="_blank">{{ campaign.category.name }}</a> is game wide.
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if campaign.created_at %}
|
||||
<p style="margin: 0.25rem 0;">
|
||||
<time datetime="{{ campaign.created_at|date:'c' }}"
|
||||
title="{{ campaign.created_at|date:'DATETIME_FORMAT' }}">
|
||||
Created: {{ campaign.created_at|date:"M d, Y H:i" }} ({{ campaign.created_at|timesince }} ago)
|
||||
</time>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if campaign.api_updated_at %}
|
||||
<p style="margin: 0.25rem 0;">
|
||||
<time datetime="{{ campaign.api_updated_at|date:'c' }}"
|
||||
title="{{ campaign.api_updated_at|date:'DATETIME_FORMAT' }}">
|
||||
API Updated: {{ campaign.api_updated_at|date:"M d, Y H:i" }} ({{ campaign.api_updated_at|timesince }} ago)
|
||||
</time>
|
||||
</p>
|
||||
{% endif %}
|
||||
<p style="margin: 0.5rem 0 0 0;">
|
||||
{% if campaign.url %}<a href="{{ campaign.url }}" rel="nofollow noopener" target="_blank">Details</a>{% endif %}
|
||||
{% if campaign.connect_url %}
|
||||
{% if campaign.url %}-{% endif %}
|
||||
<a href="{{ campaign.connect_url }}"
|
||||
rel="nofollow noopener"
|
||||
target="_blank">Connect account</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<h2>Rewards</h2>
|
||||
{% if rewards %}
|
||||
{% for reward in rewards %}
|
||||
<article>
|
||||
<div style="display: flex; gap: 1rem; align-items: flex-start;">
|
||||
<div style="flex-shrink: 0;">
|
||||
{% if reward.full_image_url %}
|
||||
<img src="{{ reward.full_image_url }}"
|
||||
alt="{{ reward.name }}"
|
||||
width="96"
|
||||
height="96"
|
||||
loading="lazy"
|
||||
style="width: 96px;
|
||||
height: auto;
|
||||
border-radius: 6px" />
|
||||
{% else %}
|
||||
<div style="width: 96px;
|
||||
height: 96px;
|
||||
background-color: #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px">No Image</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="margin: 0 0 0.25rem 0;">{{ reward.name }}</h3>
|
||||
{% if reward.required_units %}
|
||||
<p style="margin: 0.25rem 0;">{{ reward.required_units }} minutes watched</p>
|
||||
{% else %}
|
||||
<p style="margin: 0.25rem 0;">No watch-time requirement</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>No drops available for this campaign.</p>
|
||||
{% endif %}
|
||||
</main>
|
||||
{% endblock content %}
|
||||
120
templates/kick/campaign_list.html
Normal file
120
templates/kick/campaign_list.html
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
Kick Drop Campaigns
|
||||
{% endblock title %}
|
||||
{% block extra_head %}
|
||||
<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 %}
|
||||
<main>
|
||||
<h1>Kick Drop Campaigns</h1>
|
||||
<div>
|
||||
<a href="{% url 'kick:campaign_feed' %}"
|
||||
title="RSS feed for all campaigns">[rss]</a>
|
||||
<a href="{% url 'kick:campaign_feed_atom' %}"
|
||||
title="Atom feed for all campaigns">[atom]</a>
|
||||
<a href="{% url 'kick:campaign_feed_discord' %}"
|
||||
title="Discord feed for all campaigns">[discord]</a>
|
||||
</div>
|
||||
<form method="get" action="{% url 'kick:campaign_list' %}">
|
||||
<div style="display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem">
|
||||
<select name="game">
|
||||
<option value="">All Games</option>
|
||||
{% for game in games %}
|
||||
<option value="{{ game.kick_id }}"
|
||||
{% if selected_game == game.kick_id|stringformat:"s" %}selected{% endif %}>{{ game.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select name="status">
|
||||
<option value="">All Statuses</option>
|
||||
{% for s in status_options %}
|
||||
<option value="{{ s }}" {% if selected_status == s %}selected{% endif %}>{{ s|capfirst }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit">Filter</button>
|
||||
{% if selected_status or selected_game %}
|
||||
<a href="{% url 'kick:campaign_list' %}">Clear</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% if campaigns %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Game</th>
|
||||
<th>Organization</th>
|
||||
<th>Status</th>
|
||||
<th>Starts</th>
|
||||
<th>Ends</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for campaign in campaigns %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'kick:campaign_detail' campaign.kick_id %}">{{ campaign.name }}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'kick:game_detail' campaign.category.kick_id %}">{{ campaign.category.name }}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'kick:organization_detail' campaign.organization.kick_id %}">{{ campaign.organization.name }}</a>
|
||||
</td>
|
||||
<td>{{ campaign.status }}</td>
|
||||
<td>
|
||||
{% if campaign.starts_at %}
|
||||
<time datetime="{{ campaign.starts_at|date:'c' }}"
|
||||
title="{{ campaign.starts_at|date:'DATETIME_FORMAT' }}">{{ campaign.starts_at|date:"M d, Y" }}</time>
|
||||
{% if campaign.starts_at < now %}
|
||||
({{ campaign.starts_at|timesince }} ago)
|
||||
{% else %}
|
||||
(in {{ campaign.starts_at|timeuntil }})
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if campaign.ends_at %}
|
||||
<time datetime="{{ campaign.ends_at|date:'c' }}"
|
||||
title="{{ campaign.ends_at|date:'DATETIME_FORMAT' }}">{{ campaign.ends_at|date:"M d, Y" }}</time>
|
||||
{% if campaign.ends_at < now %}
|
||||
({{ campaign.ends_at|timesince }} ago)
|
||||
{% else %}
|
||||
(in {{ campaign.ends_at|timeuntil }})
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Pagination">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page={{ page_obj.previous_page_number }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if selected_game %}&game={{ selected_game }}{% endif %}">Previous</a>
|
||||
{% endif %}
|
||||
<span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?page={{ page_obj.next_page_number }}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if selected_game %}&game={{ selected_game }}{% endif %}">Next</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>No campaigns found.</p>
|
||||
{% endif %}
|
||||
</main>
|
||||
{% endblock content %}
|
||||
517
templates/kick/category_detail.html
Normal file
517
templates/kick/category_detail.html
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
{% 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>
|
||||
</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 %}
|
||||
44
templates/kick/category_list.html
Normal file
44
templates/kick/category_list.html
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
Kick Games
|
||||
{% endblock title %}
|
||||
{% block extra_head %}
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="All Kick games (RSS)"
|
||||
href="{% url 'kick:game_feed' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick games (Atom)"
|
||||
href="{% url 'kick:game_feed_atom' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick games (Discord)"
|
||||
href="{% url 'kick:game_feed_discord' %}" />
|
||||
{% endblock extra_head %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<h1>Kick Games</h1>
|
||||
<div>
|
||||
<a href="{% url 'kick:game_feed' %}" title="RSS feed for all games">[rss]</a>
|
||||
<a href="{% url 'kick:game_feed_atom' %}"
|
||||
title="Atom feed for all games">[atom]</a>
|
||||
<a href="{% url 'kick:game_feed_discord' %}"
|
||||
title="Discord feed for all games">[discord]</a>
|
||||
</div>
|
||||
{% if categories %}
|
||||
<ul>
|
||||
{% for category in categories %}
|
||||
<li>
|
||||
<a href="{% url 'kick:game_detail' category.kick_id %}">{{ category.name }}</a>
|
||||
{% if category.campaign_count %}
|
||||
- {{ category.campaign_count }} campaign{{ category.campaign_count|pluralize }}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>No games found.</p>
|
||||
{% endif %}
|
||||
</main>
|
||||
{% endblock content %}
|
||||
176
templates/kick/dashboard.html
Normal file
176
templates/kick/dashboard.html
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
Kick Drops
|
||||
{% endblock title %}
|
||||
{% block extra_head %}
|
||||
<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 %}
|
||||
<main>
|
||||
<h1>Active Kick Drop Campaigns</h1>
|
||||
<!-- RSS Feeds -->
|
||||
<div>
|
||||
<a href="{% url 'kick:campaign_feed' %}"
|
||||
title="RSS feed for all campaigns">[rss]</a>
|
||||
<a href="{% url 'kick:campaign_feed_atom' %}"
|
||||
title="Atom feed for all campaigns">[atom]</a>
|
||||
<a href="{% url 'kick:campaign_feed_discord' %}"
|
||||
title="Discord feed for all campaigns">[discord]</a>
|
||||
</div>
|
||||
<hr />
|
||||
{% if active_campaigns %}
|
||||
{% for campaign in active_campaigns %}
|
||||
<!-- {{ campaign }} -->
|
||||
<article>
|
||||
<header>
|
||||
<h2>
|
||||
<a href="{% url 'kick:game_detail' campaign.category.kick_id %}">{{ campaign.category.name }}</a>
|
||||
</h2>
|
||||
<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>
|
||||
{% else %}
|
||||
Organization: Unknown
|
||||
{% endif %}
|
||||
</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"
|
||||
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;">
|
||||
<h3>
|
||||
<a href="{% url 'kick:campaign_detail' campaign.kick_id %}">{{ campaign.name }}</a>
|
||||
</h3>
|
||||
<!-- Start -->
|
||||
{% 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 %}
|
||||
<!-- End -->
|
||||
{% 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 %}
|
||||
<!-- Duration -->
|
||||
{% 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;">
|
||||
<a href="{{ campaign.category.kick_url }}">{{ campaign.category.name }}</a> is game wide.
|
||||
</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"
|
||||
style="vertical-align: middle;
|
||||
border-radius: 4px" />
|
||||
{% endif %}
|
||||
{{ reward.name }} ({{ reward.required_units }} min)
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>No active Kick drop campaigns at the moment. Check back later!</p>
|
||||
{% endif %}
|
||||
</main>
|
||||
{% endblock content %}
|
||||
44
templates/kick/org_list.html
Normal file
44
templates/kick/org_list.html
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
Kick Organizations
|
||||
{% endblock title %}
|
||||
{% block extra_head %}
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="All Kick organizations (RSS)"
|
||||
href="{% url 'kick:organization_feed' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick organizations (Atom)"
|
||||
href="{% url 'kick:organization_feed_atom' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick organizations (Discord)"
|
||||
href="{% url 'kick:organization_feed_discord' %}" />
|
||||
{% endblock extra_head %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<h1>Kick Organizations</h1>
|
||||
<div>
|
||||
<a href="{% url 'kick:organization_feed' %}"
|
||||
title="RSS feed for all organizations">[rss]</a>
|
||||
<a href="{% url 'kick:organization_feed_atom' %}"
|
||||
title="Atom feed for all organizations">[atom]</a>
|
||||
<a href="{% url 'kick:organization_feed_discord' %}"
|
||||
title="Discord feed for all organizations">[discord]</a>
|
||||
</div>
|
||||
{% if orgs %}
|
||||
<ul>
|
||||
{% for org in orgs %}
|
||||
<li>
|
||||
<a href="{% url 'kick:organization_detail' org.kick_id %}">{{ org.name }}</a>
|
||||
{% if org.campaign_count %}- {{ org.campaign_count }} campaign{{ org.campaign_count|pluralize }}{% endif %}
|
||||
{% if org.url %}- <a href="{{ org.url }}" rel="nofollow noopener" target="_blank">{{ org.url }}</a>{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>No organizations found.</p>
|
||||
{% endif %}
|
||||
</main>
|
||||
{% endblock content %}
|
||||
210
templates/kick/organization_detail.html
Normal file
210
templates/kick/organization_detail.html
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
{{ org.name }} — Kick Organization
|
||||
{% endblock title %}
|
||||
{% block extra_head %}
|
||||
<link rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="All Kick organizations (RSS)"
|
||||
href="{% url 'kick:organization_feed' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick organizations (Atom)"
|
||||
href="{% url 'kick:organization_feed_atom' %}" />
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="All Kick organizations (Discord)"
|
||||
href="{% url 'kick:organization_feed_discord' %}" />
|
||||
{% endblock extra_head %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<nav aria-label="Breadcrumb">
|
||||
<a href="{% url 'kick:dashboard' %}">Kick</a> >
|
||||
<a href="{% url 'kick:organization_list' %}">Organizations</a> >
|
||||
{{ org.name }}
|
||||
</nav>
|
||||
<div style="display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1rem">
|
||||
{% if org.logo_url %}
|
||||
<img src="{{ org.logo_url }}"
|
||||
alt="{{ org.name }} logo"
|
||||
width="200"
|
||||
height="200"
|
||||
loading="lazy"
|
||||
style="max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px" />
|
||||
{% endif %}
|
||||
<div>
|
||||
<h1 style="margin: 0 0 0.25rem 0;">{{ org.name }}</h1>
|
||||
<div>
|
||||
<a href="{% url 'kick:organization_feed' %}"
|
||||
title="RSS feed for all organizations">[rss]</a>
|
||||
<a href="{% url 'kick:organization_feed_atom' %}"
|
||||
title="Atom feed for all organizations">[atom]</a>
|
||||
<a href="{% url 'kick:organization_feed_discord' %}"
|
||||
title="Discord feed for all organizations">[discord]</a>
|
||||
</div>
|
||||
{% if org.restricted %}<p style="margin: 0.25rem 0; color: #b00;">Restricted</p>{% endif %}
|
||||
{% if org.url %}
|
||||
<p style="margin: 0.25rem 0;">
|
||||
<a href="{{ org.url }}" rel="nofollow noopener" target="_blank">{{ org.url }}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
<p style="margin: 0.25rem 0; font-size: 0.85rem; color: #666;">
|
||||
ID: {{ org.kick_id }}
|
||||
- Added: <time datetime="{{ org.added_at|date:'c' }}"
|
||||
title="{{ org.added_at|date:'DATETIME_FORMAT' }}">{{ org.added_at|date:"M d, Y" }}</time>
|
||||
({{ org.added_at|timesince }} ago)
|
||||
- Updated: <time datetime="{{ org.updated_at|date:'c' }}"
|
||||
title="{{ org.updated_at|date:'DATETIME_FORMAT' }}">{{ org.updated_at|date:"M d, Y" }}</time>
|
||||
({{ org.updated_at|timesince }} ago)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<h2>Campaigns</h2>
|
||||
{% if campaigns %}
|
||||
{% for campaign in 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.category %}
|
||||
Game:
|
||||
<a href="{% url 'kick:game_detail' campaign.category.kick_id %}">{{ campaign.category.name }}</a>
|
||||
-
|
||||
{% endif %}
|
||||
Status: {{ campaign.status }}
|
||||
</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"
|
||||
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 %}
|
||||
{% if campaign.category %}
|
||||
<p style="margin: 0.25rem 0 0 0;">
|
||||
<a href="{{ campaign.category.kick_url }}">{{ campaign.category.name }}</a> is game wide.
|
||||
</p>
|
||||
{% else %}
|
||||
<p style="margin: 0.25rem 0 0 0;">Channel wide.</p>
|
||||
{% endif %}
|
||||
{% 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"
|
||||
style="vertical-align: middle;
|
||||
border-radius: 4px" />
|
||||
{% endif %}
|
||||
{{ reward.name }} ({{ reward.required_units }} min)
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>No campaigns from this organization.</p>
|
||||
{% endif %}
|
||||
</main>
|
||||
{% endblock content %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue