fix(auth): split login and signup into separate 1Password-compatible forms
1Password showed "No items to display" on the signup password field because login and registration shared a single form whose password input switched autocomplete between current-password and new-password, and the display-name field was dynamically added via v-if. Per 1Password compatible website design, unrelated flows must be separate forms with stable fields. Changes: - Split into two distinct <form> elements: login (autocomplete current-password) and signup (autocomplete new-password), each with unique field ids so 1Password does not cache the field as a login field - Add passwordrules, minlength=8, and maxlength=128 to the signup password input so 1Password can generate a password matching the server rules (min 8 chars) - Remove the dynamic autocomplete computed and the v-if display-name field; each form now has a static, complete field set - Add .fields form styling (flex column, gap) now that the forms sit inside the card container
This commit is contained in:
parent
f97b4f92f0
commit
cf63f27839
1 changed files with 51 additions and 24 deletions
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import { login, oidcLogin, register } from '@/game/auth'
|
||||
import { store } from '@/game/store'
|
||||
|
||||
|
|
@ -10,11 +10,6 @@ const displayName = ref('')
|
|||
const busy = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
// Password managers (1Password, Bitwarden, …) rely on distinct autocomplete
|
||||
// hints: "current-password" for login, "new-password" so a strong password is
|
||||
// suggested/saved during registration.
|
||||
const passwordAutocomplete = computed(() => (mode.value === 'login' ? 'current-password' : 'new-password'))
|
||||
|
||||
function close(): void {
|
||||
store.auth.showAuth = false
|
||||
error.value = ''
|
||||
|
|
@ -38,7 +33,7 @@ async function submit(): Promise<void> {
|
|||
|
||||
<template>
|
||||
<div v-if="store.auth.showAuth" class="backdrop" @click.self="close">
|
||||
<form class="card" @submit.prevent="submit">
|
||||
<div class="card">
|
||||
<button type="button" class="close" @click="close">✕</button>
|
||||
<h2>{{ mode === 'login' ? 'Anmelden' : 'Konto erstellen' }}</h2>
|
||||
<p class="sub">Speichere Kristalle, Forschung & Statistiken über alle Runden hinweg.</p>
|
||||
|
|
@ -48,30 +43,56 @@ async function submit(): Promise<void> {
|
|||
<button type="button" :class="{ active: mode === 'register' }" @click="mode = 'register'">Registrieren</button>
|
||||
</div>
|
||||
|
||||
<!-- Anmeldung: separates Formular mit current-password -->
|
||||
<form v-if="mode === 'login'" class="fields" @submit.prevent="submit">
|
||||
<label class="field">
|
||||
<span>Benutzername</span>
|
||||
<input id="username" name="username" v-model="username" maxlength="16" autocomplete="username" />
|
||||
<input id="login-username" name="username" v-model="username" maxlength="16" autocomplete="username" />
|
||||
</label>
|
||||
<label v-if="mode === 'register'" class="field">
|
||||
<label class="field">
|
||||
<span>Passwort</span>
|
||||
<input id="login-password" name="password" v-model="password" type="password" autocomplete="current-password" />
|
||||
</label>
|
||||
|
||||
<p v-if="error" class="error">{{ error }}</p>
|
||||
|
||||
<button type="submit" class="primary" :disabled="busy">{{ busy ? '…' : '▶ Anmelden' }}</button>
|
||||
</form>
|
||||
|
||||
<!-- Registrierung: separates Formular mit new-password + Generierungs-Regeln -->
|
||||
<form v-else class="fields" @submit.prevent="submit">
|
||||
<label class="field">
|
||||
<span>Benutzername</span>
|
||||
<input id="register-username" name="username" v-model="username" maxlength="16" autocomplete="username" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Anzeigename (optional)</span>
|
||||
<input id="displayName" name="displayName" v-model="displayName" maxlength="24" autocomplete="nickname" />
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>Passwort</span>
|
||||
<input id="password" name="password" v-model="password" type="password" :autocomplete="passwordAutocomplete" />
|
||||
<input
|
||||
id="register-password"
|
||||
name="password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
minlength="8"
|
||||
maxlength="128"
|
||||
passwordrules="minlength: 8; maxlength: 128;"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<p v-if="error" class="error">{{ error }}</p>
|
||||
|
||||
<button type="submit" class="primary" :disabled="busy">
|
||||
{{ busy ? '…' : mode === 'login' ? '▶ Anmelden' : '▶ Konto erstellen' }}
|
||||
</button>
|
||||
<button type="submit" class="primary" :disabled="busy">{{ busy ? '…' : '▶ Konto erstellen' }}</button>
|
||||
</form>
|
||||
|
||||
<div v-if="store.auth.oidcEnabled" class="divider"><span>oder</span></div>
|
||||
<button type="button" v-if="store.auth.oidcEnabled" class="oidc" @click="oidcLogin">🔑 {{ store.auth.oidcLabel }}</button>
|
||||
|
||||
<p class="hint">Als Gast spielen? Einfach schließen – Fortschritt wird lokal gespeichert.</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -138,6 +159,12 @@ h2 {
|
|||
color: var(--text);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue