Flux durch TallStackUI 4 ersetzt

- 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>
This commit is contained in:
Christoph
2026-10-01 09:33:26 +02:00
co-authored by Claude Opus 5.5
parent dedce594a0
commit b297518810
47 changed files with 644 additions and 1362 deletions
@@ -1,18 +1,14 @@
<x-layouts::auth :title="__('Two-factor authentication')">
<div class="flex flex-col gap-6">
<div
class="relative w-full h-auto"
x-cloak
x-data="{
<div class="relative h-auto w-full"
x-cloak
x-data="{
showRecoveryInput: @js($errors->has('recovery_code')),
code: '',
recovery_code: '',
focusOtp() {
this.$nextTick(() => this.$refs.otp?.querySelector('input')?.focus());
},
init() {
if (! this.showRecoveryInput) {
this.focusOtp();
this.$nextTick(() => this.$refs.code?.focus());
}
},
toggleInput() {
@@ -24,76 +20,56 @@
$nextTick(() => {
this.showRecoveryInput
? this.$refs.recovery_code?.focus()
: this.focusOtp();
: this.$refs.code?.focus();
});
},
}"
>
}">
<div x-show="!showRecoveryInput">
<x-auth-header
:title="__('Authentication code')"
:description="__('Enter the authentication code provided by your authenticator application.')"
/>
<x-auth-header :title="__('Authentication code')"
:description="__('Enter the authentication code provided by your authenticator application.')" />
</div>
<div x-show="showRecoveryInput">
<x-auth-header
:title="__('Recovery code')"
:description="__('Please confirm access to your account by entering one of your emergency recovery codes.')"
/>
<x-auth-header :title="__('Recovery code')"
:description="__('Please confirm access to your account by entering one of your emergency recovery codes.')" />
</div>
<form method="POST" action="{{ route('two-factor.login.store') }}">
@csrf
<div class="space-y-5 text-center">
<div class="my-5 space-y-5">
<div x-show="!showRecoveryInput">
<div class="flex items-center justify-center my-5" x-ref="otp">
<flux:otp
x-model="code"
length="6"
name="code"
label="OTP Code"
label:sr-only
class="mx-auto"
/>
</div>
<x-ts-input name="code"
:label="__('Authentication code')"
x-model="code"
x-ref="code"
x-bind:required="!showRecoveryInput"
inputmode="numeric"
maxlength="6"
autocomplete="one-time-code"
class="text-center font-mono tracking-[0.5em]" />
</div>
<div x-show="showRecoveryInput">
<div class="my-5">
<flux:input
type="text"
name="recovery_code"
x-ref="recovery_code"
x-bind:required="showRecoveryInput"
autocomplete="one-time-code"
x-model="recovery_code"
/>
</div>
@error('recovery_code')
<flux:text color="red">
{{ $message }}
</flux:text>
@enderror
<x-ts-input name="recovery_code"
:label="__('Recovery code')"
x-model="recovery_code"
x-ref="recovery_code"
x-bind:required="showRecoveryInput"
autocomplete="one-time-code" />
</div>
<flux:button
variant="primary"
type="submit"
class="w-full"
>
<x-ts-button submit class="w-full">
{{ __('Continue') }}
</flux:button>
</x-ts-button>
</div>
<div class="mt-5 space-x-0.5 text-sm leading-5 text-center">
<div class="mt-5 space-x-0.5 text-center text-sm leading-5">
<span class="opacity-50">{{ __('or you can') }}</span>
<div class="inline font-medium underline cursor-pointer opacity-80">
<span x-show="!showRecoveryInput" @click="toggleInput()">{{ __('login using a recovery code') }}</span>
<span x-show="showRecoveryInput" @click="toggleInput()">{{ __('login using an authentication code') }}</span>
</div>
<button type="button" class="inline cursor-pointer font-medium underline opacity-80" x-on:click="toggleInput()">
<span x-show="!showRecoveryInput">{{ __('login using a recovery code') }}</span>
<span x-show="showRecoveryInput">{{ __('login using an authentication code') }}</span>
</button>
</div>
</form>
</div>