Files
aptool/templates/login.html
2026-01-26 04:46:56 -06:00

210 lines
8.0 KiB
HTML

<!--
=============================================================================
APtool — Login Page (login.html)
=============================================================================
This is the first page a technician sees. It collects two pieces of info:
1. Site Number (4 digits) — identifies which job site the tech is at.
Stored in the session and used to organize all files into per-site
folders (e.g. uploads/5001/, Nextcloud APtool/5001/).
2. PIN — the site-specific PIN code.
Validated server-side against sites.conf (each site has its own PIN).
On successful login:
- session["authenticated"] = True
- session["site"] = "5001"
- Redirects to / (the main data collection form)
On failure:
- Re-renders this page with an error message (wrong PIN or bad site format)
Template variables (passed from Flask):
- error — error message string, or None if no error
Design:
- Centered card layout, vertically and horizontally centered on screen
- Large, touch-friendly inputs with numeric keyboard hints (inputmode)
- Site number input uses pattern="[0-9]{4}" for client-side validation
- PIN input uses type="password" to hide the digits
=============================================================================
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Mobile-first: ensure proper scaling on phones/tablets -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>APtool - Login</title>
<style>
/* =================================================================
Reset & Base Styles
================================================================= */
*, *::before, *::after {
box-sizing: border-box;
}
/* Full-viewport centered layout using flexbox.
The body acts as the flex container to vertically and
horizontally center the login card on all screen sizes. */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
margin: 0;
padding: 16px;
background: #1a1a2e;
color: #e0e0e0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* =================================================================
Login Card
================================================================= */
/* White card with shadow — max 320px wide so it looks good on
both phones (full width with padding) and desktops (compact card) */
.login-box {
background: #16213e;
border-radius: 12px;
padding: 32px 24px;
width: 100%;
max-width: 320px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
text-align: center;
}
/* App title in the card */
h1 {
font-size: 1.5rem;
margin: 0 0 8px;
}
/* "Enter site number and PIN" subtitle */
.subtitle {
color: #999;
font-size: 0.9rem;
margin: 0 0 24px;
}
/* =================================================================
PIN Input
================================================================= */
/* Large centered text with letter spacing to mimic a PIN entry UI.
type="password" hides the digits as they are typed.
inputmode="numeric" brings up the number keyboard on mobile. */
input[type="password"] {
width: 100%;
padding: 14px;
font-size: 1.5rem;
text-align: center;
letter-spacing: 0.5em;
border: 2px solid #2a2a4a;
border-radius: 8px;
background: #0f3460;
color: #e0e0e0;
-moz-appearance: textfield; /* Hide Firefox number spinner */
}
/* Blue focus ring on the PIN input */
input[type="password"]:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
}
/* Hide the increment/decrement spinner arrows that some browsers
show on inputs with inputmode="numeric" */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* =================================================================
Unlock Button
================================================================= */
/* Full-width blue button — same style as the main form's submit.
Large padding for easy tapping on mobile. */
button {
width: 100%;
padding: 14px;
font-size: 1.1rem;
font-weight: 600;
color: #fff;
background: #2563eb;
border: none;
border-radius: 8px;
cursor: pointer;
margin-top: 16px;
}
/* Darker blue on tap/press */
button:active {
background: #1d4ed8;
}
/* =================================================================
Error Message
================================================================= */
/* Red banner shown below the form when login fails.
Only rendered if Flask passes a non-None error variable. */
.error {
color: #fca5a5;
background: #3b1111;
padding: 10px;
border-radius: 8px;
margin-top: 16px;
font-weight: 600;
font-size: 0.9rem;
}
</style>
</head>
<body>
<!-- ================================================================
Login Card
================================================================ -->
<div class="login-box">
<div style="color:#999;font-size:0.8rem;margin-bottom:8px;">JCP Wifi Migration 2026</div>
<h1>APtool</h1>
<p class="subtitle">Enter site number and PIN</p>
<!-- Login form — POSTs to /login which validates and sets session -->
<form method="POST" action="/login">
<!-- Site Number Input
- type="text" with inputmode="numeric" to get the number
keyboard on mobile while allowing leading zeros
- autofocus opens the keyboard immediately on mobile
- Validated server-side against sites.conf
- Inline styles match the password input's look & feel -->
<input type="text" name="site" inputmode="numeric"
placeholder="Site Number" required autofocus
autocomplete="off" style="width:100%;padding:14px;font-size:1.2rem;text-align:center;
letter-spacing:0.3em;border:2px solid #2a2a4a;border-radius:8px;margin-bottom:12px;background:#0f3460;color:#e0e0e0;">
<!-- PIN Input
- type="password" hides the entered digits
- inputmode="numeric" brings up the number keyboard
- Validated server-side against the site's PIN in sites.conf -->
<input type="password" name="pin" inputmode="numeric" pattern="[0-9]*"
placeholder="PIN" required autocomplete="off">
<button type="submit">Unlock</button>
</form>
<!-- Error message — only shown if Flask passes error != None.
Uses Jinja2 "if" template syntax. -->
{% if error %}
<div class="error">{{ error }}</div>
{% endif %}
</div>
<div style="text-align:center;margin-top:16px;">
<a href="/admin/login" style="color:#666;font-size:0.8rem;text-decoration:none;">Admin Login</a>
</div>
<div style="text-align:center;margin-top:24px;color:#555;font-size:0.7rem;">&copy; 2026 Mack Allison, sdAnywhere LLC (with Claude Code)</div>
</body>
</html>