Debloat HTML
This commit is contained in:
parent
c7c2d86ddb
commit
547d4e6ab1
18 changed files with 874 additions and 1284 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
# Generated by Django 5.2.4 on 2025-07-21 00:54
|
# Generated by Django 5.2.4 on 2025-07-21 00:54
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import django.contrib.auth.models
|
import django.contrib.auth.models
|
||||||
import django.contrib.auth.validators
|
import django.contrib.auth.validators
|
||||||
|
|
@ -7,38 +8,86 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('auth', '0012_alter_user_first_name_max_length'),
|
("auth", "0012_alter_user_first_name_max_length"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='User',
|
name="User",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")),
|
||||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
(
|
||||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
"is_superuser",
|
||||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
models.BooleanField(
|
||||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
default=False,
|
||||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
||||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
verbose_name="superuser status",
|
||||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
),
|
||||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
),
|
||||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
(
|
||||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
"username",
|
||||||
|
models.CharField(
|
||||||
|
error_messages={"unique": "A user with that username already exists."},
|
||||||
|
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
||||||
|
max_length=150,
|
||||||
|
unique=True,
|
||||||
|
validators=[django.contrib.auth.validators.UnicodeUsernameValidator()],
|
||||||
|
verbose_name="username",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("first_name", models.CharField(blank=True, max_length=150, verbose_name="first name")),
|
||||||
|
("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")),
|
||||||
|
("email", models.EmailField(blank=True, max_length=254, verbose_name="email address")),
|
||||||
|
(
|
||||||
|
"is_staff",
|
||||||
|
models.BooleanField(
|
||||||
|
default=False, help_text="Designates whether the user can log into this admin site.", verbose_name="staff status"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_active",
|
||||||
|
models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||||
|
verbose_name="active",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")),
|
||||||
|
(
|
||||||
|
"groups",
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
|
||||||
|
related_name="user_set",
|
||||||
|
related_query_name="user",
|
||||||
|
to="auth.group",
|
||||||
|
verbose_name="groups",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user_permissions",
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Specific permissions for this user.",
|
||||||
|
related_name="user_set",
|
||||||
|
related_query_name="user",
|
||||||
|
to="auth.permission",
|
||||||
|
verbose_name="user permissions",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'User',
|
"verbose_name": "User",
|
||||||
'verbose_name_plural': 'Users',
|
"verbose_name_plural": "Users",
|
||||||
'db_table': 'auth_user',
|
"db_table": "auth_user",
|
||||||
},
|
},
|
||||||
managers=[
|
managers=[
|
||||||
('objects', django.contrib.auth.models.UserManager()),
|
("objects", django.contrib.auth.models.UserManager()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, ClassVar
|
||||||
|
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
|
@ -36,6 +36,20 @@ class CustomLogoutView(LogoutView):
|
||||||
"""Custom logout view."""
|
"""Custom logout view."""
|
||||||
|
|
||||||
next_page = reverse_lazy("twitch:dashboard")
|
next_page = reverse_lazy("twitch:dashboard")
|
||||||
|
http_method_names: ClassVar[list[str]] = ["get", "post", "options"] # pyright: ignore[reportIncompatibleVariableOverride]
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
|
"""Allow GET requests for logout.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The HTTP request object.
|
||||||
|
*args: Additional positional arguments.
|
||||||
|
**kwargs: Additional keyword arguments.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
HttpResponse: Response after logout.
|
||||||
|
"""
|
||||||
|
return self.post(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class SignUpView(CreateView):
|
class SignUpView(CreateView):
|
||||||
|
|
|
||||||
|
|
@ -189,10 +189,13 @@ TESTING: bool = "test" in sys.argv or "PYTEST_VERSION" in os.environ
|
||||||
if not TESTING:
|
if not TESTING:
|
||||||
DEBUG_TOOLBAR_CONFIG: dict[str, str] = {"ROOT_TAG_EXTRA_ATTRS": "hx-preserve"}
|
DEBUG_TOOLBAR_CONFIG: dict[str, str] = {"ROOT_TAG_EXTRA_ATTRS": "hx-preserve"}
|
||||||
INSTALLED_APPS = [ # pyright: ignore[reportConstantRedefinition]
|
INSTALLED_APPS = [ # pyright: ignore[reportConstantRedefinition]
|
||||||
|
"django_watchfiles",
|
||||||
*INSTALLED_APPS,
|
*INSTALLED_APPS,
|
||||||
"debug_toolbar",
|
"debug_toolbar",
|
||||||
|
"django_browser_reload",
|
||||||
]
|
]
|
||||||
MIDDLEWARE = [ # pyright: ignore[reportConstantRedefinition]
|
MIDDLEWARE = [ # pyright: ignore[reportConstantRedefinition]
|
||||||
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
||||||
*MIDDLEWARE,
|
*MIDDLEWARE,
|
||||||
|
"django_browser_reload.middleware.BrowserReloadMiddleware",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,8 @@ urlpatterns: list[URLResolver] = [
|
||||||
]
|
]
|
||||||
|
|
||||||
if not settings.TESTING:
|
if not settings.TESTING:
|
||||||
urlpatterns = [*urlpatterns, *debug_toolbar_urls()]
|
urlpatterns = [
|
||||||
|
*urlpatterns,
|
||||||
|
*debug_toolbar_urls(),
|
||||||
|
path("__reload__/", include("django_browser_reload.urls")),
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,10 @@ readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"django>=5.2.4",
|
"django>=5.2.4",
|
||||||
|
"django-browser-reload>=1.18.0",
|
||||||
"django-debug-toolbar>=5.2.0",
|
"django-debug-toolbar>=5.2.0",
|
||||||
|
"django-watchfiles>=1.1.0",
|
||||||
|
"djlint>=1.36.4",
|
||||||
"platformdirs>=4.3.8",
|
"platformdirs>=4.3.8",
|
||||||
"python-dotenv>=1.1.1",
|
"python-dotenv>=1.1.1",
|
||||||
]
|
]
|
||||||
|
|
@ -76,3 +79,7 @@ line-length = 140
|
||||||
"S105",
|
"S105",
|
||||||
]
|
]
|
||||||
"**/migrations/**" = ["RUF012"]
|
"**/migrations/**" = ["RUF012"]
|
||||||
|
|
||||||
|
[tool.djlint]
|
||||||
|
profile = "django"
|
||||||
|
ignore = "H021"
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,35 @@
|
||||||
{% extends 'base.html' %}
|
{% extends "base.html" %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}Login{% endblock %}
|
Login
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mt-5">
|
<h4>Login</h4>
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="card shadow">
|
|
||||||
<div class="card-header bg-primary text-white">
|
|
||||||
<h4 class="mb-0"><i class="fas fa-sign-in-alt"></i> Login</h4>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
<div class="alert alert-danger">
|
<ul>
|
||||||
<ul class="mb-0">
|
|
||||||
{% for field, errors in form.errors.items %}
|
{% for field, errors in form.errors.items %}
|
||||||
{% for error in errors %}
|
{% for error in errors %}<li>{{ error }}</li>{% endfor %}
|
||||||
<li>{{ error }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="mb-3">
|
<label for="{{ form.username.id_for_label }}">Username</label>
|
||||||
<label for="{{ form.username.id_for_label }}" class="form-label">Username</label>
|
<input type="text"
|
||||||
<div class="input-group">
|
name="username"
|
||||||
<span class="input-group-text"><i class="fas fa-user"></i></span>
|
id="{{ form.username.id_for_label }}"
|
||||||
<input type="text" class="form-control" name="username"
|
value="{{ form.username.value|default:'' }}"
|
||||||
id="{{ form.username.id_for_label }}" value="{{ form.username.value|default:'' }}"
|
|
||||||
required>
|
required>
|
||||||
</div>
|
<label for="{{ form.password.id_for_label }}">Password</label>
|
||||||
</div>
|
<input type="password"
|
||||||
|
name="password"
|
||||||
<div class="mb-3">
|
id="{{ form.password.id_for_label }}"
|
||||||
<label for="{{ form.password.id_for_label }}" class="form-label">Password</label>
|
required>
|
||||||
<div class="input-group">
|
<button type="submit">Login</button>
|
||||||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
|
||||||
<input type="password" class="form-control" name="password"
|
|
||||||
id="{{ form.password.id_for_label }}" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-grid">
|
|
||||||
<button type="submit" class="btn btn-primary btn-lg">
|
|
||||||
<i class="fas fa-sign-in-alt"></i> Login
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<p>
|
||||||
<div class="card-footer text-center">
|
Don't have an account? <a href="{% url 'accounts:signup' %}">Sign up here</a>
|
||||||
<p class="mb-0">Don't have an account? <a href="{% url 'accounts:signup' %}"
|
</p>
|
||||||
class="text-decoration-none">Sign up here</a></p>
|
<style>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.form-control {
|
.form-control {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
@ -69,5 +38,5 @@
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -1,124 +1,29 @@
|
||||||
{% extends 'base.html' %}
|
{% extends "base.html" %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}Profile{% endblock %}
|
{{ user.username }}
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mt-5">
|
<h2>{{ user.username }}</h2>
|
||||||
<div class="row justify-content-center">
|
<p>Joined {{ user.date_joined|date:"F d, Y" }}</p>
|
||||||
<div class="col-md-8">
|
<table>
|
||||||
<div class="card shadow">
|
|
||||||
<div class="card-header bg-info text-white">
|
|
||||||
<h4 class="mb-0"><i class="fas fa-user-circle"></i> User Profile</h4>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4 text-center">
|
|
||||||
<div class="avatar-placeholder bg-light rounded-circle d-inline-flex align-items-center justify-content-center"
|
|
||||||
style="width: 120px; height: 120px;">
|
|
||||||
<i class="fas fa-user fa-3x text-muted"></i>
|
|
||||||
</div>
|
|
||||||
<h5 class="mt-3">{{ user.username }}</h5>
|
|
||||||
<p class="text-muted">Member since {{ user.date_joined|date:"F Y" }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<h5>Account Information</h5>
|
|
||||||
<table class="table table-borderless">
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Username:</strong></td>
|
<td>
|
||||||
<td>{{ user.username }}</td>
|
<strong>Date Joined:</strong>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
|
||||||
<td><strong>Email:</strong></td>
|
|
||||||
<td>{{ user.email|default:"Not provided" }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><strong>Date Joined:</strong></td>
|
|
||||||
<td>{{ user.date_joined|date:"F d, Y" }}</td>
|
<td>{{ user.date_joined|date:"F d, Y" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Last Login:</strong></td>
|
<td>
|
||||||
|
<strong>Last Login:</strong>
|
||||||
|
</td>
|
||||||
<td>{{ user.last_login|date:"F d, Y H:i"|default:"Never" }}</td>
|
<td>{{ user.last_login|date:"F d, Y H:i"|default:"Never" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Account Status:</strong></td>
|
|
||||||
<td>
|
<td>
|
||||||
{% if user.is_active %}
|
<strong>Email:</strong>
|
||||||
<span class="badge bg-success">Active</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Inactive</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if user.is_staff %}
|
|
||||||
<span class="badge bg-warning">Staff</span>
|
|
||||||
{% endif %}
|
|
||||||
{% if user.is_superuser %}
|
|
||||||
<span class="badge bg-danger">Superuser</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
|
<td>{{ user.email|default:"Not provided" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
<a href="{% url 'accounts:logout' %}">Logout</a>
|
||||||
</div>
|
{% endblock content %}
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<a href="{% url 'twitch:dashboard' %}" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
|
||||||
</a>
|
|
||||||
<div>
|
|
||||||
<button class="btn btn-outline-primary me-2"
|
|
||||||
onclick="alert('Profile editing feature coming soon!')">
|
|
||||||
<i class="fas fa-edit"></i> Edit Profile
|
|
||||||
</button>
|
|
||||||
<a href="{% url 'accounts:logout' %}" class="btn btn-danger">
|
|
||||||
<i class="fas fa-sign-out-alt"></i> Logout
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Quick Stats Card -->
|
|
||||||
<div class="card shadow mt-4">
|
|
||||||
<div class="card-header bg-secondary text-white">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-chart-bar"></i> Quick Stats</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row text-center">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h3 class="text-primary">-</h3>
|
|
||||||
<p class="text-muted">Campaigns Tracked</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h3 class="text-info">-</h3>
|
|
||||||
<p class="text-muted">Games Followed</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.stat-card {
|
|
||||||
padding: 1rem;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stat-card h3 {
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-placeholder {
|
|
||||||
border: 3px solid #dee2e6;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
|
|
@ -1,96 +1,40 @@
|
||||||
{% extends 'base.html' %}
|
{% extends "base.html" %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}Sign Up{% endblock %}
|
Sign Up
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mt-5">
|
<h4>Sign Up</h4>
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="card shadow">
|
|
||||||
<div class="card-header bg-success text-white">
|
|
||||||
<h4 class="mb-0"><i class="fas fa-user-plus"></i> Sign Up</h4>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
<div class="alert alert-danger">
|
<ul>
|
||||||
<ul class="mb-0">
|
|
||||||
{% for field, errors in form.errors.items %}
|
{% for field, errors in form.errors.items %}
|
||||||
{% for error in errors %}
|
{% for error in errors %}<li>{{ error }}</li>{% endfor %}
|
||||||
<li>{{ error }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="mb-3">
|
<label for="{{ form.username.id_for_label }}">Username</label>
|
||||||
<label for="{{ form.username.id_for_label }}" class="form-label">Username</label>
|
<input type="text"
|
||||||
<div class="input-group">
|
name="username"
|
||||||
<span class="input-group-text"><i class="fas fa-user"></i></span>
|
id="{{ form.username.id_for_label }}"
|
||||||
<input type="text" class="form-control" name="username"
|
value="{{ form.username.value|default:'' }}"
|
||||||
id="{{ form.username.id_for_label }}" value="{{ form.username.value|default:'' }}"
|
|
||||||
required>
|
required>
|
||||||
</div>
|
{% if form.username.help_text %}{{ form.username.help_text }}{% endif %}
|
||||||
{% if form.username.help_text %}
|
<label for="{{ form.password1.id_for_label }}">Password</label>
|
||||||
<div class="form-text">{{ form.username.help_text }}</div>
|
<input type="password"
|
||||||
{% endif %}
|
name="password1"
|
||||||
</div>
|
id="{{ form.password1.id_for_label }}"
|
||||||
|
required>
|
||||||
<div class="mb-3">
|
{% if form.password1.help_text %}{{ form.password1.help_text }}{% endif %}
|
||||||
<label for="{{ form.password1.id_for_label }}" class="form-label">Password</label>
|
<label for="{{ form.password2.id_for_label }}">Confirm Password</label>
|
||||||
<div class="input-group">
|
<input type="password"
|
||||||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
name="password2"
|
||||||
<input type="password" class="form-control" name="password1"
|
id="{{ form.password2.id_for_label }}"
|
||||||
id="{{ form.password1.id_for_label }}" required>
|
required>
|
||||||
</div>
|
{% if form.password2.help_text %}{{ form.password2.help_text }}{% endif %}
|
||||||
{% if form.password1.help_text %}
|
<button type="submit">Sign Up</button>
|
||||||
<div class="form-text">{{ form.password1.help_text }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="{{ form.password2.id_for_label }}" class="form-label">Confirm Password</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-text"><i class="fas fa-lock"></i></span>
|
|
||||||
<input type="password" class="form-control" name="password2"
|
|
||||||
id="{{ form.password2.id_for_label }}" required>
|
|
||||||
</div>
|
|
||||||
{% if form.password2.help_text %}
|
|
||||||
<div class="form-text">{{ form.password2.help_text }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-grid">
|
|
||||||
<button type="submit" class="btn btn-success btn-lg">
|
|
||||||
<i class="fas fa-user-plus"></i> Sign Up
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<p>
|
||||||
<div class="card-footer text-center">
|
Already have an account? <a href="{% url 'accounts:login' %}">Login here</a>
|
||||||
<p class="mb-0">Already have an account? <a href="{% url 'accounts:login' %}"
|
</p>
|
||||||
class="text-decoration-none">Login here</a></p>
|
{% endblock content %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.form-control {
|
|
||||||
border-left: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group-text {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-text {
|
|
||||||
font-size: 0.875em;
|
|
||||||
color: #6c757d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
|
|
@ -1,135 +1,41 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{% block title %}ttvdrops{% endblock %}</title>
|
<meta name="description"
|
||||||
<!-- Bootstrap CSS -->
|
content="Twitch Drops Tracker - Track your Twitch drops and campaigns easily.">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<meta name="keywords" content="Twitch, Drops">
|
||||||
<!-- FontAwesome -->
|
<title>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
{% block title %}
|
||||||
|
ttvdrops
|
||||||
|
{% endblock title %}
|
||||||
|
</title>
|
||||||
<style>
|
<style>
|
||||||
/* Custom styles */
|
body {
|
||||||
.campaign-card {
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
|
||||||
height: 100%;
|
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
padding: 0 15px;
|
||||||
|
max-width: 650px;
|
||||||
|
font-size: 115%;
|
||||||
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.campaign-active {
|
html {
|
||||||
border-left: 4px solid #9147ff;
|
color-scheme: light dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
.campaign-upcoming {
|
img {
|
||||||
border-left: 4px solid #1d9bf0;
|
max-width: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.campaign-expired {
|
|
||||||
border-left: 4px solid #6c757d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drop-item {
|
|
||||||
border-left: 4px solid #9147ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.twitch-color {
|
|
||||||
color: #9147ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-twitch {
|
|
||||||
background-color: #9147ff;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.benefit-img {
|
|
||||||
width: 160px;
|
|
||||||
height: 160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header h3 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% block extra_css %}{% endblock %}
|
</head>
|
||||||
</head>
|
<body>
|
||||||
|
{% include "navbar.html" %}
|
||||||
<body>
|
<div class="content">
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
|
{% block content %}
|
||||||
<div class="container">
|
<!-- Main content will be injected here -->
|
||||||
<a class="navbar-brand" href="{% url 'twitch:dashboard' %}">
|
{% endblock content %}
|
||||||
<i class="fa-brands fa-twitch me-2"></i>ttvdrops
|
|
||||||
</a>
|
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
|
||||||
<ul class="navbar-nav ms-auto">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if request.path == '/' %}active{% endif %}"
|
|
||||||
href="{% url 'twitch:dashboard' %}">
|
|
||||||
<i class="fas fa-home me-1"></i> Dashboard
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if '/campaigns/' in request.path %}active{% endif %}"
|
|
||||||
href="{% url 'twitch:campaign_list' %}">
|
|
||||||
<i class="fas fa-gift me-1"></i> Campaigns
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link {% if '/games/' in request.path %}active{% endif %}"
|
|
||||||
href="{% url 'twitch:game_list' %}">
|
|
||||||
<i class="fas fa-gamepad me-1"></i> Games
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
{% if user.is_staff %}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="{% url 'admin:index' %}">
|
|
||||||
<i class="fas fa-cog me-1"></i> Admin
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
|
|
||||||
data-bs-toggle="dropdown" aria-expanded="false">
|
|
||||||
<i class="fas fa-user me-1"></i> {{ user.username }}
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
|
|
||||||
<li><a class="dropdown-item" href="{% url 'accounts:profile' %}">
|
|
||||||
<i class="fas fa-user-circle me-2"></i> Profile
|
|
||||||
</a></li>
|
|
||||||
<li>
|
|
||||||
<hr class="dropdown-divider">
|
|
||||||
</li>
|
|
||||||
<li><a class="dropdown-item" href="{% url 'accounts:logout' %}">
|
|
||||||
<i class="fas fa-sign-out-alt me-2"></i> Logout
|
|
||||||
</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="{% url 'accounts:login' %}">
|
|
||||||
<i class="fas fa-sign-in-alt me-1"></i> Login
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="{% url 'accounts:signup' %}">
|
|
||||||
<i class="fas fa-user-plus me-1"></i> Sign Up
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</body>
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container mb-5">
|
|
||||||
{% block content %}{% endblock %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bootstrap JS Bundle with Popper -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
{% block extra_js %}{% endblock %}
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
21
templates/navbar.html
Normal file
21
templates/navbar.html
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<nav>
|
||||||
|
<a href="{% url 'twitch:dashboard' %}"
|
||||||
|
{% if request.path == '/dashboard/' %}class="active"{% endif %}>Dashboard</a>
|
||||||
|
<a href="{% url 'twitch:campaign_list' %}"
|
||||||
|
{% if '/campaigns/' in request.path %}class="active"{% endif %}>Campaigns</a>
|
||||||
|
<a href="{% url 'twitch:game_list' %}"
|
||||||
|
{% if '/games/' in request.path %}class="active"{% endif %}>Games</a>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<a href="{% url 'admin:index' %}"
|
||||||
|
{% if '/admin/' in request.path %}class="active"{% endif %}>Admin</a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{% url 'accounts:profile' %}"
|
||||||
|
{% if '/profile/' in request.path %}class="active"{% endif %}>{{ user.username }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url 'accounts:login' %}"
|
||||||
|
{% if '/login/' in request.path %}class="active"{% endif %}>Login</a>
|
||||||
|
<a href="{% url 'accounts:signup' %}"
|
||||||
|
{% if '/signup/' in request.path %}class="active"{% endif %}>Sign Up</a>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
|
@ -1,152 +1,95 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
{% block title %}{{ campaign.clean_name }} - Twitch Drops Tracker{% endblock %}
|
{% block title %}
|
||||||
|
{{ campaign.clean_name }}
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-4">
|
<h1>
|
||||||
<div class="col-12">
|
<a href="{% url 'twitch:game_detail' campaign.game.id %}">{{ campaign.game.display_name }}</a> - {{ campaign.clean_name }}
|
||||||
<nav aria-label="breadcrumb">
|
</h1>
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'twitch:dashboard' %}">Dashboard</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{% url 'twitch:campaign_list' %}">Campaigns</a></li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ campaign.clean_name }}</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-md-8">
|
|
||||||
<h1 class="mb-3">{{ campaign.clean_name }}</h1>
|
|
||||||
<div class="d-flex flex-wrap gap-2 mb-3">
|
|
||||||
<a href="{% url 'twitch:game_detail' campaign.game.id %}" class="badge bg-primary text-decoration-none">
|
|
||||||
<i class="fas fa-gamepad me-1"></i>{{ campaign.game.display_name }}
|
|
||||||
</a>
|
|
||||||
{% if campaign.start_at <= now and campaign.end_at >= now %}
|
|
||||||
{% if campaign.status == 'ACTIVE' %}
|
|
||||||
<span class="badge bg-success">Active</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-warning text-dark">{{ campaign.status|title }}</span>
|
|
||||||
{% endif %}
|
|
||||||
{% elif campaign.start_at > now %}
|
|
||||||
<span class="badge bg-info text-dark">Upcoming</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-secondary">Expired</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<p>{{ campaign.description }}</p>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong><i class="far fa-calendar-alt me-2"></i>Start Date:</strong>
|
|
||||||
{{ campaign.start_at|date:"F j, Y, g:i a" }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong><i class="far fa-calendar-alt me-2"></i>End Date:</strong>
|
|
||||||
{{ campaign.end_at|date:"F j, Y, g:i a" }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if campaign.details_url %}
|
|
||||||
<p>
|
<p>
|
||||||
<a href="{{ campaign.details_url }}" target="_blank" class="btn btn-outline-primary">
|
{# TODO: Link to organization #}
|
||||||
<i class="fas fa-external-link-alt me-2"></i>Official Details
|
<a href="#">{{ campaign.owner.name }}</a>
|
||||||
</a>
|
</p>
|
||||||
|
{% if campaign.image_url %}
|
||||||
|
<img height="70"
|
||||||
|
width="70"
|
||||||
|
src="{{ campaign.image_url }}"
|
||||||
|
alt="{{ campaign.name }}">
|
||||||
|
{% endif %}
|
||||||
|
<p>{{ campaign.description }}</p>
|
||||||
|
<p>
|
||||||
|
Start:
|
||||||
|
{{ campaign.start_at }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
End:
|
||||||
|
{{ campaign.end_at }}
|
||||||
|
</p>
|
||||||
|
{% if campaign.details_url %}
|
||||||
|
{# TODO: Archive this URL automatically #}
|
||||||
|
<p>
|
||||||
|
<a href="{{ campaign.details_url }}" target="_blank">Official Details</a>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if campaign.account_link_url %}
|
{% if campaign.account_link_url %}
|
||||||
|
{# TODO: Archive this URL automatically #}
|
||||||
<p>
|
<p>
|
||||||
<a href="{{ campaign.account_link_url }}" target="_blank" class="btn btn-success">
|
<a href="{{ campaign.account_link_url }}" target="_blank">Connect Account</a>
|
||||||
<i class="fas fa-link me-2"></i>Connect Account
|
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
<h5>Campaign Info</h5>
|
||||||
<div class="col-md-4">
|
{% if user.is_staff %}
|
||||||
{% if campaign.image_url %}
|
<p>
|
||||||
<img src="{{ campaign.image_url }}" class="img-fluid rounded shadow-sm" alt="{{ campaign.name }}">
|
{% if campaign.is_account_connected %}
|
||||||
|
Connected
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="bg-light rounded shadow-sm p-4 text-center">
|
Not Connected
|
||||||
<i class="fas fa-image fa-5x text-muted mb-3"></i>
|
{% endif %}
|
||||||
<p class="text-muted">No image available</p>
|
</p>
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="card mt-3 border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-dark text-white">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-info-circle me-2"></i>Campaign Info</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<p><strong>Owner:</strong> {{ campaign.owner.name }}</p>
|
|
||||||
<p><strong>Status:</strong> {{ campaign.status }}</p>
|
|
||||||
<p><strong>Account Connected:</strong> {% if campaign.is_account_connected %}<span
|
|
||||||
class="text-success">Yes</span>{% else %}<span class="text-danger">No</span>{% endif %}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-twitch">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-gift me-2"></i>Rewards</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
{% if drops %}
|
{% if drops %}
|
||||||
<div class="timeline-container">
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Image</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Requirements</th>
|
||||||
|
<th>Availability</th>
|
||||||
|
</tr>
|
||||||
{% for drop in drops %}
|
{% for drop in drops %}
|
||||||
<div class="card mb-4 drop-item">
|
<tr>
|
||||||
<div class="card-body">
|
<td>
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-8">
|
|
||||||
<h4>{{ drop.name }}</h4>
|
|
||||||
<p class="mb-2">
|
|
||||||
<span class="badge bg-primary">{{ drop.required_minutes_watched }} minutes
|
|
||||||
watched</span>
|
|
||||||
{% if drop.required_subs > 0 %}
|
|
||||||
<span class="badge bg-info">{{ drop.required_subs }} subscriptions
|
|
||||||
required</span>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
<p class="mb-2">
|
|
||||||
<small class="text-muted">
|
|
||||||
<i class="far fa-clock me-1"></i>Available:
|
|
||||||
{{ drop.start_at|date:"M d, Y" }} - {{ drop.end_at|date:"M d, Y" }}
|
|
||||||
</small>
|
|
||||||
</p>
|
|
||||||
<div class="progress mb-3" style="height: 25px;">
|
|
||||||
<div class="progress-bar bg-twitch" role="progressbar" style="width: 0%;"
|
|
||||||
aria-valuenow="0" aria-valuemin="0"
|
|
||||||
aria-valuemax="{{ drop.required_minutes_watched }}">
|
|
||||||
0 / {{ drop.required_minutes_watched }} minutes
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 text-center">
|
|
||||||
{% for benefit in drop.benefits.all %}
|
{% for benefit in drop.benefits.all %}
|
||||||
<div class="mb-2">
|
|
||||||
{% if benefit.image_asset_url %}
|
{% if benefit.image_asset_url %}
|
||||||
<img src="{{ benefit.image_asset_url }}" class="benefit-img mb-2"
|
<img height="120"
|
||||||
|
width="120"
|
||||||
|
style="object-fit: cover"
|
||||||
|
src="{{ benefit.image_asset_url }}"
|
||||||
alt="{{ benefit.name }}">
|
alt="{{ benefit.name }}">
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="bg-light rounded p-3 mb-2">
|
<img height="120"
|
||||||
<i class="fas fa-gift fa-3x text-muted"></i>
|
width="120"
|
||||||
</div>
|
style="object-fit: cover"
|
||||||
|
src="{% static 'images/placeholder.png' %}"
|
||||||
|
alt="No Image Available">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="mb-0"><strong>{{ benefit.name }}</strong></p>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</td>
|
||||||
</div>
|
<td>{{ drop.name }}</td>
|
||||||
</div>
|
<td>
|
||||||
</div>
|
{{ drop.required_minutes_watched }} minutes watched
|
||||||
|
{% if drop.required_subs > 0 %}and {{ drop.required_subs }} subscriptions required{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ drop.start_at }} - {{ drop.end_at }}</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
{% if not drops %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="6">No drops found for this campaign.</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-info">
|
<p>No drops available for this campaign.</p>
|
||||||
<i class="fas fa-info-circle me-2"></i>No drops found for this campaign.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
{% endblock content %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
|
|
@ -1,286 +1,114 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
{% block title %}Drop Campaigns - Twitch Drops Tracker{% endblock %}
|
{% block title %}
|
||||||
|
Drop Campaigns - Twitch Drops Tracker
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-3">
|
<h1>Drop Campaigns</h1>
|
||||||
<div class="col">
|
<form method="get" action="{% url 'twitch:campaign_list' %}">
|
||||||
<h1 class="mb-2"><i class="fas fa-gift me-2 twitch-color"></i>Drop Campaigns</h1>
|
<!-- Game Filter -->
|
||||||
<p class="lead mb-3">Browse all Twitch drop campaigns.</p>
|
<select id="game" name="game">
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-dark text-white py-2">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-filter me-2"></i>Filter Campaigns</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body py-3">
|
|
||||||
<form method="get" action="{% url 'twitch:campaign_list' %}" class="row g-3">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<label for="game" class="form-label">Game</label>
|
|
||||||
<select class="form-select" id="game" name="game">
|
|
||||||
<option value="">All Games</option>
|
<option value="">All Games</option>
|
||||||
{% for game in games %}
|
{% for game in games %}
|
||||||
<option value="{{ game.id }}" {% if selected_game == game.id %}selected{% endif %}>
|
<option value="{{ game.id }}"
|
||||||
{{ game.display_name }}
|
{% if selected_game == game.id %}selected{% endif %}>{{ game.display_name }}</option>
|
||||||
</option>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
<!-- Status Filter -->
|
||||||
<div class="col-md-3">
|
<select id="status" name="status">
|
||||||
<label for="status" class="form-label">Status</label>
|
|
||||||
<select class="form-select" id="status" name="status">
|
|
||||||
<option value="">All Statuses</option>
|
<option value="">All Statuses</option>
|
||||||
{% for status in status_options %}
|
{% for status in status_options %}
|
||||||
<option value="{{ status }}" {% if selected_status == status %}selected{% endif %}>
|
<option value="{{ status }}"
|
||||||
{{ status|title }}
|
{% if selected_status == status %}selected{% endif %}>{{ status|title }}</option>
|
||||||
</option>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
<button type="submit">Apply Filters</button>
|
||||||
<div class="col-md-2">
|
|
||||||
<label for="per_page" class="form-label">Per Page</label>
|
|
||||||
<select class="form-select" id="per_page" name="per_page">
|
|
||||||
{% for option in per_page_options %}
|
|
||||||
<option value="{{ option }}" {% if selected_per_page == option %}selected{% endif %}>
|
|
||||||
{{ option }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 d-flex align-items-end">
|
|
||||||
<button type="submit" class="btn btn-primary w-100">
|
|
||||||
<i class="fas fa-search me-2"></i>Apply Filters
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<h5>Campaign List</h5>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-twitch py-2">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-list me-2"></i>Campaign List</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body py-3">
|
|
||||||
{% if campaigns %}
|
{% if campaigns %}
|
||||||
<div class="row g-3">
|
|
||||||
{% for campaign in campaigns %}
|
{% for campaign in campaigns %}
|
||||||
<div class="col-md-6 col-lg-4 col-xl-3">
|
|
||||||
{% if campaign.start_at <= now and campaign.end_at >= now %}
|
|
||||||
{% if campaign.status == 'ACTIVE' %}
|
|
||||||
<div class="campaign-card campaign-active border rounded p-2">
|
|
||||||
{% else %}
|
|
||||||
<div class="campaign-card border rounded p-2">
|
|
||||||
{% endif %}
|
|
||||||
{% elif campaign.start_at > now %}
|
|
||||||
<div class="campaign-card campaign-upcoming border rounded p-2">
|
|
||||||
{% else %}
|
|
||||||
<div class="campaign-card campaign-expired border rounded p-2">
|
|
||||||
{% endif %}
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="campaign-image flex-shrink-0 me-3">
|
|
||||||
{% if campaign.image_url %}
|
{% if campaign.image_url %}
|
||||||
<img src="{{ campaign.image_url }}" width="70" height="70"
|
<img src="{{ campaign.image_url }}"
|
||||||
class="rounded" alt="{{ campaign.name }}"
|
width="70"
|
||||||
style="object-fit: cover;">
|
height="70"
|
||||||
|
alt="{{ campaign.name }}">
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="bg-light rounded"
|
<img src="{% static 'images/placeholder.png' %}"
|
||||||
style="width: 70px; height: 70px; display: flex; align-items: center; justify-content: center;">
|
width="70"
|
||||||
<i class="fas fa-image text-muted" style="font-size: 1.5rem;"></i>
|
height="70"
|
||||||
</div>
|
alt="No Image Available">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
<h6 title="{{ campaign.name }}">{{ campaign.clean_name }}</h6>
|
||||||
<div class="campaign-details min-w-0">
|
<p>
|
||||||
<div class="title-wrapper" style="min-height: 2.4rem;">
|
|
||||||
<h6 class="mb-1" title="{{ campaign.name }}"
|
|
||||||
style="display: -webkit-box; display: box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; box-orient: vertical; overflow: hidden; font-size: 0.9rem;">
|
|
||||||
{{ campaign.clean_name }}</h6>
|
|
||||||
</div>
|
|
||||||
<p class="mb-1 small text-muted text-truncate">
|
|
||||||
<a href="{% url 'twitch:game_detail' campaign.game.id %}"
|
<a href="{% url 'twitch:game_detail' campaign.game.id %}"
|
||||||
class="text-decoration-none"
|
title="{{ campaign.game.display_name }}">{{ campaign.game.display_name }}</a>
|
||||||
title="{{ campaign.game.display_name }}">
|
|
||||||
<i
|
|
||||||
class="fas fa-gamepad me-1"></i>{{ campaign.game.display_name }}
|
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-0 small text-muted">
|
<p>
|
||||||
<i
|
{{ campaign.start_at|date:"M d, Y" }}
|
||||||
class="far fa-calendar-alt me-1"></i>{{ campaign.start_at|date:"M d, Y" }}
|
|
||||||
- {{ campaign.end_at|date:"M d, Y" }}
|
- {{ campaign.end_at|date:"M d, Y" }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-between align-items-center mt-2">
|
|
||||||
{% if campaign.start_at <= now and campaign.end_at >= now %}
|
{% if campaign.start_at <= now and campaign.end_at >= now %}
|
||||||
{% if campaign.status == 'ACTIVE' %}
|
{% if campaign.status == 'ACTIVE' %}Active{% endif %}
|
||||||
<span class="badge bg-success">Active</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-warning text-dark">{{ campaign.status|title }}</span>
|
|
||||||
{% endif %}
|
|
||||||
{% elif campaign.start_at > now %}
|
{% elif campaign.start_at > now %}
|
||||||
<span class="badge bg-info text-dark">Upcoming</span>
|
Upcoming
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="badge bg-secondary">Expired</span>
|
Expired
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'twitch:campaign_detail' campaign.id %}"
|
<a href="{% url 'twitch:campaign_detail' campaign.id %}">Details</a>
|
||||||
class="btn btn-sm btn-outline-primary">Details</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-info py-2">
|
No campaigns found with the current filters.
|
||||||
<i class="fas fa-info-circle me-2"></i>No campaigns found with the current filters.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<div class="row mt-3">
|
<nav>
|
||||||
<div class="col-12">
|
<ul>
|
||||||
<nav aria-label="Campaign pagination">
|
|
||||||
<ul class="pagination justify-content-center">
|
|
||||||
{% if page_obj.has_previous %}
|
{% if page_obj.has_previous %}
|
||||||
<li class="page-item">
|
<li>
|
||||||
<a class="page-link"
|
<a href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page=1">
|
||||||
href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page=1"
|
««
|
||||||
aria-label="First">
|
|
||||||
<span aria-hidden="true">««</span>
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item">
|
<li>
|
||||||
<a class="page-link"
|
<a href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ page_obj.previous_page_number }}"
|
||||||
href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ page_obj.previous_page_number }}"
|
aria-label="Previous">«</a>
|
||||||
aria-label="Previous">
|
|
||||||
<span aria-hidden="true">«</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="page-item disabled">
|
<li>««</li>
|
||||||
<span class="page-link" aria-label="First">
|
<li>«</li>
|
||||||
<span aria-hidden="true">««</span>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link" aria-label="Previous">
|
|
||||||
<span aria-hidden="true">«</span>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for num in page_obj.paginator.page_range %}
|
{% for num in page_obj.paginator.page_range %}
|
||||||
{% if page_obj.number == num %}
|
{% if page_obj.number == num %}
|
||||||
<li class="page-item active">
|
<li>{{ num }}</li>
|
||||||
<span class="page-link">{{ num }}</span>
|
|
||||||
</li>
|
|
||||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||||
<li class="page-item">
|
<li>
|
||||||
<a class="page-link"
|
<a href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ num }}">{{ num }}</a>
|
||||||
href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ num }}">{{ num }}</a>
|
|
||||||
</li>
|
</li>
|
||||||
{% elif num == 1 or num == page_obj.paginator.num_pages %}
|
{% elif num == 1 or num == page_obj.paginator.num_pages %}
|
||||||
<li class="page-item">
|
<li>
|
||||||
<a class="page-link"
|
<a href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ num }}">{{ num }}</a>
|
||||||
href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ num }}">{{ num }}</a>
|
|
||||||
</li>
|
</li>
|
||||||
{% elif num == page_obj.number|add:'-4' or num == page_obj.number|add:'4' %}
|
{% elif num == page_obj.number|add:'-4' or num == page_obj.number|add:'4' %}
|
||||||
<li class="page-item disabled">
|
<li>...</li>
|
||||||
<span class="page-link">...</span>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
{% if page_obj.has_next %}
|
||||||
<li class="page-item">
|
<li>
|
||||||
<a class="page-link"
|
<a href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ page_obj.next_page_number }}">»</a>
|
||||||
href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ page_obj.next_page_number }}"
|
|
||||||
aria-label="Next">
|
|
||||||
<span aria-hidden="true">»</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item">
|
<li>
|
||||||
<a class="page-link"
|
<a href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ page_obj.paginator.num_pages }}">»»</a>
|
||||||
href="?{% if selected_status %}status={{ selected_status }}&{% endif %}{% if selected_game %}game={{ selected_game }}&{% endif %}{% if selected_per_page != 24 %}per_page={{ selected_per_page }}&{% endif %}page={{ page_obj.paginator.num_pages }}"
|
|
||||||
aria-label="Last">
|
|
||||||
<span aria-hidden="true">»»</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="page-item disabled">
|
<li>»</li>
|
||||||
<span class="page-link" aria-label="Next">
|
<li>»»</li>
|
||||||
<span aria-hidden="true">»</span>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li class="page-item disabled">
|
|
||||||
<span class="page-link" aria-label="Last">
|
|
||||||
<span aria-hidden="true">»»</span>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
<small>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 text-center">
|
|
||||||
<small class="text-muted">
|
|
||||||
Showing {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ page_obj.paginator.count }}
|
Showing {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ page_obj.paginator.count }}
|
||||||
campaigns
|
campaigns
|
||||||
(Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }})
|
(Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }})
|
||||||
</small>
|
</small>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endblock content %}
|
||||||
<div class="row mt-3">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-dark text-white py-2">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-chart-bar me-2"></i>Quick Stats</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body py-3">
|
|
||||||
<div class="row text-center g-2">
|
|
||||||
<div class="col-md-4 mb-2 mb-md-0">
|
|
||||||
<div class="p-2 border rounded">
|
|
||||||
<h3 class="twitch-color mb-0">
|
|
||||||
{% if is_paginated %}
|
|
||||||
{{ page_obj.paginator.count }}
|
|
||||||
{% else %}
|
|
||||||
{{ campaigns|length }}
|
|
||||||
{% endif %}
|
|
||||||
</h3>
|
|
||||||
<p class="mb-0 small text-muted">Total Campaigns</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 mb-2 mb-md-0">
|
|
||||||
<div class="p-2 border rounded">
|
|
||||||
<h3 class="text-primary mb-0">{{ now|date:"F j, Y" }}</h3>
|
|
||||||
<p class="mb-0 small text-muted">Current Date</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="p-2 border rounded">
|
|
||||||
<a href="{% url 'twitch:game_list' %}" class="btn btn-primary w-100">
|
|
||||||
<i class="fas fa-gamepad me-1"></i>All Games
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
|
|
@ -1,192 +1,50 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
{% block title %}Dashboard - Twitch Drops Tracker{% endblock %}
|
{% block title %}
|
||||||
|
Dashboard
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-2">
|
|
||||||
<div class="col">
|
|
||||||
<h2 class="mb-1"><i class="fas fa-tachometer-alt me-2 twitch-color"></i>Dashboard</h2>
|
|
||||||
<p class="small text-muted mb-2">Track your active Twitch drop campaigns and progress.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.org-section {
|
|
||||||
border-left: 3px solid #9146FF;
|
|
||||||
padding-left: 10px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-section {
|
|
||||||
border-left: 2px solid #6441A4;
|
|
||||||
padding-left: 8px;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.org-section h5 {
|
|
||||||
color: #9146FF;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-section h6 {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-section h6 a {
|
|
||||||
color: #6441A4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-section h6 a:hover {
|
|
||||||
color: #9146FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.campaign-card {
|
|
||||||
padding: 8px !important;
|
|
||||||
margin-bottom: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.campaign-image img,
|
|
||||||
.campaign-image div {
|
|
||||||
width: 50px !important;
|
|
||||||
height: 50px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-body {
|
|
||||||
padding: 0.75rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-wrapper {
|
|
||||||
min-height: 1.9rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-wrapper h6 {
|
|
||||||
font-size: 0.85rem !important;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-3 {
|
|
||||||
margin-bottom: 0.75rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-4 {
|
|
||||||
margin-bottom: 1rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.g-3 {
|
|
||||||
--bs-gutter-y: 0.5rem !important;
|
|
||||||
--bs-gutter-x: 0.5rem !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="row mb-2">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-twitch py-1">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-fire me-1"></i>Active Campaigns</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body py-3">
|
|
||||||
{% if campaigns_by_org_game %}
|
{% if campaigns_by_org_game %}
|
||||||
{% for org_id, org_data in campaigns_by_org_game.items %}
|
{% for org_id, org_data in campaigns_by_org_game.items %}
|
||||||
<div class="org-section mb-4">
|
<h2>{{ org_data.name }}</h2>
|
||||||
<h5><i class="fas fa-building me-1"></i>{{ org_data.name }}</h5>
|
|
||||||
|
|
||||||
{% for game_id, game_data in org_data.games.items %}
|
{% for game_id, game_data in org_data.games.items %}
|
||||||
<div class="game-section mb-3">
|
<h3>
|
||||||
<h6>
|
<a href="{% url 'twitch:game_detail' game_id %}">{{ game_data.name }}</a>
|
||||||
<a href="{% url 'twitch:game_detail' game_id %}" class="text-decoration-none">
|
</h3>
|
||||||
<i class="fas fa-gamepad me-1"></i>{{ game_data.name }}
|
<p>{{ game_data.campaigns.0.description|default:"No description available."|linebreaksbr }}</p>
|
||||||
</a>
|
<table style="width:100%">
|
||||||
</h6>
|
<tr>
|
||||||
|
<th style="width:25%">Image</th>
|
||||||
<div class="row g-3">
|
<th>Campaign</th>
|
||||||
|
<th>Ends In</th>
|
||||||
|
</tr>
|
||||||
{% for campaign in game_data.campaigns %}
|
{% for campaign in game_data.campaigns %}
|
||||||
<div class="col-md-4 col-lg-3 col-xl-2">
|
<tr>
|
||||||
<div class="campaign-card campaign-active border rounded">
|
<td>
|
||||||
<div class="d-flex">
|
|
||||||
<div class="campaign-image flex-shrink-0 me-2">
|
|
||||||
{% if campaign.image_url %}
|
{% if campaign.image_url %}
|
||||||
<img src="{{ campaign.image_url }}" class="rounded"
|
<img height="160"
|
||||||
alt="{{ campaign.name }}" style="object-fit: cover;">
|
width="160"
|
||||||
|
src="{{ campaign.image_url }}"
|
||||||
|
alt="{{ campaign.name }}">
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="bg-light rounded"
|
<img height="160"
|
||||||
style="display: flex; align-items: center; justify-content: center;">
|
width="160"
|
||||||
<i class="fas fa-image text-muted" style="font-size: 1.2rem;"></i>
|
src="{% static 'images/placeholder.png' %}"
|
||||||
</div>
|
alt="No Image Available">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</td>
|
||||||
<div class="campaign-details min-w-0">
|
<td>
|
||||||
<div class="title-wrapper">
|
<a href="{% url 'twitch:campaign_detail' campaign.id %}">{{ campaign.clean_name }}</a>
|
||||||
<h6 class="mb-0" title="{{ campaign.name }}"
|
</td>
|
||||||
style="display: -webkit-box; display: box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; box-orient: vertical; overflow: hidden;">
|
<td>
|
||||||
{{ campaign.clean_name }}</h6>
|
<span title="{{ campaign.end_at|date:'M d, Y H:i' }}">Ends in {{ campaign.end_at|timeuntil }}</span>
|
||||||
</div>
|
</td>
|
||||||
<div class="d-flex align-items-center">
|
</tr>
|
||||||
<span class="badge bg-success" style="font-size: 0.7rem;">Active</span>
|
|
||||||
<small class="text-muted ms-1" style="font-size: 0.7rem;">Ends
|
|
||||||
{{ campaign.end_at|date:"M d" }}</small>
|
|
||||||
</div>
|
|
||||||
<a href="{% url 'twitch:campaign_detail' campaign.id %}"
|
|
||||||
class="stretched-link"></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</table>
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-info py-2">
|
No active campaigns at the moment.
|
||||||
<i class="fas fa-info-circle me-2"></i>No active campaigns at the moment.
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
{% endblock content %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-dark text-white py-1">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-chart-bar me-1"></i>Quick Stats</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body py-2">
|
|
||||||
<div class="row text-center g-2">
|
|
||||||
<div class="col-md-3 mb-1 mb-md-0">
|
|
||||||
<div class="p-1 border rounded">
|
|
||||||
<h4 class="twitch-color mb-0">{{ active_campaigns.count }}</h4>
|
|
||||||
<p class="mb-0 small text-muted" style="font-size: 0.75rem;">Active Campaigns</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3 mb-1 mb-md-0">
|
|
||||||
<div class="p-1 border rounded">
|
|
||||||
<h4 class="text-primary mb-0">{{ campaigns_by_org_game|length }}</h4>
|
|
||||||
<p class="mb-0 small text-muted" style="font-size: 0.75rem;">Organizations</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3 mb-1 mb-md-0">
|
|
||||||
<div class="p-1 border rounded">
|
|
||||||
<h4 class="text-primary mb-0">{{ now|date:"M j" }}</h4>
|
|
||||||
<p class="mb-0 small text-muted" style="font-size: 0.75rem;">Current Date</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="p-1 border rounded">
|
|
||||||
<a href="{% url 'twitch:campaign_list' %}" class="btn btn-primary btn-sm w-100">
|
|
||||||
<i class="fas fa-list me-1"></i>All Campaigns
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
|
|
@ -1,169 +1,61 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}{{ game.display_name }} - Twitch Drops Tracker{% endblock %}
|
{{ game.display_name }}
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-4">
|
<h1>{{ game.display_name }}</h1>
|
||||||
<div class="col">
|
{% if active_campaigns %}
|
||||||
<nav aria-label="breadcrumb">
|
<h5>Active Campaigns</h5>
|
||||||
<ol class="breadcrumb">
|
<table>
|
||||||
<li class="breadcrumb-item"><a href="{% url 'twitch:game_list' %}">Games</a></li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ game.display_name }}</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<h1 class="mb-4">
|
|
||||||
<i class="fas fa-gamepad me-2 twitch-color"></i>{{ game.display_name }}
|
|
||||||
</h1>
|
|
||||||
<p class="lead">View all drop campaigns for {{ game.display_name }}.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if active_campaigns %}
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-success text-white">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-circle-play me-2"></i>Active Campaigns</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Campaign</th>
|
|
||||||
<th>Organization</th>
|
|
||||||
<th>Time Remaining</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for campaign in active_campaigns %}
|
{% for campaign in active_campaigns %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ campaign.clean_name }}</td>
|
|
||||||
<td>{{ campaign.owner.name }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span class="badge bg-success" data-bs-toggle="tooltip"
|
<a href="{% url 'twitch:campaign_detail' campaign.id %}">{{ campaign.clean_name }}</a>
|
||||||
title="Ends on {{ campaign.end_at|date:'M d, Y H:i' }}">
|
|
||||||
Ends in {{ campaign.end_at|timeuntil }}
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'twitch:campaign_detail' campaign.id %}"
|
<span title="{{ campaign.end_at|date:'M d, Y H:i' }}">Ends in {{ campaign.end_at|timeuntil }}</span>
|
||||||
class="btn btn-sm btn-primary">
|
|
||||||
<i class="fas fa-eye me-1"></i> View Details
|
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
{% if upcoming_campaigns %}
|
||||||
</div>
|
<h5>Upcoming Campaigns</h5>
|
||||||
</div>
|
<table>
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if upcoming_campaigns %}
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-info text-white">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-calendar-alt me-2"></i>Upcoming Campaigns</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Campaign</th>
|
|
||||||
<th>Organization</th>
|
|
||||||
<th>Starts In</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for campaign in upcoming_campaigns %}
|
{% for campaign in upcoming_campaigns %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ campaign.clean_name }}</td>
|
|
||||||
<td>{{ campaign.owner.name }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span class="badge bg-info text-dark" data-bs-toggle="tooltip"
|
<a href="{% url 'twitch:campaign_detail' campaign.id %}">{{ campaign.clean_name }}</a>
|
||||||
title="Starts on {{ campaign.start_at|date:'M d, Y H:i' }}">
|
|
||||||
Starts in {{ campaign.start_at|timeuntil }}
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'twitch:campaign_detail' campaign.id %}"
|
<span title="Starts on {{ campaign.start_at|date:'M d, Y H:i' }}">Starts in {{ campaign.start_at|timeuntil }}</span>
|
||||||
class="btn btn-sm btn-primary">
|
|
||||||
<i class="fas fa-eye me-1"></i> View Details
|
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
{% if expired_campaigns %}
|
||||||
</div>
|
<h5>Past Campaigns</h5>
|
||||||
</div>
|
<table>
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if expired_campaigns %}
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
<div class="card-header bg-secondary text-white">
|
|
||||||
<h5 class="mb-0"><i class="fas fa-history me-2"></i>Past Campaigns</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Campaign</th>
|
|
||||||
<th>Organization</th>
|
|
||||||
<th>Ended</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for campaign in expired_campaigns %}
|
{% for campaign in expired_campaigns %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ campaign.clean_name }}</td>
|
|
||||||
<td>{{ campaign.owner.name }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span class="badge bg-secondary" data-bs-toggle="tooltip"
|
<a href="{% url 'twitch:campaign_detail' campaign.id %}">{{ campaign.clean_name }}</a>
|
||||||
title="Ended on {{ campaign.end_at|date:'M d, Y H:i' }}">
|
|
||||||
{{ campaign.end_at|timesince }} ago
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'twitch:campaign_detail' campaign.id %}"
|
<span title="Ended on {{ campaign.end_at|date:'M d, Y H:i' }}">{{ campaign.end_at|timesince }} ago</span>
|
||||||
class="btn btn-sm btn-primary">
|
|
||||||
<i class="fas fa-eye me-1"></i> View Details
|
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
{% if not active_campaigns and not upcoming_campaigns and not expired_campaigns %}
|
||||||
</div>
|
No campaigns found for this game.
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
{% endblock content %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if not active_campaigns and not upcoming_campaigns and not expired_campaigns %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="alert alert-info">
|
|
||||||
<i class="fas fa-info-circle me-2"></i> No campaigns found for this game.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,25 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}Games by Organization - Twitch Drops Tracker{% endblock %}
|
Games by Organization - Twitch Drops Tracker
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-4">
|
<h1>Games by Organization</h1>
|
||||||
<div class="col">
|
{% if games_by_org %}
|
||||||
<h1 class="mb-4"><i class="fas fa-gamepad me-2 twitch-color"></i>Games by Organization</h1>
|
{% for organization, games in games_by_org.items %}
|
||||||
<p class="lead">Browse all games with Twitch drop campaigns, grouped by organization.</p>
|
<h2>{{ organization.name }}</h2>
|
||||||
</div>
|
<table>
|
||||||
</div>
|
<tbody>
|
||||||
|
|
||||||
{% if games_by_org %}
|
|
||||||
{% for organization, games in games_by_org.items %}
|
|
||||||
<div class="card mb-4 shadow-sm">
|
|
||||||
<div class="card-header bg-dark text-white">
|
|
||||||
<h3 class="mb-0">
|
|
||||||
<i class="fas fa-building me-2"></i>{{ organization.name }}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row row-cols-1 row-cols-md-3 g-4">
|
|
||||||
{% for item in games %}
|
{% for item in games %}
|
||||||
<div class="col">
|
<tr>
|
||||||
<div class="card h-100 border-0 shadow-sm">
|
<td>
|
||||||
<div class="card-body">
|
<a href="{% url 'twitch:game_detail' item.game.id %}">{{ item.game.display_name }}</a>
|
||||||
<h5 class="card-title">
|
</td>
|
||||||
<a href="{% url 'twitch:game_detail' item.game.id %}" class="text-decoration-none">
|
</tr>
|
||||||
{{ item.game.display_name }}
|
|
||||||
</a>
|
|
||||||
</h5>
|
|
||||||
<div class="d-flex justify-content-between mt-3">
|
|
||||||
<span class="badge bg-secondary">
|
|
||||||
<i class="fas fa-gift me-1"></i> {{ item.campaign_count }} Campaigns
|
|
||||||
</span>
|
|
||||||
{% if item.active_count > 0 %}
|
|
||||||
<span class="badge bg-success">
|
|
||||||
<i class="fas fa-circle-play me-1"></i> {{ item.active_count }} Active
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer bg-transparent border-0">
|
|
||||||
<a href="{% url 'twitch:game_detail' item.game.id %}" class="btn btn-sm btn-primary">
|
|
||||||
<i class="fas fa-eye me-1"></i> View Campaigns
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</tbody>
|
||||||
</div>
|
</table>
|
||||||
</div>
|
{% endfor %}
|
||||||
{% endfor %}
|
{% else %}
|
||||||
{% else %}
|
No games found.
|
||||||
<div class="alert alert-info">
|
{% endif %}
|
||||||
<i class="fas fa-info-circle me-2"></i> No games found.
|
{% endblock content %}
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class Command(BaseCommand):
|
||||||
help="Delay in seconds between retries for database operations (default: 0.5)",
|
help="Delay in seconds between retries for database operations (default: 0.5)",
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle(self, **options) -> None: # noqa: ANN003
|
def handle(self, **options) -> None:
|
||||||
"""Execute the command.
|
"""Execute the command.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -268,7 +268,7 @@ class Command(BaseCommand):
|
||||||
id=campaign_data["id"],
|
id=campaign_data["id"],
|
||||||
defaults={
|
defaults={
|
||||||
"name": campaign_data["name"],
|
"name": campaign_data["name"],
|
||||||
"description": campaign_data["description"],
|
"description": campaign_data["description"].replace("\\n", "\n"),
|
||||||
"details_url": campaign_data.get("detailsURL", ""),
|
"details_url": campaign_data.get("detailsURL", ""),
|
||||||
"account_link_url": campaign_data.get("accountLinkURL", ""),
|
"account_link_url": campaign_data.get("accountLinkURL", ""),
|
||||||
"image_url": campaign_data.get("imageURL", ""),
|
"image_url": campaign_data.get("imageURL", ""),
|
||||||
|
|
|
||||||
|
|
@ -74,17 +74,31 @@ class DropCampaign(models.Model):
|
||||||
Examples:
|
Examples:
|
||||||
"Ravendawn - July 2" -> "July 2"
|
"Ravendawn - July 2" -> "July 2"
|
||||||
"Party Animals Twitch Drop" -> "Twitch Drop"
|
"Party Animals Twitch Drop" -> "Twitch Drop"
|
||||||
|
"Skull & Bones - Closed Beta" -> "Closed Beta" (& is replaced with "and")
|
||||||
"""
|
"""
|
||||||
if not self.game or not self.game.display_name:
|
if not self.game or not self.game.display_name:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
game_name = self.game.display_name
|
# Try different variations of the game name
|
||||||
|
game_variations = [self.game.display_name]
|
||||||
|
|
||||||
|
# Add & to "and" conversion
|
||||||
|
if "&" in self.game.display_name:
|
||||||
|
game_variations.append(self.game.display_name.replace("&", "and"))
|
||||||
|
|
||||||
|
# Add "and" to & conversion
|
||||||
|
if "and" in self.game.display_name:
|
||||||
|
game_variations.append(self.game.display_name.replace("and", "&"))
|
||||||
|
|
||||||
|
# Check each variation
|
||||||
|
for game_name in game_variations:
|
||||||
|
if not self.name.startswith(game_name):
|
||||||
|
continue
|
||||||
|
|
||||||
# Remove game name if it's at the beginning of the campaign name
|
|
||||||
if self.name.startswith(game_name):
|
|
||||||
# Check if it's followed by a separator like " - "
|
# Check if it's followed by a separator like " - "
|
||||||
if self.name[len(game_name) :].startswith(" - "):
|
if self.name[len(game_name) :].startswith(" - "):
|
||||||
return self.name[len(game_name) + 3 :].strip()
|
return self.name[len(game_name) + 3 :].strip()
|
||||||
|
|
||||||
# Or just remove the game name if it's followed by a space
|
# Or just remove the game name if it's followed by a space
|
||||||
if len(self.name) > len(game_name) and self.name[len(game_name)] == " ":
|
if len(self.name) > len(game_name) and self.name[len(game_name)] == " ":
|
||||||
return self.name[len(game_name) + 1 :].strip()
|
return self.name[len(game_name) + 1 :].strip()
|
||||||
|
|
|
||||||
268
uv.lock
generated
268
uv.lock
generated
|
|
@ -2,6 +2,19 @@ version = 1
|
||||||
revision = 2
|
revision = 2
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyio"
|
||||||
|
version = "4.9.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "idna" },
|
||||||
|
{ name = "sniffio" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asgiref"
|
name = "asgiref"
|
||||||
version = "3.9.1"
|
version = "3.9.1"
|
||||||
|
|
@ -11,6 +24,18 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/3c/0464dcada90d5da0e71018c04a140ad6349558afb30b3051b4264cc5b965/asgiref-3.9.1-py3-none-any.whl", hash = "sha256:f3bba7092a48005b5f5bacd747d36ee4a5a61f4a269a6df590b43144355ebd2c", size = 23790, upload-time = "2025-07-08T09:07:41.548Z" },
|
{ url = "https://files.pythonhosted.org/packages/7c/3c/0464dcada90d5da0e71018c04a140ad6349558afb30b3051b4264cc5b965/asgiref-3.9.1-py3-none-any.whl", hash = "sha256:f3bba7092a48005b5f5bacd747d36ee4a5a61f4a269a6df590b43144355ebd2c", size = 23790, upload-time = "2025-07-08T09:07:41.548Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
|
@ -20,6 +45,20 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cssbeautifier"
|
||||||
|
version = "1.15.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "editorconfig" },
|
||||||
|
{ name = "jsbeautifier" },
|
||||||
|
{ name = "six" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f7/01/fdf41c1e5f93d359681976ba10410a04b299d248e28ecce1d4e88588dde4/cssbeautifier-1.15.4.tar.gz", hash = "sha256:9bb08dc3f64c101a01677f128acf01905914cf406baf87434dcde05b74c0acf5", size = 25376, upload-time = "2025-02-27T17:53:51.341Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/63/51/ef6c5628e46092f0a54c7cee69acc827adc6b6aab57b55d344fefbdf28f1/cssbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:78c84d5e5378df7d08622bbd0477a1abdbd209680e95480bf22f12d5701efc98", size = 123667, upload-time = "2025-02-27T17:53:43.594Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django"
|
name = "django"
|
||||||
version = "5.2.4"
|
version = "5.2.4"
|
||||||
|
|
@ -34,6 +73,19 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/14/ae/706965237a672434c8b520e89a818e8b047af94e9beb342d0bee405c26c7/django-5.2.4-py3-none-any.whl", hash = "sha256:60c35bd96201b10c6e7a78121bd0da51084733efa303cc19ead021ab179cef5e", size = 8302187, upload-time = "2025-07-02T18:47:35.373Z" },
|
{ url = "https://files.pythonhosted.org/packages/14/ae/706965237a672434c8b520e89a818e8b047af94e9beb342d0bee405c26c7/django-5.2.4-py3-none-any.whl", hash = "sha256:60c35bd96201b10c6e7a78121bd0da51084733efa303cc19ead021ab179cef5e", size = 8302187, upload-time = "2025-07-02T18:47:35.373Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django-browser-reload"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "asgiref" },
|
||||||
|
{ name = "django" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3b/41/84eaa4f2b7f764e56e01c4ee49aa12bdea30ae50fd0d3ef7c2690b0c4ec2/django_browser_reload-1.18.0.tar.gz", hash = "sha256:c5f0b134723cbf2a0dc9ae1ee1d38e42db28fe23c74cdee613ba3ef286d04735", size = 14319, upload-time = "2025-02-06T22:14:40.799Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/9d/1322dc4bce4982d1eadd3a62802c996ae0303aad13d9ad88c1d35025f73d/django_browser_reload-1.18.0-py3-none-any.whl", hash = "sha256:ed4cc2fb83c3bf6c30b54107a1a6736c0b896e62e4eba666d81005b9f2ecf6f8", size = 12230, upload-time = "2025-02-06T22:14:36.87Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django-debug-toolbar"
|
name = "django-debug-toolbar"
|
||||||
version = "5.2.0"
|
version = "5.2.0"
|
||||||
|
|
@ -47,6 +99,52 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/c2/ed3cb815002664349e9e50799b8c00ef15941f4cad797247cadbdeebab02/django_debug_toolbar-5.2.0-py3-none-any.whl", hash = "sha256:15627f4c2836a9099d795e271e38e8cf5204ccd79d5dbcd748f8a6c284dcd195", size = 262834, upload-time = "2025-04-29T05:23:55.472Z" },
|
{ url = "https://files.pythonhosted.org/packages/fa/c2/ed3cb815002664349e9e50799b8c00ef15941f4cad797247cadbdeebab02/django_debug_toolbar-5.2.0-py3-none-any.whl", hash = "sha256:15627f4c2836a9099d795e271e38e8cf5204ccd79d5dbcd748f8a6c284dcd195", size = 262834, upload-time = "2025-04-29T05:23:55.472Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "django-watchfiles"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "django" },
|
||||||
|
{ name = "watchfiles" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/b1/89c36fb87f5af2736cfd0610ea050c38e382251b44bcebeef603d45ab100/django_watchfiles-1.1.0.tar.gz", hash = "sha256:7f7b716387d320778b003bf3ff32945b904f7e240a65f8c5432f140705a5fdda", size = 5300, upload-time = "2025-02-06T22:15:51.834Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/0f/c696529f2542c42c00a3eeef52a4c214ec01a610e769be9e8cd69ab684b9/django_watchfiles-1.1.0-py3-none-any.whl", hash = "sha256:a8256d9dc8eb4fce3f038ec6e630d4058458dda3a5e8130066f4aa4ebedef42a", size = 4598, upload-time = "2025-02-06T22:15:50.663Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "djlint"
|
||||||
|
version = "1.36.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "colorama" },
|
||||||
|
{ name = "cssbeautifier" },
|
||||||
|
{ name = "jsbeautifier" },
|
||||||
|
{ name = "json5" },
|
||||||
|
{ name = "pathspec" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
|
{ name = "regex" },
|
||||||
|
{ name = "tqdm" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/74/89/ecf5be9f5c59a0c53bcaa29671742c5e269cc7d0e2622e3f65f41df251bf/djlint-1.36.4.tar.gz", hash = "sha256:17254f218b46fe5a714b224c85074c099bcb74e3b2e1f15c2ddc2cf415a408a1", size = 47849, upload-time = "2024-12-24T13:06:36.36Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/83/88b4c885812921739f5529a29085c3762705154d41caf7eb9a8886a3380c/djlint-1.36.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ead475013bcac46095b1bbc8cf97ed2f06e83422335734363f8a76b4ba7e47c2", size = 354384, upload-time = "2024-12-24T13:06:20.809Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/38/67695f7a150b3d9d62fadb65242213d96024151570c3cf5d966effa68b0e/djlint-1.36.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6c601dfa68ea253311deb4a29a7362b7a64933bdfcfb5a06618f3e70ad1fa835", size = 322971, upload-time = "2024-12-24T13:06:22.185Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/7a/cd851393291b12e7fe17cf5d4d8874b8ea133aebbe9235f5314aabc96a52/djlint-1.36.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bda5014f295002363381969864addeb2db13955f1b26e772657c3b273ed7809f", size = 410972, upload-time = "2024-12-24T13:06:24.077Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/31/56469120394b970d4f079a552fde21ed27702ca729595ab0ed459eb6d240/djlint-1.36.4-cp313-cp313-win_amd64.whl", hash = "sha256:16ce37e085afe5a30953b2bd87cbe34c37843d94c701fc68a2dda06c1e428ff4", size = 362053, upload-time = "2024-12-24T13:06:25.432Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/67/f7aeea9be6fb3bd984487af8d0d80225a0b1e5f6f7126e3332d349fb13fe/djlint-1.36.4-py3-none-any.whl", hash = "sha256:e9699b8ac3057a6ed04fb90835b89bee954ed1959c01541ce4f8f729c938afdd", size = 52290, upload-time = "2024-12-24T13:06:33.76Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "editorconfig"
|
||||||
|
version = "0.17.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/88/3a/a61d9a1f319a186b05d14df17daea42fcddea63c213bcd61a929fb3a6796/editorconfig-0.17.1.tar.gz", hash = "sha256:23c08b00e8e08cc3adcddb825251c497478df1dada6aefeb01e626ad37303745", size = 14695, upload-time = "2025-06-09T08:21:37.097Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/96/fd/a40c621ff207f3ce8e484aa0fc8ba4eb6e3ecf52e15b42ba764b457a9550/editorconfig-0.17.1-py3-none-any.whl", hash = "sha256:1eda9c2c0db8c16dbd50111b710572a5e6de934e39772de1959d41f64fc17c82", size = 16360, upload-time = "2025-06-09T08:21:35.654Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "execnet"
|
name = "execnet"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
|
|
@ -56,6 +154,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612, upload-time = "2024-04-08T09:04:17.414Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612, upload-time = "2024-04-08T09:04:17.414Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.10"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iniconfig"
|
name = "iniconfig"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
|
@ -65,6 +172,28 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
|
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jsbeautifier"
|
||||||
|
version = "1.15.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "editorconfig" },
|
||||||
|
{ name = "six" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ea/98/d6cadf4d5a1c03b2136837a435682418c29fdeb66be137128544cecc5b7a/jsbeautifier-1.15.4.tar.gz", hash = "sha256:5bb18d9efb9331d825735fbc5360ee8f1aac5e52780042803943aa7f854f7592", size = 75257, upload-time = "2025-02-27T17:53:53.252Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/14/1c65fccf8413d5f5c6e8425f84675169654395098000d8bddc4e9d3390e1/jsbeautifier-1.15.4-py3-none-any.whl", hash = "sha256:72f65de312a3f10900d7685557f84cb61a9733c50dcc27271a39f5b0051bf528", size = 94707, upload-time = "2025-02-27T17:53:46.152Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "json5"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/12/be/c6c745ec4c4539b25a278b70e29793f10382947df0d9efba2fa09120895d/json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a", size = 51907, upload-time = "2025-04-03T16:33:13.201Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db", size = 36079, upload-time = "2025-04-03T16:33:11.927Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "25.0"
|
version = "25.0"
|
||||||
|
|
@ -74,6 +203,15 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathspec"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "4.3.8"
|
version = "4.3.8"
|
||||||
|
|
@ -171,6 +309,64 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" },
|
{ url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyyaml"
|
||||||
|
version = "6.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "2024.11.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "six"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sniffio"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlparse"
|
name = "sqlparse"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
|
|
@ -180,13 +376,28 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" },
|
{ url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tqdm"
|
||||||
|
version = "4.67.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ttvdrops"
|
name = "ttvdrops"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "django" },
|
{ name = "django" },
|
||||||
|
{ name = "django-browser-reload" },
|
||||||
{ name = "django-debug-toolbar" },
|
{ name = "django-debug-toolbar" },
|
||||||
|
{ name = "django-watchfiles" },
|
||||||
|
{ name = "djlint" },
|
||||||
{ name = "platformdirs" },
|
{ name = "platformdirs" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
]
|
]
|
||||||
|
|
@ -201,7 +412,10 @@ dev = [
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "django", specifier = ">=5.2.4" },
|
{ name = "django", specifier = ">=5.2.4" },
|
||||||
|
{ name = "django-browser-reload", specifier = ">=1.18.0" },
|
||||||
{ name = "django-debug-toolbar", specifier = ">=5.2.0" },
|
{ name = "django-debug-toolbar", specifier = ">=5.2.0" },
|
||||||
|
{ name = "django-watchfiles", specifier = ">=1.1.0" },
|
||||||
|
{ name = "djlint", specifier = ">=1.36.4" },
|
||||||
{ name = "platformdirs", specifier = ">=4.3.8" },
|
{ name = "platformdirs", specifier = ">=4.3.8" },
|
||||||
{ name = "python-dotenv", specifier = ">=1.1.1" },
|
{ name = "python-dotenv", specifier = ">=1.1.1" },
|
||||||
]
|
]
|
||||||
|
|
@ -221,3 +435,57 @@ sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be76
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
|
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "watchfiles"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/d451fcc97d029f5812e898fd30a53fd8c15c7bbd058fd75cfc6beb9bd761/watchfiles-1.1.0.tar.gz", hash = "sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575", size = 94406, upload-time = "2025-06-15T19:06:59.42Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/42/fae874df96595556a9089ade83be34a2e04f0f11eb53a8dbf8a8a5e562b4/watchfiles-1.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30", size = 402004, upload-time = "2025-06-15T19:05:38.499Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/55/a77e533e59c3003d9803c09c44c3651224067cbe7fb5d574ddbaa31e11ca/watchfiles-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a", size = 393671, upload-time = "2025-06-15T19:05:39.52Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/68/b0afb3f79c8e832e6571022611adbdc36e35a44e14f129ba09709aa4bb7a/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc", size = 449772, upload-time = "2025-06-15T19:05:40.897Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/05/46dd1f6879bc40e1e74c6c39a1b9ab9e790bf1f5a2fe6c08b463d9a807f4/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b", size = 456789, upload-time = "2025-06-15T19:05:42.045Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/ca/0eeb2c06227ca7f12e50a47a3679df0cd1ba487ea19cf844a905920f8e95/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895", size = 482551, upload-time = "2025-06-15T19:05:43.781Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/47/2cecbd8694095647406645f822781008cc524320466ea393f55fe70eed3b/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a", size = 597420, upload-time = "2025-06-15T19:05:45.244Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/7e/82abc4240e0806846548559d70f0b1a6dfdca75c1b4f9fa62b504ae9b083/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b", size = 477950, upload-time = "2025-06-15T19:05:46.332Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/0d/4d564798a49bf5482a4fa9416dea6b6c0733a3b5700cb8a5a503c4b15853/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c", size = 451706, upload-time = "2025-06-15T19:05:47.459Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/b5/5516cf46b033192d544102ea07c65b6f770f10ed1d0a6d388f5d3874f6e4/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b", size = 625814, upload-time = "2025-06-15T19:05:48.654Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/dd/7c1331f902f30669ac3e754680b6edb9a0dd06dea5438e61128111fadd2c/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb", size = 622820, upload-time = "2025-06-15T19:05:50.088Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/14/36d7a8e27cd128d7b1009e7715a7c02f6c131be9d4ce1e5c3b73d0e342d8/watchfiles-1.1.0-cp313-cp313-win32.whl", hash = "sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9", size = 279194, upload-time = "2025-06-15T19:05:51.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/41/2dd88054b849aa546dbeef5696019c58f8e0774f4d1c42123273304cdb2e/watchfiles-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7", size = 292349, upload-time = "2025-06-15T19:05:52.201Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/cf/421d659de88285eb13941cf11a81f875c176f76a6d99342599be88e08d03/watchfiles-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5", size = 283836, upload-time = "2025-06-15T19:05:53.265Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/10/6faf6858d527e3599cc50ec9fcae73590fbddc1420bd4fdccfebffeedbc6/watchfiles-1.1.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1", size = 400343, upload-time = "2025-06-15T19:05:54.252Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/20/5cb7d3966f5e8c718006d0e97dfe379a82f16fecd3caa7810f634412047a/watchfiles-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339", size = 392916, upload-time = "2025-06-15T19:05:55.264Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/07/d8f1176328fa9e9581b6f120b017e286d2a2d22ae3f554efd9515c8e1b49/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633", size = 449582, upload-time = "2025-06-15T19:05:56.317Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/e8/80a14a453cf6038e81d072a86c05276692a1826471fef91df7537dba8b46/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011", size = 456752, upload-time = "2025-06-15T19:05:57.359Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/25/0853b3fe0e3c2f5af9ea60eb2e781eade939760239a72c2d38fc4cc335f6/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670", size = 481436, upload-time = "2025-06-15T19:05:58.447Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/9e/4af0056c258b861fbb29dcb36258de1e2b857be4a9509e6298abcf31e5c9/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf", size = 596016, upload-time = "2025-06-15T19:05:59.59Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/fa/95d604b58aa375e781daf350897aaaa089cff59d84147e9ccff2447c8294/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4", size = 476727, upload-time = "2025-06-15T19:06:01.086Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" },
|
||||||
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue