Konsolidierter, bereinigter Stand der Wissensbasis (docs/). Frischer Wurzel-Commit, um urheberrechtlich problematische Volltexte aus der Historie zu entfernen (die bisherige Historie bestand aus einem einzigen Initial-Commit). Enthaltene Änderungen (vgl. docs/_Steuerung/CHANGELOG.md, 2026-05-29): - Copyright-Hygiene: 25 Volltext-/Übersetzungsdateien (Sharp 14 Kap., Wala 11 Kap.) entfernt; je Quelle _Fundstellen-Index.md als Provenienzbeleg; Quellnachweise + Steuerungsdateien angepasst. - Konsistenz-Korrekturen: Reichweite 000-013 (Scorecard-Regeln), Rule-ID MW-WK-DIFF-101, Quellnachweis-Dateiverweis, Dok.000 v2.0.2. - Dateinamen-Normalisierung: Startdatei ohne Leerzeichen. Originale (Wala/Sharp E-Books) privat außerhalb des Repos archiviert. Co-authored-by: Cursor <cursoragent@cursor.com>
94 lines
3 KiB
PHP
94 lines
3 KiB
PHP
@assets
|
|
@vite('resources/js/passkeys.js')
|
|
@endassets
|
|
|
|
<div
|
|
x-data="{
|
|
supported: false,
|
|
showForm: false,
|
|
name: '',
|
|
loading: false,
|
|
error: null,
|
|
updateSupport() {
|
|
this.supported = Boolean(window.Passkeys?.isSupported());
|
|
},
|
|
init() {
|
|
this.updateSupport();
|
|
|
|
window.addEventListener('passkeys:ready', () => this.updateSupport(), { once: true });
|
|
},
|
|
async register() {
|
|
if (!this.name.trim()) return;
|
|
|
|
this.loading = true;
|
|
this.error = null;
|
|
|
|
try {
|
|
await window.Passkeys.register({ name: this.name });
|
|
this.name = '';
|
|
this.showForm = false;
|
|
await $wire.loadPasskeys();
|
|
} catch (e) {
|
|
if (e.constructor?.name !== 'UserCancelledError') {
|
|
this.error = e.message;
|
|
}
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
cancel() {
|
|
this.showForm = false;
|
|
this.name = '';
|
|
this.error = null;
|
|
},
|
|
}"
|
|
>
|
|
<template x-if="!supported">
|
|
<flux:text>{{ __('Passkeys are not supported in this browser.') }}</flux:text>
|
|
</template>
|
|
|
|
<template x-if="supported && !showForm">
|
|
<div>
|
|
<flux:button
|
|
variant="primary"
|
|
icon="plus"
|
|
x-on:click="showForm = true"
|
|
>
|
|
{{ __('Add passkey') }}
|
|
</flux:button>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-if="supported && showForm">
|
|
<div class="space-y-4 rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800/50 p-4">
|
|
<flux:input
|
|
label="{{ __('Passkey name') }}"
|
|
x-model="name"
|
|
placeholder="{{ __('e.g., MacBook Pro, iPhone') }}"
|
|
x-on:keydown.enter.prevent="register()"
|
|
x-ref="passkeyNameInput"
|
|
x-init="$nextTick(() => $refs.passkeyNameInput?.focus())"
|
|
/>
|
|
<flux:text class="!mt-1">{{ __('Give this passkey a name to help you identify it later.') }}</flux:text>
|
|
|
|
<p x-show="error" x-text="error" x-cloak class="text-sm text-red-600 dark:text-red-400"></p>
|
|
|
|
<div class="flex gap-2">
|
|
<flux:button
|
|
variant="primary"
|
|
x-on:click="register()"
|
|
x-bind:disabled="loading || !name.trim()"
|
|
>
|
|
<span x-show="!loading">{{ __('Register passkey') }}</span>
|
|
<span x-show="loading" x-cloak>{{ __('Registering...') }}</span>
|
|
</flux:button>
|
|
<flux:button
|
|
variant="ghost"
|
|
x-on:click="cancel()"
|
|
>
|
|
{{ __('Cancel') }}
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|