diff --git a/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/app/Http/Controllers/Auth/AuthenticatedSessionController.php new file mode 100644 index 0000000..765dec6 --- /dev/null +++ b/app/Http/Controllers/Auth/AuthenticatedSessionController.php @@ -0,0 +1,47 @@ +authenticate(); + + $request->session()->regenerate(); + + return redirect()->intended(route('home.index', absolute: false)); + } + + /** + * Destroy an authenticated session. + */ + public function destroy(Request $request): RedirectResponse + { + Auth::guard('web')->logout(); + + $request->session()->invalidate(); + + $request->session()->regenerateToken(); + + return redirect('/'); + } +} diff --git a/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/app/Http/Controllers/Auth/ConfirmablePasswordController.php new file mode 100644 index 0000000..af1d849 --- /dev/null +++ b/app/Http/Controllers/Auth/ConfirmablePasswordController.php @@ -0,0 +1,40 @@ +validate([ + 'email' => $request->user()->email, + 'password' => $request->password, + ])) { + throw ValidationException::withMessages([ + 'password' => __('auth.password'), + ]); + } + + $request->session()->put('auth.password_confirmed_at', time()); + + return redirect()->intended(route('home.index', absolute: false)); + } +} diff --git a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php new file mode 100644 index 0000000..364650a --- /dev/null +++ b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php @@ -0,0 +1,24 @@ +user()->hasVerifiedEmail()) { + return redirect()->intended(route('home.index', absolute: false)); + } + + $request->user()->sendEmailVerificationNotification(); + + return back()->with('status', 'verification-link-sent'); + } +} diff --git a/app/Http/Controllers/Auth/EmailVerificationPromptController.php b/app/Http/Controllers/Auth/EmailVerificationPromptController.php new file mode 100644 index 0000000..9d543c2 --- /dev/null +++ b/app/Http/Controllers/Auth/EmailVerificationPromptController.php @@ -0,0 +1,21 @@ +user()->hasVerifiedEmail() + ? redirect()->intended(route('home.index', absolute: false)) + : view('auth.verify-email'); + } +} diff --git a/app/Http/Controllers/Auth/NewPasswordController.php b/app/Http/Controllers/Auth/NewPasswordController.php new file mode 100644 index 0000000..e8368bd --- /dev/null +++ b/app/Http/Controllers/Auth/NewPasswordController.php @@ -0,0 +1,62 @@ + $request]); + } + + /** + * Handle an incoming new password request. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function store(Request $request): RedirectResponse + { + $request->validate([ + 'token' => ['required'], + 'email' => ['required', 'email'], + 'password' => ['required', 'confirmed', Rules\Password::defaults()], + ]); + + // Here we will attempt to reset the user's password. If it is successful we + // will update the password on an actual user model and persist it to the + // database. Otherwise we will parse the error and return the response. + $status = Password::reset( + $request->only('email', 'password', 'password_confirmation', 'token'), + function (User $user) use ($request) { + $user->forceFill([ + 'password' => Hash::make($request->password), + 'remember_token' => Str::random(60), + ])->save(); + + event(new PasswordReset($user)); + } + ); + + // If the password was successfully reset, we will redirect the user back to + // the application's home authenticated view. If there is an error we can + // redirect them back to where they came from with their error message. + return $status == Password::PASSWORD_RESET + ? redirect()->route('login')->with('status', __($status)) + : back()->withInput($request->only('email')) + ->withErrors(['email' => __($status)]); + } +} diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php new file mode 100644 index 0000000..6916409 --- /dev/null +++ b/app/Http/Controllers/Auth/PasswordController.php @@ -0,0 +1,29 @@ +validateWithBag('updatePassword', [ + 'current_password' => ['required', 'current_password'], + 'password' => ['required', Password::defaults(), 'confirmed'], + ]); + + $request->user()->update([ + 'password' => Hash::make($validated['password']), + ]); + + return back()->with('status', 'password-updated'); + } +} diff --git a/app/Http/Controllers/Auth/PasswordResetLinkController.php b/app/Http/Controllers/Auth/PasswordResetLinkController.php new file mode 100644 index 0000000..bf1ebfa --- /dev/null +++ b/app/Http/Controllers/Auth/PasswordResetLinkController.php @@ -0,0 +1,44 @@ +validate([ + 'email' => ['required', 'email'], + ]); + + // We will send the password reset link to this user. Once we have attempted + // to send the link, we will examine the response then see the message we + // need to show to the user. Finally, we'll send out a proper response. + $status = Password::sendResetLink( + $request->only('email') + ); + + return $status == Password::RESET_LINK_SENT + ? back()->with('status', __($status)) + : back()->withInput($request->only('email')) + ->withErrors(['email' => __($status)]); + } +} diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php new file mode 100644 index 0000000..0739e2e --- /dev/null +++ b/app/Http/Controllers/Auth/RegisteredUserController.php @@ -0,0 +1,50 @@ +validate([ + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class], + 'password' => ['required', 'confirmed', Rules\Password::defaults()], + ]); + + $user = User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + ]); + + event(new Registered($user)); + + Auth::login($user); + + return redirect(route('dashboard', absolute: false)); + } +} diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php new file mode 100644 index 0000000..8adaecb --- /dev/null +++ b/app/Http/Controllers/Auth/VerifyEmailController.php @@ -0,0 +1,27 @@ +user()->hasVerifiedEmail()) { + return redirect()->intended(route('home.index', absolute: false).'?verified=1'); + } + + if ($request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); + } + + return redirect()->intended(route('home.index', absolute: false).'?verified=1'); + } +} diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 23c1930..b087a1e 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -3,12 +3,16 @@ namespace App\Http\Controllers; use App\Models\Episode; +use App\Models\Playlist; +use App\Models\PlaylistEpisode; use App\Http\Requests\ProfileUpdateRequest; - +use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Str; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Redirect; +use Illuminate\View\View; use Conner\Tagging\Model\Tag; @@ -17,7 +21,7 @@ class ProfileController extends Controller /** * Display the user page. */ - public function index(Request $request): \Illuminate\View\View + public function index(Request $request): View { return view('profile.index', [ 'user' => $request->user(), @@ -27,7 +31,7 @@ class ProfileController extends Controller /** * Display the user's settings form. */ - public function settings(Request $request): \Illuminate\View\View + public function settings(Request $request): View { $example = Episode::where('title', 'Succubus Yondara Gibo ga Kita!?')->first(); @@ -37,10 +41,26 @@ class ProfileController extends Controller ]); } + /** + * Update the user's profile information. + */ + public function update(ProfileUpdateRequest $request): RedirectResponse + { + $request->user()->fill($request->validated()); + + if ($request->user()->isDirty('email')) { + $request->user()->email_verified_at = null; + } + + $request->user()->save(); + + return Redirect::route('profile.settings')->with('status', 'profile-updated'); + } + /** * Display the user's watched page. */ - public function watched(Request $request): \Illuminate\View\View + public function watched(Request $request): View { return view('profile.watched', [ 'user' => $request->user(), @@ -50,7 +70,7 @@ class ProfileController extends Controller /** * Display the user's comments page. */ - public function comments(Request $request): \Illuminate\View\View + public function comments(Request $request): View { return view('profile.comments', [ 'user' => $request->user(), @@ -60,7 +80,7 @@ class ProfileController extends Controller /** * Display the user's likes page. */ - public function likes(Request $request): \Illuminate\View\View + public function likes(Request $request): View { return view('profile.likes', [ 'user' => $request->user(), @@ -70,7 +90,7 @@ class ProfileController extends Controller /** * Update user settings. */ - public function saveSettings(Request $request): \Illuminate\Http\RedirectResponse + public function saveSettings(Request $request): RedirectResponse { $user = $request->user(); $user->search_design = $request->input('searchDesign') == 'thumbnail'; @@ -84,7 +104,7 @@ class ProfileController extends Controller /** * Update user tag blacklist. */ - public function saveBlacklist(Request $request): \Illuminate\Http\RedirectResponse + public function saveBlacklist(Request $request): RedirectResponse { $user = $request->user(); $tags = json_decode($request->input('tags')); @@ -112,19 +132,28 @@ class ProfileController extends Controller */ public function destroy(Request $request): \Illuminate\Http\RedirectResponse { - $request->validateWithBag('userDeletion', [ - 'password' => ['required', 'current_password'], - ]); - $user = $request->user(); + // Delete Playlist + $playlists = Playlist::where('user_id', $user->id)->get(); + foreach($playlists as $playlist) { + PlaylistEpisode::where('playlist_id', $playlist->id)->forceDelete(); + $playlist->forceDelete(); + } + + // Update comments to deleted user + DB::table('comments')->where('commenter_id', '=', $user->id)->update(['commenter_id' => 1]); + Auth::logout(); - $user->delete(); + $user->forceDelete(); $request->session()->invalidate(); + $request->session()->regenerateToken(); + cache()->flush(); + return Redirect::to('/'); } } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 5e24903..4829151 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -3,12 +3,6 @@ namespace App\Http\Controllers; use App\Models\User; -use App\Models\Playlist; -use App\Models\PlaylistEpisode; -use App\Models\Watched; -use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; -use Illuminate\Support\Facades\DB; class UserController extends Controller { @@ -18,41 +12,11 @@ class UserController extends Controller public function index(string $username): \Illuminate\View\View { $user = User::where('name', $username) - ->select('id', 'name', 'discord_name', 'avatar', 'created_at', 'is_patreon') + ->select('id', 'name', 'discord_id', 'discord_name', 'discord_avatar', 'created_at', 'is_patreon') ->firstOrFail(); return view('user.index', [ 'user' => $user, ]); } - - /** - * Delete User. - */ - public function delete(Request $request): \Illuminate\Http\RedirectResponse - { - $user = User::where('id', $request->user()->id)->firstOrFail(); - - // Delete Playlist - $playlists = Playlist::where('user_id', $user->id)->get(); - foreach($playlists as $playlist) { - PlaylistEpisode::where('playlist_id', $playlist->id)->forceDelete(); - $playlist->forceDelete(); - } - - // Update comments to deleted user - DB::table('comments')->where('commenter_id', '=', $user->id)->update(['commenter_id' => 1]); - - $user->forceDelete(); - - Auth::guard('web')->logout(); - - $request->session()->invalidate(); - - $request->session()->regenerateToken(); - - cache()->flush(); - - return redirect('/'); - } } diff --git a/app/Http/Requests/Auth/LoginRequest.php b/app/Http/Requests/Auth/LoginRequest.php index 7a19bc0..2574642 100644 --- a/app/Http/Requests/Auth/LoginRequest.php +++ b/app/Http/Requests/Auth/LoginRequest.php @@ -22,7 +22,7 @@ class LoginRequest extends FormRequest /** * Get the validation rules that apply to the request. * - * @return array + * @return array|string> */ public function rules(): array { @@ -80,6 +80,6 @@ class LoginRequest extends FormRequest */ public function throttleKey(): string { - return Str::transliterate(Str::lower($this->input('email')).'|'.$this->ip()); + return Str::transliterate(Str::lower($this->string('email')).'|'.$this->ip()); } } diff --git a/app/Http/Requests/ProfileUpdateRequest.php b/app/Http/Requests/ProfileUpdateRequest.php index 327ce6f..3622a8f 100644 --- a/app/Http/Requests/ProfileUpdateRequest.php +++ b/app/Http/Requests/ProfileUpdateRequest.php @@ -11,13 +11,20 @@ class ProfileUpdateRequest extends FormRequest /** * Get the validation rules that apply to the request. * - * @return array + * @return array|string> */ public function rules(): array { return [ - 'name' => ['string', 'max:255'], - 'email' => ['email', 'max:255', Rule::unique(User::class)->ignore($this->user()->id)], + 'name' => ['required', 'string', 'max:255'], + 'email' => [ + 'required', + 'string', + 'lowercase', + 'email', + 'max:255', + Rule::unique(User::class)->ignore($this->user()->id), + ], ]; } } diff --git a/app/Models/User.php b/app/Models/User.php index 97fa370..9fd5cfb 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,6 +2,7 @@ namespace App\Models; +//use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; @@ -63,6 +64,23 @@ class User extends Authenticatable 'discord_avatar' => 'string', ]; + /** + * Get the user name + */ + public function getUserName(): string + { + if (!$this->discord_name) { + return $this->name; + } + + if ($this->discord_name == $this->name) + { + return $this->name; + } + + return "{$this->name} ({$this->discord_name})"; + } + /** * Has Many Playlists. */ diff --git a/composer.json b/composer.json index 2d5c06b..69f90e7 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "require-dev": { "barryvdh/laravel-debugbar": "^3.14.7", "fakerphp/faker": "^1.24.0", + "laravel/breeze": "^2.3", "laravel/pint": "^1.18", "laravel/sail": "^1.38", "mockery/mockery": "^1.4.4", diff --git a/composer.lock b/composer.lock index e1d775a..2ce5237 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1759692ca41f87ed3c80648a187d595b", + "content-hash": "ba6aa8b56350d49f92450bc54ed64912", "packages": [ { "name": "brick/math", @@ -8721,6 +8721,67 @@ }, "time": "2025-04-30T06:54:44+00:00" }, + { + "name": "laravel/breeze", + "version": "v2.3.8", + "source": { + "type": "git", + "url": "https://github.com/laravel/breeze.git", + "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/breeze/zipball/1a29c5792818bd4cddf70b5f743a227e02fbcfcd", + "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd", + "shasum": "" + }, + "require": { + "illuminate/console": "^11.0|^12.0", + "illuminate/filesystem": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "illuminate/validation": "^11.0|^12.0", + "php": "^8.2.0", + "symfony/console": "^7.0" + }, + "require-dev": { + "laravel/framework": "^11.0|^12.0", + "orchestra/testbench-core": "^9.0|^10.0", + "phpstan/phpstan": "^2.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Breeze\\BreezeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Breeze\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Minimal Laravel authentication scaffolding with Blade and Tailwind.", + "keywords": [ + "auth", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/breeze/issues", + "source": "https://github.com/laravel/breeze" + }, + "time": "2025-07-18T18:49:59+00:00" + }, { "name": "laravel/pint", "version": "v1.25.1", diff --git a/package-lock.json b/package-lock.json index 246257e..5984385 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,13 @@ "vidstack": "^1.12.13" }, "devDependencies": { - "@tailwindcss/forms": "^0.5.7", - "autoprefixer": "^10.4.18", + "@tailwindcss/forms": "^0.5.2", + "alpinejs": "^3.4.2", + "autoprefixer": "^10.4.2", "axios": "^1.6.8", "laravel-vite-plugin": "^2.0.0", - "postcss": "^8.4.35", - "tailwindcss": "^3.4.1", + "postcss": "^8.4.31", + "tailwindcss": "^3.1.0", "vite": "^7.1.6", "vite-plugin-static-copy": "^3.0.1" } @@ -974,6 +975,23 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT" }, + "node_modules/@vue/reactivity": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", + "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.1.5" + } + }, + "node_modules/@vue/shared": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", + "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==", + "dev": true, + "license": "MIT" + }, "node_modules/@yaireo/tagify": { "version": "4.35.4", "resolved": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.35.4.tgz", @@ -1001,6 +1019,16 @@ "node": ">=0.4.0" } }, + "node_modules/alpinejs": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.3.tgz", + "integrity": "sha512-fSI6F5213FdpMC4IWaup92KhuH3jBX0VVqajRJ6cOTCy1cL6888KyXdGO+seAAkn+g6fnrxBqQEx6gRpQ5EZoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "~3.1.1" + } + }, "node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", diff --git a/package.json b/package.json index da8f3b1..bbb40f4 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,13 @@ "build": "vite build" }, "devDependencies": { - "@tailwindcss/forms": "^0.5.7", - "autoprefixer": "^10.4.18", + "@tailwindcss/forms": "^0.5.2", + "alpinejs": "^3.4.2", + "autoprefixer": "^10.4.2", "axios": "^1.6.8", "laravel-vite-plugin": "^2.0.0", - "postcss": "^8.4.35", - "tailwindcss": "^3.4.1", + "postcss": "^8.4.31", + "tailwindcss": "^3.1.0", "vite": "^7.1.6", "vite-plugin-static-copy": "^3.0.1" }, diff --git a/resources/js/app.js b/resources/js/app.js index 935b972..01c671a 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1,8 +1,5 @@ import './bootstrap'; - -// import { Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm'; -// Alpine.start(); - +import 'hammerjs'; import { Collapse, Carousel, @@ -15,6 +12,10 @@ import { initTE, } from "tw-elements"; -initTE({ Collapse, Carousel, Clipboard, Modal, Tab, Lightbox, Tooltip, Ripple }); +import Alpine from 'alpinejs'; -import 'hammerjs'; +window.Alpine = Alpine; + +Alpine.start(); + +initTE({ Collapse, Carousel, Clipboard, Modal, Tab, Lightbox, Tooltip, Ripple }); diff --git a/resources/views/auth/confirm-password.blade.php b/resources/views/auth/confirm-password.blade.php new file mode 100644 index 0000000..3cbbe08 --- /dev/null +++ b/resources/views/auth/confirm-password.blade.php @@ -0,0 +1,27 @@ + +
+ {{ __('This is a secure area of the application. Please confirm your password before continuing.') }} +
+ +
+ @csrf + + +
+ + + + + +
+ +
+ + {{ __('Confirm') }} + +
+
+
diff --git a/resources/views/auth/forgot-password.blade.php b/resources/views/auth/forgot-password.blade.php new file mode 100644 index 0000000..3c70788 --- /dev/null +++ b/resources/views/auth/forgot-password.blade.php @@ -0,0 +1,25 @@ + +
+ {{ __('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.') }} +
+ + + + +
+ @csrf + + +
+ + + +
+ +
+ + {{ __('Email Password Reset Link') }} + +
+
+
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php new file mode 100644 index 0000000..80e1b39 --- /dev/null +++ b/resources/views/auth/login.blade.php @@ -0,0 +1,47 @@ + + + + +
+ @csrf + + +
+ + + +
+ + +
+ + + + + +
+ + +
+ +
+ +
+ @if (Route::has('password.request')) + + {{ __('Forgot your password?') }} + + @endif + + + {{ __('Log in') }} + +
+
+
diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php new file mode 100644 index 0000000..d4b3d58 --- /dev/null +++ b/resources/views/auth/register.blade.php @@ -0,0 +1,52 @@ + +
+ @csrf + + +
+ + + +
+ + +
+ + + +
+ + +
+ + + + + +
+ + +
+ + + + + +
+ +
+ + {{ __('Already registered?') }} + + + + {{ __('Register') }} + +
+
+
diff --git a/resources/views/auth/reset-password.blade.php b/resources/views/auth/reset-password.blade.php new file mode 100644 index 0000000..a6494cc --- /dev/null +++ b/resources/views/auth/reset-password.blade.php @@ -0,0 +1,39 @@ + +
+ @csrf + + + + + +
+ + + +
+ + +
+ + + +
+ + +
+ + + + + +
+ +
+ + {{ __('Reset Password') }} + +
+
+
diff --git a/resources/views/auth/verify-email.blade.php b/resources/views/auth/verify-email.blade.php new file mode 100644 index 0000000..4e4222f --- /dev/null +++ b/resources/views/auth/verify-email.blade.php @@ -0,0 +1,31 @@ + +
+ {{ __('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.') }} +
+ + @if (session('status') == 'verification-link-sent') +
+ {{ __('A new verification link has been sent to the email address you provided during registration.') }} +
+ @endif + +
+
+ @csrf + +
+ + {{ __('Resend Verification Email') }} + +
+
+ +
+ @csrf + + +
+
+
diff --git a/resources/views/components/dropdown-link.blade.php b/resources/views/components/dropdown-link.blade.php index 083548e..20b8f36 100644 --- a/resources/views/components/dropdown-link.blade.php +++ b/resources/views/components/dropdown-link.blade.php @@ -1 +1 @@ -merge(['class' => 'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-neutral-100 dark:hover:bg-neutral-900 focus:outline-none focus:bg-neutral-100 dark:focus:bg-neutral-800 transition duration-150 ease-in-out']) }}>{{ $slot }} +merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-neutral-100 dark:hover:bg-neutral-900 focus:outline-none focus:bg-neutral-100 dark:focus:bg-neutral-800 transition duration-150 ease-in-out']) }}>{{ $slot }} diff --git a/resources/views/components/dropdown.blade.php b/resources/views/components/dropdown.blade.php index 4a68c9e..bbb5d63 100644 --- a/resources/views/components/dropdown.blade.php +++ b/resources/views/components/dropdown.blade.php @@ -1,24 +1,16 @@ @props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-neutral-800']) @php -switch ($align) { - case 'left': - $alignmentClasses = 'origin-top-left left-0'; - break; - case 'top': - $alignmentClasses = 'origin-top'; - break; - case 'right': - default: - $alignmentClasses = 'origin-top-right right-0'; - break; -} +$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', +}; -switch ($width) { - case '48': - $width = 'w-48'; - break; -} +$width = match ($width) { + '48' => 'w-48', + default => $width, +}; @endphp
@@ -28,11 +20,11 @@ switch ($width) {