├── .github └── workflows │ ├── phpunit.xml.stub │ └── tests.yml ├── .gitignore ├── .php-cs-fixer.php ├── LICENSE ├── README.md ├── composer.json ├── phpstan.neon ├── screenshots └── screen-record.gif └── src ├── HandlesAuthScaffolding.php ├── HandlesCodeHelperScaffolding.php ├── HandlesGeneralScaffolding.php ├── TtallPreset.php ├── TtallPresetServiceProvider.php └── stubs ├── auth ├── app │ └── Http │ │ └── Livewire │ │ ├── Auth │ │ ├── Login.php │ │ ├── Passwords │ │ │ ├── Confirm.php │ │ │ ├── Email.php │ │ │ └── Reset.php │ │ ├── Register.php │ │ └── Verify.php │ │ └── Home.php ├── resources │ └── views │ │ ├── components │ │ ├── button.blade.php │ │ └── form-input.blade.php │ │ ├── layouts │ │ └── auth.blade.php │ │ └── livewire │ │ ├── auth │ │ ├── login.blade.php │ │ ├── passwords │ │ │ ├── confirm.blade.php │ │ │ ├── email.blade.php │ │ │ └── reset.blade.php │ │ ├── register.blade.php │ │ └── verify.blade.php │ │ └── home.blade.php ├── routes │ └── web.php └── tests │ └── Feature │ └── Auth │ ├── LoginTest.php │ ├── LogoutTest.php │ ├── Passwords │ ├── ConfirmTest.php │ ├── EmailTest.php │ └── ResetTest.php │ ├── RegisterTest.php │ └── VerifyTest.php └── default ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .php-cs-fixer.php ├── .prettierrc ├── phpstan.neon ├── postcss.config.js ├── public └── favicon.ico ├── resources ├── css │ └── app.css ├── js │ ├── app.js │ ├── bootstrap.js │ └── turbolinks.js └── views │ ├── components │ ├── logo.blade.php │ └── navbar.blade.php │ ├── layouts │ ├── app.blade.php │ └── base.blade.php │ ├── vendor │ └── pagination │ │ ├── default.blade.php │ │ └── simple-default.blade.php │ └── welcome.blade.php ├── routes └── web.php ├── tailwind.config.js ├── tests ├── Feature │ └── ExampleTest.php └── TestCase.php └── webpack.mix.js /.github/workflows/phpunit.xml.stub: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests/Unit 10 | 11 | 12 | ./tests/Feature 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | run: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | php: [8.1, 8.0] 14 | laravel: [^8.0] 15 | name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v2 19 | - name: Cache dependencies 20 | uses: actions/cache@v1 21 | with: 22 | path: ~/.composer/cache/files 23 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 24 | - name: Set up PHP 25 | uses: shivammathur/setup-php@v2 26 | with: 27 | php-version: ${{ matrix.php }} 28 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite 29 | coverage: none 30 | - name: Create Laravel app 31 | run: composer create-project laravel/laravel=${{ matrix.laravel }} ../app --prefer-dist 32 | - name: Install dependencies 33 | run: | 34 | cd ../app 35 | composer config repositories.local '{"type": "path", "url": "../ttall"}' --file composer.json 36 | composer require pktharindu/ttall @dev 37 | composer update 38 | - name: Install preset 39 | run: | 40 | cd ../app 41 | php artisan ui ttall --auth --option=code-helpers 42 | - name: Overwrite configuration 43 | run: | 44 | cd ../app 45 | rm phpunit.xml 46 | cp ../ttall/.github/workflows/phpunit.xml.stub ./phpunit.xml 47 | - name: Execute tests 48 | run: | 49 | cd ../app 50 | vendor/bin/phpunit --verbose 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | .php-cs-fixer.cache -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | ['syntax' => 'short'], 8 | 'binary_operator_spaces' => [ 9 | 'default' => 'single_space', 10 | 'operators' => ['=>' => null], 11 | ], 12 | 'blank_line_after_namespace' => true, 13 | 'blank_line_after_opening_tag' => true, 14 | 'blank_line_before_statement' => [ 15 | 'statements' => ['return'], 16 | ], 17 | 'braces' => true, 18 | 'cast_spaces' => true, 19 | 'class_attributes_separation' => [ 20 | 'elements' => [ 21 | 'const' => 'one', 22 | 'method' => 'one', 23 | 'property' => 'one', 24 | ], 25 | ], 26 | 'class_definition' => [ 27 | 'multi_line_extends_each_single_line' => true, 28 | 'single_item_single_line' => true, 29 | 'single_line' => true, 30 | ], 31 | 'concat_space' => [ 32 | 'spacing' => 'none', 33 | ], 34 | 'declare_equal_normalize' => true, 35 | 'elseif' => true, 36 | 'encoding' => true, 37 | 'full_opening_tag' => true, 38 | 'fully_qualified_strict_types' => true, // added by Shift 39 | 'function_declaration' => true, 40 | 'function_typehint_space' => true, 41 | 'general_phpdoc_tag_rename' => true, 42 | 'heredoc_to_nowdoc' => true, 43 | 'include' => true, 44 | 'increment_style' => ['style' => 'post'], 45 | 'indentation_type' => true, 46 | 'linebreak_after_opening_tag' => true, 47 | 'line_ending' => true, 48 | 'lowercase_cast' => true, 49 | 'constant_case' => ['case' => 'lower'], 50 | 'lowercase_keywords' => true, 51 | 'lowercase_static_reference' => true, // added from Symfony 52 | 'magic_method_casing' => true, // added from Symfony 53 | 'magic_constant_casing' => true, 54 | 'method_argument_space' => true, 55 | 'native_function_casing' => true, 56 | 'no_alias_functions' => true, 57 | 'no_extra_blank_lines' => [ 58 | 'tokens' => [ 59 | 'extra', 60 | 'throw', 61 | 'use', 62 | 'use_trait', 63 | ], 64 | ], 65 | 'no_blank_lines_after_class_opening' => true, 66 | 'no_blank_lines_after_phpdoc' => true, 67 | 'no_closing_tag' => true, 68 | 'no_empty_phpdoc' => true, 69 | 'no_empty_statement' => true, 70 | 'no_leading_import_slash' => true, 71 | 'no_leading_namespace_whitespace' => true, 72 | 'no_mixed_echo_print' => [ 73 | 'use' => 'echo', 74 | ], 75 | 'no_multiline_whitespace_around_double_arrow' => true, 76 | 'multiline_whitespace_before_semicolons' => [ 77 | 'strategy' => 'no_multi_line', 78 | ], 79 | 'no_short_bool_cast' => true, 80 | 'no_singleline_whitespace_before_semicolons' => true, 81 | 'no_spaces_after_function_name' => true, 82 | 'no_spaces_around_offset' => [ 83 | 'positions' => ['inside', 'outside'], 84 | ], 85 | 'no_spaces_inside_parenthesis' => true, 86 | 'no_trailing_comma_in_list_call' => true, 87 | 'no_trailing_comma_in_singleline_array' => true, 88 | 'no_trailing_whitespace' => true, 89 | 'no_trailing_whitespace_in_comment' => true, 90 | 'no_unneeded_control_parentheses' => [ 91 | 'statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield'], 92 | ], 93 | 'no_unreachable_default_argument_value' => true, 94 | 'no_useless_return' => true, 95 | 'no_whitespace_before_comma_in_array' => true, 96 | 'no_whitespace_in_blank_line' => true, 97 | 'normalize_index_brace' => true, 98 | 'not_operator_with_successor_space' => true, 99 | 'object_operator_without_whitespace' => true, 100 | 'ordered_imports' => [ 101 | 'sort_algorithm' => 'alpha', 102 | ], 103 | 'phpdoc_indent' => true, 104 | 'phpdoc_inline_tag_normalizer' => true, 105 | 'phpdoc_no_access' => true, 106 | 'phpdoc_no_package' => true, 107 | 'phpdoc_no_useless_inheritdoc' => true, 108 | 'phpdoc_scalar' => true, 109 | 'phpdoc_single_line_var_spacing' => true, 110 | 'phpdoc_summary' => true, 111 | 'phpdoc_to_comment' => true, 112 | 'phpdoc_tag_type' => true, 113 | 'phpdoc_trim' => true, 114 | 'phpdoc_types' => true, 115 | 'phpdoc_var_without_name' => true, 116 | 'psr_autoloading' => true, 117 | 'self_accessor' => true, 118 | 'short_scalar_cast' => true, 119 | 'simplified_null_return' => false, // disabled by Shift 120 | 'single_blank_line_at_eof' => true, 121 | 'single_blank_line_before_namespace' => true, 122 | 'single_class_element_per_statement' => true, // here 123 | 'single_import_per_statement' => true, 124 | 'single_line_after_imports' => true, 125 | 'single_line_comment_style' => [ 126 | 'comment_types' => ['hash'] 127 | ], 128 | 'single_quote' => true, 129 | 'space_after_semicolon' => true, 130 | 'standardize_not_equals' => true, 131 | 'switch_case_semicolon_to_colon' => true, 132 | 'switch_case_space' => true, 133 | 'ternary_operator_spaces' => true, 134 | 'trailing_comma_in_multiline' => ['elements' => ['arrays']], 135 | 'trim_array_spaces' => true, 136 | 'unary_operator_spaces' => true, 137 | 'visibility_required' => [ 138 | 'elements' => ['property', 'method', 'const'], 139 | ], 140 | 'whitespace_after_comma_in_array' => true, 141 | ]; 142 | 143 | $finder = Finder::create() 144 | ->notPath('vendor') 145 | ->in(getcwd()) 146 | ->name('*.php') 147 | ->notName('*.blade.php') 148 | ->notName('index.php') 149 | ->notName('server.php') 150 | ->ignoreDotFiles(true) 151 | ->ignoreVCS(true); 152 | 153 | return (new Config()) 154 | ->setFinder($finder) 155 | ->setRules($rules) 156 | ->setRiskyAllowed(true) 157 | ->setUsingCache(true); 158 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) P. K. Tharindu 4 | 5 | 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: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TTALL Preset For Laravel 7 and Up 2 | 3 | [![License: MIT](https://img.shields.io/badge/license-MIT-green)](/LICENSE) 4 | [![CI Status](https://github.com/pktharindu/ttall/workflows/tests/badge.svg)](https://github.com/pktharindu/ttall/actions) 5 | [![Total Downloads](https://poser.pugx.org/pktharindu/ttall/d/total.svg)](https://packagist.org/packages/pktharindu/ttall) 6 | 7 | An opinionated Laravel front-end scaffolding preset for TTALL stack - Tailwindcss | Turbolinks | Alpine.js | Laravel | Livewire 🚀 8 | 9 | It comes bundled with some helpful packages and their configurations (optional): 10 | 11 | It uses concerns of [laravel/ui](https://github.com/laravel/ui) through Livewire actions. So, security features of laravel/ui (ex: login throttling) are built right in. It also comes bundled with some helpful packages and their configurations (optional): 12 | 13 | - Laravel debugbar 14 | - Laravel IDE Helper 15 | - Php CS Fixer 16 | - Larastan 17 | - Eslint (Airbnb rules) 18 | - Prettier 19 | - Composer Git Hooks 20 | 21 | ![Screen Record](https://raw.githubusercontent.com/pktharindu/ttall/master/screenshots/screen-record.gif) 22 | 23 | If you like this package, show some love by starring the repo. ⭐❤ 24 | 25 | ## Contents 26 | 27 | - [TTALL Preset For Laravel 7 and Up](#ttall-preset-for-laravel-7-and-up) 28 | - [Contents](#contents) 29 | - [Installation](#installation) 30 | - [For Basic Presets (without authentication)](#for-basic-presets-without-authentication) 31 | - [For Presets with Authentication](#for-presets-with-authentication) 32 | - [Configuration](#configuration) 33 | - [Options](#options) 34 | - [Code Helpers](#code-helpers) 35 | - [Scripts](#scripts) 36 | - [Support](#support) 37 | - [Credits](#credits) 38 | - [License](#license) 39 | 40 | 41 | ## Installation 42 | 43 | To install this preset on your laravel application, run: 44 | 45 | ``` bash 46 | composer require pktharindu/ttall --dev 47 | ``` 48 | 49 | ### For Basic Presets (without authentication) 50 | 51 | To scaffold the basic preset without authentication, run: 52 | ``` bash 53 | php artisan ui ttall 54 | ``` 55 | 56 | ### For Presets with Authentication 57 | 58 | To scaffold the basic preset, auth route entry and auth views in one go, run: 59 | ``` bash 60 | php artisan ui ttall --auth 61 | ``` 62 | Finally run `composer update && npm install && npm run dev` to install the new composer packages and compile your fresh scaffolding. 63 | 64 | ## Configuration 65 | 66 | Add a new i18n string in the `resources/lang/XX/pagination.php` file for each language that your app uses: 67 | 68 | ```php 69 | 'previous' => '« Previous', 70 | 'next' => 'Next »', 71 | 'goto_page' => 'Goto page #:page', // Add this line 72 | ``` 73 | 74 | This will help with accessibility. 75 | 76 | ```html 77 |
  • 78 | 79 | 2 80 | 81 |
  • 82 | ``` 83 | 84 | ## Options 85 | 86 | As this preset is designed to get you up-and-running quickly, it comes bundled with some extra options that will take you even further. To utilize these options, use the `--option` flag when installing the preset. 87 | 88 | Usage Example: 89 | 90 | ```bash 91 | php artisan ui ttall --option=code-helpers 92 | ``` 93 | 94 | ### Code Helpers 95 | 96 | `code-helpers` option will install and configure the below packages to help you with the development: 97 | 98 | - Laravel debugbar 99 | - Laravel IDE Helper 100 | - Php CS Fixer 101 | - Larastan 102 | - Eslint (Airbnb rules) 103 | - Prettier 104 | - Composer Git Hooks 105 | 106 | #### Scripts 107 | 108 | A composer's script is added automatically to tell `Laravel IDE Helper` to rescan your `Facades` files and update git hooks after every `composer update` : 109 | 110 | ```json 111 | "scripts": { 112 | "post-update-cmd": [ 113 | "Illuminate\\Foundation\\ComposerScripts::postUpdate", 114 | "@php artisan ide-helper:generate", 115 | "cghooks update" 116 | ] 117 | } 118 | ``` 119 | 120 | Also, Git Hooks are added to format your php files automatically before each commit. 121 | 122 | ```json 123 | "extra": { 124 | "hooks": { 125 | "pre-commit": [ 126 | "STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM -- '*.php')", 127 | "php-cs-fixer fix", 128 | "git add $STAGED_FILES" 129 | ] 130 | } 131 | }, 132 | ``` 133 | 134 | Scripts are also added to your `package.json` and `composer.json` to run specific actions : 135 | 136 | - `composer format` : will use `php-cs-fixer` to format your php files 137 | - `composer test` : will use the `php artisan test` command to run your phpunit tests 138 | - `composer analyse` : will use `larastan` to analyse your code 139 | - `npm run format` : will format your js files on `resources/js` folder 140 | - `npm run lint` : will find issues in your js files based on Airbnb's rules and try to fix them 141 | 142 | ## Support 143 | 144 | If you require any support please contact me on [Twitter](https://twitter.com/CallMeTharindu) or open an issue on this repository. 145 | 146 | ## Credits 147 | 148 | - [P. K. Tharindu](https://github.com/pktharindu) 149 | - [All Contributors](../../contributors) 150 | 151 | This Package is inspired by [laravel-frontend-presets/tall](https://github.com/laravel-frontend-presets/tall) and [YannickYayo/laravel-preset-ttall](https://github.com/YannickYayo/laravel-preset-ttall). I wanted to have a combination of both. Thanks to all authors of these packages. 152 | 153 | ## License 154 | 155 | Licensed under the MIT license, see [LICENSE](/LICENSE) for details. 156 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pktharindu/ttall", 3 | "description": "TTALL Preset For Laravel 7 and Up.", 4 | "keywords": [ 5 | "tailwind", 6 | "tailwindcss", 7 | "turbolinks", 8 | "alpine", 9 | "alpinejs", 10 | "laravel", 11 | "livewire", 12 | "tall", 13 | "ttall", 14 | "preset" 15 | ], 16 | "license": "MIT", 17 | "authors": [{ 18 | "name": "P. K. Tharindu", 19 | "email": "pktharindu@outlook.com" 20 | } 21 | ], 22 | "require": { 23 | "php": "^7.2.5|^8.0", 24 | "laravel/framework": "^8.0|^9.0", 25 | "laravel/ui": "^3.0", 26 | "livewire/livewire": "^2.0" 27 | }, 28 | "require-dev": { 29 | "phpstan/phpstan": "^0.12.14", 30 | "friendsofphp/php-cs-fixer": "^2.16" 31 | }, 32 | "scripts": { 33 | "format": "php-cs-fixer fix --path-mode=intersection --config=.php-cs-fixer.php ./", 34 | "analyse": "phpstan analyse" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "Pktharindu\\TtallPreset\\": "src/" 39 | } 40 | }, 41 | "extra": { 42 | "laravel": { 43 | "providers": [ 44 | "Pktharindu\\TtallPreset\\TtallPresetServiceProvider" 45 | ] 46 | } 47 | }, 48 | "minimum-stability": "dev", 49 | "prefer-stable": true 50 | } 51 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | 3 | paths: 4 | - src 5 | 6 | # The level 8 is the highest level 7 | level: 5 8 | 9 | ignoreErrors: 10 | # - '#Function base_path not found.#' 11 | 12 | checkMissingIterableValueType: false 13 | -------------------------------------------------------------------------------- /screenshots/screen-record.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pktharindu/ttall/3ce4cb8d44b50c1ea1afce075a041da35e83294d/screenshots/screen-record.gif -------------------------------------------------------------------------------- /src/HandlesAuthScaffolding.php: -------------------------------------------------------------------------------- 1 | copyDirectory(__DIR__.'/stubs/auth', base_path()); 16 | 17 | collect($filesystem->allFiles(base_path('vendor/laravel/ui/stubs/migrations'))) 18 | ->each(function (SplFileInfo $file) use ($filesystem) { 19 | $filesystem->copy( 20 | $file->getPathname(), 21 | database_path('migrations/'.$file->getFilename()) 22 | ); 23 | }); 24 | } 25 | 26 | protected static function scaffoldAuthController(): void 27 | { 28 | if (! is_dir($directory = app_path('Http/Controllers/Auth'))) { 29 | mkdir($directory, 0755, true); 30 | } 31 | 32 | $filesystem = new Filesystem(); 33 | 34 | collect($filesystem->allFiles(base_path('vendor/laravel/ui/stubs/Auth'))) 35 | ->filter(function (SplFileInfo $file) { 36 | return in_array($file->getFilenameWithoutExtension(), [ 37 | 'LoginController', 38 | 'VerificationController', 39 | ], true); 40 | }) 41 | ->each(function (SplFileInfo $file) use ($filesystem) { 42 | $filesystem->copy( 43 | $file->getPathname(), 44 | app_path('Http/Controllers/Auth/'.Str::replaceLast('.stub', '.php', $file->getFilename())) 45 | ); 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/HandlesCodeHelperScaffolding.php: -------------------------------------------------------------------------------- 1 | '^3.6', 35 | 'barryvdh/laravel-ide-helper' => '^2.10', 36 | 'brainmaestro/composer-git-hooks' => '^2.8', 37 | 'friendsofphp/php-cs-fixer' => '^3.0', 38 | 'nunomaduro/larastan' => '^0.6.2', 39 | ], $composer); 40 | } else { 41 | return array_merge([], $composer); 42 | } 43 | } 44 | 45 | protected static function updateCodeHelperPackagesScripts(): void 46 | { 47 | if (! file_exists(base_path('package.json'))) { 48 | return; 49 | } 50 | 51 | $packages = json_decode(file_get_contents(base_path('package.json')), true); 52 | 53 | $packages['scripts'] = static::updateCodeHelperPackagesScriptsArray( 54 | array_key_exists('scripts', $packages) ? $packages['scripts'] : [] 55 | ); 56 | 57 | ksort($packages['scripts']); 58 | 59 | file_put_contents( 60 | base_path('package.json'), 61 | json_encode($packages, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL 62 | ); 63 | } 64 | 65 | protected static function updateCodeHelperPackagesScriptsArray(array $packages): array 66 | { 67 | return array_merge([ 68 | 'format' => "prettier --write 'resources/js/*.{js,jsx}'", 69 | 'lint' => "eslint '**/*.{js,jsx}' --quiet --fix", 70 | ], $packages); 71 | } 72 | 73 | protected static function updateCodeHelperComposerScripts(): void 74 | { 75 | if (! file_exists(base_path('composer.json'))) { 76 | return; 77 | } 78 | 79 | $composer = json_decode(file_get_contents(base_path('composer.json')), true); 80 | 81 | $composer['scripts'] = static::updateCodeHelperComposerScriptsArray( 82 | array_key_exists('scripts', $composer) ? $composer['scripts'] : [] 83 | ); 84 | 85 | ksort($composer['scripts']); 86 | 87 | file_put_contents( 88 | base_path('composer.json'), 89 | json_encode($composer, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL 90 | ); 91 | } 92 | 93 | protected static function updateCodeHelperComposerScriptsArray(array $composer): array 94 | { 95 | return array_merge([ 96 | 'post-update-cmd' => [ 97 | 'Illuminate\\Foundation\\ComposerScripts::postUpdate', 98 | '@php artisan ide-helper:generate', 99 | 'cghooks update', 100 | ], 101 | 'format' => 'php-cs-fixer fix --path-mode=intersection --config=.php-cs-fixer.php ./', 102 | 'test' => '@php artisan test', 103 | 'analyse' => 'phpstan analyse', 104 | ], $composer); 105 | } 106 | 107 | protected static function updateCodeHelperComposerExtra(): void 108 | { 109 | if (! file_exists(base_path('composer.json'))) { 110 | return; 111 | } 112 | 113 | $composer = json_decode(file_get_contents(base_path('composer.json')), true); 114 | 115 | $composer['extra']['hooks'] = static::updateCodeHelperComposerExtraHooksArray( 116 | array_key_exists('hooks', $composer['extra']) ? $composer['extra']['hooks'] : [] 117 | ); 118 | 119 | ksort($composer['extra']); 120 | 121 | file_put_contents( 122 | base_path('composer.json'), 123 | json_encode($composer, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL 124 | ); 125 | } 126 | 127 | protected static function updateCodeHelperComposerExtraHooksArray(array $composer): array 128 | { 129 | return array_merge([ 130 | 'pre-commit' => [ 131 | "STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM -- '*.php')", 132 | './vendor/bin/php-cs-fixer fix', 133 | 'git add $STAGED_FILES', 134 | ], 135 | ], $composer); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/HandlesGeneralScaffolding.php: -------------------------------------------------------------------------------- 1 | '^3.0', 40 | 'livewire/livewire' => '^2.6', 41 | ], $composer); 42 | } 43 | 44 | protected static function updatePackagesScripts(): void 45 | { 46 | if (! file_exists(base_path('package.json'))) { 47 | return; 48 | } 49 | 50 | $packages = json_decode(file_get_contents(base_path('package.json')), true); 51 | 52 | ksort($packages['scripts']); 53 | 54 | file_put_contents( 55 | base_path('package.json'), 56 | json_encode($packages, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT).PHP_EOL 57 | ); 58 | } 59 | 60 | protected static function scaffoldDefaults(): void 61 | { 62 | $filesystem = new Filesystem(); 63 | 64 | $filesystem->copyDirectory(__DIR__.'/stubs/default', base_path()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/TtallPreset.php: -------------------------------------------------------------------------------- 1 | '^10.3.4', 16 | 'alpinejs' => '^3.3.5', 17 | 'postcss' => '^8.2.1', 18 | 'postcss-import' => '^12.0.1', 19 | 'tailwindcss' => '^2.2.15', 20 | 'turbolinks' => '^5.2.0', 21 | ]; 22 | 23 | public const DEV_NPM_PACKAGES_TO_ADD = [ 24 | 'eslint' => '^7.7.0', 25 | 'eslint-config-airbnb' => '^18.2.0', 26 | 'eslint-config-prettier' => '^6.11.0', 27 | 'eslint-plugin-import' => '^2.22.0', 28 | 'eslint-plugin-jsx-a11y' => '^6.3.1', 29 | 'eslint-plugin-react' => '^7.20.6', 30 | 'eslint-plugin-react-hooks' => '^4.1.0', 31 | 'prettier' => '^2.0.5', 32 | 'laravel-mix' => '^6.0.0', 33 | ]; 34 | 35 | public const NPM_PACKAGES_TO_REMOVE = [ 36 | 'axios', 37 | 'laravel-mix', 38 | 'lodash', 39 | ]; 40 | 41 | public static function install(): void 42 | { 43 | static::updatePackages(); 44 | static::updatePackages(false); 45 | static::updateComposerPackages(); 46 | static::updateComposerPackages(false); 47 | static::updatePackagesScripts(); 48 | static::scaffoldDefaults(); 49 | } 50 | 51 | public static function installAuth(): void 52 | { 53 | static::scaffoldAuth(); 54 | 55 | static::scaffoldAuthController(); 56 | } 57 | 58 | public static function installCodeHelpers(): void 59 | { 60 | static::updateCodeHelperComposerPackages(); 61 | static::updateCodeHelperComposerPackages(false); 62 | static::updateCodeHelperPackagesScripts(); 63 | static::updateCodeHelperComposerScripts(); 64 | static::updateCodeHelperComposerExtra(); 65 | } 66 | 67 | protected static function updatePackageArray(array $packages, string $dev): array 68 | { 69 | if ($dev == 'devDependencies') { 70 | return array_merge( 71 | static::DEV_NPM_PACKAGES_TO_ADD, 72 | Arr::except($packages, static::NPM_PACKAGES_TO_REMOVE) 73 | ); 74 | } 75 | 76 | return array_merge( 77 | static::NPM_PACKAGES_TO_ADD, 78 | Arr::except($packages, static::NPM_PACKAGES_TO_REMOVE) 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/TtallPresetServiceProvider.php: -------------------------------------------------------------------------------- 1 | line("\n".$asciiLogo."\n"); 32 | $command->info('Ttall scaffolding installed successfully.'); 33 | 34 | if ($command->option('auth')) { 35 | TtallPreset::installAuth(); 36 | 37 | $command->info('Ttall auth scaffolding installed successfully.'); 38 | } 39 | 40 | $options = $command->option('option') ?? []; 41 | 42 | if (in_array('code-helpers', $options, true) || in_array('all', $options, true)) { 43 | TtallPreset::installCodeHelpers(); 44 | 45 | $command->info('Code helpers installed successfully.'); 46 | } 47 | 48 | $command->line('Please run "composer update && npm install && npm run dev" to install the new composer\'s packages and compile your fresh scaffolding.'); 49 | 50 | if ($command->confirm('Would you like to show some love by starring the repo?')) { 51 | if (PHP_OS_FAMILY == 'Darwin') { 52 | exec('open https://github.com/pktharindu/ttall'); 53 | } 54 | if (PHP_OS_FAMILY == 'Windows') { 55 | exec('start https://github.com/pktharindu/ttall'); 56 | } 57 | if (PHP_OS_FAMILY == 'Linux') { 58 | exec('xdg-open https://github.com/pktharindu/ttall'); 59 | } 60 | 61 | $command->line('Thanks! Means the world to me! 🥰'); 62 | } else { 63 | $command->line('I understand, but am not going to pretend I\'m not sad about it...'); 64 | } 65 | }); 66 | 67 | Paginator::defaultView('pagination::default'); 68 | 69 | Paginator::defaultSimpleView('pagination::simple-default'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/stubs/auth/app/Http/Livewire/Auth/Login.php: -------------------------------------------------------------------------------- 1 | login(new Request(collect($this)->toArray())); 23 | } 24 | 25 | protected function sendLoginResponse(Request $request) 26 | { 27 | session()->regenerate(); 28 | 29 | $this->clearLoginAttempts($request); 30 | 31 | if ($response = $this->authenticated($request, $this->guard()->user())) { 32 | return $response; 33 | } 34 | 35 | return redirect()->intended(RouteServiceProvider::HOME); 36 | } 37 | 38 | public function render() 39 | { 40 | return view('livewire.auth.login')->extends('layouts.auth'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/stubs/auth/app/Http/Livewire/Auth/Passwords/Confirm.php: -------------------------------------------------------------------------------- 1 | validate([ 17 | 'password' => 'required|password', 18 | ]); 19 | 20 | session()->put('auth.password_confirmed_at', time()); 21 | 22 | return redirect()->intended($this->redirectPath()); 23 | } 24 | 25 | public function render() 26 | { 27 | return view('livewire.auth.passwords.confirm')->extends('layouts.auth'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/stubs/auth/app/Http/Livewire/Auth/Passwords/Email.php: -------------------------------------------------------------------------------- 1 | validate([ 15 | 'email' => 'required|email', 16 | ]); 17 | 18 | $response = $this->broker()->sendResetLink(['email' => $this->email]); 19 | 20 | return $response == Password::RESET_LINK_SENT 21 | ? $this->sendResetLinkResponse($response) 22 | : $this->addError('email', trans($response)); 23 | } 24 | 25 | public function broker() 26 | { 27 | return Password::broker(); 28 | } 29 | 30 | protected function sendResetLinkResponse($response) 31 | { 32 | session()->flash('status', trans($response)); 33 | 34 | return redirect()->back(); 35 | } 36 | 37 | public function render() 38 | { 39 | return view('livewire.auth.passwords.email')->extends('layouts.auth'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/stubs/auth/app/Http/Livewire/Auth/Passwords/Reset.php: -------------------------------------------------------------------------------- 1 | token = $token; 26 | } 27 | 28 | public function passwordReset() 29 | { 30 | $this->validate([ 31 | 'token' => 'required', 32 | 'email' => 'required|email', 33 | 'password' => 'required|confirmed|min:8', 34 | ]); 35 | 36 | $response = $this->broker()->reset( 37 | $this->credentials(), 38 | function ($user, $password) { 39 | $this->resetPassword($user, $password); 40 | } 41 | ); 42 | 43 | return $response == Password::PASSWORD_RESET 44 | ? $this->sendResetResponse($response) 45 | : $this->addError('email', trans($response)); 46 | } 47 | 48 | public function broker() 49 | { 50 | return Password::broker(); 51 | } 52 | 53 | protected function guard() 54 | { 55 | return Auth::guard(); 56 | } 57 | 58 | protected function credentials() 59 | { 60 | return [ 61 | 'email' => $this->email, 62 | 'password' => $this->password, 63 | 'password_confirmation' => $this->password_confirmation, 64 | 'token' => $this->token, 65 | ]; 66 | } 67 | 68 | protected function resetPassword($user, $password) 69 | { 70 | $user->password = Hash::make($password); 71 | 72 | $user->setRememberToken(Str::random(60)); 73 | 74 | $user->save(); 75 | 76 | event(new PasswordReset($user)); 77 | 78 | $this->guard()->login($user); 79 | } 80 | 81 | protected function sendResetResponse($response) 82 | { 83 | session()->flash('status', trans($response)); 84 | 85 | return redirect(RouteServiceProvider::HOME); 86 | } 87 | 88 | public function render() 89 | { 90 | return view('livewire.auth.passwords.reset')->extends('layouts.auth'); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/stubs/auth/app/Http/Livewire/Auth/Register.php: -------------------------------------------------------------------------------- 1 | validate([ 25 | 'name' => ['required', 'string', 'max:255'], 26 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 27 | 'password' => ['required', 'string', 'min:8', 'confirmed'], 28 | ]); 29 | 30 | event(new Registered($user = $this->create())); 31 | 32 | $this->guard()->login($user); 33 | 34 | return redirect()->intended(RouteServiceProvider::HOME); 35 | } 36 | 37 | protected function create() 38 | { 39 | return User::create([ 40 | 'name' => $this->name, 41 | 'email' => $this->email, 42 | 'password' => Hash::make($this->password), 43 | ]); 44 | } 45 | 46 | protected function guard() 47 | { 48 | return Auth::guard(); 49 | } 50 | 51 | public function render() 52 | { 53 | return view('livewire.auth.register')->extends('layouts.auth'); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/stubs/auth/app/Http/Livewire/Auth/Verify.php: -------------------------------------------------------------------------------- 1 | redirectIfVerified(); 14 | 15 | Auth::user()->sendEmailVerificationNotification(); 16 | 17 | session()->flash('resent', true); 18 | } 19 | 20 | public function mount() 21 | { 22 | $this->redirectIfVerified(); 23 | } 24 | 25 | protected function redirectIfVerified() 26 | { 27 | if (Auth::user()->hasVerifiedEmail()) { 28 | return redirect(RouteServiceProvider::HOME); 29 | } 30 | } 31 | 32 | public function render() 33 | { 34 | return view('livewire.auth.verify')->extends('layouts.auth'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/stubs/auth/app/Http/Livewire/Home.php: -------------------------------------------------------------------------------- 1 | 4 | {{ $slot }} 5 | -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/components/form-input.blade.php: -------------------------------------------------------------------------------- 1 | 4 | 5 |
    6 | 8 |
    9 | 10 | @error($name) 11 |

    {{ $message }}

    12 | @enderror -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/layouts/auth.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.base') 2 | 3 | @section('body') 4 |
    5 | @yield('content') 6 | 7 | @isset($slot) 8 | {{ $slot }} 9 | @endisset 10 |
    11 | @endsection -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/livewire/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | @section('title', __('Sign in to your account')) 2 | 3 |
    4 |
    5 | 6 | 7 | 8 | 9 |

    10 | {{ __('Sign in to your account') }} 11 |

    12 |

    13 | {{ __('Or') }} 14 | 16 | {{ __('create a new account') }} 17 | 18 |

    19 |
    20 | 21 |
    22 |
    23 |
    24 |
    25 | 27 |
    28 | 29 |
    30 | 32 |
    33 | 34 |
    35 |
    36 | 38 | 41 |
    42 | 43 | 49 |
    50 | 51 |
    52 | 53 | 54 | {{ __('Log In') }} 55 | 56 | 57 |
    58 |
    59 |
    60 |
    61 |
    -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/livewire/auth/passwords/confirm.blade.php: -------------------------------------------------------------------------------- 1 | @section('title', __('Confirm your password')) 2 | 3 |
    4 |
    5 | 6 | 7 | 8 | 9 |

    10 | {{ __('Confirm your password') }} 11 |

    12 | 13 |

    14 | {{ __('Please confirm your password before continuing') }} 15 |

    16 |
    17 | 18 |
    19 |
    20 |
    21 |
    22 | 24 |
    25 | 26 | 34 | 35 |
    36 | 37 | 38 | {{ __('Confirm password') }} 39 | 40 | 41 |
    42 |
    43 |
    44 |
    45 |
    -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/livewire/auth/passwords/email.blade.php: -------------------------------------------------------------------------------- 1 | @section('title', __('Reset password')) 2 | 3 |
    4 |
    5 | 6 | 7 | 8 | 9 |

    10 | {{ __('Reset password') }} 11 |

    12 | 13 |

    14 | {{ __('Or') }} 15 | 17 | {{ __('sign in to your account') }} 18 | 19 |

    20 |
    21 | 22 |
    23 |
    24 | @if (session('status')) 25 |
    26 |
    27 |
    28 | 29 | 32 | 33 |
    34 | 35 |
    36 |

    37 | {{ session('status') }} 38 |

    39 |
    40 |
    41 |
    42 | @endif 43 |
    44 |
    45 | 47 |
    48 | 49 |
    50 | 51 | 52 | {{ __('Send password reset link') }} 53 | 54 | 55 |
    56 |
    57 |
    58 |
    59 |
    60 | -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/livewire/auth/passwords/reset.blade.php: -------------------------------------------------------------------------------- 1 | @section('title', __('Reset password')) 2 | 3 |
    4 |
    5 | 6 | 7 | 8 | 9 |

    10 | {{ __('Reset password') }} 11 |

    12 |
    13 | 14 |
    15 |
    16 |
    17 | 18 | 19 |
    20 | 22 |
    23 | 24 |
    25 | 27 |
    28 | 29 |
    30 | 32 |
    33 | 34 |
    35 | 36 | 37 | {{ __('Reset password') }} 38 | 39 | 40 |
    41 |
    42 |
    43 |
    44 |
    45 | -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/livewire/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | @section('title', __('Create a new account')) 2 | 3 |
    4 |
    5 | 6 | 7 | 8 | 9 |

    10 | {{ __('Create a new account') }} 11 |

    12 | 13 |

    14 | {{ __('Or') }} 15 | 17 | {{ __('sign in to your account') }} 18 | 19 |

    20 |
    21 | 22 |
    23 |
    24 |
    25 |
    26 | 28 |
    29 | 30 |
    31 | 33 |
    34 | 35 |
    36 | 38 |
    39 | 40 |
    41 | 43 |
    44 | 45 |
    46 | 47 | 48 | {{ __('Sign Up') }} 49 | 50 | 51 |
    52 |
    53 |
    54 |
    55 |
    -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/livewire/auth/verify.blade.php: -------------------------------------------------------------------------------- 1 | @section('title', __('Verify your email address')) 2 | 3 |
    4 |
    5 | 6 | 7 | 8 | 9 |

    10 | {{ __('Verify your email address') }} 11 |

    12 | 13 |

    14 | {{ __('Or') }} 15 | 18 | {{ __('sign out') }} 19 | 20 | 21 |

    24 |

    25 |
    26 | 27 |
    28 |
    30 |
    31 |
    32 |
    33 | 34 | 37 | 38 |
    39 | 40 |
    41 |

    42 | {{ __('A fresh verification link has been sent to your email address.') }} 43 |

    44 |
    45 |
    46 |
    47 | 48 |
    49 |

    {{ __('Before proceeding, please check your email for a verification link.') }}

    50 | 51 |

    52 | {{ __('If you did not receive the email,') }} {{ __('click here to request another') }}. 54 |

    55 |
    56 |
    57 |
    58 |
    59 | -------------------------------------------------------------------------------- /src/stubs/auth/resources/views/livewire/home.blade.php: -------------------------------------------------------------------------------- 1 | @section('title', __('Home')) 2 | 3 |
    4 |
    5 |
    6 |
    7 | 9 |
    10 |

    Dashboard

    11 |

    You are logged in!

    12 |
    13 |
    14 |
    15 |
    -------------------------------------------------------------------------------- /src/stubs/auth/routes/web.php: -------------------------------------------------------------------------------- 1 | group(function () { 28 | Route::get('login', Login::class) 29 | ->name('login'); 30 | 31 | Route::get('register', Register::class) 32 | ->name('register'); 33 | }); 34 | 35 | Route::get('password/reset', Email::class) 36 | ->name('password.request'); 37 | 38 | Route::get('password/reset/{token}', Reset::class) 39 | ->name('password.reset'); 40 | 41 | Route::middleware('auth')->group(function () { 42 | Route::get('email/verify', Verify::class) 43 | ->middleware('throttle:6,1') 44 | ->name('verification.notice'); 45 | 46 | Route::get('password/confirm', Confirm::class) 47 | ->name('password.confirm'); 48 | }); 49 | 50 | Route::middleware('auth')->group(function () { 51 | Route::get('home', Home::class) 52 | ->name('home'); 53 | 54 | Route::get('email/verify/{id}/{hash}', [VerificationController::class, 'verify']) 55 | ->middleware('signed') 56 | ->name('verification.verify'); 57 | 58 | Route::post('logout', [LoginController::class, 'logout']) 59 | ->name('logout'); 60 | }); 61 | -------------------------------------------------------------------------------- /src/stubs/auth/tests/Feature/Auth/LoginTest.php: -------------------------------------------------------------------------------- 1 | get(route('login')) 21 | ->assertSuccessful() 22 | ->assertSeeLivewire('auth.login'); 23 | } 24 | 25 | /** @test */ 26 | public function is_redirected_if_already_logged_in() 27 | { 28 | $user = User::factory()->create(); 29 | 30 | $this->be($user); 31 | 32 | $this->get(route('login')) 33 | ->assertRedirect(RouteServiceProvider::HOME); 34 | } 35 | 36 | /** @test */ 37 | public function a_user_can_login() 38 | { 39 | $user = User::factory()->create(['password' => Hash::make('password')]); 40 | 41 | Livewire::test('auth.login') 42 | ->set('email', $user->email) 43 | ->set('password', 'password') 44 | ->call('authenticate'); 45 | 46 | $this->assertAuthenticatedAs($user); 47 | } 48 | 49 | /** @test */ 50 | public function is_redirected_to_the_home_page_after_login() 51 | { 52 | $user = User::factory()->create(['password' => Hash::make('password')]); 53 | 54 | Livewire::test('auth.login') 55 | ->set('email', $user->email) 56 | ->set('password', 'password') 57 | ->call('authenticate') 58 | ->assertRedirect(RouteServiceProvider::HOME); 59 | } 60 | 61 | /** @test */ 62 | public function email_is_required() 63 | { 64 | $user = User::factory()->create(['password' => Hash::make('password')]); 65 | 66 | Livewire::test('auth.login') 67 | ->set('password', 'password') 68 | ->call('authenticate') 69 | ->assertHasErrors(['email' => 'required']); 70 | } 71 | 72 | /** @test */ 73 | public function password_is_required() 74 | { 75 | $user = User::factory()->create(['password' => Hash::make('password')]); 76 | 77 | Livewire::test('auth.login') 78 | ->set('email', $user->email) 79 | ->call('authenticate') 80 | ->assertHasErrors(['password' => 'required']); 81 | } 82 | 83 | /** @test */ 84 | public function bad_login_attempt_shows_message() 85 | { 86 | $user = User::factory()->create(); 87 | 88 | Livewire::test('auth.login') 89 | ->set('email', $user->email) 90 | ->set('password', 'bad-password') 91 | ->call('authenticate') 92 | ->assertHasErrors('email'); 93 | 94 | $this->assertFalse(Auth::check()); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/stubs/auth/tests/Feature/Auth/LogoutTest.php: -------------------------------------------------------------------------------- 1 | create(); 18 | $this->be($user); 19 | 20 | $this->post(route('logout')) 21 | ->assertRedirect('/'); 22 | 23 | $this->assertFalse(Auth::check()); 24 | } 25 | 26 | /** @test */ 27 | public function an_unauthenticated_user_can_not_log_out() 28 | { 29 | $this->post(route('logout')) 30 | ->assertRedirect(route('login')); 31 | 32 | $this->assertFalse(Auth::check()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/stubs/auth/tests/Feature/Auth/Passwords/ConfirmTest.php: -------------------------------------------------------------------------------- 1 | middleware(['web', 'password.confirm']); 23 | } 24 | 25 | /** @test */ 26 | public function a_user_must_confirm_their_password_before_visiting_a_protected_page() 27 | { 28 | $user = User::factory()->create(); 29 | $this->be($user); 30 | 31 | $this->get('/must-be-confirmed') 32 | ->assertRedirect(route('password.confirm')); 33 | 34 | $this->followingRedirects() 35 | ->get('/must-be-confirmed') 36 | ->assertSeeLivewire('auth.passwords.confirm'); 37 | } 38 | 39 | /** @test */ 40 | public function a_user_must_enter_a_password_to_confirm_it() 41 | { 42 | Livewire::test('auth.passwords.confirm') 43 | ->call('confirm') 44 | ->assertHasErrors(['password' => 'required']); 45 | } 46 | 47 | /** @test */ 48 | public function a_user_must_enter_their_own_password_to_confirm_it() 49 | { 50 | $user = User::factory()->create([ 51 | 'password' => Hash::make('password'), 52 | ]); 53 | 54 | Livewire::test('auth.passwords.confirm') 55 | ->set('password', 'not-password') 56 | ->call('confirm') 57 | ->assertHasErrors(['password' => 'password']); 58 | } 59 | 60 | /** @test */ 61 | public function a_user_who_confirms_their_password_will_get_redirected() 62 | { 63 | $user = User::factory()->create([ 64 | 'password' => Hash::make('password'), 65 | ]); 66 | 67 | $this->be($user); 68 | 69 | $this->withSession(['url.intended' => '/must-be-confirmed']); 70 | 71 | Livewire::test('auth.passwords.confirm') 72 | ->set('password', 'password') 73 | ->call('confirm') 74 | ->assertRedirect('/must-be-confirmed'); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/stubs/auth/tests/Feature/Auth/Passwords/EmailTest.php: -------------------------------------------------------------------------------- 1 | get(route('password.request')) 18 | ->assertSuccessful() 19 | ->assertSeeLivewire('auth.passwords.email'); 20 | } 21 | 22 | /** @test */ 23 | public function a_user_must_enter_an_email_address() 24 | { 25 | Livewire::test('auth.passwords.email') 26 | ->call('sendResetLinkEmail') 27 | ->assertHasErrors(['email' => 'required']); 28 | } 29 | 30 | /** @test */ 31 | public function a_user_must_enter_a_valid_email_address() 32 | { 33 | Livewire::test('auth.passwords.email') 34 | ->set('email', 'email') 35 | ->call('sendResetLinkEmail') 36 | ->assertHasErrors(['email' => 'email']); 37 | } 38 | 39 | /** @test */ 40 | public function a_user_who_enters_a_valid_email_address_will_get_sent_an_email() 41 | { 42 | $user = User::factory()->create(); 43 | 44 | Livewire::test('auth.passwords.email') 45 | ->set('email', $user->email) 46 | ->call('sendResetLinkEmail'); 47 | 48 | $this->assertDatabaseHas('password_resets', [ 49 | 'email' => $user->email, 50 | ]); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/stubs/auth/tests/Feature/Auth/Passwords/ResetTest.php: -------------------------------------------------------------------------------- 1 | create(); 23 | 24 | $token = Str::random(16); 25 | 26 | DB::table('password_resets')->insert([ 27 | 'email' => $user->email, 28 | 'token' => Hash::make($token), 29 | 'created_at' => Carbon::now(), 30 | ]); 31 | 32 | $this->get(route('password.reset', [ 33 | 'email' => $user->email, 34 | 'token' => $token, 35 | ])) 36 | ->assertSuccessful() 37 | ->assertSeeLivewire('auth.passwords.reset'); 38 | } 39 | 40 | /** @test */ 41 | public function can_reset_password() 42 | { 43 | $user = User::factory()->create(); 44 | 45 | $token = Str::random(16); 46 | 47 | DB::table('password_resets')->insert([ 48 | 'email' => $user->email, 49 | 'token' => Hash::make($token), 50 | 'created_at' => Carbon::now(), 51 | ]); 52 | 53 | Livewire::test('auth.passwords.reset', [ 54 | 'token' => $token, 55 | ]) 56 | ->set('email', $user->email) 57 | ->set('password', 'new-password') 58 | ->set('password_confirmation', 'new-password') 59 | ->call('passwordReset'); 60 | 61 | $this->assertTrue(Auth::attempt([ 62 | 'email' => $user->email, 63 | 'password' => 'new-password', 64 | ])); 65 | } 66 | 67 | /** @test */ 68 | public function token_is_required() 69 | { 70 | Livewire::test('auth.passwords.reset', [ 71 | 'token' => null, 72 | ]) 73 | ->call('passwordReset') 74 | ->assertHasErrors(['token' => 'required']); 75 | } 76 | 77 | /** @test */ 78 | public function email_is_required() 79 | { 80 | Livewire::test('auth.passwords.reset', [ 81 | 'token' => Str::random(16), 82 | ]) 83 | ->set('email', null) 84 | ->call('passwordReset') 85 | ->assertHasErrors(['email' => 'required']); 86 | } 87 | 88 | /** @test */ 89 | public function email_is_valid_email() 90 | { 91 | Livewire::test('auth.passwords.reset', [ 92 | 'token' => Str::random(16), 93 | ]) 94 | ->set('email', 'email') 95 | ->call('passwordReset') 96 | ->assertHasErrors(['email' => 'email']); 97 | } 98 | 99 | /** @test */ 100 | public function password_is_required() 101 | { 102 | Livewire::test('auth.passwords.reset', [ 103 | 'token' => Str::random(16), 104 | ]) 105 | ->set('password', '') 106 | ->call('passwordReset') 107 | ->assertHasErrors(['password' => 'required']); 108 | } 109 | 110 | /** @test */ 111 | public function password_is_minimum_of_eight_characters() 112 | { 113 | Livewire::test('auth.passwords.reset', [ 114 | 'token' => Str::random(16), 115 | ]) 116 | ->set('password', 'secret') 117 | ->call('passwordReset') 118 | ->assertHasErrors(['password' => 'min']); 119 | } 120 | 121 | /** @test */ 122 | public function password_matches_password_confirmation() 123 | { 124 | Livewire::test('auth.passwords.reset', [ 125 | 'token' => Str::random(16), 126 | ]) 127 | ->set('password', 'new-password') 128 | ->set('password_confirmation', 'not-new-password') 129 | ->call('passwordReset') 130 | ->assertHasErrors(['password' => 'confirmed']); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/stubs/auth/tests/Feature/Auth/RegisterTest.php: -------------------------------------------------------------------------------- 1 | get(route('register')) 22 | ->assertSuccessful() 23 | ->assertSeeLivewire('auth.register'); 24 | } 25 | 26 | /** @test */ 27 | public function is_redirected_if_already_logged_in() 28 | { 29 | $user = User::factory()->create(); 30 | 31 | $this->be($user); 32 | 33 | $this->get(route('register')) 34 | ->assertRedirect(RouteServiceProvider::HOME); 35 | } 36 | 37 | /** @test */ 38 | public function a_user_can_register() 39 | { 40 | Event::fake(); 41 | 42 | Livewire::test('auth.register') 43 | ->set('name', 'Tall Stack') 44 | ->set('email', 'tallstack@example.com') 45 | ->set('password', 'password') 46 | ->set('password_confirmation', 'password') 47 | ->call('signup') 48 | ->assertRedirect(RouteServiceProvider::HOME); 49 | 50 | $this->assertTrue(User::whereEmail('tallstack@example.com')->exists()); 51 | $this->assertEquals('tallstack@example.com', Auth::user()->email); 52 | 53 | Event::assertDispatched(Registered::class); 54 | } 55 | 56 | /** @test */ 57 | public function name_is_required() 58 | { 59 | Livewire::test('auth.register') 60 | ->set('name', '') 61 | ->call('signup') 62 | ->assertHasErrors(['email' => 'required']); 63 | } 64 | 65 | /** @test */ 66 | public function email_is_required() 67 | { 68 | Livewire::test('auth.register') 69 | ->set('email', '') 70 | ->call('signup') 71 | ->assertHasErrors(['email' => 'required']); 72 | } 73 | 74 | /** @test */ 75 | public function email_is_valid_email() 76 | { 77 | Livewire::test('auth.register') 78 | ->set('email', 'tallstack') 79 | ->call('signup') 80 | ->assertHasErrors(['email' => 'email']); 81 | } 82 | 83 | /** @test */ 84 | public function email_hasnt_been_taken_already() 85 | { 86 | User::factory()->create(['email' => 'tallstack@example.com']); 87 | 88 | Livewire::test('auth.register') 89 | ->set('email', 'tallstack@example.com') 90 | ->call('signup') 91 | ->assertHasErrors(['email' => 'unique']); 92 | } 93 | 94 | /** @test */ 95 | public function see_email_hasnt_already_been_taken_validation_message_as_user_types() 96 | { 97 | User::factory()->create(['email' => 'tallstack@example.com']); 98 | 99 | Livewire::test('auth.register') 100 | ->set('email', 'smallstack@gmail.com') 101 | ->assertHasNoErrors() 102 | ->set('email', 'tallstack@example.com') 103 | ->call('signup') 104 | ->assertHasErrors(['email' => 'unique']); 105 | } 106 | 107 | /** @test */ 108 | public function password_is_required() 109 | { 110 | Livewire::test('auth.register') 111 | ->set('password', '') 112 | ->set('password_confirmation', 'password') 113 | ->call('signup') 114 | ->assertHasErrors(['password' => 'required']); 115 | } 116 | 117 | /** @test */ 118 | public function password_is_minimum_of_eight_characters() 119 | { 120 | Livewire::test('auth.register') 121 | ->set('password', 'secret') 122 | ->set('password_confirmation', 'secret') 123 | ->call('signup') 124 | ->assertHasErrors(['password' => 'min']); 125 | } 126 | 127 | /** @test */ 128 | public function password_matches_password_confirmation() 129 | { 130 | Livewire::test('auth.register') 131 | ->set('email', 'tallstack@example.com') 132 | ->set('password', 'password') 133 | ->set('password_confirmation', 'not-password') 134 | ->call('signup') 135 | ->assertHasErrors(['password' => 'confirmed']); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/stubs/auth/tests/Feature/Auth/VerifyTest.php: -------------------------------------------------------------------------------- 1 | create([ 24 | 'email_verified_at' => null, 25 | ]); 26 | 27 | Auth::login($user); 28 | 29 | $this->get(route('verification.notice')) 30 | ->assertSuccessful() 31 | ->assertSeeLivewire('auth.verify'); 32 | } 33 | 34 | /** @test */ 35 | public function can_resend_verification_email() 36 | { 37 | $user = User::factory()->create(); 38 | 39 | Livewire::actingAs($user); 40 | 41 | Livewire::test('auth.verify') 42 | ->call('resend') 43 | ->assertSessionHas('resent', true); 44 | } 45 | 46 | /** @test */ 47 | public function can_verify() 48 | { 49 | $user = User::factory()->create([ 50 | 'email_verified_at' => null, 51 | ]); 52 | 53 | Auth::login($user); 54 | 55 | $url = URL::temporarySignedRoute('verification.verify', Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)), [ 56 | 'id' => $user->getKey(), 57 | 'hash' => sha1($user->getEmailForVerification()), 58 | ]); 59 | 60 | $this->get($url) 61 | ->assertRedirect(RouteServiceProvider::HOME); 62 | 63 | $this->assertTrue($user->hasVerifiedEmail()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/stubs/default/.eslintignore: -------------------------------------------------------------------------------- 1 | public/js 2 | vendor/ -------------------------------------------------------------------------------- /src/stubs/default/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb", "prettier"], 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/stubs/default/.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /node_modules 3 | /public/hot 4 | /public/storage 5 | /storage/*.key 6 | /storage/*.index 7 | /storage/*.index-journal 8 | /vendor 9 | .env 10 | .env.backup 11 | .phpunit.result.cache 12 | docker-compose.override.yml 13 | Homestead.json 14 | Homestead.yaml 15 | npm-debug.log 16 | yarn-error.log 17 | /.vscode 18 | auth.json 19 | .php-cs-fixer.cache 20 | _ide_helper.php 21 | _ide_helper_actions.php 22 | _ide_helper_models.php 23 | .phpstorm.meta.php 24 | draft.yaml 25 | .blueprint 26 | cghooks.lock 27 | -------------------------------------------------------------------------------- /src/stubs/default/.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | ['syntax' => 'short'], 8 | 'binary_operator_spaces' => [ 9 | 'default' => 'single_space', 10 | 'operators' => ['=>' => null], 11 | ], 12 | 'blank_line_after_namespace' => true, 13 | 'blank_line_after_opening_tag' => true, 14 | 'blank_line_before_statement' => [ 15 | 'statements' => ['return'], 16 | ], 17 | 'braces' => true, 18 | 'cast_spaces' => true, 19 | 'class_attributes_separation' => [ 20 | 'elements' => [ 21 | 'const' => 'one', 22 | 'method' => 'one', 23 | 'property' => 'one', 24 | ], 25 | ], 26 | 'class_definition' => [ 27 | 'multi_line_extends_each_single_line' => true, 28 | 'single_item_single_line' => true, 29 | 'single_line' => true, 30 | ], 31 | 'concat_space' => [ 32 | 'spacing' => 'none', 33 | ], 34 | 'declare_equal_normalize' => true, 35 | 'elseif' => true, 36 | 'encoding' => true, 37 | 'full_opening_tag' => true, 38 | 'fully_qualified_strict_types' => true, // added by Shift 39 | 'function_declaration' => true, 40 | 'function_typehint_space' => true, 41 | 'general_phpdoc_tag_rename' => true, 42 | 'heredoc_to_nowdoc' => true, 43 | 'include' => true, 44 | 'increment_style' => ['style' => 'post'], 45 | 'indentation_type' => true, 46 | 'linebreak_after_opening_tag' => true, 47 | 'line_ending' => true, 48 | 'lowercase_cast' => true, 49 | 'constant_case' => ['case' => 'lower'], 50 | 'lowercase_keywords' => true, 51 | 'lowercase_static_reference' => true, // added from Symfony 52 | 'magic_method_casing' => true, // added from Symfony 53 | 'magic_constant_casing' => true, 54 | 'method_argument_space' => true, 55 | 'native_function_casing' => true, 56 | 'no_alias_functions' => true, 57 | 'no_extra_blank_lines' => [ 58 | 'tokens' => [ 59 | 'extra', 60 | 'throw', 61 | 'use', 62 | 'use_trait', 63 | ], 64 | ], 65 | 'no_blank_lines_after_class_opening' => true, 66 | 'no_blank_lines_after_phpdoc' => true, 67 | 'no_closing_tag' => true, 68 | 'no_empty_phpdoc' => true, 69 | 'no_empty_statement' => true, 70 | 'no_leading_import_slash' => true, 71 | 'no_leading_namespace_whitespace' => true, 72 | 'no_mixed_echo_print' => [ 73 | 'use' => 'echo', 74 | ], 75 | 'no_multiline_whitespace_around_double_arrow' => true, 76 | 'multiline_whitespace_before_semicolons' => [ 77 | 'strategy' => 'no_multi_line', 78 | ], 79 | 'no_short_bool_cast' => true, 80 | 'no_singleline_whitespace_before_semicolons' => true, 81 | 'no_spaces_after_function_name' => true, 82 | 'no_spaces_around_offset' => [ 83 | 'positions' => ['inside', 'outside'], 84 | ], 85 | 'no_spaces_inside_parenthesis' => true, 86 | 'no_trailing_comma_in_list_call' => true, 87 | 'no_trailing_comma_in_singleline_array' => true, 88 | 'no_trailing_whitespace' => true, 89 | 'no_trailing_whitespace_in_comment' => true, 90 | 'no_unneeded_control_parentheses' => [ 91 | 'statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield'], 92 | ], 93 | 'no_unreachable_default_argument_value' => true, 94 | 'no_useless_return' => true, 95 | 'no_whitespace_before_comma_in_array' => true, 96 | 'no_whitespace_in_blank_line' => true, 97 | 'normalize_index_brace' => true, 98 | 'not_operator_with_successor_space' => true, 99 | 'object_operator_without_whitespace' => true, 100 | 'ordered_imports' => [ 101 | 'sort_algorithm' => 'alpha', 102 | ], 103 | 'phpdoc_indent' => true, 104 | 'phpdoc_inline_tag_normalizer' => true, 105 | 'phpdoc_no_access' => true, 106 | 'phpdoc_no_package' => true, 107 | 'phpdoc_no_useless_inheritdoc' => true, 108 | 'phpdoc_scalar' => true, 109 | 'phpdoc_single_line_var_spacing' => true, 110 | 'phpdoc_summary' => true, 111 | 'phpdoc_to_comment' => true, 112 | 'phpdoc_tag_type' => true, 113 | 'phpdoc_trim' => true, 114 | 'phpdoc_types' => true, 115 | 'phpdoc_var_without_name' => true, 116 | 'psr_autoloading' => true, 117 | 'self_accessor' => true, 118 | 'short_scalar_cast' => true, 119 | 'simplified_null_return' => false, // disabled by Shift 120 | 'single_blank_line_at_eof' => true, 121 | 'single_blank_line_before_namespace' => true, 122 | 'single_class_element_per_statement' => true, // here 123 | 'single_import_per_statement' => true, 124 | 'single_line_after_imports' => true, 125 | 'single_line_comment_style' => [ 126 | 'comment_types' => ['hash'] 127 | ], 128 | 'single_quote' => true, 129 | 'space_after_semicolon' => true, 130 | 'standardize_not_equals' => true, 131 | 'switch_case_semicolon_to_colon' => true, 132 | 'switch_case_space' => true, 133 | 'ternary_operator_spaces' => true, 134 | 'trailing_comma_in_multiline' => ['elements' => ['arrays']], 135 | 'trim_array_spaces' => true, 136 | 'unary_operator_spaces' => true, 137 | 'visibility_required' => [ 138 | 'elements' => ['property', 'method', 'const'], 139 | ], 140 | 'whitespace_after_comma_in_array' => true, 141 | ]; 142 | 143 | $finder = Finder::create() 144 | ->in([ 145 | __DIR__ . '/app', 146 | __DIR__ . '/config', 147 | __DIR__ . '/database', 148 | __DIR__ . '/resources', 149 | __DIR__ . '/routes', 150 | __DIR__ . '/tests', 151 | ]) 152 | ->name('*.php') 153 | ->notName('*.blade.php') 154 | ->ignoreDotFiles(true) 155 | ->ignoreVCS(true); 156 | 157 | return (new Config()) 158 | ->setFinder($finder) 159 | ->setRules($rules) 160 | ->setRiskyAllowed(true) 161 | ->setUsingCache(true); 162 | -------------------------------------------------------------------------------- /src/stubs/default/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true, 4 | "endOfLine": "lf", 5 | "tabWidth": 4, 6 | "semi": true 7 | } 8 | -------------------------------------------------------------------------------- /src/stubs/default/phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - ./vendor/nunomaduro/larastan/extension.neon 3 | 4 | parameters: 5 | 6 | paths: 7 | - app 8 | 9 | # The level 8 is the highest level 10 | level: 5 11 | 12 | ignoreErrors: 13 | - '#Unsafe usage of new static#' 14 | - '#Access to an undefined property Illuminate\\Support\\HigherOrderCollectionProxy::\$[a-zA-Z0-9_]+#' 15 | 16 | excludes_analyse: 17 | - ./app/Http/Middleware/Authenticate.php 18 | 19 | checkMissingIterableValueType: false 20 | -------------------------------------------------------------------------------- /src/stubs/default/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/stubs/default/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pktharindu/ttall/3ce4cb8d44b50c1ea1afce075a041da35e83294d/src/stubs/default/public/favicon.ico -------------------------------------------------------------------------------- /src/stubs/default/resources/css/app.css: -------------------------------------------------------------------------------- 1 | /** 2 | * This injects Tailwind's base styles, which is a combination of 3 | * Normalize.css and some additional base styles. 4 | * 5 | * You can see the styles here: 6 | * https://unpkg.com/tailwindcss/dist/base.css 7 | */ 8 | @tailwind base; 9 | 10 | /** 11 | * Remove the default box-shadow for invalid elements to prevent 12 | * inputs in Livewire components showing with a 13 | * red border by default in Firefox. 14 | * 15 | * See: https://github.com/laravel-frontend-presets/tall/issues/7 16 | */ 17 | input:invalid, textarea:invalid, select:invalid { 18 | box-shadow: none; 19 | } 20 | 21 | /** 22 | * This injects any component classes registered by plugins. 23 | */ 24 | @tailwind components; 25 | 26 | /** 27 | * Here you would add any of your custom component classes; stuff that you'd 28 | * want loaded *before* the utilities so that the utilities could still 29 | * override them. 30 | * 31 | * Example: 32 | * 33 | * .btn { ... } 34 | * .form-input { ... } 35 | */ 36 | 37 | .turbolinks-progress-bar { 38 | @apply bg-indigo-500; 39 | } 40 | 41 | /** 42 | * This injects all of Tailwind's utility classes, generated based on your 43 | * config file. 44 | */ 45 | @tailwind utilities; 46 | 47 | /** 48 | * Here you would add any custom utilities you need that don't come out of the 49 | * box with Tailwind. 50 | * 51 | * Example : 52 | * 53 | * .bg-pattern-graph-paper { ... } 54 | * .skew-45 { ... } 55 | */ 56 | 57 | /** 58 | * x-cloak attributes are removed from elements when Alpine initializes. 59 | * This is useful for hiding pre-initialized DOM. 60 | * 61 | * See: https://github.com/alpinejs/alpine#x-cloak 62 | */ 63 | [x-cloak] { 64 | display: none !important; 65 | } -------------------------------------------------------------------------------- /src/stubs/default/resources/js/app.js: -------------------------------------------------------------------------------- 1 | import './bootstrap'; 2 | -------------------------------------------------------------------------------- /src/stubs/default/resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | import 'alpinejs'; 2 | 3 | /** 4 | * Echo exposes an expressive API for subscribing to channels and listening 5 | * for events that are broadcast by Laravel. Echo and event broadcasting 6 | * allows your team to easily build robust real-time web applications. 7 | */ 8 | 9 | // import Echo from 'laravel-echo' 10 | 11 | // window.Pusher = require('pusher-js'); 12 | 13 | // window.Echo = new Echo({ 14 | // broadcaster: 'pusher', 15 | // key: process.env.MIX_PUSHER_APP_KEY, 16 | // cluster: process.env.MIX_PUSHER_APP_CLUSTER, 17 | // forceTLS: true 18 | // }); 19 | -------------------------------------------------------------------------------- /src/stubs/default/resources/js/turbolinks.js: -------------------------------------------------------------------------------- 1 | import Turbolinks from 'turbolinks'; 2 | 3 | Turbolinks.start(); 4 | -------------------------------------------------------------------------------- /src/stubs/default/resources/views/components/logo.blade.php: -------------------------------------------------------------------------------- 1 | 2 | {{ config('app.name') }} 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/stubs/default/resources/views/components/navbar.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/stubs/default/resources/views/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.base') 2 | 3 | @section('body') 4 | 5 | @yield('content') 6 | 7 | @isset($slot) 8 | {{ $slot }} 9 | @endisset 10 | @endsection -------------------------------------------------------------------------------- /src/stubs/default/resources/views/layouts/base.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | @hasSection('title') 12 | @yield('title') - {{ config('app.name') }} 13 | @else 14 | {{ config('app.name') }} 15 | @endif 16 | 17 | 18 | 19 | 20 | 21 | @stack('before-styles') 22 | 23 | 24 | @livewireStyles 25 | @stack('after-styles') 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | @yield('body') 39 | 40 | @livewireScripts 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/stubs/default/resources/views/vendor/pagination/default.blade.php: -------------------------------------------------------------------------------- 1 | @if ($paginator->hasPages()) 2 | 69 | @endif 70 | -------------------------------------------------------------------------------- /src/stubs/default/resources/views/vendor/pagination/simple-default.blade.php: -------------------------------------------------------------------------------- 1 | @if ($paginator->hasPages()) 2 | 41 | @endif 42 | 43 | -------------------------------------------------------------------------------- /src/stubs/default/resources/views/welcome.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.base') 2 | 3 | @section('body') 4 |
    5 |
    6 | @if (Route::has('login')) 7 |
    8 | @auth 9 | 14 | {{ __('Sign Out') }} 15 | 16 | 17 | 20 | @else 21 | {{ __('Log In') }} 22 | 23 | @if (Route::has('register')) 24 | {{ __('Sign Up') }} 25 | @endif 26 | @endauth 27 |
    28 | @endif 29 |
    30 | 31 |
    32 |
    33 |
    34 | 35 | 36 | 37 | 38 |

    39 | {{ config('app.name') }} 40 |

    41 | 42 | 59 |
    60 |
    61 |
    62 |
    63 | @endsection 64 | -------------------------------------------------------------------------------- /src/stubs/default/routes/web.php: -------------------------------------------------------------------------------- 1 | name('home'); 17 | -------------------------------------------------------------------------------- /src/stubs/default/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | const defaultTheme = require('tailwindcss/defaultTheme'); 3 | 4 | module.exports = { 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: ['Inter var', ...defaultTheme.fontFamily.sans], 9 | }, 10 | }, 11 | }, 12 | 13 | variants: {}, 14 | 15 | purge: { 16 | content: [ 17 | './app/**/*.php', 18 | './resources/**/*.html', 19 | './resources/**/*.js', 20 | './resources/**/*.jsx', 21 | './resources/**/*.ts', 22 | './resources/**/*.tsx', 23 | './resources/**/*.php', 24 | './resources/**/*.vue', 25 | './resources/**/*.twig', 26 | ], 27 | 28 | options: { 29 | defaultExtractor: (content) => content.match(/[\w-/.:]+(?get('/')->assertSuccessful(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/stubs/default/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | swap(Mix::class, function () { 20 | return ''; 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/stubs/default/webpack.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require("laravel-mix"); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for the application as well as bundling up all the JS files. 11 | | 12 | */ 13 | 14 | mix.js('resources/js/app.js', 'public/js') 15 | .js('resources/js/turbolinks.js', 'public/js') 16 | .postCss('resources/css/app.css', 'public/css', [ 17 | require('postcss-import'), 18 | require('tailwindcss'), 19 | require('autoprefixer'), 20 | ]).sourceMaps(); 21 | 22 | if (mix.inProduction()) { 23 | mix.version(); 24 | } --------------------------------------------------------------------------------