|
|
@@ -0,0 +1,248 @@
|
|
|
+<script>
|
|
|
+ import logoMark from '$lib/images/logo_white.svg';
|
|
|
+
|
|
|
+ let email = $state('');
|
|
|
+ let password = $state('');
|
|
|
+ /** Honeypot — leave empty. Bots often fill this. */
|
|
|
+ let website = $state('');
|
|
|
+
|
|
|
+ function handleSubmit(event) {
|
|
|
+ event.preventDefault();
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<svelte:head>
|
|
|
+ <title>Log in — Torus</title>
|
|
|
+</svelte:head>
|
|
|
+
|
|
|
+<div class="page">
|
|
|
+ <header class="top">
|
|
|
+ <a class="brand" href="/">
|
|
|
+ <img class="brand-mark" src={logoMark} alt="" width="28" height="28" />
|
|
|
+ <span class="brand-name">Torus</span>
|
|
|
+ </a>
|
|
|
+ <a class="btn btn-ghost" href="/register">Create account</a>
|
|
|
+ </header>
|
|
|
+
|
|
|
+ <main>
|
|
|
+ <section class="card" aria-labelledby="login-title">
|
|
|
+ <div class="card-head">
|
|
|
+ <img class="card-logo" src={logoMark} alt="" width="36" height="36" />
|
|
|
+ <h1 id="login-title">Log in</h1>
|
|
|
+ <p class="lede">Email and password. Back to the floor.</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <form class="form" method="POST" onsubmit={handleSubmit}>
|
|
|
+ <label class="field">
|
|
|
+ <span class="label">Email</span>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="email"
|
|
|
+ name="email"
|
|
|
+ autocomplete="email"
|
|
|
+ required
|
|
|
+ autofocus
|
|
|
+ bind:value={email}
|
|
|
+ />
|
|
|
+ </label>
|
|
|
+
|
|
|
+ <label class="field">
|
|
|
+ <span class="label">Password</span>
|
|
|
+ <input
|
|
|
+ class="input"
|
|
|
+ type="password"
|
|
|
+ name="password"
|
|
|
+ autocomplete="current-password"
|
|
|
+ required
|
|
|
+ bind:value={password}
|
|
|
+ />
|
|
|
+ </label>
|
|
|
+
|
|
|
+ <div class="hp" aria-hidden="true">
|
|
|
+ <label>
|
|
|
+ Website
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ name="website"
|
|
|
+ tabindex="-1"
|
|
|
+ autocomplete="off"
|
|
|
+ bind:value={website}
|
|
|
+ />
|
|
|
+ </label>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <button class="btn btn-primary btn-submit" type="submit">Log in</button>
|
|
|
+ </form>
|
|
|
+
|
|
|
+ <p class="switch">
|
|
|
+ Need an account?
|
|
|
+ <a class="switch-link" href="/register">Create account</a>
|
|
|
+ </p>
|
|
|
+ </section>
|
|
|
+ </main>
|
|
|
+</div>
|
|
|
+
|
|
|
+<style>
|
|
|
+ .page {
|
|
|
+ min-height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .top {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 16px;
|
|
|
+ padding: 16px 20px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ font-weight: 700;
|
|
|
+ letter-spacing: -0.02em;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-mark {
|
|
|
+ display: block;
|
|
|
+ width: 28px;
|
|
|
+ height: 28px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-name {
|
|
|
+ font-size: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ main {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 40px 20px 64px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card {
|
|
|
+ width: min(420px, 100%);
|
|
|
+ background: var(--surface);
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ border-radius: var(--radius-lg);
|
|
|
+ padding: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-head {
|
|
|
+ margin-bottom: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card-logo {
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ h1 {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 1.6rem;
|
|
|
+ letter-spacing: -0.03em;
|
|
|
+ font-weight: 750;
|
|
|
+ }
|
|
|
+
|
|
|
+ .lede {
|
|
|
+ margin: 8px 0 0;
|
|
|
+ color: var(--text-muted);
|
|
|
+ font-size: 0.95rem;
|
|
|
+ line-height: 1.45;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form {
|
|
|
+ display: grid;
|
|
|
+ gap: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .field {
|
|
|
+ display: grid;
|
|
|
+ gap: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .label {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 650;
|
|
|
+ color: var(--text-muted);
|
|
|
+ }
|
|
|
+
|
|
|
+ .input {
|
|
|
+ width: 100%;
|
|
|
+ padding: 11px 12px;
|
|
|
+ border: 1px solid var(--border);
|
|
|
+ border-radius: var(--radius-sm);
|
|
|
+ background: var(--surface-3);
|
|
|
+ color: var(--text);
|
|
|
+ font: inherit;
|
|
|
+ font-size: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input::placeholder {
|
|
|
+ color: color-mix(in srgb, var(--text-muted) 80%, transparent);
|
|
|
+ }
|
|
|
+
|
|
|
+ .input:hover {
|
|
|
+ border-color: color-mix(in srgb, var(--border) 70%, var(--ash));
|
|
|
+ }
|
|
|
+
|
|
|
+ .input:focus {
|
|
|
+ outline: 2px solid var(--focus);
|
|
|
+ outline-offset: 2px;
|
|
|
+ border-color: color-mix(in srgb, var(--ember) 45%, var(--border));
|
|
|
+ }
|
|
|
+
|
|
|
+ .hp {
|
|
|
+ position: absolute;
|
|
|
+ left: -10000px;
|
|
|
+ top: auto;
|
|
|
+ width: 1px;
|
|
|
+ height: 1px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-submit {
|
|
|
+ width: 100%;
|
|
|
+ margin-top: 6px;
|
|
|
+ padding: 12px 16px;
|
|
|
+ font-size: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .switch {
|
|
|
+ margin: 20px 0 0;
|
|
|
+ text-align: center;
|
|
|
+ color: var(--text-muted);
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .switch-link {
|
|
|
+ color: var(--heat);
|
|
|
+ font-weight: 650;
|
|
|
+ margin-left: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .switch-link:hover {
|
|
|
+ color: var(--ember);
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
+
|
|
|
+ @media (min-width: 720px) {
|
|
|
+ .top {
|
|
|
+ padding: 16px 28px;
|
|
|
+ }
|
|
|
+
|
|
|
+ main {
|
|
|
+ align-items: center;
|
|
|
+ padding: 48px 28px 80px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .card {
|
|
|
+ padding: 28px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|