Files
Oxyde/src/lib/components/AuthCard.svelte
qdust41 faaea6c729
Some checks failed
Release / release (macos-latest) (push) Has been cancelled
Release / release (ubuntu-22.04) (push) Has been cancelled
Release / release (windows-latest) (push) Has been cancelled
Initial commit
I asked claude to scaffold a project.
I also made changes to it afterwards but they were mostly in getting workflows and testing stuff.
2026-04-15 23:11:48 -04:00

120 lines
3.9 KiB
Svelte

<script lang="ts">
interface Props {
authMode: 'signin' | 'signup';
err: string;
fEmail: string;
fPass: string;
fUser: string;
onSignin: () => void;
onSignup: () => void;
onToggleMode: () => void;
}
let {
authMode,
err,
fEmail = $bindable(),
fPass = $bindable(),
fUser = $bindable(),
onSignin,
onSignup,
onToggleMode,
}: Props = $props();
</script>
<div class="auth-wrap">
<div class="auth-card">
<h1 class="auth-brand">OXYDE</h1>
<p class="auth-tagline">encrypted · realtime · distributed</p>
{#if err}
<div class="err-banner">{err}</div>
{/if}
{#if authMode === 'signin'}
<div class="field-stack">
<input class="field" type="email" placeholder="email" bind:value={fEmail} autocomplete="email" />
<input class="field" type="password" placeholder="password" bind:value={fPass}
onkeydown={(e) => e.key === 'Enter' && onSignin()} autocomplete="current-password" />
<button class="btn-primary" onclick={onSignin}>sign in</button>
</div>
<button class="btn-ghost" onclick={onToggleMode}>
no account? create one →
</button>
{:else}
<div class="field-stack">
<input class="field" type="text" placeholder="username" bind:value={fUser} autocomplete="username" />
<input class="field" type="email" placeholder="email" bind:value={fEmail} autocomplete="email" />
<input class="field" type="password" placeholder="password" bind:value={fPass}
onkeydown={(e) => e.key === 'Enter' && onSignup()} autocomplete="new-password" />
<button class="btn-primary" onclick={onSignup}>create account</button>
</div>
<button class="btn-ghost" onclick={onToggleMode}>
← back to sign in
</button>
{/if}
</div>
</div>
<style>
.auth-wrap {
display: flex; align-items: center; justify-content: center;
height: 100vh; background: var(--bg);
animation: rise 0.28s ease;
}
@keyframes rise {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.auth-card {
width: 360px; padding: 52px 44px;
background: var(--sidebar-bg);
border: 1px solid var(--border);
border-radius: var(--r);
}
.auth-brand {
font-family: 'Cormorant Garamond', Georgia, serif;
font-size: 52px; font-weight: 700;
color: var(--accent); letter-spacing: 0.22em;
text-align: center;
}
.auth-tagline {
text-align: center; color: var(--muted);
font-size: 9.5px; letter-spacing: 0.15em;
margin-top: 8px; margin-bottom: 36px;
}
.err-banner {
padding: 10px 14px; margin-bottom: 18px;
background: rgba(184, 48, 48, 0.10);
border: 1px solid rgba(184, 48, 48, 0.28);
border-radius: var(--r);
color: #d98080; font-size: 11px; line-height: 1.5;
}
.field-stack { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.field {
width: 100%; padding: 10px 14px;
background: var(--bg);
border: 1px solid var(--border); border-radius: var(--r);
color: var(--text); font-family: inherit; font-size: 12px;
outline: none; transition: border-color 0.12s;
}
.field:focus { border-color: var(--accent); }
.field::placeholder { color: var(--muted); }
.btn-primary {
width: 100%; padding: 11px;
background: var(--accent); border: none; border-radius: var(--r);
color: #fff; font-family: inherit; font-size: 12px;
font-weight: 500; letter-spacing: 0.07em;
cursor: pointer; transition: opacity 0.12s, transform 0.08s;
}
.btn-primary:hover { opacity: 0.85; }
.btn-primary:active { transform: scale(0.98); }
.btn-ghost {
display: block; width: 100%; text-align: center;
padding: 9px; background: none; border: none;
color: var(--muted); font-family: inherit; font-size: 11px;
cursor: pointer; transition: color 0.12s;
}
.btn-ghost:hover { color: var(--text-2); }
</style>