Mercurial > packages > auth
changeset 0:90e38de8f2ba
Initial Commit
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,9 @@ +syntax: glob +vendor +*.env +*.env.backup +*.env.production +.php-cs-fixer.cache +*.aichat +tags +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CHANGELOG.md Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,801 @@ +# Release Notes + +## [Unreleased](https://github.com/laravel/breeze/compare/v2.3.8...2.x) + +## [v2.3.8](https://github.com/laravel/breeze/compare/v2.3.7...v2.3.8) - 2025-07-18 + +* [2.x] Bump Livewire to 3.6.4 by [@PerryvanderMeer](https://github.com/PerryvanderMeer) in https://github.com/laravel/breeze/pull/474 + +## [v2.3.7](https://github.com/laravel/breeze/compare/v2.3.6...v2.3.7) - 2025-06-17 + +* [2.x] Fix adding middleware group and alias during installation by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/breeze/pull/473 + +## [v2.3.6](https://github.com/laravel/breeze/compare/v2.3.5...v2.3.6) - 2025-03-06 + +* Updated Volt version to ^1.7.0 by [@MrPunyapal](https://github.com/MrPunyapal) in https://github.com/laravel/breeze/pull/471 + +## [v2.3.5](https://github.com/laravel/breeze/compare/v2.3.4...v2.3.5) - 2025-02-19 + +* Supports Laravel 12 by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/breeze/pull/451 + +## [v2.3.4](https://github.com/laravel/breeze/compare/v2.3.3...v2.3.4) - 2025-02-11 + +* update bun lockfile by [@fouteox](https://github.com/fouteox) in https://github.com/laravel/breeze/pull/462 +* [2.x] [ApiStack] Remove `node_modules` and associated lock files by [@miclaus](https://github.com/miclaus) in https://github.com/laravel/breeze/pull/467 + +## [v2.3.3](https://github.com/laravel/breeze/compare/v2.3.2...v2.3.3) - 2025-01-26 + +* Fix type error in Login component for `setData` function by [@florikodra](https://github.com/florikodra) in https://github.com/laravel/breeze/pull/454 +* Fix tsc error in Pages/Auth/Login.tsx on fresh install by [@MariosIgkiempor](https://github.com/MariosIgkiempor) in https://github.com/laravel/breeze/pull/457 + +## [v2.3.2](https://github.com/laravel/breeze/compare/v2.3.1...v2.3.2) - 2025-01-21 + +* [2.x] Unpin typescript version for Inertia Vue stack by [@reyberyturiaga](https://github.com/reyberyturiaga) in https://github.com/laravel/breeze/pull/447 +* Missing type declaration add to NewPasswordController.php by [@ashokbaruaakas](https://github.com/ashokbaruaakas) in https://github.com/laravel/breeze/pull/449 + +## [v2.3.1](https://github.com/laravel/breeze/compare/v2.3.0...v2.3.1) - 2025-01-13 + +* [2.x] Remove tailwind config files on api stack by [@p-nerd](https://github.com/p-nerd) in https://github.com/laravel/breeze/pull/444 +* [2.x] Remove redundant `.d.ts` inclusion from `tsconfig.json` by [@panakour](https://github.com/panakour) in https://github.com/laravel/breeze/pull/445 + +## [v2.3.0](https://github.com/laravel/breeze/compare/v2.2.6...v2.3.0) - 2024-12-14 + +* Fix typescript version by [@mo7zayed](https://github.com/mo7zayed) in https://github.com/laravel/breeze/pull/442 +* Upgrade to Inertia V2 by [@adamjgriffith](https://github.com/adamjgriffith) in https://github.com/laravel/breeze/pull/443 + +## [v2.2.6](https://github.com/laravel/breeze/compare/v2.2.5...v2.2.6) - 2024-11-20 + +* [2.x] Supports PHPStan 2 by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/breeze/pull/441 + +## [v2.2.5](https://github.com/laravel/breeze/compare/v2.2.4...v2.2.5) - 2024-11-12 + +* fix(ts): remove redundant [@ts-expect-error](https://github.com/ts-expect-error) directives in SSR route setup by [@datlechin](https://github.com/datlechin) in https://github.com/laravel/breeze/pull/434 +* Backport JetStream Modal.vue enhancements by [@mrleblanc101](https://github.com/mrleblanc101) in https://github.com/laravel/breeze/pull/435 +* Convert array to single line format by [@Rattone](https://github.com/Rattone) in https://github.com/laravel/breeze/pull/436 +* [2.x] Replace `Rule` with `ValidationRule` by [@avosalmon](https://github.com/avosalmon) in https://github.com/laravel/breeze/pull/437 + +## [v2.2.4](https://github.com/laravel/breeze/compare/v2.2.3...v2.2.4) - 2024-10-29 + +* fix(sanctum): add 127.0.0.1:3000 for proper API auth during local development with 127.0.0.1:3000 by [@ShahAlamShaikat](https://github.com/ShahAlamShaikat) in https://github.com/laravel/breeze/pull/431 +* Using the translate function instead of a static value by [@ashkanfekridev](https://github.com/ashkanfekridev) in https://github.com/laravel/breeze/pull/432 + +## [v2.2.3](https://github.com/laravel/breeze/compare/v2.2.2...v2.2.3) - 2024-10-17 + +* [2.x] Fixed TypeScript Errors in React SSR Setup with Ziggy Props when Builds by [@akr4m](https://github.com/akr4m) in https://github.com/laravel/breeze/pull/430 + +## [v2.2.2](https://github.com/laravel/breeze/compare/v2.2.1...v2.2.2) - 2024-10-06 + +* Update logo to support dark/light theme by [@milewski](https://github.com/milewski) in https://github.com/laravel/breeze/pull/418 +* Add hint to clarify how to use multiselect by [@bdweix](https://github.com/bdweix) in https://github.com/laravel/breeze/pull/417 +* [2.x] Utilise `Illuminate\Support\php_binary()` by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/breeze/pull/421 +* Remove blade unescape for attributes by [@Rattone](https://github.com/Rattone) in https://github.com/laravel/breeze/pull/422 +* [2.x] chore: text-input to use [@disabled](https://github.com/disabled) by [@MrPunyapal](https://github.com/MrPunyapal) in https://github.com/laravel/breeze/pull/427 +* Updated names of the default functions to match the file names. by [@msamgan](https://github.com/msamgan) in https://github.com/laravel/breeze/pull/428 + +## [v2.2.1](https://github.com/laravel/breeze/compare/v2.2.0...v2.2.1) - 2024-09-22 + +* [2.x] Add `pnpm` lockfile to `flushNodeModules` by [@osbre](https://github.com/osbre) in https://github.com/laravel/breeze/pull/411 +* [2.x] Add option to install ESLint with Prettier by [@avosalmon](https://github.com/avosalmon) in https://github.com/laravel/breeze/pull/412 +* [2.x] Allows GitHub Actions to run directly from GA UI by [@crynobone](https://github.com/crynobone) in https://github.com/laravel/breeze/pull/413 +* Refactor: Break long email validation rule into multiple lines by [@Amidope](https://github.com/Amidope) in https://github.com/laravel/breeze/pull/416 + +## [v2.2.0](https://github.com/laravel/breeze/compare/v2.1.5...v2.2.0) - 2024-09-11 + +* fix: add clearErrors on DeleteUserForm on closeModal function by [@radumargina](https://github.com/radumargina) in https://github.com/laravel/breeze/pull/406 +* check for import.meta.env.SSR instead of import.meta.env.DEV to know… by [@YassineBenh](https://github.com/YassineBenh) in https://github.com/laravel/breeze/pull/409 +* Declare global types for React PageProps by [@matsantosz](https://github.com/matsantosz) in https://github.com/laravel/breeze/pull/405 + +## [v2.1.5](https://github.com/laravel/breeze/compare/v2.1.4...v2.1.5) - 2024-09-09 + +* Adjust feature request template by [@driesvints](https://github.com/driesvints) in https://github.com/laravel/breeze/pull/401 +* [2.x] Add Bun & Deno Support for installStacks (Blade, Livewire, Inertia) by [@thecodechef](https://github.com/thecodechef) in https://github.com/laravel/breeze/pull/403 +* [2.x] Eagerly prefetch assets by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/breeze/pull/400 +* [2.x] Added `bun` & `deno` support to `flushNodeModules()` by [@thecodechef](https://github.com/thecodechef) in https://github.com/laravel/breeze/pull/404 +* [2.x] Use Pest as default testing framework by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/breeze/pull/402 +* Uses Pest 3 by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/408 + +**Full Changelog**: https://github.com/laravel/breeze/compare/v2.1.4...v2.1.5 + +## [v2.1.4](https://github.com/laravel/breeze/compare/v2.1.3...v2.1.4) - 2024-08-12 + +* Update User type to match db schema by [@ninjaparade](https://github.com/ninjaparade) in https://github.com/laravel/breeze/pull/399 + +## [v2.1.3](https://github.com/laravel/breeze/compare/v2.1.2...v2.1.3) - 2024-07-17 + +* fix clearing password fields on React auth forms by [@daleweaver777](https://github.com/daleweaver777) in https://github.com/laravel/breeze/pull/395 + +## [v2.1.2](https://github.com/laravel/breeze/compare/v2.1.1...v2.1.2) - 2024-07-05 + +* [2.x] Replace `switch` with `match` in `dropdown.blade.php` by [@osbre](https://github.com/osbre) in https://github.com/laravel/breeze/pull/393 + +## [v2.1.1](https://github.com/laravel/breeze/compare/v2.1.0...v2.1.1) - 2024-07-02 + +* Bump vue-tsc to v2 to fix crash with TypeScript v5.5 by [@daleweaver777](https://github.com/daleweaver777) in https://github.com/laravel/breeze/pull/391 + +## [v2.1.0](https://github.com/laravel/breeze/compare/v2.0.5...v2.1.0) - 2024-06-06 + +* Bump `[@headlessui](https://github.com/headlessui)/react` to v2 by [@RobinMalfait](https://github.com/RobinMalfait) in https://github.com/laravel/breeze/pull/389 + +## [v2.0.5](https://github.com/laravel/breeze/compare/v2.0.4...v2.0.5) - 2024-05-28 + +* [2.x] Use `[@isset](https://github.com/isset)` directive by [@dasundev](https://github.com/dasundev) in https://github.com/laravel/breeze/pull/388 + +## [v2.0.4](https://github.com/laravel/breeze/compare/v2.0.3...v2.0.4) - 2024-05-20 + +* Update RegisteredUserController.php by [@olivsinz](https://github.com/olivsinz) in https://github.com/laravel/breeze/pull/386 +* Update NewPasswordController.php by [@olivsinz](https://github.com/olivsinz) in https://github.com/laravel/breeze/pull/385 +* Adding bun support within install command by [@Mavv3006](https://github.com/Mavv3006) in https://github.com/laravel/breeze/pull/384 +* fix: add `hydrateRoot` when react ssr enabled by [@jrson83](https://github.com/jrson83) in https://github.com/laravel/breeze/pull/387 + +## [v2.0.3](https://github.com/laravel/breeze/compare/v2.0.2...v2.0.3) - 2024-04-24 + +* Refactor email verification tests by [@javadihugo](https://github.com/javadihugo) in https://github.com/laravel/breeze/pull/379 +* [2.x] Fix React TS errors by [@jessarcher](https://github.com/jessarcher) in https://github.com/laravel/breeze/pull/381 +* Remove welcome view by [@taylorotwell](https://github.com/taylorotwell) in https://github.com/laravel/breeze/commit/86cccf3d7ed843fc60738963ed2ed800eaf314d9 +* Remove welcome view by [@taylorotwell](https://github.com/taylorotwell) in https://github.com/laravel/breeze/commit/0d97c710d25e69916b84eb8ff4b630c838709c11 + +## [v2.0.2](https://github.com/laravel/breeze/compare/v2.0.1...v2.0.2) - 2024-04-01 + +* [2.x] Removes "(experimental)" label by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/377 + +## [v2.0.1](https://github.com/laravel/breeze/compare/v2.0.0...v2.0.1) - 2024-03-21 + +* Remove duplicate "id" attribute by [@edikurniawan-dev](https://github.com/edikurniawan-dev) in https://github.com/laravel/breeze/pull/368 +* Add Laravel Herd by [@mpociot](https://github.com/mpociot) in https://github.com/laravel/breeze/pull/372 +* [2.x] Make commands lazy by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/breeze/pull/373 +* [2.x] Fixes non dark mode on Livewire's `welcome/navigation.blade.php` by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/375 + +## [v2.0.0](https://github.com/laravel/breeze/compare/v1.29.1...v2.0.0) - 2024-03-12 + +* Adds Laravel 11 support by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/331 +* Add id to Input component by [@mmkhakdaman](https://github.com/mmkhakdaman) in https://github.com/laravel/breeze/pull/151 +* Implement 11.x welcome page design by [@jasonlbeggs](https://github.com/jasonlbeggs) in https://github.com/laravel/breeze/pull/362 + +## [v1.29.1](https://github.com/laravel/breeze/compare/v1.29.0...v1.29.1) - 2024-03-04 + +* Updated throttleKey method to meet Str::lower excepted value in LoginRequest stub by [@rileyshannon](https://github.com/rileyshannon) in https://github.com/laravel/breeze/pull/365 +* Fix Livewire form validation by [@PerryvanderMeer](https://github.com/PerryvanderMeer) in https://github.com/laravel/breeze/pull/364 + +## [v1.29.0](https://github.com/laravel/breeze/compare/v1.28.3...v1.29.0) - 2024-02-21 + +* Update to Ziggy v2 by [@bakerkretzmar](https://github.com/bakerkretzmar) in https://github.com/laravel/breeze/pull/359 + +## [v1.28.3](https://github.com/laravel/breeze/compare/v1.28.2...v1.28.3) - 2024-02-19 + +* Improve default auth tests inside the stubs by [@Pilskalns](https://github.com/Pilskalns) in https://github.com/laravel/breeze/pull/358 + +## [v1.28.2](https://github.com/laravel/breeze/compare/v1.28.1...v1.28.2) - 2024-02-13 + +* [1.x] Use Livewire's `redirectIntended` function by [@PerryvanderMeer](https://github.com/PerryvanderMeer) in https://github.com/laravel/breeze/pull/352 + +## [v1.28.1](https://github.com/laravel/breeze/compare/v1.28.0...v1.28.1) - 2024-01-15 + +* Add default value for useRef calls in .tsx files by [@matthiasweiss](https://github.com/matthiasweiss) in https://github.com/laravel/breeze/pull/348 + +## [v1.28.0](https://github.com/laravel/breeze/compare/v1.27.0...v1.28.0) - 2024-01-06 + +* [1.x] Switch to `defineModel` in Vue stubs by [@osbre](https://github.com/osbre) in https://github.com/laravel/breeze/pull/285 + +## [v1.27.0](https://github.com/laravel/breeze/compare/v1.26.3...v1.27.0) - 2023-12-19 + +* Update PostCSS version by [@TENIOS](https://github.com/TENIOS) in https://github.com/laravel/breeze/pull/339 +* Added a x-on:close-modal.window directive so we can close modal from a livewire function by [@lucidpolygon](https://github.com/lucidpolygon) in https://github.com/laravel/breeze/pull/341 +* Improve Ziggy setup in Inertia stacks by [@bakerkretzmar](https://github.com/bakerkretzmar) in https://github.com/laravel/breeze/pull/340 +* [1.x] Vite 5 by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/breeze/pull/342 + +## [v1.26.3](https://github.com/laravel/breeze/compare/v1.26.2...v1.26.3) - 2023-12-06 + +* asserting responses are ok before asserting presence of components by [@da-mask](https://github.com/da-mask) in https://github.com/laravel/breeze/pull/337 +* Fix handling of names with single quotes in Livewire navigation by [@dragi-ns](https://github.com/dragi-ns) in https://github.com/laravel/breeze/pull/336 +* Change Livewire Rule Attribute to Validate Attribute by [@achmedislamic](https://github.com/achmedislamic) in https://github.com/laravel/breeze/pull/334 +* [1.x] Uses `json_encode` like Jetstream by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/338 + +## [v1.26.2](https://github.com/laravel/breeze/compare/v1.26.1...v1.26.2) - 2023-11-24 + +* refactor: remove unused import by [@hsndmr](https://github.com/hsndmr) in https://github.com/laravel/breeze/pull/328 +* Remove unused import statement by [@arifhp86](https://github.com/arifhp86) in https://github.com/laravel/breeze/pull/329 +* [1.x] Fix duplicate password fields by [@tonysm](https://github.com/tonysm) in https://github.com/laravel/breeze/pull/33 + +## [v1.26.1](https://github.com/laravel/breeze/compare/v1.26.0...v1.26.1) - 2023-11-01 + +- Better Support for RTL by [@joelbutcher](https://github.com/joelbutcher) in https://github.com/laravel/breeze/pull/327 + +## [v1.26.0](https://github.com/laravel/breeze/compare/v1.25.1...v1.26.0) - 2023-10-29 + +- Fix Livewire 'remember me' flow for login doesn't remember by [@ebosveld](https://github.com/ebosveld) in https://github.com/laravel/breeze/pull/325 +- Beautify Livewire Stack by [@taylorotwell](https://github.com/taylorotwell) in https://github.com/laravel/breeze/pull/326 + +## [v1.25.1](https://github.com/laravel/breeze/compare/v1.25.0...v1.25.1) - 2023-10-20 + +- [1.x] Adds `lowercase` validation rule to user's `email` field by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/321 +- [1.x] Fix React type issue for SSR route by [@parth391](https://github.com/parth391) in https://github.com/laravel/breeze/pull/320 +- [1.x] Don't hide options by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/breeze/pull/322 + +## [v1.25.0](https://github.com/laravel/breeze/compare/v1.24.1...v1.25.0) - 2023-10-06 + +- Adds Livewire Volt Functional API by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/318 + +## [v1.24.1](https://github.com/laravel/breeze/compare/v1.24.0...v1.24.1) - 2023-10-04 + +- Fix missing class import by [@qwert1x](https://github.com/qwert1x) in https://github.com/laravel/breeze/pull/317 + +## [v1.24.0](https://github.com/laravel/breeze/compare/v1.23.3...v1.24.0) - 2023-09-20 + +- Adds Livewire stack 🐙 by [@nunomaduro](https://github.com/nunomaduro) in https://github.com/laravel/breeze/pull/314 + +## [v1.23.3](https://github.com/laravel/breeze/compare/v1.23.2...v1.23.3) - 2023-09-06 + +- Add logout tests by [@xiCO2k](https://github.com/xiCO2k) in https://github.com/laravel/breeze/pull/311 + +## [v1.23.2](https://github.com/laravel/breeze/compare/v1.23.1...v1.23.2) - 2023-09-01 + +- Highlight Alpine by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/breeze/pull/307 + +## [v1.23.1](https://github.com/laravel/breeze/compare/v1.23.0...v1.23.1) - 2023-08-27 + +- Replace `array_merge` with spread operator in `HandleInertiaRequests` by [@osbre](https://github.com/osbre) in https://github.com/laravel/breeze/pull/302 + +## [v1.23.0](https://github.com/laravel/breeze/compare/v1.22.0...v1.23.0) - 2023-08-08 + +- [1.x] Pest detection by [@jessarcher](https://github.com/jessarcher) in https://github.com/laravel/breeze/pull/300 + +## [v1.22.0](https://github.com/laravel/breeze/compare/v1.21.2...v1.22.0) - 2023-08-02 + +- [1.x] Update `[@vitejs](https://github.com/vitejs)/plugin-react` to v4 by [@parth391](https://github.com/parth391) in https://github.com/laravel/breeze/pull/298 +- [1.x] Prompts by [@jessarcher](https://github.com/jessarcher) in https://github.com/laravel/breeze/pull/295 + +## [v1.21.2](https://github.com/laravel/breeze/compare/v1.21.1...v1.21.2) - 2023-06-21 + +- Fix and standardise transitions by [@timacdonald](https://github.com/timacdonald) in https://github.com/laravel/breeze/pull/293 +- Use appName directly from .env in <title> by [@domnantas](https://github.com/domnantas) in https://github.com/laravel/breeze/pull/292 + +## [v1.21.1](https://github.com/laravel/breeze/compare/v1.21.0...v1.21.1) - 2023-06-16 + +- Remove implicit form method calls by @Jacobtims in https://github.com/laravel/breeze/pull/290 + +## [v1.21.0](https://github.com/laravel/breeze/compare/v1.20.2...v1.21.0) - 2023-05-04 + +- Migrate to modules by @timacdonald in https://github.com/laravel/breeze/pull/246 + +## [v1.20.2](https://github.com/laravel/breeze/compare/v1.20.1...v1.20.2) - 2023-04-16 + +- Remove redundant form data in vue stub by @datlechin in https://github.com/laravel/breeze/pull/280 +- Add Sanctum Guard by @taylorotwell in https://github.com/laravel/breeze/commit/b010ff3f8cd8e9ae2a2023ca323fba9987157f60 + +## [v1.20.1](https://github.com/laravel/breeze/compare/v1.20.0...v1.20.1) - 2023-03-28 + +- Fix ref in react TextInput by @denis-n-ko in https://github.com/laravel/breeze/pull/277 +- Update `current_password` rule in ProfileController by @saade in https://github.com/laravel/breeze/pull/278 +- Fix Pest test installation for Inertia stack by @jessarcher in https://github.com/laravel/breeze/pull/279 + +## [v1.20.0](https://github.com/laravel/breeze/compare/v1.19.2...v1.20.0) - 2023-03-20 + +- Add opt-in TypeScript support by @jessarcher in https://github.com/laravel/breeze/pull/267 +- Uses Pest 2 by @nunomaduro in https://github.com/laravel/breeze/pull/274 +- API Stub EnsureEmailIsVerified Middleware: Remove unused function arguments in params by @raksbisht in https://github.com/laravel/breeze/pull/264 +- Prop consistency by @jessarcher in https://github.com/laravel/breeze/pull/272 +- React - Fix potential "undefined" class by @jessarcher in https://github.com/laravel/breeze/pull/271 +- React - Remove unnecessary text input wrapper by @jessarcher in https://github.com/laravel/breeze/pull/270 +- React - Fix input focusing when password update fails by @jessarcher in https://github.com/laravel/breeze/pull/269 +- React - Simplify Form Handler by @jessarcher in https://github.com/laravel/breeze/pull/268 +- Fix password-update pest tests by @mtvbrianking in https://github.com/laravel/breeze/pull/273 + +## [v1.19.2](https://github.com/laravel/breeze/compare/v1.19.1...v1.19.2) - 2023-02-18 + +- Improve React components by @jessarcher in https://github.com/laravel/breeze/pull/257 +- Fix input field Id in ForgotPassword.jsx by @tomdupont in https://github.com/laravel/breeze/pull/262 + +## [v1.19.1](https://github.com/laravel/breeze/compare/v1.19.0...v1.19.1) - 2023-02-14 + +### Changed + +- Remove link + +## [v1.19.0](https://github.com/laravel/breeze/compare/v1.18.2...v1.19.0) - 2023-02-14 + +### Changed + +- Clean up route definition for Single Action Controllers by @istiak-tridip in https://github.com/laravel/breeze/pull/249 +- Add translation to placeholder in delete-user-form.blade.php by @castrohenworx in https://github.com/laravel/breeze/pull/250 +- Allowed a hardcoded string to be localized by @Wendelstein7 in https://github.com/laravel/breeze/pull/254 +- Update font and welcome page by @jessarcher in https://github.com/laravel/breeze/pull/253 + +### Fixed + +- Allows to install `--pest` in Laravel 10 by @driesvints in https://github.com/laravel/breeze/pull/251 + +### Removed + +- Remove unused files from stubs by @emargareten in https://github.com/laravel/breeze/pull/255 + +## [v1.18.2](https://github.com/laravel/breeze/compare/v1.18.1...v1.18.2) - 2023-02-02 + +### Changed + +- Use autocomplete for all fields for password manager compatibility by @lukearmstrong in https://github.com/laravel/breeze/pull/245 + +## [v1.18.1](https://github.com/laravel/breeze/compare/v1.18.0...v1.18.1) - 2023-01-31 + +### Changed + +- Inform user of dependency install process by @itxshakil in https://github.com/laravel/breeze/pull/241 + +### Fixed + +- Update nav menu dark text to be consistent with nav link by @RhysLees in https://github.com/laravel/breeze/pull/239 + +## [v1.18.0](https://github.com/laravel/breeze/compare/v1.17.0...v1.18.0) - 2023-01-18 + +### Added + +- Laravel v10 Support by @driesvints in https://github.com/laravel/breeze/pull/235 +- Inertia v1 Support by @jessarcher in https://github.com/laravel/breeze/pull/238 + +### Changed + +- Prompt when the stack argument is not provided by @jessarcher in https://github.com/laravel/breeze/pull/236 +- Use Illuminate console components for prompting by @jessarcher in https://github.com/laravel/breeze/pull/237 + +## [v1.17.0](https://github.com/laravel/breeze/compare/v1.16.1...v1.17.0) - 2023-01-03 + +### Changed + +- Uses PHP Native Type Declarations 🐘 by @nunomaduro in https://github.com/laravel/breeze/pull/201 + +## [v1.16.1](https://github.com/laravel/breeze/compare/v1.16.0...v1.16.1) - 2022-12-19 + +### Fixed + +- Remove unused vue imports by @dillingham in https://github.com/laravel/breeze/pull/231 +- Renamed isFocused prop on TextInput component by @drewmw5 in https://github.com/laravel/breeze/pull/232 + +## [v1.16.0](https://github.com/laravel/breeze/compare/v1.15.4...v1.16.0) - 2022-12-16 + +### Added + +- [1.x] Vite 4 support by @timacdonald in https://github.com/laravel/breeze/pull/226 + +### Changed + +- Blade stack - Moved duplicated logo component to guest layout by @magdicom in https://github.com/laravel/breeze/pull/228 + +### Fixed + +- Fix typo in delete user forms by @alexcanana in https://github.com/laravel/breeze/pull/225 +- Fixed capitalization of autoComplete prop by @drewmw5 in https://github.com/laravel/breeze/pull/230 + +## [v1.15.4](https://github.com/laravel/breeze/compare/v1.15.3...v1.15.4) - 2022-12-05 + +### Changed + +- Use Default NPM Package Manager of User if Lock File Exists In Base Path by @andrewdwallo in https://github.com/laravel/breeze/pull/224 + +## [v1.15.3](https://github.com/laravel/breeze/compare/v1.15.2...v1.15.3) - 2022-11-28 + +### Fixed + +- Fix-psr-4-warning by @Kamona-WD in https://github.com/laravel/breeze/pull/221 +- Status must be String by @marsuboss in https://github.com/laravel/breeze/pull/219 +- Fix close modal with escape keydown and cleanup import react by @fouteox in https://github.com/laravel/breeze/pull/218 + +## [v1.15.2](https://github.com/laravel/breeze/compare/v1.15.1...v1.15.2) - 2022-11-21 + +### Fixed + +- Fix closing tag by @kaozaza2 in https://github.com/laravel/breeze/pull/213 +- Vue code formatting by @jessarcher in https://github.com/laravel/breeze/pull/212 +- React formatting by @fouteox in https://github.com/laravel/breeze/pull/214 +- Add missing translation methods to Blade stack by @jessarcher in https://github.com/laravel/breeze/pull/215 + +## [v1.15.1](https://github.com/laravel/breeze/compare/v1.15.0...v1.15.1) - 2022-11-15 + +### Fixed + +- Fix namespace in PasswordUpdateTest.php by @irsyadadl in https://github.com/laravel/breeze/pull/211 + +## [v1.15.0](https://github.com/laravel/breeze/compare/v1.14.3...v1.15.0) - 2022-11-15 + +### Added + +- Add "Profile" page by @jessarcher in https://github.com/laravel/breeze/pull/205 +- Opt-in dark mode support :crescent_moon: by @jessarcher in https://github.com/laravel/breeze/pull/209 + +## [v1.14.3](https://github.com/laravel/breeze/compare/v1.14.2...v1.14.3) - 2022-11-06 + +### Changed + +- RegisteredUserController stubs should use the User model name instead of table name in the validators by @viliamjr in https://github.com/laravel/breeze/pull/206 + +## [v1.14.2](https://github.com/laravel/breeze/compare/v1.14.1...v1.14.2) - 2022-10-26 + +### Fixed + +- Fix preloading in dev by @timacdonald in https://github.com/laravel/breeze/pull/199 + +## [v1.14.1](https://github.com/laravel/breeze/compare/v1.14.0...v1.14.1) - 2022-10-25 + +### Changed + +- Replace double quote(") with single quote(') by @itxshakil in https://github.com/laravel/breeze/pull/195 +- Bump React and Vue Dependencies by @dammy001 in https://github.com/laravel/breeze/pull/197 +- Vite preloading by @timacdonald in https://github.com/laravel/breeze/pull/196 + +## [v1.14.0](https://github.com/laravel/breeze/compare/v1.13.1...v1.14.0) - 2022-09-27 + +### Added + +- Upgrade to React 18 by @kjoedion in https://github.com/laravel/breeze/pull/192 + +### Changed + +- Display errors alongside fields in Blade stack by @jessarcher in https://github.com/laravel/breeze/pull/191 +- Consistently use `verified` middleware on `/dashboard` route. by @jessarcher in https://github.com/laravel/breeze/pull/190 +- Make Blade app header optional by @jessarcher in https://github.com/laravel/breeze/pull/189 + +### Fixed + +- Fixes `HandleInertiaRequests::handle` related types by @felixdorn in https://github.com/laravel/breeze/pull/193 + +## [v1.13.1](https://github.com/laravel/breeze/compare/v1.13.0...v1.13.1) - 2022-09-20 + +### Fixed + +- Make app directory consistently lowercase by @jessarcher in https://github.com/laravel/breeze/pull/187 + +## [v1.13.0](https://github.com/laravel/breeze/compare/v1.12.0...v1.13.0) - 2022-09-06 + +### Changed + +- Remove "Breeze" component prefix by @jessarcher in https://github.com/laravel/breeze/pull/179 + +## [v1.12.0](https://github.com/laravel/breeze/compare/v1.11.4...v1.12.0) - 2022-08-16 + +### Changed + +- Install NPM dependencies and build assets by @jessarcher in https://github.com/laravel/breeze/pull/180 +- Set application home URI to /dashboard by @nikolaynikolaevn in https://github.com/laravel/breeze/pull/181 +- Update inertia-laravel by @timacdonald in https://github.com/laravel/breeze/commit/6d95e9aacbe992e19c81d5cd6f7eec994e50dd8d + +## [v1.11.4](https://github.com/laravel/breeze/compare/v1.11.3...v1.11.4) - 2022-08-08 + +### Changed + +- Display validation errors alongside their field by @jessarcher in https://github.com/laravel/breeze/pull/175 +- Validate the stack argument by @jessarcher in https://github.com/laravel/breeze/pull/178 +- Style improvements by @jessarcher in https://github.com/laravel/breeze/pull/177 + +## [v1.11.3](https://github.com/laravel/breeze/compare/v1.11.2...v1.11.3) - 2022-08-01 + +### Changed + +- Transliterate throttle key by @JurianArie in https://github.com/laravel/breeze/pull/173 +- Switch to fonts.bunny.net instead of Google Fonts by @lucasRolff in https://github.com/laravel/breeze/pull/174 + +## [v1.11.2](https://github.com/laravel/breeze/compare/v1.11.1...v1.11.2) - 2022-07-20 + +### Changed + +- Improved console output by @nunomaduro in https://github.com/laravel/breeze/pull/172 + +## [v1.11.1](https://github.com/laravel/breeze/compare/v1.11.0...v1.11.1) - 2022-07-20 + +### Changed + +- Vite 3 support by @timacdonald in https://github.com/laravel/breeze/pull/171 + +## [v1.11.0](https://github.com/laravel/breeze/compare/v1.10.0...v1.11.0) - 2022-07-11 + +### Changed + +- Add default view / routes reloading to breeze stacks by @timacdonald in https://github.com/laravel/breeze/pull/166 +- Update SSR directory by @jessarcher in https://github.com/laravel/breeze/pull/168 + +### Fixed + +- Fix: React SSR installation error by @renomureza in https://github.com/laravel/breeze/pull/169 + +### Removed + +- Laravel 8 don't support the vite. by @Jehong-Ahn in https://github.com/laravel/breeze/pull/167 + +## [v1.10.0](https://github.com/laravel/breeze/compare/v1.9.4...v1.10.0) - 2022-06-28 + +### Added + +- Vite by @jessarcher in https://github.com/laravel/breeze/pull/158 + +### Fixed + +- fix TailwindCSS first party TypeScript types weren't working right by @geisi in https://github.com/laravel/breeze/pull/160 +- Bump `@tailwindcss/forms` fix console warning with Vite by @timacdonald in https://github.com/laravel/breeze/pull/161 +- Fix ziggy determing current URL when using SSR by @timacdonald in https://github.com/laravel/breeze/pull/163 + +## [v1.9.4](https://github.com/laravel/breeze/compare/v1.9.3...v1.9.4) - 2022-06-13 + +### Changed + +- Bump TailwindCSS to 3.1 by @geisi in https://github.com/laravel/breeze/pull/156 + +## [v1.9.3](https://github.com/laravel/breeze/compare/v1.9.2...v1.9.3) - 2022-06-01 + +### Changed + +- Improve Vite compatibility by @jessarcher in https://github.com/laravel/breeze/pull/154 + +## [v1.9.2](https://github.com/laravel/breeze/compare/v1.9.1...v1.9.2) - 2022-05-30 + +### Changed + +- Simplify Tailwind installation by @jessarcher in https://github.com/laravel/breeze/pull/155 + +### Fixed + +- Fix inability to click dropdown content in React version by @jessarcher in https://github.com/laravel/breeze/pull/153 + +## [v1.9.1](https://github.com/laravel/breeze/compare/v1.9.0...v1.9.1) - 2022-05-11 + +### Changed + +- Update command comments by @taylorotwell in https://github.com/laravel/breeze/commit/cde98d03954bfcad0c9370c825187b8a579d94e1 + +## [v1.9.0](https://github.com/laravel/breeze/compare/v1.8.2...v1.9.0) - 2022-03-26 + +### Added + +- Add Inertia SSR Support by @xiCO2k in https://github.com/laravel/breeze/pull/146 + +### Changed + +- Update cors.php by @trungpv1601 in https://github.com/laravel/breeze/pull/144 +- Use `.alias` method from `Mix` by @xiCO2k in https://github.com/laravel/breeze/pull/145 + +## [v1.8.2](https://github.com/laravel/breeze/compare/v1.8.1...v1.8.2) - 2022-02-21 + +### Changed + +- Remove unused import by @MohmmedAshraf in https://github.com/laravel/breeze/pull/141 +- Add routes name to register and login paths by @alphaolomi in https://github.com/laravel/breeze/pull/140 +- Updated Inertia Version to Latest by @As1fAli in https://github.com/laravel/breeze/pull/142 + +## [v1.8.1](https://github.com/laravel/breeze/compare/v1.7.3...v1.8.1) - 2022-02-15 + +### Changed + +- Update `InitialVueStack` packages to latest by @dammy001 in https://github.com/laravel/breeze/pull/128 +- Update `InertiaReactStack` dependencies by @dammy001 in https://github.com/laravel/breeze/pull/130 +- Update `BladeStack` dependencies by @dammy001 in https://github.com/laravel/breeze/pull/129 +- Don't mix __() and trans() in the same file by @hailwood in https://github.com/laravel/breeze/pull/132 +- Group common middleware instead of duplicating by @dammy001 in https://github.com/laravel/breeze/pull/131 +- Group common middleware instead of duplicating on inertia-common by @dammy001 in https://github.com/laravel/breeze/pull/135 + +### Fixed + +- Fix assertRedirect in EmailVerificationTest when using API with pest by @lpheller in https://github.com/laravel/breeze/pull/133 + +## [v1.8.0](https://github.com/laravel/breeze/compare/v1.7.3...v1.8.0) - 2022-02-15 + +### Changed + +- Transition Inertia Vue stubs to `<script setup>` syntax by @jessarcher in https://github.com/laravel/breeze/pull/127 + +## [v1.7.3](https://github.com/laravel/breeze/compare/v1.7.2...v1.7.3) - 2022-02-15 + +### Fixed + +- Fix url replacement ([5af95ec](https://github.com/laravel/breeze/commit/5af95eca8ee2d18077347a34b74a2658c8356682)) + +## [v1.7.2](https://github.com/laravel/breeze/compare/v1.7.1...v1.7.2) - 2022-02-08 + +### Changed + +- Remove CSRF token in app layout ([#125](https://github.com/laravel/breeze/pull/125)) +- Update Inertia version ([d5f7582](https://github.com/laravel/breeze/commit/d5f7582d4bc4c6af3922eb04782b204bca32e635)) + +### Fixed + +- Api stack EmailVerificationTest assertRedirect ([#122](https://github.com/laravel/breeze/pull/122)) + +## [v1.7.1 (2022-02-01)](https://github.com/laravel/breeze/compare/v1.7.0...v1.7.1) + +### Changed + +- Fix exception throwing on older PHP versions ([#120](https://github.com/laravel/breeze/pull/120)) + +## [v1.7.0 (2022-01-12)](https://github.com/laravel/breeze/compare/v1.6.1...v1.7.0) + +### Changed + +- Laravel 9 Support ([#119](https://github.com/laravel/breeze/pull/119)) + +## [v1.6.1 (2022-01-04)](https://github.com/laravel/breeze/compare/v1.6.0...v1.6.1) + +### Changed + +- Fix Inertia Controllers @return tag and Inertia Vue Input Component [#112](https://github.com/laravel/breeze/pull/112) +- Update outdated dependencies for react stack [#114](https://github.com/laravel/breeze/pull/114) + +## [v1.6.0 (2021-12-14)](https://github.com/laravel/breeze/compare/v1.5.0...v1.6.0) + +### Changed + +- Tailwind CSS v3 support ([#110](https://github.com/laravel/breeze/pull/110)) + +## [v1.5.0 (2021-12-07)](https://github.com/laravel/breeze/compare/v1.4.3...v1.5.0) + +### Added + +- Breeze "API" / SPA Stack ([#109](https://github.com/laravel/breeze/pull/109)) + +### Changed + +- Use KeyboardEvent key attribute for Escape ([#108](https://github.com/laravel/breeze/pull/108)) + +## [v1.4.3 (2021-11-02)](https://github.com/laravel/breeze/compare/v1.4.2...v1.4.3) + +### Changed + +- Upgrade alpinejs to v3 ([#105](https://github.com/laravel/breeze/pull/105)) +- Use dashboard named routes ([#106](https://github.com/laravel/breeze/pull/106)) + +## [v1.4.2 (2021-09-28)](https://github.com/laravel/breeze/compare/v1.4.1...v1.4.2) + +### Changed + +- Change namespace ([7b39f9c](https://github.com/laravel/breeze/commit/7b39f9c114c713a7d75ceeb79b4f5efe3d4f682a)) + +## [v1.4.1 (2021-09-07)](https://github.com/laravel/breeze/compare/v1.4.0...v1.4.1) + +### Fixed + +- Fixes installation of pest on vue/react stacks ([#100](https://github.com/laravel/breeze/pull/100)) + +## [v1.4.0 (2021-08-27)](https://github.com/laravel/breeze/compare/v1.3.2...v1.4.0) + +### Added + +- Pest scaffolding ([#99](https://github.com/laravel/breeze/pull/99)) + +## [v1.3.2 (2021-08-03)](https://github.com/laravel/breeze/compare/v1.3.1...v1.3.2) + +### Changed + +- Update url for JS ([eba8457](https://github.com/laravel/breeze/commit/eba8457b2e16d92fb0909e6e4a36f7cf9f50bc78)) +- Add Vue file extension to all Vue components imported ([#89](https://github.com/laravel/breeze/pull/89)) +- Update `<Link>` tags & implement `<Head>` management (title tag) ([#90](https://github.com/laravel/breeze/pull/90), [4dce8a8](https://github.com/laravel/breeze/commit/4dce8a8c9dd1b0ca23fbe92fa51b17cc5ccd6bb5), [128fd28](https://github.com/laravel/breeze/commit/128fd28e2ebd5fde7730d90b0052d175b887568a), [#94](https://github.com/laravel/breeze/pull/94)) + +### Fixed + +- Change from POST to GET on responsive dashboard link ([#92](https://github.com/laravel/breeze/pull/92)) + +## [v1.3.1 (2021-06-22)](https://github.com/laravel/breeze/compare/v1.3.0...v1.3.1) + +### Fixed + +- Fix EmailVerificationTest to pass using Uuids ([#85](https://github.com/laravel/breeze/pull/85)) + +## [v1.3.0 (2021-06-08)](https://github.com/laravel/breeze/compare/v1.2.3...v1.3.0) + +### Changed + +- Update Inertia ([c439176](https://github.com/laravel/breeze/commit/c43917630e9b45b78dfd805f152262e08a7d2ffb)) +- Update versions ([aa90bfd](https://github.com/laravel/breeze/commit/aa90bfd5b31cedf848087d105b6924b0f120fc99)) + +## [v1.2.3 (2021-06-08)](https://github.com/laravel/breeze/compare/v1.2.2...v1.2.3) + +### Fixed + +- Fix purge line to include *.js ([#83](https://github.com/laravel/breeze/pull/83)) + +## [v1.2.2 (2021-06-01)](https://github.com/laravel/breeze/compare/v1.2.1...v1.2.2) + +### Fixed + +- Fix CORS policy errors with inertia stack ([#82](https://github.com/laravel/breeze/pull/82)) + +## [v1.2.1 (2021-05-25)](https://github.com/laravel/breeze/compare/v1.2.0...v1.2.1) + +### Fixed + +- Fix dropdown ([87e849a](https://github.com/laravel/breeze/commit/87e849a2fd635628d99aa8514e2ee9321decee27)) +- Fix link type ([c83d1ac](https://github.com/laravel/breeze/commit/c83d1ac389a58f1fb9ee6491ce14488f6a0a746b)) + +## [v1.2.0 (2021-05-20)](https://github.com/laravel/breeze/compare/v1.1.8...v1.2.0) + +### Added + +- React installation option ([#73](https://github.com/laravel/breeze/pull/73)) +- Use new `Password::defaults()` feature ([#71](https://github.com/laravel/breeze/pull/71)) + +## [v1.1.8 (2021-05-18)](https://github.com/laravel/breeze/compare/v1.1.7...v1.1.8) + +### Fixed + +- Bump Inertia version to match Spark ([#70](https://github.com/laravel/breeze/pull/70)) + +## [v1.1.7 (2021-05-11)](https://github.com/laravel/breeze/compare/v1.1.6...v1.1.7) + +### Changed + +- Uses password rule by default ([#65](https://github.com/laravel/breeze/pull/65)) + +### Fixed + +- Use boolean() instead of filled() ([#68](https://github.com/laravel/breeze/pull/68)) +- Fix create method docblock return value ([#69](https://github.com/laravel/breeze/pull/69)) + +## [v1.1.6 (2021-04-27)](https://github.com/laravel/breeze/compare/v1.1.5...v1.1.6) + +### Fixed + +- Fix Vue warning ([#62](https://github.com/laravel/breeze/pull/62)) + +## [v1.1.5 (2021-04-13)](https://github.com/laravel/breeze/compare/v1.1.4...v1.1.5) + +### Fixed + +- Fix Login event firing before Register ([#59](https://github.com/laravel/breeze/pull/59)) + +## [v1.1.4 (2021-03-23)](https://github.com/laravel/breeze/compare/v1.1.3...v1.1.4) + +### Fixed + +- Fixes Vue warning ([#55](https://github.com/laravel/breeze/pull/55)) + +### Removed + +- Remove unused component ([#54](https://github.com/laravel/breeze/pull/54)) + +## [v1.1.3 (2021-02-18)](https://github.com/laravel/breeze/compare/v1.1.2...v1.1.3) + +### Fixed + +- Update stubs/inertia/app case in installInertiaStack ([#53](https://github.com/laravel/breeze/pull/53)) + +## [v1.1.2 (2021-02-18)](https://github.com/laravel/breeze/compare/v1.1.1...v1.1.2) + +### Changed + +- Add `@inertiajs/progress` to package dependencies ([#46](https://github.com/laravel/breeze/pull/46), [#49](https://github.com/laravel/breeze/pull/49)) +- Reduce verbosity by introducing a 'Guest' layout ([#52](https://github.com/laravel/breeze/pull/52)) +- Add email (username) autocomplete ([#51](https://github.com/laravel/breeze/pull/51)) +- Simplify Inertia logout links ([#48](https://github.com/laravel/breeze/pull/48)) + +## [v1.1.1 (2021-02-17)](https://github.com/laravel/breeze/compare/v1.0.4...v1.1.1) + +### Added + +- Inertia Stack ([#44)](https://github.com/laravel/breeze/pull/44)) + +### Fixed + +- Copy webpack.config.js on inertia init ([#45](https://github.com/laravel/breeze/pull/45)) + +## [v1.0.4 (2021-02-16)](https://github.com/laravel/breeze/compare/v1.0.3...v1.0.4) + +### Changed + +- Update Tailwind config ([de0cbf4](https://github.com/laravel/breeze/commit/de0cbf49b50c22aaf047dcaba8c83827164ff668)) + +## [v1.0.3 (2021-02-16)](https://github.com/laravel/breeze/compare/v1.0.2...v1.0.3) + +### Fixed + +- Redirect to intended path after login ([#39](https://github.com/laravel/breeze/pull/39)) +- Change "Logout" text to "Log out" and "Login" to "Log in" ([#41](https://github.com/laravel/breeze/pull/41)) + +## [v1.0.2 (2021-01-05)](https://github.com/laravel/breeze/compare/v1.0.1...v1.0.2) + +### Changed + +- Upgrade to PostCSS 8 as Laravel Mix v6 is out ([#31](https://github.com/laravel/breeze/pull/31)) + +## [v1.0.1 (2020-12-22)](https://github.com/laravel/breeze/compare/v1.0.0...v1.0.1) + +### Changed + +- Reuse blade component ([#30](https://github.com/laravel/breeze/pull/30)) +- Improve SPA compatibility ([#29](https://github.com/laravel/breeze/pull/29)) + +## v1.0.0 (2020-10-08) + +Initial stable release.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE.md Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Taylor Otwell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,1 @@ +This basic authentication for Laravel.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UPGRADE.md Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,10 @@ +# Upgrade Guide + +## Upgrading from Breeze 1.x to Breeze 2.x + +#### Dependency Changes + +Unlike other starter kits such as Jetstream, the Laravel Breeze dependency can be removed after you run the `breeze:install` Artisan command. Therefore, if you are in the process of upgrading to Laravel 11, we advise you to simply remove the `laravel/breeze` dependency from your application's `composer.json` file. Then, run the `composer update` command: + + composer update +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/composer.json Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,40 @@ +{ + "name": "wizzard/auth", + "description": "Minimal Laravel authentication scaffolding with Blade and Bootstrap.", + "keywords": ["wizard", "auth"], + "license": "MIT", + "authors": [ + { + } + ], + "require": { + "php": "^8.2.0", + "illuminate/console": "^11.0|^12.0", + "illuminate/filesystem": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "illuminate/validation": "^11.0|^12.0", + "symfony/console": "^7.0" + }, + "require-dev": { + "laravel/framework": "^11.0|^12.0", + "orchestra/testbench-core": "^9.0|^10.0", + "phpstan/phpstan": "^2.0" + }, + "autoload": { + "psr-4": { + "Laravel\\Breeze\\": "src/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Wizard\\Auth\\AuthServiceProvider" + ] + } + }, + "config": { + "sort-packages": true + }, + "minimum-stability": "dev", + "prefer-stable": true +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/AuthServiceProvider.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,45 @@ +<?php + +namespace Wizard\Auth; + +use Illuminate\Contracts\Support\DeferrableProvider; +use Illuminate\Support\ServiceProvider; + +class AuthServiceProvider extends ServiceProvider implements DeferrableProvider +{ + /** + * Register any application services. + * + * @return void + */ + public function register() + { + // + } + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + if (! $this->app->runningInConsole()) { + return; + } + + $this->commands([ + Console\InstallCommand::class, + ]); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return [Console\InstallCommand::class]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Console/InstallCommand.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,379 @@ +<?php + +namespace Wizard\Auth\Console; + +use Illuminate\Console\Command; +use Illuminate\Contracts\Console\PromptsForMissingInput; +use Illuminate\Filesystem\Filesystem; +use Illuminate\Support\Arr; +use Illuminate\Support\Str; +use RuntimeException; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Finder\Finder; +use Symfony\Component\Process\PhpExecutableFinder; +use Symfony\Component\Process\Process; + +use function Laravel\Prompts\confirm; +use function Laravel\Prompts\multiselect; +use function Laravel\Prompts\select; + +#[AsCommand(name: 'breeze:install')] +class InstallCommand extends Command implements PromptsForMissingInput +{ + use InstallsBladeStack; + + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'breeze:install {stack : The development stack that should be installed (blade)}'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Install the Breeze controllers and resources'; + + /** + * Execute the console command. + * + * @return int|null + */ + public function handle() + { + return $this->installBladeStack(); + } + + /** + * Install Breeze's tests. + * + * @return bool + */ + protected function installTests() + { + (new Filesystem)->ensureDirectoryExists(base_path('tests/Feature')); + + $stubStack = match ($this->argument('stack')) { + default => 'default', + }; + + (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/'.$stubStack.'/tests/Feature', base_path('tests/Feature')); + + return true; + } + + /** + * Install the given middleware names into the application. + * + * @param array|string $name + * @param string $group + * @param string $modifier + * @return void + */ + protected function installMiddleware($names, $group = 'web', $modifier = 'append') + { + $bootstrapApp = file_get_contents(base_path('bootstrap/app.php')); + + $names = collect(Arr::wrap($names)) + ->filter(fn ($name) => ! Str::contains($bootstrapApp, $name)) + ->whenNotEmpty(function ($names) use ($bootstrapApp, $group, $modifier) { + $names = $names->map(fn ($name) => "$name")->implode(','.PHP_EOL.' '); + + $stubs = [ + '->withMiddleware(function (Middleware $middleware) {', + '->withMiddleware(function (Middleware $middleware): void {', + ]; + + $bootstrapApp = str_replace( + $stubs, + collect($stubs)->transform(fn ($stub) => $stub + .PHP_EOL." \$middleware->$group($modifier: [" + .PHP_EOL." $names," + .PHP_EOL.' ]);' + .PHP_EOL + )->all(), + $bootstrapApp, + ); + + file_put_contents(base_path('bootstrap/app.php'), $bootstrapApp); + }); + } + + /** + * Install the given middleware aliases into the application. + * + * @param array $aliases + * @return void + */ + protected function installMiddlewareAliases($aliases) + { + $bootstrapApp = file_get_contents(base_path('bootstrap/app.php')); + + $aliases = collect($aliases) + ->filter(fn ($alias) => ! Str::contains($bootstrapApp, $alias)) + ->whenNotEmpty(function ($aliases) use ($bootstrapApp) { + $aliases = $aliases->map(fn ($name, $alias) => "'$alias' => $name")->implode(','.PHP_EOL.' '); + + $stubs = [ + '->withMiddleware(function (Middleware $middleware) {', + '->withMiddleware(function (Middleware $middleware): void {', + ]; + + $bootstrapApp = str_replace( + $stubs, + collect($stubs)->transform(fn ($stub) => $stub + .PHP_EOL.' $middleware->alias([' + .PHP_EOL." $aliases," + .PHP_EOL.' ]);' + .PHP_EOL + )->all(), + $bootstrapApp, + ); + + file_put_contents(base_path('bootstrap/app.php'), $bootstrapApp); + }); + } + + /** + * Determine if the given Composer package is installed. + * + * @param string $package + * @return bool + */ + protected function hasComposerPackage($package) + { + $packages = json_decode(file_get_contents(base_path('composer.json')), true); + + return array_key_exists($package, $packages['require'] ?? []) + || array_key_exists($package, $packages['require-dev'] ?? []); + } + + /** + * Installs the given Composer Packages into the application. + * + * @param bool $asDev + * @return bool + */ + protected function requireComposerPackages(array $packages, $asDev = false) + { + $composer = $this->option('composer'); + + if ($composer !== 'global') { + $command = ['php', $composer, 'require']; + } + + $command = array_merge( + $command ?? ['composer', 'require'], + $packages, + $asDev ? ['--dev'] : [], + ); + + return (new Process($command, base_path(), ['COMPOSER_MEMORY_LIMIT' => '-1'])) + ->setTimeout(null) + ->run(function ($type, $output) { + $this->output->write($output); + }) === 0; + } + + /** + * Removes the given Composer Packages from the application. + * + * @param bool $asDev + * @return bool + */ + protected function removeComposerPackages(array $packages, $asDev = false) + { + $composer = $this->option('composer'); + + if ($composer !== 'global') { + $command = ['php', $composer, 'remove']; + } + + $command = array_merge( + $command ?? ['composer', 'remove'], + $packages, + $asDev ? ['--dev'] : [], + ); + + return (new Process($command, base_path(), ['COMPOSER_MEMORY_LIMIT' => '-1'])) + ->setTimeout(null) + ->run(function ($type, $output) { + $this->output->write($output); + }) === 0; + } + + /** + * Update the dependencies in the "package.json" file. + * + * @param bool $dev + * @return void + */ + protected static function updateNodePackages(callable $callback, $dev = true) + { + if (! file_exists(base_path('package.json'))) { + return; + } + + $configurationKey = $dev ? 'devDependencies' : 'dependencies'; + + $packages = json_decode(file_get_contents(base_path('package.json')), true); + + $packages[$configurationKey] = $callback( + array_key_exists($configurationKey, $packages) ? $packages[$configurationKey] : [], + $configurationKey + ); + + ksort($packages[$configurationKey]); + + file_put_contents( + base_path('package.json'), + json_encode($packages, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL + ); + } + + /** + * Update the scripts in the "package.json" file. + * + * @return void + */ + protected static function updateNodeScripts(callable $callback) + { + if (! file_exists(base_path('package.json'))) { + return; + } + + $content = json_decode(file_get_contents(base_path('package.json')), true); + + $content['scripts'] = $callback( + array_key_exists('scripts', $content) ? $content['scripts'] : [] + ); + + file_put_contents( + base_path('package.json'), + json_encode($content, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL + ); + } + + /** + * Delete the "node_modules" directory and remove the associated lock files. + * + * @return void + */ + protected static function flushNodeModules() + { + tap(new Filesystem, function ($files) { + $files->deleteDirectory(base_path('node_modules')); + + $files->delete(base_path('pnpm-lock.yaml')); + $files->delete(base_path('yarn.lock')); + $files->delete(base_path('bun.lock')); + $files->delete(base_path('bun.lockb')); + $files->delete(base_path('deno.lock')); + $files->delete(base_path('package-lock.json')); + }); + } + + /** + * Replace a given string within a given file. + * + * @param string $search + * @param string $replace + * @param string $path + * @return void + */ + protected function replaceInFile($search, $replace, $path) + { + file_put_contents($path, str_replace($search, $replace, file_get_contents($path))); + } + + /** + * Get the path to the appropriate PHP binary. + * + * @return string + */ + protected function phpBinary() + { + if (function_exists('Illuminate\Support\php_binary')) { + return \Illuminate\Support\php_binary(); + } + + return (new PhpExecutableFinder)->find(false) ?: 'php'; + } + + /** + * Run the given commands. + * + * @param array $commands + * @return void + */ + protected function runCommands($commands) + { + $process = Process::fromShellCommandline(implode(' && ', $commands), null, null, null, null); + + if ('\\' !== DIRECTORY_SEPARATOR && file_exists('/dev/tty') && is_readable('/dev/tty')) { + try { + $process->setTty(true); + } catch (RuntimeException $e) { + $this->output->writeln(' <bg=yellow;fg=black> WARN </> '.$e->getMessage().PHP_EOL); + } + } + + $process->run(function ($type, $line) { + $this->output->write(' '.$line); + }); + } + + /** + * Remove Tailwind dark classes from the given files. + * + * @return void + */ + protected function removeDarkClasses(Finder $finder) + { + foreach ($finder as $file) { + file_put_contents($file->getPathname(), preg_replace('/\sdark:[^\s"\']+/', '', $file->getContents())); + } + } + + /** + * Prompt for missing input arguments using the returned questions. + * + * @return array + */ + protected function promptForMissingArgumentsUsing() + { + return [ + 'stack' => fn () => select( + label: 'Which Breeze stack would you like to install?', + options: [ + 'blade' => 'Blade', + ], + scroll: 6, + ), + ]; + } + + /** + * Interact further with the user if they were prompted for missing arguments. + * + * @return void + */ + protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output) + { + $stack = $input->getArgument('stack'); + } + + /** + * Determine whether the project is already using Pest. + * + * @return bool + */ + protected function isUsingPest() + { + return class_exists(\Pest\TestSuite::class); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Console/InstallsBladeStack.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,87 @@ +<?php + +namespace Wizard\Auth\Console; + +use Illuminate\Filesystem\Filesystem; +use Symfony\Component\Finder\Finder; + +trait InstallsBladeStack +{ + /** + * Install the Blade Breeze stack. + * + * @return int|null + */ + protected function installBladeStack() + { + // NPM Packages... + $this->updateNodePackages(function ($packages) { + return [ + "@popperjs/core" => "^2.11.8", + "bootstrap" => "^5.3.0", + ] + $packages; + }); + + // Controllers... + (new Filesystem)->ensureDirectoryExists(app_path('Http/Controllers')); + (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/app/Http/Controllers', app_path('Http/Controllers')); + + // Requests... + (new Filesystem)->ensureDirectoryExists(app_path('Http/Requests')); + (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/app/Http/Requests', app_path('Http/Requests')); + + // Views... + (new Filesystem)->ensureDirectoryExists(resource_path('views')); + (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/resources/views', resource_path('views')); + + if (! $this->option('dark')) { + $this->removeDarkClasses((new Finder) + ->in(resource_path('views')) + ->name('*.blade.php') + ->notPath('livewire/welcome/navigation.blade.php') + ->notName('welcome.blade.php') + ); + } + + // Components... + (new Filesystem)->ensureDirectoryExists(app_path('View/Components')); + (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/default/app/View/Components', app_path('View/Components')); + + // Tests... + if (! $this->installTests()) { + return 1; + } + + // Routes... + copy(__DIR__.'/../../stubs/default/routes/web.php', base_path('routes/web.php')); + copy(__DIR__.'/../../stubs/default/routes/auth.php', base_path('routes/auth.php')); + + // "Dashboard" Route... + $this->replaceInFile('/home', '/dashboard', resource_path('views/welcome.blade.php')); + $this->replaceInFile('Home', 'Dashboard', resource_path('views/welcome.blade.php')); + + // Tailwind / Vite... + copy(__DIR__.'/../../stubs/default/tailwind.config.js', base_path('tailwind.config.js')); + copy(__DIR__.'/../../stubs/default/postcss.config.js', base_path('postcss.config.js')); + copy(__DIR__.'/../../stubs/default/vite.config.js', base_path('vite.config.js')); + copy(__DIR__.'/../../stubs/default/resources/css/app.css', resource_path('css/app.css')); + copy(__DIR__.'/../../stubs/default/resources/js/app.js', resource_path('js/app.js')); + + $this->components->info('Installing and building Node dependencies.'); + + if (file_exists(base_path('pnpm-lock.yaml'))) { + $this->runCommands(['pnpm install', 'pnpm run build']); + } elseif (file_exists(base_path('yarn.lock'))) { + $this->runCommands(['yarn install', 'yarn run build']); + } elseif (file_exists(base_path('bun.lock')) || file_exists(base_path('bun.lockb'))) { + $this->runCommands(['bun install', 'bun run build']); + } elseif (file_exists(base_path('deno.lock'))) { + $this->runCommands(['deno install', 'deno task build']); + } else { + $this->runCommands(['npm install', 'npm run build']); + } + + $this->line(''); + $this->components->info('Breeze scaffolding installed successfully.'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/AuthenticatedSessionController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,47 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Http\Requests\Auth\LoginRequest; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\View\View; + +class AuthenticatedSessionController extends Controller +{ + /** + * Display the login view. + */ + public function create(): View + { + return view('auth.login'); + } + + /** + * Handle an incoming authentication request. + */ + public function store(LoginRequest $request): RedirectResponse + { + $request->authenticate(); + + $request->session()->regenerate(); + + return redirect()->intended(route('dashboard', absolute: false)); + } + + /** + * Destroy an authenticated session. + */ + public function destroy(Request $request): RedirectResponse + { + Auth::guard('web')->logout(); + + $request->session()->invalidate(); + + $request->session()->regenerateToken(); + + return redirect('/'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/ConfirmablePasswordController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,40 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\Validation\ValidationException; +use Illuminate\View\View; + +class ConfirmablePasswordController extends Controller +{ + /** + * Show the confirm password view. + */ + public function show(): View + { + return view('auth.confirm-password'); + } + + /** + * Confirm the user's password. + */ + public function store(Request $request): RedirectResponse + { + if (! Auth::guard('web')->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('dashboard', absolute: false)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/EmailVerificationNotificationController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,24 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; + +class EmailVerificationNotificationController extends Controller +{ + /** + * Send a new email verification notification. + */ + public function store(Request $request): RedirectResponse + { + if ($request->user()->hasVerifiedEmail()) { + return redirect()->intended(route('dashboard', absolute: false)); + } + + $request->user()->sendEmailVerificationNotification(); + + return back()->with('status', 'verification-link-sent'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/EmailVerificationPromptController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,21 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\View\View; + +class EmailVerificationPromptController extends Controller +{ + /** + * Display the email verification prompt. + */ + public function __invoke(Request $request): RedirectResponse|View + { + return $request->user()->hasVerifiedEmail() + ? redirect()->intended(route('dashboard', absolute: false)) + : view('auth.verify-email'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/NewPasswordController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,62 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Models\User; +use Illuminate\Auth\Events\PasswordReset; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Password; +use Illuminate\Support\Str; +use Illuminate\Validation\Rules; +use Illuminate\View\View; + +class NewPasswordController extends Controller +{ + /** + * Display the password reset view. + */ + public function create(Request $request): View + { + return view('auth.reset-password', ['request' => $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)]); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/PasswordController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,29 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Hash; +use Illuminate\Validation\Rules\Password; + +class PasswordController extends Controller +{ + /** + * Update the user's password. + */ + public function update(Request $request): RedirectResponse + { + $validated = $request->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'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/PasswordResetLinkController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,44 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Password; +use Illuminate\View\View; + +class PasswordResetLinkController extends Controller +{ + /** + * Display the password reset link request view. + */ + public function create(): View + { + return view('auth.forgot-password'); + } + + /** + * Handle an incoming password reset link request. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function store(Request $request): RedirectResponse + { + $request->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)]); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/RegisteredUserController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,50 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use App\Models\User; +use Illuminate\Auth\Events\Registered; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Hash; +use Illuminate\Validation\Rules; +use Illuminate\View\View; + +class RegisteredUserController extends Controller +{ + /** + * Display the registration view. + */ + public function create(): View + { + return view('auth.register'); + } + + /** + * Handle an incoming registration request. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function store(Request $request): RedirectResponse + { + $request->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)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/Auth/VerifyEmailController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,27 @@ +<?php + +namespace App\Http\Controllers\Auth; + +use App\Http\Controllers\Controller; +use Illuminate\Auth\Events\Verified; +use Illuminate\Foundation\Auth\EmailVerificationRequest; +use Illuminate\Http\RedirectResponse; + +class VerifyEmailController extends Controller +{ + /** + * Mark the authenticated user's email address as verified. + */ + public function __invoke(EmailVerificationRequest $request): RedirectResponse + { + if ($request->user()->hasVerifiedEmail()) { + return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); + } + + if ($request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); + } + + return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Controllers/ProfileController.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,60 @@ +<?php + +namespace App\Http\Controllers; + +use App\Http\Requests\ProfileUpdateRequest; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Redirect; +use Illuminate\View\View; + +class ProfileController extends Controller +{ + /** + * Display the user's profile form. + */ + public function edit(Request $request): View + { + return view('profile.edit', [ + 'user' => $request->user(), + ]); + } + + /** + * 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.edit')->with('status', 'profile-updated'); + } + + /** + * Delete the user's account. + */ + public function destroy(Request $request): RedirectResponse + { + $request->validateWithBag('userDeletion', [ + 'password' => ['required', 'current_password'], + ]); + + $user = $request->user(); + + Auth::logout(); + + $user->delete(); + + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return Redirect::to('/'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Requests/Auth/LoginRequest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,85 @@ +<?php + +namespace App\Http\Requests\Auth; + +use Illuminate\Auth\Events\Lockout; +use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\RateLimiter; +use Illuminate\Support\Str; +use Illuminate\Validation\ValidationException; + +class LoginRequest extends FormRequest +{ + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string> + */ + public function rules(): array + { + return [ + 'email' => ['required', 'string', 'email'], + 'password' => ['required', 'string'], + ]; + } + + /** + * Attempt to authenticate the request's credentials. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function authenticate(): void + { + $this->ensureIsNotRateLimited(); + + if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) { + RateLimiter::hit($this->throttleKey()); + + throw ValidationException::withMessages([ + 'email' => trans('auth.failed'), + ]); + } + + RateLimiter::clear($this->throttleKey()); + } + + /** + * Ensure the login request is not rate limited. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function ensureIsNotRateLimited(): void + { + if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) { + return; + } + + event(new Lockout($this)); + + $seconds = RateLimiter::availableIn($this->throttleKey()); + + throw ValidationException::withMessages([ + 'email' => trans('auth.throttle', [ + 'seconds' => $seconds, + 'minutes' => ceil($seconds / 60), + ]), + ]); + } + + /** + * Get the rate limiting throttle key for the request. + */ + public function throttleKey(): string + { + return Str::transliterate(Str::lower($this->string('email')).'|'.$this->ip()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/Http/Requests/ProfileUpdateRequest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,30 @@ +<?php + +namespace App\Http\Requests; + +use App\Models\User; +use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Validation\Rule; + +class ProfileUpdateRequest extends FormRequest +{ + /** + * Get the validation rules that apply to the request. + * + * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string> + */ + public function rules(): array + { + return [ + 'name' => ['required', 'string', 'max:255'], + 'email' => [ + 'required', + 'string', + 'lowercase', + 'email', + 'max:255', + Rule::unique(User::class)->ignore($this->user()->id), + ], + ]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/View/Components/AppLayout.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,17 @@ +<?php + +namespace App\View\Components; + +use Illuminate\View\Component; +use Illuminate\View\View; + +class AppLayout extends Component +{ + /** + * Get the view / contents that represents the component. + */ + public function render(): View + { + return view('layouts.app'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/app/View/Components/GuestLayout.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,17 @@ +<?php + +namespace App\View\Components; + +use Illuminate\View\Component; +use Illuminate\View\View; + +class GuestLayout extends Component +{ + /** + * Get the view / contents that represents the component. + */ + public function render(): View + { + return view('layouts.guest'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/Auth/AuthenticationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,41 @@ +<?php + +use App\Models\User; + +test('login screen can be rendered', function () { + $response = $this->get('/login'); + + $response->assertStatus(200); +}); + +test('users can authenticate using the login screen', function () { + $user = User::factory()->create(); + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard', absolute: false)); +}); + +test('users can not authenticate with invalid password', function () { + $user = User::factory()->create(); + + $this->post('/login', [ + 'email' => $user->email, + 'password' => 'wrong-password', + ]); + + $this->assertGuest(); +}); + +test('users can logout', function () { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/logout'); + + $this->assertGuest(); + $response->assertRedirect('/'); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/Auth/EmailVerificationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,46 @@ +<?php + +use App\Models\User; +use Illuminate\Auth\Events\Verified; +use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\URL; + +test('email verification screen can be rendered', function () { + $user = User::factory()->unverified()->create(); + + $response = $this->actingAs($user)->get('/verify-email'); + + $response->assertStatus(200); +}); + +test('email can be verified', function () { + $user = User::factory()->unverified()->create(); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)] + ); + + $response = $this->actingAs($user)->get($verificationUrl); + + Event::assertDispatched(Verified::class); + expect($user->fresh()->hasVerifiedEmail())->toBeTrue(); + $response->assertRedirect(route('dashboard', absolute: false).'?verified=1'); +}); + +test('email is not verified with invalid hash', function () { + $user = User::factory()->unverified()->create(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1('wrong-email')] + ); + + $this->actingAs($user)->get($verificationUrl); + + expect($user->fresh()->hasVerifiedEmail())->toBeFalse(); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/Auth/PasswordConfirmationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,32 @@ +<?php + +use App\Models\User; + +test('confirm password screen can be rendered', function () { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->get('/confirm-password'); + + $response->assertStatus(200); +}); + +test('password can be confirmed', function () { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'password', + ]); + + $response->assertRedirect(); + $response->assertSessionHasNoErrors(); +}); + +test('password is not confirmed with invalid password', function () { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'wrong-password', + ]); + + $response->assertSessionHasErrors(); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/Auth/PasswordResetTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,60 @@ +<?php + +use App\Models\User; +use Illuminate\Auth\Notifications\ResetPassword; +use Illuminate\Support\Facades\Notification; + +test('reset password link screen can be rendered', function () { + $response = $this->get('/forgot-password'); + + $response->assertStatus(200); +}); + +test('reset password link can be requested', function () { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class); +}); + +test('reset password screen can be rendered', function () { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { + $response = $this->get('/reset-password/'.$notification->token); + + $response->assertStatus(200); + + return true; + }); +}); + +test('password can be reset with valid token', function () { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { + $response = $this->post('/reset-password', [ + 'token' => $notification->token, + 'email' => $user->email, + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('login')); + + return true; + }); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/Auth/PasswordUpdateTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,40 @@ +<?php + +use App\Models\User; +use Illuminate\Support\Facades\Hash; + +test('password can be updated', function () { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $this->assertTrue(Hash::check('new-password', $user->refresh()->password)); +}); + +test('correct password must be provided to update password', function () { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'wrong-password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasErrorsIn('updatePassword', 'current_password') + ->assertRedirect('/profile'); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/Auth/RegistrationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,19 @@ +<?php + +test('registration screen can be rendered', function () { + $response = $this->get('/register'); + + $response->assertStatus(200); +}); + +test('new users can register', function () { + $response = $this->post('/register', [ + 'name' => 'Test User', + 'email' => 'test@example.com', + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard', absolute: false)); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/ExampleTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,7 @@ +<?php + +it('returns a successful response', function () { + $response = $this->get('/'); + + $response->assertStatus(200); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Feature/ProfileTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,85 @@ +<?php + +use App\Models\User; + +test('profile page is displayed', function () { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->get('/profile'); + + $response->assertOk(); +}); + +test('profile information can be updated', function () { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->patch('/profile', [ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $user->refresh(); + + $this->assertSame('Test User', $user->name); + $this->assertSame('test@example.com', $user->email); + $this->assertNull($user->email_verified_at); +}); + +test('email verification status is unchanged when the email address is unchanged', function () { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->patch('/profile', [ + 'name' => 'Test User', + 'email' => $user->email, + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $this->assertNotNull($user->refresh()->email_verified_at); +}); + +test('user can delete their account', function () { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->delete('/profile', [ + 'password' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/'); + + $this->assertGuest(); + $this->assertNull($user->fresh()); +}); + +test('correct password must be provided to delete account', function () { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->delete('/profile', [ + 'password' => 'wrong-password', + ]); + + $response + ->assertSessionHasErrorsIn('userDeletion', 'password') + ->assertRedirect('/profile'); + + $this->assertNotNull($user->fresh()); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Pest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,47 @@ +<?php + +/* +|-------------------------------------------------------------------------- +| Test Case +|-------------------------------------------------------------------------- +| +| The closure you provide to your test functions is always bound to a specific PHPUnit test +| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may +| need to change it using the "pest()" function to bind a different classes or traits. +| +*/ + +pest()->extend(Tests\TestCase::class) + ->use(Illuminate\Foundation\Testing\RefreshDatabase::class) + ->in('Feature'); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +expect()->extend('toBeOne', function () { + return $this->toBe(1); +}); + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +function something() +{ + // .. +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/pest-tests/Unit/ExampleTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,5 @@ +<?php + +test('that true is true', function () { + expect(true)->toBeTrue(); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/auth/confirm-password.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,27 @@ +<x-guest-layout> + <div class="mb-4 text-muted"> + {{ __('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 class="mb-3"> + <x-input-label for="password" :value="__('Password')" /> + + <x-text-input id="password" class="form-control" + type="password" + name="password" + required autocomplete="current-password" /> + + <x-input-error :messages="$errors->get('password')" class="mt-2" /> + </div> + + <div class="d-flex justify-content-end mt-4"> + <x-primary-button> + {{ __('Confirm') }} + </x-primary-button> + </div> + </form> +</x-guest-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/auth/forgot-password.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,25 @@ +<x-guest-layout> + <div class="mb-4 text-muted"> + {{ __('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 class="mb-3"> + <x-input-label for="email" :value="__('Email')" /> + <x-text-input id="email" class="form-control" type="email" name="email" :value="old('email')" required autofocus /> + <x-input-error :messages="$errors->get('email')" class="mt-2" /> + </div> + + <div class="d-flex justify-content-end mt-4"> + <x-primary-button> + {{ __('Email Password Reset Link') }} + </x-primary-button> + </div> + </form> +</x-guest-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/auth/login.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,42 @@ +<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 class="mb-3"> + <x-input-label for="email" :value="__('Email')" /> + <x-text-input id="email" class="form-control" 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="mb-3"> + <x-input-label for="password" :value="__('Password')" /> + <x-text-input id="password" class="form-control" type="password" name="password" required autocomplete="current-password" /> + <x-input-error :messages="$errors->get('password')" class="mt-2" /> + </div> + + <!-- Remember Me --> + <div class="form-check mb-3"> + <input id="remember_me" type="checkbox" class="form-check-input" name="remember"> + <label for="remember_me" class="form-check-label"> + {{ __('Remember me') }} + </label> + </div> + + <div class="d-flex justify-content-end"> + @if (Route::has('password.request')) + <a class="text-decoration-underline text-muted me-3" href="{{ route('password.request') }}"> + {{ __('Forgot your password?') }} + </a> + @endif + + <x-primary-button class="btn btn-primary"> + {{ __('Log in') }} + </x-primary-button> + </div> + </form> +</x-guest-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/auth/register.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,52 @@ +<x-guest-layout> + <form method="POST" action="{{ route('register') }}"> + @csrf + + <!-- Name --> + <div class="mb-3"> + <x-input-label for="name" :value="__('Name')" /> + <x-text-input id="name" class="form-control" 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="mb-3"> + <x-input-label for="email" :value="__('Email')" /> + <x-text-input id="email" class="form-control" type="email" name="email" :value="old('email')" required autocomplete="username" /> + <x-input-error :messages="$errors->get('email')" class="mt-2" /> + </div> + + <!-- Password --> + <div class="mb-3"> + <x-input-label for="password" :value="__('Password')" /> + + <x-text-input id="password" class="form-control" + type="password" + name="password" + required autocomplete="new-password" /> + + <x-input-error :messages="$errors->get('password')" class="mt-2" /> + </div> + + <!-- Confirm Password --> + <div class="mb-3"> + <x-input-label for="password_confirmation" :value="__('Confirm Password')" /> + + <x-text-input id="password_confirmation" class="form-control" + type="password" + name="password_confirmation" required autocomplete="new-password" /> + + <x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" /> + </div> + + <div class="d-flex justify-content-end mt-4"> + <a class="text-decoration-underline text-muted me-4" href="{{ route('login') }}"> + {{ __('Already registered?') }} + </a> + + <x-primary-button class="btn btn-primary"> + {{ __('Register') }} + </x-primary-button> + </div> + </form> +</x-guest-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/auth/reset-password.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,35 @@ +<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 class="mb-3"> + <x-input-label for="email" :value="__('Email')" /> + <x-text-input id="email" class="form-control" 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="mb-3"> + <x-input-label for="password" :value="__('Password')" /> + <x-text-input id="password" class="form-control" type="password" name="password" required autocomplete="new-password" /> + <x-input-error :messages="$errors->get('password')" class="mt-2" /> + </div> + + <!-- Confirm Password --> + <div class="mb-3"> + <x-input-label for="password_confirmation" :value="__('Confirm Password')" /> + <x-text-input id="password_confirmation" class="form-control" type="password" name="password_confirmation" required autocomplete="new-password" /> + <x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" /> + </div> + + <div class="d-flex justify-content-end mt-4"> + <x-primary-button> + {{ __('Reset Password') }} + </x-primary-button> + </div> + </form> +</x-guest-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/auth/verify-email.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,31 @@ +<x-guest-layout> + <div class="mb-4 text-muted"> + {{ __('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-weight-medium text-success"> + {{ __('A new verification link has been sent to the email address you provided during registration.') }} + </div> + @endif + + <div class="mt-4 d-flex align-items-center justify-content-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="text-decoration-underline text-muted hover:text-dark rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"> + {{ __('Log Out') }} + </button> + </form> + </div> +</x-guest-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/application-logo.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -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>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/auth-session-status.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,7 @@ +@props(['status']) + +@if ($status) + <div {{ $attributes->merge(['class' => 'font-medium text-sm text-green-600 dark:text-green-400']) }}> + {{ $status }} + </div> +@endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/danger-button.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -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 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150']) }}> + {{ $slot }} +</button>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/dropdown-link.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,1 @@ +<a {{ $attributes->merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out']) }}>{{ $slot }}</a>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/dropdown.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,35 @@ +@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-gray-700']) + +@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>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/input-error.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,9 @@ +@props(['messages']) + +@if ($messages) + <ul {{ $attributes->merge(['class' => 'text-sm text-red-600 dark:text-red-400 space-y-1']) }}> + @foreach ((array) $messages as $message) + <li>{{ $message }}</li> + @endforeach + </ul> +@endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/input-label.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,5 @@ +@props(['value']) + +<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700 dark:text-gray-300']) }}> + {{ $value ?? $slot }} +</label>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/modal.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -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 dark:bg-gray-900 opacity-75"></div> + </div> + + <div + x-show="show" + class="mb-6 bg-white dark:bg-gray-800 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>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/nav-link.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,11 @@ +@props(['active']) + +@php +$classes = ($active ?? false) + ? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 dark:border-indigo-600 text-sm font-medium leading-5 text-gray-900 dark:text-gray-100 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 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-700 focus:outline-none focus:text-gray-700 dark:focus:text-gray-300 focus:border-gray-300 dark:focus:border-gray-700 transition duration-150 ease-in-out'; +@endphp + +<a {{ $attributes->merge(['class' => $classes]) }}> + {{ $slot }} +</a>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/primary-button.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,3 @@ +<button {{ $attributes->merge(['type' => 'submit', 'class' => 'inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150']) }}> + {{ $slot }} +</button>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/responsive-nav-link.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -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 dark:border-indigo-600 text-start text-base font-medium text-indigo-700 dark:text-indigo-300 bg-indigo-50 dark:bg-indigo-900/50 focus:outline-none focus:text-indigo-800 dark:focus:text-indigo-200 focus:bg-indigo-100 dark:focus:bg-indigo-900 focus:border-indigo-700 dark:focus:border-indigo-300 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 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:border-gray-300 dark:hover:border-gray-600 focus:outline-none focus:text-gray-800 dark:focus:text-gray-200 focus:bg-gray-50 dark:focus:bg-gray-700 focus:border-gray-300 dark:focus:border-gray-600 transition duration-150 ease-in-out'; +@endphp + +<a {{ $attributes->merge(['class' => $classes]) }}> + {{ $slot }} +</a>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/secondary-button.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,3 @@ +<button {{ $attributes->merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-500 rounded-md font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150']) }}> + {{ $slot }} +</button>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/components/text-input.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,3 @@ +@props(['disabled' => false]) + +<input @disabled($disabled) {{ $attributes->merge(['class' => 'border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm']) }}>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/dashboard.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,17 @@ +<x-app-layout> + <x-slot name="header"> + <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 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 dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg"> + <div class="p-6 text-gray-900 dark:text-gray-100"> + {{ __("You're logged in!") }} + </div> + </div> + </div> + </div> +</x-app-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/layouts/app.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -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 dark:bg-gray-900"> + @include('layouts.navigation') + + <!-- Page Heading --> + @isset($header) + <header class="bg-white dark:bg-gray-800 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>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/layouts/guest.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -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 dark:bg-gray-900"> + <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 dark:bg-gray-800 shadow-md overflow-hidden sm:rounded-lg"> + {{ $slot }} + </div> + </div> + </body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/layouts/navigation.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,100 @@ +<nav x-data="{ open: false }" class="bg-white dark:bg-gray-800 border-b border-gray-100 dark:border-gray-700"> + <!-- 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 dark:text-gray-200" /> + </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 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 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 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-900 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-900 focus:text-gray-500 dark:focus:text-gray-400 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 dark:border-gray-600"> + <div class="px-4"> + <div class="font-medium text-base text-gray-800 dark:text-gray-200">{{ 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>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/profile/edit.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,29 @@ +<x-app-layout> + <x-slot name="header"> + <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 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 dark:bg-gray-800 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 dark:bg-gray-800 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 dark:bg-gray-800 shadow sm:rounded-lg"> + <div class="max-w-xl"> + @include('profile.partials.delete-user-form') + </div> + </div> + </div> + </div> +</x-app-layout>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/profile/partials/delete-user-form.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,55 @@ +<section class="space-y-6"> + <header> + <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> + {{ __('Delete Account') }} + </h2> + + <p class="mt-1 text-sm text-gray-600 dark:text-gray-400"> + {{ __('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 dark:text-gray-100"> + {{ __('Are you sure you want to delete your account?') }} + </h2> + + <p class="mt-1 text-sm text-gray-600 dark:text-gray-400"> + {{ __('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>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/profile/partials/update-password-form.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,48 @@ +<section> + <header> + <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> + {{ __('Update Password') }} + </h2> + + <p class="mt-1 text-sm text-gray-600 dark:text-gray-400"> + {{ __('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 dark:text-gray-400" + >{{ __('Saved.') }}</p> + @endif + </div> + </form> +</section>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/resources/views/profile/partials/update-profile-information-form.blade.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,64 @@ +<section> + <header> + <h2 class="text-lg font-medium text-gray-900 dark:text-gray-100"> + {{ __('Profile Information') }} + </h2> + + <p class="mt-1 text-sm text-gray-600 dark:text-gray-400"> + {{ __("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 dark:text-gray-200"> + {{ __('Your email address is unverified.') }} + + <button form="send-verification" class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800"> + {{ __('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 dark:text-green-400"> + {{ __('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 dark:text-gray-400" + >{{ __('Saved.') }}</p> + @endif + </div> + </form> +</section>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/routes/auth.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,59 @@ +<?php + +use App\Http\Controllers\Auth\AuthenticatedSessionController; +use App\Http\Controllers\Auth\ConfirmablePasswordController; +use App\Http\Controllers\Auth\EmailVerificationNotificationController; +use App\Http\Controllers\Auth\EmailVerificationPromptController; +use App\Http\Controllers\Auth\NewPasswordController; +use App\Http\Controllers\Auth\PasswordController; +use App\Http\Controllers\Auth\PasswordResetLinkController; +use App\Http\Controllers\Auth\RegisteredUserController; +use App\Http\Controllers\Auth\VerifyEmailController; +use Illuminate\Support\Facades\Route; + +Route::middleware('guest')->group(function () { + Route::get('register', [RegisteredUserController::class, 'create']) + ->name('register'); + + Route::post('register', [RegisteredUserController::class, 'store']); + + Route::get('login', [AuthenticatedSessionController::class, 'create']) + ->name('login'); + + Route::post('login', [AuthenticatedSessionController::class, 'store']); + + Route::get('forgot-password', [PasswordResetLinkController::class, 'create']) + ->name('password.request'); + + Route::post('forgot-password', [PasswordResetLinkController::class, 'store']) + ->name('password.email'); + + Route::get('reset-password/{token}', [NewPasswordController::class, 'create']) + ->name('password.reset'); + + Route::post('reset-password', [NewPasswordController::class, 'store']) + ->name('password.store'); +}); + +Route::middleware('auth')->group(function () { + Route::get('verify-email', EmailVerificationPromptController::class) + ->name('verification.notice'); + + Route::get('verify-email/{id}/{hash}', VerifyEmailController::class) + ->middleware(['signed', 'throttle:6,1']) + ->name('verification.verify'); + + Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store']) + ->middleware('throttle:6,1') + ->name('verification.send'); + + Route::get('confirm-password', [ConfirmablePasswordController::class, 'show']) + ->name('password.confirm'); + + Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']); + + Route::put('password', [PasswordController::class, 'update'])->name('password.update'); + + Route::post('logout', [AuthenticatedSessionController::class, 'destroy']) + ->name('logout'); +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/routes/web.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,20 @@ +<?php + +use App\Http\Controllers\ProfileController; +use Illuminate\Support\Facades\Route; + +Route::get('/', function () { + return view('welcome'); +}); + +Route::get('/dashboard', function () { + return view('dashboard'); +})->middleware(['auth', 'verified'])->name('dashboard'); + +Route::middleware('auth')->group(function () { + Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); + Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); + Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); +}); + +require __DIR__.'/auth.php';
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/tests/Feature/Auth/AuthenticationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,54 @@ +<?php + +namespace Tests\Feature\Auth; + +use App\Models\User; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\TestCase; + +class AuthenticationTest extends TestCase +{ + use RefreshDatabase; + + public function test_login_screen_can_be_rendered(): void + { + $response = $this->get('/login'); + + $response->assertStatus(200); + } + + public function test_users_can_authenticate_using_the_login_screen(): void + { + $user = User::factory()->create(); + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard', absolute: false)); + } + + public function test_users_can_not_authenticate_with_invalid_password(): void + { + $user = User::factory()->create(); + + $this->post('/login', [ + 'email' => $user->email, + 'password' => 'wrong-password', + ]); + + $this->assertGuest(); + } + + public function test_users_can_logout(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/logout'); + + $this->assertGuest(); + $response->assertRedirect('/'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/tests/Feature/Auth/EmailVerificationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,58 @@ +<?php + +namespace Tests\Feature\Auth; + +use App\Models\User; +use Illuminate\Auth\Events\Verified; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\URL; +use Tests\TestCase; + +class EmailVerificationTest extends TestCase +{ + use RefreshDatabase; + + public function test_email_verification_screen_can_be_rendered(): void + { + $user = User::factory()->unverified()->create(); + + $response = $this->actingAs($user)->get('/verify-email'); + + $response->assertStatus(200); + } + + public function test_email_can_be_verified(): void + { + $user = User::factory()->unverified()->create(); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)] + ); + + $response = $this->actingAs($user)->get($verificationUrl); + + Event::assertDispatched(Verified::class); + $this->assertTrue($user->fresh()->hasVerifiedEmail()); + $response->assertRedirect(route('dashboard', absolute: false).'?verified=1'); + } + + public function test_email_is_not_verified_with_invalid_hash(): void + { + $user = User::factory()->unverified()->create(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1('wrong-email')] + ); + + $this->actingAs($user)->get($verificationUrl); + + $this->assertFalse($user->fresh()->hasVerifiedEmail()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/tests/Feature/Auth/PasswordConfirmationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,44 @@ +<?php + +namespace Tests\Feature\Auth; + +use App\Models\User; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\TestCase; + +class PasswordConfirmationTest extends TestCase +{ + use RefreshDatabase; + + public function test_confirm_password_screen_can_be_rendered(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->get('/confirm-password'); + + $response->assertStatus(200); + } + + public function test_password_can_be_confirmed(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'password', + ]); + + $response->assertRedirect(); + $response->assertSessionHasNoErrors(); + } + + public function test_password_is_not_confirmed_with_invalid_password(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'wrong-password', + ]); + + $response->assertSessionHasErrors(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/tests/Feature/Auth/PasswordResetTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,73 @@ +<?php + +namespace Tests\Feature\Auth; + +use App\Models\User; +use Illuminate\Auth\Notifications\ResetPassword; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\Notification; +use Tests\TestCase; + +class PasswordResetTest extends TestCase +{ + use RefreshDatabase; + + public function test_reset_password_link_screen_can_be_rendered(): void + { + $response = $this->get('/forgot-password'); + + $response->assertStatus(200); + } + + public function test_reset_password_link_can_be_requested(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class); + } + + public function test_reset_password_screen_can_be_rendered(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { + $response = $this->get('/reset-password/'.$notification->token); + + $response->assertStatus(200); + + return true; + }); + } + + public function test_password_can_be_reset_with_valid_token(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { + $response = $this->post('/reset-password', [ + 'token' => $notification->token, + 'email' => $user->email, + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('login')); + + return true; + }); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/tests/Feature/Auth/PasswordUpdateTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,51 @@ +<?php + +namespace Tests\Feature\Auth; + +use App\Models\User; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\Hash; +use Tests\TestCase; + +class PasswordUpdateTest extends TestCase +{ + use RefreshDatabase; + + public function test_password_can_be_updated(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $this->assertTrue(Hash::check('new-password', $user->refresh()->password)); + } + + public function test_correct_password_must_be_provided_to_update_password(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'wrong-password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasErrorsIn('updatePassword', 'current_password') + ->assertRedirect('/profile'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/tests/Feature/Auth/RegistrationTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,31 @@ +<?php + +namespace Tests\Feature\Auth; + +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\TestCase; + +class RegistrationTest extends TestCase +{ + use RefreshDatabase; + + public function test_registration_screen_can_be_rendered(): void + { + $response = $this->get('/register'); + + $response->assertStatus(200); + } + + public function test_new_users_can_register(): void + { + $response = $this->post('/register', [ + 'name' => 'Test User', + 'email' => 'test@example.com', + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard', absolute: false)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubs/default/tests/Feature/ProfileTest.php Wed Aug 13 22:17:20 2025 -0400 @@ -0,0 +1,99 @@ +<?php + +namespace Tests\Feature; + +use App\Models\User; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\TestCase; + +class ProfileTest extends TestCase +{ + use RefreshDatabase; + + public function test_profile_page_is_displayed(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->get('/profile'); + + $response->assertOk(); + } + + public function test_profile_information_can_be_updated(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->patch('/profile', [ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $user->refresh(); + + $this->assertSame('Test User', $user->name); + $this->assertSame('test@example.com', $user->email); + $this->assertNull($user->email_verified_at); + } + + public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->patch('/profile', [ + 'name' => 'Test User', + 'email' => $user->email, + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $this->assertNotNull($user->refresh()->email_verified_at); + } + + public function test_user_can_delete_their_account(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->delete('/profile', [ + 'password' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/'); + + $this->assertGuest(); + $this->assertNull($user->fresh()); + } + + public function test_correct_password_must_be_provided_to_delete_account(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->delete('/profile', [ + 'password' => 'wrong-password', + ]); + + $response + ->assertSessionHasErrorsIn('userDeletion', 'password') + ->assertRedirect('/profile'); + + $this->assertNotNull($user->fresh()); + } +}
