This commit is contained in:
Jens
2026-07-24 22:46:37 +02:00
parent 0101660bd7
commit bdf44eec04
26 changed files with 1770 additions and 24 deletions
+149 -19
View File
@@ -1,19 +1,149 @@
{% extends "base.html" %}
{% block title %}Aanmelden · VacatureRadar{% endblock %}
{% block body_class %}login-page{% endblock %}
{% block content %}
<div class="login-cockpit">
<section class="login-intelligence" aria-labelledby="login-brand-title">
<div class="login-brandline"><span class="brand-radar"><svg class="icon"><use href="#icon-radar"></use></svg></span><span><strong>VacatureRadar</strong><small>Intelligence cockpit</small></span></div>
<div class="login-radar" aria-hidden="true"><span></span><span></span><span></span><i></i></div>
<div class="login-intro"><p class="eyebrow">Persoonlijke vacature-intelligence</p><h1 id="login-brand-title">Van bronruis naar beslisbare IT-matches.</h1><p>Breng vacatures, werkgevers, skillsvraag en opvolging samen in één betrouwbare radar.</p></div>
<ul class="login-signals" aria-label="Platformmogelijkheden"><li><svg class="icon"><use href="#icon-check"></use></svg>Deterministische IT-selectie</li><li><svg class="icon"><use href="#icon-check"></use></svg>Herleidbare matchonderbouwing</li><li><svg class="icon"><use href="#icon-check"></use></svg>Bron- en automatiseringscontrole</li></ul>
</section>
<section class="auth-card" aria-labelledby="login-title">
<div class="auth-brand"><span class="brand-mark"><svg class="icon"><use href="#icon-profile"></use></svg></span><div><p class="eyebrow">Beveiligde toegang</p><h2 id="login-title">Welkom terug</h2><p>Open je persoonlijke intelligence cockpit.</p></div></div>
{% if form.errors %}<div class="message error" role="alert">Gebruikersnaam of wachtwoord klopt niet.</div>{% endif %}
<form method="post" class="stack">{% csrf_token %}<label for="{{ form.username.id_for_label }}">Gebruikersnaam</label>{{ form.username }}<label for="{{ form.password.id_for_label }}">Wachtwoord</label>{{ form.password }}{% if next %}<input type="hidden" name="next" value="{{ next }}">{% endif %}<button class="button button-primary button-block" type="submit">Cockpit openen <svg class="icon"><use href="#icon-arrow"></use></svg></button></form>
<div class="auth-trust"><span class="status-beacon is-live" aria-hidden="true"></span><span><strong>Lokale, afgeschermde sessie</strong><small>Je gegevens blijven binnen de geconfigureerde omgeving.</small></span></div>
</section>
</div>
{% endblock %}
{% load static %}<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<meta name="theme-color" content="#fbf8ff">
<title>Inloggen · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
</div>
<div class="auth-card">
<h1>Inloggen</h1>
{% if messages %}
{% for message in messages %}
<div class="auth-alert {% if message.tags == 'error' %}is-error{% elif message.tags == 'success' %}is-success{% else %}is-info{% endif %}" role="alert">
<svg class="icon" aria-hidden="true"><use href="{% if message.tags == 'error' %}#icon-alert{% else %}#icon-check{% endif %}"></use></svg>
<span>{{ message }}</span>
</div>
{% endfor %}
{% endif %}
{% if form.errors and not messages %}
<div class="auth-alert is-error" role="alert">
<svg class="icon" aria-hidden="true"><use href="#icon-alert"></use></svg>
<span>E-mailadres of wachtwoord klopt niet. Probeer het opnieuw.</span>
</div>
{% endif %}
<form method="post" class="auth-form" novalidate>
{% csrf_token %}
<div class="field">
<label for="id_username">E-mailadres</label>
<input class="auth-input" id="id_username" name="username" type="email"
autocomplete="username" autocapitalize="none" spellcheck="false"
placeholder="naam@organisatie.nl" required
{% if form.errors %}aria-invalid="true"{% endif %}
value="{{ form.username.value|default:'' }}">
</div>
<div class="field">
<div class="field-label-row">
<label for="id_password">Wachtwoord</label>
<a class="field-link" href="{% url 'password_reset' %}">Wachtwoord vergeten?</a>
</div>
<div class="input-wrap">
<input class="auth-input" id="id_password" name="password" type="password"
autocomplete="current-password" placeholder="••••••••" required
{% if form.errors %}aria-invalid="true"{% endif %}>
<button class="pw-toggle" type="button" data-pw-toggle aria-label="Wachtwoord tonen">
<svg class="icon" aria-hidden="true" data-eye><use href="#icon-eye"></use></svg>
<svg class="icon" aria-hidden="true" data-eye-off hidden><use href="#icon-eye-off"></use></svg>
</button>
</div>
</div>
{% if next %}<input type="hidden" name="next" value="{{ next }}">{% endif %}
<button class="btn btn-primary" type="submit" data-submit>
<span data-label>Inloggen</span>
<svg class="icon" aria-hidden="true" data-arrow><use href="#icon-arrow"></use></svg>
</button>
{% if entra_enabled %}
<div class="auth-separator"><span>Of ga door met</span></div>
{% endif %}
</form>
{% if entra_enabled %}
<form method="post" action="{% url 'entra-login' %}">
{% csrf_token %}
{% if next %}<input type="hidden" name="next" value="{{ next }}">{% endif %}
<button class="btn btn-sso" type="submit">
<svg viewBox="0 0 23 23" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M1 1h10v10H1z" fill="#f35325"></path>
<path d="M12 1h10v10H12z" fill="#81bc06"></path>
<path d="M1 12h10v10H1z" fill="#05a6f0"></path>
<path d="M12 12h10v10H12z" fill="#ffba08"></path>
</svg>
Inloggen met Entra ID
</button>
</form>
{% endif %}
{% if demo_enabled %}
<div class="auth-secondary">
<p>Nog geen account?</p>
<form method="post" action="{% url 'demo-login' %}" class="btn-ghost inline-form">
{% csrf_token %}
{% if next %}<input type="hidden" name="next" value="{{ next }}">{% endif %}
<button class="btn-ghost" type="submit">
<svg class="icon" aria-hidden="true"><use href="#icon-eye"></use></svg>
Bekijk demo
</button>
</form>
</div>
{% endif %}
</div>
<footer class="auth-footer">
<div class="auth-footer-links">
<a href="{% url 'password_reset' %}">Wachtwoord vergeten</a>
</div>
<div class="auth-badge">
<svg class="icon" aria-hidden="true"><use href="#icon-shield"></use></svg>
<span>Local-first secure node</span>
</div>
</footer>
</main>
<script>
(function () {
var toggle = document.querySelector('[data-pw-toggle]');
if (toggle) {
var pw = document.getElementById('id_password');
var eye = toggle.querySelector('[data-eye]');
var eyeOff = toggle.querySelector('[data-eye-off]');
toggle.addEventListener('click', function () {
var show = pw.type === 'password';
pw.type = show ? 'text' : 'password';
toggle.setAttribute('aria-label', show ? 'Wachtwoord verbergen' : 'Wachtwoord tonen');
if (eye && eyeOff) { eye.hidden = show; eyeOff.hidden = !show; }
});
}
var form = document.querySelector('form.auth-form');
if (form) {
form.addEventListener('submit', function () {
var btn = form.querySelector('[data-submit]');
if (!btn || btn.dataset.busy) return;
if (typeof form.checkValidity === 'function' && !form.checkValidity()) return;
btn.dataset.busy = '1';
var label = btn.querySelector('[data-label]');
if (label) label.textContent = 'Bezig met inloggen…';
});
}
})();
</script>
</body>
</html>
@@ -0,0 +1,35 @@
{% load static %}<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Wachtwoord gewijzigd · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
</div>
<div class="auth-card">
<h1>Wachtwoord gewijzigd</h1>
<div class="auth-alert is-success" role="status">
<svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg>
<span>Je wachtwoord is bijgewerkt. Je kunt nu inloggen met je nieuwe wachtwoord.</span>
</div>
<form method="get" action="{% url 'login' %}" class="auth-form">
<button class="btn btn-primary" type="submit">
Naar inloggen
<svg class="icon" aria-hidden="true"><use href="#icon-arrow"></use></svg>
</button>
</form>
</div>
</main>
</body>
</html>
@@ -0,0 +1,64 @@
{% load static %}<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Nieuw wachtwoord · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
</div>
<div class="auth-card">
{% if validlink %}
<h1>Kies een nieuw wachtwoord</h1>
<p class="auth-lead">Gebruik een uniek, sterk wachtwoord dat je nergens anders gebruikt.</p>
{% if form.errors %}
<div class="auth-alert is-error" role="alert">
<svg class="icon" aria-hidden="true"><use href="#icon-alert"></use></svg>
<span>Controleer de gemarkeerde velden en probeer het opnieuw.</span>
</div>
{% endif %}
<form method="post" class="auth-form" novalidate>
{% csrf_token %}
<div class="field">
<label for="id_new_password1">Nieuw wachtwoord</label>
<input class="auth-input" id="id_new_password1" name="new_password1" type="password"
autocomplete="new-password" required
{% if form.new_password1.errors %}aria-invalid="true"{% endif %}>
{% if form.new_password1.errors %}<p class="field-error">{{ form.new_password1.errors|join:" " }}</p>{% endif %}
</div>
<div class="field">
<label for="id_new_password2">Herhaal wachtwoord</label>
<input class="auth-input" id="id_new_password2" name="new_password2" type="password"
autocomplete="new-password" required
{% if form.new_password2.errors %}aria-invalid="true"{% endif %}>
{% if form.new_password2.errors %}<p class="field-error">{{ form.new_password2.errors|join:" " }}</p>{% endif %}
</div>
<button class="btn btn-primary" type="submit">
Wachtwoord opslaan
<svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg>
</button>
</form>
{% else %}
<h1>Link is verlopen</h1>
<div class="auth-alert is-error" role="alert">
<svg class="icon" aria-hidden="true"><use href="#icon-alert"></use></svg>
<span>Deze herstel-link is ongeldig of al gebruikt. Vraag een nieuwe link aan.</span>
</div>
<a class="auth-back" href="{% url 'password_reset' %}"><svg class="icon" aria-hidden="true"><use href="#icon-arrow"></use></svg>Nieuwe link aanvragen</a>
{% endif %}
</div>
</main>
</body>
</html>
@@ -0,0 +1,30 @@
{% load static %}<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Herstel-link verstuurd · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
</div>
<div class="auth-card">
<h1>Controleer je e-mail</h1>
<div class="auth-alert is-info" role="status">
<svg class="icon" aria-hidden="true"><use href="#icon-mail"></use></svg>
<span>Bestaat er een account met dit e-mailadres, dan is er een herstel-link verstuurd. Volg de instructies in de mail om een nieuw wachtwoord in te stellen.</span>
</div>
<a class="auth-back" href="{% url 'login' %}"><svg class="icon" aria-hidden="true"><use href="#icon-arrow"></use></svg>Terug naar inloggen</a>
</div>
</main>
</body>
</html>
@@ -0,0 +1,15 @@
{% autoescape off %}Hallo,
Je ontving deze e-mail omdat er een wachtwoordherstel is aangevraagd voor je
VacatureRadar-account ({{ user.get_username }}).
Ga naar de volgende pagina om een nieuw wachtwoord te kiezen:
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
Heb je dit niet aangevraagd? Dan kun je deze e-mail negeren; je wachtwoord blijft
ongewijzigd.
Met vriendelijke groet,
VacatureRadar
{% endautoescape %}
@@ -0,0 +1,45 @@
{% load static %}<!doctype html>
<html lang="nl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>Wachtwoord herstellen · VacatureRadar</title>
<link rel="icon" href="{% static 'favicon.svg' %}" type="image/svg+xml">
<link rel="stylesheet" href="{% static 'css/auth.css' %}?v={{ app_version }}">
</head>
<body class="auth-page">
{% include "components/icon_sprite.html" %}
<main class="auth-shell">
<div class="auth-brand">
<img class="auth-brand-logo" src="{% static 'img/vacatureradar-logo.svg' %}" alt="VacatureRadar logo" width="64" height="64">
<p class="auth-brand-name">VacatureRadar</p>
<p class="auth-brand-tagline">Intelligence cockpit</p>
</div>
<div class="auth-card">
<h1>Wachtwoord herstellen</h1>
<p class="auth-lead">Vul je e-mailadres in. Als er een account bij hoort, sturen we een herstel-link.</p>
<form method="post" class="auth-form" novalidate>
{% csrf_token %}
<div class="field">
<label for="id_email">E-mailadres</label>
<input class="auth-input" id="id_email" name="email" type="email"
autocomplete="email" autocapitalize="none" spellcheck="false"
placeholder="naam@organisatie.nl" required
{% if form.email.errors %}aria-invalid="true"{% endif %}
value="{{ form.email.value|default:'' }}">
{% if form.email.errors %}<p class="field-error">{{ form.email.errors|join:" " }}</p>{% endif %}
</div>
<button class="btn btn-primary" type="submit">
Stuur herstel-link
<svg class="icon" aria-hidden="true"><use href="#icon-mail"></use></svg>
</button>
</form>
<a class="auth-back" href="{% url 'login' %}"><svg class="icon" aria-hidden="true"><use href="#icon-arrow"></use></svg>Terug naar inloggen</a>
</div>
</main>
</body>
</html>
@@ -0,0 +1 @@
VacatureRadar — wachtwoord herstellen