- TallStackUI 4 (MIT) statt Flux; Komponenten mit Präfix ts- (<x-ts-…>) - Layouts, Login-, Passwort-, 2FA- und Einstellungsseiten neu aufgebaut - Livewire-Skripte explizit in beiden Layouts, damit Alpine auch auf den Fortify-Seiten ohne Livewire-Komponente läuft - Dark Mode über tallstackui_darkTheme(), ohne Aufblitzen beim Laden - Registrierungs-View und ungenutzte Layout-Varianten entfernt - Test: Seiten laden keine Ressourcen von fremden Hosts (Vorgabe "alles lokal") Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.5 KiB
PHP
75 lines
2.5 KiB
PHP
@props([
|
|
'optionsRoute' => 'passkey.login-options',
|
|
'submitRoute' => 'passkey.login',
|
|
'label' => __('Sign in with a passkey'),
|
|
'loadingLabel' => __('Authenticating...'),
|
|
'separator' => __('Or continue with email'),
|
|
])
|
|
|
|
@assets
|
|
@vite('resources/js/passkeys.js')
|
|
@endassets
|
|
|
|
<div
|
|
x-data="{
|
|
supported: false,
|
|
loading: false,
|
|
error: null,
|
|
updateSupport() {
|
|
this.supported = Boolean(window.Passkeys?.isSupported());
|
|
},
|
|
init() {
|
|
this.updateSupport();
|
|
|
|
window.addEventListener('passkeys:ready', () => this.updateSupport(), { once: true });
|
|
},
|
|
async verify() {
|
|
this.loading = true;
|
|
this.error = null;
|
|
try {
|
|
const response = await window.Passkeys.verify({
|
|
routes: {
|
|
options: '{{ route($optionsRoute) }}',
|
|
submit: '{{ route($submitRoute) }}',
|
|
},
|
|
});
|
|
Livewire.navigate(response.redirect || '/dashboard');
|
|
} catch (e) {
|
|
if (e.constructor?.name !== 'UserCancelledError') {
|
|
this.error = e.message;
|
|
}
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
}"
|
|
>
|
|
<template x-if="supported">
|
|
<div>
|
|
<div class="grid gap-2">
|
|
<x-ts-button outline
|
|
icon="finger-print"
|
|
class="w-full"
|
|
x-on:click="verify()"
|
|
x-bind:disabled="loading">
|
|
<span x-show="!loading">{{ $label }}</span>
|
|
<span x-show="loading" x-cloak>{{ $loadingLabel }}</span>
|
|
</x-ts-button>
|
|
<p x-show="error" x-text="error" x-cloak
|
|
class="text-center text-sm text-red-600 dark:text-red-400"></p>
|
|
</div>
|
|
|
|
<div class="relative my-6">
|
|
<div class="absolute inset-0 flex items-center">
|
|
<div class="w-full border-t border-gray-200 dark:border-dark-600"></div>
|
|
</div>
|
|
<div class="relative flex justify-center text-xs uppercase">
|
|
<span class="bg-white px-2 text-gray-500 dark:bg-dark-800 dark:text-dark-300">
|
|
{{ $separator }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|