first commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,7 @@
|
||||
import './bootstrap';
|
||||
|
||||
import Alpine from 'alpinejs';
|
||||
|
||||
window.Alpine = Alpine;
|
||||
|
||||
Alpine.start();
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
@@ -0,0 +1,27 @@
|
||||
<x-guest-layout>
|
||||
<div class="mb-4 text-sm text-gray-600">
|
||||
{{ __('This is a secure area of the application. Please confirm your password before continuing.') }}
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('password.confirm') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Password -->
|
||||
<div>
|
||||
<x-input-label for="password" :value="__('Password')" />
|
||||
|
||||
<x-text-input id="password" class="block mt-1 w-full"
|
||||
type="password"
|
||||
name="password"
|
||||
required autocomplete="current-password" />
|
||||
|
||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end mt-4">
|
||||
<x-primary-button>
|
||||
{{ __('Confirm') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-guest-layout>
|
||||
@@ -0,0 +1,25 @@
|
||||
<x-guest-layout>
|
||||
<div class="mb-4 text-sm text-gray-600">
|
||||
{{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }}
|
||||
</div>
|
||||
|
||||
<!-- Session Status -->
|
||||
<x-auth-session-status class="mb-4" :status="session('status')" />
|
||||
|
||||
<form method="POST" action="{{ route('password.email') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Email Address -->
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<x-primary-button>
|
||||
{{ __('Email Password Reset Link') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-guest-layout>
|
||||
@@ -0,0 +1,47 @@
|
||||
<x-guest-layout>
|
||||
<!-- Session Status -->
|
||||
<x-auth-session-status class="mb-4" :status="session('status')" />
|
||||
|
||||
<form method="POST" action="{{ route('login') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Email Address -->
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus autocomplete="username" />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password" :value="__('Password')" />
|
||||
|
||||
<x-text-input id="password" class="block mt-1 w-full"
|
||||
type="password"
|
||||
name="password"
|
||||
required autocomplete="current-password" />
|
||||
|
||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Remember Me -->
|
||||
<div class="block mt-4">
|
||||
<label for="remember_me" class="inline-flex items-center">
|
||||
<input id="remember_me" type="checkbox" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500" name="remember">
|
||||
<span class="ms-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
@if (Route::has('password.request'))
|
||||
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}">
|
||||
{{ __('Forgot your password?') }}
|
||||
</a>
|
||||
@endif
|
||||
|
||||
<x-primary-button class="ms-3">
|
||||
{{ __('Log in') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-guest-layout>
|
||||
@@ -0,0 +1,52 @@
|
||||
<x-guest-layout>
|
||||
<form method="POST" action="{{ route('register') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Name -->
|
||||
<div>
|
||||
<x-input-label for="name" :value="__('Name')" />
|
||||
<x-text-input id="name" class="block mt-1 w-full" type="text" name="name" :value="old('name')" required autofocus autocomplete="name" />
|
||||
<x-input-error :messages="$errors->get('name')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Email Address -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autocomplete="username" />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password" :value="__('Password')" />
|
||||
|
||||
<x-text-input id="password" class="block mt-1 w-full"
|
||||
type="password"
|
||||
name="password"
|
||||
required autocomplete="new-password" />
|
||||
|
||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
||||
|
||||
<x-text-input id="password_confirmation" class="block mt-1 w-full"
|
||||
type="password"
|
||||
name="password_confirmation" required autocomplete="new-password" />
|
||||
|
||||
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('login') }}">
|
||||
{{ __('Already registered?') }}
|
||||
</a>
|
||||
|
||||
<x-primary-button class="ms-4">
|
||||
{{ __('Register') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-guest-layout>
|
||||
@@ -0,0 +1,39 @@
|
||||
<x-guest-layout>
|
||||
<form method="POST" action="{{ route('password.store') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Password Reset Token -->
|
||||
<input type="hidden" name="token" value="{{ $request->route('token') }}">
|
||||
|
||||
<!-- Email Address -->
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email', $request->email)" required autofocus autocomplete="username" />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password" :value="__('Password')" />
|
||||
<x-text-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
|
||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
||||
|
||||
<x-text-input id="password_confirmation" class="block mt-1 w-full"
|
||||
type="password"
|
||||
name="password_confirmation" required autocomplete="new-password" />
|
||||
|
||||
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<x-primary-button>
|
||||
{{ __('Reset Password') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-guest-layout>
|
||||
@@ -0,0 +1,31 @@
|
||||
<x-guest-layout>
|
||||
<div class="mb-4 text-sm text-gray-600">
|
||||
{{ __('Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn\'t receive the email, we will gladly send you another.') }}
|
||||
</div>
|
||||
|
||||
@if (session('status') == 'verification-link-sent')
|
||||
<div class="mb-4 font-medium text-sm text-green-600">
|
||||
{{ __('A new verification link has been sent to the email address you provided during registration.') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<form method="POST" action="{{ route('verification.send') }}">
|
||||
@csrf
|
||||
|
||||
<div>
|
||||
<x-primary-button>
|
||||
{{ __('Resend Verification Email') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="POST" action="{{ route('logout') }}">
|
||||
@csrf
|
||||
|
||||
<button type="submit" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
{{ __('Log Out') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</x-guest-layout>
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 316 316" xmlns="http://www.w3.org/2000/svg" {{ $attributes }}>
|
||||
<path d="M305.8 81.125C305.77 80.995 305.69 80.885 305.65 80.755C305.56 80.525 305.49 80.285 305.37 80.075C305.29 79.935 305.17 79.815 305.07 79.685C304.94 79.515 304.83 79.325 304.68 79.175C304.55 79.045 304.39 78.955 304.25 78.845C304.09 78.715 303.95 78.575 303.77 78.475L251.32 48.275C249.97 47.495 248.31 47.495 246.96 48.275L194.51 78.475C194.33 78.575 194.19 78.725 194.03 78.845C193.89 78.955 193.73 79.045 193.6 79.175C193.45 79.325 193.34 79.515 193.21 79.685C193.11 79.815 192.99 79.935 192.91 80.075C192.79 80.285 192.71 80.525 192.63 80.755C192.58 80.875 192.51 80.995 192.48 81.125C192.38 81.495 192.33 81.875 192.33 82.265V139.625L148.62 164.795V52.575C148.62 52.185 148.57 51.805 148.47 51.435C148.44 51.305 148.36 51.195 148.32 51.065C148.23 50.835 148.16 50.595 148.04 50.385C147.96 50.245 147.84 50.125 147.74 49.995C147.61 49.825 147.5 49.635 147.35 49.485C147.22 49.355 147.06 49.265 146.92 49.155C146.76 49.025 146.62 48.885 146.44 48.785L93.99 18.585C92.64 17.805 90.98 17.805 89.63 18.585L37.18 48.785C37 48.885 36.86 49.035 36.7 49.155C36.56 49.265 36.4 49.355 36.27 49.485C36.12 49.635 36.01 49.825 35.88 49.995C35.78 50.125 35.66 50.245 35.58 50.385C35.46 50.595 35.38 50.835 35.3 51.065C35.25 51.185 35.18 51.305 35.15 51.435C35.05 51.805 35 52.185 35 52.575V232.235C35 233.795 35.84 235.245 37.19 236.025L142.1 296.425C142.33 296.555 142.58 296.635 142.82 296.725C142.93 296.765 143.04 296.835 143.16 296.865C143.53 296.965 143.9 297.015 144.28 297.015C144.66 297.015 145.03 296.965 145.4 296.865C145.5 296.835 145.59 296.775 145.69 296.745C145.95 296.655 146.21 296.565 146.45 296.435L251.36 236.035C252.72 235.255 253.55 233.815 253.55 232.245V174.885L303.81 145.945C305.17 145.165 306 143.725 306 142.155V82.265C305.95 81.875 305.89 81.495 305.8 81.125ZM144.2 227.205L100.57 202.515L146.39 176.135L196.66 147.195L240.33 172.335L208.29 190.625L144.2 227.205ZM244.75 114.995V164.795L226.39 154.225L201.03 139.625V89.825L219.39 100.395L244.75 114.995ZM249.12 57.105L292.81 82.265L249.12 107.425L205.43 82.265L249.12 57.105ZM114.49 184.425L96.13 194.995V85.305L121.49 70.705L139.85 60.135V169.815L114.49 184.425ZM91.76 27.425L135.45 52.585L91.76 77.745L48.07 52.585L91.76 27.425ZM43.67 60.135L62.03 70.705L87.39 85.305V202.545V202.555V202.565C87.39 202.735 87.44 202.895 87.46 203.055C87.49 203.265 87.49 203.485 87.55 203.695V203.705C87.6 203.875 87.69 204.035 87.76 204.195C87.84 204.375 87.89 204.575 87.99 204.745C87.99 204.745 87.99 204.755 88 204.755C88.09 204.905 88.22 205.035 88.33 205.175C88.45 205.335 88.55 205.495 88.69 205.635L88.7 205.645C88.82 205.765 88.98 205.855 89.12 205.965C89.28 206.085 89.42 206.225 89.59 206.325C89.6 206.325 89.6 206.325 89.61 206.335C89.62 206.335 89.62 206.345 89.63 206.345L139.87 234.775V285.065L43.67 229.705V60.135ZM244.75 229.705L148.58 285.075V234.775L219.8 194.115L244.75 179.875V229.705ZM297.2 139.625L253.49 164.795V114.995L278.85 100.395L297.21 89.825V139.625H297.2Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,7 @@
|
||||
@props(['status'])
|
||||
|
||||
@if ($status)
|
||||
<div {{ $attributes->merge(['class' => 'font-medium text-sm text-green-600']) }}>
|
||||
{{ $status }}
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,3 @@
|
||||
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 transition ease-in-out duration-150']) }}>
|
||||
{{ $slot }}
|
||||
</button>
|
||||
@@ -0,0 +1 @@
|
||||
<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>
|
||||
@@ -0,0 +1,35 @@
|
||||
@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white'])
|
||||
|
||||
@php
|
||||
$alignmentClasses = match ($align) {
|
||||
'left' => 'ltr:origin-top-left rtl:origin-top-right start-0',
|
||||
'top' => 'origin-top',
|
||||
default => 'ltr:origin-top-right rtl:origin-top-left end-0',
|
||||
};
|
||||
|
||||
$width = match ($width) {
|
||||
'48' => 'w-48',
|
||||
default => $width,
|
||||
};
|
||||
@endphp
|
||||
|
||||
<div class="relative" x-data="{ open: false }" @click.outside="open = false" @close.stop="open = false">
|
||||
<div @click="open = ! open">
|
||||
{{ $trigger }}
|
||||
</div>
|
||||
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
x-transition:leave="transition ease-in duration-75"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
class="absolute z-50 mt-2 {{ $width }} rounded-md shadow-lg {{ $alignmentClasses }}"
|
||||
style="display: none;"
|
||||
@click="open = false">
|
||||
<div class="rounded-md ring-1 ring-black ring-opacity-5 {{ $contentClasses }}">
|
||||
{{ $content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
@props(['messages'])
|
||||
|
||||
@if ($messages)
|
||||
<ul {{ $attributes->merge(['class' => 'text-sm text-red-600 space-y-1']) }}>
|
||||
@foreach ((array) $messages as $message)
|
||||
<li>{{ $message }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
@@ -0,0 +1,5 @@
|
||||
@props(['value'])
|
||||
|
||||
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700']) }}>
|
||||
{{ $value ?? $slot }}
|
||||
</label>
|
||||
@@ -0,0 +1,78 @@
|
||||
@props([
|
||||
'name',
|
||||
'show' => false,
|
||||
'maxWidth' => '2xl'
|
||||
])
|
||||
|
||||
@php
|
||||
$maxWidth = [
|
||||
'sm' => 'sm:max-w-sm',
|
||||
'md' => 'sm:max-w-md',
|
||||
'lg' => 'sm:max-w-lg',
|
||||
'xl' => 'sm:max-w-xl',
|
||||
'2xl' => 'sm:max-w-2xl',
|
||||
][$maxWidth];
|
||||
@endphp
|
||||
|
||||
<div
|
||||
x-data="{
|
||||
show: @js($show),
|
||||
focusables() {
|
||||
// All focusable element types...
|
||||
let selector = 'a, button, input:not([type=\'hidden\']), textarea, select, details, [tabindex]:not([tabindex=\'-1\'])'
|
||||
return [...$el.querySelectorAll(selector)]
|
||||
// All non-disabled elements...
|
||||
.filter(el => ! el.hasAttribute('disabled'))
|
||||
},
|
||||
firstFocusable() { return this.focusables()[0] },
|
||||
lastFocusable() { return this.focusables().slice(-1)[0] },
|
||||
nextFocusable() { return this.focusables()[this.nextFocusableIndex()] || this.firstFocusable() },
|
||||
prevFocusable() { return this.focusables()[this.prevFocusableIndex()] || this.lastFocusable() },
|
||||
nextFocusableIndex() { return (this.focusables().indexOf(document.activeElement) + 1) % (this.focusables().length + 1) },
|
||||
prevFocusableIndex() { return Math.max(0, this.focusables().indexOf(document.activeElement)) -1 },
|
||||
}"
|
||||
x-init="$watch('show', value => {
|
||||
if (value) {
|
||||
document.body.classList.add('overflow-y-hidden');
|
||||
{{ $attributes->has('focusable') ? 'setTimeout(() => firstFocusable().focus(), 100)' : '' }}
|
||||
} else {
|
||||
document.body.classList.remove('overflow-y-hidden');
|
||||
}
|
||||
})"
|
||||
x-on:open-modal.window="$event.detail == '{{ $name }}' ? show = true : null"
|
||||
x-on:close-modal.window="$event.detail == '{{ $name }}' ? show = false : null"
|
||||
x-on:close.stop="show = false"
|
||||
x-on:keydown.escape.window="show = false"
|
||||
x-on:keydown.tab.prevent="$event.shiftKey || nextFocusable().focus()"
|
||||
x-on:keydown.shift.tab.prevent="prevFocusable().focus()"
|
||||
x-show="show"
|
||||
class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50"
|
||||
style="display: {{ $show ? 'block' : 'none' }};"
|
||||
>
|
||||
<div
|
||||
x-show="show"
|
||||
class="fixed inset-0 transform transition-all"
|
||||
x-on:click="show = false"
|
||||
x-transition:enter="ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
>
|
||||
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
x-show="show"
|
||||
class="mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full {{ $maxWidth }} sm:mx-auto"
|
||||
x-transition:enter="ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave="ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
@props(['active'])
|
||||
|
||||
@php
|
||||
$classes = ($active ?? false)
|
||||
? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out'
|
||||
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out';
|
||||
@endphp
|
||||
|
||||
<a {{ $attributes->merge(['class' => $classes]) }}>
|
||||
{{ $slot }}
|
||||
</a>
|
||||
@@ -0,0 +1,3 @@
|
||||
<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150']) }}>
|
||||
{{ $slot }}
|
||||
</button>
|
||||
@@ -0,0 +1,11 @@
|
||||
@props(['active'])
|
||||
|
||||
@php
|
||||
$classes = ($active ?? false)
|
||||
? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
|
||||
: 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out';
|
||||
@endphp
|
||||
|
||||
<a {{ $attributes->merge(['class' => $classes]) }}>
|
||||
{{ $slot }}
|
||||
</a>
|
||||
@@ -0,0 +1,3 @@
|
||||
<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md font-semibold text-xs text-gray-700 uppercase tracking-widest shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 transition ease-in-out duration-150']) }}>
|
||||
{{ $slot }}
|
||||
</button>
|
||||
@@ -0,0 +1,3 @@
|
||||
@props(['disabled' => false])
|
||||
|
||||
<input @disabled($disabled) {{ $attributes->merge(['class' => 'border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 rounded-md shadow-sm']) }}>
|
||||
@@ -0,0 +1,17 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('Dashboard') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 text-gray-900">
|
||||
{{ __("You're logged in!") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@@ -0,0 +1,159 @@
|
||||
@extends('layouts.game')
|
||||
|
||||
@section('title', 'Create Character')
|
||||
|
||||
@section('game-content')
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg p-8">
|
||||
<h1 class="text-2xl font-bold text-gray-800 dark:text-gray-200 mb-6">
|
||||
Create Your Character
|
||||
</h1>
|
||||
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-8">
|
||||
Welcome to {{ config('game.name', 'The Crime Syndicate') }}!
|
||||
Create your character to start your criminal career.
|
||||
</p>
|
||||
|
||||
<form method="POST" action="{{ route('game.character.store') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Name -->
|
||||
<div class="mb-6">
|
||||
<label for="name" class="block font-medium text-sm text-gray-700 dark:text-gray-300 mb-2">
|
||||
Character Name
|
||||
</label>
|
||||
<input
|
||||
id="name"
|
||||
type="text"
|
||||
name="name"
|
||||
value="{{ old('name') }}"
|
||||
required
|
||||
autofocus
|
||||
autocomplete="name"
|
||||
class="w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 rounded-md shadow-sm @error('name') border-red-500 @enderror"
|
||||
placeholder="Enter your character name"
|
||||
maxlength="50"
|
||||
>
|
||||
@error('name')
|
||||
<p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
Choose a unique name for your character (max 50 characters).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Gender -->
|
||||
<div class="mb-6">
|
||||
<label class="block font-medium text-sm text-gray-700 dark:text-gray-300 mb-2">
|
||||
Gender
|
||||
</label>
|
||||
<div class="space-y-2">
|
||||
@foreach($genders as $gender)
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
id="gender-{{ $gender }}"
|
||||
type="radio"
|
||||
name="gender"
|
||||
value="{{ $gender }}"
|
||||
{{ old('gender') === $gender ? 'checked' : ($loop->first ? 'checked' : '') }}
|
||||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 dark:border-gray-600"
|
||||
>
|
||||
<label
|
||||
for="gender-{{ $gender }}"
|
||||
class="ml-2 block text-sm text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
{{ ucfirst($gender) }}
|
||||
</label>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@error('gender')
|
||||
<p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Location -->
|
||||
<div class="mb-6">
|
||||
<label for="location_id" class="block font-medium text-sm text-gray-700 dark:text-gray-300 mb-2">
|
||||
Starting Location
|
||||
</label>
|
||||
<select
|
||||
id="location_id"
|
||||
name="location_id"
|
||||
required
|
||||
class="w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 rounded-md shadow-sm @error('location_id') border-red-500 @enderror"
|
||||
>
|
||||
@foreach($locations as $location)
|
||||
<option
|
||||
value="{{ $location->id }}"
|
||||
{{ old('location_id') == $location->id ? 'selected' : ($loop->first ? 'selected' : '') }}
|
||||
>
|
||||
{{ $location->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('location_id')
|
||||
<p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
||||
@enderror
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
Choose where your character will start their journey.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Starting Stats Preview -->
|
||||
<div class="mb-6 bg-gray-50 dark:bg-gray-700 p-4 rounded-lg">
|
||||
<h3 class="font-medium text-sm text-gray-700 dark:text-gray-300 mb-3">
|
||||
Starting Stats
|
||||
</h3>
|
||||
<div class="grid grid-cols-2 gap-3 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Health</span>
|
||||
<span>{{ config('game.health.start_amount', 100) }}/{{ config('game.health.max', 100) }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Energy</span>
|
||||
<span>{{ config('game.energy.start_amount', 100) }}/{{ config('game.energy.max', 100) }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Money</span>
|
||||
<span>${{ number_format(config('game.economy.start_money', 5000)) }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Bank</span>
|
||||
<span>${{ number_format(config('game.economy.start_bank', 0)) }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Strength</span>
|
||||
<span>5</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Defense</span>
|
||||
<span>5</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Speed</span>
|
||||
<span>5</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Dexterity</span>
|
||||
<span>5</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="flex justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
class="inline-flex items-center px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition"
|
||||
>
|
||||
Create Character
|
||||
<svg class="ml-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 12h14" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,139 @@
|
||||
@extends('layouts.game')
|
||||
|
||||
@section('title', 'Crimes')
|
||||
|
||||
@section('game-content')
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Available Crimes</h1>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Energy: {{ $character->energy }}/{{ $character->max_energy }}
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
|
||||
Commit crimes to earn money and experience. Each crime costs energy and has a chance of success or failure.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-6">
|
||||
@if($availableCrimes->isEmpty())
|
||||
<p class="text-center text-gray-500 dark:text-gray-400 py-8">
|
||||
No crimes available. Try leveling up or restoring your energy.
|
||||
</p>
|
||||
@else
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
@foreach($availableCrimes as $crime)
|
||||
@php
|
||||
$onCooldown = $crimeService->isOnCooldown($character, $crime);
|
||||
$cooldownRemaining = $onCooldown ? $crimeService->getCooldownRemaining($character, $crime) : 0;
|
||||
$successRate = $crime->calculateSuccessRate($character);
|
||||
@endphp
|
||||
|
||||
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4 border border-gray-200 dark:border-gray-600">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<div>
|
||||
<h3 class="font-medium text-gray-800 dark:text-gray-200">{{ $crime->name }}</h3>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
{{ $crime->difficulty_label }} Difficulty
|
||||
</p>
|
||||
</div>
|
||||
<span class="text-xs px-2 py-1 rounded-full {{ $crime->difficulty_color }} text-white">
|
||||
{{ number_format($successRate * 100, 1) }}% Success
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
|
||||
{{ Str::limit($crime->description, 100) }}
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2 text-xs">
|
||||
<div class="flex items-center">
|
||||
<span class="text-yellow-500 mr-1">⚡</span>
|
||||
<span>{{ $crime->energy_cost }} Energy</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="text-green-500 mr-1">💰</span>
|
||||
<span>${{ $crime->reward_min }}-{{ $crime->reward_max }}</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="text-blue-500 mr-1">📈</span>
|
||||
<span>{{ $crime->experience }} EXP</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="text-gray-500 mr-1">⏱️</span>
|
||||
<span>{{ $crime->cooldown }}s Cooldown</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($onCooldown)
|
||||
<button
|
||||
disabled
|
||||
class="w-full mt-3 py-2 px-4 text-sm text-center bg-gray-300 dark:bg-gray-600 text-gray-500 dark:text-gray-400 rounded-lg cursor-not-allowed"
|
||||
>
|
||||
On Cooldown ({{ ceil($cooldownRemaining / 60) }}m)
|
||||
</button>
|
||||
@else
|
||||
<form action="{{ route('game.crimes.attempt', $crime) }}" method="POST" class="mt-3">
|
||||
@csrf
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full py-2 px-4 text-sm text-center bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition"
|
||||
>
|
||||
Attempt Crime
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
@if($crime->requires_level)
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
Requires Level {{ $crime->requires_level }}+
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="p-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-3">Recent Attempts</h3>
|
||||
|
||||
@if($recentAttempts->isEmpty())
|
||||
<p class="text-center text-gray-500 dark:text-gray-400 py-4">
|
||||
No recent crime attempts.
|
||||
</p>
|
||||
@else
|
||||
<div class="space-y-2">
|
||||
@foreach($recentAttempts as $attempt)
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
||||
<div class="flex items-center">
|
||||
<span class="mr-3">
|
||||
@if($attempt->success)
|
||||
<span class="text-green-500">✅</span>
|
||||
@else
|
||||
<span class="text-red-500">❌</span>
|
||||
@endif
|
||||
</span>
|
||||
<div>
|
||||
<p class="font-medium text-gray-800 dark:text-gray-200">{{ $attempt->crime->name }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ $attempt->attempted_at->diffForHumans() }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
@if($attempt->success)
|
||||
<p class="text-sm text-green-600 dark:text-green-400">+${{ number_format($attempt->reward) }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">+{{ $attempt->experience_gained }} EXP</p>
|
||||
@else
|
||||
<p class="text-sm text-red-600 dark:text-red-400">Failed</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,195 @@
|
||||
@extends('layouts.game')
|
||||
|
||||
@section('title', 'Dashboard')
|
||||
|
||||
@section('game-content')
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<!-- Welcome Card -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg p-6">
|
||||
<h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200 mb-4">
|
||||
Welcome, {{ $character->name }}!
|
||||
</h2>
|
||||
<p class="text-gray-600 dark:text-gray-400">
|
||||
You are in <strong>{{ $character->location->name ?? 'Unknown Location' }}</strong>.
|
||||
</p>
|
||||
<p class="text-gray-600 dark:text-gray-400 mt-2">
|
||||
Level: {{ $character->level }} ({{ number_format($character->experience) }} / {{ number_format($character->experience_for_next_level) }} EXP)
|
||||
</p>
|
||||
<div class="w-full bg-gray-200 rounded-full h-2 mt-3">
|
||||
<div
|
||||
class="bg-blue-600 h-2 rounded-full"
|
||||
style="width: {{ $character->experience_progress }}%"
|
||||
></div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-1">EXP Progress: {{ number_format($character->experience_progress, 1) }}%</p>
|
||||
</div>
|
||||
|
||||
<!-- Quick Stats -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Quick Stats</h3>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Strength</span>
|
||||
<span class="font-medium">{{ $character->strength }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Defense</span>
|
||||
<span class="font-medium">{{ $character->defense }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Speed</span>
|
||||
<span class="font-medium">{{ $character->speed }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Dexterity</span>
|
||||
<span class="font-medium">{{ $character->dexterity }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between pt-2 border-t border-gray-200 dark:border-gray-700">
|
||||
<span class="text-gray-600 dark:text-gray-400">Attack Power</span>
|
||||
<span class="font-medium text-green-600 dark:text-green-400">{{ $character->attack_power }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-400">Defense</span>
|
||||
<span class="font-medium text-blue-600 dark:text-blue-400">{{ $character->defense }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Money & Bank -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Finances</h3>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<span class="text-green-500 mr-2">💰</span>
|
||||
<span class="text-gray-600 dark:text-gray-400">Cash</span>
|
||||
</div>
|
||||
<span class="font-medium">${{ number_format($character->money) }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<span class="text-blue-500 mr-2">🏦</span>
|
||||
<span class="text-gray-600 dark:text-gray-400">Bank</span>
|
||||
</div>
|
||||
<span class="font-medium">${{ number_format($character->bank) }}</span>
|
||||
</div>
|
||||
<div class="pt-2 border-t border-gray-200 dark:border-gray-700 space-y-2">
|
||||
<a
|
||||
href="#"
|
||||
onclick="event.preventDefault(); document.getElementById('deposit-form').submit();"
|
||||
class="block w-full text-center bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded text-sm transition"
|
||||
>
|
||||
Deposit to Bank
|
||||
</a>
|
||||
<form id="deposit-form" action="{{ route('game.character.deposit') }}" method="POST" class="hidden">
|
||||
@csrf
|
||||
<input type="number" name="amount" value="1000" min="1" max="{{ $character->money }}">
|
||||
</form>
|
||||
|
||||
<a
|
||||
href="#"
|
||||
onclick="event.preventDefault(); document.getElementById('withdraw-form').submit();"
|
||||
class="block w-full text-center bg-gray-600 hover:bg-gray-700 text-white py-2 px-4 rounded text-sm transition"
|
||||
>
|
||||
Withdraw from Bank
|
||||
</a>
|
||||
<form id="withdraw-form" action="{{ route('game.character.withdraw') }}" method="POST" class="hidden">
|
||||
@csrf
|
||||
<input type="number" name="amount" value="1000" min="1" max="{{ $character->bank }}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg p-6 lg:col-span-2">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Quick Actions</h3>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
<a
|
||||
href="{{ route('game.crimes.index') }}"
|
||||
class="flex flex-col items-center justify-center bg-blue-500 hover:bg-blue-600 text-white py-4 px-2 rounded-lg transition group"
|
||||
>
|
||||
<span class="text-2xl mb-1">🎯</span>
|
||||
<span class="text-sm font-medium">Crimes</span>
|
||||
<span class="text-xs opacity-75">Commit crimes</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="{{ route('game.inventory.index') }}"
|
||||
class="flex flex-col items-center justify-center bg-green-500 hover:bg-green-600 text-white py-4 px-2 rounded-lg transition group"
|
||||
>
|
||||
<span class="text-2xl mb-1">🎒</span>
|
||||
<span class="text-sm font-medium">Inventory</span>
|
||||
<span class="text-xs opacity-75">Manage items</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="{{ route('game.character.show') }}"
|
||||
class="flex flex-col items-center justify-center bg-purple-500 hover:bg-purple-600 text-white py-4 px-2 rounded-lg transition group"
|
||||
>
|
||||
<span class="text-2xl mb-1">👤</span>
|
||||
<span class="text-sm font-medium">Profile</span>
|
||||
<span class="text-xs opacity-75">View profile</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="{{ route('profile.edit') }}"
|
||||
class="flex flex-col items-center justify-center bg-gray-500 hover:bg-gray-600 text-white py-4 px-2 rounded-lg transition group"
|
||||
>
|
||||
<span class="text-2xl mb-1">⚙️</span>
|
||||
<span class="text-sm font-medium">Settings</span>
|
||||
<span class="text-xs opacity-75">Account settings</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg p-6 lg:col-span-3">
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Recent Activity</h3>
|
||||
|
||||
@if($recentActivity->isEmpty())
|
||||
<p class="text-gray-500 dark:text-gray-400 text-center py-4">No recent activity.</p>
|
||||
@else
|
||||
<div class="space-y-3">
|
||||
@foreach($recentActivity as $activity)
|
||||
<div class="flex items-start space-x-3 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
||||
<span class="text-gray-400 dark:text-gray-500">
|
||||
@switch($activity->action)
|
||||
@case('crime_attempt')
|
||||
@if(str_contains($activity->description, 'success'))
|
||||
✅
|
||||
@else
|
||||
❌
|
||||
@endif
|
||||
@break
|
||||
@case('money_earned')
|
||||
💰
|
||||
@break
|
||||
@case('money_spent')
|
||||
💸
|
||||
@break
|
||||
@case('character_created')
|
||||
🎉
|
||||
@break
|
||||
@default
|
||||
📝
|
||||
@endswitch
|
||||
</span>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
{{ ucfirst(str_replace('_', ' ', $activity->action)) }}
|
||||
</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ $activity->description }}
|
||||
</p>
|
||||
<p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
|
||||
{{ $activity->created_at->diffForHumans() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,72 @@
|
||||
@extends('layouts.game')
|
||||
|
||||
@section('title', 'Hospital')
|
||||
|
||||
@section('game-content')
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-8 text-center">
|
||||
<div class="mb-6">
|
||||
<span class="text-6xl text-red-500">🏥</span>
|
||||
</div>
|
||||
|
||||
<h1 class="text-2xl font-bold text-gray-800 dark:text-gray-200 mb-4">
|
||||
You're in the Hospital
|
||||
</h1>
|
||||
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-6">
|
||||
Your character has been injured and is currently recovering in the hospital.
|
||||
</p>
|
||||
|
||||
<div class="bg-red-50 dark:bg-red-900/30 rounded-lg p-6 mb-6">
|
||||
<h3 class="text-lg font-medium text-red-800 dark:text-red-200 mb-3">
|
||||
Your Status
|
||||
</h3>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600 dark:text-gray-400">Health</span>
|
||||
<span class="font-medium">{{ $character->health }}/{{ $character->max_health }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600 dark:text-gray-400">Status</span>
|
||||
<span class="font-medium text-red-600 dark:text-red-400">
|
||||
@if($character->health <= 0) Dead @else In Hospital @endif
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600 dark:text-gray-400">Release Time</span>
|
||||
<span class="font-medium">{{ $releaseTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<form action="{{ route('game.character.revive') }}" method="POST">
|
||||
@csrf
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full flex items-center justify-center px-6 py-4 bg-green-500 hover:bg-green-600 text-white font-medium rounded-lg transition"
|
||||
>
|
||||
<span class="mr-2">💵</span>
|
||||
Revive Now for ${{ number_format($reviveCost) }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Or wait to be automatically released when your health regenerates.
|
||||
</p>
|
||||
|
||||
<a
|
||||
href="{{ route('game.dashboard') }}"
|
||||
class="inline-flex items-center text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 transition"
|
||||
>
|
||||
<svg class="w-5 h-5 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,133 @@
|
||||
@extends('layouts.game')
|
||||
|
||||
@section('title', 'Inventory')
|
||||
|
||||
@section('game-content')
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
|
||||
<h1 class="text-xl font-semibold text-gray-800 dark:text-gray-200">Inventory</h1>
|
||||
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
|
||||
Manage your items. Equip weapons and armor, or use consumables.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-6">
|
||||
@if($inventory->isEmpty())
|
||||
<p class="text-center text-gray-500 dark:text-gray-400 py-8">
|
||||
Your inventory is empty.
|
||||
</p>
|
||||
@else
|
||||
<div class="space-y-4">
|
||||
@foreach($inventory->groupBy('item.type') as $type => $items)
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-gray-800 dark:text-gray-200 capitalizes mb-3">
|
||||
{{ ucfirst($type) }}s ({{ $items->sum('quantity') }})
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
@foreach($items as $item)
|
||||
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4 border border-gray-200 dark:border-gray-600">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<div>
|
||||
<h4 class="font-medium text-gray-800 dark:text-gray-200">{{ $item->item->name }}</h4>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
x{{ $item->quantity }}
|
||||
</p>
|
||||
</div>
|
||||
@if($item->equipped)
|
||||
<span class="text-xs px-2 py-1 bg-green-500 text-white rounded-full">Equipped</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if($item->item->description)
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">
|
||||
{{ Str::limit($item->item->description, 80) }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<div class="grid grid-cols-2 gap-2 text-xs mb-3">
|
||||
@if($item->item->attack_bonus > 0)
|
||||
<div class="flex items-center">
|
||||
<span class="text-red-500 mr-1">⚔️</span>
|
||||
<span>+{{ $item->item->attack_bonus }} Attack</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($item->item->defense_bonus > 0)
|
||||
<div class="flex items-center">
|
||||
<span class="text-blue-500 mr-1">🛡️</span>
|
||||
<span>+{{ $item->item->defense_bonus }} Defense</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($item->item->health_bonus > 0)
|
||||
<div class="flex items-center">
|
||||
<span class="text-green-500 mr-1">❤️</span>
|
||||
<span>+{{ $item->item->health_bonus }} Health</span>
|
||||
</div>
|
||||
@endif
|
||||
@if($item->item->energy_bonus > 0)
|
||||
<div class="flex items-center">
|
||||
<span class="text-yellow-500 mr-1">⚡</span>
|
||||
<span>+{{ $item->item->energy_bonus }} Energy</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-2">
|
||||
@if($item->item->canEquip())
|
||||
@if($item->equipped)
|
||||
<form action="{{ route('game.inventory.unequip', $item) }}" method="POST">
|
||||
@csrf
|
||||
<button
|
||||
type="submit"
|
||||
class="px-3 py-1 text-xs bg-gray-400 hover:bg-gray-500 text-white rounded transition"
|
||||
>
|
||||
Unequip
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<form action="{{ route('game.inventory.equip', $item) }}" method="POST">
|
||||
@csrf
|
||||
<button
|
||||
type="submit"
|
||||
class="px-3 py-1 text-xs bg-blue-500 hover:bg-blue-600 text-white rounded transition"
|
||||
>
|
||||
Equip
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if($item->item->canUse())
|
||||
<form action="{{ route('game.inventory.use', $item) }}" method="POST">
|
||||
@csrf
|
||||
<button
|
||||
type="submit"
|
||||
class="px-3 py-1 text-xs bg-green-500 hover:bg-green-600 text-white rounded transition"
|
||||
>
|
||||
Use
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('game.inventory.drop', $item) }}" method="POST">
|
||||
@csrf
|
||||
<input type="number" name="quantity" value="1" min="1" max="{{ $item->quantity }}" class="hidden">
|
||||
<button
|
||||
type="submit"
|
||||
class="px-3 py-1 text-xs bg-red-500 hover:bg-red-600 text-white rounded transition"
|
||||
>
|
||||
Drop
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,55 @@
|
||||
@extends('layouts.game')
|
||||
|
||||
@section('title', 'Jail')
|
||||
|
||||
@section('game-content')
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-8 text-center">
|
||||
<div class="mb-6">
|
||||
<span class="text-6xl text-yellow-500">🚔</span>
|
||||
</div>
|
||||
|
||||
<h1 class="text-2xl font-bold text-gray-800 dark:text-gray-200 mb-4">
|
||||
You're in Jail
|
||||
</h1>
|
||||
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-6">
|
||||
Your character has been arrested and is currently serving time in jail.
|
||||
</p>
|
||||
|
||||
<div class="bg-yellow-50 dark:bg-yellow-900/30 rounded-lg p-6 mb-6">
|
||||
<h3 class="text-lg font-medium text-yellow-800 dark:text-yellow-200 mb-3">
|
||||
Your Status
|
||||
</h3>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600 dark:text-gray-400">Status</span>
|
||||
<span class="font-medium text-yellow-600 dark:text-yellow-400">In Jail</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-gray-600 dark:text-gray-400">Release Time</span>
|
||||
<span class="font-medium">{{ $releaseTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
You must wait for your sentence to complete. There is no way to reduce your jail time.
|
||||
</p>
|
||||
|
||||
<a
|
||||
href="{{ route('game.dashboard') }}"
|
||||
class="inline-flex items-center text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 transition"
|
||||
>
|
||||
<svg class="w-5 h-5 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,48 @@
|
||||
@php
|
||||
$character = auth()->user()->character;
|
||||
@endphp
|
||||
|
||||
<div class="flex items-center space-x-4 text-sm">
|
||||
<!-- Energy Bar -->
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="text-yellow-400">⚡</span>
|
||||
<div class="w-20 bg-gray-600 rounded-full h-2">
|
||||
<div
|
||||
class="bg-yellow-400 h-2 rounded-full transition-all duration-300"
|
||||
style="width: {{ $character->energy_percentage }}%"
|
||||
></div>
|
||||
</div>
|
||||
<span>{{ $character->energy }}/{{ $character->max_energy }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Health Bar -->
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="text-red-400">❤️</span>
|
||||
<div class="w-20 bg-gray-600 rounded-full h-2">
|
||||
<div
|
||||
class="bg-red-400 h-2 rounded-full transition-all duration-300"
|
||||
style="width: {{ $character->health_percentage }}%"
|
||||
></div>
|
||||
</div>
|
||||
<span>{{ $character->health }}/{{ $character->max_health }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Money -->
|
||||
<div class="flex items-center space-x-1">
|
||||
<span class="text-green-400">💰</span>
|
||||
<span>${{ number_format($character->money) }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Level -->
|
||||
<div class="flex items-center space-x-1">
|
||||
<span class="text-blue-400">📈</span>
|
||||
<span>Lv. {{ $character->level }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Status -->
|
||||
@if($character->status !== 'active')
|
||||
<span class="px-2 py-1 text-xs rounded {{ $character->status === 'in_hospital' ? 'bg-red-500' : 'bg-yellow-500' }}">
|
||||
{{ ucfirst(str_replace('_', ' ', $character->status)) }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
<body class="font-sans antialiased">
|
||||
<div class="min-h-screen bg-gray-100">
|
||||
@include('layouts.navigation')
|
||||
|
||||
<!-- Page Heading -->
|
||||
@isset($header)
|
||||
<header class="bg-white shadow">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
{{ $header }}
|
||||
</div>
|
||||
</header>
|
||||
@endisset
|
||||
|
||||
<!-- Page Content -->
|
||||
<main>
|
||||
{{ $slot }}
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,62 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', config('game.name', 'The Crime Syndicate') . ' - ' . ($title ?? 'Game'))
|
||||
|
||||
@section('content')
|
||||
<!-- Game Header -->
|
||||
<header class="bg-gray-800 text-white shadow">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-16">
|
||||
<!-- Logo -->
|
||||
<div class="flex-shrink-0 flex items-center">
|
||||
<a href="{{ route('game.dashboard') }}" class="text-xl font-bold">
|
||||
{{ config('game.name', 'The Crime Syndicate') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Character Stats -->
|
||||
<div class="flex items-center space-x-4">
|
||||
@if(auth()->check() && auth()->user()->character)
|
||||
@include('game.partials.stats-bar')
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- User Menu -->
|
||||
<div class="flex items-center">
|
||||
@include('layouts.navigation')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Flash Messages -->
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
@if(session('success'))
|
||||
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4" role="alert">
|
||||
<strong class="font-bold">Success!</strong>
|
||||
<span class="block sm:inline">{{ session('success') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4" role="alert">
|
||||
<strong class="font-bold">Error!</strong>
|
||||
<span class="block sm:inline">{{ session('error') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
@yield('game-content')
|
||||
</main>
|
||||
|
||||
<!-- Game Footer -->
|
||||
<footer class="bg-gray-800 text-white mt-auto">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<div class="text-center text-sm text-gray-400">
|
||||
© {{ date('Y') }} {{ config('game.name', 'The Crime Syndicate') }} - v{{ config('game.version', '1.0.0') }}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@endsection
|
||||
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
<body class="font-sans text-gray-900 antialiased">
|
||||
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
|
||||
<div>
|
||||
<a href="/">
|
||||
<x-application-logo class="w-20 h-20 fill-current text-gray-500" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,100 @@
|
||||
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
|
||||
<!-- Primary Navigation Menu -->
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between h-16">
|
||||
<div class="flex">
|
||||
<!-- Logo -->
|
||||
<div class="shrink-0 flex items-center">
|
||||
<a href="{{ route('dashboard') }}">
|
||||
<x-application-logo class="block h-9 w-auto fill-current text-gray-800" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Links -->
|
||||
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
|
||||
{{ __('Dashboard') }}
|
||||
</x-nav-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Dropdown -->
|
||||
<div class="hidden sm:flex sm:items-center sm:ms-6">
|
||||
<x-dropdown align="right" width="48">
|
||||
<x-slot name="trigger">
|
||||
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
|
||||
<div>{{ Auth::user()->name }}</div>
|
||||
|
||||
<div class="ms-1">
|
||||
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<x-dropdown-link :href="route('profile.edit')">
|
||||
{{ __('Profile') }}
|
||||
</x-dropdown-link>
|
||||
|
||||
<!-- Authentication -->
|
||||
<form method="POST" action="{{ route('logout') }}">
|
||||
@csrf
|
||||
|
||||
<x-dropdown-link :href="route('logout')"
|
||||
onclick="event.preventDefault();
|
||||
this.closest('form').submit();">
|
||||
{{ __('Log Out') }}
|
||||
</x-dropdown-link>
|
||||
</form>
|
||||
</x-slot>
|
||||
</x-dropdown>
|
||||
</div>
|
||||
|
||||
<!-- Hamburger -->
|
||||
<div class="-me-2 flex items-center sm:hidden">
|
||||
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
|
||||
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Navigation Menu -->
|
||||
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
|
||||
<div class="pt-2 pb-3 space-y-1">
|
||||
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
|
||||
{{ __('Dashboard') }}
|
||||
</x-responsive-nav-link>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Settings Options -->
|
||||
<div class="pt-4 pb-1 border-t border-gray-200">
|
||||
<div class="px-4">
|
||||
<div class="font-medium text-base text-gray-800">{{ Auth::user()->name }}</div>
|
||||
<div class="font-medium text-sm text-gray-500">{{ Auth::user()->email }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 space-y-1">
|
||||
<x-responsive-nav-link :href="route('profile.edit')">
|
||||
{{ __('Profile') }}
|
||||
</x-responsive-nav-link>
|
||||
|
||||
<!-- Authentication -->
|
||||
<form method="POST" action="{{ route('logout') }}">
|
||||
@csrf
|
||||
|
||||
<x-responsive-nav-link :href="route('logout')"
|
||||
onclick="event.preventDefault();
|
||||
this.closest('form').submit();">
|
||||
{{ __('Log Out') }}
|
||||
</x-responsive-nav-link>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,29 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('Profile') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
@include('profile.partials.update-profile-information-form')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
@include('profile.partials.update-password-form')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 sm:p-8 bg-white shadow sm:rounded-lg">
|
||||
<div class="max-w-xl">
|
||||
@include('profile.partials.delete-user-form')
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@@ -0,0 +1,55 @@
|
||||
<section class="space-y-6">
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900">
|
||||
{{ __('Delete Account') }}
|
||||
</h2>
|
||||
|
||||
<p class="mt-1 text-sm text-gray-600">
|
||||
{{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<x-danger-button
|
||||
x-data=""
|
||||
x-on:click.prevent="$dispatch('open-modal', 'confirm-user-deletion')"
|
||||
>{{ __('Delete Account') }}</x-danger-button>
|
||||
|
||||
<x-modal name="confirm-user-deletion" :show="$errors->userDeletion->isNotEmpty()" focusable>
|
||||
<form method="post" action="{{ route('profile.destroy') }}" class="p-6">
|
||||
@csrf
|
||||
@method('delete')
|
||||
|
||||
<h2 class="text-lg font-medium text-gray-900">
|
||||
{{ __('Are you sure you want to delete your account?') }}
|
||||
</h2>
|
||||
|
||||
<p class="mt-1 text-sm text-gray-600">
|
||||
{{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }}
|
||||
</p>
|
||||
|
||||
<div class="mt-6">
|
||||
<x-input-label for="password" value="{{ __('Password') }}" class="sr-only" />
|
||||
|
||||
<x-text-input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
class="mt-1 block w-3/4"
|
||||
placeholder="{{ __('Password') }}"
|
||||
/>
|
||||
|
||||
<x-input-error :messages="$errors->userDeletion->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-end">
|
||||
<x-secondary-button x-on:click="$dispatch('close')">
|
||||
{{ __('Cancel') }}
|
||||
</x-secondary-button>
|
||||
|
||||
<x-danger-button class="ms-3">
|
||||
{{ __('Delete Account') }}
|
||||
</x-danger-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-modal>
|
||||
</section>
|
||||
@@ -0,0 +1,48 @@
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900">
|
||||
{{ __('Update Password') }}
|
||||
</h2>
|
||||
|
||||
<p class="mt-1 text-sm text-gray-600">
|
||||
{{ __('Ensure your account is using a long, random password to stay secure.') }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form method="post" action="{{ route('password.update') }}" class="mt-6 space-y-6">
|
||||
@csrf
|
||||
@method('put')
|
||||
|
||||
<div>
|
||||
<x-input-label for="update_password_current_password" :value="__('Current Password')" />
|
||||
<x-text-input id="update_password_current_password" name="current_password" type="password" class="mt-1 block w-full" autocomplete="current-password" />
|
||||
<x-input-error :messages="$errors->updatePassword->get('current_password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="update_password_password" :value="__('New Password')" />
|
||||
<x-text-input id="update_password_password" name="password" type="password" class="mt-1 block w-full" autocomplete="new-password" />
|
||||
<x-input-error :messages="$errors->updatePassword->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="update_password_password_confirmation" :value="__('Confirm Password')" />
|
||||
<x-text-input id="update_password_password_confirmation" name="password_confirmation" type="password" class="mt-1 block w-full" autocomplete="new-password" />
|
||||
<x-input-error :messages="$errors->updatePassword->get('password_confirmation')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<x-primary-button>{{ __('Save') }}</x-primary-button>
|
||||
|
||||
@if (session('status') === 'password-updated')
|
||||
<p
|
||||
x-data="{ show: true }"
|
||||
x-show="show"
|
||||
x-transition
|
||||
x-init="setTimeout(() => show = false, 2000)"
|
||||
class="text-sm text-gray-600"
|
||||
>{{ __('Saved.') }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
@@ -0,0 +1,64 @@
|
||||
<section>
|
||||
<header>
|
||||
<h2 class="text-lg font-medium text-gray-900">
|
||||
{{ __('Profile Information') }}
|
||||
</h2>
|
||||
|
||||
<p class="mt-1 text-sm text-gray-600">
|
||||
{{ __("Update your account's profile information and email address.") }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form id="send-verification" method="post" action="{{ route('verification.send') }}">
|
||||
@csrf
|
||||
</form>
|
||||
|
||||
<form method="post" action="{{ route('profile.update') }}" class="mt-6 space-y-6">
|
||||
@csrf
|
||||
@method('patch')
|
||||
|
||||
<div>
|
||||
<x-input-label for="name" :value="__('Name')" />
|
||||
<x-text-input id="name" name="name" type="text" class="mt-1 block w-full" :value="old('name', $user->name)" required autofocus autocomplete="name" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('name')" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" name="email" type="email" class="mt-1 block w-full" :value="old('email', $user->email)" required autocomplete="username" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('email')" />
|
||||
|
||||
@if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail())
|
||||
<div>
|
||||
<p class="text-sm mt-2 text-gray-800">
|
||||
{{ __('Your email address is unverified.') }}
|
||||
|
||||
<button form="send-verification" class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
{{ __('Click here to re-send the verification email.') }}
|
||||
</button>
|
||||
</p>
|
||||
|
||||
@if (session('status') === 'verification-link-sent')
|
||||
<p class="mt-2 font-medium text-sm text-green-600">
|
||||
{{ __('A new verification link has been sent to your email address.') }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<x-primary-button>{{ __('Save') }}</x-primary-button>
|
||||
|
||||
@if (session('status') === 'profile-updated')
|
||||
<p
|
||||
x-data="{ show: true }"
|
||||
x-show="show"
|
||||
x-transition
|
||||
x-init="setTimeout(() => show = false, 2000)"
|
||||
class="text-sm text-gray-600"
|
||||
>{{ __('Saved.') }}</p>
|
||||
@endif
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user