feat: add resources and view components
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
<x-guest-layout>
|
||||
@php
|
||||
$logo = get_setting('app_logo');
|
||||
@endphp
|
||||
|
||||
{{-- Logo & Intro --}}
|
||||
<div class="text-center text-primary mb-5">
|
||||
<img src="{{ asset('assets/img/logo.png') }}" alt="logo" class="maxwidth-200 mx-auto"><br>
|
||||
<i class="fs-15 opacity-75 mb-0">
|
||||
{{ $app_tagline1 ?? '' }}<br>
|
||||
{{ $app_tagline ?? '' }}
|
||||
</i>
|
||||
</div>
|
||||
|
||||
{{-- Alert Session Status (Login feedback) --}}
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success">{{ session('status') }}</div>
|
||||
@endif
|
||||
@if($errors->has('email'))
|
||||
<div class="alert alert-danger mt-2">
|
||||
{{ $errors->first('email') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Login Form --}}
|
||||
<form method="POST" action="{{ route('login') }}">
|
||||
@csrf
|
||||
|
||||
{{-- Email Input --}}
|
||||
<div class="form-floating mb-3">
|
||||
<input type="email" autocomplete="off" class="form-control @error('email') is-invalid @enderror" id="email"
|
||||
name="email" placeholder="Enter email" required value="{{ old('email') }}">
|
||||
<label for="email">Email Address</label>
|
||||
</div>
|
||||
|
||||
{{-- Password Input --}}
|
||||
<div class="input-group mb-3">
|
||||
<div class="form-floating flex-grow-1">
|
||||
<input type="password" autocomplete="new-password"
|
||||
class="form-control border-end-0 @error('password') is-invalid @enderror" id="password"
|
||||
name="password" placeholder="Enter your password" required>
|
||||
<label for="password">Password</label>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary bg-white border-start-0 password-toggle" type="button"
|
||||
style="border-color: #dee2e6;">
|
||||
<i class="bi bi-eye text-secondary"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- Options: Remember + Forgot Password --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<label class="text-primary">
|
||||
<input type="checkbox" name="remember"> Remember me
|
||||
</label>
|
||||
|
||||
@if (Route::has('password.request'))
|
||||
<a href="{{ route('password.request') }}" class="text-primary small">
|
||||
Forgot Password?
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
{{-- Captcha --}}
|
||||
@if(get_setting('captcha_enabled', false))
|
||||
<div class="mb-3 d-flex justify-content-center">
|
||||
{!! NoCaptcha::display() !!}
|
||||
</div>
|
||||
@if ($errors->has('g-recaptcha-response'))
|
||||
<div class="alert alert-danger py-2 small mb-3">
|
||||
{{ $errors->first('g-recaptcha-response') }}
|
||||
</div>
|
||||
@endif
|
||||
{!! NoCaptcha::renderJs() !!}
|
||||
@endif
|
||||
|
||||
{{-- Submit --}}
|
||||
<button type="submit" class="btn btn-lg btn-primary theme-black w-100 mb-2">
|
||||
Login
|
||||
</button>
|
||||
|
||||
@if(get_setting('webauthn_enabled', false))
|
||||
<button type="button" id="passkey-login" class="btn btn-lg btn-info w-100 mb-2 text-white">
|
||||
<i class="bi bi-fingerprint me-2"></i> {{ __('Login with Passkey') }}
|
||||
</button>
|
||||
@endif
|
||||
|
||||
{{-- Social Logins --}}
|
||||
<div class="row g-2 mt-2">
|
||||
@if(get_setting('feature_google_oauth', false))
|
||||
<div class="col-12">
|
||||
<a href="{{ route('auth.social', 'google') }}" class="btn btn-lg btn-outline-dark w-100">
|
||||
<img src="{{ asset('assets/img/google.png') }}" alt="google" class="maxwidth-20 mx-auto me-2">
|
||||
{{ __('Login with Google') }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(get_setting('feature_facebook_oauth', false))
|
||||
<div class="col-12">
|
||||
<a href="{{ route('auth.social', 'facebook') }}" class="btn btn-lg btn-outline-dark w-100">
|
||||
<img src="{{ asset('assets/img/facebook.png') }}" alt="facebook" class="maxwidth-20 mx-auto me-2">
|
||||
{{ __('Login with Facebook') }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(get_setting('feature_github_oauth', false))
|
||||
<div class="col-12">
|
||||
<a href="{{ route('auth.social', 'github') }}" class="btn btn-lg btn-outline-dark w-100">
|
||||
<img src="{{ asset('assets/img/github.png') }}" alt="github" class="maxwidth-20 mx-auto me-2">
|
||||
{{ __('Login with GitHub') }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if(get_setting('webauthn_enabled', false))
|
||||
<script src="{{ asset('vendor/webauthn/webauthn.js') }}"></script>
|
||||
<script>
|
||||
document.getElementById('passkey-login').addEventListener('click', async () => {
|
||||
const passkeyBtn = document.getElementById('passkey-login');
|
||||
|
||||
// Check if class is available
|
||||
if (typeof WebAuthn === 'undefined') {
|
||||
console.error('WebAuthn library not loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (WebAuthn.supportsWebAuthn()) {
|
||||
try {
|
||||
passkeyBtn.disabled = true;
|
||||
passkeyBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span> {{ __("Authenticating...") }}';
|
||||
|
||||
const webauthn = new WebAuthn();
|
||||
const response = await webauthn.login();
|
||||
|
||||
if (response) {
|
||||
window.location.href = "{{ route('dashboard') }}";
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('WebAuthn Error:', error);
|
||||
|
||||
let errorMsg = 'Authentication failed. Please use your password.';
|
||||
|
||||
if (!window.isSecureContext) {
|
||||
errorMsg = 'Passkeys require a secure context (HTTPS). \n\n' +
|
||||
'Developer Tip: If you are on a local domain (like .test), you can bypass this in Chrome/Edge by going to: \n' +
|
||||
'chrome://flags/#unsafely-treat-insecure-origin-as-secure \n' +
|
||||
'and adding your domain to the list.';
|
||||
} else if (error.name === 'NotAllowedError') {
|
||||
errorMsg = 'Authentication was cancelled or timed out.';
|
||||
} else {
|
||||
errorMsg = 'Login failed. Ensure you have registered a passkey on this device.';
|
||||
}
|
||||
|
||||
StandardSwal.fire({
|
||||
icon: 'error',
|
||||
title: 'Authentication Failed!',
|
||||
text: errorMsg || 'Unable to log in with Passkey. Please verify your device settings or use your password.',
|
||||
confirmButtonText: 'Try Again'
|
||||
});
|
||||
} finally {
|
||||
passkeyBtn.disabled = false;
|
||||
passkeyBtn.innerHTML = '<i class="bi bi-fingerprint me-2"></i> {{ __("Login with Passkey") }}';
|
||||
}
|
||||
} else {
|
||||
StandardSwal.fire({
|
||||
icon: 'info',
|
||||
title: 'Passkey Not Supported',
|
||||
text: 'Your current browser or device does not support secure Passkey authentication.',
|
||||
confirmButtonText: 'Understood'
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
<div class="text-center text-primary mb-5">
|
||||
{{-- Footer --}}
|
||||
<small class="opacity-50 d-block mt-4"> {{ $footer_text }} </small>
|
||||
</div>
|
||||
|
||||
</x-guest-layout>
|
||||
Reference in New Issue
Block a user