This commit is contained in:
pacnpal
2024-10-29 01:09:14 -04:00
parent d19e5a5c07
commit 2d31847974
195 changed files with 5000 additions and 1213 deletions

View File

@@ -6,127 +6,110 @@
{% block title %}Login - ThrillWiki{% endblock %}
{% block content %}
<div class="max-w-md mx-auto">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<h1 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">{% trans "Sign In" %}</h1>
<div class="flex items-center justify-center min-h-[calc(100vh-16rem)]">
<div class="w-full max-w-md">
<div class="auth-card">
<h1 class="auth-title">{% trans "Welcome Back" %}</h1>
{% get_providers as socialaccount_providers %}
{% if socialaccount_providers %}
<div class="space-y-3 mb-6">
{% for provider in socialaccount_providers %}
<a href="{% provider_login_url provider.id process='login' %}"
class="w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
role="button"
tabindex="0"
onkeydown="if(event.key === 'Enter' || event.key === ' ') { this.click(); event.preventDefault(); }">
{% if provider.id == 'google' %}
<img src="{% static 'images/google-icon.svg' %}" alt="Google" class="h-5 w-5 mr-2">
{% elif provider.id == 'discord' %}
<img src="{% static 'images/discord-icon.svg' %}" alt="Discord" class="h-5 w-5 mr-2">
{% endif %}
Sign in with {{ provider.name }}
</a>
{% endfor %}
</div>
{% get_providers as socialaccount_providers %}
<div class="relative my-6">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-300 dark:border-gray-600"></div>
{% if socialaccount_providers %}
<div class="space-y-3">
{% for provider in socialaccount_providers %}
<a href="{% provider_login_url provider.id process='login' %}"
class="btn-social {% if provider.id == 'discord' %}btn-discord{% elif provider.id == 'google' %}btn-google{% endif %}"
role="button"
tabindex="0"
onkeydown="if(event.key === 'Enter' || event.key === ' ') { this.click(); event.preventDefault(); }">
{% if provider.id == 'google' %}
<img src="{% static 'images/google-icon.svg' %}" alt="Google" class="w-5 h-5 mr-3">
<span>Continue with Google</span>
{% elif provider.id == 'discord' %}
<img src="{% static 'images/discord-icon.svg' %}" alt="Discord" class="w-5 h-5 mr-3">
<span>Continue with Discord</span>
{% endif %}
</a>
{% endfor %}
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-white dark:bg-gray-800 text-gray-500">Or continue with</span>
<div class="auth-divider">
<span>Or continue with email</span>
</div>
</div>
{% endif %}
{% endif %}
<form class="space-y-4" method="POST" action="{% url 'account_login' %}"
onkeydown="if(event.key === 'Enter' && !event.shiftKey) {
const activeElement = document.activeElement;
if (activeElement.tagName === 'TEXTAREA') {
if (!event.shiftKey) {
event.preventDefault();
this.submit();
}
} else {
event.preventDefault();
this.submit();
}
}">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="bg-red-50 dark:bg-red-900 border-l-4 border-red-400 p-4 mb-4">
<div class="text-sm text-red-700 dark:text-red-200">
{{ form.non_field_errors }}
<form class="space-y-6" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-error">
<div class="text-sm">{{ form.non_field_errors }}</div>
</div>
{% endif %}
<div>
<label for="id_login" class="form-label">
{% trans "Username or Email" %}
</label>
<input type="text" name="login" id="id_login" required
autocomplete="username email"
class="form-input">
{% if form.login.errors %}
<p class="form-error">{{ form.login.errors }}</p>
{% endif %}
</div>
<div>
<label for="id_password" class="form-label">
{% trans "Password" %}
</label>
<input type="password" name="password" id="id_password" required
autocomplete="current-password"
class="form-input">
{% if form.password.errors %}
<p class="form-error">{{ form.password.errors }}</p>
{% endif %}
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<input type="checkbox" name="remember" id="id_remember"
class="w-4 h-4 border-gray-300 rounded text-primary focus:ring-primary/50 dark:border-gray-700">
<label for="id_remember" class="block ml-2 text-sm text-gray-700 dark:text-gray-300">
{% trans "Remember me" %}
</label>
</div>
<div class="text-sm">
<a href="{% url 'account_reset_password' %}"
class="font-medium transition-colors text-primary hover:text-primary/80 focus:outline-none focus:underline"
onkeydown="if(event.key === 'Enter') { this.click(); }">
{% trans "Forgot Password?" %}
</a>
</div>
</div>
{% endif %}
<div>
<label for="id_login" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
{% trans "Username or Email" %}
</label>
<input type="text" name="login" id="id_login" required
autocomplete="username email"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
{% if form.login.errors %}
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ form.login.errors }}</p>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}">
{% endif %}
</div>
<div>
<label for="id_password" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
{% trans "Password" %}
</label>
<input type="password" name="password" id="id_password" required
autocomplete="current-password"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
{% if form.password.errors %}
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ form.password.errors }}</p>
{% endif %}
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<input type="checkbox" name="remember" id="id_remember"
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
<label for="id_remember" class="ml-2 block text-sm text-gray-900 dark:text-gray-300">
{% trans "Remember me" %}
</label>
<div>
<button type="submit" class="w-full btn-primary">
<i class="mr-2 fas fa-sign-in-alt"></i>
{% trans "Sign In" %}
</button>
</div>
</form>
<div class="text-sm">
<a href="{% url 'account_reset_password' %}"
class="font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400 focus:outline-none focus:underline"
<div class="mt-6 text-sm text-center">
<p class="text-gray-600 dark:text-gray-400">
{% trans "Don't have an account?" %}
<a href="{% url 'account_signup' %}"
class="ml-1 font-medium transition-colors text-primary hover:text-primary/80 focus:outline-none focus:underline"
onkeydown="if(event.key === 'Enter') { this.click(); }">
{% trans "Forgot Password?" %}
{% trans "Sign up" %}
</a>
</div>
</p>
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<div>
<button type="submit"
class="w-full inline-flex justify-center items-center px-4 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
<i class="fas fa-sign-in-alt mr-2"></i>
{% trans "Sign In" %}
</button>
</div>
</form>
<div class="mt-6 text-center text-sm">
<p class="text-gray-600 dark:text-gray-400">
{% trans "Don't have an account?" %}
<a href="{% url 'account_signup' %}"
class="font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400 focus:outline-none focus:underline"
onkeydown="if(event.key === 'Enter') { this.click(); }">
{% trans "Sign up" %}
</a>
</p>
</div>
</div>
</div>

View File

@@ -6,132 +6,133 @@
{% block title %}Register - ThrillWiki{% endblock %}
{% block content %}
<div class="max-w-md mx-auto">
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<h1 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">{% trans "Sign Up" %}</h1>
<div class="flex items-center justify-center min-h-[calc(100vh-16rem)]">
<div class="w-full max-w-md">
<div class="auth-card">
<h1 class="auth-title">{% trans "Create Account" %}</h1>
{% get_providers as socialaccount_providers %}
{% if socialaccount_providers %}
<div class="space-y-3 mb-6">
{% for provider in socialaccount_providers %}
<a href="{% provider_login_url provider.id process='signup' %}"
class="w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
role="button"
tabindex="0"
onkeydown="if(event.key === 'Enter' || event.key === ' ') { this.click(); event.preventDefault(); }">
{% if provider.id == 'google' %}
<img src="{% static 'images/google-icon.svg' %}" alt="Google" class="h-5 w-5 mr-2">
{% elif provider.id == 'discord' %}
<img src="{% static 'images/discord-icon.svg' %}" alt="Discord" class="h-5 w-5 mr-2">
{% endif %}
Sign up with {{ provider.name }}
</a>
{% endfor %}
</div>
{% get_providers as socialaccount_providers %}
<div class="relative my-6">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-300 dark:border-gray-600"></div>
{% if socialaccount_providers %}
<div class="space-y-3">
{% for provider in socialaccount_providers %}
<a href="{% provider_login_url provider.id process='signup' %}"
class="btn-social {% if provider.id == 'discord' %}btn-discord{% elif provider.id == 'google' %}btn-google{% endif %}"
role="button"
tabindex="0"
onkeydown="if(event.key === 'Enter' || event.key === ' ') { this.click(); event.preventDefault(); }">
{% if provider.id == 'google' %}
<img src="{% static 'images/google-icon.svg' %}" alt="Google" class="w-5 h-5 mr-3">
<span>Continue with Google</span>
{% elif provider.id == 'discord' %}
<img src="{% static 'images/discord-icon.svg' %}" alt="Discord" class="w-5 h-5 mr-3">
<span>Continue with Discord</span>
{% endif %}
</a>
{% endfor %}
</div>
<div class="relative flex justify-center text-sm">
<span class="px-2 bg-white dark:bg-gray-800 text-gray-500">Or continue with</span>
</div>
</div>
{% endif %}
<form class="space-y-4" method="POST" action="{% url 'account_signup' %}"
onkeydown="if(event.key === 'Enter' && !event.shiftKey) {
const activeElement = document.activeElement;
if (activeElement.tagName === 'TEXTAREA') {
if (!event.shiftKey) {
event.preventDefault();
this.submit();
}
} else {
event.preventDefault();
this.submit();
}
}">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="bg-red-50 dark:bg-red-900 border-l-4 border-red-400 p-4 mb-4">
<div class="text-sm text-red-700 dark:text-red-200">
{{ form.non_field_errors }}
</div>
<div class="auth-divider">
<span>Or continue with email</span>
</div>
{% endif %}
<div>
<label for="id_username" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
{% trans "Username" %}
</label>
<input type="text" name="username" id="id_username" required
autocomplete="username"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
{% if form.username.errors %}
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ form.username.errors }}</p>
<form class="space-y-6" method="POST" action="{% url 'account_signup' %}">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-error">
<div class="text-sm">{{ form.non_field_errors }}</div>
</div>
{% endif %}
<div>
<label for="id_username" class="form-label">
{% trans "Username" %}
</label>
<input type="text" name="username" id="id_username" required
autocomplete="username"
class="form-input">
{% if form.username.errors %}
<p class="form-error">{{ form.username.errors }}</p>
{% endif %}
</div>
<div>
<label for="id_email" class="form-label">
{% trans "Email" %}
</label>
<input type="email" name="email" id="id_email" required
autocomplete="email"
class="form-input">
{% if form.email.errors %}
<p class="form-error">{{ form.email.errors }}</p>
{% endif %}
</div>
<div>
<label for="id_password1" class="form-label">
{% trans "Password" %}
</label>
<input type="password" name="password1" id="id_password1" required
autocomplete="new-password"
class="form-input"
oninput="validatePassword(this.value)">
{% if form.password1.errors %}
<p class="form-error">{{ form.password1.errors }}</p>
{% endif %}
<div class="mt-3 password-requirements">
<ul id="passwordRequirements">
<li class="invalid" id="req-length">
<i class="text-xs fas fa-circle"></i>
<span>Must be at least 8 characters long</span>
</li>
<li class="invalid" id="req-similar">
<i class="text-xs fas fa-circle"></i>
<span>Can't be too similar to your personal information</span>
</li>
<li class="invalid" id="req-common">
<i class="text-xs fas fa-circle"></i>
<span>Can't be a commonly used password</span>
</li>
<li class="invalid" id="req-numeric">
<i class="text-xs fas fa-circle"></i>
<span>Can't be entirely numeric</span>
</li>
</ul>
</div>
</div>
<div>
<label for="id_email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
{% trans "Email" %}
</label>
<input type="email" name="email" id="id_email" required
autocomplete="email"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
{% if form.email.errors %}
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ form.email.errors }}</p>
{% endif %}
</div>
<div>
<label for="id_password1" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
{% trans "Password" %}
</label>
<input type="password" name="password1" id="id_password1" required
autocomplete="new-password"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
{% if form.password1.errors %}
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ form.password1.errors }}</p>
{% endif %}
{% if form.password1.help_text %}
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ form.password1.help_text }}</p>
{% endif %}
</div>
<div>
<label for="id_password2" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="id_password2" class="form-label">
{% trans "Confirm Password" %}
</label>
<input type="password" name="password2" id="id_password2" required
autocomplete="new-password"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white">
class="form-input"
oninput="validatePasswordMatch()">
{% if form.password2.errors %}
<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ form.password2.errors }}</p>
<p class="form-error">{{ form.password2.errors }}</p>
{% endif %}
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}">
{% endif %}
<div class="mt-6">
<button type="submit"
class="w-full inline-flex justify-center items-center px-4 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
<i class="fas fa-user-plus mr-2"></i>
<div>
<button type="submit" class="w-full btn-primary">
<i class="mr-2 fas fa-user-plus"></i>
{% trans "Create Account" %}
</button>
</div>
</form>
<div class="mt-6 text-center text-sm">
<div class="mt-6 text-sm text-center">
<p class="text-gray-600 dark:text-gray-400">
{% trans "Already have an account?" %}
<a href="{% url 'account_login' %}"
class="font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400 focus:outline-none focus:underline"
class="ml-1 font-medium transition-colors text-primary hover:text-primary/80 focus:outline-none focus:underline"
onkeydown="if(event.key === 'Enter') { this.click(); }">
{% trans "Sign in" %}
</a>
@@ -139,4 +140,69 @@
</div>
</div>
</div>
<script>
function validatePassword(password) {
// Length requirement
const lengthReq = document.getElementById('req-length');
if (password.length >= 8) {
lengthReq.classList.remove('invalid');
lengthReq.classList.add('valid');
lengthReq.querySelector('i').classList.remove('fa-circle');
lengthReq.querySelector('i').classList.add('fa-check');
} else {
lengthReq.classList.remove('valid');
lengthReq.classList.add('invalid');
lengthReq.querySelector('i').classList.remove('fa-check');
lengthReq.querySelector('i').classList.add('fa-circle');
}
// Numeric requirement
const numericReq = document.getElementById('req-numeric');
if (!/^\d+$/.test(password)) {
numericReq.classList.remove('invalid');
numericReq.classList.add('valid');
numericReq.querySelector('i').classList.remove('fa-circle');
numericReq.querySelector('i').classList.add('fa-check');
} else {
numericReq.classList.remove('valid');
numericReq.classList.add('invalid');
numericReq.querySelector('i').classList.remove('fa-check');
numericReq.querySelector('i').classList.add('fa-circle');
}
// Common password check (basic)
const commonReq = document.getElementById('req-common');
const commonPasswords = ['password', '12345678', 'qwerty', 'letmein'];
if (!commonPasswords.includes(password.toLowerCase())) {
commonReq.classList.remove('invalid');
commonReq.classList.add('valid');
commonReq.querySelector('i').classList.remove('fa-circle');
commonReq.querySelector('i').classList.add('fa-check');
} else {
commonReq.classList.remove('valid');
commonReq.classList.add('invalid');
commonReq.querySelector('i').classList.remove('fa-check');
commonReq.querySelector('i').classList.add('fa-circle');
}
}
function validatePasswordMatch() {
const password1 = document.getElementById('id_password1').value;
const password2 = document.getElementById('id_password2').value;
const password2Input = document.getElementById('id_password2');
if (password2.length > 0) {
if (password1 === password2) {
password2Input.classList.remove('border-red-500');
password2Input.classList.add('border-green-500');
} else {
password2Input.classList.remove('border-green-500');
password2Input.classList.add('border-red-500');
}
} else {
password2Input.classList.remove('border-green-500', 'border-red-500');
}
}
</script>
{% endblock %}