Skip to main content

max / makenotwork

3.5 KB · 103 lines History Blame Raw
1 {% extends "base.html" %}
2
3 {% block title %}Log In - Makenotwork{% endblock %}
4
5 {% block body_attrs %} class="centered-page"{% endblock %}
6
7 {% block content %}
8 <h1 class="brand-h1">Makenot<span class="dot">.</span>work</h1>
9 <div class="login-container">
10 {% if let Some(note) = notice %}<div class="alert alert-note">{{ note }}</div>{% endif %}
11 <div id="login-errors">
12 {% if let Some(msg) = error %}<div class="alert alert-error">{{ msg }}</div>{% endif %}
13 </div>
14
15 {% if sso_enabled %}
16 <div class="sso-login">
17 <h2 class="subtitle-h2">Log in</h2>
18 <p class="login-prose">testnot.work is a preview of makenot.work. Sign in with your makenot.work account to continue &mdash; your password is only ever entered on makenot.work.</p>
19 <a class="btn-primary btn--large" href="/sso/login">Sign in with Makenot<span class="dot">.</span>work</a>
20 </div>
21 {% else %}
22 <form class="login-form"
23 method="post"
24 action="/login"
25 hx-post="/login"
26 hx-target="#login-errors"
27 hx-swap="innerHTML"
28 hx-indicator="#login-spinner">
29 {% if let Some(token) = csrf_token %}<input type="hidden" name="_csrf" value="{{ token }}">{% endif %}
30 <h2 class="subtitle-h2">Log in</h2>
31 <div class="form-group">
32 <label for="login">Username or Email</label>
33 <input
34 type="text"
35 id="login"
36 name="login"
37 placeholder="username or you@example.com"
38 value="{{ prefill_login }}"
39 required
40 autofocus
41 />
42 </div>
43
44 <div class="form-group">
45 <label for="password">Password</label>
46 <input
47 type="password"
48 id="password"
49 name="password"
50 placeholder="--------"
51 required
52 />
53 </div>
54
55 <div class="checkbox-group">
56 <input type="checkbox" id="remember-me" name="remember_me" />
57 <label for="remember-me">Remember me</label>
58 </div>
59
60 <button type="submit" class="btn-primary">
61 Log In
62 <span id="login-spinner" class="htmx-indicator"> ...</span>
63 </button>
64
65 <div class="foot-link">
66 <a href="/forgot-password">Reset Password<span class="dot">.</span></a>
67 </div>
68
69 <div class="foot-link">
70 <a href="/join">Join now<span class="dot">.</span></a>
71 </div>
72 </form>
73
74 <div id="passkey-login" class="hidden">
75 <div class="login-divider">or</div>
76 <button class="btn-secondary login-passkey-btn" onclick="loginWithPasskey()">
77 Sign in with Passkey (fingerprint, face, or security key)
78 </button>
79 <div id="passkey-login-error" class="login-passkey-error"></div>
80 </div>
81 {% endif %}
82 </div>
83 {% endblock %}
84
85 {% block scripts %}
86 <script>
87 // Handle successful login redirect via HX-Redirect header
88 document.body.addEventListener('htmx:beforeSwap', function(evt) {
89 if (evt.detail.xhr.status === 200 && evt.detail.xhr.getResponseHeader('HX-Redirect')) {
90 // Let HTMX handle the redirect
91 }
92 });
93 </script>
94 <script src="/static/passkey.js"></script>
95 <script>
96 // Show passkey button if browser supports WebAuthn (absent in SSO-only mode)
97 var passkeyLogin = document.getElementById('passkey-login');
98 if (window.PublicKeyCredential && passkeyLogin) {
99 passkeyLogin.classList.remove('hidden');
100 }
101 </script>
102 {% endblock %}
103